2006-03-03 11:57:55 -05:00
|
|
|
/* ====================================================================
|
2006-12-22 14:18:16 -05:00
|
|
|
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
|
2006-03-03 11:57:55 -05:00
|
|
|
|
|
|
|
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;
|
2008-08-12 14:44:50 -04:00
|
|
|
import java.util.Set;
|
2006-03-03 11:57:55 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
import org.apache.commons.collections4.bidimap.TreeBidiMap;
|
2006-03-03 11:57:55 -05:00
|
|
|
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Maintains the instances of {@link CustomProperty} that belong to a
|
2006-03-03 11:57:55 -05:00
|
|
|
* {@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
|
2016-11-27 15:19:18 -05:00
|
|
|
* typed values.<p>
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* While this class provides a simple API to custom properties, it ignores
|
2006-03-03 11:57:55 -05:00
|
|
|
* 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
|
2016-11-27 15:19:18 -05:00
|
|
|
* such property sets, use HPSF's low-level access methods.<p>
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* An application can call the {@link #isPure} method to check whether a
|
2006-03-03 11:57:55 -05:00
|
|
|
* property set parsed by {@link CustomProperties} is still pure (i.e.
|
2016-11-27 15:19:18 -05:00
|
|
|
* unmodified) or whether one or more properties have been dropped.<p>
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* This class is not thread-safe; concurrent access to instances of this
|
|
|
|
* class must be synchronized.<p>
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* 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.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2010-01-13 10:42:53 -05:00
|
|
|
@SuppressWarnings("serial")
|
2016-11-27 15:19:18 -05:00
|
|
|
public class CustomProperties extends HashMap<Long,CustomProperty> {
|
2006-03-03 11:57:55 -05:00
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Maps property IDs to property names and vice versa.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
private final TreeBidiMap<Long,String> dictionary = new TreeBidiMap<Long,String>();
|
2006-03-03 11:57:55 -05:00
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Tells whether this object is pure or not.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
|
|
|
private boolean isPure = true;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Puts a {@link CustomProperty} into this map. It is assumed that the
|
2006-03-03 11:57:55 -05:00
|
|
|
* {@link CustomProperty} already has a valid ID. Otherwise use
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@link #put(CustomProperty)}.
|
2016-07-03 14:25:05 -04:00
|
|
|
*
|
|
|
|
* @param name the property name
|
|
|
|
* @param cp the property
|
|
|
|
*
|
|
|
|
* @return the previous property stored under this name
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public CustomProperty put(final String name, final CustomProperty cp) {
|
|
|
|
if (name == null) {
|
2006-03-03 11:57:55 -05:00
|
|
|
/* Ignoring a property without a name. */
|
|
|
|
isPure = false;
|
|
|
|
return null;
|
|
|
|
}
|
2016-11-27 15:19:18 -05:00
|
|
|
|
|
|
|
if (!name.equals(cp.getName())) {
|
2006-03-03 11:57:55 -05:00
|
|
|
throw new IllegalArgumentException("Parameter \"name\" (" + name +
|
|
|
|
") and custom property's name (" + cp.getName() +
|
|
|
|
") do not match.");
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2006-03-03 11:57:55 -05:00
|
|
|
|
|
|
|
/* Register name and ID in the dictionary. Mapping in both directions is possible. If there is already a */
|
2016-11-27 15:19:18 -05:00
|
|
|
super.remove(dictionary.getKey(name));
|
|
|
|
dictionary.put(cp.getID(), name);
|
2006-03-03 11:57:55 -05:00
|
|
|
|
|
|
|
/* Put the custom property into this map. */
|
2016-11-27 15:19:18 -05:00
|
|
|
return super.put(cp.getID(), cp);
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* 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:
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2006-03-03 11:57:55 -05:00
|
|
|
* <ul>
|
2016-11-27 15:19:18 -05:00
|
|
|
* <li>If there is already a property with the same name, take the ID
|
|
|
|
* of that property.
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* <li>Otherwise find the highest ID and use its value plus one.
|
2006-03-03 11:57:55 -05:00
|
|
|
* </ul>
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2006-03-03 11:57:55 -05:00
|
|
|
* @param customProperty
|
2016-11-27 15:19:18 -05:00
|
|
|
* @return If there was already a property with the same name, the old property
|
2006-03-03 11:57:55 -05:00
|
|
|
* @throws ClassCastException
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
private Object put(final CustomProperty customProperty) throws ClassCastException {
|
2006-03-03 11:57:55 -05:00
|
|
|
final String name = customProperty.getName();
|
|
|
|
|
|
|
|
/* Check whether a property with this name is in the map already. */
|
2016-11-27 15:19:18 -05:00
|
|
|
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);
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
return this.put(name, customProperty);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Removes a custom property.
|
2009-10-08 18:29:41 -04:00
|
|
|
* @param name The name of the custom property to remove
|
2016-11-27 15:19:18 -05:00
|
|
|
* @return The removed property or {@code null} if the specified property was not found.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @see java.util.HashSet#remove(java.lang.Object)
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public Object remove(final String name) {
|
|
|
|
final Long id = dictionary.removeValue(name);
|
2006-03-03 11:57:55 -05:00
|
|
|
return super.remove(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Adds a named string property.
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2006-03-03 11:57:55 -05:00
|
|
|
* @param name The property's name.
|
|
|
|
* @param value The property's value.
|
|
|
|
* @return the property that was stored under the specified name before, or
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@code null} if there was no such property before.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
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));
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Adds a named long property.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param name The property's name.
|
|
|
|
* @param value The property's value.
|
|
|
|
* @return the property that was stored under the specified name before, or
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@code null} if there was no such property before.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
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));
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Adds a named double property.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param name The property's name.
|
|
|
|
* @param value The property's value.
|
|
|
|
* @return the property that was stored under the specified name before, or
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@code null} if there was no such property before.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
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));
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Adds a named integer property.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param name The property's name.
|
|
|
|
* @param value The property's value.
|
|
|
|
* @return the property that was stored under the specified name before, or
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@code null} if there was no such property before.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
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));
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Adds a named boolean property.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param name The property's name.
|
|
|
|
* @param value The property's value.
|
|
|
|
* @return the property that was stored under the specified name before, or
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@code null} if there was no such property before.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
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));
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
2009-10-08 18:29:41 -04:00
|
|
|
|
2006-03-03 11:57:55 -05:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Gets a named value from the custom properties.
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2006-03-03 11:57:55 -05:00
|
|
|
* @param name the name of the value to get
|
2016-11-27 15:19:18 -05:00
|
|
|
* @return the value or {@code null} if a value with the specified
|
2006-03-03 11:57:55 -05:00
|
|
|
* name is not found in the custom properties.
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public Object get(final String name) {
|
|
|
|
final Long id = dictionary.getKey(name);
|
2014-12-28 04:06:12 -05:00
|
|
|
final CustomProperty cp = super.get(id);
|
2006-03-03 11:57:55 -05:00
|
|
|
return cp != null ? cp.getValue() : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Adds a named date property.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param name The property's name.
|
|
|
|
* @param value The property's value.
|
|
|
|
* @return the property that was stored under the specified name before, or
|
2016-11-27 15:19:18 -05:00
|
|
|
* {@code null} if there was no such property before.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
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));
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
2009-10-08 18:29:41 -04:00
|
|
|
|
2006-03-03 11:57:55 -05:00
|
|
|
/**
|
2016-07-03 14:25:05 -04:00
|
|
|
* 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
|
2008-08-12 14:44:50 -04:00
|
|
|
*/
|
2016-07-03 14:25:05 -04:00
|
|
|
@Override
|
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
2008-08-12 14:44:50 -04:00
|
|
|
public Set keySet() {
|
2016-11-27 15:19:18 -05:00
|
|
|
return dictionary.values();
|
2009-10-08 18:29:41 -04:00
|
|
|
}
|
2008-08-12 14:44:50 -04:00
|
|
|
|
2010-01-13 10:42:53 -05:00
|
|
|
/**
|
2016-07-03 14:25:05 -04:00
|
|
|
* Returns a set of all the names of our custom properties
|
|
|
|
*
|
|
|
|
* @return a set of all the names of our custom properties
|
2010-01-13 10:42:53 -05:00
|
|
|
*/
|
|
|
|
public Set<String> nameSet() {
|
2016-11-27 15:19:18 -05:00
|
|
|
return dictionary.values();
|
2010-01-13 10:42:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-07-03 14:25:05 -04:00
|
|
|
* Returns a set of all the IDs of our custom properties
|
|
|
|
*
|
|
|
|
* @return a set of all the IDs of our custom properties
|
2010-01-13 10:42:53 -05:00
|
|
|
*/
|
|
|
|
public Set<String> idSet() {
|
2016-11-27 15:19:18 -05:00
|
|
|
return dictionary.values();
|
2010-01-13 10:42:53 -05:00
|
|
|
}
|
2008-08-12 14:44:50 -04:00
|
|
|
|
|
|
|
|
2009-10-08 18:29:41 -04:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Sets the codepage.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param codepage the codepage
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public void setCodepage(final int codepage) {
|
|
|
|
Property p = new Property(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage);
|
2006-03-03 11:57:55 -05:00
|
|
|
put(new CustomProperty(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Gets the dictionary which contains IDs and names of the named custom
|
|
|
|
* properties.
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2006-03-03 11:57:55 -05:00
|
|
|
* @return the dictionary.
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
Map<Long,String> getDictionary() {
|
|
|
|
return dictionary;
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-01-13 10:42:53 -05:00
|
|
|
* Checks against both String Name and Long ID
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
@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()) {
|
2010-01-13 10:42:53 -05:00
|
|
|
if(cp.getValue() == value) {
|
2016-11-27 15:19:18 -05:00
|
|
|
return true;
|
2010-01-13 10:42:53 -05:00
|
|
|
}
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2010-01-13 10:42:53 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
return false;
|
|
|
|
}
|
2010-01-13 10:42:53 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
/**
|
|
|
|
* Gets the codepage.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @return the codepage or -1 if the codepage is undefined.
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public int getCodepage() {
|
|
|
|
CustomProperty cp = get(PropertyIDMap.PID_CODEPAGE);
|
|
|
|
return (cp == null) ? -1 : (Integer)cp.getValue();
|
2006-03-03 11:57:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Tells whether this {@link CustomProperties} instance is pure or one or
|
2006-03-03 11:57:55 -05:00
|
|
|
* more properties of the underlying low-level property set has been
|
2016-11-27 15:19:18 -05:00
|
|
|
* dropped.
|
2009-10-08 18:29:41 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* @return {@code true} if the {@link CustomProperties} is pure, else
|
|
|
|
* {@code false}.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public boolean isPure() {
|
2006-03-03 11:57:55 -05:00
|
|
|
return isPure;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Sets the purity of the custom property set.
|
2006-03-03 11:57:55 -05:00
|
|
|
*
|
|
|
|
* @param isPure the purity
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public void setPure(final boolean isPure) {
|
2006-03-03 11:57:55 -05:00
|
|
|
this.isPure = isPure;
|
|
|
|
}
|
|
|
|
}
|