diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index 222f0a6ab..84ebf9962 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -95,7 +95,7 @@ public final class Workbook implements Model { protected int numxfs = 0; // hold the number of extended format records protected int numfonts = 0; // hold the number of font records - private short maxformatid = -1; // holds the max format id + private int maxformatid = -1; // holds the max format id private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used private DrawingManager2 drawingManager; private List escherBSERecords = new ArrayList(); // EscherBSERecord @@ -1106,15 +1106,8 @@ public final class Workbook implements Model { * @see org.apache.poi.hssf.record.Record * @return record containing a TabIdRecord */ - - protected Record createTabId() { - TabIdRecord retval = new TabIdRecord(); - short[] tabidarray = { - 0 - }; - - retval.setTabIdArray(tabidarray); - return retval; + private static TabIdRecord createTabId() { + return new TabIdRecord(); } /** @@ -1334,7 +1327,6 @@ public final class Workbook implements Model { * @see org.apache.poi.hssf.record.Record * @return record containing a FontRecord */ - protected Record createFont() { FontRecord retval = new FontRecord(); @@ -1342,7 +1334,6 @@ public final class Workbook implements Model { retval.setAttributes(( short ) 0x0); retval.setColorPaletteIndex(( short ) 0x7fff); retval.setBoldWeight(( short ) 0x190); - retval.setFontNameLength(( byte ) 5); retval.setFontName("Arial"); return retval; } @@ -1355,66 +1346,21 @@ public final class Workbook implements Model { * @see org.apache.poi.hssf.record.FormatRecord * @see org.apache.poi.hssf.record.Record */ - - protected Record createFormat(int id) { // we'll need multiple editions for - FormatRecord retval = new FormatRecord(); // the differnt formats + private static FormatRecord createFormat(int id) { + // we'll need multiple editions for + // the different formats switch (id) { - - case 0 : - retval.setIndexCode(( short ) 5); - retval.setFormatStringLength(( byte ) 0x17); - retval.setFormatString("\"$\"#,##0_);\\(\"$\"#,##0\\)"); - break; - - case 1 : - retval.setIndexCode(( short ) 6); - retval.setFormatStringLength(( byte ) 0x1c); - retval.setFormatString("\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)"); - break; - - case 2 : - retval.setIndexCode(( short ) 7); - retval.setFormatStringLength(( byte ) 0x1d); - retval.setFormatString("\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)"); - break; - - case 3 : - retval.setIndexCode(( short ) 8); - retval.setFormatStringLength(( byte ) 0x22); - retval.setFormatString( - "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)"); - break; - - case 4 : - retval.setIndexCode(( short ) 0x2a); - retval.setFormatStringLength(( byte ) 0x32); - retval.setFormatString( - "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"); - break; - - case 5 : - retval.setIndexCode(( short ) 0x29); - retval.setFormatStringLength(( byte ) 0x29); - retval.setFormatString( - "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"); - break; - - case 6 : - retval.setIndexCode(( short ) 0x2c); - retval.setFormatStringLength(( byte ) 0x3a); - retval.setFormatString( - "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"); - break; - - case 7 : - retval.setIndexCode(( short ) 0x2b); - retval.setFormatStringLength(( byte ) 0x31); - retval.setFormatString( - "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"); - break; + case 0: return new FormatRecord(5, "\"$\"#,##0_);\\(\"$\"#,##0\\)"); + case 1: return new FormatRecord(6, "\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)"); + case 2: return new FormatRecord(7, "\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)"); + case 3: return new FormatRecord(8, "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)"); + case 4: return new FormatRecord(0x2a, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"); + case 5: return new FormatRecord(0x29, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"); + case 6: return new FormatRecord(0x2c, "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"); + case 7: return new FormatRecord(0x2b, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"); } - return retval; + throw new IllegalArgumentException("Unexpected id " + id); } /** @@ -2061,12 +2007,12 @@ public final class Workbook implements Model { for (iterator = formats.iterator(); iterator.hasNext();) { FormatRecord r = (FormatRecord)iterator.next(); if (r.getFormatString().equals(format)) { - return r.getIndexCode(); + return (short)r.getIndexCode(); } } if (createIfNotFound) { - return createFormat(format); + return (short)createFormat(format); } return -1; @@ -2082,21 +2028,15 @@ public final class Workbook implements Model { /** * Creates a FormatRecord, inserts it, and returns the index code. - * @param format the format string + * @param formatString the format string * @return the index code of the format record. * @see org.apache.poi.hssf.record.FormatRecord * @see org.apache.poi.hssf.record.Record */ - public short createFormat( String format ) - { -// ++xfpos; //These are to ensure that positions are updated properly -// ++palettepos; -// ++bspos; - FormatRecord rec = new FormatRecord(); - maxformatid = maxformatid >= (short) 0xa4 ? (short) ( maxformatid + 1 ) : (short) 0xa4; //Starting value from M$ empiracle study. - rec.setIndexCode( maxformatid ); - rec.setFormatStringLength( (byte) format.length() ); - rec.setFormatString( format ); + public int createFormat(String formatString) { + + maxformatid = maxformatid >= 0xa4 ? maxformatid + 1 : 0xa4; //Starting value from M$ empircal study. + FormatRecord rec = new FormatRecord(maxformatid, formatString); int pos = 0; while ( pos < records.size() && records.get( pos ).getSid() != FormatRecord.sid ) diff --git a/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java b/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java index 17d337f82..391a3a08b 100644 --- a/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java @@ -24,20 +24,19 @@ import java.util.List; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.HexDump; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; /** - * Title: Bound Sheet Record (aka BundleSheet)

- * Description: Defines a sheet within a workbook. Basically stores the sheetname + * Title: Bound Sheet Record (aka BundleSheet) (0x0085)

+ * Description: Defines a sheet within a workbook. Basically stores the sheet name * and tells where the Beginning of file record is within the HSSF * file.

* REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Sergei Kozello (sergeikozello at mail.ru) - * @version 2.0-pre */ -public final class BoundSheetRecord extends Record { +public final class BoundSheetRecord extends StandardRecord { public final static short sid = 0x0085; private static final BitField hiddenFlag = BitFieldFactory.getInstance(0x01); @@ -160,23 +159,19 @@ public final class BoundSheetRecord extends Record { return 8 + field_5_sheetname.length() * (isMultibyte() ? 2 : 1); } - public int serialize(int offset, byte[] data) { - int dataSize = getDataSize(); - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, dataSize); - LittleEndian.putInt(data, 4 + offset, getPositionOfBof()); - LittleEndian.putUShort(data, 8 + offset, field_2_option_flags); + public void serialize(LittleEndianOutput out) { + out.writeInt(getPositionOfBof()); + out.writeShort(field_2_option_flags); String name = field_5_sheetname; - LittleEndian.putByte(data, 10 + offset, name.length()); - LittleEndian.putByte(data, 11 + offset, field_4_isMultibyteUnicode); + out.writeByte(name.length()); + out.writeByte(field_4_isMultibyteUnicode); if (isMultibyte()) { - StringUtil.putUnicodeLE(name, data, 12 + offset); + StringUtil.putUnicodeLE(name, out); } else { - StringUtil.putCompressedUnicode(name, data, 12 + offset); + StringUtil.putCompressedUnicode(name, out); } - return 4 + dataSize; } public short getSid() { @@ -215,16 +210,14 @@ public final class BoundSheetRecord extends Record { * Converts a List of {@link BoundSheetRecord}s to an array and sorts by the position of their * BOFs. */ - public static BoundSheetRecord[] orderByBofPosition(List boundSheetRecords) { + public static BoundSheetRecord[] orderByBofPosition(List boundSheetRecords) { BoundSheetRecord[] bsrs = new BoundSheetRecord[boundSheetRecords.size()]; boundSheetRecords.toArray(bsrs); Arrays.sort(bsrs, BOFComparator); return bsrs; } - private static final Comparator BOFComparator = new Comparator() { - public int compare(Object bsr1, Object bsr2) { - return compare((BoundSheetRecord)bsr1, (BoundSheetRecord)bsr2); - } + private static final Comparator BOFComparator = new Comparator() { + public int compare(BoundSheetRecord bsr1, BoundSheetRecord bsr2) { return bsr1.getPositionOfBof() - bsr2.getPositionOfBof(); } diff --git a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java index eeadd388a..eb17ee275 100644 --- a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java +++ b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java @@ -20,15 +20,15 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.record.cf.CellRangeUtil; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** - * Conditional Formatting Header record CFHEADER (0x1B0) + * Conditional Formatting Header record CFHEADER (0x01B0) * * @author Dmitriy Kumshayev */ -public final class CFHeaderRecord extends Record { - public static final short sid = 0x1B0; +public final class CFHeaderRecord extends StandardRecord { + public static final short sid = 0x01B0; private int field_1_numcf; private int field_2_need_recalculation; @@ -136,23 +136,15 @@ public final class CFHeaderRecord extends Record { + field_4_cell_ranges.getSize(); } - /** - * @return byte array containing instance data - */ - public int serialize(int offset, byte[] data) { - int dataSize = getDataSize(); - - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, dataSize); - LittleEndian.putUShort(data, 4 + offset, field_1_numcf); - LittleEndian.putUShort(data, 6 + offset, field_2_need_recalculation); - field_3_enclosing_cell_range.serialize(8 + offset, data); - field_4_cell_ranges.serialize(16 + offset, data); - return 4 + dataSize; + public void serialize(LittleEndianOutput out) { + + out.writeShort(field_1_numcf); + out.writeShort(field_2_need_recalculation); + field_3_enclosing_cell_range.serialize(out); + field_4_cell_ranges.serialize(out); } - public short getSid() - { + public short getSid() { return sid; } diff --git a/src/java/org/apache/poi/hssf/record/ChartTitleFormatRecord.java b/src/java/org/apache/poi/hssf/record/ChartTitleFormatRecord.java index 37f539e4a..d24c58a7d 100644 --- a/src/java/org/apache/poi/hssf/record/ChartTitleFormatRecord.java +++ b/src/java/org/apache/poi/hssf/record/ChartTitleFormatRecord.java @@ -20,76 +20,67 @@ */ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; - -import java.util.ArrayList; +import org.apache.poi.util.LittleEndianOutput; /** + * CHARTTITLEFORMAT (0x1050)

* Describes the formatting runs associated with a chart title. */ -public class ChartTitleFormatRecord extends Record { +public class ChartTitleFormatRecord extends StandardRecord { public static final short sid = 0x1050; - private int m_recs; + private CTFormat[] _formats; - private class CTFormat { - private short m_offset; - private short m_fontIndex; + private static final class CTFormat { + public static final int ENCODED_SIZE=4; + private int _offset; + private int _fontIndex; protected CTFormat(short offset,short fontIdx){ - m_offset = offset; - m_fontIndex = fontIdx; + _offset = offset; + _fontIndex = fontIdx; } - public short getOffset(){ - return m_offset; + public CTFormat(RecordInputStream in) { + _offset = in.readShort(); + _fontIndex = in.readShort(); } - public void setOffset(short newOff){ - m_offset = newOff; - } - public short getFontIndex() { - return m_fontIndex; - } - } - - private ArrayList m_formats; - public ChartTitleFormatRecord() { - super(); + public int getOffset(){ + return _offset; + } + public void setOffset(int newOff){ + _offset = newOff; + } + public int getFontIndex() { + return _fontIndex; + } + + public void serialize(LittleEndianOutput out) { + out.writeShort(_offset); + out.writeShort(_fontIndex); + } } + public ChartTitleFormatRecord(RecordInputStream in) { - m_recs = in.readUShort(); - int idx; - CTFormat ctf; - if (m_formats == null){ - m_formats = new ArrayList(m_recs); - } - for(idx=0;idx * Description: Used by Excel and other MS apps to quickly find rows in the sheets.

* REFERENCE: PG 299/440 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height - * @version 2.0-pre */ -public final class DBCellRecord extends Record { +public final class DBCellRecord extends StandardRecord { + public final static short sid = 0x00D7; public final static int BLOCK_SIZE = 32; - public final static short sid = 0xd7; - private int field_1_row_offset; - private short[] field_2_cell_offsets; + + public static final class Builder { + private short[] _cellOffsets; + private int _nCellOffsets; + public Builder() { + _cellOffsets = new short[4]; + } - public DBCellRecord() - { - field_2_cell_offsets = new short[0]; + public void addCellOffset(int cellRefOffset) { + if (_cellOffsets.length <= _nCellOffsets) { + short[] temp = new short[_nCellOffsets * 2]; + System.arraycopy(_cellOffsets, 0, temp, 0, _nCellOffsets); + _cellOffsets = temp; + } + _cellOffsets[_nCellOffsets] = (short) cellRefOffset; + _nCellOffsets++; + } + + public DBCellRecord build(int rowOffset) { + short[] cellOffsets = new short[_nCellOffsets]; + System.arraycopy(_cellOffsets, 0, cellOffsets, 0, _nCellOffsets); + return new DBCellRecord(rowOffset, cellOffsets); + } + } + /** + * offset from the start of this DBCellRecord to the start of the first cell in + * the next DBCell block. + */ + private final int field_1_row_offset; + private final short[] field_2_cell_offsets; + + DBCellRecord(int rowOffset, short[]cellOffsets) { + field_1_row_offset = rowOffset; + field_2_cell_offsets = cellOffsets; } - public DBCellRecord(RecordInputStream in) - { + public DBCellRecord(RecordInputStream in) { field_1_row_offset = in.readUShort(); int size = in.remaining(); field_2_cell_offsets = new short[ size / 2 ]; @@ -50,101 +77,28 @@ public final class DBCellRecord extends Record { } } - /** - * sets offset from the start of this DBCellRecord to the start of the first cell in - * the next DBCell block. - * - * @param offset offset to the start of the first cell in the next DBCell block - */ - public void setRowOffset(int offset) - { - field_1_row_offset = offset; - } - // need short list impl. - public void addCellOffset(short offset) - { - if (field_2_cell_offsets == null) - { - field_2_cell_offsets = new short[ 1 ]; - } - else - { - short[] temp = new short[ field_2_cell_offsets.length + 1 ]; - - System.arraycopy(field_2_cell_offsets, 0, temp, 0, - field_2_cell_offsets.length); - field_2_cell_offsets = temp; - } - field_2_cell_offsets[ field_2_cell_offsets.length - 1 ] = offset; - } - - /** - * gets offset from the start of this DBCellRecord to the start of the first cell in - * the next DBCell block. - * - * @return rowoffset to the start of the first cell in the next DBCell block - */ - public int getRowOffset() - { - return field_1_row_offset; - } - - /** - * return the cell offset in the array - * - * @param index of the cell offset to retrieve - * @return celloffset from the celloffset array - */ - public short getCellOffsetAt(int index) - { - return field_2_cell_offsets[ index ]; - } - - /** - * get the number of cell offsets in the celloffset array - * - * @return number of cell offsets - */ - public int getNumCellOffsets() - { - return field_2_cell_offsets.length; - } - - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[DBCELL]\n"); - buffer.append(" .rowoffset = ") - .append(Integer.toHexString(getRowOffset())).append("\n"); - for (int k = 0; k < getNumCellOffsets(); k++) - { - buffer.append(" .cell_" + k + " = ") - .append(Integer.toHexString(getCellOffsetAt(k))).append("\n"); + buffer.append(" .rowoffset = ").append(HexDump.intToHex(field_1_row_offset)).append("\n"); + for (int k = 0; k < field_2_cell_offsets.length; k++) { + buffer.append(" .cell_").append(k).append(" = ") + .append(HexDump.shortToHex(field_2_cell_offsets[ k ])).append("\n"); } buffer.append("[/DBCELL]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - if (field_2_cell_offsets == null) - { - field_2_cell_offsets = new short[ 0 ]; + public void serialize(LittleEndianOutput out) { + out.writeInt(field_1_row_offset); + for (int k = 0; k < field_2_cell_offsets.length; k++) { + out.writeShort(field_2_cell_offsets[ k ]); } - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, - (( short ) (4 + (getNumCellOffsets() * 2)))); - LittleEndian.putInt(data, 4 + offset, getRowOffset()); - for (int k = 0; k < getNumCellOffsets(); k++) - { - LittleEndian.putShort(data, 8 + 2*k + offset, getCellOffsetAt(k)); - } - return getRecordSize(); } protected int getDataSize() { - return 4 + (getNumCellOffsets() * 2); + return 4 + field_2_cell_offsets.length * 2; } /** @@ -158,14 +112,12 @@ public final class DBCellRecord extends Record { return nBlocks * 8 + nRows * 2; } - public short getSid() - { + public short getSid() { return sid; } public Object clone() { - // TODO - make immutable. - // this should be safe because only the instantiating code mutates these objects + // safe because immutable return this; } } diff --git a/src/java/org/apache/poi/hssf/record/DVALRecord.java b/src/java/org/apache/poi/hssf/record/DVALRecord.java index 69e94deac..0bd4600b6 100644 --- a/src/java/org/apache/poi/hssf/record/DVALRecord.java +++ b/src/java/org/apache/poi/hssf/record/DVALRecord.java @@ -16,16 +16,15 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: DATAVALIDATIONS Record

+ * Title: DATAVALIDATIONS Record (0x01B2)

* Description: used in data validation ; * This record is the list header of all data validation records (0x01BE) in the current sheet. * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) */ -public class DVALRecord extends Record -{ +public final class DVALRecord extends StandardRecord { public final static short sid = 0x01B2; /** Options of the DVAL */ @@ -48,57 +47,51 @@ public class DVALRecord extends Record field_5_dv_no = 0x00000000; } - public DVALRecord(RecordInputStream in) - { - this.field_1_options = in.readShort(); - this.field_2_horiz_pos = in.readInt(); - this.field_3_vert_pos = in.readInt(); - this.field_cbo_id = in.readInt(); - this.field_5_dv_no = in.readInt(); + public DVALRecord(RecordInputStream in) { + field_1_options = in.readShort(); + field_2_horiz_pos = in.readInt(); + field_3_vert_pos = in.readInt(); + field_cbo_id = in.readInt(); + field_5_dv_no = in.readInt(); } - /** * @param field_1_options the options of the dialog */ - public void setOptions(short field_1_options) { - this.field_1_options = field_1_options; + public void setOptions(short options) { + field_1_options = options; } /** * @param field_2_horiz_pos the Horizontal position of the dialog */ - public void setHorizontalPos(int field_2_horiz_pos) { - this.field_2_horiz_pos = field_2_horiz_pos; + public void setHorizontalPos(int horiz_pos) { + field_2_horiz_pos = horiz_pos; } /** * @param field_3_vert_pos the Vertical position of the dialog */ - public void setVerticalPos(int field_3_vert_pos) { - this.field_3_vert_pos = field_3_vert_pos; + public void setVerticalPos(int vert_pos) { + field_3_vert_pos = vert_pos; } /** * set the object ID of the drop down arrow object for list boxes * @param cboID - Object ID */ - public void setObjectID(int cboID) - { - this.field_cbo_id = cboID; + public void setObjectID(int cboID) { + field_cbo_id = cboID; } /** * Set the number of following DV records * @param dvNo - the DV records number */ - public void setDVRecNo(int dvNo) - { - this.field_5_dv_no = dvNo; + public void setDVRecNo(int dvNo) { + field_5_dv_no = dvNo; } - - /** * @return the field_1_options */ @@ -123,64 +116,55 @@ public class DVALRecord extends Record /** * get Object ID of the drop down arrow object for list boxes */ - public int getObjectID( ) - { - return this.field_cbo_id; + public int getObjectID() { + return field_cbo_id; } /** * Get number of following DV records */ - public int getDVRecNo( ) - { - return this.field_5_dv_no; + public int getDVRecNo() { + return field_5_dv_no; } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[DVAL]\n"); - buffer.append(" .options = ").append(this.getOptions()).append('\n'); - buffer.append(" .horizPos = ").append(this.getHorizontalPos()).append('\n'); - buffer.append(" .vertPos = ").append(this.getVerticalPos()).append('\n'); - buffer.append(" .comboObjectID = ").append(Integer.toHexString(this.getObjectID())).append("\n"); - buffer.append(" .DVRecordsNumber = ").append(Integer.toHexString(this.getDVRecNo())).append("\n"); + buffer.append(" .options = ").append(getOptions()).append('\n'); + buffer.append(" .horizPos = ").append(getHorizontalPos()).append('\n'); + buffer.append(" .vertPos = ").append(getVerticalPos()).append('\n'); + buffer.append(" .comboObjectID = ").append(Integer.toHexString(getObjectID())).append("\n"); + buffer.append(" .DVRecordsNumber = ").append(Integer.toHexString(getDVRecNo())).append("\n"); buffer.append("[/DVAL]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - LittleEndian.putShort(data, 0 + offset, this.sid); - LittleEndian.putShort(data, 2 + offset, ( short)(this.getRecordSize()-4)); - - LittleEndian.putShort(data, 4 + offset, this.getOptions()); - LittleEndian.putInt(data, 6 + offset, this.getHorizontalPos()); - LittleEndian.putInt(data, 10 + offset, this.getVerticalPos()); - LittleEndian.putInt(data, 14 + offset, this.getObjectID()); - LittleEndian.putInt(data, 18 + offset, this.getDVRecNo()); - return getRecordSize(); + public void serialize(LittleEndianOutput out) { + + out.writeShort(getOptions()); + out.writeInt(getHorizontalPos()); + out.writeInt(getVerticalPos()); + out.writeInt(getObjectID()); + out.writeInt(getDVRecNo()); } protected int getDataSize() { return 18; } - public short getSid() - { - return this.sid; + public short getSid() { + return sid; } - public Object clone() - { + public Object clone() { DVALRecord rec = new DVALRecord(); rec.field_1_options = field_1_options; rec.field_2_horiz_pos = field_2_horiz_pos; rec.field_3_vert_pos = field_3_vert_pos; - rec.field_cbo_id = this.field_cbo_id; - rec.field_5_dv_no = this.field_5_dv_no; + rec.field_cbo_id = field_cbo_id; + rec.field_5_dv_no = field_5_dv_no; return rec; } } diff --git a/src/java/org/apache/poi/hssf/record/DrawingRecord.java b/src/java/org/apache/poi/hssf/record/DrawingRecord.java index b0af2c7e6..9ba18aee0 100644 --- a/src/java/org/apache/poi/hssf/record/DrawingRecord.java +++ b/src/java/org/apache/poi/hssf/record/DrawingRecord.java @@ -17,9 +17,12 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; - -public final class DrawingRecord extends Record { +import org.apache.poi.util.LittleEndianOutput; +/** + * DrawingRecord (0x00EC)

+ * + */ +public final class DrawingRecord extends StandardRecord { public static final short sid = 0x00EC; private static final byte[] EMPTY_BYTE_ARRAY = { }; @@ -31,70 +34,50 @@ public final class DrawingRecord extends Record { recordData = EMPTY_BYTE_ARRAY; } - public DrawingRecord( RecordInputStream in ) - { + public DrawingRecord(RecordInputStream in) { recordData = in.readRemainder(); } - public void processContinueRecord( byte[] record ) - { + public void processContinueRecord(byte[] record) { //don't merge continue record with the drawing record, it must be serialized separately contd = record; } - public int serialize( int offset, byte[] data ) - { - if (recordData == null) - { - recordData = new byte[ 0 ]; - } - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) (recordData.length)); - if (recordData.length > 0) - { - System.arraycopy(recordData, 0, data, 4 + offset, recordData.length); - } - return getRecordSize(); + public void serialize(LittleEndianOutput out) { + out.write(recordData); } protected int getDataSize() { - int retval = 0; - - if (recordData != null) { - retval += recordData.length; - } - return retval; + return recordData.length; } - public short getSid() - { + public short getSid() { return sid; } - public byte[] getData() - { + public byte[] getData() { if(contd != null) { byte[] newBuffer = new byte[ recordData.length + contd.length ]; System.arraycopy( recordData, 0, newBuffer, 0, recordData.length ); System.arraycopy( contd, 0, newBuffer, recordData.length, contd.length); return newBuffer; - } else { - return recordData; } + return recordData; } - public void setData( byte[] thedata ) - { - this.recordData = thedata; + public void setData(byte[] thedata) { + if (thedata == null) { + throw new IllegalArgumentException("data must not be null"); + } + recordData = thedata; } public Object clone() { DrawingRecord rec = new DrawingRecord(); - rec.recordData = new byte[ recordData.length ]; - System.arraycopy(recordData, 0, rec.recordData, 0, recordData.length); + rec.recordData = recordData.clone(); if (contd != null) { - System.arraycopy(contd, 0, rec.contd, 0, contd.length); - rec.contd = new byte[ contd.length ]; + // TODO - this code probably never executes + rec.contd = contd.clone(); } return rec; diff --git a/src/java/org/apache/poi/hssf/record/ExtSSTInfoSubRecord.java b/src/java/org/apache/poi/hssf/record/ExtSSTInfoSubRecord.java deleted file mode 100644 index 845f95a16..000000000 --- a/src/java/org/apache/poi/hssf/record/ExtSSTInfoSubRecord.java +++ /dev/null @@ -1,111 +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. -==================================================================== */ - - -/* - * ExtSSTInfoSubRecord.java - * - * Created on September 8, 2001, 8:37 PM - */ -package org.apache.poi.hssf.record; - -import org.apache.poi.util.LittleEndian; - -/** - * Extended SST table info subrecord

- * contains the elements of "info" in the SST's array field

- * @author Andrew C. Oliver (acoliver at apache dot org) - * @version 2.0-pre - * @see org.apache.poi.hssf.record.ExtSSTRecord - */ - -public class ExtSSTInfoSubRecord - extends Record -{ - public static final int INFO_SIZE = 8; - public final static short sid = - 0xFFF; // only here for conformance, doesn't really have an sid - private int field_1_stream_pos; // stream pointer to the SST record - private short field_2_bucket_sst_offset; // don't really understand this yet. - private short field_3_zero; // must be 0; - - /** Creates new ExtSSTInfoSubRecord */ - - public ExtSSTInfoSubRecord() - { - } - - public ExtSSTInfoSubRecord(RecordInputStream in) - { - field_1_stream_pos = in.readInt(); - field_2_bucket_sst_offset = in.readShort(); - field_3_zero = in.readShort(); - } - - public void setStreamPos(int pos) - { - field_1_stream_pos = pos; - } - - public void setBucketRecordOffset(short offset) - { - field_2_bucket_sst_offset = offset; - } - - public int getStreamPos() - { - return field_1_stream_pos; - } - - public short getBucketSSTOffset() - { - return field_2_bucket_sst_offset; - } - - public String toString() - { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[EXTSST]\n"); - buffer.append(" .streampos = ") - .append(Integer.toHexString(getStreamPos())).append("\n"); - buffer.append(" .bucketsstoffset= ") - .append(Integer.toHexString(getBucketSSTOffset())).append("\n"); - buffer.append(" .zero = ") - .append(Integer.toHexString(field_3_zero)).append("\n"); - buffer.append("[/EXTSST]\n"); - return buffer.toString(); - } - - public int serialize(int offset, byte [] data) - { - LittleEndian.putInt(data, 0 + offset, getStreamPos()); - LittleEndian.putShort(data, 4 + offset, getBucketSSTOffset()); - LittleEndian.putShort(data, 6 + offset, ( short ) 0); - return getRecordSize(); - } - - protected int getDataSize() { - return 4; - } - - public short getSid() - { - return sid; - } -} diff --git a/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java b/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java index 8225f6b76..f5fe5df32 100644 --- a/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java @@ -17,13 +17,10 @@ package org.apache.poi.hssf.record; -import java.util.ArrayList; -import java.util.List; - -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: Extended Static String Table

+ * Title: Extended Static String Table (0x00FF)

* Description: This record is used for a quick lookup into the SST record. This * record breaks the SST table into a set of buckets. The offsets * to these buckets within the SST record are kept as well as the @@ -31,101 +28,108 @@ import org.apache.poi.util.LittleEndian; * REFERENCE: PG 313 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at apache dot org) - * @version 2.0-pre + * * @see org.apache.poi.hssf.record.ExtSSTInfoSubRecord */ -public final class ExtSSTRecord extends Record { +public final class ExtSSTRecord extends StandardRecord { public final static short sid = 0x00FF; public static final int DEFAULT_BUCKET_SIZE = 8; //Can't seem to find this documented but from the biffviewer it is clear that //Excel only records the indexes for the first 128 buckets. public static final int MAX_BUCKETS = 128; - private short field_1_strings_per_bucket = DEFAULT_BUCKET_SIZE; - private List field_2_sst_info; + + + private static final class InfoSubRecord { + public static final int ENCODED_SIZE = 8; + private int field_1_stream_pos; // stream pointer to the SST record + private int field_2_bucket_sst_offset; // don't really understand this yet. + /** unused - supposed to be zero */ + private short field_3_zero; + + /** Creates new ExtSSTInfoSubRecord */ + + public InfoSubRecord(int streamPos, int bucketSstOffset) { + field_1_stream_pos = streamPos; + field_2_bucket_sst_offset = bucketSstOffset; + } + + public InfoSubRecord(RecordInputStream in) + { + field_1_stream_pos = in.readInt(); + field_2_bucket_sst_offset = in.readShort(); + field_3_zero = in.readShort(); + } + + public int getStreamPos() { + return field_1_stream_pos; + } + + public int getBucketSSTOffset() { + return field_2_bucket_sst_offset; + } + + public void serialize(LittleEndianOutput out) { + out.writeInt(field_1_stream_pos); + out.writeShort(field_2_bucket_sst_offset); + out.writeShort(field_3_zero); + } + } + + + private short _stringsPerBucket; + private InfoSubRecord[] _sstInfos; - public ExtSSTRecord() - { - field_2_sst_info = new ArrayList(); + public ExtSSTRecord() { + _stringsPerBucket = DEFAULT_BUCKET_SIZE; + _sstInfos = new InfoSubRecord[0]; } - public ExtSSTRecord(RecordInputStream in) - { - field_2_sst_info = new ArrayList(); - field_1_strings_per_bucket = in.readShort(); - while (in.remaining() > 0) { - ExtSSTInfoSubRecord rec = new ExtSSTInfoSubRecord(in); - - field_2_sst_info.add(rec); + public ExtSSTRecord(RecordInputStream in) { + _stringsPerBucket = in.readShort(); + int nInfos = in.remaining() / InfoSubRecord.ENCODED_SIZE; + _sstInfos = new InfoSubRecord[nInfos]; + for (int i = 0; i < _sstInfos.length; i++) { + _sstInfos[i] = new InfoSubRecord(in); } } - public void setNumStringsPerBucket(short numStrings) - { - field_1_strings_per_bucket = numStrings; + public void setNumStringsPerBucket(short numStrings) { + _stringsPerBucket = numStrings; } - public void addInfoRecord(ExtSSTInfoSubRecord rec) - { - field_2_sst_info.add(rec); - } - - public short getNumStringsPerBucket() - { - return field_1_strings_per_bucket; - } - - public int getNumInfoRecords() - { - return field_2_sst_info.size(); - } - - public ExtSSTInfoSubRecord getInfoRecordAt(int elem) - { - return ( ExtSSTInfoSubRecord ) field_2_sst_info.get(elem); - } - - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[EXTSST]\n"); buffer.append(" .dsst = ") - .append(Integer.toHexString(getNumStringsPerBucket())) + .append(Integer.toHexString(_stringsPerBucket)) .append("\n"); - buffer.append(" .numInfoRecords = ").append(getNumInfoRecords()) + buffer.append(" .numInfoRecords = ").append(_sstInfos.length) .append("\n"); - for (int k = 0; k < getNumInfoRecords(); k++) + for (int k = 0; k < _sstInfos.length; k++) { buffer.append(" .inforecord = ").append(k).append("\n"); buffer.append(" .streampos = ") .append(Integer - .toHexString(getInfoRecordAt(k).getStreamPos())).append("\n"); + .toHexString(_sstInfos[k].getStreamPos())).append("\n"); buffer.append(" .sstoffset = ") .append(Integer - .toHexString(getInfoRecordAt(k).getBucketSSTOffset())) + .toHexString(_sstInfos[k].getBucketSSTOffset())) .append("\n"); } buffer.append("[/EXTSST]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); - LittleEndian.putShort(data, 4 + offset, field_1_strings_per_bucket); - int pos = 6; - - for (int k = 0; k < getNumInfoRecords(); k++) - { - ExtSSTInfoSubRecord rec = getInfoRecordAt(k); - pos += rec.serialize(pos + offset, data); + public void serialize(LittleEndianOutput out) { + out.writeShort(_stringsPerBucket); + for (int k = 0; k < _sstInfos.length; k++) { + _sstInfos[k].serialize(out); } - return pos; } protected int getDataSize() { - return 2 + 8*getNumInfoRecords(); + return 2 + InfoSubRecord.ENCODED_SIZE*_sstInfos.length; } public static final int getNumberOfInfoRecsForStrings(int numStrings) { @@ -133,7 +137,7 @@ public final class ExtSSTRecord extends Record { if ((numStrings % DEFAULT_BUCKET_SIZE) != 0) infoRecs ++; //Excel seems to max out after 128 info records. - //This isnt really documented anywhere... + //This isn't really documented anywhere... if (infoRecs > MAX_BUCKETS) infoRecs = MAX_BUCKETS; return infoRecs; @@ -141,24 +145,18 @@ public final class ExtSSTRecord extends Record { /** Given a number of strings (in the sst), returns the size of the extsst record*/ public static final int getRecordSizeForStrings(int numStrings) { - return 4 + 2 + (getNumberOfInfoRecsForStrings(numStrings) * 8); + return 4 + 2 + getNumberOfInfoRecsForStrings(numStrings) * 8; } - public short getSid() - { + public short getSid() { return sid; } - public void setBucketOffsets( int[] bucketAbsoluteOffsets, int[] bucketRelativeOffsets ) - { - this.field_2_sst_info = new ArrayList(bucketAbsoluteOffsets.length); - for ( int i = 0; i < bucketAbsoluteOffsets.length; i++ ) - { - ExtSSTInfoSubRecord r = new ExtSSTInfoSubRecord(); - r.setBucketRecordOffset((short)bucketRelativeOffsets[i]); - r.setStreamPos(bucketAbsoluteOffsets[i]); - field_2_sst_info.add(r); + public void setBucketOffsets(int[] bucketAbsoluteOffsets, int[] bucketRelativeOffsets) { + // TODO - replace no-arg constructor with this logic + _sstInfos = new InfoSubRecord[bucketAbsoluteOffsets.length]; + for (int i = 0; i < bucketAbsoluteOffsets.length; i++) { + _sstInfos[i] = new InfoSubRecord(bucketAbsoluteOffsets[i], bucketRelativeOffsets[i]); } } - } diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java index cbb287ed1..af6b9731a 100644 --- a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java @@ -20,7 +20,7 @@ package org.apache.poi.hssf.record; import java.util.ArrayList; import java.util.List; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** * EXTERNSHEET (0x0017)
@@ -28,9 +28,9 @@ import org.apache.poi.util.LittleEndian; * * @author Libin Roman (Vista Portal LDT. Developer) */ -public class ExternSheetRecord extends Record { +public class ExternSheetRecord extends StandardRecord { public final static short sid = 0x0017; - private List _list; + private List _list; private final class RefSubRecord { public static final int ENCODED_SIZE = 6; @@ -73,43 +73,27 @@ public class ExternSheetRecord extends Record { return buffer.toString(); } - /** - * called by the class that is responsible for writing this sucker. - * Subclasses should implement this so that their data is passed back in a - * byte array. - * - * @param offset to begin writing at - * @param data byte array containing instance data - * @return number of bytes written - */ - public void serialize(int offset, byte [] data) { - LittleEndian.putUShort(data, 0 + offset, _extBookIndex); - LittleEndian.putUShort(data, 2 + offset, _firstSheetIndex); - LittleEndian.putUShort(data, 4 + offset, _lastSheetIndex); + public void serialize(LittleEndianOutput out) { + out.writeShort(_extBookIndex); + out.writeShort(_firstSheetIndex); + out.writeShort(_lastSheetIndex); } } public ExternSheetRecord() { - _list = new ArrayList(); + _list = new ArrayList(); } - - /** - * called by the constructor, should set class level fields. Should throw - * runtime exception for bad/icomplete data. - * - * @param in the RecordInputstream to read the record from - */ + public ExternSheetRecord(RecordInputStream in) { - _list = new ArrayList(); + _list = new ArrayList(); int nItems = in.readShort(); for (int i = 0 ; i < nItems ; ++i) { RefSubRecord rec = new RefSubRecord(in); - - _list.add( rec); + _list.add(rec); } } @@ -157,35 +141,18 @@ public class ExternSheetRecord extends Record { return 2 + _list.size() * RefSubRecord.ENCODED_SIZE; } - /** - * called by the class that is responsible for writing this sucker. - * Subclasses should implement this so that their data is passed back in a - * byte array. - * - * @param offset to begin writing at - * @param data byte array containing instance data - * @return number of bytes written - */ - public int serialize(int offset, byte [] data) { - int dataSize = getDataSize(); - + public void serialize(LittleEndianOutput out) { int nItems = _list.size(); - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, dataSize); - LittleEndian.putUShort(data, 4 + offset, nItems); - - int pos = 6 ; + out.writeShort(nItems); for (int i = 0; i < nItems; i++) { - getRef(i).serialize(offset + pos, data); - pos +=6; + getRef(i).serialize(out); } - return dataSize + 4; } private RefSubRecord getRef(int i) { - return (RefSubRecord) _list.get(i); + return _list.get(i); } /** diff --git a/src/java/org/apache/poi/hssf/record/FileSharingRecord.java b/src/java/org/apache/poi/hssf/record/FileSharingRecord.java index f6b3e6340..d53911dde 100644 --- a/src/java/org/apache/poi/hssf/record/FileSharingRecord.java +++ b/src/java/org/apache/poi/hssf/record/FileSharingRecord.java @@ -17,19 +17,19 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; /** - * Title: FILESHARING

+ * Title: FILESHARING (0x005B)

* Description: stores the encrypted readonly for a workbook (write protect) * This functionality is accessed from the options dialog box available when performing 'Save As'.

* REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) */ -public final class FileSharingRecord extends Record { +public final class FileSharingRecord extends StandardRecord { - public final static short sid = 0x5b; + public final static short sid = 0x005B; private short field_1_readonly; private short field_2_password; private byte field_3_username_unicode_options; @@ -103,12 +103,6 @@ public final class FileSharingRecord extends Record { return field_2_password; } - /** - * @return byte representing the length of the username field - */ - public short getUsernameLength() { - return (short) field_3_username_value.length(); - } /** * @return username of the user that created the file @@ -139,22 +133,19 @@ public final class FileSharingRecord extends Record { return buffer.toString(); } - public int serialize(int offset, byte [] data) { + public void serialize(LittleEndianOutput out) { // TODO - junit - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4)); - LittleEndian.putShort(data, 4 + offset, getReadOnly()); - LittleEndian.putShort(data, 6 + offset, getPassword()); - LittleEndian.putShort(data, 8 + offset, getUsernameLength()); - if(getUsernameLength() > 0) { - LittleEndian.putByte(data, 10 + offset, field_3_username_unicode_options); - StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset ); + out.writeShort(getReadOnly()); + out.writeShort(getPassword()); + out.writeShort(field_3_username_value.length()); + if(field_3_username_value.length() > 0) { + out.writeByte(field_3_username_unicode_options); + StringUtil.putCompressedUnicode(getUsername(), out); } - return getRecordSize(); } protected int getDataSize() { - short nameLen = getUsernameLength(); + int nameLen = field_3_username_value.length(); if (nameLen < 1) { return 6; } diff --git a/src/java/org/apache/poi/hssf/record/FontRecord.java b/src/java/org/apache/poi/hssf/record/FontRecord.java index 890460f9e..3b0b4f3e3 100644 --- a/src/java/org/apache/poi/hssf/record/FontRecord.java +++ b/src/java/org/apache/poi/hssf/record/FontRecord.java @@ -17,18 +17,19 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.StringUtil; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndianOutput; +import org.apache.poi.util.StringUtil; /** - * Title: Font Record - descrbes a font in the workbook (index = 0-3,5-infinity - skip 4)

+ * Title: Font Record (0x0031)

+ * - describes a font in the workbook (index = 0-3,5-infinity - skip 4)

* Description: An element in the Font Table

* REFERENCE: PG 315 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) */ -public final class FontRecord extends Record { +public final class FontRecord extends StandardRecord { public final static short sid = 0x0031; // docs are wrong (0x231 Microsoft Support site article Q184647) public final static short SS_NONE = 0; public final static short SS_SUPER = 1; @@ -42,16 +43,12 @@ public final class FontRecord extends Record { private short field_2_attributes; // 0 0x01 - Reserved bit must be 0 - static final private BitField italic = - BitFieldFactory.getInstance(0x02); // is this font in italics + private static final BitField italic = BitFieldFactory.getInstance(0x02); // is this font in italics // 2 0x04 - reserved bit must be 0 - static final private BitField strikeout = - BitFieldFactory.getInstance(0x08); // is this font has a line through the center - static final private BitField macoutline = BitFieldFactory.getInstance( - 0x10); // some weird macintosh thing....but who understands those mac people anyhow - static final private BitField macshadow = BitFieldFactory.getInstance( - 0x20); // some weird macintosh thing....but who understands those mac people anyhow + private static final BitField strikeout =BitFieldFactory.getInstance(0x08); // is this font has a line through the center + private static final BitField macoutline = BitFieldFactory.getInstance(0x10); // some weird macintosh thing....but who understands those mac people anyhow + private static final BitField macshadow = BitFieldFactory.getInstance(0x20); // some weird macintosh thing....but who understands those mac people anyhow // 7-6 - reserved bits must be 0 // the rest is unused @@ -62,15 +59,13 @@ public final class FontRecord extends Record { private byte field_7_family; // ?? defined by windows api logfont structure? private byte field_8_charset; // ?? defined by windows api logfont structure? private byte field_9_zero = 0; // must be 0 - private byte field_10_font_name_len; // length of the font name + /** possibly empty string never null */ private String field_11_font_name; // whoa...the font name - public FontRecord() - { + public FontRecord() { } - public FontRecord(RecordInputStream in) - { + public FontRecord(RecordInputStream in) { field_1_font_height = in.readShort(); field_2_attributes = in.readShort(); field_3_color_palette_index = in.readShort(); @@ -80,17 +75,15 @@ public final class FontRecord extends Record { field_7_family = in.readByte(); field_8_charset = in.readByte(); field_9_zero = in.readByte(); - field_10_font_name_len = in.readByte(); - if (field_10_font_name_len > 0) - { - if (in.readByte() == 0) - { // is compressed unicode - field_11_font_name = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_font_name_len)); - } - else - { // is not compressed unicode + int field_10_font_name_len = in.readUByte(); + if (field_10_font_name_len > 0) { + if (in.readByte() == 0) { // is compressed unicode + field_11_font_name = in.readCompressedUnicode(field_10_font_name_len); + } else { // is not compressed unicode field_11_font_name = in.readUnicodeLEString(field_10_font_name_len); } + } else { + field_11_font_name = ""; } } @@ -244,17 +237,6 @@ public final class FontRecord extends Record { field_8_charset = charset; } - /** - * set the length of the fontname string - * - * @param len length of the font name - * @see #setFontName(String) - */ - - public void setFontNameLength(byte len) - { - field_10_font_name_len = len; - } /** * set the name of the font @@ -415,18 +397,6 @@ public final class FontRecord extends Record { return field_8_charset; } - /** - * get the length of the fontname string - * - * @return length of the font name - * @see #getFontName() - */ - - public byte getFontNameLength() - { - return field_10_font_name_len; - } - /** * get the name of the font * @@ -467,45 +437,46 @@ public final class FontRecord extends Record { .append(Integer.toHexString(getFamily())).append("\n"); buffer.append(" .charset = ") .append(Integer.toHexString(getCharset())).append("\n"); - buffer.append(" .namelength = ") - .append(Integer.toHexString(getFontNameLength())).append("\n"); buffer.append(" .fontname = ").append(getFontName()) .append("\n"); buffer.append("[/FONT]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - int realflen = getFontNameLength() * 2; - - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort( - data, 2 + offset, - ( short ) (15 + realflen - + 1)); // 19 - 4 (sid/len) + font name length = datasize - - // undocumented single byte (1) - LittleEndian.putShort(data, 4 + offset, getFontHeight()); - LittleEndian.putShort(data, 6 + offset, getAttributes()); - LittleEndian.putShort(data, 8 + offset, getColorPaletteIndex()); - LittleEndian.putShort(data, 10 + offset, getBoldWeight()); - LittleEndian.putShort(data, 12 + offset, getSuperSubScript()); - data[ 14 + offset ] = getUnderline(); - data[ 15 + offset ] = getFamily(); - data[ 16 + offset ] = getCharset(); - data[ 17 + offset ] = field_9_zero; - data[ 18 + offset ] = getFontNameLength(); - data[ 19 + offset ] = ( byte ) 1; - if (getFontName() != null) { - StringUtil.putUnicodeLE(getFontName(), data, 20 + offset); - } - return getRecordSize(); + public void serialize(LittleEndianOutput out) { + + out.writeShort(getFontHeight()); + out.writeShort(getAttributes()); + out.writeShort(getColorPaletteIndex()); + out.writeShort(getBoldWeight()); + out.writeShort(getSuperSubScript()); + out.writeByte(getUnderline()); + out.writeByte(getFamily()); + out.writeByte(getCharset()); + out.writeByte(field_9_zero); + int fontNameLen = field_11_font_name.length(); + out.writeByte(fontNameLen); + if (fontNameLen > 0) { + boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name); + out.writeByte(hasMultibyte ? 0x01 : 0x00); + if (hasMultibyte) { + StringUtil.putUnicodeLE(field_11_font_name, out); + } else { + StringUtil.putCompressedUnicode(field_11_font_name, out); + } + } } protected int getDataSize() { - // Note - no matter the original, we always - // re-serialise the font name as unicode - return 16 + getFontNameLength() * 2; + int size = 15; // 5 shorts + 5 bytes + int fontNameLen = field_11_font_name.length(); + if (fontNameLen < 1) { + // options byte is not encoded if no character data + return size; + } + size ++; // options byte + + boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name); + return size + fontNameLen * (hasMultibyte ? 2 : 1); } public short getSid() @@ -528,7 +499,6 @@ public final class FontRecord extends Record { field_7_family = source.field_7_family; field_8_charset = source.field_8_charset; field_9_zero = source.field_9_zero; - field_10_font_name_len = source.field_10_font_name_len; field_11_font_name = source.field_11_font_name; } @@ -548,7 +518,6 @@ public final class FontRecord extends Record { result = prime * result + field_7_family; result = prime * result + field_8_charset; result = prime * result + field_9_zero; - result = prime * result + field_10_font_name_len; return result; } @@ -572,7 +541,6 @@ public final class FontRecord extends Record { field_7_family == other.field_7_family && field_8_charset == other.field_8_charset && field_9_zero == other.field_9_zero && - field_10_font_name_len == other.field_10_font_name_len && field_11_font_name.equals(other.field_11_font_name) ; } diff --git a/src/java/org/apache/poi/hssf/record/FooterRecord.java b/src/java/org/apache/poi/hssf/record/FooterRecord.java index 0350d3a8c..b08d3dca1 100644 --- a/src/java/org/apache/poi/hssf/record/FooterRecord.java +++ b/src/java/org/apache/poi/hssf/record/FooterRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,191 +14,61 @@ 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.LittleEndian; -import org.apache.poi.util.StringUtil; - /** - * Title: Footer Record

+ * Title: Footer Record (0x0015)

* Description: Specifies the footer for a sheet

- * REFERENCE: PG 317 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

+ * REFERENCE: PG 317 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Shawn Laubach (slaubach at apache dot org) Modified 3/14/02 * @author Jason Height (jheight at chariot dot net dot au) - * @version 2.0-pre + * */ +public final class FooterRecord extends HeaderFooterBase { + public final static short sid = 0x0015; -public class FooterRecord - extends Record -{ - public final static short sid = 0x15; - private byte field_1_footer_len; - private byte field_2_reserved; - private byte field_3_unicode_flag; - private String field_4_footer; - - public FooterRecord() - { + public FooterRecord(String text) { + super(text); } - public FooterRecord(RecordInputStream in) - { - if (in.remaining() > 0) - { - field_1_footer_len = in.readByte(); - /** These two fields are a bit odd. They are not documented*/ - field_2_reserved = in.readByte(); - field_3_unicode_flag = in.readByte(); // unicode - - if(isMultibyte()) - { - field_4_footer = in.readUnicodeLEString(LittleEndian.ubyteToInt( field_1_footer_len)); - } - else - { - field_4_footer = in.readCompressedUnicode(LittleEndian.ubyteToInt( field_1_footer_len)); - } - } - } + public FooterRecord(RecordInputStream in) { + super(in); + } - /** - * see the unicode flag - * - * @return boolean flag - * true:footer string has at least one multibyte character - */ - public boolean isMultibyte() { - return ((field_3_unicode_flag & 0xFF) == 1); - } - - - /** - * set the length of the footer string - * - * @param len length of the footer string - * @see #setFooter(String) - */ - - public void setFooterLength(byte len) - { - field_1_footer_len = len; - } - - /** + /** * set the footer string * * @param footer string to display - * @see #setFooterLength(byte) */ - - public void setFooter(String footer) - { - field_4_footer = footer; - field_3_unicode_flag = - (byte) (StringUtil.hasMultibyte(field_4_footer) ? 1 : 0); - // Check it'll fit into the space in the record - - if(field_4_footer == null) return; - if(field_3_unicode_flag == 1) { - if(field_4_footer.length() > 127) { - throw new IllegalArgumentException("Footer string too long (limit is 127 for unicode strings)"); - } - } else { - if(field_4_footer.length() > 255) { - throw new IllegalArgumentException("Footer string too long (limit is 255 for non-unicode strings)"); - } - } - } - - /** - * get the length of the footer string - * - * @return length of the footer string - * @see #getFooter() - */ - - public short getFooterLength() - { - return (short)(0xFF & field_1_footer_len); // [Shawn] Fixed needing unsigned byte + public void setFooter(String footer) { + setText(footer); } /** * get the footer string * * @return footer string to display - * @see #getFooterLength() */ - - public String getFooter() - { - return field_4_footer; + public String getFooter() { + return getText(); } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[FOOTER]\n"); - buffer.append(" .footerlen = ") - .append(Integer.toHexString(getFooterLength())).append("\n"); - buffer.append(" .footer = ").append(getFooter()) - .append("\n"); + buffer.append(" .footer = ").append(getText()).append("\n"); buffer.append("[/FOOTER]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - int len = 4; - - if (getFooterLength() > 0) - { - len+=3; // [Shawn] Fixed for two null bytes in the length - } - short bytelen = (short)(isMultibyte() ? - getFooterLength()*2 : getFooterLength() ); - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, - ( short ) ((len - 4) + bytelen )); - if (getFooterLength() > 0) - { - data[ 4 + offset ] = (byte)getFooterLength(); - data[ 6 + offset ] = field_3_unicode_flag; - if(isMultibyte()) - { - StringUtil.putUnicodeLE(getFooter(), data, 7 + offset); - } - else - { - StringUtil.putCompressedUnicode(getFooter(), data, 7 + offset); // [Shawn] Place the string in the correct offset - } - } - return getRecordSize(); - } - - protected int getDataSize() { - int retval = 0; - - if (getFooterLength() > 0) { - retval+=3; // [Shawn] Fixed for two null bytes in the length - } - return retval + getFooterLength() * (isMultibyte() ? 2 : 1); - } - - public short getSid() - { + public short getSid() { return sid; } public Object clone() { - FooterRecord rec = new FooterRecord(); - rec.field_1_footer_len = field_1_footer_len; - rec.field_2_reserved = field_2_reserved; - rec.field_3_unicode_flag = field_3_unicode_flag; - rec.field_4_footer = field_4_footer; - return rec; + return new FooterRecord(getText()); } } diff --git a/src/java/org/apache/poi/hssf/record/FormatRecord.java b/src/java/org/apache/poi/hssf/record/FormatRecord.java index 6ea2ce963..2d2f238c5 100644 --- a/src/java/org/apache/poi/hssf/record/FormatRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormatRecord.java @@ -17,91 +17,41 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; /** - * Title: Format Record

- * Description: describes a number format -- those goofy strings like $(#,###)

+ * Title: Format Record (0x041E)

+ * Description: describes a number format -- those goofy strings like $(#,###)

* - * REFERENCE: PG 317 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

+ * REFERENCE: PG 317 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) - * @author Shawn M. Laubach (slaubach at apache dot org) + * @author Shawn M. Laubach (slaubach at apache dot org) */ -public final class FormatRecord extends Record { +public final class FormatRecord extends StandardRecord { public final static short sid = 0x041E; - private short field_1_index_code; - private short field_3_unicode_len; // unicode string length - private boolean field_3_unicode_flag; // it is not undocumented - it is unicode flag - private String field_4_formatstring; + private final int field_1_index_code; + private final boolean field_3_hasMultibyte; + private final String field_4_formatstring; - public FormatRecord() - { - } - - public FormatRecord(RecordInputStream in) - { - field_1_index_code = in.readShort(); - field_3_unicode_len = in.readShort(); - field_3_unicode_flag = ( in.readByte() & (byte)0x01 ) != 0; - - if ( field_3_unicode_flag ) { - // unicode - field_4_formatstring = in.readUnicodeLEString( field_3_unicode_len ); - } - else { - // not unicode - field_4_formatstring = in.readCompressedUnicode( field_3_unicode_len ); - } - } - - /** - * set the format index code (for built in formats) - * - * @param index the format index code - * @see org.apache.poi.hssf.model.Workbook - */ - - public void setIndexCode(short index) - { - field_1_index_code = index; - } - - /** - * set the format string length - * - * @param len the length of the format string - * @see #setFormatString(String) - */ - - public void setFormatStringLength(byte len) - { - - field_3_unicode_len = len; - } - - /** - * set whether the string is unicode - * - * @param unicode flag for whether string is unicode - */ - - public void setUnicodeFlag(boolean unicode) { - field_3_unicode_flag = unicode; - } - - /** - * set the format string - * - * @param fs the format string - * @see #setFormatStringLength(byte) - */ - - public void setFormatString(String fs) - { + public FormatRecord(int indexCode, String fs) { + field_1_index_code = indexCode; field_4_formatstring = fs; - setUnicodeFlag(StringUtil.hasMultibyte(fs)); + field_3_hasMultibyte = StringUtil.hasMultibyte(fs); + } + + public FormatRecord(RecordInputStream in) { + field_1_index_code = in.readShort(); + int field_3_unicode_len = in.readUShort(); + field_3_hasMultibyte = (in.readByte() & 0x01) != 0; + + if (field_3_hasMultibyte) { + field_4_formatstring = in.readUnicodeLEString(field_3_unicode_len); + } else { + field_4_formatstring = in.readCompressedUnicode(field_3_unicode_len); + } } /** @@ -110,95 +60,53 @@ public final class FormatRecord extends Record { * @return the format index code * @see org.apache.poi.hssf.model.Workbook */ - - public short getIndexCode() - { + public int getIndexCode() { return field_1_index_code; } - /** - * get the format string length - * - * @return the length of the format string - * @see #getFormatString() - */ - - /* public short getFormatStringLength() - { - return field_3_unicode_flag ? field_3_unicode_len : field_2_formatstring_len; - }*/ - - /** - * get whether the string is unicode - * - * @return flag for whether string is unicode - */ - - public boolean getUnicodeFlag() { - return field_3_unicode_flag; - } - /** * get the format string * * @return the format string */ - - public String getFormatString() - { + public String getFormatString() { return field_4_formatstring; } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[FORMAT]\n"); - buffer.append(" .indexcode = ") - .append(Integer.toHexString(getIndexCode())).append("\n"); - /* - buffer.append(" .formatstringlen = ") - .append(Integer.toHexString(getFormatStringLength())) - .append("\n"); - */ - buffer.append(" .unicode length = ") - .append(Integer.toHexString(field_3_unicode_len)).append("\n"); - buffer.append(" .isUnicode = ") - .append( field_3_unicode_flag ).append("\n"); - buffer.append(" .formatstring = ").append(getFormatString()) - .append("\n"); + buffer.append(" .indexcode = ").append(HexDump.shortToHex(getIndexCode())).append("\n"); + buffer.append(" .isUnicode = ").append(field_3_hasMultibyte ).append("\n"); + buffer.append(" .formatstring = ").append(getFormatString()).append("\n"); buffer.append("[/FORMAT]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, (short)( 2 + 2 + 1 + ( (field_3_unicode_flag) - ? 2 * field_3_unicode_len - : field_3_unicode_len ) ) ); - // index + len + flag + format string length - LittleEndian.putShort(data, 4 + offset, getIndexCode()); - LittleEndian.putShort(data, 6 + offset, field_3_unicode_len); - data[ 8 + offset ] = (byte)( (field_3_unicode_flag) ? 0x01 : 0x00 ); + public void serialize(LittleEndianOutput out) { + String formatString = getFormatString(); + out.writeShort(getIndexCode()); + out.writeShort(formatString.length()); + out.writeByte(field_3_hasMultibyte ? 0x01 : 0x00); - if ( field_3_unicode_flag ) { - // unicode - StringUtil.putUnicodeLE( getFormatString(), data, 9 + offset ); + if ( field_3_hasMultibyte ) { + StringUtil.putUnicodeLE( formatString, out); + } else { + StringUtil.putCompressedUnicode( formatString, out); } - else { - // not unicode - StringUtil.putCompressedUnicode( getFormatString(), data, 9 + offset ); - } - - return getRecordSize(); } protected int getDataSize() { - return 5 + field_3_unicode_len * (field_3_unicode_flag ? 2 : 1); + return 5 // 2 shorts + 1 byte + + getFormatString().length() * (field_3_hasMultibyte ? 2 : 1); } - public short getSid() - { + public short getSid() { return sid; } + @Override + public Object clone() { + // immutable + return this; + } } diff --git a/src/java/org/apache/poi/hssf/record/HeaderFooterBase.java b/src/java/org/apache/poi/hssf/record/HeaderFooterBase.java new file mode 100644 index 000000000..92ccf944f --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/HeaderFooterBase.java @@ -0,0 +1,109 @@ +/* ==================================================================== + 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.LittleEndianOutput; +import org.apache.poi.util.StringUtil; + +/** + * Common header/footer base class + * + * @author Josh Micich + */ +abstract class HeaderFooterBase extends StandardRecord { + private boolean field_2_hasMultibyte; + private String field_3_text; + + protected HeaderFooterBase(String text) { + setText(text); + } + + protected HeaderFooterBase(RecordInputStream in) { + if (in.remaining() > 0) { + int field_1_footer_len = in.readShort(); + field_2_hasMultibyte = in.readByte() != 0x00; + + if (field_2_hasMultibyte) { + field_3_text = in.readUnicodeLEString(field_1_footer_len); + } else { + field_3_text = in.readCompressedUnicode(field_1_footer_len); + } + } else { + // Note - this is unusual: when the text is empty string, the whole record is empty (just the 4 byte BIFF header) + field_3_text = ""; + } + } + + /** + * set the footer string + * + * @param text string to display + */ + public final void setText(String text) { + if (text == null) { + throw new IllegalArgumentException("text must not be null"); + } + field_2_hasMultibyte = StringUtil.hasMultibyte(text); + field_3_text = text; + + // Check it'll fit into the space in the record + if (field_2_hasMultibyte) { + if (field_3_text.length() > 127) { + throw new IllegalArgumentException( + "Footer string too long (limit is 127 for unicode strings)"); + } + } else { + if (field_3_text.length() > 255) { + throw new IllegalArgumentException( + "Footer string too long (limit is 255 for non-unicode strings)"); + } + } + } + + /** + * get the length of the footer string + * + * @return length of the footer string + */ + private int getTextLength() { + return field_3_text.length(); + } + + public final String getText() { + return field_3_text; + } + + public final void serialize(LittleEndianOutput out) { + if (getTextLength() > 0) { + out.writeShort(getTextLength()); + out.writeByte(field_2_hasMultibyte ? 0x01 : 0x00); + if (field_2_hasMultibyte) { + StringUtil.putUnicodeLE(field_3_text, out); + } else { + StringUtil.putCompressedUnicode(field_3_text, out); + } + } + } + + protected final int getDataSize() { + if (getTextLength() < 1) { + return 0; + } + return 3 + getTextLength() * (field_2_hasMultibyte ? 2 : 1); + } +} diff --git a/src/java/org/apache/poi/hssf/record/HeaderRecord.java b/src/java/org/apache/poi/hssf/record/HeaderRecord.java index aea321eac..188149d7d 100644 --- a/src/java/org/apache/poi/hssf/record/HeaderRecord.java +++ b/src/java/org/apache/poi/hssf/record/HeaderRecord.java @@ -17,8 +17,6 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.StringUtil; /** * Title: Header Record

@@ -28,172 +26,50 @@ import org.apache.poi.util.StringUtil; * @author Shawn Laubach (slaubach at apache dot org) Modified 3/14/02 * @author Jason Height (jheight at chariot dot net dot au) */ -public final class HeaderRecord extends Record { +public final class HeaderRecord extends HeaderFooterBase { public final static short sid = 0x0014; - private byte field_1_header_len; - private byte field_2_reserved; - private byte field_3_unicode_flag; - private String field_4_header; - public HeaderRecord() - { + public HeaderRecord(String text) { + super(text); } - public HeaderRecord(RecordInputStream in) - { - if (in.remaining() > 0) - { - field_1_header_len = in.readByte(); - /** These two fields are a bit odd. They are not documented*/ - field_2_reserved = in.readByte(); - field_3_unicode_flag = in.readByte(); // unicode - - if(isMultibyte()) - { - field_4_header = in.readUnicodeLEString(LittleEndian.ubyteToInt( field_1_header_len)); - } - else - { - field_4_header = in.readCompressedUnicode(LittleEndian.ubyteToInt( field_1_header_len)); - } - } - } - - /** - * see the unicode flag - * - * @return boolean flag - * true:footer string has at least one multibyte character - */ - public boolean isMultibyte() { - return ((field_3_unicode_flag & 0xFF) == 1); - } - - /** - * set the length of the header string - * - * @param len length of the header string - * @see #setHeader(String) - */ - - public void setHeaderLength(byte len) - { - field_1_header_len = len; + public HeaderRecord(RecordInputStream in) { + super(in); } /** * set the header string * * @param header string to display - * @see #setHeaderLength(byte) */ - - public void setHeader(String header) - { - field_4_header = header; - field_3_unicode_flag = - (byte) (StringUtil.hasMultibyte(field_4_header) ? 1 : 0); - - // Check it'll fit into the space in the record - if(field_4_header == null) return; - if(field_3_unicode_flag == 1) { - if(field_4_header.length() > 127) { - throw new IllegalArgumentException("Header string too long (limit is 127 for unicode strings)"); - } - } else { - if(field_4_header.length() > 255) { - throw new IllegalArgumentException("Header string too long (limit is 255 for non-unicode strings)"); - } - } - } - - /** - * get the length of the header string - * - * @return length of the header string - * @see #getHeader() - */ - - public short getHeaderLength() - { - return (short)(0xFF & field_1_header_len); // [Shawn] Fixed needing unsigned byte + public void setHeader(String header) { + setText(header); } /** * get the header string * * @return header string to display - * @see #getHeaderLength() */ - - public String getHeader() - { - return field_4_header; + public String getHeader() { + return getText(); } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[HEADER]\n"); - buffer.append(" .length = ").append(getHeaderLength()) - .append("\n"); - buffer.append(" .header = ").append(getHeader()) - .append("\n"); + buffer.append(" .header = ").append(getText()).append("\n"); buffer.append("[/HEADER]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - int len = 4; - if (getHeaderLength() != 0) - { - len+=3; // [Shawn] Fixed for two null bytes in the length - } - short bytelen = (short)(isMultibyte() ? - getHeaderLength()*2 : getHeaderLength() ); - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, - ( short ) ((len - 4) + bytelen)); - - if (getHeaderLength() > 0) - { - data[ 4 + offset ] = (byte)getHeaderLength(); - data[ 6 + offset ] = field_3_unicode_flag; - if(isMultibyte()) - { - StringUtil.putUnicodeLE(getHeader(), data, 7 + offset); - } - else - { - StringUtil.putCompressedUnicode(getHeader(), data, 7 + offset); // [Shawn] Place the string in the correct offset - } - } - return getRecordSize(); - } - - protected int getDataSize() { - int retval = 0; - - if (getHeaderLength() != 0) { - retval+=3; // [Shawn] Fixed for two null bytes in the length - } - return retval + getHeaderLength() * (isMultibyte() ? 2 : 1); - } - - public short getSid() - { + public short getSid() { return sid; } public Object clone() { - HeaderRecord rec = new HeaderRecord(); - rec.field_1_header_len = field_1_header_len; - rec.field_2_reserved = field_2_reserved; - rec.field_3_unicode_flag = field_3_unicode_flag; - rec.field_4_header = field_4_header; - return rec; + return new HeaderRecord(getText()); } } diff --git a/src/java/org/apache/poi/hssf/record/IndexRecord.java b/src/java/org/apache/poi/hssf/record/IndexRecord.java index 650d1258c..63727bb94 100644 --- a/src/java/org/apache/poi/hssf/record/IndexRecord.java +++ b/src/java/org/apache/poi/hssf/record/IndexRecord.java @@ -18,25 +18,23 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.IntList; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: Index Record

+ * Title: Index Record (0x020B)

* Description: Occurs right after BOF, tells you where the DBCELL records are for a sheet - * Important for locating cells

+ * Important for locating cells

* NOT USED IN THIS RELEASE - * REFERENCE: PG 323 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

+ * REFERENCE: PG 323 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) */ -public class IndexRecord extends Record { - public final static short sid = 0x020B; - public final static int DBCELL_CAPACITY = 30; - public int field_1_zero; // reserved must be 0 - public int field_2_first_row; // first row on the sheet - public int field_3_last_row_add1; // last row - public int field_4_zero; // reserved must be 0 - public IntList field_5_dbcells; // array of offsets to DBCELL records +public class IndexRecord extends StandardRecord { + public final static short sid = 0x020B; + private int field_2_first_row; // first row on the sheet + private int field_3_last_row_add1; // last row + private int field_4_zero; // supposed to be zero + private IntList field_5_dbcells; // array of offsets to DBCELL records public IndexRecord() { @@ -44,16 +42,17 @@ public class IndexRecord extends Record { public IndexRecord(RecordInputStream in) { - field_5_dbcells = - new IntList(DBCELL_CAPACITY); // initial capacity of 30 - field_1_zero = in.readInt(); + int field_1_zero = in.readInt(); + if (field_1_zero != 0) { + throw new RecordFormatException("Expected zero for field 1 but got " + field_1_zero); + } field_2_first_row = in.readInt(); field_3_last_row_add1 = in.readInt(); - field_4_zero = in.readInt(); - while(in.remaining() > 0) - { - - // System.out.println("getting " + k); + field_4_zero = in.readInt(); + + int nCells = in.remaining() / 4; + field_5_dbcells = new IntList(nCells); + for(int i=0; i + * Describes a linked data record. This record refers to the series data or text.

* * @author Glen Stampoultzis (glens at apache.org) */ -public final class LinkedDataRecord extends Record { +public final class LinkedDataRecord extends StandardRecord { public final static short sid = 0x1051; private static final BitField customNumberFormat= BitFieldFactory.getInstance(0x1); @@ -44,7 +46,7 @@ public final class LinkedDataRecord extends Record { public final static byte REFERENCE_TYPE_ERROR_REPORTED = 4; private short field_3_options; private short field_4_indexNumberFmtRecord; - private LinkedDataFormulaField field_5_formulaOfLink; + private Formula field_5_formulaOfLink; public LinkedDataRecord() @@ -58,8 +60,8 @@ public final class LinkedDataRecord extends Record { field_2_referenceType = in.readByte(); field_3_options = in.readShort(); field_4_indexNumberFmtRecord = in.readShort(); - field_5_formulaOfLink = new LinkedDataFormulaField(); - field_5_formulaOfLink.fillField(in); + int encodedTokenLen = in.readUShort(); + field_5_formulaOfLink = Formula.read(encodedTokenLen, in); } public String toString() @@ -92,28 +94,19 @@ public final class LinkedDataRecord extends Record { 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)); - - data[ 4 + offset + pos ] = field_1_linkType; - data[ 5 + offset + pos ] = field_2_referenceType; - LittleEndian.putShort(data, 6 + offset + pos, field_3_options); - LittleEndian.putShort(data, 8 + offset + pos, field_4_indexNumberFmtRecord); - pos += field_5_formulaOfLink.serializeField( pos + 10 + offset, data ); - - return getRecordSize(); + public void serialize(LittleEndianOutput out) { + out.writeByte(field_1_linkType); + out.writeByte(field_2_referenceType); + out.writeShort(field_3_options); + out.writeShort(field_4_indexNumberFmtRecord); + field_5_formulaOfLink.serialize(out); } protected int getDataSize() { - return 1 + 1 + 2 + 2 + field_5_formulaOfLink.getSize(); + return 1 + 1 + 2 + 2 + field_5_formulaOfLink.getEncodedSize(); } - public short getSid() - { + public short getSid() { return sid; } @@ -224,17 +217,16 @@ public final class LinkedDataRecord extends Record { /** * Get the formula of link field for the LinkedData record. */ - public LinkedDataFormulaField getFormulaOfLink() - { - return field_5_formulaOfLink; + public Ptg[] getFormulaOfLink() { + return field_5_formulaOfLink.getTokens(); } /** * Set the formula of link field for the LinkedData record. */ - public void setFormulaOfLink(LinkedDataFormulaField field_5_formulaOfLink) + public void setFormulaOfLink(Ptg[] ptgs) { - this.field_5_formulaOfLink = field_5_formulaOfLink; + this.field_5_formulaOfLink = Formula.create(ptgs); } /** diff --git a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java index 5ecce79aa..c8a1379dc 100644 --- a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java +++ b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java @@ -19,18 +19,15 @@ package org.apache.poi.hssf.record; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** * Title: Merged Cells Record (0x00E5) *
- * Description: Optional record defining a square area of cells to "merged" into - * one cell.
- * REFERENCE: NONE (UNDOCUMENTED PRESENTLY)
+ * Description: Optional record defining a square area of cells to "merged" into one cell.
* @author Andrew C. Oliver (acoliver at apache dot org) - * @version 2.0-pre */ -public final class MergeCellsRecord extends Record { +public final class MergeCellsRecord extends StandardRecord { public final static short sid = 0x00E5; /** sometimes the regions array is shared with other MergedCellsRecords */ private CellRangeAddress[] _regions; @@ -80,37 +77,26 @@ public final class MergeCellsRecord extends Record { return sid; } - public int serialize(int offset, byte [] data) { - int dataSize = CellRangeAddressList.getEncodedSize(_numberOfRegions); - - LittleEndian.putUShort(data, offset + 0, sid); - LittleEndian.putUShort(data, offset + 2, dataSize); + public void serialize(LittleEndianOutput out) { int nItems = _numberOfRegions; - LittleEndian.putUShort(data, offset + 4, nItems); - int pos = 6; + out.writeShort(nItems); for (int i = 0; i < _numberOfRegions; i++) { - pos += _regions[_startIndex + i].serialize(offset+pos, data); + _regions[_startIndex + i].serialize(out); } - return 4 + dataSize; } public String toString() { StringBuffer retval = new StringBuffer(); retval.append("[MERGEDCELLS]").append("\n"); - retval.append(" .numregions =").append(getNumAreas()) - .append("\n"); + retval.append(" .numregions =").append(getNumAreas()).append("\n"); for (int k = 0; k < _numberOfRegions; k++) { - CellRangeAddress region = _regions[_startIndex + k]; + CellRangeAddress r = _regions[_startIndex + k]; - retval.append(" .rowfrom =").append(region.getFirstRow()) - .append("\n"); - retval.append(" .rowto =").append(region.getLastRow()) - .append("\n"); - retval.append(" .colfrom =").append(region.getFirstColumn()) - .append("\n"); - retval.append(" .colto =").append(region.getLastColumn()) - .append("\n"); + retval.append(" .rowfrom =").append(r.getFirstRow()).append("\n"); + retval.append(" .rowto =").append(r.getLastRow()).append("\n"); + retval.append(" .colfrom =").append(r.getFirstColumn()).append("\n"); + retval.append(" .colto =").append(r.getLastColumn()).append("\n"); } retval.append("[MERGEDCELLS]").append("\n"); return retval.toString(); diff --git a/src/java/org/apache/poi/hssf/record/MulBlankRecord.java b/src/java/org/apache/poi/hssf/record/MulBlankRecord.java index 6ecaa20f9..009148ea3 100644 --- a/src/java/org/apache/poi/hssf/record/MulBlankRecord.java +++ b/src/java/org/apache/poi/hssf/record/MulBlankRecord.java @@ -17,6 +17,8 @@ package org.apache.poi.hssf.record; +import org.apache.poi.util.LittleEndianOutput; + /** * Title: Multiple Blank cell record(0x00BE)

* Description: Represents a set of columns in a row with no value but with styling. @@ -27,7 +29,7 @@ package org.apache.poi.hssf.record; * @author Glen Stampoultzis (glens at apache.org) * @see BlankRecord */ -public final class MulBlankRecord extends Record { +public final class MulBlankRecord extends StandardRecord { public final static short sid = 0x00BE; private int field_1_row; @@ -124,7 +126,7 @@ public final class MulBlankRecord extends Record { return sid; } - public int serialize(int offset, byte [] data) { + public void serialize(LittleEndianOutput out) { throw new RecordFormatException( "Sorry, you can't serialize MulBlank in this release"); } protected int getDataSize() { diff --git a/src/java/org/apache/poi/hssf/record/MulRKRecord.java b/src/java/org/apache/poi/hssf/record/MulRKRecord.java index dbb41c10f..3c1390d07 100644 --- a/src/java/org/apache/poi/hssf/record/MulRKRecord.java +++ b/src/java/org/apache/poi/hssf/record/MulRKRecord.java @@ -19,6 +19,7 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.util.RKUtil; import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndianOutput; /** * MULRK (0x00BD)

@@ -29,7 +30,7 @@ import org.apache.poi.util.HexDump; * @author Andrew C. Oliver (acoliver at apache dot org) * @version 2.0-pre */ -public final class MulRKRecord extends Record { +public final class MulRKRecord extends StandardRecord { public final static short sid = 0x00BD; private int field_1_row; @@ -113,7 +114,7 @@ public final class MulRKRecord extends Record { return sid; } - public int serialize(int offset, byte [] data) { + public void serialize(LittleEndianOutput out) { throw new RecordFormatException( "Sorry, you can't serialize MulRK in this release"); } protected int getDataSize() { diff --git a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java index a3717f40e..d0f6e2af0 100644 --- a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java +++ b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java @@ -23,7 +23,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** *

Record that contains the functionality page breaks (horizontal and vertical)

@@ -36,11 +36,11 @@ import org.apache.poi.util.LittleEndian; * @see VerticalPageBreakRecord * @author Danny Mui (dmui at apache dot org) */ -public abstract class PageBreakRecord extends Record { +public abstract class PageBreakRecord extends StandardRecord { private static final int[] EMPTY_INT_ARRAY = { }; - private List _breaks; - private Map _breakMap; + private List _breaks; + private Map _breakMap; /** * Since both records store 2byte integers (short), no point in @@ -49,7 +49,7 @@ public abstract class PageBreakRecord extends Record { * The subs (rows or columns, don't seem to be able to set but excel sets * them automatically) */ - public class Break { + public static final class Break { public static final int ENCODED_SIZE = 6; public int main; @@ -69,24 +69,23 @@ public abstract class PageBreakRecord extends Record { subTo = in.readUShort(); } - public int serialize(int offset, byte[] data) { - LittleEndian.putUShort(data, offset + 0, main + 1); - LittleEndian.putUShort(data, offset + 2, subFrom); - LittleEndian.putUShort(data, offset + 4, subTo); - return ENCODED_SIZE; + public void serialize(LittleEndianOutput out) { + out.writeShort(main + 1); + out.writeShort(subFrom); + out.writeShort(subTo); } } protected PageBreakRecord() { - _breaks = new ArrayList(); - _breakMap = new HashMap(); + _breaks = new ArrayList(); + _breakMap = new HashMap(); } public PageBreakRecord(RecordInputStream in) { int nBreaks = in.readShort(); - _breaks = new ArrayList(nBreaks + 2); - _breakMap = new HashMap(); + _breaks = new ArrayList(nBreaks + 2); + _breakMap = new HashMap(); for(int k = 0; k < nBreaks; k++) { Break br = new Break(in); @@ -103,34 +102,25 @@ public abstract class PageBreakRecord extends Record { return 2 + _breaks.size() * Break.ENCODED_SIZE; } - public final int serialize(int offset, byte data[]) { + public final void serialize(LittleEndianOutput out) { int nBreaks = _breaks.size(); - int dataSize = getDataSize(); - LittleEndian.putUShort(data, offset + 0, getSid()); - LittleEndian.putUShort(data, offset + 2, dataSize); - LittleEndian.putUShort(data, offset + 4, nBreaks); - int pos = 6; + out.writeShort(nBreaks); for (int i=0; i getBreaksIterator() { return _breaks.iterator(); } - public String toString() - { + public String toString() { StringBuffer retval = new StringBuffer(); - String label; String mainLabel; String subLabel; @@ -148,10 +138,10 @@ public abstract class PageBreakRecord extends Record { retval.append("["+label+"]").append("\n"); retval.append(" .sid =").append(getSid()).append("\n"); retval.append(" .numbreaks =").append(getNumBreaks()).append("\n"); - Iterator iterator = getBreaksIterator(); + Iterator iterator = getBreaksIterator(); for(int k = 0; k < getNumBreaks(); k++) { - Break region = (Break)iterator.next(); + Break region = iterator.next(); retval.append(" .").append(mainLabel).append(" (zero-based) =").append(region.main).append("\n"); retval.append(" .").append(subLabel).append("From =").append(region.subFrom).append("\n"); @@ -171,7 +161,7 @@ public abstract class PageBreakRecord extends Record { public void addBreak(int main, int subFrom, int subTo) { Integer key = new Integer(main); - Break region = (Break)_breakMap.get(key); + Break region = _breakMap.get(key); if(region == null) { region = new Break(main, subFrom, subTo); _breakMap.put(key, region); @@ -189,7 +179,7 @@ public abstract class PageBreakRecord extends Record { */ public final void removeBreak(int main) { Integer rowKey = new Integer(main); - Break region = (Break)_breakMap.get(rowKey); + Break region = _breakMap.get(rowKey); _breaks.remove(region); _breakMap.remove(rowKey); } @@ -201,7 +191,7 @@ public abstract class PageBreakRecord extends Record { */ public final Break getBreak(int main) { Integer rowKey = new Integer(main); - return (Break)_breakMap.get(rowKey); + return _breakMap.get(rowKey); } public final int[] getBreaks() { @@ -211,7 +201,7 @@ public abstract class PageBreakRecord extends Record { } int[] result = new int[count]; for (int i=0; i field_2_colors; public PaletteRecord() { - createDefaultPalette(); + PColor[] defaultPalette = createDefaultPalette(); + field_2_colors = new ArrayList(defaultPalette.length); + for (int i = 0; i < defaultPalette.length; i++) { + field_2_colors.add(defaultPalette[i]); + } } public PaletteRecord(RecordInputStream in) { - field_1_numcolors = in.readShort(); - field_2_colors = new ArrayList(field_1_numcolors); + int field_1_numcolors = in.readShort(); + field_2_colors = new ArrayList(field_1_numcolors); for (int k = 0; k < field_1_numcolors; k++) { - field_2_colors.add(new PColor( - in.readByte(), - in.readByte(), - in.readByte() - ) - ); - //Read unused byte. - in.readByte(); + field_2_colors.add(new PColor(in)); } } @@ -69,35 +60,27 @@ public class PaletteRecord StringBuffer buffer = new StringBuffer(); buffer.append("[PALETTE]\n"); - buffer.append(" numcolors = ").append(field_1_numcolors) - .append('\n'); - for (int k = 0; k < field_1_numcolors; k++) { - PColor c = (PColor) field_2_colors.get(k); - buffer.append("* colornum = ").append(k) - .append('\n'); - buffer.append(c.toString()); - buffer.append("/*colornum = ").append(k) - .append('\n'); + buffer.append(" numcolors = ").append(field_2_colors.size()).append('\n'); + for (int i = 0; i < field_2_colors.size(); i++) { + PColor c = field_2_colors.get(i); + buffer.append("* colornum = ").append(i).append('\n'); + buffer.append(c.toString()); + buffer.append("/*colornum = ").append(i).append('\n'); } buffer.append("[/PALETTE]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) + public void serialize(LittleEndianOutput out) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, (short) (getRecordSize() - 4)); - LittleEndian.putShort(data, 4 + offset, field_1_numcolors); - for (int k = 0; k < field_1_numcolors; k++) { - PColor c = (PColor)field_2_colors.get(k); - c.serialize(data, (6+offset+(k*4))); + out.writeShort(field_2_colors.size()); + for (int i = 0; i < field_2_colors.size(); i++) { + field_2_colors.get(i).serialize(out); } - - return getRecordSize(); } protected int getDataSize() { - return 2 + (field_1_numcolors * 4); + return 2 + field_2_colors.size() * PColor.ENCODED_SIZE; } public short getSid() @@ -108,17 +91,16 @@ public class PaletteRecord /** * Returns the color value at a given index * - * @return the RGB triplet for the color, or null if the specified index + * @return the RGB triplet for the color, or null if the specified index * does not exist */ - public byte[] getColor(short byteIndex) - { + public byte[] getColor(short byteIndex) { int i = byteIndex - FIRST_COLOR_INDEX; if (i < 0 || i >= field_2_colors.size()) { return null; } - PColor color = (PColor) field_2_colors.get(i); + PColor color = field_2_colors.get(i); return new byte[] { color.red, color.green, color.blue }; } @@ -138,9 +120,9 @@ public class PaletteRecord { return; } - while (field_2_colors.size() <= i) - { - field_2_colors.add(new PColor((byte) 0, (byte) 0, (byte) 0)); + // may need to grow - fill intervening pallette entries with black + while (field_2_colors.size() <= i) { + field_2_colors.add(new PColor(0, 0, 0)); } PColor custColor = new PColor(red, green, blue); field_2_colors.set(i, custColor); @@ -151,100 +133,99 @@ public class PaletteRecord * * @see org.apache.poi.hssf.model.Workbook#createPalette */ - private void createDefaultPalette() + private static PColor[] createDefaultPalette() { - field_1_numcolors = STANDARD_PALETTE_SIZE; - field_2_colors = new ArrayList(field_1_numcolors); - byte[] palette = new byte[] - { - (byte) 0, (byte) 0, (byte) 0, (byte) 0, //color 0... - (byte) 255, (byte) 255, (byte) 255, (byte) 0, - (byte) 255, (byte) 0, (byte) 0, (byte) 0, - (byte) 0, (byte) 255, (byte) 0, (byte) 0, - (byte) 0, (byte) 0, (byte) 255, (byte) 0, - (byte) 255, (byte) 255, (byte) 0, (byte) 0, - (byte) 255, (byte) 0, (byte) 255, (byte) 0, - (byte) 0, (byte) 255, (byte) 255, (byte) 0, - (byte) 128, (byte) 0, (byte) 0, (byte) 0, - (byte) 0, (byte) 128, (byte) 0, (byte) 0, - (byte) 0, (byte) 0, (byte) 128, (byte) 0, - (byte) 128, (byte) 128, (byte) 0, (byte) 0, - (byte) 128, (byte) 0, (byte) 128, (byte) 0, - (byte) 0, (byte) 128, (byte) 128, (byte) 0, - (byte) 192, (byte) 192, (byte) 192, (byte) 0, - (byte) 128, (byte) 128, (byte) 128, (byte) 0, - (byte) 153, (byte) 153, (byte) 255, (byte) 0, - (byte) 153, (byte) 51, (byte) 102, (byte) 0, - (byte) 255, (byte) 255, (byte) 204, (byte) 0, - (byte) 204, (byte) 255, (byte) 255, (byte) 0, - (byte) 102, (byte) 0, (byte) 102, (byte) 0, - (byte) 255, (byte) 128, (byte) 128, (byte) 0, - (byte) 0, (byte) 102, (byte) 204, (byte) 0, - (byte) 204, (byte) 204, (byte) 255, (byte) 0, - (byte) 0, (byte) 0, (byte) 128, (byte) 0, - (byte) 255, (byte) 0, (byte) 255, (byte) 0, - (byte) 255, (byte) 255, (byte) 0, (byte) 0, - (byte) 0, (byte) 255, (byte) 255, (byte) 0, - (byte) 128, (byte) 0, (byte) 128, (byte) 0, - (byte) 128, (byte) 0, (byte) 0, (byte) 0, - (byte) 0, (byte) 128, (byte) 128, (byte) 0, - (byte) 0, (byte) 0, (byte) 255, (byte) 0, - (byte) 0, (byte) 204, (byte) 255, (byte) 0, - (byte) 204, (byte) 255, (byte) 255, (byte) 0, - (byte) 204, (byte) 255, (byte) 204, (byte) 0, - (byte) 255, (byte) 255, (byte) 153, (byte) 0, - (byte) 153, (byte) 204, (byte) 255, (byte) 0, - (byte) 255, (byte) 153, (byte) 204, (byte) 0, - (byte) 204, (byte) 153, (byte) 255, (byte) 0, - (byte) 255, (byte) 204, (byte) 153, (byte) 0, - (byte) 51, (byte) 102, (byte) 255, (byte) 0, - (byte) 51, (byte) 204, (byte) 204, (byte) 0, - (byte) 153, (byte) 204, (byte) 0, (byte) 0, - (byte) 255, (byte) 204, (byte) 0, (byte) 0, - (byte) 255, (byte) 153, (byte) 0, (byte) 0, - (byte) 255, (byte) 102, (byte) 0, (byte) 0, - (byte) 102, (byte) 102, (byte) 153, (byte) 0, - (byte) 150, (byte) 150, (byte) 150, (byte) 0, - (byte) 0, (byte) 51, (byte) 102, (byte) 0, - (byte) 51, (byte) 153, (byte) 102, (byte) 0, - (byte) 0, (byte) 51, (byte) 0, (byte) 0, - (byte) 51, (byte) 51, (byte) 0, (byte) 0, - (byte) 153, (byte) 51, (byte) 0, (byte) 0, - (byte) 153, (byte) 51, (byte) 102, (byte) 0, - (byte) 51, (byte) 51, (byte) 153, (byte) 0, - (byte) 51, (byte) 51, (byte) 51, (byte) 0 + return new PColor[] { + pc(0, 0, 0), + pc(255, 255, 255), + pc(255, 0, 0), + pc(0, 255, 0), + pc(0, 0, 255), + pc(255, 255, 0), + pc(255, 0, 255), + pc(0, 255, 255), + pc(128, 0, 0), + pc(0, 128, 0), + pc(0, 0, 128), + pc(128, 128, 0), + pc(128, 0, 128), + pc(0, 128, 128), + pc(192, 192, 192), + pc(128, 128, 128), + pc(153, 153, 255), + pc(153, 51, 102), + pc(255, 255, 204), + pc(204, 255, 255), + pc(102, 0, 102), + pc(255, 128, 128), + pc(0, 102, 204), + pc(204, 204, 255), + pc(0, 0, 128), + pc(255, 0, 255), + pc(255, 255, 0), + pc(0, 255, 255), + pc(128, 0, 128), + pc(128, 0, 0), + pc(0, 128, 128), + pc(0, 0, 255), + pc(0, 204, 255), + pc(204, 255, 255), + pc(204, 255, 204), + pc(255, 255, 153), + pc(153, 204, 255), + pc(255, 153, 204), + pc(204, 153, 255), + pc(255, 204, 153), + pc(51, 102, 255), + pc(51, 204, 204), + pc(153, 204, 0), + pc(255, 204, 0), + pc(255, 153, 0), + pc(255, 102, 0), + pc(102, 102, 153), + pc(150, 150, 150), + pc(0, 51, 102), + pc(51, 153, 102), + pc(0, 51, 0), + pc(51, 51, 0), + pc(153, 51, 0), + pc(153, 51, 102), + pc(51, 51, 153), + pc(51, 51, 51), }; - - for (int k = 0; k < field_1_numcolors; k++) { - field_2_colors.add(new PColor( - palette[k*4], - palette[k*4+1], - palette[k*4+2] - ) - ); - } - } -} + + private static PColor pc(int r, int g, int b) { + return new PColor(r, g, b); + } /** * PColor - element in the list of colors - consider it a "struct" */ -class PColor { +private static final class PColor { + public static final short ENCODED_SIZE = 4; public byte red; public byte green; public byte blue; - public PColor(byte red, byte green, byte blue) { - this.red=red; - this.green=green; - this.blue=blue; + + public PColor(int red, int green, int blue) { + this.red=(byte) red; + this.green=(byte) green; + this.blue=(byte) blue; } - public void serialize(byte[] data, int offset) { - data[offset + 0] = red; - data[offset + 1] = green; - data[offset + 2] = blue; - data[offset + 3] = 0; + public PColor(RecordInputStream in) { + red=in.readByte(); + green=in.readByte(); + blue=in.readByte(); + in.readByte(); // unused + } + + public void serialize(LittleEndianOutput out) { + out.writeByte(red); + out.writeByte(green); + out.writeByte(blue); + out.writeByte(0); } public String toString() { @@ -255,3 +236,4 @@ class PColor { return buffer.toString(); } } +} \ No newline at end of file diff --git a/src/java/org/apache/poi/hssf/record/RKRecord.java b/src/java/org/apache/poi/hssf/record/RKRecord.java index 48a8c564f..966aaf219 100644 --- a/src/java/org/apache/poi/hssf/record/RKRecord.java +++ b/src/java/org/apache/poi/hssf/record/RKRecord.java @@ -19,15 +19,16 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.util.RKUtil; import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: RK Record (0x027E) + * Title: RK Record (0x027E)

* Description: An internal 32 bit number with the two most significant bits * storing the type. This is part of a bizarre scheme to save disk * space and memory (gee look at all the other whole records that * are in the file just "cause"..,far better to waste processor - * cycles on this then leave on of those "valuable" records out).

- * We support this in READ-ONLY mode. HSSF converts these to NUMBER records

+ * cycles on this then leave on of those "valuable" records out).

+ * We support this in READ-ONLY mode. HSSF converts these to NUMBER records

* * * @@ -36,7 +37,7 @@ import org.apache.poi.util.HexDump; * @author Jason Height (jheight at chariot dot net dot au) * @see org.apache.poi.hssf.record.NumberRecord */ -public final class RKRecord extends Record implements CellValueRecordInterface { +public final class RKRecord extends StandardRecord implements CellValueRecordInterface { public final static short sid = 0x027E; public final static short RK_IEEE_NUMBER = 0; public final static short RK_IEEE_NUMBER_TIMES_100 = 1; @@ -47,7 +48,7 @@ public final class RKRecord extends Record implements CellValueRecordInterface { private int field_3_xf_index; private int field_4_rk_number; - public RKRecord() + private RKRecord() { } @@ -133,7 +134,7 @@ public final class RKRecord extends Record implements CellValueRecordInterface { return sb.toString(); } - public int serialize(int offset, byte [] data) { + public void serialize(LittleEndianOutput out) { throw new RecordFormatException( "Sorry, you can't serialize RK in this release"); } protected int getDataSize() { diff --git a/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java b/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java index d66e31089..00efceb6a 100644 --- a/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java +++ b/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java @@ -17,10 +17,11 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: Recalc Id Record

+ * Title: Recalc Id Record (0x01C1)

* Description: This record contains an ID that marks when a worksheet was last * recalculated. It's an optimization Excel uses to determine if it * needs to recalculate the spreadsheet when it's opened. So far, only @@ -28,100 +29,51 @@ import org.apache.poi.util.LittleEndian; * (do not recalculate) and 0xC1 0x01 0x00 0x00 0x60 0x69 0x01 * 0x00 have been seen. If the field isNeeded is * set to false (default), then this record is swallowed during the - * serialization process

- * REFERENCE: http://chicago.sourceforge.net/devel/docs/excel/biff8.html

+ * serialization process

+ * REFERENCE: http://chicago.sourceforge.net/devel/docs/excel/biff8.html

* @author Luc Girardin (luc dot girardin at macrofocus dot com) - * @version 2.0-pre + * * @see org.apache.poi.hssf.model.Workbook */ +public final class RecalcIdRecord extends StandardRecord { + public final static short sid = 0x01C1; + private final int _reserved0; + private final int _engineId; -public final class RecalcIdRecord extends Record { - public final static short sid = 0x1c1; - public short[] field_1_recalcids; - - private boolean isNeeded = true; - - public RecalcIdRecord() - { - } - - public RecalcIdRecord(RecordInputStream in) - { - field_1_recalcids = new short[ in.remaining() / 2 ]; - for (int k = 0; k < field_1_recalcids.length; k++) - { - field_1_recalcids[ k ] = in.readShort(); - } - } - - /** - * set the recalc array. - * @param array of recalc id's - */ - - public void setRecalcIdArray(short [] array) - { - field_1_recalcids = array; - } - - /** - * get the recalc array. - * @return array of recalc id's - */ - - public short [] getRecalcIdArray() - { - return field_1_recalcids; - } - - public void setIsNeeded(boolean isNeeded) { - this.isNeeded = isNeeded; + public RecalcIdRecord(RecordInputStream in) { + int rt = in.readUShort(); + if (rt != sid) { + throw new RecordFormatException("expected " + sid + " but got " + rt); + } + _reserved0 = in.readUShort(); + _engineId = in.readInt(); } public boolean isNeeded() { - return isNeeded; + return true; } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[RECALCID]\n"); - buffer.append(" .elements = ").append(field_1_recalcids.length) - .append("\n"); - for (int k = 0; k < field_1_recalcids.length; k++) - { - buffer.append(" .element_" + k + " = ") - .append(field_1_recalcids[ k ]).append("\n"); - } + buffer.append(" .reserved = ").append(HexDump.shortToHex(_reserved0)); + buffer.append(" .engineId = ").append(HexDump.intToHex(_engineId)); buffer.append("[/RECALCID]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - short[] tabids = getRecalcIdArray(); - short length = ( short ) (tabids.length * 2); - int byteoffset = 4; - - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, length); - - // 2 (num bytes in a short) - for (int k = 0; k < (length / 2); k++) - { - LittleEndian.putShort(data, byteoffset + offset, tabids[ k ]); - byteoffset += 2; - } - return getRecordSize(); + public void serialize(LittleEndianOutput out) { + out.writeShort(sid); + out.writeShort(_reserved0); + out.writeInt(_engineId); } protected int getDataSize() { - return (getRecalcIdArray().length * 2); + return 8; } - public short getSid() - { + public short getSid() { return sid; } } diff --git a/src/java/org/apache/poi/hssf/record/SelectionRecord.java b/src/java/org/apache/poi/hssf/record/SelectionRecord.java index 2898c8d14..2a7499268 100644 --- a/src/java/org/apache/poi/hssf/record/SelectionRecord.java +++ b/src/java/org/apache/poi/hssf/record/SelectionRecord.java @@ -18,7 +18,9 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.util.CellRangeAddress8Bit; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** * Title: Selection Record (0x001D)

@@ -30,7 +32,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @author Glen Stampoultzis (glens at apache.org) */ -public final class SelectionRecord extends Record { +public final class SelectionRecord extends StandardRecord { public final static short sid = 0x001D; private byte field_1_pane; private int field_2_row_active_cell; @@ -123,45 +125,35 @@ public final class SelectionRecord extends Record { * @return ref number of active cell */ public int getActiveCellRef() { - return (short)field_4_active_cell_ref_index; + return field_4_active_cell_ref_index; } public String toString() { - StringBuffer buffer = new StringBuffer(); + StringBuffer sb = new StringBuffer(); - buffer.append("[SELECTION]\n"); - buffer.append(" .pane = ") - .append(Integer.toHexString(getPane())).append("\n"); - buffer.append(" .activecellrow = ") - .append(Integer.toHexString(getActiveCellRow())).append("\n"); - buffer.append(" .activecellcol = ") - .append(Integer.toHexString(getActiveCellCol())).append("\n"); - buffer.append(" .activecellref = ") - .append(Integer.toHexString(getActiveCellRef())).append("\n"); - buffer.append(" .numrefs = ") - .append(Integer.toHexString(field_6_refs.length)).append("\n"); - buffer.append("[/SELECTION]\n"); - return buffer.toString(); + sb.append("[SELECTION]\n"); + sb.append(" .pane = ").append(HexDump.byteToHex(getPane())).append("\n"); + sb.append(" .activecellrow = ").append(HexDump.shortToHex(getActiveCellRow())).append("\n"); + sb.append(" .activecellcol = ").append(HexDump.shortToHex(getActiveCellCol())).append("\n"); + sb.append(" .activecellref = ").append(HexDump.shortToHex(getActiveCellRef())).append("\n"); + sb.append(" .numrefs = ").append(HexDump.shortToHex(field_6_refs.length)).append("\n"); + sb.append("[/SELECTION]\n"); + return sb.toString(); } protected int getDataSize() { return 9 // 1 byte + 4 shorts + CellRangeAddress8Bit.getEncodedSize(field_6_refs.length); } - public int serialize(int offset, byte [] data) { - int dataSize = getDataSize(); - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, dataSize); - LittleEndian.putByte(data, 4 + offset, getPane()); - LittleEndian.putUShort(data, 5 + offset, getActiveCellRow()); - LittleEndian.putUShort(data, 7 + offset, getActiveCellCol()); - LittleEndian.putUShort(data, 9 + offset, getActiveCellRef()); + public void serialize(LittleEndianOutput out) { + out.writeByte(getPane()); + out.writeShort(getActiveCellRow()); + out.writeShort(getActiveCellCol()); + out.writeShort(getActiveCellRef()); int nRefs = field_6_refs.length; - LittleEndian.putUShort(data, 11 + offset, nRefs); + out.writeShort(nRefs); for (int i = 0; i < field_6_refs.length; i++) { - CellRangeAddress8Bit r = field_6_refs[i]; - r.serialize(offset + 13 + i * CellRangeAddress8Bit.ENCODED_SIZE, data); + field_6_refs[i].serialize(out); } - return 4 + dataSize; } public short getSid() { diff --git a/src/java/org/apache/poi/hssf/record/SeriesListRecord.java b/src/java/org/apache/poi/hssf/record/SeriesListRecord.java index a6ebefd25..c8edda2aa 100644 --- a/src/java/org/apache/poi/hssf/record/SeriesListRecord.java +++ b/src/java/org/apache/poi/hssf/record/SeriesListRecord.java @@ -17,16 +17,19 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** + * SERIESLIST (0x1016) * * The series list record defines the series displayed as an overlay to the main chart record.
- * TODO - does this record (0x1016) really exist. It doesn't seem to be referenced in either the OOO or MS doc + * This record doesn't seem to be referenced in either the OOO or MS doc, but this page mentions it + * http://ooxmlisdefectivebydesign.blogspot.com/2008/03/bad-surprise-in-microsoft-office-binary.html + * * * @author Glen Stampoultzis (glens at apache.org) */ -public final class SeriesListRecord extends Record { +public final class SeriesListRecord extends StandardRecord { public final static short sid = 0x1016; private short[] field_1_seriesNumbers; @@ -55,23 +58,13 @@ public final class SeriesListRecord extends Record { return buffer.toString(); } - public int serialize(int offset, byte[] data) { + public void serialize(LittleEndianOutput out) { int nItems = field_1_seriesNumbers.length; - int dataSize = 2 + 2 * nItems; - - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, dataSize); - - LittleEndian.putUShort(data, 4 + offset, nItems); - - int pos = offset + 6; + out.writeShort(nItems); for (int i = 0; i < nItems; i++) { - LittleEndian.putUShort(data, pos, field_1_seriesNumbers[i]); - pos += 2; + out.writeShort(field_1_seriesNumbers[i]); } - - return 4 + dataSize; } protected int getDataSize() { @@ -84,7 +77,7 @@ public final class SeriesListRecord extends Record { } public Object clone() { - return new SeriesListRecord((short[]) field_1_seriesNumbers.clone()); + return new SeriesListRecord(field_1_seriesNumbers.clone()); } /** diff --git a/src/java/org/apache/poi/hssf/record/StyleRecord.java b/src/java/org/apache/poi/hssf/record/StyleRecord.java index 9994dfcf7..f9541d593 100644 --- a/src/java/org/apache/poi/hssf/record/StyleRecord.java +++ b/src/java/org/apache/poi/hssf/record/StyleRecord.java @@ -20,7 +20,7 @@ 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; +import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; /** @@ -30,11 +30,9 @@ import org.apache.poi.util.StringUtil; * @author Andrew C. Oliver (acoliver at apache dot org) * @author aviks : string fixes for UserDefined Style */ -public final class StyleRecord extends Record { +public final class StyleRecord extends StandardRecord { public final static short sid = 0x0293; - private static final BitField is16BitUnicodeFlag = BitFieldFactory.getInstance(0x01); - private static final BitField styleIndexMask = BitFieldFactory.getInstance(0x0FFF); private static final BitField isBuiltinFlag = BitFieldFactory.getInstance(0x8000); @@ -46,7 +44,7 @@ public final class StyleRecord extends Record { private int field_3_outline_style_level; // only for user defined styles - private int field_3_string_options; + private boolean field_3_stringHasMultibyte; private String field_4_name; /** @@ -74,8 +72,8 @@ public final class StyleRecord extends Record { field_4_name = ""; } else { - int is16BitUnicode = in.readByte(); - if (is16BitUnicodeFlag.isSet(is16BitUnicode)) { + field_3_stringHasMultibyte = in.readByte() != 0x00; + if (field_3_stringHasMultibyte) { field_4_name = StringUtil.readUnicodeLE(in, field_2_name_length); } else { field_4_name = StringUtil.readCompressedUnicode(in, field_2_name_length); @@ -107,7 +105,7 @@ public final class StyleRecord extends Record { */ public void setName(String name) { field_4_name = name; - field_3_string_options = StringUtil.hasMultibyte(name) ? 0x01 : 0x00; + field_3_stringHasMultibyte = StringUtil.hasMultibyte(name); field_1_xf_index = isBuiltinFlag.clear(field_1_xf_index); } @@ -162,34 +160,24 @@ public final class StyleRecord extends Record { if (isBuiltin()) { return 4; // short, byte, byte } - int size = 2 + 3; // short - if (is16BitUnicodeFlag.isSet(field_3_string_options)) { - size += 2 * field_4_name.length(); - } else { - size += field_4_name.length(); - } - return size; + return 2 // short xf index + + 3 // str len + flag + + field_4_name.length() * (field_3_stringHasMultibyte ? 2 : 1); } - public int serialize(int offset, byte [] data) { - int dataSize = getDataSize(); - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, dataSize); - - LittleEndian.putUShort(data, 4 + offset, field_1_xf_index); + public void serialize(LittleEndianOutput out) { + out.writeShort(field_1_xf_index); if (isBuiltin()) { - LittleEndian.putByte(data, 6 + offset, field_2_builtin_style); - LittleEndian.putByte(data, 7 + offset, field_3_outline_style_level); + out.writeByte(field_2_builtin_style); + out.writeByte(field_3_outline_style_level); } else { - LittleEndian.putUShort(data, 6 + offset, field_4_name.length()); - LittleEndian.putByte(data, 8 + offset, field_3_string_options); - StringUtil.putCompressedUnicode(getName(), data, 9 + offset); + out.writeShort(field_4_name.length()); + out.writeByte(field_3_stringHasMultibyte ? 0x01 : 0x00); + StringUtil.putCompressedUnicode(getName(), out); } - return 4+dataSize; } - public short getSid() - { + public short getSid() { return sid; } } diff --git a/src/java/org/apache/poi/hssf/record/TabIdRecord.java b/src/java/org/apache/poi/hssf/record/TabIdRecord.java index 9478d008b..7c6803d4e 100644 --- a/src/java/org/apache/poi/hssf/record/TabIdRecord.java +++ b/src/java/org/apache/poi/hssf/record/TabIdRecord.java @@ -17,30 +17,31 @@ package org.apache.poi.hssf.record; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: Sheet Tab Index Array Record

+ * Title: Sheet Tab Index Array Record (0x013D)

* Description: Contains an array of sheet id's. Sheets always keep their ID - * regardless of what their name is.

- * REFERENCE: PG 412 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

+ * regardless of what their name is.

+ * REFERENCE: PG 412 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) - * @version 2.0-pre + * */ -public final class TabIdRecord extends Record { +public final class TabIdRecord extends StandardRecord { public final static short sid = 0x13d; - public short[] field_1_tabids; + private static final short[] EMPTY_SHORT_ARRAY = { }; + + public short[] _tabids; - public TabIdRecord() - { + public TabIdRecord() { + _tabids = EMPTY_SHORT_ARRAY; } - public TabIdRecord(RecordInputStream in) - { - field_1_tabids = new short[ in.remaining() / 2 ]; - for (int k = 0; k < field_1_tabids.length; k++) - { - field_1_tabids[ k ] = in.readShort(); + public TabIdRecord(RecordInputStream in) { + int nTabs = in.remaining() / 2; + _tabids = new short[nTabs]; + for (int k = 0; k < _tabids.length; k++) { + _tabids[ k ] = in.readShort(); } } @@ -48,62 +49,36 @@ public final class TabIdRecord extends Record { * set the tab array. (0,1,2). * @param array of tab id's {0,1,2} */ - - public void setTabIdArray(short [] array) - { - field_1_tabids = array; + public void setTabIdArray(short[] array) { + _tabids = array; } - /** - * get the tab array. (0,1,2). - * @return array of tab id's {0,1,2} - */ - - public short [] getTabIdArray() - { - return field_1_tabids; - } - - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[TABID]\n"); - buffer.append(" .elements = ").append(field_1_tabids.length) - .append("\n"); - for (int k = 0; k < field_1_tabids.length; k++) + buffer.append(" .elements = ").append(_tabids.length).append("\n"); + for (int k = 0; k < _tabids.length; k++) { - buffer.append(" .element_" + k + " = ") - .append(field_1_tabids[ k ]).append("\n"); + buffer.append(" .element_").append(k).append(" = ").append(_tabids[ k ]).append("\n"); } buffer.append("[/TABID]\n"); return buffer.toString(); } - public int serialize(int offset, byte [] data) - { - short[] tabids = getTabIdArray(); - int length = tabids.length * 2; - int byteoffset = 4; + public void serialize(LittleEndianOutput out) { + short[] tabids = _tabids; - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, length); // nubmer tabids * - - // 2 (num bytes in a short) - for (int k = 0; k < (length / 2); k++) - { - LittleEndian.putShort(data, byteoffset + offset, tabids[ k ]); - byteoffset += 2; + for (int k = 0; k < tabids.length; k++) { + out.writeShort(tabids[ k ]); } - return getRecordSize(); } protected int getDataSize() { - return (getTabIdArray().length * 2); + return _tabids.length * 2; } - public short getSid() - { + public short getSid() { return sid; } } diff --git a/src/java/org/apache/poi/hssf/record/UnknownRecord.java b/src/java/org/apache/poi/hssf/record/UnknownRecord.java index 6bbb09663..997c35642 100644 --- a/src/java/org/apache/poi/hssf/record/UnknownRecord.java +++ b/src/java/org/apache/poi/hssf/record/UnknownRecord.java @@ -18,19 +18,19 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.HexDump; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; /** - * Title: Unknown Record (for debugging)

+ * Title: Unknown Record (for debugging)

* Description: Unknown record just tells you the sid so you can figure out * what records you are missing. Also helps us read/modify sheets we - * don't know all the records to. (HSSF leaves these alone!)

+ * don't know all the records to. (HSSF leaves these alone!)

* Company: SuperLink Software, Inc.

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) * @author Glen Stampoultzis (glens at apache.org) */ -public final class UnknownRecord extends Record { +public final class UnknownRecord extends StandardRecord { /* * Some Record IDs used by POI as 'milestones' in the record stream @@ -79,12 +79,8 @@ public final class UnknownRecord extends Record { /** * spit the record out AS IS. no interpretation or identification */ - public final int serialize(int offset, byte[] data) { - LittleEndian.putUShort(data, 0 + offset, _sid); - int dataSize = _rawData.length; - LittleEndian.putUShort(data, 2 + offset, dataSize); - System.arraycopy(_rawData, 0, data, 4 + offset, dataSize); - return 4 + dataSize; + public void serialize(LittleEndianOutput out) { + out.write(_rawData); } protected int getDataSize() { @@ -94,7 +90,7 @@ public final class UnknownRecord extends Record { /** * print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD]) */ - public final String toString() { + public String toString() { String biffName = getBiffName(_sid); if (biffName == null) { biffName = "UNKNOWNRECORD"; @@ -110,7 +106,7 @@ public final class UnknownRecord extends Record { return sb.toString(); } - public final short getSid() { + public short getSid() { return (short) _sid; } @@ -267,8 +263,8 @@ public final class UnknownRecord extends Record { return false; } - public final Object clone() { - // immutable - ok to return this + public Object clone() { + // immutable - OK to return this return this; } } diff --git a/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java b/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java index 5870a9ace..3ff094e7f 100644 --- a/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java +++ b/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java @@ -19,7 +19,7 @@ package org.apache.poi.hssf.record; import java.util.Arrays; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; /** @@ -33,9 +33,10 @@ import org.apache.poi.util.StringUtil; * * @author Andrew C. Oliver (acoliver at apache dot org) */ -public final class WriteAccessRecord extends Record { - private static final byte PAD_CHAR = (byte) ' '; +public final class WriteAccessRecord extends StandardRecord { public final static short sid = 0x005C; + + private static final byte PAD_CHAR = (byte) ' '; private static final int DATA_SIZE = 112; private String field_1_username; /** this record is always padded to a constant length */ @@ -113,24 +114,18 @@ public final class WriteAccessRecord extends Record { return buffer.toString(); } - public int serialize(int offset, byte[] data) { + public void serialize(LittleEndianOutput out) { String username = getUsername(); boolean is16bit = StringUtil.hasMultibyte(username); - LittleEndian.putUShort(data, 0 + offset, sid); - LittleEndian.putUShort(data, 2 + offset, DATA_SIZE); - LittleEndian.putUShort(data, 4 + offset, username.length()); - LittleEndian.putByte(data, 6 + offset, is16bit ? 0x01 : 0x00); - int pos = offset + 7; + out.writeShort(username.length()); + out.writeByte(is16bit ? 0x01 : 0x00); if (is16bit) { - StringUtil.putUnicodeLE(username, data, pos); - pos += username.length() * 2; + StringUtil.putUnicodeLE(username, out); } else { - StringUtil.putCompressedUnicode(username, data, pos); - pos += username.length(); + StringUtil.putCompressedUnicode(username, out); } - System.arraycopy(padding, 0, data, pos, padding.length); - return 4 + DATA_SIZE; + out.write(padding); } protected int getDataSize() { diff --git a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java index c4d156597..68d4559a3 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java @@ -51,8 +51,8 @@ public final class PageSettingsBlock extends RecordAggregate { // (The whole PageSettingsBlock may not be present) private PageBreakRecord _rowBreaksRecord; private PageBreakRecord _columnBreaksRecord; - private HeaderRecord header; - private FooterRecord footer; + private HeaderRecord _header; + private FooterRecord _footer; private HCenterRecord _hCenter; private VCenterRecord _vCenter; private LeftMarginRecord _leftMargin; @@ -77,8 +77,8 @@ public final class PageSettingsBlock extends RecordAggregate { public PageSettingsBlock() { _rowBreaksRecord = new HorizontalPageBreakRecord(); _columnBreaksRecord = new VerticalPageBreakRecord(); - header = createHeader(); - footer = createFooter(); + _header = new HeaderRecord(""); + _footer = new FooterRecord(""); _hCenter = createHCenter(); _vCenter = createVCenter(); printSetup = createPrintSetup(); @@ -117,10 +117,10 @@ public final class PageSettingsBlock extends RecordAggregate { _columnBreaksRecord = (PageBreakRecord) rs.getNext(); break; case HeaderRecord.sid: - header = (HeaderRecord) rs.getNext(); + _header = (HeaderRecord) rs.getNext(); break; case FooterRecord.sid: - footer = (FooterRecord) rs.getNext(); + _footer = (FooterRecord) rs.getNext(); break; case HCenterRecord.sid: _hCenter = (HCenterRecord) rs.getNext(); @@ -193,8 +193,8 @@ public final class PageSettingsBlock extends RecordAggregate { public void visitContainedRecords(RecordVisitor rv) { visitIfPresent(_rowBreaksRecord, rv); visitIfPresent(_columnBreaksRecord, rv); - visitIfPresent(header, rv); - visitIfPresent(footer, rv); + visitIfPresent(_header, rv); + visitIfPresent(_footer, rv); visitIfPresent(_hCenter, rv); visitIfPresent(_vCenter, rv); visitIfPresent(_leftMargin, rv); @@ -220,28 +220,6 @@ public final class PageSettingsBlock extends RecordAggregate { } } - /** - * creates the Header Record and sets it to nothing/0 length - */ - private static HeaderRecord createHeader() { - HeaderRecord retval = new HeaderRecord(); - - retval.setHeaderLength(( byte ) 0); - retval.setHeader(null); - return retval; - } - - /** - * creates the Footer Record and sets it to nothing/0 length - */ - private static FooterRecord createFooter() { - FooterRecord retval = new FooterRecord(); - - retval.setFooterLength(( byte ) 0); - retval.setFooter(null); - return retval; - } - /** * creates the HCenter Record and sets it to false (don't horizontally center) */ @@ -292,7 +270,7 @@ public final class PageSettingsBlock extends RecordAggregate { */ public HeaderRecord getHeader () { - return header; + return _header; } /** @@ -301,7 +279,7 @@ public final class PageSettingsBlock extends RecordAggregate { */ public void setHeader (HeaderRecord newHeader) { - header = newHeader; + _header = newHeader; } /** @@ -310,7 +288,7 @@ public final class PageSettingsBlock extends RecordAggregate { */ public FooterRecord getFooter () { - return footer; + return _footer; } /** @@ -319,7 +297,7 @@ public final class PageSettingsBlock extends RecordAggregate { */ public void setFooter (FooterRecord newFooter) { - footer = newFooter; + _footer = newFooter; } /** @@ -419,11 +397,11 @@ public final class PageSettingsBlock extends RecordAggregate { */ private static void shiftBreaks(PageBreakRecord breaks, int start, int stop, int count) { - Iterator iterator = breaks.getBreaksIterator(); - List shiftedBreak = new ArrayList(); + Iterator iterator = breaks.getBreaksIterator(); + List shiftedBreak = new ArrayList(); while(iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); + PageBreakRecord.Break breakItem = iterator.next(); int breakLocation = breakItem.main; boolean inStart = (breakLocation >= start); boolean inEnd = (breakLocation <= stop); @@ -433,7 +411,7 @@ public final class PageSettingsBlock extends RecordAggregate { iterator = shiftedBreak.iterator(); while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); + PageBreakRecord.Break breakItem = iterator.next(); breaks.removeBreak(breakItem.main); breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo); } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java index 0d57edbc4..075e3ae5d 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java @@ -250,7 +250,7 @@ public final class RowRecordsAggregate extends RecordAggregate { // Serialize a block of cells for those rows final int startRowNumber = getStartRowNumberForBlock(blockIndex); final int endRowNumber = getEndRowNumberForBlock(blockIndex); - DBCellRecord cellRecord = new DBCellRecord(); + DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder(); // Note: Cell references start from the second row... int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE); for (int row = startRowNumber; row <= endRowNumber; row++) { @@ -261,13 +261,12 @@ public final class RowRecordsAggregate extends RecordAggregate { pos += rowCellSize; // Add the offset to the first cell for the row into the // DBCellRecord. - cellRecord.addCellOffset((short) cellRefOffset); + dbcrBuilder.addCellOffset(cellRefOffset); cellRefOffset = rowCellSize; } } // Calculate Offset from the start of a DBCellRecord to the first Row - cellRecord.setRowOffset(pos); - rv.visitRecord(cellRecord); + rv.visitRecord(dbcrBuilder.build(pos)); } for (int i=0; i< _unknownRecords.size(); i++) { // Potentially breaking the file here since we don't know exactly where to write these records diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java index a2dbd4d91..d32151207 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java @@ -1015,9 +1015,7 @@ public class HSSFCellStyle implements CellStyle if(workbook != source.workbook) { // Then we need to clone the format string, // and update the format record for this - short fmt = workbook.createFormat( - source.getDataFormatString() - ); + short fmt = (short)workbook.createFormat(source.getDataFormatString() ); setDataFormat(fmt); // Finally we need to clone the font, diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java index 2141c74f0..310abecef 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java @@ -15,12 +15,6 @@ limitations under the License. ==================================================================== */ - -/* - * HSSFFont.java - * - * Created on December 9, 2001, 10:34 AM - */ package org.apache.poi.hssf.usermodel; import org.apache.poi.hssf.record.FontRecord; @@ -29,16 +23,13 @@ import org.apache.poi.ss.usermodel.Font; /** * Represents a Font used in a workbook. * - * @version 1.0-pre + * * @author Andrew C. Oliver * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createFont() * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getFontAt(short) * @see org.apache.poi.hssf.usermodel.HSSFCellStyle#setFont(HSSFFont) */ - -public class HSSFFont implements Font -{ - +public final class HSSFFont implements Font { private FontRecord font; private short index; @@ -60,7 +51,6 @@ public class HSSFFont implements Font public void setFontName(String name) { font.setFontName(name); - font.setFontNameLength(( byte ) name.length()); } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java index 422af62c7..4f10ba8c9 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java @@ -86,7 +86,6 @@ public class HSSFFooter extends HeaderFooter implements Footer { "&C" + (center == null ? "" : center) + "&L" + (left == null ? "" : left) + "&R" + (right == null ? "" : right)); - footerRecord.setFooterLength((byte)footerRecord.getFooter().length()); } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java b/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java index c5247525a..36dfc969b 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java @@ -92,7 +92,6 @@ public class HSSFHeader extends HeaderFooter implements Header { headerRecord.setHeader( "&C" + ( center == null ? "" : center ) + "&L" + ( left == null ? "" : left ) + "&R" + ( right == null ? "" : right ) ); - headerRecord.setHeaderLength( (byte) headerRecord.getHeader().length() ); } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java index 3b1fd1e1e..c0a1daaeb 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java +++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java @@ -47,12 +47,12 @@ import org.apache.poi.hssf.record.HCenterRecord; import org.apache.poi.hssf.record.HeaderRecord; import org.apache.poi.hssf.record.LegendRecord; import org.apache.poi.hssf.record.LineFormatRecord; -import org.apache.poi.hssf.record.LinkedDataFormulaField; import org.apache.poi.hssf.record.LinkedDataRecord; import org.apache.poi.hssf.record.PlotAreaRecord; import org.apache.poi.hssf.record.PlotGrowthRecord; import org.apache.poi.hssf.record.PrintSetupRecord; import org.apache.poi.hssf.record.ProtectRecord; +import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RecordBase; import org.apache.poi.hssf.record.SCLRecord; import org.apache.poi.hssf.record.SeriesIndexRecord; @@ -96,12 +96,12 @@ public final class HSSFChart { public void createBarChart( HSSFWorkbook workbook, HSSFSheet sheet ) { - List records = new ArrayList(); + List records = new ArrayList(); records.add( createMSDrawingObjectRecord() ); records.add( createOBJRecord() ); records.add( createBOFRecord() ); - records.add( createHeaderRecord() ); - records.add( createFooterRecord() ); + records.add(new HeaderRecord("")); + records.add(new FooterRecord("")); records.add( createHCenterRecord() ); records.add( createVCenterRecord() ); records.add( createPrintSetupRecord() ); @@ -340,20 +340,6 @@ public final class HSSFChart { return r; } - private FooterRecord createFooterRecord() - { - FooterRecord r = new FooterRecord(); - r.setFooter(null); - return r; - } - - private HeaderRecord createHeaderRecord() - { - HeaderRecord r = new HeaderRecord(); - r.setHeader(null); - return r; - } - private BOFRecord createBOFRecord() { BOFRecord r = new BOFRecord(); @@ -447,7 +433,7 @@ public final class HSSFChart { r.setReferenceType(LinkedDataRecord.REFERENCE_TYPE_DIRECT); r.setCustomNumberFormat(false); r.setIndexNumberFmtRecord((short)0); - r.setFormulaOfLink( new LinkedDataFormulaField() ); + r.setFormulaOfLink(null); return r; } @@ -647,7 +633,7 @@ public final class HSSFChart { r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_DIRECT ); r.setCustomNumberFormat( false ); r.setIndexNumberFmtRecord( (short) 0 ); - r.setFormulaOfLink( new LinkedDataFormulaField() ); + r.setFormulaOfLink(null); return r; } @@ -758,11 +744,9 @@ public final class HSSFChart { r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET ); r.setCustomNumberFormat( false ); r.setIndexNumberFmtRecord( (short) 0 ); - LinkedDataFormulaField formula = new LinkedDataFormulaField(); Area3DPtg p = new Area3DPtg(0, 31, 1, 1, false, false, false, false, 0); - formula.setFormulaTokens(new Ptg[] { p, }); - r.setFormulaOfLink( formula ); + r.setFormulaOfLink(new Ptg[] { p, }); return r; } @@ -773,11 +757,9 @@ public final class HSSFChart { r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET ); r.setCustomNumberFormat( false ); r.setIndexNumberFmtRecord( (short) 0 ); - LinkedDataFormulaField formula = new LinkedDataFormulaField(); Area3DPtg p = new Area3DPtg(0, 31, 0, 0, false, false, false, false, 0); - formula.setFormulaTokens(new Ptg[] { p, }); - r.setFormulaOfLink( formula ); + r.setFormulaOfLink(new Ptg[] { p, }); return r; } @@ -788,7 +770,7 @@ public final class HSSFChart { r.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_DIRECT ); r.setCustomNumberFormat( false ); r.setIndexNumberFmtRecord( (short) 0 ); - r.setFormulaOfLink( new LinkedDataFormulaField() ); + r.setFormulaOfLink(null); return r; } diff --git a/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java index 5a8855b66..3d5e053da 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java @@ -14,58 +14,52 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; import junit.framework.TestCase; /** - * Tests the serialization and deserialization of the FontRecord - * class works correctly. Test data taken directly from a real - * Excel file. + * Tests the serialization and deserialization of the {@link FontRecord} + * class works correctly. Test data taken directly from a real Excel file. */ public final class TestFontRecord extends TestCase { - byte[] header = new byte[] { - 0x31, 00, 0x1a, 00, // sid=31, 26 bytes long - }; - byte[] data = new byte[] { - 0xC8-256, 00, // font height = xc8 - 00, 00, // attrs = 0 - 0xFF-256, 0x7F, // colour palette = x7fff - 0x90-256, 0x01, // bold weight = x190 - 00, 00, // supersubscript - 00, 00, // underline, family - 00, 00, // charset, padding - 05, 01, // name length, unicode flag - 0x41, 0x00, 0x72, 0x00, 0x69, // Arial, as unicode - 0x00, 0x61, 0x00, 0x6C, 0x00 + + private static final byte[] data = { + 0xC8-256, 00, // font height = xc8 + 00, 00, // attrs = 0 + 0xFF-256, 0x7F, // colour palette = x7fff + 0x90-256, 0x01, // bold weight = x190 + 00, 00, // supersubscript + 00, 00, // underline, family + 00, 00, // charset, padding + 05, 00, // name length, unicode flag + 0x41, 0x72, 0x69, 0x61, 0x6C, // Arial, as unicode + }; public void testLoad() { FontRecord record = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); - assertEquals( 0xc8, record.getFontHeight()); - assertEquals( 0x00, record.getAttributes()); - assertFalse( record.isItalic()); - assertFalse( record.isStruckout()); - assertFalse( record.isMacoutlined()); - assertFalse( record.isMacshadowed()); - assertEquals( 0x7fff, record.getColorPaletteIndex()); - assertEquals( 0x190, record.getBoldWeight()); - assertEquals( 0x00, record.getSuperSubScript()); - assertEquals( 0x00, record.getUnderline()); - assertEquals( 0x00, record.getFamily()); - assertEquals( 0x00, record.getCharset()); - assertEquals( 0x05, record.getFontNameLength()); - assertEquals( "Arial", record.getFontName()); + assertEquals(0xc8, record.getFontHeight()); + assertEquals(0x00, record.getAttributes()); + assertFalse(record.isItalic()); + assertFalse(record.isStruckout()); + assertFalse(record.isMacoutlined()); + assertFalse(record.isMacshadowed()); + assertEquals(0x7fff, record.getColorPaletteIndex()); + assertEquals(0x190, record.getBoldWeight()); + assertEquals(0x00, record.getSuperSubScript()); + assertEquals(0x00, record.getUnderline()); + assertEquals(0x00, record.getFamily()); + assertEquals(0x00, record.getCharset()); + assertEquals("Arial", record.getFontName()); - - assertEquals( 26 + 4, record.getRecordSize() ); + assertEquals(21 + 4, record.getRecordSize()); } - public void testStore() - { + public void testStore() { // .fontheight = c8 // .attributes = 0 // .italic = false @@ -90,7 +84,6 @@ public final class TestFontRecord extends TestCase { record.setUnderline((byte)0); record.setFamily((byte)0); record.setCharset((byte)0); - record.setFontNameLength((byte)5); record.setFontName("Arial"); byte [] recordBytes = record.serialize(); @@ -98,10 +91,10 @@ public final class TestFontRecord extends TestCase { for (int i = 0; i < data.length; i++) assertEquals("At offset " + i, data[i], recordBytes[i+4]); } - - public void testCloneOnto() throws Exception { + + public void testCloneOnto() { FontRecord base = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); - + FontRecord other = new FontRecord(); other.cloneStyleFrom(base); @@ -110,18 +103,18 @@ public final class TestFontRecord extends TestCase { for (int i = 0; i < data.length; i++) assertEquals("At offset " + i, data[i], recordBytes[i+4]); } - + public void testSameProperties() throws Exception { FontRecord f1 = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); FontRecord f2 = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); - + assertTrue(f1.sameProperties(f2)); - + f2.setFontName("Arial2"); assertFalse(f1.sameProperties(f2)); f2.setFontName("Arial"); assertTrue(f1.sameProperties(f2)); - + f2.setFontHeight((short)11); assertFalse(f1.sameProperties(f2)); f2.setFontHeight((short)0xc8); diff --git a/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java b/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java index adca93814..6f6e8cc13 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java @@ -167,7 +167,7 @@ recordid = 0x1051, size =8 Area3DPtg ptgExpected = new Area3DPtg(0, 7936, 0, 0, false, false, false, false, 0); - Object ptgActual = record.getFormulaOfLink().getFormulaTokens()[0]; + Ptg ptgActual = record.getFormulaOfLink()[0]; assertEquals(ptgExpected.toString(), ptgActual.toString()); assertEquals( data.length + 4, record.getRecordSize() ); @@ -182,9 +182,7 @@ recordid = 0x1051, size =8 record.setIndexNumberFmtRecord( (short)0 ); Area3DPtg ptg = new Area3DPtg(0, 7936, 0, 0, false, false, false, false, 0); - LinkedDataFormulaField formulaOfLink = new LinkedDataFormulaField(); - formulaOfLink.setFormulaTokens(new Ptg[] { ptg, }); - record.setFormulaOfLink(formulaOfLink ); + record.setFormulaOfLink(new Ptg[] { ptg, } ); byte [] recordBytes = record.serialize(); assertEquals(recordBytes.length - 4, data.length);