diff --git a/pom.xml b/pom.xml index 0df00e01c..a2d921605 100644 --- a/pom.xml +++ b/pom.xml @@ -72,11 +72,6 @@ test 4.12 - - org.apache.commons - commons-collections4 - 4.1 - diff --git a/src/main/java/org/apache/poi/hpsf/CustomProperties.java b/src/main/java/org/apache/poi/hpsf/CustomProperties.java deleted file mode 100644 index c420f1d3a..000000000 --- a/src/main/java/org/apache/poi/hpsf/CustomProperties.java +++ /dev/null @@ -1,350 +0,0 @@ -/* ==================================================================== - 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.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.collections4.bidimap.TreeBidiMap; -import org.apache.poi.hpsf.wellknown.PropertyIDMap; - -/** - * Maintains the instances of {@link CustomProperty} that belong to a - * {@link DocumentSummaryInformation}. The class maintains the names of the - * custom properties in a dictionary. It implements the {@link Map} interface - * and by this provides a simplified view on custom properties: A property's - * name is the key that maps to a typed value. This implementation hides - * property IDs from the developer and regards the property names as keys to - * typed values.

- * - * While this class provides a simple API to custom properties, it ignores - * the fact that not names, but IDs are the real keys to properties. Under the - * hood this class maintains a 1:1 relationship between IDs and names. Therefore - * you should not use this class to process property sets with several IDs - * mapping to the same name or with properties without a name: the result will - * contain only a subset of the original properties. If you really need to deal - * such property sets, use HPSF's low-level access methods.

- * - * An application can call the {@link #isPure} method to check whether a - * property set parsed by {@link CustomProperties} is still pure (i.e. - * unmodified) or whether one or more properties have been dropped.

- * - * This class is not thread-safe; concurrent access to instances of this - * class must be synchronized.

- * - * While this class is roughly HashMap<Long,CustomProperty>, that's the - * internal representation. To external calls, it should appear as - * HashMap<String,Object> mapping between Names and Custom Property Values. - */ -@SuppressWarnings("serial") -public class CustomProperties extends HashMap { - - /** - * Maps property IDs to property names and vice versa. - */ - private final TreeBidiMap dictionary = new TreeBidiMap(); - - /** - * Tells whether this object is pure or not. - */ - private boolean isPure = true; - - - /** - * Puts a {@link CustomProperty} into this map. It is assumed that the - * {@link CustomProperty} already has a valid ID. Otherwise use - * {@link #put(CustomProperty)}. - * - * @param name the property name - * @param cp the property - * - * @return the previous property stored under this name - */ - public CustomProperty put(final String name, final CustomProperty cp) { - if (name == null) { - /* Ignoring a property without a name. */ - isPure = false; - return null; - } - - if (!name.equals(cp.getName())) { - throw new IllegalArgumentException("Parameter \"name\" (" + name + - ") and custom property's name (" + cp.getName() + - ") do not match."); - } - - /* Register name and ID in the dictionary. Mapping in both directions is possible. If there is already a */ - super.remove(dictionary.getKey(name)); - dictionary.put(cp.getID(), name); - - /* Put the custom property into this map. */ - return super.put(cp.getID(), cp); - } - - - - /** - * Puts a {@link CustomProperty} that has not yet a valid ID into this - * map. The method will allocate a suitable ID for the custom property: - * - *

- * - * @param customProperty - * @return If there was already a property with the same name, the old property - * @throws ClassCastException - */ - private Object put(final CustomProperty customProperty) throws ClassCastException { - final String name = customProperty.getName(); - - /* Check whether a property with this name is in the map already. */ - final Long oldId = (name == null) ? null : dictionary.getKey(name); - if (oldId != null) { - customProperty.setID(oldId); - } else { - long lastKey = (dictionary.isEmpty()) ? 0 : dictionary.lastKey(); - customProperty.setID(Math.max(lastKey,PropertyIDMap.PID_MAX) + 1); - } - return this.put(name, customProperty); - } - - - - /** - * Removes a custom property. - * @param name The name of the custom property to remove - * @return The removed property or {@code null} if the specified property was not found. - * - * @see java.util.HashSet#remove(java.lang.Object) - */ - public Object remove(final String name) { - final Long id = dictionary.removeValue(name); - return super.remove(id); - } - - /** - * Adds a named string property. - * - * @param name The property's name. - * @param value The property's value. - * @return the property that was stored under the specified name before, or - * {@code null} if there was no such property before. - */ - public Object put(final String name, final String value) { - final Property p = new Property(-1, Variant.VT_LPWSTR, value); - return put(new CustomProperty(p, name)); - } - - /** - * Adds a named long property. - * - * @param name The property's name. - * @param value The property's value. - * @return the property that was stored under the specified name before, or - * {@code null} if there was no such property before. - */ - public Object put(final String name, final Long value) { - final Property p = new Property(-1, Variant.VT_I8, value); - return put(new CustomProperty(p, name)); - } - - /** - * Adds a named double property. - * - * @param name The property's name. - * @param value The property's value. - * @return the property that was stored under the specified name before, or - * {@code null} if there was no such property before. - */ - public Object put(final String name, final Double value) { - final Property p = new Property(-1, Variant.VT_R8, value); - return put(new CustomProperty(p, name)); - } - - /** - * Adds a named integer property. - * - * @param name The property's name. - * @param value The property's value. - * @return the property that was stored under the specified name before, or - * {@code null} if there was no such property before. - */ - public Object put(final String name, final Integer value) { - final Property p = new Property(-1, Variant.VT_I4, value); - return put(new CustomProperty(p, name)); - } - - /** - * Adds a named boolean property. - * - * @param name The property's name. - * @param value The property's value. - * @return the property that was stored under the specified name before, or - * {@code null} if there was no such property before. - */ - public Object put(final String name, final Boolean value) { - final Property p = new Property(-1, Variant.VT_BOOL, value); - return put(new CustomProperty(p, name)); - } - - - /** - * Gets a named value from the custom properties. - * - * @param name the name of the value to get - * @return the value or {@code null} if a value with the specified - * name is not found in the custom properties. - */ - public Object get(final String name) { - final Long id = dictionary.getKey(name); - final CustomProperty cp = super.get(id); - return cp != null ? cp.getValue() : null; - } - - - - /** - * Adds a named date property. - * - * @param name The property's name. - * @param value The property's value. - * @return the property that was stored under the specified name before, or - * {@code null} if there was no such property before. - */ - public Object put(final String name, final Date value) { - final Property p = new Property(-1, Variant.VT_FILETIME, value); - return put(new CustomProperty(p, name)); - } - - /** - * Returns a set of all the names of our custom properties. - * Equivalent to {@link #nameSet()} - * - * @return a set of all the names of our custom properties - */ - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Set keySet() { - return dictionary.values(); - } - - /** - * Returns a set of all the names of our custom properties - * - * @return a set of all the names of our custom properties - */ - public Set nameSet() { - return dictionary.values(); - } - - /** - * Returns a set of all the IDs of our custom properties - * - * @return a set of all the IDs of our custom properties - */ - public Set idSet() { - return dictionary.values(); - } - - - /** - * Sets the codepage. - * - * @param codepage the codepage - */ - public void setCodepage(final int codepage) { - Property p = new Property(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); - put(new CustomProperty(p)); - } - - - - /** - *

Gets the dictionary which contains IDs and names of the named custom - * properties. - * - * @return the dictionary. - */ - Map getDictionary() { - return dictionary; - } - - - /** - * Checks against both String Name and Long ID - */ - @Override - public boolean containsKey(Object key) { - return ((key instanceof Long && dictionary.containsKey(key)) || dictionary.containsValue(key)); - } - - /** - * Checks against both the property, and its values. - */ - @Override - public boolean containsValue(Object value) { - if(value instanceof CustomProperty) { - return super.containsValue(value); - } - - for(CustomProperty cp : super.values()) { - if(cp.getValue() == value) { - return true; - } - } - - return false; - } - - /** - * Gets the codepage. - * - * @return the codepage or -1 if the codepage is undefined. - */ - public int getCodepage() { - CustomProperty cp = get(PropertyIDMap.PID_CODEPAGE); - return (cp == null) ? -1 : (Integer)cp.getValue(); - } - - /** - * Tells whether this {@link CustomProperties} instance is pure or one or - * more properties of the underlying low-level property set has been - * dropped. - * - * @return {@code true} if the {@link CustomProperties} is pure, else - * {@code false}. - */ - public boolean isPure() { - return isPure; - } - - /** - * Sets the purity of the custom property set. - * - * @param isPure the purity - */ - public void setPure(final boolean isPure) { - this.isPure = isPure; - } -} diff --git a/src/main/java/org/apache/poi/hpsf/DocumentSummaryInformation.java b/src/main/java/org/apache/poi/hpsf/DocumentSummaryInformation.java index f63ab8d92..fac3ffb7e 100644 --- a/src/main/java/org/apache/poi/hpsf/DocumentSummaryInformation.java +++ b/src/main/java/org/apache/poi/hpsf/DocumentSummaryInformation.java @@ -718,66 +718,6 @@ public class DocumentSummaryInformation extends SpecialPropertySet { 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 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 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. */ diff --git a/src/main/java/org/apache/poi/hpsf/Section.java b/src/main/java/org/apache/poi/hpsf/Section.java index 306e14a22..4e5ab23be 100644 --- a/src/main/java/org/apache/poi/hpsf/Section.java +++ b/src/main/java/org/apache/poi/hpsf/Section.java @@ -25,7 +25,6 @@ import java.util.Date; import java.util.Map; import java.util.TreeMap; -import org.apache.commons.collections4.bidimap.TreeBidiMap; import org.apache.poi.hpsf.wellknown.PropertyIDMap; import org.apache.poi.hpsf.wellknown.SectionIDMap; import org.apache.poi.util.CodePageUtil; @@ -115,136 +114,8 @@ public class Section { * @exception UnsupportedEncodingException if the section's codepage is not * supported. */ - @SuppressWarnings("unchecked") public Section(final byte[] src, final int offset) throws UnsupportedEncodingException { - int o1 = offset; - - /* - * Read the format ID. - */ - formatID = new ClassID(src, o1); - o1 += ClassID.LENGTH; - - /* - * Read the offset from the stream's start and positions to - * the section header. - */ - this.offset = LittleEndian.getUInt(src, o1); - o1 = (int) this.offset; - - /* - * Read the section length. - */ - size = (int) LittleEndian.getUInt(src, o1); - o1 += LittleEndian.INT_SIZE; - - /* - * Read the number of properties. - */ - final int propertyCount = (int) LittleEndian.getUInt(src, o1); - o1 += LittleEndian.INT_SIZE; - - /* - * Read the properties. The offset is positioned at the first - * entry of the property list. There are two problems: - * - * 1. For each property we have to find out its length. In the - * property list we find each property's ID and its offset relative - * to the section's beginning. Unfortunately the properties in the - * property list need not to be in ascending order, so it is not - * possible to calculate the length as - * (offset of property(i+1) - offset of property(i)). Before we can - * that we first have to sort the property list by ascending offsets. - * - * 2. We have to read the property with ID 1 before we read other - * properties, at least before other properties containing strings. - * The reason is that property 1 specifies the codepage. If it is - * 1200, all strings are in Unicode. In other words: Before we can - * read any strings we have to know whether they are in Unicode or - * not. Unfortunately property 1 is not guaranteed to be the first in - * a section. - * - * The algorithm below reads the properties in two passes: The first - * one looks for property ID 1 and extracts the codepage number. The - * seconds pass reads the other properties. - */ - /* Pass 1: Read the property list. */ - int pass1Offset = o1; - long cpOffset = -1; - final TreeBidiMap offset2Id = new TreeBidiMap(); - for (int i = 0; i < propertyCount; i++) { - /* Read the property ID. */ - long id = LittleEndian.getUInt(src, pass1Offset); - pass1Offset += LittleEndian.INT_SIZE; - - /* Offset from the section's start. */ - long off = LittleEndian.getUInt(src, pass1Offset); - pass1Offset += LittleEndian.INT_SIZE; - - offset2Id.put(off, id); - - if (id == PropertyIDMap.PID_CODEPAGE) { - cpOffset = off; - } - } - - /* Look for the codepage. */ - int codepage = -1; - if (cpOffset != -1) { - /* Read the property's value type. It must be VT_I2. */ - long o = this.offset + cpOffset; - final long type = LittleEndian.getUInt(src, (int)o); - o += LittleEndian.INT_SIZE; - - if (type != Variant.VT_I2) { - throw new HPSFRuntimeException - ("Value type of property ID 1 is not VT_I2 but " + - type + "."); - } - - /* Read the codepage number. */ - codepage = LittleEndian.getUShort(src, (int)o); - } - - - /* Pass 2: Read all properties - including the codepage property, - * if available. */ - for (Map.Entry me : offset2Id.entrySet()) { - long off = me.getKey(); - long id = me.getValue(); - Property p; - if (id == PropertyIDMap.PID_CODEPAGE) { - p = new Property(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); - } else { - int pLen = propLen(offset2Id, off, size); - long o = this.offset + off; - p = new Property(id, src, o, pLen, codepage); - } - properties.put(id, p); - } - - /* - * Extract the dictionary (if available). - */ - dictionary = (Map) getProperty(0); - } - - /** - * Retrieves the length of the given property (by key) - * - * @param offset2Id the offset to id map - * @param entryOffset the current entry key - * @param maxSize the maximum offset/size of the section stream - * @return the length of the current property - */ - private static int propLen( - TreeBidiMap offset2Id, - Long entryOffset, - long maxSize) { - Long nextKey = offset2Id.nextKey(entryOffset); - long begin = entryOffset; - long end = (nextKey != null) ? nextKey : maxSize; - return (int)(end - begin); + throw new UnsupportedEncodingException("support for reading these has been removed in poi-fast-calc"); } diff --git a/src/main/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java b/src/main/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java index 36c3f3a9c..b84b169d3 100644 --- a/src/main/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java +++ b/src/main/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java @@ -23,7 +23,6 @@ import java.io.IOException; import org.apache.poi.POIDocument; import org.apache.poi.POIOLE2TextExtractor; import org.apache.poi.POITextExtractor; -import org.apache.poi.hpsf.CustomProperties; import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.HPSFPropertiesOnlyDocument; import org.apache.poi.hpsf.Property; @@ -64,15 +63,6 @@ public class HPSFPropertiesExtractor extends POIOLE2TextExtractor { // Normal properties text.append( getPropertiesText(dsi) ); - // Now custom ones - CustomProperties cps = dsi == null ? null : dsi.getCustomProperties(); - if (cps != null) { - for (String key : cps.nameSet()) { - String val = getPropertyValueText(cps.get(key)); - text.append(key).append(" = ").append(val).append("\n"); - } - } - // All done return text.toString(); }