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
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");
+ }
}
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;
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;
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();
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record;\r
+\r
+import junit.framework.*;\r
+\r
+import java.util.Arrays;\r
+import java.util.List;\r
+import java.io.ByteArrayInputStream;\r
+\r
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;\r
+\r
+/**\r
+ * Tests that serialization and deserialization of the TextObjectRecord .\r
+ * Test data taken directly from a real Excel file.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestTextObjectRecord extends TestCase {\r
+\r
+ byte[] data = {(byte)0xB6, 0x01, 0x12, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00,\r
+ 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\r
+ 0x00, 0x3C, 0x00, 0x1B, 0x00, 0x01, 0x48, 0x00, 0x65, 0x00, 0x6C,\r
+ 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x2C, 0x00, 0x20, 0x00, 0x57, 0x00,\r
+ 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x21, 0x00, 0x3C,\r
+ 0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\r
+\r
+\r
+ public void testRead()\r
+ throws Exception\r
+ {\r
+\r
+\r
+ RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));\r
+ is.nextRecord();\r
+ TextObjectRecord record = new TextObjectRecord(is);\r
+\r
+ assertEquals(TextObjectRecord.sid, record.getSid());\r
+ record.validateSid(TextObjectRecord.sid);\r
+ assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED, record.getHorizontalTextAlignment());\r
+ assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP, record.getVerticalTextAlignment());\r
+ assertEquals(TextObjectRecord.TEXT_ORIENTATION_NONE, record.getTextOrientation());\r
+ assertEquals(0, record.getReserved7());\r
+ assertEquals("Hello, World!", record.getStr().getString());\r
+\r
+ }\r
+\r
+ public void testWrite()\r
+ {\r
+ HSSFRichTextString str = new HSSFRichTextString("Hello, World!");\r
+\r
+ TextObjectRecord record = new TextObjectRecord();\r
+ int frLength = ( str.numFormattingRuns() + 1 ) * 8;\r
+ record.setFormattingRunLength( (short) frLength );\r
+ record.setTextLength( (short) str.length() );\r
+ record.setStr( str );\r
+ record.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED );\r
+ record.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP );\r
+ record.setTextLocked( true );\r
+ record.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );\r
+ record.setReserved7( 0 );\r
+\r
+ byte [] ser = record.serialize();\r
+ assertEquals(ser.length , data.length);\r
+\r
+ assertTrue(Arrays.equals(data, ser));\r
+\r
+ //read again\r
+ RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));\r
+ is.nextRecord();\r
+ record = new TextObjectRecord(is);\r
+\r
+ }\r
+\r
+ /**\r
+ * Test that TextObjectRecord serializes logs records properly.\r
+ */\r
+ public void testLongRecords() {\r
+ int[] length = {1024, 2048, 4096, 8192, 16384}; //test against strings of different length\r
+ for (int i = 0; i < length.length; i++) {\r
+ StringBuffer buff = new StringBuffer(length[i]);\r
+ for (int j = 0; j < length[i]; j++) {\r
+ buff.append("x");\r
+ }\r
+ HSSFRichTextString str = new HSSFRichTextString(buff.toString());\r
+\r
+ TextObjectRecord obj = new TextObjectRecord();\r
+ int frLength = ( str.numFormattingRuns() + 1 ) * 8;\r
+ obj.setFormattingRunLength( (short) frLength );\r
+ obj.setTextLength( (short) str.length() );\r
+ obj.setStr( str );\r
+\r
+ byte [] data = obj.serialize();\r
+ RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));\r
+ is.nextRecord();\r
+ TextObjectRecord record = new TextObjectRecord(is);\r
+ str = record.getStr();\r
+\r
+ assertEquals(buff.length(), str.length());\r
+ assertEquals(buff.toString(), str.getString());\r
+ }\r
+\r
+ }\r
+}\r