You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2007/08/26 17:03:14 UTC
svn commit: r569821 - in /poi/trunk/src:
java/org/apache/poi/hssf/record/RecordInputStream.java
java/org/apache/poi/hssf/record/TextObjectRecord.java
testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java
Author: yegor
Date: Sun Aug 26 08:03:13 2007
New Revision: 569821
URL: http://svn.apache.org/viewvc?rev=569821&view=rev
Log:
fixed: Bug 43088: Excel file can't be loaded if comments exceed a size of 4111 characters
Added:
poi/trunk/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java
Modified:
poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java
poi/trunk/src/java/org/apache/poi/hssf/record/TextObjectRecord.java
Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java?rev=569821&r1=569820&r2=569821&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java Sun Aug 26 08:03:13 2007
@@ -230,11 +230,14 @@
if ((length < 0) || (((remaining() / 2) < length) && !isContinueNext())) {
throw new IllegalArgumentException("Illegal length");
}
-
+
StringBuffer buf = new StringBuffer(length);
for (int i=0;i<length;i++) {
- if ((remaining() == 0) && (isContinueNext()))
+ if ((remaining() == 0) && (isContinueNext())){
nextRecord();
+ int compressByte = readByte();
+ if(compressByte != 1) throw new IllegalArgumentException("compressByte in continue records must be 1 while reading unicode LE string");
+ }
char ch = (char)readShort();
buf.append(ch);
}
@@ -242,14 +245,17 @@
}
public String readCompressedUnicode(int length) {
- if ((length < 0) || (remaining() < length)) {
+ if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
throw new IllegalArgumentException("Illegal length");
}
StringBuffer buf = new StringBuffer(length);
for (int i=0;i<length;i++) {
- if ((remaining() == 0) && (isContinueNext()))
+ if ((remaining() == 0) && (isContinueNext())) {
nextRecord();
+ int compressByte = readByte();
+ if(compressByte != 0) throw new IllegalArgumentException("compressByte in continue records must be 0 while reading compressed unicode");
+ }
byte b = readByte();
//Typecast direct to char from byte with high bit set causes all ones
//in the high byte of the char (which is of course incorrect)
Modified: poi/trunk/src/java/org/apache/poi/hssf/record/TextObjectRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/TextObjectRecord.java?rev=569821&r1=569820&r2=569821&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/TextObjectRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/TextObjectRecord.java Sun Aug 26 08:03:13 2007
@@ -21,6 +21,7 @@
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.HexDump;
import java.io.UnsupportedEncodingException;
+import java.io.ByteArrayOutputStream;
public class TextObjectRecord
extends TextObjectBaseRecord
@@ -40,21 +41,21 @@
protected void fillFields(RecordInputStream in)
{
- super.fillFields(in);
- if (getTextLength() > 0) {
- if (in.isContinueNext() && in.remaining() == 0) {
- //1st Continue
- in.nextRecord();
- processRawString(in);
- } else
- throw new RecordFormatException("Expected Continue record to hold string data for TextObjectRecord");
- }
- if (getFormattingRunLength() > 0) {
+ super.fillFields(in);
+ if (getTextLength() > 0) {
if (in.isContinueNext() && in.remaining() == 0) {
- in.nextRecord();
- processFontRuns(in);
- } else throw new RecordFormatException("Expected Continue Record to hold font runs for TextObjectRecord");
- }
+ //1st Continue
+ in.nextRecord();
+ processRawString(in);
+ } else
+ throw new RecordFormatException("Expected Continue record to hold string data for TextObjectRecord");
+ }
+ if (getFormattingRunLength() > 0) {
+ if (in.isContinueNext() && in.remaining() == 0) {
+ in.nextRecord();
+ processFontRuns(in);
+ } else throw new RecordFormatException("Expected Continue Record to hold font runs for TextObjectRecord");
+ }
}
@@ -64,7 +65,15 @@
int continue2Size = 0;
if (str.length() != 0)
{
- continue1Size = str.length() * 2 + 1 + 4;
+ int length = str.length() * 2;
+ while(length > 0){
+ int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE-2, length);
+ length -= chunkSize;
+
+ continue1Size += chunkSize;
+ continue1Size += 1 + 4;
+ }
+
continue2Size = (str.numFormattingRuns() + 1) * 8 + 4;
}
return super.getRecordSize() + continue1Size + continue2Size;
@@ -83,9 +92,44 @@
int pos = offset + bytesWritten1;
if ( str.getString().equals( "" ) == false )
{
- ContinueRecord c1 = createContinue1();
ContinueRecord c2 = createContinue2();
- int bytesWritten2 = c1.serialize( pos, data );
+ int bytesWritten2 = 0;
+
+ try
+ {
+ byte[] c1Data = str.getString().getBytes( "UTF-16LE" );
+ int length = c1Data.length;
+
+ int charsWritten = 0;
+ int spos = pos;
+ while(length > 0){
+ int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE-2 , length);
+ length -= chunkSize;
+
+ //continue header
+ LittleEndian.putShort(data, spos, ContinueRecord.sid);
+ spos += LittleEndian.SHORT_SIZE;
+ LittleEndian.putShort(data, spos, (short)(chunkSize+1));
+ spos += LittleEndian.SHORT_SIZE;
+
+ //The first byte specifies if the text is compressed unicode or unicode.
+ //(regardless what was read, we always serialize double-byte unicode characters (UTF-16LE).
+ data[spos] = 1;
+ spos += LittleEndian.BYTE_SIZE;
+
+ //copy characters data
+ System.arraycopy(c1Data, charsWritten, data, spos, chunkSize);
+ spos += chunkSize;
+ charsWritten += chunkSize;
+ }
+
+ bytesWritten2 = (spos-pos);
+ }
+ catch ( UnsupportedEncodingException e )
+ {
+ throw new RuntimeException( e.getMessage(), e );
+ }
+
pos += bytesWritten2;
int bytesWritten3 = c2.serialize( pos, data );
pos += bytesWritten3;
@@ -98,23 +142,6 @@
if ( bytesWritten1 != getRecordSize() )
throw new RecordFormatException(bytesWritten1 + " bytes written but getRecordSize() reports " + getRecordSize());
return bytesWritten1;
- }
-
- private ContinueRecord createContinue1()
- {
- ContinueRecord c1 = new ContinueRecord();
- byte[] c1Data = new byte[str.length() * 2 + 1];
- try
- {
- c1Data[0] = 1;
- System.arraycopy( str.getString().getBytes( "UTF-16LE" ), 0, c1Data, 1, str.length() * 2 );
- }
- catch ( UnsupportedEncodingException e )
- {
- throw new RuntimeException( e.getMessage() );
- }
- c1.setData( c1Data );
- return c1;
}
private ContinueRecord createContinue2()
Added: poi/trunk/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java?rev=569821&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java Sun Aug 26 08:03:13 2007
@@ -0,0 +1,120 @@
+
+/* ====================================================================
+ 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.hssf.record;
+
+import junit.framework.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.io.ByteArrayInputStream;
+
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+
+/**
+ * Tests that serialization and deserialization of the TextObjectRecord .
+ * Test data taken directly from a real Excel file.
+ *
+ * @author Yegor Kozlov
+ */
+public class TestTextObjectRecord extends TestCase {
+
+ byte[] data = {(byte)0xB6, 0x01, 0x12, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3C, 0x00, 0x1B, 0x00, 0x01, 0x48, 0x00, 0x65, 0x00, 0x6C,
+ 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x2C, 0x00, 0x20, 0x00, 0x57, 0x00,
+ 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x21, 0x00, 0x3C,
+ 0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+
+ public void testRead()
+ throws Exception
+ {
+
+
+ RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));
+ is.nextRecord();
+ TextObjectRecord record = new TextObjectRecord(is);
+
+ assertEquals(TextObjectRecord.sid, record.getSid());
+ record.validateSid(TextObjectRecord.sid);
+ assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED, record.getHorizontalTextAlignment());
+ assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP, record.getVerticalTextAlignment());
+ assertEquals(TextObjectRecord.TEXT_ORIENTATION_NONE, record.getTextOrientation());
+ assertEquals(0, record.getReserved7());
+ assertEquals("Hello, World!", record.getStr().getString());
+
+ }
+
+ public void testWrite()
+ {
+ HSSFRichTextString str = new HSSFRichTextString("Hello, World!");
+
+ TextObjectRecord record = new TextObjectRecord();
+ int frLength = ( str.numFormattingRuns() + 1 ) * 8;
+ record.setFormattingRunLength( (short) frLength );
+ record.setTextLength( (short) str.length() );
+ record.setStr( str );
+ record.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED );
+ record.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP );
+ record.setTextLocked( true );
+ record.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );
+ record.setReserved7( 0 );
+
+ byte [] ser = record.serialize();
+ assertEquals(ser.length , data.length);
+
+ assertTrue(Arrays.equals(data, ser));
+
+ //read again
+ RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));
+ is.nextRecord();
+ record = new TextObjectRecord(is);
+
+ }
+
+ /**
+ * Test that TextObjectRecord serializes logs records properly.
+ */
+ public void testLongRecords() {
+ int[] length = {1024, 2048, 4096, 8192, 16384}; //test against strings of different length
+ for (int i = 0; i < length.length; i++) {
+ StringBuffer buff = new StringBuffer(length[i]);
+ for (int j = 0; j < length[i]; j++) {
+ buff.append("x");
+ }
+ HSSFRichTextString str = new HSSFRichTextString(buff.toString());
+
+ TextObjectRecord obj = new TextObjectRecord();
+ int frLength = ( str.numFormattingRuns() + 1 ) * 8;
+ obj.setFormattingRunLength( (short) frLength );
+ obj.setTextLength( (short) str.length() );
+ obj.setStr( str );
+
+ byte [] data = obj.serialize();
+ RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));
+ is.nextRecord();
+ TextObjectRecord record = new TextObjectRecord(is);
+ str = record.getStr();
+
+ assertEquals(buff.length(), str.length());
+ assertEquals(buff.toString(), str.getString());
+ }
+
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org