You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/11/14 00:01:47 UTC

svn commit: r713852 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/hssf/record/ testcases/org/apache/poi/hssf/record/

Author: josh
Date: Thu Nov 13 15:01:46 2008
New Revision: 713852

URL: http://svn.apache.org/viewvc?rev=713852&view=rev
Log:
Fix for bug 46199 - tweaks to EmbeddedObjectRefSubRecord

Modified:
    poi/trunk/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java

Modified: poi/trunk/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/changes.xml?rev=713852&r1=713851&r2=713852&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Thu Nov 13 15:01:46 2008
@@ -37,6 +37,7 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">46199 - More tweaks to EmbeddedObjectRefSubRecord</header>
            <action dev="POI-DEVELOPERS" type="add">Changes to formula evaluation allowing for reduced memory usage</action>
            <action dev="POI-DEVELOPERS" type="fix">45290 - Support odd files where the POIFS header block comes after the data blocks, and is on the data blocks list</header>
            <action dev="POI-DEVELOPERS" type="fix">46184 - More odd escaped date formats</action>

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=713852&r1=713851&r2=713852&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Thu Nov 13 15:01:46 2008
@@ -34,6 +34,7 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">46199 - More tweaks to EmbeddedObjectRefSubRecord</header>
            <action dev="POI-DEVELOPERS" type="add">Changes to formula evaluation allowing for reduced memory usage</action>
            <action dev="POI-DEVELOPERS" type="fix">45290 - Support odd files where the POIFS header block comes after the data blocks, and is on the data blocks list</header>
            <action dev="POI-DEVELOPERS" type="fix">46184 - More odd escaped date formats</action>

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java?rev=713852&r1=713851&r2=713852&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java Thu Nov 13 15:01:46 2008
@@ -46,9 +46,9 @@
 	private int field_1_unknown_int;
 	/** either an area or a cell ref */
 	private Ptg field_2_refPtg;
+	/** for when the 'formula' doesn't parse properly */
 	private byte[] field_2_unknownFormulaData;
-	// TODO: Consider making a utility class for these.  I've discovered the same field ordering
-	//	   in FormatRecord and StringRecord, it may be elsewhere too.
+	/** note- this byte is not present in the encoding if the string length is zero */ 
 	private boolean field_3_unicode_flag;  // Flags whether the string is Unicode.
 	private String  field_4_ole_classname; // Classname of the embedded OLE document (e.g. Word.Document.8)
 	/** Formulas often have a single non-zero trailing byte.
@@ -72,7 +72,7 @@
 	}
 
 	public EmbeddedObjectRefSubRecord(LittleEndianInput in, int size) {
-		// TODO use 'size' param 
+
 		// Much guess-work going on here due to lack of any documentation.
 		// See similar source code in OOO:
 		// http://lxr.go-oo.org/source/sc/sc/source/filter/excel/xiescher.cxx
@@ -101,26 +101,25 @@
 		int stringByteCount;
 		if (remaining >= dataLenAfterFormula + 3) {
 			int tag = in.readByte();
-			remaining -= LittleEndian.BYTE_SIZE;
+			stringByteCount = LittleEndian.BYTE_SIZE;
 			if (tag != 0x03) {
 				throw new RecordFormatException("Expected byte 0x03 here");
 			}
 			int nChars = in.readUShort();
-			remaining -= LittleEndian.SHORT_SIZE;
+			stringByteCount += LittleEndian.SHORT_SIZE;
 			if (nChars > 0) {
 				 // OOO: the 4th way Xcl stores a unicode string: not even a Grbit byte present if length 0
 				field_3_unicode_flag = ( in.readByte() & 0x01 ) != 0;
-				remaining -= LittleEndian.BYTE_SIZE;
+				stringByteCount += LittleEndian.BYTE_SIZE;
 				if (field_3_unicode_flag) {
 					field_4_ole_classname = StringUtil.readUnicodeLE(in, nChars);
-					stringByteCount = nChars * 2;
+					stringByteCount += nChars * 2;
 				} else {
 					field_4_ole_classname = StringUtil.readCompressedUnicode(in, nChars);
-					stringByteCount = nChars;
+					stringByteCount += nChars;
 				}
 			} else {
 				field_4_ole_classname = "";
-				stringByteCount = 0;
 			}
 		} else {
 			field_4_ole_classname = null;
@@ -150,10 +149,7 @@
 		} else {
 			field_5_stream_id = null;
 		}
-
-		byte [] buf = new byte[remaining];
-		in.readFully(buf);
-		field_6_unknown = buf;
+		field_6_unknown = readRawData(in, remaining);
 	}
 
 	private static Ptg readRefPtg(byte[] formulaRawBytes) {
@@ -176,9 +172,7 @@
 			return EMPTY_BYTE_ARRAY;
 		}
 		byte[] result = new byte[size];
-		for(int i=0; i< size; i++) {
-			result[i] = in.readByte();
-		}
+		in.readFully(result);
 		return result;
 	}
 	
@@ -191,12 +185,15 @@
 			// don't write 0x03, stringLen, flag, text
 			stringLen = 0;
 		} else {
-			result += 1 + 2 + 1;  // 0x03, stringLen, flag
+			result += 1 + 2;  // 0x03, stringLen
 			stringLen = field_4_ole_classname.length();
-			if (field_3_unicode_flag) {
-				result += stringLen * 2;
-			} else {
-				result += stringLen;
+			if (stringLen > 0) {
+				result += 1; // flag
+				if (field_3_unicode_flag) {
+					result += stringLen * 2;
+				} else {
+					result += stringLen;
+				}
 			}
 		}
 		// pad to next 2 byte boundary
@@ -253,15 +250,17 @@
 			stringLen = field_4_ole_classname.length();
 			out.writeShort(stringLen);
 			pos+=2;
-			out.writeByte(field_3_unicode_flag ? 0x01 : 0x00);
-			pos+=1;
-
-			if (field_3_unicode_flag) {
-				StringUtil.putUnicodeLE(field_4_ole_classname, out);
-				pos += stringLen * 2;
-			} else {
-				StringUtil.putCompressedUnicode(field_4_ole_classname, out);
-				pos += stringLen;
+			if (stringLen > 0) {
+    			out.writeByte(field_3_unicode_flag ? 0x01 : 0x00);
+    			pos+=1;
+    
+    			if (field_3_unicode_flag) {
+    				StringUtil.putUnicodeLE(field_4_ole_classname, out);
+    				pos += stringLen * 2;
+    			} else {
+    				StringUtil.putCompressedUnicode(field_4_ole_classname, out);
+    				pos += stringLen;
+    			}
 			}
 		}
 

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java?rev=713852&r1=713851&r2=713852&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java Thu Nov 13 15:01:46 2008
@@ -33,14 +33,18 @@
  */
 public final class TestEmbeddedObjectRefSubRecord extends TestCase {
 
-	String data1 = "[20, 00, 05, 00, FC, 10, 76, 01, 02, 24, 14, DF, 00, 03, 10, 00, 00, 46, 6F, 72, 6D, 73, 2E, 43, 68, 65, 63, 6B, 42, 6F, 78, 2E, 31, 00, 00, 00, 00, 00, 70, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, ]";
+	private static final short EORSR_SID = EmbeddedObjectRefSubRecord.sid;
 
 	public void testStore() {
+		String data1
+				= "20 00 05 00 FC 10 76 01 02 24 14 DF 00 03 10 00 "
+				+ "00 46 6F 72 6D 73 2E 43 68 65 63 6B 42 6F 78 2E "
+				+ "31 00 00 00 00 00 70 00 00 00 00 00 00 00 00 00 "
+				+ "00 00";
 
 		byte[] src = hr(data1);
-//		src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);
 
-		RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, src);
+		RecordInputStream in = TestcaseRecordInputStream.create(EORSR_SID, src);
 
 		EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length);
 
@@ -84,22 +88,19 @@
 		assertTrue(Arrays.equals(ser, ser2));
 	}
 
-
-	/**
-	 * taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).
-	 */
-	private static final byte[] data45912 = hr(
-		"12 00 0B 00 F8 02 88 04 3B 00 " +
-		"00 00 00 01 00 00 00 01 " +
-		"00 00");
-
 	public void testCameraTool_bug45912() {
-		byte[] data = data45912;
-		RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);
+		/**
+		 * taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).
+		 */
+		byte[] data45912 = hr(
+				"12 00 0B 00 F8 02 88 04 3B 00 " +
+				"00 00 00 01 00 00 00 01 " +
+				"00 00");
+		RecordInputStream in = TestcaseRecordInputStream.create(EORSR_SID, data45912);
 
-		EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);
+		EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data45912.length);
 		byte[] ser2 = rec.serialize();
-		confirmData(data, ser2);
+		confirmData(data45912, ser2);
 	}
 
 	private static byte[] hr(String string) {
@@ -134,14 +135,37 @@
 	}
 
 	private static void confirmRead(byte[] data, int i) {
-		RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);
+		RecordInputStream in = TestcaseRecordInputStream.create(EORSR_SID, data);
 
 		EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);
 		byte[] ser2 = rec.serialize();
-		byte[] d2 = (byte[]) data.clone(); // remove sid+len for compare
-		System.arraycopy(ser2, 4, d2, 0, d2.length);
-		if (!Arrays.equals(data, d2)) {
-			fail("re-read NQR for case " + i);
+		TestcaseRecordInputStream.confirmRecordEncoding("Test record " + i, EORSR_SID, data, ser2);
+	}
+	
+	public void testVisioDrawing_bug46199() {
+		/**
+		 * taken from ftPictFmla sub-record in attachment 22860 (stream offset 0x768F).<br/>
+		 * Note that the since the string length is zero, there is no unicode flag byte
+		 */
+		byte[] data46199 = hr(
+				  "0E 00 "
+				+ "05 00 "
+				+ "28 25 A3 01 "
+				+ "02 6C D1 34 02 "
+				+ "03 00 00 "
+				+ "0F CB E8 00");
+		RecordInputStream in = TestcaseRecordInputStream.create(EORSR_SID, data46199);
+
+		EmbeddedObjectRefSubRecord rec;
+		try {
+			rec = new EmbeddedObjectRefSubRecord(in, data46199.length);
+		} catch (RecordFormatException e) {
+			if (e.getMessage().equals("Not enough data (3) to read requested (4) bytes")) {
+				throw new AssertionFailedError("Identified bug 22860");
+			}
+			throw e;
 		}
+		byte[] ser2 = rec.serialize();
+		TestcaseRecordInputStream.confirmRecordEncoding(EORSR_SID, data46199, ser2);
 	}
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java?rev=713852&r1=713851&r2=713852&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java Thu Nov 13 15:01:46 2008
@@ -21,7 +21,9 @@
 import java.io.InputStream;
 
 import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
 
+import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianInput;
@@ -29,29 +31,29 @@
 /**
  * A Record Input Stream derivative that makes access to byte arrays used in the
  * test cases work a bit easier.
- * <p> Creates the sream and moves to the first record.
+ * <p> Creates the stream and moves to the first record.
  *
  * @author Jason Height (jheight at apache.org)
  */
 public final class TestcaseRecordInputStream {
-	
+
 	private TestcaseRecordInputStream() {
 		// no instances of this class
 	}
-	
+
 	/**
-	 * Prepends a mock record identifier to the supplied data and opens a record input stream 
+	 * Prepends a mock record identifier to the supplied data and opens a record input stream
 	 */
 	public static LittleEndianInput createLittleEndian(byte[] data) {
 		return new LittleEndianByteArrayInputStream(data);
-		
+
 	}
 	public static RecordInputStream create(int sid, byte[] data) {
 		return create(mergeDataAndSid(sid, data.length, data));
 	}
 	/**
-	 * First 4 bytes of <tt>data</tt> are assumed to be record identifier and length. The supplied 
-	 * <tt>data</tt> can contain multiple records (sequentially encoded in the same way) 
+	 * First 4 bytes of <tt>data</tt> are assumed to be record identifier and length. The supplied
+	 * <tt>data</tt> can contain multiple records (sequentially encoded in the same way)
 	 */
 	public static RecordInputStream create(byte[] data) {
 		InputStream is = new ByteArrayInputStream(data);
@@ -59,40 +61,45 @@
 		result.nextRecord();
 		return result;
 	}
-	
-    /**
-     * Convenience constructor
-     */
-//    public TestcaseRecordInputStream(int sid, byte[] data)
-//    {
-//      super(new ByteArrayInputStream(mergeDataAndSid(sid, data.length, data)));
-//      nextRecord();
-//    }
-//    public TestcaseRecordInputStream(short sid, short length, byte[] data)
-//    {
-//      super(new ByteArrayInputStream(mergeDataAndSid(sid, length, data)));
-//      nextRecord();
-//    }
-
-    public static byte[] mergeDataAndSid(int sid, int length, byte[] data) {
-      byte[] result = new byte[data.length + 4];
-      LittleEndian.putUShort(result, 0, sid);
-      LittleEndian.putUShort(result, 2, length);
-      System.arraycopy(data, 0, result, 4, data.length);
-      return result;
-    }
-    /**
-     * Confirms data sections are equal
-     * @param expectedData - just raw data (without sid or size short ints)
-     * @param actualRecordBytes this includes 4 prefix bytes (sid & size)
-     */
-    public static void confirmRecordEncoding(int expectedSid, byte[] expectedData, byte[] actualRecordBytes) {
-        int expectedDataSize = expectedData.length;
-        Assert.assertEquals(actualRecordBytes.length - 4, expectedDataSize);
-        Assert.assertEquals(expectedSid, LittleEndian.getShort(actualRecordBytes, 0));
-        Assert.assertEquals(expectedDataSize, LittleEndian.getShort(actualRecordBytes, 2));
-        for (int i = 0; i < expectedDataSize; i++)
-            Assert.assertEquals("At offset " + i, expectedData[i], actualRecordBytes[i+4]);
-        
-    }
+
+	public static byte[] mergeDataAndSid(int sid, int length, byte[] data) {
+	  byte[] result = new byte[data.length + 4];
+	  LittleEndian.putUShort(result, 0, sid);
+	  LittleEndian.putUShort(result, 2, length);
+	  System.arraycopy(data, 0, result, 4, data.length);
+	  return result;
+	}
+	/**
+	 * Confirms data sections are equal
+	 * @param expectedData - just raw data (without sid or size short ints)
+	 * @param actualRecordBytes this includes 4 prefix bytes (sid & size)
+	 */
+	public static void confirmRecordEncoding(int expectedSid, byte[] expectedData, byte[] actualRecordBytes)
+			throws AssertionFailedError {
+		confirmRecordEncoding(null, expectedSid, expectedData, actualRecordBytes);
+	}
+	/**
+	 * Confirms data sections are equal
+	 * @param msgPrefix message prefix to be displayed in case of failure
+	 * @param expectedData - just raw data (without ushort sid, ushort size)
+	 * @param actualRecordBytes this includes 4 prefix bytes (sid & size)
+	 */
+	public static void confirmRecordEncoding(String msgPrefix, int expectedSid, byte[] expectedData, byte[] actualRecordBytes)
+			throws AssertionFailedError {
+		int expectedDataSize = expectedData.length;
+		Assert.assertEquals("Size of encode data mismatch", actualRecordBytes.length - 4, expectedDataSize);
+		Assert.assertEquals(expectedSid, LittleEndian.getShort(actualRecordBytes, 0));
+		Assert.assertEquals(expectedDataSize, LittleEndian.getShort(actualRecordBytes, 2));
+		for (int i = 0; i < expectedDataSize; i++)
+			if (expectedData[i] != actualRecordBytes[i+4]) {
+				StringBuilder sb = new StringBuilder(64);
+				if (msgPrefix != null) {
+					sb.append(msgPrefix).append(": ");
+				}
+				sb.append("At offset ").append(i);
+				sb.append(": expected ").append(HexDump.byteToHex(expectedData[i]));
+				sb.append(" but found ").append(HexDump.byteToHex(actualRecordBytes[i+4]));
+				throw new AssertionFailedError(sb.toString());
+			}
+	}
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org