bug 22195, ClassID support, by Michael Zalewski

PR:
Obtained from:
Submitted by:
Reviewed by:


git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353428 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Avik Sengupta 2003-10-31 16:33:46 +00:00
parent d6fac7a361
commit f23535d9f5
5 changed files with 289 additions and 26 deletions

View File

@ -56,6 +56,8 @@
package org.apache.poi.hpsf; package org.apache.poi.hpsf;
import java.io.*; import java.io.*;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
/** /**
@ -105,8 +107,14 @@ public class ClassID
public final static int LENGTH = 16; /** <p>The number of bytes occupied by this object in the byte
* stream.</p> */
public static final int LENGTH = 16;
/**
* @return The number of bytes occupied by this object in the byte
* stream.
*/
public int length() public int length()
{ {
return LENGTH; return LENGTH;
@ -117,6 +125,8 @@ public class ClassID
/** /**
* <p>Gets the bytes making out the class ID. They are returned in * <p>Gets the bytes making out the class ID. They are returned in
* correct order, i.e. big-endian.</p> * correct order, i.e. big-endian.</p>
*
* @return the bytes making out the class ID.
*/ */
public byte[] getBytes() public byte[] getBytes()
{ {
@ -170,13 +180,17 @@ public class ClassID
* *
* @param offset The offset within the <var>dst</var> byte array. * @param offset The offset within the <var>dst</var> byte array.
* *
* @throws ArrayIndexOutOfBoundsException if there is not enough * @exception ArrayStoreException if there is not enough room for the class
* room for the class ID in the byte array. There must be at least * ID 16 bytes in the byte array after the <var>offset</var> position.
* 16 bytes in the byte array after the <var>offset</var>
* position.
*/ */
public void write(final byte[] dst, final int offset) public void write(final byte[] dst, final int offset)
throws ArrayStoreException
{ {
/* Check array size: */
if (dst.length < 16)
throw new ArrayStoreException
("Destination byte[] must have room for at least 16 bytes, " +
"but has a length of only " + dst.length + ".");
/* Write double word. */ /* Write double word. */
dst[0 + offset] = bytes[3]; dst[0 + offset] = bytes[3];
dst[1 + offset] = bytes[2]; dst[1 + offset] = bytes[2];
@ -196,4 +210,45 @@ public class ClassID
dst[i + offset] = bytes[i]; dst[i + offset] = bytes[i];
} }
/**
* <p>Checks whether this <code>ClassID</code> is equal to another
* object.</p>
*
* @param o the object to compare this <code>PropertySet</code> with
* @return <code>true</code> if the objects are equal, else
* <code>false</code>.</p>
*/
public boolean equals(final Object o)
{
if (o == null || !(o instanceof ClassID))
return false;
final ClassID cid = (ClassID) o;
if (bytes.length != cid.bytes.length)
return false;
for (int i = 0; i < bytes.length; i++)
if (bytes[i] != cid.bytes[i])
return false;
return true;
}
/**
* Returns a human readable representation of the Class ID
* in standard format <code>"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"</code>
* @return String representation of the Class ID represented
* by this object.
*/
public String toString()
{
StringBuffer sbClassId = new StringBuffer( 38);
sbClassId.append( '{');
for( int i=0; i < 16; i++) {
sbClassId.append( HexDump.toHex( bytes[ i]));
if( i == 3 || i == 5 || i == 7 || i == 9) {
sbClassId.append( '-');
}
}
sbClassId.append( '}');
return sbClassId.toString();
}
} }

View File

@ -59,6 +59,8 @@ import java.io.*;
import java.util.*; import java.util.*;
import org.apache.poi.hpsf.ClassID;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable; import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.util.ByteField; import org.apache.poi.util.ByteField;
@ -87,6 +89,8 @@ public abstract class Property
static final private int _previous_property_offset = 0x44; static final private int _previous_property_offset = 0x44;
static final private int _next_property_offset = 0x48; static final private int _next_property_offset = 0x48;
static final private int _child_property_offset = 0x4C; static final private int _child_property_offset = 0x4C;
static final private int _storage_clsid_offset = 0x50;
static final private int _user_flags_offset = 0x60;
static final private int _seconds_1_offset = 0x64; static final private int _seconds_1_offset = 0x64;
static final private int _days_1_offset = 0x68; static final private int _days_1_offset = 0x68;
static final private int _seconds_2_offset = 0x6C; static final private int _seconds_2_offset = 0x6C;
@ -107,6 +111,8 @@ public abstract class Property
private IntegerField _previous_property; private IntegerField _previous_property;
private IntegerField _next_property; private IntegerField _next_property;
private IntegerField _child_property; private IntegerField _child_property;
private ClassID _storage_clsid;
private IntegerField _user_flags;
private IntegerField _seconds_1; private IntegerField _seconds_1;
private IntegerField _days_1; private IntegerField _days_1;
private IntegerField _seconds_2; private IntegerField _seconds_2;
@ -136,6 +142,8 @@ public abstract class Property
_NO_INDEX, _raw_data); _NO_INDEX, _raw_data);
_child_property = new IntegerField(_child_property_offset, _child_property = new IntegerField(_child_property_offset,
_NO_INDEX, _raw_data); _NO_INDEX, _raw_data);
_storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
_user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
_seconds_1 = new IntegerField(_seconds_1_offset, 0, _seconds_1 = new IntegerField(_seconds_1_offset, 0,
_raw_data); _raw_data);
_days_1 = new IntegerField(_days_1_offset, 0, _raw_data); _days_1 = new IntegerField(_days_1_offset, 0, _raw_data);
@ -173,6 +181,8 @@ public abstract class Property
_raw_data); _raw_data);
_child_property = new IntegerField(_child_property_offset, _child_property = new IntegerField(_child_property_offset,
_raw_data); _raw_data);
_storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
_user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
_seconds_1 = new IntegerField(_seconds_1_offset, _raw_data); _seconds_1 = new IntegerField(_seconds_1_offset, _raw_data);
_days_1 = new IntegerField(_days_1_offset, _raw_data); _days_1 = new IntegerField(_days_1_offset, _raw_data);
_seconds_2 = new IntegerField(_seconds_2_offset, _raw_data); _seconds_2 = new IntegerField(_seconds_2_offset, _raw_data);
@ -295,12 +305,21 @@ public abstract class Property
abstract public boolean isDirectory(); abstract public boolean isDirectory();
/**
* Sets the storage clsid, which is the Class ID of a COM object which
* reads and writes this stream
* @return storage Class ID for this property stream
*/
public ClassID getStorageClsid()
{
return _storage_clsid;
}
/** /**
* Set the name; silently truncates the name if it's too long. * Set the name; silently truncates the name if it's too long.
* *
* @param name the new name * @param name the new name
*/ */
protected final void setName(final String name) protected final void setName(final String name)
{ {
char[] char_array = name.toCharArray(); char[] char_array = name.toCharArray();
@ -327,6 +346,20 @@ public abstract class Property
* LittleEndianConsts.SHORT_SIZE), _raw_data); * LittleEndianConsts.SHORT_SIZE), _raw_data);
} }
/**
* Sets the storage class ID for this property stream. This is the Class ID
* of the COM object which can read and write this property stream
* @param clsidStorage Storage Class ID
*/
public void setStorageClsid( ClassID clsidStorage)
{
_storage_clsid = clsidStorage;
if( clsidStorage == null) {
Arrays.fill( _raw_data, _storage_clsid_offset, _storage_clsid_offset + ClassID.LENGTH, (byte) 0);
} else {
clsidStorage.write( _raw_data, _storage_clsid_offset);
}
}
/** /**
* Set the property type. Makes no attempt to validate the value. * Set the property type. Makes no attempt to validate the value.
* *

View File

@ -0,0 +1,171 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache POI" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache POI", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.poi.hpsf.basic;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.apache.poi.hpsf.ClassID;
/**
* <p>Tests ClassID structure.</p>
*
* @author Michael Zalewski (zalewski@optonline.net)
*/
public class TestClassID extends TestCase
{
/**
* <p>Constructor</p>
*
* @param name the test case's name
*/
public TestClassID(final String name)
{
super(name);
}
/**
* Various tests of overridden .equals()
*/
public void testEquals()
{
ClassID clsidTest1 = new ClassID(
new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }
, 0
);
ClassID clsidTest2 = new ClassID(
new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }
, 0
);
ClassID clsidTest3 = new ClassID(
new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11 }
, 0
);
Assert.assertEquals( clsidTest1, clsidTest1);
Assert.assertEquals( clsidTest1, clsidTest2);
Assert.assertFalse( clsidTest1.equals( clsidTest3));
Assert.assertFalse( clsidTest1.equals( null));
}
/**
* Try to write to a buffer that is too small. This should
* throw an Exception
*/
public void testWriteArrayStoreException()
{
ClassID clsidTest = new ClassID(
new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }
, 0
);
boolean bExceptionOccurred = false;
try {
clsidTest.write( new byte[ 15], 0);
} catch( Exception e) {
bExceptionOccurred = true;
}
Assert.assertTrue( bExceptionOccurred);
bExceptionOccurred = false;
try {
clsidTest.write( new byte[ 16], 1);
} catch( Exception e) {
bExceptionOccurred = true;
}
Assert.assertTrue( bExceptionOccurred);
// These should work without throwing an Exception
bExceptionOccurred = false;
try {
clsidTest.write( new byte[ 16], 0);
clsidTest.write( new byte[ 17], 1);
} catch( Exception e) {
bExceptionOccurred = true;
}
Assert.assertFalse( bExceptionOccurred);
}
/**
* <p>Tests the {@link PropertySet} methods. The test file has two
* property set: the first one is a {@link SummaryInformation},
* the second one is a {@link DocumentSummaryInformation}.</p>
*/
public void testClassID()
{
ClassID clsidTest = new ClassID(
new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }
, 0
);
Assert.assertEquals(
clsidTest.toString().toUpperCase()
, "{04030201-0605-0807-090A-0B0C0D0E0F10}"
);
}
/**
* <p>Runs the test cases stand-alone.</p>
*/
public static void main(final String[] args)
{
System.setProperty("HPSF.testdata.path",
"./src/testcases/org/apache/poi/hpsf/data");
junit.textui.TestRunner.run(TestClassID.class);
}
}

View File

@ -150,6 +150,7 @@ public class TestDocumentProperty
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x57, ( byte ) 0x00, ( byte ) 0x6F, ( byte ) 0x00, ( byte ) 0x57, ( byte ) 0x00, ( byte ) 0x6F, ( byte ) 0x00,
( byte ) 0x72, ( byte ) 0x00, ( byte ) 0x6B, ( byte ) 0x00, ( byte ) 0x72, ( byte ) 0x00, ( byte ) 0x6B, ( byte ) 0x00,
( byte ) 0x62, ( byte ) 0x00, ( byte ) 0x6F, ( byte ) 0x00, ( byte ) 0x62, ( byte ) 0x00, ( byte ) 0x6F, ( byte ) 0x00,
@ -182,6 +183,7 @@ public class TestDocumentProperty
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x05, ( byte ) 0x00, ( byte ) 0x53, ( byte ) 0x00, ( byte ) 0x05, ( byte ) 0x00, ( byte ) 0x53, ( byte ) 0x00,
( byte ) 0x75, ( byte ) 0x00, ( byte ) 0x6D, ( byte ) 0x00, ( byte ) 0x75, ( byte ) 0x00, ( byte ) 0x6D, ( byte ) 0x00,
( byte ) 0x6D, ( byte ) 0x00, ( byte ) 0x61, ( byte ) 0x00, ( byte ) 0x6D, ( byte ) 0x00, ( byte ) 0x61, ( byte ) 0x00,
@ -214,6 +216,7 @@ public class TestDocumentProperty
( byte ) 0x08, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x08, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x05, ( byte ) 0x00, ( byte ) 0x44, ( byte ) 0x00, ( byte ) 0x05, ( byte ) 0x00, ( byte ) 0x44, ( byte ) 0x00,
( byte ) 0x6F, ( byte ) 0x00, ( byte ) 0x63, ( byte ) 0x00, ( byte ) 0x6F, ( byte ) 0x00, ( byte ) 0x63, ( byte ) 0x00,
( byte ) 0x75, ( byte ) 0x00, ( byte ) 0x6D, ( byte ) 0x00, ( byte ) 0x75, ( byte ) 0x00, ( byte ) 0x6D, ( byte ) 0x00,

View File

@ -217,11 +217,11 @@ public class TestRootProperty
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00
}; };
verifyReadingProperty(0, input, 0, "Root Entry"); verifyReadingProperty(0, input, 0, "Root Entry", "{00020820-0000-0000-C000-000000000046}");
} }
private void verifyReadingProperty(int index, byte [] input, int offset, private void verifyReadingProperty(int index, byte [] input, int offset,
String name) String name, String sClsId)
throws IOException throws IOException
{ {
RootProperty property = new RootProperty(index, input, RootProperty property = new RootProperty(index, input,
@ -242,6 +242,7 @@ public class TestRootProperty
assertEquals(index, property.getIndex()); assertEquals(index, property.getIndex());
assertEquals(name, property.getName()); assertEquals(name, property.getName());
assertTrue(!property.getChildren().hasNext()); assertTrue(!property.getChildren().hasNext());
assertEquals(property.getStorageClsid().toString(), sClsId);
} }
/** /**