mirror of https://github.com/apache/poi.git
Fix for bug 45964 - support for link formulas in Text Objects
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@703302 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
69b99aa672
commit
91c8480933
|
@ -37,6 +37,7 @@
|
|||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<release version="3.2-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45964 - support for link formulas in Text Objects</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43354 - support for evalating formulas with missing args</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<release version="3.2-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45964 - support for link formulas in Text Objects</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43354 - support for evalating formulas with missing args</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
|
||||
|
|
|
@ -138,15 +138,11 @@ public class TextboxShape
|
|||
HSSFTextbox shape = hssfShape;
|
||||
|
||||
TextObjectRecord obj = new TextObjectRecord();
|
||||
obj.setHorizontalTextAlignment( hssfShape.getHorizontalAlignment() );
|
||||
obj.setVerticalTextAlignment( hssfShape.getVerticalAlignment());
|
||||
obj.setTextLocked( true );
|
||||
obj.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );
|
||||
int frLength = ( shape.getString().numFormattingRuns() + 1 ) * 8;
|
||||
obj.setFormattingRunLength( (short) frLength );
|
||||
obj.setTextLength( (short) shape.getString().length() );
|
||||
obj.setStr( shape.getString() );
|
||||
obj.setReserved7( 0 );
|
||||
obj.setHorizontalTextAlignment(hssfShape.getHorizontalAlignment());
|
||||
obj.setVerticalTextAlignment(hssfShape.getVerticalAlignment());
|
||||
obj.setTextLocked(true);
|
||||
obj.setTextOrientation(TextObjectRecord.TEXT_ORIENTATION_NONE);
|
||||
obj.setStr(shape.getString());
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -22,76 +22,44 @@ package org.apache.poi.hssf.record;
|
|||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Title: Continue Record - Helper class used primarily for SST Records <P>
|
||||
* Title: Continue Record(0x003C) - Helper class used primarily for SST Records <P>
|
||||
* Description: handles overflow for prior record in the input
|
||||
* stream; content is tailored to that prior record<P>
|
||||
* @author Marc Johnson (mjohnson at apache dot org)
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @author Csaba Nagy (ncsaba at yahoo dot com)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class ContinueRecord
|
||||
extends Record
|
||||
{
|
||||
public final class ContinueRecord extends Record {
|
||||
public final static short sid = 0x003C;
|
||||
private byte[] field_1_data;
|
||||
private byte[] _data;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
|
||||
public ContinueRecord()
|
||||
{
|
||||
public ContinueRecord(byte[] data) {
|
||||
_data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* USE ONLY within "processContinue"
|
||||
*/
|
||||
|
||||
public byte [] serialize()
|
||||
{
|
||||
byte[] retval = new byte[ field_1_data.length + 4 ];
|
||||
byte[] retval = new byte[ _data.length + 4 ];
|
||||
serialize(0, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
|
||||
LittleEndian.putShort(data, offset, sid);
|
||||
LittleEndian.putShort(data, offset + 2, ( short ) field_1_data.length);
|
||||
System.arraycopy(field_1_data, 0, data, offset + 4, field_1_data.length);
|
||||
return field_1_data.length + 4;
|
||||
// throw new RecordFormatException(
|
||||
// "You're not supposed to serialize Continue records like this directly");
|
||||
}
|
||||
|
||||
/*
|
||||
* @param data raw data
|
||||
*/
|
||||
|
||||
public void setData(byte [] data)
|
||||
{
|
||||
field_1_data = data;
|
||||
public int serialize(int offset, byte[] data) {
|
||||
return write(data, offset, null, _data);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the data for continuation
|
||||
* @return byte array containing all of the continued data
|
||||
*/
|
||||
|
||||
public byte [] getData()
|
||||
{
|
||||
return field_1_data;
|
||||
return _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging toString
|
||||
*
|
||||
* @return string representation
|
||||
*/
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
@ -113,19 +81,36 @@ public class ContinueRecord
|
|||
*
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
|
||||
public ContinueRecord(RecordInputStream in)
|
||||
{
|
||||
field_1_data = in.readRemainder();
|
||||
_data = in.readRemainder();
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new ContinueRecord(_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone this record.
|
||||
* Writes the full encoding of a Continue record without making an instance
|
||||
*/
|
||||
public Object clone() {
|
||||
ContinueRecord clone = new ContinueRecord();
|
||||
clone.setData(field_1_data);
|
||||
return clone;
|
||||
public static int write(byte[] destBuf, int destOffset, Byte initialDataByte, byte[] srcData) {
|
||||
return write(destBuf, destOffset, initialDataByte, srcData, 0, srcData.length);
|
||||
}
|
||||
/**
|
||||
* @param initialDataByte (optional - often used for unicode flag).
|
||||
* If supplied, this will be written before srcData
|
||||
* @return the total number of bytes written
|
||||
*/
|
||||
public static int write(byte[] destBuf, int destOffset, Byte initialDataByte, byte[] srcData, int srcOffset, int len) {
|
||||
int totalLen = len + (initialDataByte == null ? 0 : 1);
|
||||
LittleEndian.putUShort(destBuf, destOffset, sid);
|
||||
LittleEndian.putUShort(destBuf, destOffset + 2, totalLen);
|
||||
int pos = destOffset + 4;
|
||||
if (initialDataByte != null) {
|
||||
LittleEndian.putByte(destBuf, pos, initialDataByte.byteValue());
|
||||
pos += 1;
|
||||
}
|
||||
System.arraycopy(srcData, srcOffset, destBuf, pos, len);
|
||||
return 4 + totalLen;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -321,51 +321,54 @@ public final class RecordFactory {
|
|||
Record lastRecord = null;
|
||||
while (recStream.hasNextRecord()) {
|
||||
recStream.nextRecord();
|
||||
if (recStream.getSid() != 0) {
|
||||
Record[] recs = createRecord(recStream); // handle MulRK records
|
||||
if (recStream.getSid() == 0) {
|
||||
// After EOF, Excel seems to pad block with zeros
|
||||
continue;
|
||||
}
|
||||
Record[] recs = createRecord(recStream); // handle MulRK records
|
||||
|
||||
if (recs.length > 1) {
|
||||
for (int k = 0; k < recs.length; k++) {
|
||||
records.add(recs[ k ]); // these will be number records
|
||||
}
|
||||
} else {
|
||||
Record record = recs[ 0 ];
|
||||
|
||||
if (record != null) {
|
||||
if (record.getSid() == DrawingGroupRecord.sid
|
||||
&& lastRecord instanceof DrawingGroupRecord) {
|
||||
DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) lastRecord;
|
||||
lastDGRecord.join((AbstractEscherHolderRecord) record);
|
||||
} else if (record.getSid() == ContinueRecord.sid &&
|
||||
((lastRecord instanceof ObjRecord) || (lastRecord instanceof TextObjectRecord))) {
|
||||
// Drawing records have a very strange continue behaviour.
|
||||
//There can actually be OBJ records mixed between the continues.
|
||||
lastDrawingRecord.processContinueRecord( ((ContinueRecord)record).getData() );
|
||||
//we must remember the position of the continue record.
|
||||
//in the serialization procedure the original structure of records must be preserved
|
||||
records.add(record);
|
||||
} else if (record.getSid() == ContinueRecord.sid &&
|
||||
(lastRecord instanceof DrawingGroupRecord)) {
|
||||
((DrawingGroupRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData());
|
||||
} else if (record.getSid() == ContinueRecord.sid &&
|
||||
(lastRecord instanceof StringRecord)) {
|
||||
((StringRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData());
|
||||
} else if (record.getSid() == ContinueRecord.sid) {
|
||||
if (lastRecord instanceof UnknownRecord) {
|
||||
//Gracefully handle records that we dont know about,
|
||||
//that happen to be continued
|
||||
records.add(record);
|
||||
} else
|
||||
throw new RecordFormatException("Unhandled Continue Record");
|
||||
} else {
|
||||
lastRecord = record;
|
||||
if (record instanceof DrawingRecord) {
|
||||
lastDrawingRecord = (DrawingRecord) record;
|
||||
}
|
||||
records.add(record);
|
||||
}
|
||||
}
|
||||
if (recs.length > 1) {
|
||||
for (int k = 0; k < recs.length; k++) {
|
||||
records.add(recs[ k ]); // these will be number records
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Record record = recs[ 0 ];
|
||||
|
||||
if (record == null) {
|
||||
continue;
|
||||
}
|
||||
if (record.getSid() == DrawingGroupRecord.sid
|
||||
&& lastRecord instanceof DrawingGroupRecord) {
|
||||
DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) lastRecord;
|
||||
lastDGRecord.join((AbstractEscherHolderRecord) record);
|
||||
} else if (record.getSid() == ContinueRecord.sid) {
|
||||
ContinueRecord contRec = (ContinueRecord)record;
|
||||
|
||||
if (lastRecord instanceof ObjRecord || lastRecord instanceof TextObjectRecord) {
|
||||
// Drawing records have a very strange continue behaviour.
|
||||
//There can actually be OBJ records mixed between the continues.
|
||||
lastDrawingRecord.processContinueRecord(contRec.getData() );
|
||||
//we must remember the position of the continue record.
|
||||
//in the serialization procedure the original structure of records must be preserved
|
||||
records.add(record);
|
||||
} else if (lastRecord instanceof DrawingGroupRecord) {
|
||||
((DrawingGroupRecord)lastRecord).processContinueRecord(contRec.getData());
|
||||
} else if (lastRecord instanceof StringRecord) {
|
||||
((StringRecord)lastRecord).processContinueRecord(contRec.getData());
|
||||
} else if (lastRecord instanceof UnknownRecord) {
|
||||
//Gracefully handle records that we don't know about,
|
||||
//that happen to be continued
|
||||
records.add(record);
|
||||
} else {
|
||||
throw new RecordFormatException("Unhandled Continue Record");
|
||||
}
|
||||
} else {
|
||||
lastRecord = record;
|
||||
if (record instanceof DrawingRecord) {
|
||||
lastDrawingRecord = (DrawingRecord) record;
|
||||
}
|
||||
records.add(record);
|
||||
}
|
||||
}
|
||||
return records;
|
||||
|
|
|
@ -1,427 +0,0 @@
|
|||
|
||||
/* ====================================================================
|
||||
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 org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.BitFieldFactory;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* The TXO record is used to define the properties of a text box. It is followed
|
||||
* by two continue records unless there is no actual text. The first continue record contains
|
||||
* the text data and the next continue record contains the formatting runs.<p/>
|
||||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
public class TextObjectBaseRecord extends Record {
|
||||
// TODO - don't instantiate superclass
|
||||
public final static short sid = 0x01B6;
|
||||
|
||||
private static final BitField reserved1 = BitFieldFactory.getInstance(0x0001);
|
||||
private static final BitField HorizontalTextAlignment = BitFieldFactory.getInstance(0x000E);
|
||||
private static final BitField VerticalTextAlignment = BitFieldFactory.getInstance(0x0070);
|
||||
private static final BitField reserved2 = BitFieldFactory.getInstance(0x0180);
|
||||
private static final BitField textLocked = BitFieldFactory.getInstance(0x0200);
|
||||
private static final BitField reserved3 = BitFieldFactory.getInstance(0xFC00);
|
||||
|
||||
private short field_1_options;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4;
|
||||
private short field_2_textOrientation;
|
||||
public final static short TEXT_ORIENTATION_NONE = 0;
|
||||
public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1;
|
||||
public final static short TEXT_ORIENTATION_ROT_RIGHT = 2;
|
||||
public final static short TEXT_ORIENTATION_ROT_LEFT = 3;
|
||||
private short field_3_reserved4;
|
||||
private short field_4_reserved5;
|
||||
private short field_5_reserved6;
|
||||
private short field_6_textLength;
|
||||
private short field_7_formattingRunLength;
|
||||
private int field_8_reserved7;
|
||||
|
||||
|
||||
public TextObjectBaseRecord()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TextObjectBaseRecord(RecordInputStream in)
|
||||
{
|
||||
field_1_options = in.readShort();
|
||||
field_2_textOrientation = in.readShort();
|
||||
field_3_reserved4 = in.readShort();
|
||||
field_4_reserved5 = in.readShort();
|
||||
field_5_reserved6 = in.readShort();
|
||||
field_6_textLength = in.readShort();
|
||||
field_7_formattingRunLength = in.readShort();
|
||||
field_8_reserved7 = in.readInt();
|
||||
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[TXO]\n");
|
||||
buffer.append(" .options = ")
|
||||
.append("0x").append(HexDump.toHex( getOptions ()))
|
||||
.append(" (").append( getOptions() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .reserved1 = ").append(isReserved1()).append('\n');
|
||||
buffer.append(" .HorizontalTextAlignment = ").append(getHorizontalTextAlignment()).append('\n');
|
||||
buffer.append(" .VerticalTextAlignment = ").append(getVerticalTextAlignment()).append('\n');
|
||||
buffer.append(" .reserved2 = ").append(getReserved2()).append('\n');
|
||||
buffer.append(" .textLocked = ").append(isTextLocked()).append('\n');
|
||||
buffer.append(" .reserved3 = ").append(getReserved3()).append('\n');
|
||||
buffer.append(" .textOrientation = ")
|
||||
.append("0x").append(HexDump.toHex( getTextOrientation ()))
|
||||
.append(" (").append( getTextOrientation() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .reserved4 = ")
|
||||
.append("0x").append(HexDump.toHex( getReserved4 ()))
|
||||
.append(" (").append( getReserved4() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .reserved5 = ")
|
||||
.append("0x").append(HexDump.toHex( getReserved5 ()))
|
||||
.append(" (").append( getReserved5() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .reserved6 = ")
|
||||
.append("0x").append(HexDump.toHex( getReserved6 ()))
|
||||
.append(" (").append( getReserved6() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .textLength = ")
|
||||
.append("0x").append(HexDump.toHex( getTextLength ()))
|
||||
.append(" (").append( getTextLength() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .formattingRunLength = ")
|
||||
.append("0x").append(HexDump.toHex( getFormattingRunLength ()))
|
||||
.append(" (").append( getFormattingRunLength() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
buffer.append(" .reserved7 = ")
|
||||
.append("0x").append(HexDump.toHex( getReserved7 ()))
|
||||
.append(" (").append( getReserved7() ).append(" )");
|
||||
buffer.append(System.getProperty("line.separator"));
|
||||
|
||||
buffer.append("[/TXO]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte[] data)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
|
||||
|
||||
LittleEndian.putShort(data, 4 + offset + pos, field_1_options);
|
||||
LittleEndian.putShort(data, 6 + offset + pos, field_2_textOrientation);
|
||||
LittleEndian.putShort(data, 8 + offset + pos, field_3_reserved4);
|
||||
LittleEndian.putShort(data, 10 + offset + pos, field_4_reserved5);
|
||||
LittleEndian.putShort(data, 12 + offset + pos, field_5_reserved6);
|
||||
LittleEndian.putShort(data, 14 + offset + pos, field_6_textLength);
|
||||
LittleEndian.putShort(data, 16 + offset + pos, field_7_formattingRunLength);
|
||||
LittleEndian.putInt(data, 18 + offset + pos, field_8_reserved7);
|
||||
|
||||
return getRecordSize();
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
return 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4;
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
return sid;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
TextObjectBaseRecord rec = new TextObjectBaseRecord();
|
||||
|
||||
rec.field_1_options = field_1_options;
|
||||
rec.field_2_textOrientation = field_2_textOrientation;
|
||||
rec.field_3_reserved4 = field_3_reserved4;
|
||||
rec.field_4_reserved5 = field_4_reserved5;
|
||||
rec.field_5_reserved6 = field_5_reserved6;
|
||||
rec.field_6_textLength = field_6_textLength;
|
||||
rec.field_7_formattingRunLength = field_7_formattingRunLength;
|
||||
rec.field_8_reserved7 = field_8_reserved7;
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the options field for the TextObjectBase record.
|
||||
*/
|
||||
public short getOptions()
|
||||
{
|
||||
return field_1_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the options field for the TextObjectBase record.
|
||||
*/
|
||||
public void setOptions(short field_1_options)
|
||||
{
|
||||
this.field_1_options = field_1_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text orientation field for the TextObjectBase record.
|
||||
*
|
||||
* @return One of
|
||||
* TEXT_ORIENTATION_NONE
|
||||
* TEXT_ORIENTATION_TOP_TO_BOTTOM
|
||||
* TEXT_ORIENTATION_ROT_RIGHT
|
||||
* TEXT_ORIENTATION_ROT_LEFT
|
||||
*/
|
||||
public short getTextOrientation()
|
||||
{
|
||||
return field_2_textOrientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text orientation field for the TextObjectBase record.
|
||||
*
|
||||
* @param field_2_textOrientation
|
||||
* One of
|
||||
* TEXT_ORIENTATION_NONE
|
||||
* TEXT_ORIENTATION_TOP_TO_BOTTOM
|
||||
* TEXT_ORIENTATION_ROT_RIGHT
|
||||
* TEXT_ORIENTATION_ROT_LEFT
|
||||
*/
|
||||
public void setTextOrientation(short field_2_textOrientation)
|
||||
{
|
||||
this.field_2_textOrientation = field_2_textOrientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved4 field for the TextObjectBase record.
|
||||
*/
|
||||
public short getReserved4()
|
||||
{
|
||||
return field_3_reserved4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reserved4 field for the TextObjectBase record.
|
||||
*/
|
||||
public void setReserved4(short field_3_reserved4)
|
||||
{
|
||||
this.field_3_reserved4 = field_3_reserved4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved5 field for the TextObjectBase record.
|
||||
*/
|
||||
public short getReserved5()
|
||||
{
|
||||
return field_4_reserved5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reserved5 field for the TextObjectBase record.
|
||||
*/
|
||||
public void setReserved5(short field_4_reserved5)
|
||||
{
|
||||
this.field_4_reserved5 = field_4_reserved5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved6 field for the TextObjectBase record.
|
||||
*/
|
||||
public short getReserved6()
|
||||
{
|
||||
return field_5_reserved6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reserved6 field for the TextObjectBase record.
|
||||
*/
|
||||
public void setReserved6(short field_5_reserved6)
|
||||
{
|
||||
this.field_5_reserved6 = field_5_reserved6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text length field for the TextObjectBase record.
|
||||
*/
|
||||
public short getTextLength()
|
||||
{
|
||||
return field_6_textLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text length field for the TextObjectBase record.
|
||||
*/
|
||||
public void setTextLength(short field_6_textLength)
|
||||
{
|
||||
this.field_6_textLength = field_6_textLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatting run length field for the TextObjectBase record.
|
||||
*/
|
||||
public short getFormattingRunLength()
|
||||
{
|
||||
return field_7_formattingRunLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatting run length field for the TextObjectBase record.
|
||||
*/
|
||||
public void setFormattingRunLength(short field_7_formattingRunLength)
|
||||
{
|
||||
this.field_7_formattingRunLength = field_7_formattingRunLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved7 field for the TextObjectBase record.
|
||||
*/
|
||||
public int getReserved7()
|
||||
{
|
||||
return field_8_reserved7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reserved7 field for the TextObjectBase record.
|
||||
*/
|
||||
public void setReserved7(int field_8_reserved7)
|
||||
{
|
||||
this.field_8_reserved7 = field_8_reserved7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reserved1 field value.
|
||||
* reserved field
|
||||
*/
|
||||
public void setReserved1(boolean value)
|
||||
{
|
||||
field_1_options = reserved1.setShortBoolean(field_1_options, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* reserved field
|
||||
* @return the reserved1 field value.
|
||||
*/
|
||||
public boolean isReserved1()
|
||||
{
|
||||
return reserved1.isSet(field_1_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Horizontal text alignment field value.
|
||||
*
|
||||
*/
|
||||
public void setHorizontalTextAlignment(short value)
|
||||
{
|
||||
field_1_options = HorizontalTextAlignment.setShortValue(field_1_options, value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the Horizontal text alignment field value.
|
||||
*/
|
||||
public short getHorizontalTextAlignment()
|
||||
{
|
||||
return HorizontalTextAlignment.getShortValue(field_1_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Vertical text alignment field value.
|
||||
*
|
||||
*/
|
||||
public void setVerticalTextAlignment(short value)
|
||||
{
|
||||
field_1_options = VerticalTextAlignment.setShortValue(field_1_options, value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the Vertical text alignment field value.
|
||||
*/
|
||||
public short getVerticalTextAlignment()
|
||||
{
|
||||
return VerticalTextAlignment.getShortValue(field_1_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reserved2 field value.
|
||||
*
|
||||
*/
|
||||
public void setReserved2(short value)
|
||||
{
|
||||
field_1_options = reserved2.setShortValue(field_1_options, value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the reserved2 field value.
|
||||
*/
|
||||
public short getReserved2()
|
||||
{
|
||||
return reserved2.getShortValue(field_1_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text locked field value.
|
||||
* Text has been locked
|
||||
*/
|
||||
public void setTextLocked(boolean value)
|
||||
{
|
||||
field_1_options = textLocked.setShortBoolean(field_1_options, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Text has been locked
|
||||
* @return the text locked field value.
|
||||
*/
|
||||
public boolean isTextLocked()
|
||||
{
|
||||
return textLocked.isSet(field_1_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reserved3 field value.
|
||||
*
|
||||
*/
|
||||
public void setReserved3(short value)
|
||||
{
|
||||
field_1_options = reserved3.setShortValue(field_1_options, value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the reserved3 field value.
|
||||
*/
|
||||
public short getReserved3()
|
||||
{
|
||||
return reserved3.getShortValue(field_1_options);
|
||||
}
|
||||
}
|
|
@ -19,253 +19,427 @@ package org.apache.poi.hssf.record;
|
|||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.BitFieldFactory;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
public class TextObjectRecord
|
||||
extends TextObjectBaseRecord
|
||||
{
|
||||
HSSFRichTextString str;
|
||||
/**
|
||||
* The TXO record (0x01B6) is used to define the properties of a text box. It is
|
||||
* followed by two or more continue records unless there is no actual text. The
|
||||
* first continue records contain the text data and the last continue record
|
||||
* contains the formatting runs.<p/>
|
||||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
public final class TextObjectRecord extends Record {
|
||||
public final static short sid = 0x01B6;
|
||||
|
||||
public TextObjectRecord()
|
||||
{
|
||||
}
|
||||
private static final int FORMAT_RUN_ENCODED_SIZE = 8; // 2 shorts and 4 bytes reserved
|
||||
|
||||
public TextObjectRecord( RecordInputStream in )
|
||||
{
|
||||
super( in );
|
||||
private static final BitField HorizontalTextAlignment = BitFieldFactory.getInstance(0x000E);
|
||||
private static final BitField VerticalTextAlignment = BitFieldFactory.getInstance(0x0070);
|
||||
private static final BitField textLocked = BitFieldFactory.getInstance(0x0200);
|
||||
|
||||
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) {
|
||||
if (in.isContinueNext() && in.remaining() == 0) {
|
||||
in.nextRecord();
|
||||
processFontRuns(in);
|
||||
} else throw new RecordFormatException("Expected Continue Record to hold font runs for TextObjectRecord");
|
||||
}
|
||||
if (str == null)
|
||||
str = new HSSFRichTextString("");
|
||||
}
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3;
|
||||
public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3;
|
||||
public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4;
|
||||
|
||||
public final static short TEXT_ORIENTATION_NONE = 0;
|
||||
public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1;
|
||||
public final static short TEXT_ORIENTATION_ROT_RIGHT = 2;
|
||||
public final static short TEXT_ORIENTATION_ROT_LEFT = 3;
|
||||
|
||||
private int field_1_options;
|
||||
private int field_2_textOrientation;
|
||||
private int field_3_reserved4;
|
||||
private int field_4_reserved5;
|
||||
private int field_5_reserved6;
|
||||
private int field_8_reserved7;
|
||||
|
||||
private HSSFRichTextString _text;
|
||||
|
||||
/*
|
||||
* Note - the next three fields are very similar to those on
|
||||
* EmbededObjectRefSubRecord(ftPictFmla 0x0009)
|
||||
*
|
||||
* some observed values for the 4 bytes preceding the formula: C0 5E 86 03
|
||||
* C0 11 AC 02 80 F1 8A 03 D4 F0 8A 03
|
||||
*/
|
||||
private int _unknownPreFormulaInt;
|
||||
/** expect tRef, tRef3D, tArea, tArea3D or tName */
|
||||
private Ptg _linkRefPtg;
|
||||
/**
|
||||
* Not clear if needed . Excel seems to be OK if this byte is not present.
|
||||
* Value is often the same as the earlier firstColumn byte. */
|
||||
private Byte _unknownPostFormulaByte;
|
||||
|
||||
public TextObjectRecord() {
|
||||
}
|
||||
|
||||
public TextObjectRecord(RecordInputStream in) {
|
||||
field_1_options = in.readUShort();
|
||||
field_2_textOrientation = in.readUShort();
|
||||
field_3_reserved4 = in.readUShort();
|
||||
field_4_reserved5 = in.readUShort();
|
||||
field_5_reserved6 = in.readUShort();
|
||||
int field_6_textLength = in.readUShort();
|
||||
int field_7_formattingDataLength = in.readUShort();
|
||||
field_8_reserved7 = in.readInt();
|
||||
|
||||
if (in.remaining() > 0) {
|
||||
// Text Objects can have simple reference formulas
|
||||
// (This bit not mentioned in the MS document)
|
||||
if (in.remaining() < 11) {
|
||||
throw new RecordFormatException("Not enough remaining data for a link formula");
|
||||
}
|
||||
int formulaSize = in.readUShort();
|
||||
_unknownPreFormulaInt = in.readInt();
|
||||
Ptg[] ptgs = Ptg.readTokens(formulaSize, in);
|
||||
if (ptgs.length != 1) {
|
||||
throw new RecordFormatException("Read " + ptgs.length
|
||||
+ " tokens but expected exactly 1");
|
||||
}
|
||||
_linkRefPtg = ptgs[0];
|
||||
if (in.remaining() > 0) {
|
||||
_unknownPostFormulaByte = new Byte(in.readByte());
|
||||
} else {
|
||||
_unknownPostFormulaByte = null;
|
||||
}
|
||||
} else {
|
||||
_linkRefPtg = null;
|
||||
}
|
||||
if (in.remaining() > 0) {
|
||||
throw new RecordFormatException("Unused " + in.remaining() + " bytes at end of record");
|
||||
}
|
||||
|
||||
String text;
|
||||
if (field_6_textLength > 0) {
|
||||
text = readRawString(in, field_6_textLength);
|
||||
} else {
|
||||
text = "";
|
||||
}
|
||||
_text = new HSSFRichTextString(text);
|
||||
|
||||
if (field_7_formattingDataLength > 0) {
|
||||
if (in.isContinueNext() && in.remaining() == 0) {
|
||||
in.nextRecord();
|
||||
processFontRuns(in, _text, field_7_formattingDataLength);
|
||||
} else {
|
||||
throw new RecordFormatException(
|
||||
"Expected Continue Record to hold font runs for TextObjectRecord");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String readRawString(RecordInputStream in, int textLength) {
|
||||
byte compressByte = in.readByte();
|
||||
boolean isCompressed = (compressByte & 0x01) == 0;
|
||||
if (isCompressed) {
|
||||
return in.readCompressedUnicode(textLength);
|
||||
}
|
||||
return in.readUnicodeLEString(textLength);
|
||||
}
|
||||
|
||||
private static void processFontRuns(RecordInputStream in, HSSFRichTextString str,
|
||||
int formattingRunDataLength) {
|
||||
if (formattingRunDataLength % FORMAT_RUN_ENCODED_SIZE != 0) {
|
||||
throw new RecordFormatException("Bad format run data length " + formattingRunDataLength
|
||||
+ ")");
|
||||
}
|
||||
if (in.remaining() != formattingRunDataLength) {
|
||||
throw new RecordFormatException("Expected " + formattingRunDataLength
|
||||
+ " bytes but got " + in.remaining());
|
||||
}
|
||||
int nRuns = formattingRunDataLength / FORMAT_RUN_ENCODED_SIZE;
|
||||
for (int i = 0; i < nRuns; i++) {
|
||||
short index = in.readShort();
|
||||
short iFont = in.readShort();
|
||||
in.readInt(); // skip reserved.
|
||||
str.applyFont(index, str.length(), iFont);
|
||||
}
|
||||
}
|
||||
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for the current record. does not include any subsequent Continue
|
||||
* records
|
||||
*/
|
||||
private int getDataSize() {
|
||||
int result = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4;
|
||||
if (_linkRefPtg != null) {
|
||||
result += 2 // formula size
|
||||
+ 4 // unknownInt
|
||||
+_linkRefPtg.getSize();
|
||||
if (_unknownPostFormulaByte != null) {
|
||||
result += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int serializeTXORecord(int offset, byte[] data) {
|
||||
int dataSize = getDataSize();
|
||||
|
||||
LittleEndian.putUShort(data, 0 + offset, TextObjectRecord.sid);
|
||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
int continue1Size = 0;
|
||||
int continue2Size = 0;
|
||||
if (str.length() != 0)
|
||||
{
|
||||
int length = str.length() * 2;
|
||||
while(length > 0){
|
||||
int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE-2, length);
|
||||
length -= chunkSize;
|
||||
LittleEndian.putUShort(data, 4 + offset, field_1_options);
|
||||
LittleEndian.putUShort(data, 6 + offset, field_2_textOrientation);
|
||||
LittleEndian.putUShort(data, 8 + offset, field_3_reserved4);
|
||||
LittleEndian.putUShort(data, 10 + offset, field_4_reserved5);
|
||||
LittleEndian.putUShort(data, 12 + offset, field_5_reserved6);
|
||||
LittleEndian.putUShort(data, 14 + offset, _text.length());
|
||||
LittleEndian.putUShort(data, 16 + offset, getFormattingDataLength());
|
||||
LittleEndian.putInt(data, 18 + offset, field_8_reserved7);
|
||||
|
||||
continue1Size += chunkSize;
|
||||
continue1Size += 1 + 4;
|
||||
}
|
||||
if (_linkRefPtg != null) {
|
||||
int pos = offset+22;
|
||||
int formulaSize = _linkRefPtg.getSize();
|
||||
LittleEndian.putUShort(data, pos, formulaSize);
|
||||
pos += LittleEndian.SHORT_SIZE;
|
||||
LittleEndian.putInt(data, pos, _unknownPreFormulaInt);
|
||||
pos += LittleEndian.INT_SIZE;
|
||||
_linkRefPtg.writeBytes(data, pos);
|
||||
pos += formulaSize;
|
||||
if (_unknownPostFormulaByte != null) {
|
||||
LittleEndian.putByte(data, pos, _unknownPostFormulaByte.byteValue());
|
||||
pos += LittleEndian.BYTE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
continue2Size = (str.numFormattingRuns() + 1) * 8 + 4;
|
||||
}
|
||||
return super.getRecordSize() + continue1Size + continue2Size;
|
||||
}
|
||||
return 4 + dataSize;
|
||||
}
|
||||
|
||||
private int serializeTrailingRecords(int offset, byte[] data) {
|
||||
byte[] textBytes;
|
||||
try {
|
||||
textBytes = _text.getString().getBytes("UTF-16LE");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
int remainingLength = textBytes.length;
|
||||
|
||||
int countTextBytesWritten = 0;
|
||||
int pos = offset;
|
||||
// (regardless what was read, we always serialize double-byte
|
||||
// unicode characters (UTF-16LE).
|
||||
Byte unicodeFlag = new Byte((byte)1);
|
||||
while (remainingLength > 0) {
|
||||
int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE - 2, remainingLength);
|
||||
remainingLength -= chunkSize;
|
||||
pos += ContinueRecord.write(data, pos, unicodeFlag, textBytes, countTextBytesWritten, chunkSize);
|
||||
countTextBytesWritten += chunkSize;
|
||||
}
|
||||
|
||||
byte[] formatData = createFormatData(_text);
|
||||
pos += ContinueRecord.write(data, pos, null, formatData);
|
||||
return pos - offset;
|
||||
}
|
||||
|
||||
private int getTrailingRecordsSize() {
|
||||
if (_text.length() < 1) {
|
||||
return 0;
|
||||
}
|
||||
int encodedTextSize = 0;
|
||||
int textBytesLength = _text.length() * LittleEndian.SHORT_SIZE;
|
||||
while (textBytesLength > 0) {
|
||||
int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE - 2, textBytesLength);
|
||||
textBytesLength -= chunkSize;
|
||||
|
||||
encodedTextSize += 4; // +4 for ContinueRecord sid+size
|
||||
encodedTextSize += 1+chunkSize; // +1 for compressed unicode flag,
|
||||
}
|
||||
|
||||
int encodedFormatSize = (_text.numFormattingRuns() + 1) * FORMAT_RUN_ENCODED_SIZE
|
||||
+ 4; // +4 for ContinueRecord sid+size
|
||||
return encodedTextSize + encodedFormatSize;
|
||||
}
|
||||
|
||||
|
||||
public int serialize(int offset, byte[] data) {
|
||||
|
||||
public int serialize( int offset, byte[] data )
|
||||
{
|
||||
// Temporarily blank out str so that record size is calculated without the continue records.
|
||||
HSSFRichTextString temp = str;
|
||||
str = new HSSFRichTextString("");
|
||||
int bytesWritten1 = super.serialize( offset, data );
|
||||
str = temp;
|
||||
int expectedTotalSize = getRecordSize();
|
||||
int totalSize = serializeTXORecord(offset, data);
|
||||
|
||||
int pos = offset + bytesWritten1;
|
||||
if ( str.getString().equals( "" ) == false )
|
||||
{
|
||||
ContinueRecord c2 = createContinue2();
|
||||
int bytesWritten2 = 0;
|
||||
if (_text.getString().length() > 0) {
|
||||
totalSize += serializeTrailingRecords(offset+totalSize, data);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] c1Data = str.getString().getBytes( "UTF-16LE" );
|
||||
int length = c1Data.length;
|
||||
if (totalSize != expectedTotalSize)
|
||||
throw new RecordFormatException(totalSize
|
||||
+ " bytes written but getRecordSize() reports " + expectedTotalSize);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int charsWritten = 0;
|
||||
int spos = pos;
|
||||
while(length > 0){
|
||||
int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE-2 , length);
|
||||
length -= chunkSize;
|
||||
/**
|
||||
* Note - this total size includes all potential {@link ContinueRecord}s written
|
||||
*/
|
||||
public int getRecordSize() {
|
||||
int baseSize = 4 + getDataSize();
|
||||
return baseSize + getTrailingRecordsSize();
|
||||
}
|
||||
|
||||
//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;
|
||||
private int getFormattingDataLength() {
|
||||
if (_text.length() < 1) {
|
||||
// important - no formatting data if text is empty
|
||||
return 0;
|
||||
}
|
||||
return (_text.numFormattingRuns() + 1) * FORMAT_RUN_ENCODED_SIZE;
|
||||
}
|
||||
|
||||
//copy characters data
|
||||
System.arraycopy(c1Data, charsWritten, data, spos, chunkSize);
|
||||
spos += chunkSize;
|
||||
charsWritten += chunkSize;
|
||||
}
|
||||
private static byte[] createFormatData(HSSFRichTextString str) {
|
||||
int nRuns = str.numFormattingRuns();
|
||||
byte[] result = new byte[(nRuns + 1) * FORMAT_RUN_ENCODED_SIZE];
|
||||
int pos = 0;
|
||||
for (int i = 0; i < nRuns; i++) {
|
||||
LittleEndian.putUShort(result, pos, str.getIndexOfFormattingRun(i));
|
||||
pos += 2;
|
||||
int fontIndex = str.getFontOfFormattingRun(i);
|
||||
LittleEndian.putUShort(result, pos, fontIndex == str.NO_FONT ? 0 : fontIndex);
|
||||
pos += 2;
|
||||
pos += 4; // skip reserved
|
||||
}
|
||||
LittleEndian.putUShort(result, pos, str.length());
|
||||
pos += 2;
|
||||
LittleEndian.putUShort(result, pos, 0);
|
||||
pos += 2;
|
||||
pos += 4; // skip reserved
|
||||
|
||||
bytesWritten2 = (spos-pos);
|
||||
}
|
||||
catch ( UnsupportedEncodingException e )
|
||||
{
|
||||
throw new RuntimeException( e.getMessage(), e );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pos += bytesWritten2;
|
||||
int bytesWritten3 = c2.serialize( pos, data );
|
||||
pos += bytesWritten3;
|
||||
/**
|
||||
* Sets the Horizontal text alignment field value.
|
||||
*/
|
||||
public void setHorizontalTextAlignment(int value) {
|
||||
field_1_options = HorizontalTextAlignment.setValue(field_1_options, value);
|
||||
}
|
||||
|
||||
int size = bytesWritten1 + bytesWritten2 + bytesWritten3;
|
||||
if ( size != getRecordSize() )
|
||||
throw new RecordFormatException(size + " bytes written but getRecordSize() reports " + getRecordSize());
|
||||
return size;
|
||||
}
|
||||
if ( bytesWritten1 != getRecordSize() )
|
||||
throw new RecordFormatException(bytesWritten1 + " bytes written but getRecordSize() reports " + getRecordSize());
|
||||
return bytesWritten1;
|
||||
}
|
||||
/**
|
||||
* @return the Horizontal text alignment field value.
|
||||
*/
|
||||
public int getHorizontalTextAlignment() {
|
||||
return HorizontalTextAlignment.getValue(field_1_options);
|
||||
}
|
||||
|
||||
private ContinueRecord createContinue2()
|
||||
{
|
||||
ContinueRecord c2 = new ContinueRecord();
|
||||
byte[] c2Data = new byte[str.numFormattingRuns() * 8 + 8];
|
||||
int pos = 0;
|
||||
for ( int i = 0; i < str.numFormattingRuns(); i++ )
|
||||
{
|
||||
LittleEndian.putShort( c2Data, pos, (short) str.getIndexOfFormattingRun( i ) );
|
||||
pos += 2;
|
||||
LittleEndian.putShort( c2Data, pos, str.getFontOfFormattingRun( i ) == str.NO_FONT ? 0 : str.getFontOfFormattingRun( i ) );
|
||||
pos += 2;
|
||||
pos += 4; // skip reserved
|
||||
}
|
||||
LittleEndian.putShort( c2Data, pos, (short) str.length() );
|
||||
pos += 2;
|
||||
LittleEndian.putShort( c2Data, pos, (short) 0 );
|
||||
pos += 2;
|
||||
pos += 4; // skip reserved
|
||||
/**
|
||||
* Sets the Vertical text alignment field value.
|
||||
*/
|
||||
public void setVerticalTextAlignment(int value) {
|
||||
field_1_options = VerticalTextAlignment.setValue(field_1_options, value);
|
||||
}
|
||||
|
||||
c2.setData( c2Data );
|
||||
/**
|
||||
* @return the Vertical text alignment field value.
|
||||
*/
|
||||
public int getVerticalTextAlignment() {
|
||||
return VerticalTextAlignment.getValue(field_1_options);
|
||||
}
|
||||
|
||||
return c2;
|
||||
}
|
||||
/**
|
||||
* Sets the text locked field value.
|
||||
*/
|
||||
public void setTextLocked(boolean value) {
|
||||
field_1_options = textLocked.setBoolean(field_1_options, value);
|
||||
}
|
||||
|
||||
private void processFontRuns( RecordInputStream in )
|
||||
{
|
||||
while (in.remaining() > 0)
|
||||
{
|
||||
short index = in.readShort();
|
||||
short iFont = in.readShort();
|
||||
in.readInt(); // skip reserved.
|
||||
/**
|
||||
* @return the text locked field value.
|
||||
*/
|
||||
public boolean isTextLocked() {
|
||||
return textLocked.isSet(field_1_options);
|
||||
}
|
||||
|
||||
str.applyFont( index, str.length(), iFont );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the text orientation field for the TextObjectBase record.
|
||||
*
|
||||
* @return One of TEXT_ORIENTATION_NONE TEXT_ORIENTATION_TOP_TO_BOTTOM
|
||||
* TEXT_ORIENTATION_ROT_RIGHT TEXT_ORIENTATION_ROT_LEFT
|
||||
*/
|
||||
public int getTextOrientation() {
|
||||
return field_2_textOrientation;
|
||||
}
|
||||
|
||||
private void processRawString( RecordInputStream in )
|
||||
{
|
||||
String s;
|
||||
byte compressByte = in.readByte();
|
||||
boolean isCompressed = compressByte == 0;
|
||||
if ( isCompressed )
|
||||
{
|
||||
s = in.readCompressedUnicode(getTextLength());
|
||||
}
|
||||
else
|
||||
{
|
||||
s = in.readUnicodeLEString(getTextLength());
|
||||
}
|
||||
str = new HSSFRichTextString( s );
|
||||
}
|
||||
/**
|
||||
* Set the text orientation field for the TextObjectBase record.
|
||||
*
|
||||
* @param textOrientation
|
||||
* One of TEXT_ORIENTATION_NONE TEXT_ORIENTATION_TOP_TO_BOTTOM
|
||||
* TEXT_ORIENTATION_ROT_RIGHT TEXT_ORIENTATION_ROT_LEFT
|
||||
*/
|
||||
public void setTextOrientation(int textOrientation) {
|
||||
this.field_2_textOrientation = textOrientation;
|
||||
}
|
||||
|
||||
public HSSFRichTextString getStr()
|
||||
{
|
||||
return str;
|
||||
}
|
||||
public HSSFRichTextString getStr() {
|
||||
return _text;
|
||||
}
|
||||
|
||||
public void setStr( HSSFRichTextString str )
|
||||
{
|
||||
this.str = str;
|
||||
}
|
||||
public void setStr(HSSFRichTextString str) {
|
||||
_text = str;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
public Ptg getLinkRefPtg() {
|
||||
return _linkRefPtg;
|
||||
}
|
||||
|
||||
buffer.append( "[TXO]\n" );
|
||||
buffer.append( " .options = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getOptions() ) )
|
||||
.append( " (" ).append( getOptions() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
buffer.append( " .reserved1 = " ).append( isReserved1() ).append( '\n' );
|
||||
buffer.append( " .HorizontalTextAlignment = " ).append( getHorizontalTextAlignment() ).append( '\n' );
|
||||
buffer.append( " .VerticalTextAlignment = " ).append( getVerticalTextAlignment() ).append( '\n' );
|
||||
buffer.append( " .reserved2 = " ).append( getReserved2() ).append( '\n' );
|
||||
buffer.append( " .textLocked = " ).append( isTextLocked() ).append( '\n' );
|
||||
buffer.append( " .reserved3 = " ).append( getReserved3() ).append( '\n' );
|
||||
buffer.append( " .textOrientation = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getTextOrientation() ) )
|
||||
.append( " (" ).append( getTextOrientation() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
buffer.append( " .reserved4 = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getReserved4() ) )
|
||||
.append( " (" ).append( getReserved4() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
buffer.append( " .reserved5 = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getReserved5() ) )
|
||||
.append( " (" ).append( getReserved5() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
buffer.append( " .reserved6 = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getReserved6() ) )
|
||||
.append( " (" ).append( getReserved6() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
buffer.append( " .textLength = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getTextLength() ) )
|
||||
.append( " (" ).append( getTextLength() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
buffer.append( " .reserved7 = " )
|
||||
.append( "0x" ).append( HexDump.toHex( getReserved7() ) )
|
||||
.append( " (" ).append( getReserved7() ).append( " )" );
|
||||
buffer.append( System.getProperty( "line.separator" ) );
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
buffer.append( " .string = " ).append(str).append('\n');
|
||||
sb.append("[TXO]\n");
|
||||
sb.append(" .options = ").append(HexDump.shortToHex(field_1_options)).append("\n");
|
||||
sb.append(" .isHorizontal = ").append(getHorizontalTextAlignment()).append('\n');
|
||||
sb.append(" .isVertical = ").append(getVerticalTextAlignment()).append('\n');
|
||||
sb.append(" .textLocked = ").append(isTextLocked()).append('\n');
|
||||
sb.append(" .textOrientation= ").append(HexDump.shortToHex(getTextOrientation())).append("\n");
|
||||
sb.append(" .reserved4 = ").append(HexDump.shortToHex(field_3_reserved4)).append("\n");
|
||||
sb.append(" .reserved5 = ").append(HexDump.shortToHex(field_4_reserved5)).append("\n");
|
||||
sb.append(" .reserved6 = ").append(HexDump.shortToHex(field_5_reserved6)).append("\n");
|
||||
sb.append(" .textLength = ").append(HexDump.shortToHex(_text.length())).append("\n");
|
||||
sb.append(" .reserved7 = ").append(HexDump.intToHex(field_8_reserved7)).append("\n");
|
||||
|
||||
for (int i = 0; i < str.numFormattingRuns(); i++) {
|
||||
buffer.append( " .textrun = " ).append(str.getFontOfFormattingRun(i)).append('\n');
|
||||
sb.append(" .string = ").append(_text).append('\n');
|
||||
|
||||
}
|
||||
buffer.append( "[/TXO]\n" );
|
||||
return buffer.toString();
|
||||
}
|
||||
for (int i = 0; i < _text.numFormattingRuns(); i++) {
|
||||
sb.append(" .textrun = ").append(_text.getFontOfFormattingRun(i)).append('\n');
|
||||
|
||||
public Object clone() {
|
||||
}
|
||||
sb.append("[/TXO]\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
TextObjectRecord rec = new TextObjectRecord();
|
||||
rec.str = str;
|
||||
public Object clone() {
|
||||
|
||||
rec.setOptions(getOptions());
|
||||
rec.setTextOrientation(getTextOrientation());
|
||||
rec.setReserved4(getReserved4());
|
||||
rec.setReserved5(getReserved5());
|
||||
rec.setReserved6(getReserved6());
|
||||
rec.setTextLength(getTextLength());
|
||||
rec.setFormattingRunLength(getFormattingRunLength());
|
||||
rec.setReserved7(getReserved7());
|
||||
return rec;
|
||||
}
|
||||
TextObjectRecord rec = new TextObjectRecord();
|
||||
rec._text = _text;
|
||||
|
||||
rec.field_1_options = field_1_options;
|
||||
rec.field_2_textOrientation = field_2_textOrientation;
|
||||
rec.field_3_reserved4 = field_3_reserved4;
|
||||
rec.field_4_reserved5 = field_4_reserved5;
|
||||
rec.field_5_reserved6 = field_5_reserved6;
|
||||
rec.field_8_reserved7 = field_8_reserved7;
|
||||
|
||||
rec._text = _text; // clone needed?
|
||||
|
||||
if (_linkRefPtg != null) {
|
||||
rec._unknownPreFormulaInt = _unknownPreFormulaInt;
|
||||
rec._linkRefPtg = _linkRefPtg.copy();
|
||||
rec._unknownPostFormulaByte = rec._unknownPostFormulaByte;
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,10 +152,7 @@ public class HSSFComment extends HSSFTextbox {
|
|||
if (string.numFormattingRuns() == 0) string.applyFont((short)0);
|
||||
|
||||
if (txo != null) {
|
||||
int frLength = ( string.numFormattingRuns() + 1 ) * 8;
|
||||
txo.setFormattingRunLength( (short) frLength );
|
||||
txo.setTextLength( (short) string.length() );
|
||||
txo.setStr( string );
|
||||
txo.setStr(string);
|
||||
}
|
||||
super.setString(string);
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ public class HSSFRichTextString
|
|||
|
||||
|
||||
/**
|
||||
* @return the number of characters in the font.
|
||||
* @return the number of characters in the text.
|
||||
*/
|
||||
public int length()
|
||||
{
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
package org.apache.poi.hssf.record;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||
import org.apache.poi.util.HexRead;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
|
@ -25,63 +30,62 @@ import junit.framework.TestCase;
|
|||
* class works correctly. Test data taken directly from a real
|
||||
* Excel file.
|
||||
*
|
||||
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
public class TestTextObjectBaseRecord extends TestCase {
|
||||
byte[] data = new byte[] {
|
||||
0x44, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
};
|
||||
public final class TestTextObjectBaseRecord extends TestCase {
|
||||
/** data for one TXO rec and two continue recs */
|
||||
private static final byte[] data = HexRead.readFromString(
|
||||
"B6 01 " + // TextObjectRecord.sid
|
||||
"12 00 " + // size 18
|
||||
"44 02 02 00 00 00 00 00" +
|
||||
"00 00 " +
|
||||
"02 00 " + // strLen 2
|
||||
"10 00 " + // 16 bytes for 2 format runs
|
||||
"00 00" +
|
||||
"00 00 " +
|
||||
"3C 00 " + // ContinueRecord.sid
|
||||
"05 00 " + // size 5
|
||||
"01 " + // unicode uncompressed
|
||||
"41 00 42 00 " + // 'AB'
|
||||
"3C 00 " + // ContinueRecord.sid
|
||||
"10 00 " + // size 16
|
||||
"00 00 18 00 00 00 00 00 " +
|
||||
"02 00 00 00 00 00 00 00 "
|
||||
);
|
||||
|
||||
|
||||
public void testLoad() {
|
||||
TextObjectBaseRecord record = new TextObjectBaseRecord(new TestcaseRecordInputStream((short)0x1B6, (short)data.length, data));
|
||||
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
|
||||
in.nextRecord();
|
||||
TextObjectRecord record = new TextObjectRecord(in);
|
||||
|
||||
|
||||
// assertEquals( (short), record.getOptions());
|
||||
assertEquals( false, record.isReserved1() );
|
||||
assertEquals( TextObjectBaseRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment() );
|
||||
assertEquals( TextObjectBaseRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment() );
|
||||
assertEquals( 0, record.getReserved2() );
|
||||
assertEquals( true, record.isTextLocked() );
|
||||
assertEquals( 0, record.getReserved3() );
|
||||
assertEquals( TextObjectBaseRecord.TEXT_ORIENTATION_ROT_RIGHT, record.getTextOrientation());
|
||||
assertEquals( 0, record.getReserved4());
|
||||
assertEquals( 0, record.getReserved5());
|
||||
assertEquals( 0, record.getReserved6());
|
||||
assertEquals( 2, record.getTextLength());
|
||||
assertEquals( 2, record.getFormattingRunLength());
|
||||
assertEquals( 0, record.getReserved7());
|
||||
assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment());
|
||||
assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment());
|
||||
assertEquals(true, record.isTextLocked());
|
||||
assertEquals(TextObjectRecord.TEXT_ORIENTATION_ROT_RIGHT, record.getTextOrientation());
|
||||
|
||||
|
||||
assertEquals( 22, record.getRecordSize() );
|
||||
assertEquals(51, record.getRecordSize() );
|
||||
}
|
||||
|
||||
public void testStore()
|
||||
{
|
||||
TextObjectBaseRecord record = new TextObjectBaseRecord();
|
||||
TextObjectRecord record = new TextObjectRecord();
|
||||
|
||||
|
||||
HSSFRichTextString str = new HSSFRichTextString("AB");
|
||||
str.applyFont(0, 2, (short)0x0018);
|
||||
str.applyFont(2, 2, (short)0x0320);
|
||||
|
||||
// record.setOptions( (short) 0x0000);
|
||||
record.setReserved1( false );
|
||||
record.setHorizontalTextAlignment( TextObjectBaseRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED );
|
||||
record.setVerticalTextAlignment( TextObjectBaseRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY );
|
||||
record.setReserved2( (short)0 );
|
||||
record.setTextLocked( true );
|
||||
record.setReserved3( (short)0 );
|
||||
record.setTextOrientation( TextObjectBaseRecord.TEXT_ORIENTATION_ROT_RIGHT );
|
||||
record.setReserved4( (short)0 );
|
||||
record.setReserved5( (short)0 );
|
||||
record.setReserved6( (short)0 );
|
||||
record.setTextLength( (short)2 );
|
||||
record.setFormattingRunLength( (short)2 );
|
||||
record.setReserved7( 0 );
|
||||
record.setHorizontalTextAlignment(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED);
|
||||
record.setVerticalTextAlignment(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY);
|
||||
record.setTextLocked(true);
|
||||
record.setTextOrientation(TextObjectRecord.TEXT_ORIENTATION_ROT_RIGHT);
|
||||
record.setStr(str);
|
||||
|
||||
byte [] recordBytes = record.serialize();
|
||||
assertEquals(recordBytes.length - 4, data.length);
|
||||
assertEquals(recordBytes.length, data.length);
|
||||
for (int i = 0; i < data.length; i++)
|
||||
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
|
||||
assertEquals("At offset " + i, data[i], recordBytes[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,11 @@ import java.util.Arrays;
|
|||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||
import org.apache.poi.util.HexRead;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Tests that serialization and deserialization of the TextObjectRecord .
|
||||
|
@ -32,17 +36,23 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
|||
*/
|
||||
public final 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 };
|
||||
private static final byte[] simpleData = HexRead.readFromString(
|
||||
"B6 01 12 00 " +
|
||||
"12 02 00 00 00 00 00 00" +
|
||||
"00 00 0D 00 08 00 00 00" +
|
||||
"00 00 " +
|
||||
"3C 00 1B 00 " +
|
||||
"01 48 00 65 00 6C 00 6C 00 6F 00 " +
|
||||
"2C 00 20 00 57 00 6F 00 72 00 6C " +
|
||||
"00 64 00 21 00 " +
|
||||
"3C 00 08 " +
|
||||
"00 0D 00 00 00 00 00 00 00"
|
||||
);
|
||||
|
||||
|
||||
public void testRead() {
|
||||
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
|
||||
is.nextRecord();
|
||||
TextObjectRecord record = new TextObjectRecord(is);
|
||||
|
||||
|
@ -50,36 +60,51 @@ public final class TestTextObjectRecord extends TestCase {
|
|||
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()
|
||||
{
|
||||
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.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);
|
||||
assertEquals(ser.length , simpleData.length);
|
||||
|
||||
//assertTrue(Arrays.equals(data, ser));
|
||||
assertTrue(Arrays.equals(simpleData, ser));
|
||||
|
||||
//read again
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
|
||||
is.nextRecord();
|
||||
record = new TextObjectRecord(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero {@link ContinueRecord}s follow a {@link TextObjectRecord} if the text is empty
|
||||
*/
|
||||
public void testWriteEmpty() {
|
||||
HSSFRichTextString str = new HSSFRichTextString("");
|
||||
|
||||
TextObjectRecord record = new TextObjectRecord();
|
||||
record.setStr(str);
|
||||
|
||||
byte [] ser = record.serialize();
|
||||
|
||||
int formatDataLen = LittleEndian.getUShort(ser, 16);
|
||||
assertEquals("formatDataLength", 0, formatDataLen);
|
||||
|
||||
assertEquals(22, ser.length); // just the TXO record
|
||||
|
||||
//read again
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));
|
||||
is.nextRecord();
|
||||
record = new TextObjectRecord(is);
|
||||
assertEquals(0, record.getStr().length());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,10 +120,7 @@ public final class TestTextObjectRecord extends TestCase {
|
|||
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 );
|
||||
obj.setStr(str);
|
||||
|
||||
byte [] data = obj.serialize();
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));
|
||||
|
@ -120,30 +142,12 @@ public final class TestTextObjectRecord extends TestCase {
|
|||
HSSFRichTextString str = new HSSFRichTextString(text);
|
||||
|
||||
TextObjectRecord obj = new TextObjectRecord();
|
||||
int frLength = ( str.numFormattingRuns() + 1 ) * 8;
|
||||
obj.setFormattingRunLength( (short) frLength );
|
||||
obj.setTextLength( (short) str.length() );
|
||||
obj.setReserved1(true);
|
||||
obj.setReserved2((short)2);
|
||||
obj.setReserved3((short)3);
|
||||
obj.setReserved4((short)4);
|
||||
obj.setReserved5((short)5);
|
||||
obj.setReserved6((short)6);
|
||||
obj.setReserved7((short)7);
|
||||
obj.setStr( str );
|
||||
|
||||
|
||||
TextObjectRecord cloned = (TextObjectRecord)obj.clone();
|
||||
assertEquals(obj.getReserved2(), cloned.getReserved2());
|
||||
assertEquals(obj.getReserved3(), cloned.getReserved3());
|
||||
assertEquals(obj.getReserved4(), cloned.getReserved4());
|
||||
assertEquals(obj.getReserved5(), cloned.getReserved5());
|
||||
assertEquals(obj.getReserved6(), cloned.getReserved6());
|
||||
assertEquals(obj.getReserved7(), cloned.getReserved7());
|
||||
assertEquals(obj.getRecordSize(), cloned.getRecordSize());
|
||||
assertEquals(obj.getOptions(), cloned.getOptions());
|
||||
assertEquals(obj.getHorizontalTextAlignment(), cloned.getHorizontalTextAlignment());
|
||||
assertEquals(obj.getFormattingRunLength(), cloned.getFormattingRunLength());
|
||||
assertEquals(obj.getStr().getString(), cloned.getStr().getString());
|
||||
|
||||
//finally check that the serialized data is the same
|
||||
|
@ -151,4 +155,47 @@ public final class TestTextObjectRecord extends TestCase {
|
|||
byte[] cln = cloned.serialize();
|
||||
assertTrue(Arrays.equals(src, cln));
|
||||
}
|
||||
|
||||
/** similar to {@link #simpleData} but with link formula at end of TXO rec*/
|
||||
private static final byte[] linkData = HexRead.readFromString(
|
||||
"B6 01 " + // TextObjectRecord.sid
|
||||
"1E 00 " + // size 18
|
||||
"44 02 02 00 00 00 00 00" +
|
||||
"00 00 " +
|
||||
"02 00 " + // strLen 2
|
||||
"10 00 " + // 16 bytes for 2 format runs
|
||||
"00 00 00 00 " +
|
||||
|
||||
"05 00 " + // formula size
|
||||
"D4 F0 8A 03 " + // unknownInt
|
||||
"24 01 00 13 C0 " + //tRef(T2)
|
||||
"13 " + // ??
|
||||
|
||||
"3C 00 " + // ContinueRecord.sid
|
||||
"05 00 " + // size 5
|
||||
"01 " + // unicode uncompressed
|
||||
"41 00 42 00 " + // 'AB'
|
||||
"3C 00 " + // ContinueRecord.sid
|
||||
"10 00 " + // size 16
|
||||
"00 00 18 00 00 00 00 00 " +
|
||||
"02 00 00 00 00 00 00 00 "
|
||||
);
|
||||
|
||||
|
||||
public void testLinkFormula() {
|
||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(linkData));
|
||||
is.nextRecord();
|
||||
TextObjectRecord rec = new TextObjectRecord(is);
|
||||
|
||||
Ptg ptg = rec.getLinkRefPtg();
|
||||
assertNotNull(ptg);
|
||||
assertEquals(RefPtg.class, ptg.getClass());
|
||||
RefPtg rptg = (RefPtg) ptg;
|
||||
assertEquals("T2", rptg.toFormulaString());
|
||||
|
||||
byte [] data2 = rec.serialize();
|
||||
assertEquals(linkData.length, data2.length);
|
||||
assertTrue(Arrays.equals(linkData, data2));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue