2004-04-09 09:05:39 -04: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
|
2004-04-09 09:05:39 -04: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.
|
|
|
|
==================================================================== */
|
2009-06-01 17:07:20 -04:00
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
package org.apache.poi.hpsf;
|
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.OutputStream;
|
2003-12-02 12:46:01 -05:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2015-09-01 15:36:22 -04:00
|
|
|
import java.nio.charset.Charset;
|
2016-11-27 15:19:18 -05:00
|
|
|
import java.util.Arrays;
|
2011-10-02 04:58:11 -04:00
|
|
|
import java.util.LinkedHashMap;
|
2003-08-02 15:02:28 -04:00
|
|
|
import java.util.Map;
|
2003-08-23 11:12:22 -04:00
|
|
|
|
2013-06-26 14:20:37 -04:00
|
|
|
import org.apache.poi.util.CodePageUtil;
|
2003-12-02 12:46:01 -05:00
|
|
|
import org.apache.poi.util.HexDump;
|
2002-05-26 18:18:40 -04:00
|
|
|
import org.apache.poi.util.LittleEndian;
|
2008-02-08 06:55:43 -05:00
|
|
|
import org.apache.poi.util.POILogFactory;
|
|
|
|
import org.apache.poi.util.POILogger;
|
2002-02-13 23:00:59 -05:00
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* A property in a {@link Section} of a {@link PropertySet}.<p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* The property's {@code ID} gives the property a meaning
|
2002-07-18 11:51:39 -04:00
|
|
|
* in the context of its {@link Section}. Each {@link Section} spans
|
2016-11-27 15:19:18 -05:00
|
|
|
* its own name space of property IDs.<p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* The property's {@code type} determines how its
|
|
|
|
* {@code value} is interpreted. For example, if the type is
|
2002-07-18 11:51:39 -04:00
|
|
|
* {@link Variant#VT_LPSTR} (byte string), the value consists of a
|
2002-07-22 04:25:19 -04:00
|
|
|
* DWord telling how many bytes the string contains. The bytes follow
|
|
|
|
* immediately, including any null bytes that terminate the
|
2002-07-18 11:51:39 -04:00
|
|
|
* string. The type {@link Variant#VT_I4} denotes a four-byte integer
|
2016-11-27 15:19:18 -05:00
|
|
|
* value, {@link Variant#VT_FILETIME} some date and time (of a file).<p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* Please note that not all {@link Variant} types yet. This might change
|
2003-08-30 05:13:53 -04:00
|
|
|
* over time but largely depends on your feedback so that the POI team knows
|
|
|
|
* which variant types are really needed. So please feel free to submit error
|
2016-11-27 15:19:18 -05:00
|
|
|
* reports or patches for the types you need.
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2002-07-18 11:51:39 -04:00
|
|
|
* @see Section
|
|
|
|
* @see Variant
|
2016-11-27 15:19:18 -05:00
|
|
|
* @see <a href="https://msdn.microsoft.com/en-us/library/dd942421.aspx">
|
|
|
|
* [MS-OLEPS]: Object Linking and Embedding (OLE) Property Set Data Structures</a>
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public class Property {
|
2002-02-13 23:00:59 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
/** The property's ID. */
|
|
|
|
private long id;
|
2002-02-13 23:00:59 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
/** The property's type. */
|
|
|
|
private long type;
|
2002-05-11 10:47:24 -04:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
/** The property's value. */
|
2016-12-07 18:45:38 -05:00
|
|
|
private Object value;
|
2002-05-11 10:47:24 -04:00
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Creates an empty property. It must be filled using the set method to be usable.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public Property() {
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Creates a {@code Property} as a copy of an existing {@code Property}.
|
2002-05-11 10:47:24 -04:00
|
|
|
*
|
2016-11-27 15:19:18 -05:00
|
|
|
* @param p The property to copy.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public Property(Property p) {
|
|
|
|
this(p.id, p.type, p.value);
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|
2016-11-27 15:19:18 -05:00
|
|
|
|
2006-03-03 11:57:55 -05:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Creates a property.
|
2009-08-18 12:50:24 -04:00
|
|
|
*
|
2006-03-03 11:57:55 -05:00
|
|
|
* @param id the property's ID.
|
|
|
|
* @param type the property's type, see {@link Variant}.
|
2008-02-08 06:55:43 -05:00
|
|
|
* @param value the property's value. Only certain types are allowed, see
|
|
|
|
* {@link Variant}.
|
2006-03-03 11:57:55 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public Property(final long id, final long type, final Object value) {
|
2006-03-03 11:57:55 -05:00
|
|
|
this.id = id;
|
|
|
|
this.type = type;
|
|
|
|
this.value = value;
|
|
|
|
}
|
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Creates a {@link Property} instance by reading its bytes
|
|
|
|
* from the property set stream.
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2002-07-18 11:51:39 -04:00
|
|
|
* @param id The property's ID.
|
|
|
|
* @param src The bytes the property set stream consists of.
|
|
|
|
* @param offset The property's type/value pair's offset in the
|
|
|
|
* section.
|
|
|
|
* @param length The property's type/value pair's length in bytes.
|
2002-12-10 01:15:20 -05:00
|
|
|
* @param codepage The section's and thus the property's
|
|
|
|
* codepage. It is needed only when reading string values.
|
2003-12-02 12:46:01 -05:00
|
|
|
* @exception UnsupportedEncodingException if the specified codepage is not
|
2004-06-22 12:11:39 -04:00
|
|
|
* supported.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public Property(final long id, final byte[] src, final long offset, final int length, final int codepage)
|
|
|
|
throws UnsupportedEncodingException {
|
2002-02-13 23:00:59 -05:00
|
|
|
this.id = id;
|
|
|
|
|
2002-05-11 10:47:24 -04:00
|
|
|
/*
|
2002-12-10 01:15:20 -05:00
|
|
|
* ID 0 is a special case since it specifies a dictionary of
|
|
|
|
* property IDs and property names.
|
2002-05-11 10:47:24 -04:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
if (id == 0) {
|
2002-12-10 01:15:20 -05:00
|
|
|
value = readDictionary(src, offset, length, codepage);
|
2002-02-13 23:00:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-05-11 10:47:24 -04:00
|
|
|
int o = (int) offset;
|
|
|
|
type = LittleEndian.getUInt(src, o);
|
|
|
|
o += LittleEndian.INT_SIZE;
|
2002-02-13 23:00:59 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
try {
|
2003-12-02 12:46:01 -05:00
|
|
|
value = VariantSupport.read(src, o, length, (int) type, codepage);
|
2016-11-27 15:19:18 -05:00
|
|
|
} catch (UnsupportedVariantTypeException ex) {
|
2003-08-30 05:13:53 -04:00
|
|
|
VariantSupport.writeUnsupportedTypeMessage(ex);
|
2003-08-23 11:12:22 -04:00
|
|
|
value = ex.getValue();
|
2003-08-02 15:02:28 -04:00
|
|
|
}
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-08-03 16:16:46 -04:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Returns the property's ID.
|
|
|
|
*
|
|
|
|
* @return The ID value
|
|
|
|
*/
|
|
|
|
public long getID() {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the property's ID.
|
|
|
|
*
|
|
|
|
* @param id the ID
|
|
|
|
*/
|
|
|
|
public void setID(final long id) {
|
|
|
|
this.id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the property's type.
|
|
|
|
*
|
|
|
|
* @return The type value
|
|
|
|
*/
|
|
|
|
public long getType() {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the property's type.
|
|
|
|
*
|
|
|
|
* @param type the property's type
|
|
|
|
*/
|
|
|
|
public void setType(final long type) {
|
|
|
|
this.type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the property's value.
|
|
|
|
*
|
|
|
|
* @return The property's value
|
|
|
|
*/
|
|
|
|
public Object getValue() {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the property's value.
|
|
|
|
*
|
|
|
|
* @param value the property's value
|
2003-08-03 16:16:46 -04:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public void setValue(final Object value) {
|
|
|
|
this.value = value;
|
|
|
|
}
|
|
|
|
|
2003-08-03 16:16:46 -04:00
|
|
|
|
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
|
2003-08-03 16:16:46 -04:00
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Reads a dictionary.
|
2009-08-18 12:50:24 -04:00
|
|
|
*
|
2005-04-01 11:58:00 -05:00
|
|
|
* @param src The byte array containing the bytes making out the dictionary.
|
2016-11-27 15:19:18 -05:00
|
|
|
* @param offset At this offset within {@code src} the dictionary
|
2005-04-01 11:58:00 -05:00
|
|
|
* starts.
|
2002-07-18 11:51:39 -04:00
|
|
|
* @param length The dictionary contains at most this many bytes.
|
2002-12-10 01:15:20 -05:00
|
|
|
* @param codepage The codepage of the string values.
|
2002-07-18 11:51:39 -04:00
|
|
|
* @return The dictonary
|
2005-04-01 11:58:00 -05:00
|
|
|
* @throws UnsupportedEncodingException if the dictionary's codepage is not
|
|
|
|
* (yet) supported.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
protected Map<?, ?> readDictionary(final byte[] src, final long offset, final int length, final int codepage)
|
|
|
|
throws UnsupportedEncodingException {
|
2003-08-02 15:02:28 -04:00
|
|
|
/* Check whether "offset" points into the "src" array". */
|
2016-11-27 15:19:18 -05:00
|
|
|
if (offset < 0 || offset > src.length) {
|
2003-08-02 15:02:28 -04:00
|
|
|
throw new HPSFRuntimeException
|
|
|
|
("Illegal offset " + offset + " while HPSF stream contains " +
|
|
|
|
length + " bytes.");
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2002-12-10 01:15:20 -05:00
|
|
|
int o = (int) offset;
|
2002-05-11 10:47:24 -04:00
|
|
|
|
|
|
|
/*
|
2002-12-10 01:15:20 -05:00
|
|
|
* Read the number of dictionary entries.
|
2002-05-11 10:47:24 -04:00
|
|
|
*/
|
|
|
|
final long nrEntries = LittleEndian.getUInt(src, o);
|
|
|
|
o += LittleEndian.INT_SIZE;
|
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
final Map<Object, Object> m = new LinkedHashMap<Object, Object>((int) nrEntries, (float) 1.0 );
|
2008-02-08 06:55:43 -05:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
try {
|
|
|
|
for (int i = 0; i < nrEntries; i++) {
|
2008-02-08 06:55:43 -05:00
|
|
|
/* The key. */
|
2009-10-08 18:29:41 -04:00
|
|
|
final Long id = Long.valueOf(LittleEndian.getUInt(src, o));
|
2008-02-08 06:55:43 -05:00
|
|
|
o += LittleEndian.INT_SIZE;
|
|
|
|
|
|
|
|
/* The value (a string). The length is the either the
|
|
|
|
* number of (two-byte) characters if the character set is Unicode
|
|
|
|
* or the number of bytes if the character set is not Unicode.
|
|
|
|
* The length includes terminating 0x00 bytes which we have to strip
|
|
|
|
* off to create a Java string. */
|
|
|
|
long sLength = LittleEndian.getUInt(src, o);
|
|
|
|
o += LittleEndian.INT_SIZE;
|
|
|
|
|
|
|
|
/* Read the string. */
|
|
|
|
final StringBuffer b = new StringBuffer();
|
2016-11-27 15:19:18 -05:00
|
|
|
switch (codepage) {
|
2008-02-08 06:55:43 -05:00
|
|
|
case -1:
|
|
|
|
/* Without a codepage the length is equal to the number of
|
|
|
|
* bytes. */
|
2015-09-01 15:36:22 -04:00
|
|
|
b.append(new String(src, o, (int) sLength, Charset.forName("ASCII")));
|
2008-02-08 06:55:43 -05:00
|
|
|
break;
|
2013-06-26 14:20:37 -04:00
|
|
|
case CodePageUtil.CP_UNICODE:
|
2008-02-08 06:55:43 -05:00
|
|
|
/* The length is the number of characters, i.e. the number
|
|
|
|
* of bytes is twice the number of the characters. */
|
|
|
|
final int nrBytes = (int) (sLength * 2);
|
|
|
|
final byte[] h = new byte[nrBytes];
|
|
|
|
for (int i2 = 0; i2 < nrBytes; i2 += 2)
|
|
|
|
{
|
|
|
|
h[i2] = src[o + i2 + 1];
|
|
|
|
h[i2 + 1] = src[o + i2];
|
|
|
|
}
|
2016-11-27 15:19:18 -05:00
|
|
|
b.append(new String(h, 0, nrBytes, CodePageUtil.codepageToEncoding(codepage)));
|
2008-02-08 06:55:43 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* For encodings other than Unicode the length is the number
|
|
|
|
* of bytes. */
|
2016-11-27 15:19:18 -05:00
|
|
|
b.append(new String(src, o, (int) sLength, CodePageUtil.codepageToEncoding(codepage)));
|
2008-02-08 06:55:43 -05:00
|
|
|
break;
|
2005-04-01 11:58:00 -05:00
|
|
|
}
|
2008-02-08 06:55:43 -05:00
|
|
|
|
|
|
|
/* Strip 0x00 characters from the end of the string: */
|
2016-11-27 15:19:18 -05:00
|
|
|
while (b.length() > 0 && b.charAt(b.length() - 1) == 0x00) {
|
2008-02-08 06:55:43 -05:00
|
|
|
b.setLength(b.length() - 1);
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
|
|
|
if (codepage == CodePageUtil.CP_UNICODE) {
|
|
|
|
if (sLength % 2 == 1) {
|
2008-02-08 06:55:43 -05:00
|
|
|
sLength++;
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2008-02-08 06:55:43 -05:00
|
|
|
o += (sLength + sLength);
|
2016-11-27 15:19:18 -05:00
|
|
|
} else {
|
2008-02-08 06:55:43 -05:00
|
|
|
o += sLength;
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2008-02-08 06:55:43 -05:00
|
|
|
m.put(id, b.toString());
|
2005-04-01 11:58:00 -05:00
|
|
|
}
|
2016-11-27 15:19:18 -05:00
|
|
|
} catch (RuntimeException ex) {
|
2008-02-08 06:55:43 -05:00
|
|
|
final POILogger l = POILogFactory.getLogger(getClass());
|
|
|
|
l.log(POILogger.WARN,
|
|
|
|
"The property set's dictionary contains bogus data. "
|
|
|
|
+ "All dictionary entries starting with the one with ID "
|
|
|
|
+ id + " will be ignored.", ex);
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2003-08-02 15:02:28 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Returns the property's size in bytes. This is always a multiple of 4.
|
2003-08-02 15:02:28 -04:00
|
|
|
*
|
|
|
|
* @return the property's size in bytes
|
2009-08-18 12:50:24 -04:00
|
|
|
*
|
2003-08-30 05:13:53 -04:00
|
|
|
* @exception WritingNotSupportedException if HPSF does not yet support the
|
|
|
|
* property's variant type.
|
2003-08-02 15:02:28 -04:00
|
|
|
*/
|
2003-08-30 05:13:53 -04:00
|
|
|
protected int getSize() throws WritingNotSupportedException
|
2003-08-02 15:02:28 -04:00
|
|
|
{
|
2003-08-30 05:13:53 -04:00
|
|
|
int length = VariantSupport.getVariantLength(type);
|
2016-11-27 15:19:18 -05:00
|
|
|
if (length >= 0) {
|
2003-08-30 05:13:53 -04:00
|
|
|
return length; /* Fixed length */
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
|
|
|
if (length == -2) {
|
2003-08-30 05:13:53 -04:00
|
|
|
/* Unknown length */
|
|
|
|
throw new WritingNotSupportedException(type, null);
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
/* Variable length: */
|
2003-08-23 11:12:22 -04:00
|
|
|
final int PADDING = 4; /* Pad to multiples of 4. */
|
2016-11-27 15:19:18 -05:00
|
|
|
switch ((int) type) {
|
|
|
|
case Variant.VT_LPSTR: {
|
2003-08-23 11:12:22 -04:00
|
|
|
int l = ((String) value).length() + 1;
|
|
|
|
int r = l % PADDING;
|
|
|
|
if (r > 0)
|
|
|
|
l += PADDING - r;
|
|
|
|
length += l;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Variant.VT_EMPTY:
|
|
|
|
break;
|
|
|
|
default:
|
2003-08-30 05:13:53 -04:00
|
|
|
throw new WritingNotSupportedException(type, value);
|
2003-08-23 11:12:22 -04:00
|
|
|
}
|
|
|
|
return length;
|
2003-08-02 15:02:28 -04:00
|
|
|
}
|
|
|
|
|
2003-08-03 16:16:46 -04:00
|
|
|
|
|
|
|
|
2003-08-23 11:12:22 -04:00
|
|
|
/**
|
2016-11-27 15:19:18 -05:00
|
|
|
* Compares two properties.<p>
|
|
|
|
*
|
|
|
|
* Please beware that a property with
|
2008-02-08 06:55:43 -05:00
|
|
|
* ID == 0 is a special case: It does not have a type, and its value is the
|
|
|
|
* section's dictionary. Another special case are strings: Two properties
|
2016-11-27 15:19:18 -05:00
|
|
|
* may have the different types Variant.VT_LPSTR and Variant.VT_LPWSTR;
|
2009-08-18 12:50:24 -04:00
|
|
|
*
|
2003-08-23 11:12:22 -04:00
|
|
|
* @see Object#equals(java.lang.Object)
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public boolean equals(final Object o) {
|
2009-08-18 12:50:24 -04:00
|
|
|
if (!(o instanceof Property)) {
|
2003-08-30 05:13:53 -04:00
|
|
|
return false;
|
2009-08-18 12:50:24 -04:00
|
|
|
}
|
2003-08-30 05:13:53 -04:00
|
|
|
final Property p = (Property) o;
|
|
|
|
final Object pValue = p.getValue();
|
2003-09-18 14:56:35 -04:00
|
|
|
final long pId = p.getID();
|
2016-11-27 15:19:18 -05:00
|
|
|
if (id != pId || (id != 0 && !typesAreEqual(type, p.getType()))) {
|
2003-08-30 05:13:53 -04:00
|
|
|
return false;
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
|
|
|
if (value == null && pValue == null) {
|
2003-08-30 05:13:53 -04:00
|
|
|
return true;
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
|
|
|
if (value == null || pValue == null) {
|
2003-08-30 05:13:53 -04:00
|
|
|
return false;
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2003-09-18 14:56:35 -04:00
|
|
|
|
2003-08-30 05:13:53 -04:00
|
|
|
/* It's clear now that both values are non-null. */
|
2009-08-18 12:50:24 -04:00
|
|
|
final Class<?> valueClass = value.getClass();
|
|
|
|
final Class<?> pValueClass = pValue.getClass();
|
2003-08-30 05:13:53 -04:00
|
|
|
if (!(valueClass.isAssignableFrom(pValueClass)) &&
|
2016-11-27 15:19:18 -05:00
|
|
|
!(pValueClass.isAssignableFrom(valueClass))) {
|
2003-08-30 05:13:53 -04:00
|
|
|
return false;
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
2003-08-30 05:13:53 -04:00
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
if (value instanceof byte[]) {
|
|
|
|
return Arrays.equals((byte[]) value, (byte[]) pValue);
|
|
|
|
}
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
return value.equals(pValue);
|
2003-08-03 16:16:46 -04:00
|
|
|
}
|
|
|
|
|
2003-08-23 11:12:22 -04:00
|
|
|
|
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
private boolean typesAreEqual(final long t1, final long t2) {
|
|
|
|
return (t1 == t2 ||
|
2004-08-31 16:45:00 -04:00
|
|
|
(t1 == Variant.VT_LPSTR && t2 == Variant.VT_LPWSTR) ||
|
2016-11-27 15:19:18 -05:00
|
|
|
(t2 == Variant.VT_LPSTR && t1 == Variant.VT_LPWSTR));
|
2004-08-31 16:45:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-08-23 11:12:22 -04:00
|
|
|
/**
|
2003-08-30 05:13:53 -04:00
|
|
|
* @see Object#hashCode()
|
2003-08-23 11:12:22 -04:00
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public int hashCode() {
|
2003-08-30 05:13:53 -04:00
|
|
|
long hashCode = 0;
|
|
|
|
hashCode += id;
|
|
|
|
hashCode += type;
|
2016-11-27 15:19:18 -05:00
|
|
|
if (value != null) {
|
2003-08-30 05:13:53 -04:00
|
|
|
hashCode += value.hashCode();
|
2016-11-27 15:19:18 -05:00
|
|
|
}
|
|
|
|
return (int) (hashCode & 0x0ffffffffL );
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-08-23 11:12:22 -04:00
|
|
|
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @see Object#toString()
|
|
|
|
*/
|
2016-11-27 15:19:18 -05:00
|
|
|
public String toString() {
|
2003-08-30 05:13:53 -04:00
|
|
|
final StringBuffer b = new StringBuffer();
|
|
|
|
b.append(getClass().getName());
|
|
|
|
b.append('[');
|
|
|
|
b.append("id: ");
|
|
|
|
b.append(getID());
|
|
|
|
b.append(", type: ");
|
|
|
|
b.append(getType());
|
2003-12-02 12:46:01 -05:00
|
|
|
final Object value = getValue();
|
2003-08-30 05:13:53 -04:00
|
|
|
b.append(", value: ");
|
2016-11-27 15:19:18 -05:00
|
|
|
if (value instanceof String) {
|
2012-02-15 02:49:25 -05:00
|
|
|
b.append(value.toString());
|
2003-12-02 12:46:01 -05:00
|
|
|
final String s = (String) value;
|
|
|
|
final int l = s.length();
|
|
|
|
final byte[] bytes = new byte[l * 2];
|
2016-11-27 15:19:18 -05:00
|
|
|
for (int i = 0; i < l; i++) {
|
2003-12-02 12:46:01 -05:00
|
|
|
final char c = s.charAt(i);
|
|
|
|
final byte high = (byte) ((c & 0x00ff00) >> 8);
|
|
|
|
final byte low = (byte) ((c & 0x0000ff) >> 0);
|
|
|
|
bytes[i * 2] = high;
|
|
|
|
bytes[i * 2 + 1] = low;
|
|
|
|
}
|
|
|
|
b.append(" [");
|
2012-02-15 02:49:25 -05:00
|
|
|
if(bytes.length > 0) {
|
|
|
|
final String hex = HexDump.dump(bytes, 0L, 0);
|
|
|
|
b.append(hex);
|
|
|
|
}
|
2003-12-02 12:46:01 -05:00
|
|
|
b.append("]");
|
2016-11-27 15:19:18 -05:00
|
|
|
} else if (value instanceof byte[]) {
|
2012-02-15 02:49:25 -05:00
|
|
|
byte[] bytes = (byte[])value;
|
|
|
|
if(bytes.length > 0) {
|
|
|
|
String hex = HexDump.dump(bytes, 0L, 0);
|
|
|
|
b.append(hex);
|
|
|
|
}
|
2016-11-27 15:19:18 -05:00
|
|
|
} else {
|
2012-02-15 02:49:25 -05:00
|
|
|
b.append(value.toString());
|
|
|
|
}
|
2003-08-30 05:13:53 -04:00
|
|
|
b.append(']');
|
|
|
|
return b.toString();
|
2003-08-23 11:12:22 -04:00
|
|
|
}
|
|
|
|
|
2016-11-27 15:19:18 -05:00
|
|
|
/**
|
|
|
|
* Writes the property to an output stream.
|
|
|
|
*
|
|
|
|
* @param out The output stream to write to.
|
|
|
|
* @param codepage The codepage to use for writing non-wide strings
|
|
|
|
* @return the number of bytes written to the stream
|
|
|
|
*
|
|
|
|
* @exception IOException if an I/O error occurs
|
|
|
|
* @exception WritingNotSupportedException if a variant type is to be
|
|
|
|
* written that is not yet supported
|
|
|
|
*/
|
|
|
|
public int write(final OutputStream out, final int codepage)
|
|
|
|
throws IOException, WritingNotSupportedException {
|
|
|
|
int length = 0;
|
|
|
|
long variantType = getType();
|
|
|
|
|
|
|
|
/* Ensure that wide strings are written if the codepage is Unicode. */
|
|
|
|
if (codepage == CodePageUtil.CP_UNICODE && variantType == Variant.VT_LPSTR) {
|
|
|
|
variantType = Variant.VT_LPWSTR;
|
|
|
|
}
|
|
|
|
|
|
|
|
length += TypeWriter.writeUIntToStream(out, variantType);
|
|
|
|
length += VariantSupport.write(out, variantType, getValue(), codepage);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|