Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677027,677030-677040,677042-677056,677058-677375,677377-677968,677970-677971,677973,677975-677994,677996-678286,678288-678538,678540-680393,680395-680469,680471-680529,680531-680852,680854-681529,681531-681571,681573-682224,682226,682228,682231-682281,682283-682335,682337-682507,682509,682512-682517,682519-682532,682534-682619,682622-682777,682779-682998,683000-683019,683021-683022,683024-683080,683082-683092,683094-683095,683097-683127,683129-683131,683133-683166,683168-683698,683700-683705,683707-683757,683759-683787,683789-683870,683872-683879,683881-683900,683902-684066,684068-684074,684076-684222,684224-684254,684257-684281,684283-684286,684288-684292,684294-684298,684300-684301,684303-684308,684310-684317,684320,684323-684335,684337-684348,684350-684354,684356-684361,684363-684369,684371-684453,684455-684883,684885-684937,684940-684958,684960-684970,684972-684985,684987-685053,685055-685063,685065-685259,685261-685262,685264-685266,685268-685282,685285-686035,686037-686045,686047-686052,686054-686206,686208-686215,686217-686277,686279-686289,686291-686620,686622-686623,686626-686627,686629-686639,686641-686843,686845-686976,686978-687402,687404-687422,687424-687428,687430-687442,687444-688425,688427-688641,688643-688649,688651-688654,688656-688824,688826-688909,688911-689543,689545-689558,689560-689635,689637-689703,689705-689715,689717-689718,689720,689722-689972,689974-690090,690092-690093,690095-690111,690113-690258,690260-690261,690263-690517 via svnmerge from

https://svn.apache.org/repos/asf/poi/trunk

........
  r690404 | josh | 2008-08-29 23:08:42 +0100 (Fri, 29 Aug 2008) | 1 line
  
  Clean-up toString() and inner class
........
  r690411 | josh | 2008-08-29 23:21:10 +0100 (Fri, 29 Aug 2008) | 1 line
  
  Added ArrayRecord and CellRangeAddress8Bit
........
  r690461 | josh | 2008-08-30 05:34:01 +0100 (Sat, 30 Aug 2008) | 1 line
  
  Fixed decoding of operand class for ArrayPtg
........
  r690517 | nick | 2008-08-30 15:47:33 +0100 (Sat, 30 Aug 2008) | 1 line
  
  Various bug fixes, and hpbf updates
........


git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@690533 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-08-30 16:49:07 +00:00
parent 555b6980ab
commit d45000201f
29 changed files with 961 additions and 722 deletions

View File

@ -64,6 +64,11 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
<action dev="POI-DEVELOPERS" type="fix">Avoid NPE in hssf.usermodel.HeaderFooter when stripping fields out</action>
<action dev="POI-DEVELOPERS" type="fix">Avoid NPE in EscherBSERecord on older escher records</action>
<action dev="POI-DEVELOPERS" type="add">Basic text extractraction support in HPBF</action>
<action dev="POI-DEVELOPERS" type="add">Initial, low level support for Publisher files, in the form of HPBF</action>
<action dev="POI-DEVELOPERS" type="fix">45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records</action>
<action dev="POI-DEVELOPERS" type="fix">45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records</action>
<action dev="POI-DEVELOPERS" type="fix">45682 - Fix for cloning of CFRecordsAggregate</action>

View File

@ -165,6 +165,12 @@ PL 62 1a 00 00 48 00 00 00 // PL from: 1a62 (6754), len: 48 (72)
(the text will then start)
</source>
<p>We think that the first 4 bytes of text describes the
the function of the data at the offset. The first short is
then the count of that type, eg the 2nd will have 1. We
think that the second 4 bytes of text describes the format
of data block at the offset. The format of the text block
is easy, but we're still trying to figure out the others.</p>
</section>
</body>
</document>

View File

@ -33,11 +33,20 @@
<title>Overview</title>
<p>HPBF is the POI Project's pure Java implementation of the Visio file format.</p>
<p>Currently, HPBF is in the experimental stage, while we try
to figure out the file format. Our initial aim is to provide
a text extractor for the format, with low level code following
after that if demand and developer interest warrant it.</p>
<p>At this time, there is no <em>usermodel</em> api or similar.</p>
<p>Currently, HPBF is in an early stage, whilst we try to
figure out the file format. So far, we have basic text
extraction support, and are able to read some parts within
the file. Writing is not yet supported, as we are unable
to make sense of the Contents stream, which we think has
lots of offsets to other parts of the file.</p>
<p>Our initial aim is to provude a text extractor for the format
(now done), and be able to extract hyperlinks from within
the document (not yet supported). Additional low level
code to process the file format may follow, if there
is demand and developer interest warrant it.</p>
<p>At this time, there is no <em>usermodel</em> api or similar.
There is only low level support for certain parts of
the file, but by no means all of it.</p>
<p>Our current understanding of the file format is documented
<link href="file-format.html">here</link>.</p>
<note>

View File

@ -160,8 +160,8 @@
</section>
<section><title>HPBF for Publisher Documents</title>
<p>HPBF is our port of the Microsoft Publisher 98(-2007) file format to pure
Java. At the moment, we are still figuring out the file format, but we hope
to have simple text extraction shortly. Please see <link
Java. It currently only supports reading at a low level for around
half of the file parts, and simple text extraction. Please see <link
href="./hpbf/index.html">the HPBF project page for more
information</link>.</p>
</section>

View File

@ -61,6 +61,11 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
<action dev="POI-DEVELOPERS" type="fix">Avoid NPE in hssf.usermodel.HeaderFooter when stripping fields out</action>
<action dev="POI-DEVELOPERS" type="fix">Avoid NPE in EscherBSERecord on older escher records</action>
<action dev="POI-DEVELOPERS" type="add">Basic text extractraction support in HPBF</action>
<action dev="POI-DEVELOPERS" type="add">Initial, low level support for Publisher files, in the form of HPBF</action>
<action dev="POI-DEVELOPERS" type="fix">45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records</action>
<action dev="POI-DEVELOPERS" type="fix">45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records</action>
<action dev="POI-DEVELOPERS" type="fix">45682 - Fix for cloning of CFRecordsAggregate</action>

View File

@ -87,9 +87,10 @@ public class EscherBSERecord
field_10_unused2 = data[pos + 34];
field_11_unused3 = data[pos + 35];
bytesRemaining -= 36;
int bytesRead = 0;
if (bytesRemaining > 0)
{
if (bytesRemaining > 0) {
// Some older escher formats skip this last record
field_12_blipRecord = (EscherBlipRecord) recordFactory.createRecord( data, pos + 36 );
bytesRead = field_12_blipRecord.fillFields( data, pos + 36, recordFactory );
}
@ -168,7 +169,16 @@ public class EscherBSERecord
*/
public int getRecordSize()
{
return 8 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + field_12_blipRecord.getRecordSize() + (remainingData == null ? 0 : remainingData.length);
int field_12_size = 0;
if(field_12_blipRecord != null) {
field_12_size = field_12_blipRecord.getRecordSize();
}
int remaining_size = 0;
if(remainingData != null) {
remaining_size = remainingData.length;
}
return 8 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 +
1 + 1 + field_12_size + remaining_size;
}
/**

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

@ -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,184 +14,152 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
/*
* MulRKRecord.java
*
* Created on November 9, 2001, 4:53 PM
*/
package org.apache.poi.hssf.record;
import java.util.ArrayList;
import org.apache.poi.hssf.util.RKUtil;
import org.apache.poi.util.HexDump;
/**
* MULRK (0x00BD) <p/>
*
* Used to store multiple RK numbers on a row. 1 MulRk = Multiple Cell values.
* HSSF just converts this into multiple NUMBER records. READ-ONLY SUPPORT!<P>
* REFERENCE: PG 330 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @version 2.0-pre
*/
public final class MulRKRecord extends Record {
public final static short sid = 0x00BD;
public class MulRKRecord
extends Record
{
public final static short sid = 0xbd;
//private short field_1_row;
private int field_1_row;
private short field_2_first_col;
private ArrayList field_3_rks;
private short field_4_last_col;
private int field_1_row;
private short field_2_first_col;
private RkRec[] field_3_rks;
private short field_4_last_col;
/** Creates new MulRKRecord */
/**
* Constructs a MulRK record and sets its fields appropriately.
*
* @param in the RecordInputstream to read the record from
*/
public MulRKRecord(RecordInputStream in) {
super(in);
}
public MulRKRecord()
{
}
public int getRow() {
return field_1_row;
}
/**
* Constructs a MulRK record and sets its fields appropriately.
*
* @param in the RecordInputstream to read the record from
*/
/**
* starting column (first cell this holds in the row)
* @return first column number
*/
public short getFirstColumn() {
return field_2_first_col;
}
public MulRKRecord(RecordInputStream in)
{
super(in);
}
/**
* ending column (last cell this holds in the row)
* @return first column number
*/
public short getLastColumn() {
return field_4_last_col;
}
//public short getRow()
public int getRow()
{
return field_1_row;
}
/**
* get the number of columns this contains (last-first +1)
* @return number of columns (last - first +1)
*/
public int getNumColumns() {
return field_4_last_col - field_2_first_col + 1;
}
/**
* starting column (first cell this holds in the row)
* @return first column number
*/
/**
* returns the xf index for column (coffset = column - field_2_first_col)
* @return the XF index for the column
*/
public short getXFAt(int coffset) {
return field_3_rks[coffset].xf;
}
public short getFirstColumn()
{
return field_2_first_col;
}
/**
* returns the rk number for column (coffset = column - field_2_first_col)
* @return the value (decoded into a double)
*/
public double getRKNumberAt(int coffset) {
return RKUtil.decodeNumber(field_3_rks[coffset].rk);
}
/**
* ending column (last cell this holds in the row)
* @return first column number
*/
/**
* @param in the RecordInputstream to read the record from
*/
protected void fillFields(RecordInputStream in) {
field_1_row = in.readUShort();
field_2_first_col = in.readShort();
field_3_rks = RkRec.parseRKs(in);
field_4_last_col = in.readShort();
}
public short getLastColumn()
{
return field_4_last_col;
}
/**
* get the number of columns this contains (last-first +1)
* @return number of columns (last - first +1)
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
public int getNumColumns()
{
return field_4_last_col - field_2_first_col + 1;
}
buffer.append("[MULRK]\n");
buffer.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
buffer.append(" .firstcol= ").append(HexDump.shortToHex(getFirstColumn())).append("\n");
buffer.append(" .lastcol = ").append(HexDump.shortToHex(getLastColumn())).append("\n");
/**
* returns the xf index for column (coffset = column - field_2_first_col)
* @return the XF index for the column
*/
for (int k = 0; k < getNumColumns(); k++) {
buffer.append(" xf[").append(k).append("] = ").append(HexDump.shortToHex(getXFAt(k))).append("\n");
buffer.append(" rk[").append(k).append("] = ").append(getRKNumberAt(k)).append("\n");
}
buffer.append("[/MULRK]\n");
return buffer.toString();
}
public short getXFAt(int coffset)
{
return (( RkRec ) field_3_rks.get(coffset)).xf;
}
/**
* called by constructor, should throw runtime exception in the event of a
* record passed with a differing ID.
*
* @param id alleged id for this record
*/
/**
* returns the rk number for column (coffset = column - field_2_first_col)
* @return the value (decoded into a double)
*/
protected void validateSid(short id)
{
if (id != sid)
{
throw new RecordFormatException("Not a MulRKRecord!");
}
}
public double getRKNumberAt(int coffset)
{
return RKUtil.decodeNumber((( RkRec ) field_3_rks.get(coffset)).rk);
}
public short getSid()
{
return sid;
}
/**
* @param in the RecordInputstream to read the record from
*/
protected void fillFields(RecordInputStream in)
{
//field_1_row = LittleEndian.getShort(data, 0 + offset);
field_1_row = in.readUShort();
field_2_first_col = in.readShort();
field_3_rks = parseRKs(in);
field_4_last_col = in.readShort();
}
public int serialize(int offset, byte [] data)
{
throw new RecordFormatException(
"Sorry, you can't serialize a MulRK in this release");
}
private ArrayList parseRKs(RecordInputStream in)
{
ArrayList retval = new ArrayList();
while ((in.remaining()-2) > 0) {
RkRec rec = new RkRec();
private static final class RkRec {
public static final int ENCODED_SIZE = 6;
public final short xf;
public final int rk;
rec.xf = in.readShort();
rec.rk = in.readInt();
retval.add(rec);
}
return retval;
}
private RkRec(RecordInputStream in) {
xf = in.readShort();
rk = in.readInt();
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("[MULRK]\n");
buffer.append("firstcol = ")
.append(Integer.toHexString(getFirstColumn())).append("\n");
buffer.append(" lastcol = ")
.append(Integer.toHexString(getLastColumn())).append("\n");
for (int k = 0; k < getNumColumns(); k++)
{
buffer.append("xf").append(k).append(" = ")
.append(Integer.toHexString(getXFAt(k))).append("\n");
buffer.append("rk").append(k).append(" = ")
.append(getRKNumberAt(k)).append("\n");
}
buffer.append("[/MULRK]\n");
return buffer.toString();
}
/**
* called by constructor, should throw runtime exception in the event of a
* record passed with a differing ID.
*
* @param id alleged id for this record
*/
protected void validateSid(short id)
{
if (id != sid)
{
throw new RecordFormatException("Not a MulRKRecord!");
}
}
public short getSid()
{
return sid;
}
public int serialize(int offset, byte [] data)
{
throw new RecordFormatException(
"Sorry, you can't serialize a MulRK in this release");
}
}
class RkRec
{
public short xf;
public int rk;
public static RkRec[] parseRKs(RecordInputStream in) {
int nItems = (in.remaining()-2) / ENCODED_SIZE;
RkRec[] retval = new RkRec[nItems];
for (int i=0; i<nItems; i++) {
retval[i] = new RkRec(in);
}
return retval;
}
}
}

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

@ -43,58 +43,6 @@ import org.apache.poi.ss.usermodel.Workbook;
public abstract class Ptg implements Cloneable {
public static final Ptg[] EMPTY_PTG_ARRAY = { };
/* convert infix order ptg list to rpn order ptg list
* @return List ptgs in RPN order
* @param infixPtgs List of ptgs in infix order
*/
/* DO NOT REMOVE
*we keep this method in case we wish to change the way we parse
*It needs a getPrecedence in OperationsPtg
public static List ptgsToRpn(List infixPtgs) {
java.util.Stack operands = new java.util.Stack();
java.util.List retval = new java.util.Stack();
java.util.ListIterator i = infixPtgs.listIterator();
Object p;
OperationPtg o ;
boolean weHaveABracket = false;
while (i.hasNext()) {
p=i.next();
if (p instanceof OperationPtg) {
if (p instanceof ParenthesisPtg) {
if (!weHaveABracket) {
operands.push(p);
weHaveABracket = true;
} else {
o = (OperationPtg) operands.pop();
while (!(o instanceof ParenthesisPtg)) {
retval.add(o);
}
weHaveABracket = false;
}
} else {
while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
retval.add(operands.pop());
}
operands.push(p);
}
} else {
retval.add(p);
}
}
while (!operands.isEmpty()) {
if (operands.peek() instanceof ParenthesisPtg ){
//throw some error
} else {
retval.add(operands.pop());
}
}
return retval;
}
*/
/**
* Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
@ -145,15 +93,15 @@ public abstract class Ptg implements Cloneable {
Ptg retval = createClassifiedPtg(id, in);
if (id > 0x60) {
if (id >= 0x60) {
retval.setClass(CLASS_ARRAY);
} else if (id > 0x40) {
} else if (id >= 0x40) {
retval.setClass(CLASS_VALUE);
} else {
retval.setClass(CLASS_REF);
}
return retval;
return retval;
}
private static Ptg createClassifiedPtg(byte id, RecordInputStream in) {
@ -396,6 +344,22 @@ public abstract class Ptg implements Cloneable {
public final byte getPtgClass() {
return ptgClass;
}
/**
* Debug / diagnostic method to get this token's 'operand class' type.
* @return 'R' for 'reference', 'V' for 'value', 'A' for 'array' and '.' for base tokens
*/
public final char getRVAType() {
if (isBaseToken()) {
return '.';
}
switch (ptgClass) {
case Ptg.CLASS_REF: return 'R';
case Ptg.CLASS_VALUE: return 'V';
case Ptg.CLASS_ARRAY: return 'A';
}
throw new RuntimeException("Unknown operand class (" + ptgClass + ")");
}
public abstract byte getDefaultOperandClass();

View File

@ -245,6 +245,11 @@ public abstract class HeaderFooter implements org.apache.poi.ss.usermodel.Header
public static String stripFields(String text) {
int pos;
// Check we really got something to work on
if(text == null || text.length() == 0) {
return text;
}
// Firstly, do the easy ones which are static
for(int i=0; i<Field.ALL_FIELDS.size(); i++) {
String seq = ((Field)Field.ALL_FIELDS.get(i)).sequence;
@ -255,6 +260,7 @@ public abstract class HeaderFooter implements org.apache.poi.ss.usermodel.Header
}
// Now do the tricky, dynamic ones
// These are things like font sizes and font names
text = text.replaceAll("\\&\\d+", "");
text = text.replaceAll("\\&\".*?,.*?\"", "");
@ -290,9 +296,9 @@ public abstract class HeaderFooter implements org.apache.poi.ss.usermodel.Header
public static final Field TIME_FIELD = new Field("&T");
public static final Field NUM_PAGES_FIELD = new Field("&N");
public static final Field PICTURE_FIELD = new Field("&P");
public static final Field PICTURE_FIELD = new Field("&G");
public static final PairField BOLD_FIELD = new PairField("&B"); // PAID
public static final PairField BOLD_FIELD = new PairField("&B");
public static final PairField ITALIC_FIELD = new PairField("&I");
public static final PairField STRIKETHROUGH_FIELD = new PairField("&S");
public static final PairField SUBSCRIPT_FIELD = new PairField("&Y");

View File

@ -27,20 +27,23 @@ import org.apache.poi.util.LittleEndian;
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
*/
public class CellRangeAddress extends org.apache.poi.ss.util.CellRangeAddress {
/*
* TODO - replace org.apache.poi.hssf.util.Region
*/
public static final int ENCODED_SIZE = 8;
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
super(firstRow, lastRow, firstCol, lastCol);
}
public CellRangeAddress() {
super();
}
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();
}
return in.readUShort();
}
}

View File

@ -0,0 +1,65 @@
/* ====================================================================
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.ss.util.CellRangeAddressBase;
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

@ -25,143 +25,29 @@ import org.apache.poi.util.LittleEndian;
* Note - {@link SelectionRecord} uses the BIFF5 version of this structure
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
*/
public class CellRangeAddress {
public class CellRangeAddress extends CellRangeAddressBase {
/*
* TODO - replace org.apache.poi.hssf.util.Region
*/
public static final int ENCODED_SIZE = 8;
/** max 65536 rows in BIFF8 */
public static final int LAST_ROW_INDEX = 0x00FFFF;
/** max 256 columns in BIFF8 */
public static final int LAST_COLUMN_INDEX = 0x00FF;
protected int _firstRow;
protected int _firstCol;
protected int _lastRow;
protected int _lastCol;
protected CellRangeAddress() {}
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 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;
public int serialize(int offset, byte[] data) {
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+"]";
}
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);
return 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.ss.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
*/
public 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

@ -0,0 +1,90 @@
/* ====================================================================
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.hpbf.dev;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hpbf.HPBFDocument;
import org.apache.poi.hpbf.model.QuillContents;
import org.apache.poi.hpbf.model.qcbits.QCBit;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
/**
* For dumping out the PLC contents of QC Bits of a
* HPBF (Publisher) file, while we try to figure out
* what the format of them is.
*/
public class PLCDumper {
private HPBFDocument doc;
private QuillContents qc;
public PLCDumper(HPBFDocument doc) {
this.doc = doc;
qc = doc.getQuillContents();
}
public PLCDumper(POIFSFileSystem fs) throws IOException {
this(new HPBFDocument(fs));
}
public PLCDumper(InputStream inp) throws IOException {
this(new POIFSFileSystem(inp));
}
public static void main(String[] args) throws Exception {
if(args.length < 1) {
System.err.println("Use:");
System.err.println(" PLCDumper <filename>");
System.exit(1);
}
PLCDumper dump = new PLCDumper(
new FileInputStream(args[0])
);
System.out.println("Dumping " + args[0]);
dump.dumpPLC();
}
private void dumpPLC() {
QuillContents qc = doc.getQuillContents();
QCBit[] bits = qc.getBits();
for(int i=0; i<bits.length; i++) {
if(bits[i] == null) continue;
if(bits[i].getBitType().equals("PLC ")) {
dumpBit(bits[i], i);
}
}
}
private void dumpBit(QCBit bit, int index) {
System.out.println("");
System.out.println("Dumping " + bit.getBitType() + " bit at " + index);
System.out.println(" Is a " + bit.getThingType() + ", number is " + bit.getOptA());
System.out.println(" Starts at " + bit.getDataOffset() + " (" + Integer.toHexString(bit.getDataOffset()) + ")");
System.out.println(" Runs for " + bit.getLength() + " (" + Integer.toHexString(bit.getLength()) + ")");
System.out.println(HexDump.dump(bit.getData(), 0, 0));
}
}

View File

@ -70,6 +70,7 @@ public final class QuillContents extends HPBFPart {
bits[i].setOptA(optA);
bits[i].setOptB(optB);
bits[i].setOptC(optC);
bits[i].setDataOffset(from);
} else {
// Doesn't have data
}

View File

@ -28,6 +28,8 @@ public abstract class QCBit {
protected int optB;
protected int optC;
protected int dataOffset;
public QCBit(String thingType, String bitType, byte[] data) {
this.thingType = thingType;
this.bitType = bitType;
@ -66,4 +68,15 @@ public abstract class QCBit {
public void setOptC(int optC) {
this.optC = optC;
}
public int getDataOffset() {
return dataOffset;
}
public void setDataOffset(int offset) {
this.dataOffset = offset;
}
public int getLength() {
return data.length;
}
}

View File

@ -167,6 +167,13 @@ public class HeaderStories {
if(stripFields) {
return Range.stripFields(text);
}
// If you create a header/footer, then remove it again, word
// will leave \r\r. Turn these back into an empty string,
// which is more what you'd expect
if(text.equals("\r\r")) {
return "";
}
return text;
}

View File

@ -59,11 +59,11 @@ public class TextPublisherTextExtractor extends TestCase {
assertEquals(
"This is some text on the first page\n" +
"Its in times new roman, font size 10, all normal\n" +
"It\u2019s in times new roman, font size 10, all normal\n" +
"" +
"This is in bold and italic\n" +
"Its Arial, 20 point font\n" +
"Its in the second textbox on the first page\n" +
"It\u2019s Arial, 20 point font\n" +
"It\u2019s in the second textbox on the first page\n" +
"" +
"This is the second page\n\n" +
"" +
@ -102,4 +102,36 @@ public class TextPublisherTextExtractor extends TestCase {
, text
);
}
/**
* We have the same file saved for Publisher 98, Publisher
* 2000 and Publisher 2007. Check they all agree.
* @throws Exception
*/
public void testMultipleVersions() throws Exception {
File f;
HPBFDocument doc;
f = new File(dir, "Sample.pub");
doc = new HPBFDocument(
new FileInputStream(f)
);
String s2007 = (new PublisherTextExtractor(doc)).getText();
f = new File(dir, "Sample2000.pub");
doc = new HPBFDocument(
new FileInputStream(f)
);
String s2000 = (new PublisherTextExtractor(doc)).getText();
f = new File(dir, "Sample98.pub");
doc = new HPBFDocument(
new FileInputStream(f)
);
String s98 = (new PublisherTextExtractor(doc)).getText();
// Check they all agree
assertEquals(s2007, s2000);
assertEquals(s2007, s98);
}
}

View File

@ -47,4 +47,38 @@ public class TestEscherParts extends TestCase {
// TODO - check the contents
}
public void testComplex() throws Exception {
File f = new File(dir, "SampleBrochure.pub");
HPBFDocument doc = new HPBFDocument(
new FileInputStream(f)
);
EscherStm es = doc.getEscherStm();
EscherDelayStm eds = doc.getEscherDelayStm();
assertNotNull(es);
assertNotNull(eds);
assertEquals(30, es.getEscherRecords().length);
assertEquals(19, eds.getEscherRecords().length);
// TODO - check contents
// Now do another complex file
f = new File(dir, "SampleNewsletter.pub");
doc = new HPBFDocument(
new FileInputStream(f)
);
es = doc.getEscherStm();
eds = doc.getEscherDelayStm();
assertNotNull(es);
assertNotNull(eds);
assertEquals(51, es.getEscherRecords().length);
assertEquals(92, eds.getEscherRecords().length);
}
}

View File

@ -183,7 +183,7 @@ public class TestWordExtractor extends TestCase {
extractor = new WordExtractor(doc);
assertEquals(
"\n\nThis is a simple header, with a \u20ac euro symbol in it.\n\n",
"This is a simple header, with a \u20ac euro symbol in it.\n\n",
extractor.getHeaderText()
);
text = extractor.getText();
@ -217,7 +217,7 @@ public class TestWordExtractor extends TestCase {
extractor = new WordExtractor(doc);
assertEquals(
"\n\nThe footer, with Moli\u00e8re, has Unicode in it.\n",
"The footer, with Moli\u00e8re, has Unicode in it.\n",
extractor.getFooterText()
);
text = extractor.getText();

View File

@ -123,7 +123,7 @@ public class TestHeaderStories extends TestCase {
assertEquals("", hs.getFirstHeader());
assertEquals("", hs.getEvenHeader());
assertEquals("\r\r", hs.getOddHeader());
assertEquals("", hs.getOddHeader()); // Was \r\r but gets emptied
assertEquals("", hs.getFirstFooter());
@ -181,13 +181,13 @@ public class TestHeaderStories extends TestCase {
public void testUnicode() throws Exception {
HeaderStories hs = new HeaderStories(unicode);
assertEquals("\r\r", hs.getFirstHeader());
assertEquals("\r\r", hs.getEvenHeader());
assertEquals("", hs.getFirstHeader());
assertEquals("", hs.getEvenHeader());
assertEquals("This is a simple header, with a \u20ac euro symbol in it.\r\r\r", hs.getOddHeader());
assertEquals("\r\r", hs.getFirstFooter());
assertEquals("\r\r", hs.getEvenFooter());
assertEquals("", hs.getFirstFooter());
assertEquals("", hs.getEvenFooter());
assertEquals("The footer, with Moli\u00e8re, has Unicode in it.\r\r", hs.getOddFooter());
}

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]);
}
}

View File

@ -20,6 +20,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.Arrays;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -128,4 +129,28 @@ public final class TestArrayPtg extends TestCase {
}
assertEquals("{TRUE,\"ABCD\";\"E\",0.0;FALSE,\"FG\"}", actualFormula);
}
/**
* worth checking since AttrPtg.sid=0x20 and Ptg.CLASS_* = (0x00, 0x20, and 0x40)
*/
public void testOperandClassDecoding() {
confirmOperandClassDecoding(Ptg.CLASS_REF);
confirmOperandClassDecoding(Ptg.CLASS_VALUE);
confirmOperandClassDecoding(Ptg.CLASS_ARRAY);
}
private static void confirmOperandClassDecoding(byte operandClass) {
byte[] fullData = new byte[ENCODED_PTG_DATA.length + ENCODED_CONSTANT_DATA.length];
System.arraycopy(ENCODED_PTG_DATA, 0, fullData, 0, ENCODED_PTG_DATA.length);
System.arraycopy(ENCODED_CONSTANT_DATA, 0, fullData, ENCODED_PTG_DATA.length, ENCODED_CONSTANT_DATA.length);
// Force encoded operand class for tArray
fullData[0] = (byte) (ArrayPtg.sid + operandClass);
RecordInputStream in = new TestcaseRecordInputStream(ArrayPtg.sid, fullData);
Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in);
ArrayPtg aPtg = (ArrayPtg) ptgs[0];
assertEquals(operandClass, aPtg.getPtgClass());
}
}

View File

@ -87,8 +87,8 @@ public final class TestHSSFHeaderFooter extends TestCase {
assertTrue(head.areFieldsStripped());
// Now even more complex
head.setCenter("HEADER TEXT &P&N&D&T&Z&F&F&A&G");
assertEquals("HEADER TEXT &G", head.getCenter());
head.setCenter("HEADER TEXT &P&N&D&T&Z&F&F&A&G&X END");
assertEquals("HEADER TEXT END", head.getCenter());
}
/**