| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.hpsf; |
| |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.poi.hpsf.wellknown.PropertyIDMap; |
| import org.apache.poi.hpsf.wellknown.SectionIDMap; |
| import org.apache.poi.util.CodePageUtil; |
| |
| /** |
| * Convenience class representing a DocumentSummary Information stream in a |
| * Microsoft Office document. |
| * |
| * @see SummaryInformation |
| */ |
| public class DocumentSummaryInformation extends SpecialPropertySet { |
| /** |
| * The document name a document summary information stream |
| * usually has in a POIFS filesystem. |
| */ |
| public static final String DEFAULT_STREAM_NAME = |
| "\005DocumentSummaryInformation"; |
| |
| @Override |
| public PropertyIDMap getPropertySetIDMap() { |
| return PropertyIDMap.getDocumentSummaryInformationProperties(); |
| } |
| |
| |
| /** |
| * Creates an empty {@link DocumentSummaryInformation}. |
| */ |
| public DocumentSummaryInformation() { |
| getFirstSection().setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]); |
| } |
| |
| |
| /** |
| * Creates a {@link DocumentSummaryInformation} from a given |
| * {@link PropertySet}. |
| * |
| * @param ps A property set which should be created from a |
| * document summary information stream. |
| * @throws UnexpectedPropertySetTypeException if {@code ps} |
| * does not contain a document summary information stream. |
| */ |
| public DocumentSummaryInformation(final PropertySet ps) |
| throws UnexpectedPropertySetTypeException { |
| super(ps); |
| if (!isDocumentSummaryInformation()) { |
| throw new UnexpectedPropertySetTypeException("Not a " + getClass().getName()); |
| } |
| } |
| |
| |
| /** |
| * Returns the category (or {@code null}). |
| * |
| * @return The category value |
| */ |
| public String getCategory() { |
| return getPropertyStringValue(PropertyIDMap.PID_CATEGORY); |
| } |
| |
| /** |
| * Sets the category. |
| * |
| * @param category The category to set. |
| */ |
| public void setCategory(final String category) { |
| getFirstSection().setProperty(PropertyIDMap.PID_CATEGORY, category); |
| } |
| |
| /** |
| * Removes the category. |
| */ |
| public void removeCategory() { |
| remove1stProperty(PropertyIDMap.PID_CATEGORY); |
| } |
| |
| |
| |
| /** |
| * Returns the presentation format (or |
| * {@code null}). |
| * |
| * @return The presentation format value |
| */ |
| public String getPresentationFormat() { |
| return getPropertyStringValue(PropertyIDMap.PID_PRESFORMAT); |
| } |
| |
| /** |
| * Sets the presentation format. |
| * |
| * @param presentationFormat The presentation format to set. |
| */ |
| public void setPresentationFormat(final String presentationFormat) { |
| getFirstSection().setProperty(PropertyIDMap.PID_PRESFORMAT, presentationFormat); |
| } |
| |
| /** |
| * Removes the presentation format. |
| */ |
| public void removePresentationFormat() { |
| remove1stProperty(PropertyIDMap.PID_PRESFORMAT); |
| } |
| |
| |
| |
| /** |
| * Returns the byte count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a byte count. |
| * |
| * @return The byteCount value |
| */ |
| public int getByteCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_BYTECOUNT); |
| } |
| |
| /** |
| * Sets the byte count. |
| * |
| * @param byteCount The byte count to set. |
| */ |
| public void setByteCount(final int byteCount) { |
| set1stProperty(PropertyIDMap.PID_BYTECOUNT, byteCount); |
| } |
| |
| /** |
| * Removes the byte count. |
| */ |
| public void removeByteCount() { |
| remove1stProperty(PropertyIDMap.PID_BYTECOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns the line count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a line count. |
| * |
| * @return The line count value |
| */ |
| public int getLineCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_LINECOUNT); |
| } |
| |
| /** |
| * Sets the line count. |
| * |
| * @param lineCount The line count to set. |
| */ |
| public void setLineCount(final int lineCount) { |
| set1stProperty(PropertyIDMap.PID_LINECOUNT, lineCount); |
| } |
| |
| /** |
| * Removes the line count. |
| */ |
| public void removeLineCount() { |
| remove1stProperty(PropertyIDMap.PID_LINECOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns the par count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a par count. |
| * |
| * @return The par count value |
| */ |
| public int getParCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_PARCOUNT); |
| } |
| |
| /** |
| * Sets the par count. |
| * |
| * @param parCount The par count to set. |
| */ |
| public void setParCount(final int parCount) { |
| set1stProperty(PropertyIDMap.PID_PARCOUNT, parCount); |
| } |
| |
| /** |
| * Removes the par count. |
| */ |
| public void removeParCount() { |
| remove1stProperty(PropertyIDMap.PID_PARCOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns the slide count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a slide count. |
| * |
| * @return The slide count value |
| */ |
| public int getSlideCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_SLIDECOUNT); |
| } |
| |
| /** |
| * Sets the slideCount. |
| * |
| * @param slideCount The slide count to set. |
| */ |
| public void setSlideCount(final int slideCount) { |
| set1stProperty(PropertyIDMap.PID_SLIDECOUNT, slideCount); |
| } |
| |
| /** |
| * Removes the slide count. |
| */ |
| public void removeSlideCount() { |
| remove1stProperty(PropertyIDMap.PID_SLIDECOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns the note count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a note count. |
| * |
| * @return The note count value |
| */ |
| public int getNoteCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_NOTECOUNT); |
| } |
| |
| /** |
| * Sets the note count. |
| * |
| * @param noteCount The note count to set. |
| */ |
| public void setNoteCount(final int noteCount) { |
| set1stProperty(PropertyIDMap.PID_NOTECOUNT, noteCount); |
| } |
| |
| /** |
| * Removes the noteCount. |
| */ |
| public void removeNoteCount() { |
| remove1stProperty(PropertyIDMap.PID_NOTECOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns the hidden count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a hidden |
| * count. |
| * |
| * @return The hidden count value |
| */ |
| public int getHiddenCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_HIDDENCOUNT); |
| } |
| |
| /** |
| * Sets the hidden count. |
| * |
| * @param hiddenCount The hidden count to set. |
| */ |
| public void setHiddenCount(final int hiddenCount) { |
| set1stProperty(PropertyIDMap.PID_HIDDENCOUNT, hiddenCount); |
| } |
| |
| /** |
| * Removes the hidden count. |
| */ |
| public void removeHiddenCount() { |
| remove1stProperty(PropertyIDMap.PID_HIDDENCOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns the mmclip count or 0 if the {@link |
| * DocumentSummaryInformation} does not contain a mmclip |
| * count. |
| * |
| * @return The mmclip count value |
| */ |
| public int getMMClipCount() { |
| return getPropertyIntValue(PropertyIDMap.PID_MMCLIPCOUNT); |
| } |
| |
| /** |
| * Sets the mmclip count. |
| * |
| * @param mmClipCount The mmclip count to set. |
| */ |
| public void setMMClipCount(final int mmClipCount) { |
| set1stProperty(PropertyIDMap.PID_MMCLIPCOUNT, mmClipCount); |
| } |
| |
| /** |
| * Removes the mmclip count. |
| */ |
| public void removeMMClipCount() { |
| remove1stProperty(PropertyIDMap.PID_MMCLIPCOUNT); |
| } |
| |
| |
| |
| /** |
| * Returns {@code true} when scaling of the thumbnail is |
| * desired, {@code false} if cropping is desired. |
| * |
| * @return The scale value |
| */ |
| public boolean getScale() { |
| return getPropertyBooleanValue(PropertyIDMap.PID_SCALE); |
| } |
| |
| /** |
| * Sets the scale. |
| * |
| * @param scale The scale to set. |
| */ |
| public void setScale(final boolean scale) { |
| set1stProperty(PropertyIDMap.PID_SCALE, scale); |
| } |
| |
| /** |
| * Removes the scale. |
| */ |
| public void removeScale() { |
| remove1stProperty(PropertyIDMap.PID_SCALE); |
| } |
| |
| |
| |
| /** |
| * <p>Returns the heading pair (or {@code null}) |
| * <strong>when this method is implemented. Please note that the |
| * return type is likely to change!</strong> |
| * |
| * @return The heading pair value |
| */ |
| public byte[] getHeadingPair() { |
| notYetImplemented("Reading byte arrays "); |
| return (byte[]) getProperty(PropertyIDMap.PID_HEADINGPAIR); |
| } |
| |
| /** |
| * Sets the heading pair. |
| * |
| * @param headingPair The heading pair to set. |
| */ |
| public void setHeadingPair(final byte[] headingPair) { |
| notYetImplemented("Writing byte arrays "); |
| } |
| |
| /** |
| * Removes the heading pair. |
| */ |
| public void removeHeadingPair() { |
| remove1stProperty(PropertyIDMap.PID_HEADINGPAIR); |
| } |
| |
| |
| |
| /** |
| * <p>Returns the doc parts (or {@code null}) |
| * <strong>when this method is implemented. Please note that the |
| * return type is likely to change!</strong> |
| * |
| * @return The doc parts value |
| */ |
| public byte[] getDocparts() { |
| notYetImplemented("Reading byte arrays"); |
| return (byte[]) getProperty(PropertyIDMap.PID_DOCPARTS); |
| } |
| |
| |
| |
| /** |
| * Sets the doc parts. |
| * |
| * @param docparts The doc parts to set. |
| */ |
| public void setDocparts(final byte[] docparts) { |
| notYetImplemented("Writing byte arrays"); |
| } |
| |
| /** |
| * Removes the doc parts. |
| */ |
| public void removeDocparts() { |
| remove1stProperty(PropertyIDMap.PID_DOCPARTS); |
| } |
| |
| |
| |
| /** |
| * Returns the manager (or {@code null}). |
| * |
| * @return The manager value |
| */ |
| public String getManager() { |
| return getPropertyStringValue(PropertyIDMap.PID_MANAGER); |
| } |
| |
| /** |
| * Sets the manager. |
| * |
| * @param manager The manager to set. |
| */ |
| public void setManager(final String manager) { |
| set1stProperty(PropertyIDMap.PID_MANAGER, manager); |
| } |
| |
| /** |
| * Removes the manager. |
| */ |
| public void removeManager() { |
| remove1stProperty(PropertyIDMap.PID_MANAGER); |
| } |
| |
| |
| |
| /** |
| * Returns the company (or {@code null}). |
| * |
| * @return The company value |
| */ |
| public String getCompany() { |
| return getPropertyStringValue(PropertyIDMap.PID_COMPANY); |
| } |
| |
| /** |
| * Sets the company. |
| * |
| * @param company The company to set. |
| */ |
| public void setCompany(final String company) { |
| set1stProperty(PropertyIDMap.PID_COMPANY, company); |
| } |
| |
| /** |
| * Removes the company. |
| */ |
| public void removeCompany() { |
| remove1stProperty(PropertyIDMap.PID_COMPANY); |
| } |
| |
| |
| /** |
| * Returns {@code true} if the custom links are dirty. <p> |
| * |
| * @return The links dirty value |
| */ |
| public boolean getLinksDirty() { |
| return getPropertyBooleanValue(PropertyIDMap.PID_LINKSDIRTY); |
| } |
| |
| /** |
| * Sets the linksDirty. |
| * |
| * @param linksDirty The links dirty value to set. |
| */ |
| public void setLinksDirty(final boolean linksDirty) { |
| set1stProperty(PropertyIDMap.PID_LINKSDIRTY, linksDirty); |
| } |
| |
| /** |
| * Removes the links dirty. |
| */ |
| public void removeLinksDirty() { |
| remove1stProperty(PropertyIDMap.PID_LINKSDIRTY); |
| } |
| |
| |
| /** |
| * Returns the character count including whitespace, or 0 if the |
| * {@link DocumentSummaryInformation} does not contain this char count. |
| * <p>This is the whitespace-including version of {@link SummaryInformation#getCharCount()} |
| * |
| * @return The character count or {@code null} |
| */ |
| public int getCharCountWithSpaces() { |
| return getPropertyIntValue(PropertyIDMap.PID_CCHWITHSPACES); |
| } |
| |
| /** |
| * Sets the character count including whitespace |
| * |
| * @param count The character count to set. |
| */ |
| public void setCharCountWithSpaces(int count) { |
| set1stProperty(PropertyIDMap.PID_CCHWITHSPACES, count); |
| } |
| |
| /** |
| * Removes the character count |
| */ |
| public void removeCharCountWithSpaces() { |
| remove1stProperty(PropertyIDMap.PID_CCHWITHSPACES); |
| } |
| |
| |
| /** |
| * Get if the User Defined Property Set has been updated outside of the |
| * Application.<p> |
| * If it has (true), the hyperlinks should be updated on document load. |
| * |
| * @return true, if the hyperlinks should be updated on document load |
| */ |
| public boolean getHyperlinksChanged() { |
| return getPropertyBooleanValue(PropertyIDMap.PID_HYPERLINKSCHANGED); |
| } |
| |
| /** |
| * Set the flag for if the User Defined Property Set has been updated outside |
| * of the Application. |
| * |
| * @param changed true, if the User Defined Property Set has been updated |
| */ |
| public void setHyperlinksChanged(boolean changed) { |
| set1stProperty(PropertyIDMap.PID_HYPERLINKSCHANGED, changed); |
| } |
| |
| /** |
| * Removes the flag for if the User Defined Property Set has been updated |
| * outside of the Application. |
| */ |
| public void removeHyperlinksChanged() { |
| remove1stProperty(PropertyIDMap.PID_HYPERLINKSCHANGED); |
| } |
| |
| |
| /** |
| * Gets the version of the Application which wrote the |
| * Property set, stored with the two high order bytes having the major |
| * version number, and the two low order bytes the minor version number.<p> |
| * This will be 0 if no version is set. |
| * |
| * @return the Application version |
| */ |
| public int getApplicationVersion() { |
| return getPropertyIntValue(PropertyIDMap.PID_VERSION); |
| } |
| |
| /** |
| * Sets the Application version, which must be a 4 byte int with |
| * the two high order bytes having the major version number, and the |
| * two low order bytes the minor version number. |
| * |
| * @param version the Application version |
| */ |
| public void setApplicationVersion(int version) { |
| set1stProperty(PropertyIDMap.PID_VERSION, version); |
| } |
| |
| /** |
| * Removes the Application Version |
| */ |
| public void removeApplicationVersion() { |
| remove1stProperty(PropertyIDMap.PID_VERSION); |
| } |
| |
| |
| /** |
| * Returns the VBA digital signature for the VBA project |
| * embedded in the document (or {@code null}). |
| * |
| * @return the VBA digital signature |
| */ |
| public byte[] getVBADigitalSignature() { |
| Object value = getProperty(PropertyIDMap.PID_DIGSIG); |
| if (value != null && value instanceof byte[]) { |
| return (byte[])value; |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the VBA digital signature for the VBA project |
| * embedded in the document. |
| * |
| * @param signature VBA Digital Signature for the project |
| */ |
| public void setVBADigitalSignature(byte[] signature) { |
| set1stProperty(PropertyIDMap.PID_DIGSIG, signature); |
| } |
| |
| /** |
| * Removes the VBA Digital Signature |
| */ |
| public void removeVBADigitalSignature() { |
| remove1stProperty(PropertyIDMap.PID_DIGSIG); |
| } |
| |
| |
| /** |
| * Gets the content type of the file (or {@code null}). |
| * |
| * @return the content type of the file |
| */ |
| public String getContentType() { |
| return getPropertyStringValue(PropertyIDMap.PID_CONTENTTYPE); |
| } |
| |
| /** |
| * Sets the content type of the file |
| * |
| * @param type the content type of the file |
| */ |
| public void setContentType(String type) { |
| set1stProperty(PropertyIDMap.PID_CONTENTTYPE, type); |
| } |
| |
| /** |
| * Removes the content type of the file |
| */ |
| public void removeContentType() { |
| remove1stProperty(PropertyIDMap.PID_CONTENTTYPE); |
| } |
| |
| |
| /** |
| * Gets the content status of the file (or {@code null}). |
| * |
| * @return the content status of the file |
| */ |
| public String getContentStatus() { |
| return getPropertyStringValue(PropertyIDMap.PID_CONTENTSTATUS); |
| } |
| |
| /** |
| * Sets the content status of the file |
| * |
| * @param status the content status of the file |
| */ |
| public void setContentStatus(String status) { |
| set1stProperty(PropertyIDMap.PID_CONTENTSTATUS, status); |
| } |
| |
| /** |
| * Removes the content status of the file |
| */ |
| public void removeContentStatus() { |
| remove1stProperty(PropertyIDMap.PID_CONTENTSTATUS); |
| } |
| |
| |
| /** |
| * Gets the document language, which is normally unset and empty (or {@code null}). |
| * |
| * @return the document language |
| */ |
| public String getLanguage() { |
| return getPropertyStringValue(PropertyIDMap.PID_LANGUAGE); |
| } |
| |
| /** |
| * Set the document language |
| * |
| * @param language the document language |
| */ |
| public void setLanguage(String language) { |
| set1stProperty(PropertyIDMap.PID_LANGUAGE, language); |
| } |
| |
| /** |
| * Removes the document language |
| */ |
| public void removeLanguage() { |
| remove1stProperty(PropertyIDMap.PID_LANGUAGE); |
| } |
| |
| |
| /** |
| * Gets the document version as a string, which is normally unset and empty |
| * (or {@code null}). |
| * |
| * @return the document verion |
| */ |
| public String getDocumentVersion() { |
| return getPropertyStringValue(PropertyIDMap.PID_DOCVERSION); |
| } |
| |
| /** |
| * Sets the document version string |
| * |
| * @param version the document version string |
| */ |
| public void setDocumentVersion(String version) { |
| set1stProperty(PropertyIDMap.PID_DOCVERSION, version); |
| } |
| |
| /** |
| * Removes the document version string |
| */ |
| public void removeDocumentVersion() { |
| remove1stProperty(PropertyIDMap.PID_DOCVERSION); |
| } |
| |
| |
| /** |
| * Gets the custom properties. |
| * |
| * @return The custom properties. |
| */ |
| public CustomProperties getCustomProperties() { |
| CustomProperties cps = null; |
| if (getSectionCount() >= 2) { |
| cps = new CustomProperties(); |
| final Section section = getSections().get(1); |
| final Map<Long,String> dictionary = section.getDictionary(); |
| final Property[] properties = section.getProperties(); |
| int propertyCount = 0; |
| for (int i = 0; i < properties.length; i++) { |
| final Property p = properties[i]; |
| final long id = p.getID(); |
| if (id != 0 && id != 1) { |
| propertyCount++; |
| final CustomProperty cp = new CustomProperty(p, |
| dictionary.get(Long.valueOf(id))); |
| cps.put(cp.getName(), cp); |
| } |
| } |
| if (cps.size() != propertyCount) { |
| cps.setPure(false); |
| } |
| } |
| return cps; |
| } |
| |
| /** |
| * Sets the custom properties. |
| * |
| * @param customProperties The custom properties |
| */ |
| public void setCustomProperties(final CustomProperties customProperties) { |
| ensureSection2(); |
| final Section section = getSections().get(1); |
| final Map<Long,String> dictionary = customProperties.getDictionary(); |
| section.clear(); |
| |
| /* Set the codepage. If both custom properties and section have a |
| * codepage, the codepage from the custom properties wins, else take the |
| * one that is defined. If none is defined, take Unicode. */ |
| int cpCodepage = customProperties.getCodepage(); |
| if (cpCodepage < 0) { |
| cpCodepage = section.getCodepage(); |
| } |
| if (cpCodepage < 0) { |
| cpCodepage = CodePageUtil.CP_UNICODE; |
| } |
| customProperties.setCodepage(cpCodepage); |
| section.setCodepage(cpCodepage); |
| section.setDictionary(dictionary); |
| for (CustomProperty p : customProperties.values()) { |
| section.setProperty(p); |
| } |
| } |
| |
| /** |
| * Creates section 2 if it is not already present. |
| */ |
| private void ensureSection2() { |
| if (getSectionCount() < 2) { |
| Section s2 = new MutableSection(); |
| s2.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[1]); |
| addSection(s2); |
| } |
| } |
| |
| /** |
| * Removes the custom properties. |
| */ |
| public void removeCustomProperties() { |
| if (getSectionCount() < 2) { |
| throw new HPSFRuntimeException("Illegal internal format of Document SummaryInformation stream: second section is missing."); |
| } |
| |
| List<Section> l = new LinkedList<Section>(getSections()); |
| clearSections(); |
| int idx = 0; |
| for (Section s : l) { |
| if (idx++ != 1) { |
| addSection(s); |
| } |
| } |
| } |
| |
| /** |
| * Throws an {@link UnsupportedOperationException} with a message text |
| * telling which functionality is not yet implemented. |
| * |
| * @param msg text telling was leaves to be implemented, e.g. |
| * "Reading byte arrays". |
| */ |
| private void notYetImplemented(final String msg) { |
| throw new UnsupportedOperationException(msg + " is not yet implemented."); |
| } |
| } |