fixed: Bug 43088: Excel file can't be loaded if comments exceed a size of 4111 characters

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@569821 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2007-08-26 15:03:13 +00:00
parent 3d40a25d36
commit 22350f3b21
3 changed files with 191 additions and 38 deletions

View File

@ -233,8 +233,11 @@ public class RecordInputStream extends InputStream
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 class RecordInputStream extends InputStream
}
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)

View File

@ -21,6 +21,7 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString;
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
@ -64,7 +65,15 @@ public class TextObjectRecord
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 @@ public class TextObjectRecord
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;
@ -100,23 +144,6 @@ public class TextObjectRecord
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()
{
ContinueRecord c2 = new ContinueRecord();

View File

@ -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());
}
}
}