Added ArrayRecord and CellRangeAddress8Bit

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690411 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-08-29 22:21:10 +00:00
parent 5cb7d5e0d1
commit 1c3cefbfdd
9 changed files with 551 additions and 488 deletions

View File

@ -0,0 +1,126 @@
/* ====================================================================
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.hssf.record.formula.Ptg;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
/**
* ARRAY (0x0221)<p/>
*
* Treated in a similar way to SharedFormulaRecord
*
* @author Josh Micich
*/
public final class ArrayRecord extends Record {
public final static short sid = 0x0221;
private static final int OPT_ALWAYS_RECALCULATE = 0x0001;
private static final int OPT_CALCULATE_ON_OPEN = 0x0002;
private CellRangeAddress8Bit _range;
private int _options;
private int _field3notUsed;
private Ptg[] _formulaTokens;
public ArrayRecord(RecordInputStream in) {
super(in);
}
public boolean isAlwaysRecalculate() {
return (_options & OPT_ALWAYS_RECALCULATE) != 0;
}
public boolean isCalculateOnOpen() {
return (_options & OPT_CALCULATE_ON_OPEN) != 0;
}
protected void validateSid(short id) {
if (id != sid) {
throw new RecordFormatException("NOT A valid Array RECORD");
}
}
private int getDataSize(){
return CellRangeAddress8Bit.ENCODED_SIZE
+ 2 + 4
+ getFormulaSize();
}
public int serialize( int offset, byte[] data ) {
int dataSize = getDataSize();
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putUShort(data, 2 + offset, dataSize);
int pos = offset+4;
_range.serialize(pos, data);
pos += CellRangeAddress8Bit.ENCODED_SIZE;
LittleEndian.putUShort(data, pos, _options);
pos+=2;
LittleEndian.putInt(data, pos, _field3notUsed);
pos+=4;
int tokenSize = Ptg.getEncodedSizeWithoutArrayData(_formulaTokens);
LittleEndian.putUShort(data, pos, tokenSize);
pos+=2;
Ptg.serializePtgs(_formulaTokens, data, pos);
return dataSize + 4;
}
private int getFormulaSize() {
int result = 0;
for (int i = 0; i < _formulaTokens.length; i++) {
result += _formulaTokens[i].getSize();
}
return result;
}
public int getRecordSize(){
return 4 + getDataSize();
}
protected void fillFields(RecordInputStream in) {
_range = new CellRangeAddress8Bit(in);
_options = in.readUShort();
_field3notUsed = in.readInt();
int formulaLen = in.readUShort();
_formulaTokens = Ptg.readTokens(formulaLen, in);
}
public short getSid() {
return sid;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName()).append(" [ARRAY]\n");
sb.append(" range=").append(_range.toString()).append("\n");
sb.append(" options=").append(HexDump.shortToHex(_options)).append("\n");
sb.append(" notUsed=").append(HexDump.intToHex(_field3notUsed)).append("\n");
sb.append(" formula:").append("\n");
for (int i = 0; i < _formulaTokens.length; i++) {
sb.append(_formulaTokens[i].toString());
}
sb.append("]");
return sb.toString();
}
}

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import org.apache.poi.util.LittleEndian;
/**
@ -35,66 +36,25 @@ public final class SelectionRecord extends Record {
private int field_2_row_active_cell;
private int field_3_col_active_cell;
private int field_4_active_cell_ref_index;
private Reference[] field_6_refs;
/**
* Note - column values are 8-bit so cannot use <tt>CellRangeAddressList</tt>
*/
public class Reference {
/* package */ static final int ENCODED_SIZE = 6;
private int _firstRow;
private int _lastRow;
private int _firstCol;
private int _lastCol;
/* package */ Reference(int firstRow, int lastRow, int firstColumn, int lastColumn) {
_firstRow = firstRow;
_lastRow = lastRow;
_firstCol = firstColumn;
_lastCol = lastColumn;
}
/* package */ Reference(RecordInputStream in) {
this(in.readUShort(), in.readUShort(), in.readUByte(), in.readUByte());
}
public void serialize(int offset, byte[] data) {
LittleEndian.putUShort(data, offset + 0, _firstRow);
LittleEndian.putUShort(data, offset + 2, _lastRow);
LittleEndian.putByte(data, offset + 4, _firstCol);
LittleEndian.putByte(data, offset + 6, _lastCol);
}
public int getFirstRow() {
return _firstRow;
}
public int getLastRow() {
return _lastRow;
}
public int getFirstColumn() {
return _firstCol;
}
public int getLastColumn() {
return _lastCol;
}
}
private CellRangeAddress8Bit[] field_6_refs;
/**
* Creates a default selection record (cell A1, in pane ID 3)
*/
public SelectionRecord(int activeCellRow, int activeCellCol) {
field_1_pane = 3; // pane id 3 is always present. see OOO sec 5.75 'PANE'
field_2_row_active_cell = activeCellRow;
field_3_col_active_cell = activeCellCol;
field_4_active_cell_ref_index = 0;
field_6_refs = new Reference[] {
new Reference(activeCellRow, activeCellRow, activeCellCol, activeCellCol),
};
field_1_pane = 3; // pane id 3 is always present. see OOO sec 5.75 'PANE'
field_2_row_active_cell = activeCellRow;
field_3_col_active_cell = activeCellCol;
field_4_active_cell_ref_index = 0;
field_6_refs = new CellRangeAddress8Bit[] {
new CellRangeAddress8Bit(activeCellRow, activeCellRow, activeCellCol, activeCellCol),
};
}
/**
* Constructs a Selection record and sets its fields appropriately.
* @param in the RecordInputstream to read the record from
*/
public SelectionRecord(RecordInputStream in) {
super(in);
}
@ -112,10 +72,10 @@ public final class SelectionRecord extends Record {
field_4_active_cell_ref_index = in.readShort();
int field_5_num_refs = in.readUShort();
field_6_refs = new Reference[field_5_num_refs];
field_6_refs = new CellRangeAddress8Bit[field_5_num_refs];
for (int i = 0; i < field_6_refs.length; i++) {
field_6_refs[i] = new Reference(in);
}
field_6_refs[i] = new CellRangeAddress8Bit(in);
}
}
/**
@ -180,8 +140,7 @@ public final class SelectionRecord extends Record {
return (short)field_4_active_cell_ref_index;
}
public String toString()
{
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[SELECTION]\n");
@ -199,11 +158,11 @@ public final class SelectionRecord extends Record {
return buffer.toString();
}
private int getDataSize() {
return 9 // 1 byte + 4 shorts
+ field_6_refs.length * Reference.ENCODED_SIZE;
return 9 // 1 byte + 4 shorts
+ CellRangeAddress8Bit.getEncodedSize(field_6_refs.length);
}
public int serialize(int offset, byte [] data) {
int dataSize = getDataSize();
int dataSize = getDataSize();
LittleEndian.putUShort(data, 0 + offset, sid);
LittleEndian.putUShort(data, 2 + offset, dataSize);
LittleEndian.putByte(data, 4 + offset, getPane());
@ -213,9 +172,9 @@ public final class SelectionRecord extends Record {
int nRefs = field_6_refs.length;
LittleEndian.putUShort(data, 11 + offset, nRefs);
for (int i = 0; i < field_6_refs.length; i++) {
Reference r = field_6_refs[i];
r.serialize(offset + 13 + i * Reference.ENCODED_SIZE, data);
}
CellRangeAddress8Bit r = field_6_refs[i];
r.serialize(offset + 13 + i * CellRangeAddress8Bit.ENCODED_SIZE, data);
}
return 4 + dataSize;
}

View File

@ -17,17 +17,16 @@
package org.apache.poi.hssf.record;
import java.util.List;
import java.util.Stack;
import org.apache.poi.hssf.record.formula.AreaNPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefNPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import org.apache.poi.util.HexDump;
/**
* Title: SharedFormulaRecord
* Title: SHAREDFMLA (0x04BC) SharedFormulaRecord
* Description: Primarily used as an excel optimization so that multiple similar formulas
* are not written out too many times. We should recognize this record and
* serialize as is since this is used when reading templates.
@ -40,58 +39,46 @@ import org.apache.poi.hssf.record.formula.RefPtg;
public final class SharedFormulaRecord extends Record {
public final static short sid = 0x04BC;
private int field_1_first_row;
private int field_2_last_row;
private short field_3_first_column;
private short field_4_last_column;
private int field_5_reserved;
private short field_6_expression_len;
private Stack field_7_parsed_expr;
private CellRangeAddress8Bit _range;
private int field_5_reserved;
private Ptg[] field_7_parsed_expr;
public SharedFormulaRecord()
{
public SharedFormulaRecord() {
_range = new CellRangeAddress8Bit(0, 0, 0, 0);
field_7_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
}
/**
* @param in the RecordInputstream to read the record from
*/
public SharedFormulaRecord(RecordInputStream in)
{
public SharedFormulaRecord(RecordInputStream in) {
super(in);
}
protected void validateSid(short id)
{
if (id != this.sid)
{
protected void validateSid(short id) {
if (id != this.sid) {
throw new RecordFormatException("Not a valid SharedFormula");
}
}
public int getFirstRow() {
return field_1_first_row;
return _range.getFirstRow();
}
public int getLastRow() {
return field_2_last_row;
return _range.getLastRow();
}
public short getFirstColumn() {
return field_3_first_column;
return (short) _range.getFirstColumn();
}
public short getLastColumn() {
return field_4_last_column;
}
public short getExpressionLength()
{
return field_6_expression_len;
return (short) _range.getLastColumn();
}
/**
* spit the record out AS IS. no interperatation or identification
* spit the record out AS IS. no interpretation or identification
*/
public int serialize(int offset, byte [] data)
@ -115,65 +102,28 @@ public final class SharedFormulaRecord extends Record {
{
StringBuffer buffer = new StringBuffer();
buffer.append("[SHARED FORMULA RECORD:" + Integer.toHexString(sid) + "]\n");
buffer.append(" .id = ").append(Integer.toHexString(sid))
.append("\n");
buffer.append(" .first_row = ")
.append(Integer.toHexString(getFirstRow())).append("\n");
buffer.append(" .last_row = ")
.append(Integer.toHexString(getLastRow()))
.append("\n");
buffer.append(" .first_column = ")
.append(Integer.toHexString(getFirstColumn())).append("\n");
buffer.append(" .last_column = ")
.append(Integer.toHexString(getLastColumn()))
.append("\n");
buffer.append(" .reserved = ")
.append(Integer.toHexString(field_5_reserved))
.append("\n");
buffer.append(" .expressionlength= ").append(getExpressionLength())
.append("\n");
buffer.append("[SHARED FORMULA (").append(HexDump.intToHex(sid)).append("]\n");
buffer.append(" .range = ").append(_range.toString()).append("\n");
buffer.append(" .reserved = ").append(HexDump.shortToHex(field_5_reserved)).append("\n");
buffer.append(" .numptgsinarray = ").append(field_7_parsed_expr.size())
.append("\n");
for (int k = 0; k < field_7_parsed_expr.size(); k++ ) {
buffer.append("Formula ")
.append(k)
.append("\n")
.append(field_7_parsed_expr.get(k).toString())
.append("\n");
for (int k = 0; k < field_7_parsed_expr.length; k++ ) {
buffer.append("Formula[").append(k).append("]");
buffer.append(field_7_parsed_expr[k].toString()).append("\n");
}
buffer.append("[/SHARED FORMULA RECORD]\n");
buffer.append("[/SHARED FORMULA]\n");
return buffer.toString();
}
public short getSid()
{
public short getSid() {
return sid;
}
protected void fillFields(RecordInputStream in)
{
field_1_first_row = in.readUShort();
field_2_last_row = in.readUShort();
field_3_first_column = in.readUByte();
field_4_last_column = in.readUByte();
field_5_reserved = in.readShort();
field_6_expression_len = in.readShort();
field_7_parsed_expr = getParsedExpressionTokens(in);
}
private Stack getParsedExpressionTokens(RecordInputStream in)
{
Stack stack = new Stack();
while (in.remaining() != 0) {
Ptg ptg = Ptg.createPtg(in);
stack.push(ptg);
}
return stack;
protected void fillFields(RecordInputStream in) {
_range = new CellRangeAddress8Bit(in);
field_5_reserved = in.readShort();
int field_6_expression_len = in.readShort();
field_7_parsed_expr = Ptg.readTokens(field_6_expression_len, in);
}
/**
@ -190,7 +140,7 @@ public final class SharedFormulaRecord extends Record {
* Creates a non shared formula from the shared formula
* counter part
*/
protected static Stack convertSharedFormulas(Stack ptgs, int formulaRow, int formulaColumn) {
protected static Ptg[] convertSharedFormulas(Ptg[] ptgs, int formulaRow, int formulaColumn) {
if(false) {
/*
* TODO - (May-2008) Stop converting relative ref Ptgs in shared formula records.
@ -201,11 +151,10 @@ public final class SharedFormulaRecord extends Record {
*/
return ptgs;
}
Stack newPtgStack = new Stack();
Ptg[] newPtgStack = new Ptg[ptgs.length];
if (ptgs != null)
for (int k = 0; k < ptgs.size(); k++) {
Ptg ptg = (Ptg) ptgs.get(k);
for (int k = 0; k < ptgs.length; k++) {
Ptg ptg = ptgs[k];
byte originalOperandClass = -1;
if (!ptg.isBaseToken()) {
originalOperandClass = ptg.getPtgClass();
@ -226,12 +175,16 @@ public final class SharedFormulaRecord extends Record {
areaNPtg.isLastRowRelative(),
areaNPtg.isFirstColRelative(),
areaNPtg.isLastColRelative());
} else {
if (false) {// do we need a ptg clone here?
ptg = ptg.copy();
}
}
if (!ptg.isBaseToken()) {
ptg.setClass(originalOperandClass);
}
newPtgStack.add(ptg);
newPtgStack[k] = ptg;
}
return newPtgStack;
}
@ -248,9 +201,7 @@ public final class SharedFormulaRecord extends Record {
final int formulaRow = formula.getRow();
final int formulaColumn = formula.getColumn();
List ptgList = convertSharedFormulas(field_7_parsed_expr, formulaRow, formulaColumn);
Ptg[] ptgs = new Ptg[ptgList.size()];
ptgList.toArray(ptgs);
Ptg[] ptgs = convertSharedFormulas(field_7_parsed_expr, formulaRow, formulaColumn);
formula.setParsedExpression(ptgs);
//Now its not shared!
formula.setSharedFormula(false);

View File

@ -18,47 +18,46 @@
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.formula.TblPtg;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
/**
* DATATABLE (0x0236)<p/>
*
* TableRecord - The record specifies a data table.
* This record is preceded by a single Formula record that
* defines the first cell in the data table, which should
* only contain a single Ptg, {@link TblPtg}.
*
*
* See p536 of the June 08 binary docs
*/
public final class TableRecord extends Record {
public static final short sid = 566;
private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
private static final BitField reserved1 = BitFieldFactory.getInstance(0x0002);
private static final BitField rowOrColInpCell = BitFieldFactory.getInstance(0x0004);
private static final BitField oneOrTwoVar = BitFieldFactory.getInstance(0x0008);
private static final BitField rowDeleted = BitFieldFactory.getInstance(0x0010);
private static final BitField colDeleted = BitFieldFactory.getInstance(0x0020);
private static final BitField reserved2 = BitFieldFactory.getInstance(0x0040);
private static final BitField reserved3 = BitFieldFactory.getInstance(0x0080);
private short field_1_ref_rowFirst;
private short field_2_ref_rowLast;
private short field_3_ref_colFirst;
private short field_4_ref_colLast;
private byte field_5_flags;
private byte field_6_res;
private short field_7_rowInputRow;
private short field_8_colInputRow;
private short field_9_rowInputCol;
private short field_10_colInputCol;
public static final short sid = 0x0236;
private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
private static final BitField reserved1 = BitFieldFactory.getInstance(0x0002);
private static final BitField rowOrColInpCell = BitFieldFactory.getInstance(0x0004);
private static final BitField oneOrTwoVar = BitFieldFactory.getInstance(0x0008);
private static final BitField rowDeleted = BitFieldFactory.getInstance(0x0010);
private static final BitField colDeleted = BitFieldFactory.getInstance(0x0020);
private static final BitField reserved2 = BitFieldFactory.getInstance(0x0040);
private static final BitField reserved3 = BitFieldFactory.getInstance(0x0080);
private CellRangeAddress8Bit _range;
private int field_5_flags;
private int field_6_res;
private int field_7_rowInputRow;
private int field_8_colInputRow;
private int field_9_rowInputCol;
private int field_10_colInputCol;
protected void fillFields(RecordInputStream in) {
field_1_ref_rowFirst = in.readShort();
field_2_ref_rowLast = in.readShort();
field_3_ref_colFirst = in.readUByte();
field_4_ref_colLast = in.readUByte();
_range = new CellRangeAddress8Bit(in);
field_5_flags = in.readByte();
field_6_res = in.readByte();
field_7_rowInputRow = in.readShort();
@ -66,183 +65,146 @@ public final class TableRecord extends Record {
field_9_rowInputCol = in.readShort();
field_10_colInputCol = in.readShort();
}
public TableRecord(RecordInputStream in) {
super(in);
}
public TableRecord() {
super();
}
public short getRowFirst() {
return field_1_ref_rowFirst;
public TableRecord(RecordInputStream in) {
super(in);
}
public void setRowFirst(short field_1_ref_rowFirst) {
this.field_1_ref_rowFirst = field_1_ref_rowFirst;
public TableRecord(CellRangeAddress8Bit range) {
_range = range;
field_6_res = 0;
}
public short getRowLast() {
return field_2_ref_rowLast;
}
public void setRowLast(short field_2_ref_rowLast) {
this.field_2_ref_rowLast = field_2_ref_rowLast;
public CellRangeAddress8Bit getRange() {
return _range;
}
public short getColFirst() {
return field_3_ref_colFirst;
}
public void setColFirst(short field_3_ref_colFirst) {
this.field_3_ref_colFirst = field_3_ref_colFirst;
}
public short getColLast() {
return field_4_ref_colLast;
}
public void setColLast(short field_4_ref_colLast) {
this.field_4_ref_colLast = field_4_ref_colLast;
}
public byte getFlags() {
public int getFlags() {
return field_5_flags;
}
public void setFlags(byte field_5_flags) {
this.field_5_flags = field_5_flags;
public void setFlags(int flags) {
field_5_flags = flags;
}
public byte getReserved() {
return field_6_res;
}
public void setReserved(byte field_6_res) {
this.field_6_res = field_6_res;
}
public short getRowInputRow() {
public int getRowInputRow() {
return field_7_rowInputRow;
}
public void setRowInputRow(short field_7_rowInputRow) {
this.field_7_rowInputRow = field_7_rowInputRow;
public void setRowInputRow(int rowInputRow) {
field_7_rowInputRow = rowInputRow;
}
public short getColInputRow() {
public int getColInputRow() {
return field_8_colInputRow;
}
public void setColInputRow(short field_8_colInputRow) {
this.field_8_colInputRow = field_8_colInputRow;
public void setColInputRow(int colInputRow) {
field_8_colInputRow = colInputRow;
}
public short getRowInputCol() {
public int getRowInputCol() {
return field_9_rowInputCol;
}
public void setRowInputCol(short field_9_rowInputCol) {
this.field_9_rowInputCol = field_9_rowInputCol;
public void setRowInputCol(int rowInputCol) {
field_9_rowInputCol = rowInputCol;
}
public short getColInputCol() {
public int getColInputCol() {
return field_10_colInputCol;
}
public void setColInputCol(short field_10_colInputCol) {
this.field_10_colInputCol = field_10_colInputCol;
public void setColInputCol(int colInputCol) {
field_10_colInputCol = colInputCol;
}
public boolean isAlwaysCalc() {
return alwaysCalc.isSet(field_5_flags);
}
public void setAlwaysCalc(boolean flag) {
field_5_flags = alwaysCalc.setByteBoolean(field_5_flags, flag);
field_5_flags = alwaysCalc.setBoolean(field_5_flags, flag);
}
public boolean isRowOrColInpCell() {
return rowOrColInpCell.isSet(field_5_flags);
}
public void setRowOrColInpCell(boolean flag) {
field_5_flags = rowOrColInpCell.setByteBoolean(field_5_flags, flag);
field_5_flags = rowOrColInpCell.setBoolean(field_5_flags, flag);
}
public boolean isOneNotTwoVar() {
return oneOrTwoVar.isSet(field_5_flags);
}
public void setOneNotTwoVar(boolean flag) {
field_5_flags = oneOrTwoVar.setByteBoolean(field_5_flags, flag);
field_5_flags = oneOrTwoVar.setBoolean(field_5_flags, flag);
}
public boolean isColDeleted() {
return colDeleted.isSet(field_5_flags);
}
public void setColDeleted(boolean flag) {
field_5_flags = colDeleted.setByteBoolean(field_5_flags, flag);
field_5_flags = colDeleted.setBoolean(field_5_flags, flag);
}
public boolean isRowDeleted() {
return rowDeleted.isSet(field_5_flags);
}
public void setRowDeleted(boolean flag) {
field_5_flags = rowDeleted.setByteBoolean(field_5_flags, flag);
field_5_flags = rowDeleted.setBoolean(field_5_flags, flag);
}
public short getSid() {
return sid;
}
public int serialize(int offset, byte[] data) {
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) (16));
LittleEndian.putShort(data, 4 + offset, field_1_ref_rowFirst);
LittleEndian.putShort(data, 6 + offset, field_2_ref_rowLast);
LittleEndian.putByte(data, 8 + offset, field_3_ref_colFirst);
LittleEndian.putByte(data, 9 + offset, field_4_ref_colLast);
LittleEndian.putByte(data, 10 + offset, field_5_flags);
LittleEndian.putByte(data, 11 + offset, field_6_res);
LittleEndian.putShort(data, 12 + offset, field_7_rowInputRow);
LittleEndian.putShort(data, 14 + offset, field_8_colInputRow);
LittleEndian.putShort(data, 16 + offset, field_9_rowInputCol);
LittleEndian.putShort(data, 18 + offset, field_10_colInputCol);
return getRecordSize();
int dataSize = getDataSize();
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putUShort(data, 2 + offset, dataSize);
_range.serialize(4 + offset, data);
LittleEndian.putByte(data, 10 + offset, field_5_flags);
LittleEndian.putByte(data, 11 + offset, field_6_res);
LittleEndian.putUShort(data, 12 + offset, field_7_rowInputRow);
LittleEndian.putUShort(data, 14 + offset, field_8_colInputRow);
LittleEndian.putUShort(data, 16 + offset, field_9_rowInputCol);
LittleEndian.putUShort(data, 18 + offset, field_10_colInputCol);
return 4 + dataSize;
}
private int getDataSize() {
return CellRangeAddress8Bit.ENCODED_SIZE
+ 2 // 2 byte fields
+ 8; // 4 short fields
}
public int getRecordSize() {
return 4+16;
return 4+getDataSize();
}
protected void validateSid(short id) {
if (id != sid)
{
throw new RecordFormatException("NOT A TABLE RECORD");
}
if (id != sid)
{
throw new RecordFormatException("NOT A TABLE RECORD");
}
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[TABLE]\n");
buffer.append(" .range = ").append(_range.toString()).append("\n");
buffer.append(" .flags = ") .append(HexDump.byteToHex(field_5_flags)).append("\n");
buffer.append(" .alwaysClc= ").append(isAlwaysCalc()).append("\n");
buffer.append(" .reserved = ").append(HexDump.intToHex(field_6_res)).append("\n");
CellReference crRowInput = cr(field_7_rowInputRow, field_8_colInputRow);
CellReference crColInput = cr(field_9_rowInputCol, field_10_colInputCol);
buffer.append(" .rowInput = ").append(crRowInput.formatAsString()).append("\n");
buffer.append(" .colInput = ").append(crColInput.formatAsString()).append("\n");
buffer.append("[/TABLE]\n");
return buffer.toString();
}
private static CellReference cr(int rowIx, int colIxAndFlags) {
int colIx = colIxAndFlags & 0x00FF;
boolean isRowAbs = (colIxAndFlags & 0x8000) == 0;
boolean isColAbs = (colIxAndFlags & 0x4000) == 0;
return new CellReference(rowIx, colIx, isRowAbs, isColAbs);
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("[TABLE]\n");
buffer.append(" .row from = ")
.append(Integer.toHexString(field_1_ref_rowFirst)).append("\n");
buffer.append(" .row to = ")
.append(Integer.toHexString(field_2_ref_rowLast)).append("\n");
buffer.append(" .column from = ")
.append(Integer.toHexString(field_3_ref_colFirst)).append("\n");
buffer.append(" .column to = ")
.append(Integer.toHexString(field_4_ref_colLast)).append("\n");
buffer.append(" .flags = ")
.append(Integer.toHexString(field_5_flags)).append("\n");
buffer.append(" .always calc =")
.append(isAlwaysCalc()).append("\n");
buffer.append(" .reserved = ")
.append(Integer.toHexString(field_6_res)).append("\n");
buffer.append(" .row input row = ")
.append(Integer.toHexString(field_7_rowInputRow)).append("\n");
buffer.append(" .col input row = ")
.append(Integer.toHexString(field_8_colInputRow)).append("\n");
buffer.append(" .row input col = ")
.append(Integer.toHexString(field_9_rowInputCol)).append("\n");
buffer.append(" .col input col = ")
.append(Integer.toHexString(field_10_colInputCol)).append("\n");
buffer.append("[/TABLE]\n");
return buffer.toString();
}
}

View File

@ -26,153 +26,41 @@ import org.apache.poi.util.LittleEndian;
* Note - {@link SelectionRecord} uses the BIFF5 version of this structure
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
*/
public final class CellRangeAddress {
public final class CellRangeAddress extends CellRangeAddressBase {
/*
* TODO - replace org.apache.poi.hssf.util.Region
*/
public static final int ENCODED_SIZE = 8;
/** max 65536 rows in BIFF8 */
private static final int LAST_ROW_INDEX = 0x00FFFF;
/** max 256 columns in BIFF8 */
private static final int LAST_COLUMN_INDEX = 0x00FF;
private int _firstRow;
private int _firstCol;
private int _lastRow;
private int _lastCol;
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
if(!isValid(firstRow, lastRow, firstCol, lastCol)) {
throw new IllegalArgumentException("invalid cell range (" + firstRow + ", " + lastRow
+ ", " + firstCol + ", " + lastCol + ")");
}
_firstRow = firstRow;
_lastRow = convertM1ToMax(lastRow, LAST_ROW_INDEX);
_firstCol = firstCol;
_lastCol = convertM1ToMax(lastCol, LAST_COLUMN_INDEX);
super(firstRow, lastRow, firstCol, lastCol);
}
private static boolean isValid(int firstRow, int lastRow, int firstColumn, int lastColumn)
{
if(lastRow < 0 || lastRow > LAST_ROW_INDEX) {
return false;
}
if(firstRow < 0 || firstRow > LAST_ROW_INDEX) {
return false;
}
if(lastColumn < 0 || lastColumn > LAST_COLUMN_INDEX) {
return false;
}
if(firstColumn < 0 || firstColumn > LAST_COLUMN_INDEX) {
return false;
}
return true;
}
/**
* Range arithmetic is easier when using a large positive number for 'max row or column'
* instead of <tt>-1</tt>.
*/
private static int convertM1ToMax(int lastIx, int maxIndex) {
if(lastIx < 0) {
return maxIndex;
}
return lastIx;
}
public CellRangeAddress(RecordInputStream in) {
super(readUShortAndCheck(in), in.readUShort(), in.readUShort(), in.readUShort());
}
private static int readUShortAndCheck(RecordInputStream in) {
if (in.remaining() < ENCODED_SIZE) {
// Ran out of data
throw new RuntimeException("Ran out of data reading CellRangeAddress");
}
_firstRow = in.readUShort();
_lastRow = in.readUShort();
_firstCol = in.readUShort();
_lastCol = in.readUShort();
}
public boolean isFullColumnRange() {
return _firstRow == 0 && _lastRow == LAST_ROW_INDEX;
}
public boolean isFullRowRange() {
return _firstCol == 0 && _lastCol == LAST_COLUMN_INDEX;
}
/**
* @return column number for the upper left hand corner
*/
public int getFirstColumn() {
return _firstCol;
}
/**
* @return row number for the upper left hand corner
*/
public int getFirstRow() {
return _firstRow;
}
/**
* @return column number for the lower right hand corner
*/
public int getLastColumn() {
return _lastCol;
}
/**
* @return row number for the lower right hand corner
*/
public int getLastRow() {
return _lastRow;
}
/**
* @param _firstCol column number for the upper left hand corner
*/
public void setFirstColumn(int firstCol) {
_firstCol = firstCol;
}
/**
* @param rowFrom row number for the upper left hand corner
*/
public void setFirstRow(int firstRow) {
_firstRow = firstRow;
}
/**
* @param colTo column number for the lower right hand corner
*/
public void setLastColumn(int lastCol) {
_lastCol = lastCol;
}
/**
* @param rowTo row number for the lower right hand corner
*/
public void setLastRow(int lastRow) {
_lastRow = lastRow;
}
return in.readUShort();
}
public int serialize(int offset, byte[] data) {
LittleEndian.putUShort(data, offset + 0, _firstRow);
LittleEndian.putUShort(data, offset + 2, _lastRow);
LittleEndian.putUShort(data, offset + 4, _firstCol);
LittleEndian.putUShort(data, offset + 6, _lastCol);
LittleEndian.putUShort(data, offset + 0, getFirstRow());
LittleEndian.putUShort(data, offset + 2, getLastRow());
LittleEndian.putUShort(data, offset + 4, getFirstColumn());
LittleEndian.putUShort(data, offset + 6, getLastColumn());
return ENCODED_SIZE;
}
public CellRangeAddress copy() {
return new CellRangeAddress(_firstRow, _lastRow, _firstCol, _lastCol);
return new CellRangeAddress(getFirstRow(), getLastRow(), getFirstColumn(), getLastColumn());
}
public static int getEncodedSize(int numberOfItems) {
return numberOfItems * ENCODED_SIZE;
}
public String toString() {
return getClass().getName() + " ["+_firstRow+", "+_lastRow+", "+_firstCol+", "+_lastCol+"]";
}
}

View File

@ -0,0 +1,64 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
Licensed 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.util;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndian;
/**
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
*
* Like {@link CellRangeAddress} except column fields are 8-bit.
*
* @author Josh Micich
*/
public final class CellRangeAddress8Bit extends CellRangeAddressBase {
public static final int ENCODED_SIZE = 6;
public CellRangeAddress8Bit(int firstRow, int lastRow, int firstCol, int lastCol) {
super(firstRow, lastRow, firstCol, lastCol);
}
public CellRangeAddress8Bit(RecordInputStream in) {
super(readUShortAndCheck(in), in.readUShort(), in.readUByte(), in.readUByte());
}
private static int readUShortAndCheck(RecordInputStream in) {
if (in.remaining() < ENCODED_SIZE) {
// Ran out of data
throw new RuntimeException("Ran out of data reading CellRangeAddress");
}
return in.readUShort();
}
public int serialize(int offset, byte[] data) {
LittleEndian.putUShort(data, offset + 0, getFirstRow());
LittleEndian.putUShort(data, offset + 2, getLastRow());
LittleEndian.putByte(data, offset + 4, getFirstColumn());
LittleEndian.putByte(data, offset + 5, getLastColumn());
return ENCODED_SIZE;
}
public CellRangeAddress8Bit copy() {
return new CellRangeAddress8Bit(getFirstRow(), getLastRow(), getFirstColumn(), getLastColumn());
}
public static int getEncodedSize(int numberOfItems) {
return numberOfItems * ENCODED_SIZE;
}
}

View File

@ -0,0 +1,134 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
Licensed 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.util;
/**
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
*
* Common subclass of 8-bit and 16-bit versions
*
* @author Josh Micich
*/
abstract class CellRangeAddressBase {
/** max 65536 rows in BIFF8 */
private static final int LAST_ROW_INDEX = 0x00FFFF;
/** max 256 columns in BIFF8 */
private static final int LAST_COLUMN_INDEX = 0x00FF;
private int _firstRow;
private int _firstCol;
private int _lastRow;
private int _lastCol;
protected CellRangeAddressBase(int firstRow, int lastRow, int firstCol, int lastCol) {
if(!isValid(firstRow, lastRow, firstCol, lastCol)) {
throw new IllegalArgumentException("invalid cell range (" + firstRow + ", " + lastRow
+ ", " + firstCol + ", " + lastCol + ")");
}
_firstRow = firstRow;
_lastRow =lastRow;
_firstCol = firstCol;
_lastCol = lastCol;
}
private static boolean isValid(int firstRow, int lastRow, int firstColumn, int lastColumn)
{
if(lastRow < 0 || lastRow > LAST_ROW_INDEX) {
return false;
}
if(firstRow < 0 || firstRow > LAST_ROW_INDEX) {
return false;
}
if(lastColumn < 0 || lastColumn > LAST_COLUMN_INDEX) {
return false;
}
if(firstColumn < 0 || firstColumn > LAST_COLUMN_INDEX) {
return false;
}
return true;
}
public final boolean isFullColumnRange() {
return _firstRow == 0 && _lastRow == LAST_ROW_INDEX;
}
public final boolean isFullRowRange() {
return _firstCol == 0 && _lastCol == LAST_COLUMN_INDEX;
}
/**
* @return column number for the upper left hand corner
*/
public final int getFirstColumn() {
return _firstCol;
}
/**
* @return row number for the upper left hand corner
*/
public final int getFirstRow() {
return _firstRow;
}
/**
* @return column number for the lower right hand corner
*/
public final int getLastColumn() {
return _lastCol;
}
/**
* @return row number for the lower right hand corner
*/
public final int getLastRow() {
return _lastRow;
}
/**
* @param _firstCol column number for the upper left hand corner
*/
public final void setFirstColumn(int firstCol) {
_firstCol = firstCol;
}
/**
* @param rowFrom row number for the upper left hand corner
*/
public final void setFirstRow(int firstRow) {
_firstRow = firstRow;
}
/**
* @param colTo column number for the lower right hand corner
*/
public final void setLastColumn(int lastCol) {
_lastCol = lastCol;
}
/**
* @param rowTo row number for the lower right hand corner
*/
public final void setLastRow(int lastRow) {
_lastRow = lastRow;
}
public final String toString() {
return getClass().getName() + " ["+_firstRow+", "+_lastRow+", "+_firstCol+", "+_lastCol+"]";
}
}

View File

@ -17,9 +17,6 @@
package org.apache.poi.hssf.record;
import java.util.List;
import java.util.Stack;
import junit.framework.AssertionFailedError;
import junit.framework.ComparisonFailure;
import junit.framework.TestCase;
@ -63,18 +60,18 @@ public final class TestSharedFormulaRecord extends TestCase {
public void testConvertSharedFormulasOperandClasses_bug45123() {
TestcaseRecordInputStream in = new TestcaseRecordInputStream(0, SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
short encodedLen = in.readShort();
Stack sharedFormula = Ptg.createParsedExpressionTokens(encodedLen, in);
int encodedLen = in.readUShort();
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
Stack convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 100, 200);
Ptg[] convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 100, 200);
RefPtg refPtg = (RefPtg) convertedFormula.get(1);
RefPtg refPtg = (RefPtg) convertedFormula[1];
assertEquals("$C101", refPtg.toFormulaString(null));
if (refPtg.getPtgClass() == Ptg.CLASS_REF) {
throw new AssertionFailedError("Identified bug 45123");
}
confirmOperandClasses(toPtgArray(sharedFormula), toPtgArray(convertedFormula));
confirmOperandClasses(sharedFormula, convertedFormula);
}
private static void confirmOperandClasses(Ptg[] originalPtgs, Ptg[] convertedPtgs) {
@ -88,10 +85,4 @@ public final class TestSharedFormulaRecord extends TestCase {
}
}
}
private static Ptg[] toPtgArray(List list) {
Ptg[] result = new Ptg[list.size()];
list.toArray(result);
return result;
}
}

View File

@ -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,9 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import junit.framework.TestCase;
@ -26,48 +26,40 @@ import junit.framework.TestCase;
* class works correctly. Test data taken directly from a real
* Excel file.
*/
public class TestTableRecord
extends TestCase
{
public final class TestTableRecord extends TestCase {
byte[] header = new byte[] {
0x36, 02, 0x10, 00, // sid=x236, 16 bytes long
0x36, 02, 0x10, 00, // sid=x236, 16 bytes long
};
byte[] data = new byte[] {
03, 00, // from row 3
8, 00, // to row 8
04, // from col 4
06, // to col 6
00, 00, // no flags set
04, 00, // row inp row 4
01, 00, // col inp row 1
0x76, 0x40, // row inp col 0x4076 (!)
00, 00 // col inp col 0
};
byte[] data = new byte[] {
03, 00, // from row 3
8, 00, // to row 8
04, // from col 4
06, // to col 6
00, 00, // no flags set
04, 00, // row inp row 4
01, 00, // col inp row 1
0x76, 0x40, // row inp col 0x4076 (!)
00, 00 // col inp col 0
};
public TestTableRecord(String name)
{
super(name);
}
public void testLoad() {
public void testLoad()
throws Exception
{
TableRecord record = new TableRecord(new TestcaseRecordInputStream((short)0x236, (short)data.length, data));
TableRecord record = new TableRecord(new TestcaseRecordInputStream((short)0x236, (short)data.length, data));
CellRangeAddress8Bit range = record.getRange();
assertEquals(3, range.getFirstRow());
assertEquals(8, range.getLastRow());
assertEquals(4, range.getFirstColumn());
assertEquals(6, range.getLastColumn());
assertEquals(0, record.getFlags());
assertEquals(4, record.getRowInputRow());
assertEquals(1, record.getColInputRow());
assertEquals(0x4076, record.getRowInputCol());
assertEquals(0, record.getColInputCol());
assertEquals(3, record.getRowFirst());
assertEquals(8, record.getRowLast());
assertEquals(4, record.getColFirst());
assertEquals(6, record.getColLast());
assertEquals(0, record.getFlags());
assertEquals(4, record.getRowInputRow());
assertEquals(1, record.getColInputRow());
assertEquals(0x4076, record.getRowInputCol());
assertEquals(0, record.getColInputCol());
assertEquals( 16 + 4, record.getRecordSize() );
record.validateSid((short)0x236);
}
assertEquals( 16 + 4, record.getRecordSize() );
record.validateSid((short)0x236);
}
public void testStore()
{
@ -87,21 +79,17 @@ public class TestTableRecord
// .col input col = 0
// [/TABLE]
TableRecord record = new TableRecord();
record.setRowFirst((short)3);
record.setRowLast((short)8);
record.setColFirst((short)4);
record.setColLast((short)6);
record.setFlags((byte)0);
record.setReserved((byte)0);
record.setRowInputRow((short)4);
record.setColInputRow((short)1);
record.setRowInputCol((short)0x4076);
record.setColInputCol((short)0);
CellRangeAddress8Bit crab = new CellRangeAddress8Bit(3, 8, 4, 6);
TableRecord record = new TableRecord(crab);
record.setFlags((byte)0);
record.setRowInputRow(4);
record.setColInputRow(1);
record.setRowInputCol(0x4076);
record.setColInputCol(0);
byte [] recordBytes = record.serialize();
assertEquals(recordBytes.length - 4, data.length);
for (int i = 0; i < data.length; i++)
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
}
byte [] recordBytes = record.serialize();
assertEquals(recordBytes.length - 4, data.length);
for (int i = 0; i < data.length; i++)
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
}
}