From ed01488eb5ab1b6972dc0ef42bfe30ee3cb001ee Mon Sep 17 00:00:00 2001 From: Glen Stampoultzis Date: Wed, 21 Aug 2002 11:56:49 +0000 Subject: [PATCH] Fixes to chart handling and to a hidden bug to do with where the beginning of the sheet is located. Also fixed an issue with doubles and the NaN values. Some of this could use some more refactoring. git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352827 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hssf/eventmodel/HSSFEventFactory.java | 22 ++-- src/java/org/apache/poi/hssf/model/Sheet.java | 112 +++++++++++------- .../apache/poi/hssf/record/DBCellRecord.java | 4 +- .../apache/poi/hssf/record/FormulaRecord.java | 2 +- .../aggregates/ValueRecordsAggregate.java | 23 ++-- .../apache/poi/hssf/record/formula/Ptg.java | 4 +- .../apache/poi/hssf/usermodel/HSSFCell.java | 43 ++++--- .../poi/hssf/usermodel/HSSFWorkbook.java | 18 +-- .../org/apache/poi/util/LittleEndian.java | 2 +- .../org/apache/poi/util/TestLittleEndian.java | 25 +++- 10 files changed, 151 insertions(+), 104 deletions(-) diff --git a/src/java/org/apache/poi/hssf/eventmodel/HSSFEventFactory.java b/src/java/org/apache/poi/hssf/eventmodel/HSSFEventFactory.java index 4935f1ef4c..5e07c953f0 100644 --- a/src/java/org/apache/poi/hssf/eventmodel/HSSFEventFactory.java +++ b/src/java/org/apache/poi/hssf/eventmodel/HSSFEventFactory.java @@ -78,7 +78,7 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; * @see org.apache.poi.hssf.dev.EFHSSF * * @author Andrew C. Oliver (acoliver at apache dot org) - * @authro Carey Sublette (careysub@earthling.net) + * @author Carey Sublette (careysub@earthling.net) */ public class HSSFEventFactory @@ -103,7 +103,7 @@ public class HSSFEventFactory processEvents(req, in); } - + /** * Processes a file into essentially record events. * @@ -111,7 +111,7 @@ public class HSSFEventFactory * @param fs a POIFS filesystem containing your workbook * @return numeric user-specified result code. */ - + public short abortableProcessWorkbookEvents(HSSFRequest req, POIFSFileSystem fs) throws IOException, HSSFUserException { @@ -121,9 +121,9 @@ public class HSSFEventFactory /** * Processes a DocumentInputStream into essentially Record events. - * + * * If an AbortableHSSFListener causes a halt to processing during this call - * the method will return just as with abortableProcessEvents, but no + * the method will return just as with abortableProcessEvents, but no * user code or HSSFUserException will be passed back. * * @see org.apache.poi.poifs.filesystem.POIFSFileSystem#createDocumentInputStream(String) @@ -133,15 +133,15 @@ public class HSSFEventFactory public void processEvents(HSSFRequest req, InputStream in) throws IOException - { + { try { genericProcessEvents(req, in); } - catch (HSSFUserException hue) + catch (HSSFUserException hue) {/*If an HSSFUserException user exception is thrown, ignore it.*/ } } - + /** * Processes a DocumentInputStream into essentially Record events. @@ -153,11 +153,11 @@ public class HSSFEventFactory */ public short abortableProcessEvents(HSSFRequest req, InputStream in) - throws IOException, HSSFUserException + throws IOException, HSSFUserException { return genericProcessEvents(req, in); - } - + } + /** * Processes a DocumentInputStream into essentially Record events. * diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 9b88a67f98..0fc37939a8 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -59,12 +59,10 @@ import java.util.List; import java.util.ArrayList; import java.util.Iterator; -import org.apache.poi.util.POILogFactory; import org.apache.poi.hssf .record.*; // normally I don't do this, buy we literally mean ALL import org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.util.IntList; -import org.apache.poi.util.POILogger; +import org.apache.poi.util.*; import org.apache.poi.hssf.record .aggregates.*; // normally I don't do this, buy we literally mean ALL @@ -91,35 +89,33 @@ import org.apache.poi.hssf.record public class Sheet extends java.lang.Object { - public static final short LeftMargin = 0; - public static final short RightMargin = 1; - public static final short TopMargin = 2; - public static final short BottomMargin = 3; + public static final short LeftMargin = 0; + public static final short RightMargin = 1; + public static final short TopMargin = 2; + public static final short BottomMargin = 3; - protected ArrayList records = null; - int preoffset = 0; // offset of the sheet in a new file - int loc = 0; - protected boolean containsLabels = false; - ; - protected int dimsloc = 0; - protected DimensionsRecord dims; - protected DefaultColWidthRecord defaultcolwidth = null; - protected DefaultRowHeightRecord defaultrowheight = null; - protected GridsetRecord gridset = null; - protected PrintSetupRecord printSetup = null; - protected HeaderRecord header = null; - protected FooterRecord footer = null; - protected PrintGridlinesRecord printGridlines = null; - protected MergeCellsRecord merged = null; - protected int mergedloc = 0; - private static POILogger log = - POILogFactory.getLogger(Sheet.class); - private ArrayList columnSizes = - null; // holds column info - protected ValueRecordsAggregate cells = null; - protected RowRecordsAggregate rows = null; - private Iterator valueRecIterator = null; - private Iterator rowRecIterator = null; + protected ArrayList records = null; + int preoffset = 0; // offset of the sheet in a new file + int loc = 0; + protected boolean containsLabels = false; + protected int dimsloc = 0; + protected DimensionsRecord dims; + protected DefaultColWidthRecord defaultcolwidth = null; + protected DefaultRowHeightRecord defaultrowheight = null; + protected GridsetRecord gridset = null; + protected PrintSetupRecord printSetup = null; + protected HeaderRecord header = null; + protected FooterRecord footer = null; + protected PrintGridlinesRecord printGridlines = null; + protected MergeCellsRecord merged = null; + protected int mergedloc = 0; + private static POILogger log = POILogFactory.getLogger(Sheet.class); + private ArrayList columnSizes = null; // holds column info + protected ValueRecordsAggregate cells = null; + protected RowRecordsAggregate rows = null; + private Iterator valueRecIterator = null; + private Iterator rowRecIterator = null; + protected int eofLoc = 0; /** * Creates new Sheet with no intialization --useless at this point @@ -164,19 +160,23 @@ public class Sheet if (rec.getSid() == LabelRecord.sid) { - log.log(log.DEBUG, "Hit label record"); + log.log(log.DEBUG, "Hit label record."); retval.containsLabels = true; } else if (rec.getSid() == BOFRecord.sid) { bofEofNestingLevel++; + log.log(log.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel); } - else if ((rec.getSid() == EOFRecord.sid) - && (--bofEofNestingLevel == 0)) + else if (rec.getSid() == EOFRecord.sid) { - log.log(log.DEBUG, "Hit EOF record at "); - records.add(rec); - break; + --bofEofNestingLevel; + log.log(log.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel); + if (bofEofNestingLevel == 0) { + records.add(rec); + retval.eofLoc = k; + break; + } } else if (rec.getSid() == DimensionsRecord.sid) { @@ -204,7 +204,7 @@ public class Sheet { retval.defaultrowheight = ( DefaultRowHeightRecord ) rec; } - else if ( rec.isValue() ) + else if ( rec.isValue() && bofEofNestingLevel == 1 ) { if ( isfirstcell ) { @@ -218,6 +218,10 @@ public class Sheet rec = null; } } + else if ( rec.getSid() == StringRecord.sid ) + { + rec = null; + } else if ( rec.getSid() == RowRecord.sid ) { if ( isfirstrow ) @@ -255,6 +259,14 @@ public class Sheet } } retval.records = records; + if (retval.rows == null) + { + retval.rows = new RowRecordsAggregate(); + } + if (retval.cells == null) + { + retval.cells = new ValueRecordsAggregate(); + } log.log(log.DEBUG, "sheet createSheet (existing file) exited"); return retval; } @@ -421,7 +433,7 @@ public class Sheet newrec.setColumn(oldrec.getColumn()); newrec.setXFIndex(oldrec.getXFIndex()); newrec.setSSTIndex(stringid); - records.add(k, newrec); + records.add(k, newrec); } } } @@ -608,11 +620,19 @@ public class Sheet // } for (int k = 0; k < records.size(); k++) { - - // byte[] rec = (( byte [] ) bytes.get(k)); +// byte[] rec = (( byte [] ) bytes.get(k)); // System.arraycopy(rec, 0, data, offset + pos, rec.length); - pos += (( Record ) records.get(k)).serialize(pos + offset, - data); // rec.length; + Record record = (( Record ) records.get(k)); + + //uncomment to test record sizes +// byte[] data2 = new byte[record.getRecordSize()]; +// record.serialize(0, data2 ); // rec.length; +// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4 +// && record instanceof RowRecordsAggregate == false && record instanceof ValueRecordsAggregate == false) +// throw new RuntimeException("Blah!!!"); + + pos += record.serialize(pos + offset, data ); // rec.length; + } log.log(log.DEBUG, "Sheet.serialize returning "); return pos; @@ -2116,4 +2136,10 @@ public class Sheet } m.setMargin(size); } + + public int getEofLoc() + { + return eofLoc; + } + } diff --git a/src/java/org/apache/poi/hssf/record/DBCellRecord.java b/src/java/org/apache/poi/hssf/record/DBCellRecord.java index 3ccfbe1277..24ae29b903 100644 --- a/src/java/org/apache/poi/hssf/record/DBCellRecord.java +++ b/src/java/org/apache/poi/hssf/record/DBCellRecord.java @@ -57,8 +57,6 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.LittleEndian; -import java.util.ArrayList; - /** * Title: DBCell Record (Currently read only. Not required.) * Description: Used to find rows in blocks...TODO

@@ -130,7 +128,7 @@ public class DBCellRecord * sets offset from the start of this DBCellRecord to the start of the first cell in * the next DBCell block. * - * @param rowoffset to the start of the first cell in the next DBCell block + * @param offset offset to the start of the first cell in the next DBCell block */ public void setRowOffset(int offset) diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java index b5ee198f1f..836bd08d97 100644 --- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java @@ -370,7 +370,7 @@ public class FormulaRecord LittleEndian.putShort(data, 4 + offset, ( short ) getRow()); LittleEndian.putShort(data, 6 + offset, getColumn()); LittleEndian.putShort(data, 8 + offset, getXFIndex()); - LittleEndian.putDouble(data, 10 + offset, getValue()); + LittleEndian.putDouble(data, 10 + offset, field_4_value); LittleEndian.putShort(data, 18 + offset, getOptions()); LittleEndian.putInt(data, 20 + offset, field_6_zero); LittleEndian.putShort(data, 24 + offset, getExpressionLength()); diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java index c949e6fc5d..f30a5afd5a 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java @@ -55,9 +55,7 @@ package org.apache.poi.hssf.record.aggregates; -import org.apache.poi.hssf.record.CellValueRecordInterface; -import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.UnknownRecord; +import org.apache.poi.hssf.record.*; import java.util.Iterator; import java.util.List; @@ -100,7 +98,8 @@ public class ValueRecordsAggregate }*/ // XYLocator xy = new XYLocator(cell.getRow(), cell.getColumn()); - records.put(cell, cell); + Object o = records.put(cell, cell); + if ((cell.getColumn() < firstcell) || (firstcell == -1)) { firstcell = cell.getColumn(); @@ -138,15 +137,26 @@ public class ValueRecordsAggregate { int k = 0; + FormulaRecordAggregate lastFormulaAggregate = null; + for (k = offset; k < records.size(); k++) { Record rec = ( Record ) records.get(k); - if (!rec.isInValueSection() && !(rec instanceof UnknownRecord)) + if (rec instanceof StringRecord == false && !rec.isInValueSection() && !(rec instanceof UnknownRecord)) { break; } - if (rec.isValue()) + if (rec instanceof FormulaRecord) + { + lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null); + insertCell( lastFormulaAggregate ); + } + else if (rec instanceof StringRecord) + { + lastFormulaAggregate.setStringRecord((StringRecord)rec); + } + else if (rec.isValue()) { insertCell(( CellValueRecordInterface ) rec); } @@ -175,7 +185,6 @@ public class ValueRecordsAggregate } return pos - offset; } - /** * called by the constructor, should set class level fields. Should throw * runtime exception for bad/icomplete data. diff --git a/src/java/org/apache/poi/hssf/record/formula/Ptg.java b/src/java/org/apache/poi/hssf/record/formula/Ptg.java index 9bebec869d..0781c3caca 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ptg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ptg.java @@ -299,14 +299,14 @@ public abstract class Ptg */ public abstract String toFormulaString(SheetReferences refs); /** - * dump a debug representation (hexdump) to a strnig + * dump a debug representation (hexdump) to a string */ public String toDebugString() { byte[] ba = new byte[getSize()]; String retval=null; writeBytes(ba,0); try { - retval = org.apache.poi.util.HexDump.dump(ba,0,0); + retval = org.apache.poi.util.HexDump.dump(ba,0,0); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 6ba0c63f75..27d9d681e3 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -71,6 +71,7 @@ import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.ExtendedFormatRecord; +import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.util.SheetReferences; @@ -259,10 +260,11 @@ public class HSSFCell break; case CELL_TYPE_FORMULA : - record = new FormulaRecord(); - (( FormulaRecord ) record).setColumn(col); - (( FormulaRecord ) record).setRow(row); - (( FormulaRecord ) record).setXFIndex(( short ) 0); + FormulaRecord formulaRecord = new FormulaRecord(); + record = new FormulaRecordAggregate(formulaRecord,null); + formulaRecord.setColumn(col); + formulaRecord.setRow(row); + formulaRecord.setXFIndex(( short ) 0); case CELL_TYPE_BOOLEAN : record = new BoolErrRecord(); (( BoolErrRecord ) record).setColumn(col); @@ -314,15 +316,14 @@ public class HSSFCell case CELL_TYPE_STRING : stringValue = - book - .getSSTString((( LabelSSTRecord ) cval).getSSTIndex()); + book.getSSTString( ( (LabelSSTRecord ) cval).getSSTIndex()); break; case CELL_TYPE_BLANK : break; case CELL_TYPE_FORMULA : - cellValue = (( FormulaRecord ) cval).getValue(); + cellValue = (( FormulaRecordAggregate ) cval).getFormulaRecord().getValue(); break; case CELL_TYPE_BOOLEAN : @@ -369,7 +370,7 @@ public class HSSFCell retval = HSSFCell.CELL_TYPE_STRING; break; - case FormulaRecord.sid : + case FormulaRecordAggregate.sid : retval = HSSFCell.CELL_TYPE_FORMULA; break; @@ -446,20 +447,20 @@ public class HSSFCell { case CELL_TYPE_FORMULA : - FormulaRecord frec = null; + FormulaRecordAggregate frec = null; if (cellType != this.cellType) { - frec = new FormulaRecord(); + frec = new FormulaRecordAggregate(new FormulaRecord(),null); } else { - frec = ( FormulaRecord ) record; + frec = ( FormulaRecordAggregate ) record; } frec.setColumn(getCellNum()); if (setValue) { - frec.setValue(getNumericCellValue()); + frec.getFormulaRecord().setValue(getNumericCellValue()); } frec.setXFIndex(( short ) cellStyle.getIndex()); frec.setRow(row); @@ -676,8 +677,7 @@ public class HSSFCell } else { - if ((cellType != CELL_TYPE_STRING) - && (cellType != CELL_TYPE_FORMULA)) + if ((cellType != CELL_TYPE_STRING ) && ( cellType != CELL_TYPE_FORMULA)) { setCellType(CELL_TYPE_STRING, false); } @@ -702,9 +702,9 @@ public class HSSFCell setCellType(CELL_TYPE_BLANK,false); } else { setCellType(CELL_TYPE_FORMULA,false); - FormulaRecord rec = (FormulaRecord) record; - rec.setOptions(( short ) 2); - rec.setValue(0); + FormulaRecordAggregate rec = (FormulaRecordAggregate) record; + rec.getFormulaRecord().setOptions(( short ) 2); + rec.getFormulaRecord().setValue(0); rec.setXFIndex(( short ) 0x0f); FormulaParser fp = new FormulaParser(formula+";",book); fp.parse(); @@ -713,9 +713,9 @@ public class HSSFCell //System.out.println("got Ptgs " + ptg.length); for (int k = 0; k < ptg.length; k++) { size += ptg[ k ].getSize(); - rec.pushExpressionToken(ptg[ k ]); + rec.getFormulaRecord().pushExpressionToken(ptg[ k ]); } - rec.setExpressionLength(( short ) size); + rec.getFormulaRecord().setExpressionLength(( short ) size); //Workbook.currentBook = null; } } @@ -723,7 +723,7 @@ public class HSSFCell public String getCellFormula() { //Workbook.currentBook=book; SheetReferences refs = book.getSheetReferences(); - String retval = FormulaParser.toFormulaString(refs, ((FormulaRecord)record).getParsedExpression()); + String retval = FormulaParser.toFormulaString(refs, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression()); //Workbook.currentBook=null; return retval; } @@ -825,8 +825,7 @@ public class HSSFCell public void setCellValue(boolean value) { - if ((cellType != CELL_TYPE_BOOLEAN) - && (cellType != CELL_TYPE_FORMULA)) + if ((cellType != CELL_TYPE_BOOLEAN ) && ( cellType != CELL_TYPE_FORMULA)) { setCellType(CELL_TYPE_BOOLEAN, false); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 3c9df3c27c..89d4b1b18e 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -152,14 +152,14 @@ public class HSSFWorkbook workbook = Workbook.createWorkbook(records); setPropertiesFromWorkbook(workbook); - int numRecords = workbook.getNumRecords(); + int recOffset = workbook.getNumRecords(); int sheetNum = 0; - while (numRecords < records.size()) + while (recOffset < records.size()) { - Sheet sheet = Sheet.createSheet(records, sheetNum++, numRecords); + Sheet sheet = Sheet.createSheet(records, sheetNum++, recOffset ); - numRecords += sheet.getNumRecords(); + recOffset = sheet.getEofLoc()+1; sheet.convertLabelRecords( workbook); // convert all LabelRecord records to LabelSSTRecord HSSFSheet hsheet = new HSSFSheet(workbook, sheet); @@ -511,8 +511,8 @@ public class HSSFWorkbook { totalsize = 4096; } - byte[] retval = new byte[totalsize]; - int pos = workbook.serialize(0, retval); + byte[] data = new byte[totalsize]; + int pos = workbook.serialize(0, data); // System.arraycopy(wb, 0, retval, 0, wb.length); for (int k = 0; k < sheets.size(); k++) @@ -521,13 +521,13 @@ public class HSSFWorkbook // byte[] sb = (byte[])sheetbytes.get(k); // System.arraycopy(sb, 0, retval, pos, sb.length); pos += ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos, - retval); // sb.length; + data); // sb.length; } for (int k = pos; k < totalsize; k++) { - retval[k] = 0; + data[k] = 0; } - return retval; + return data; } public int addSSTString(String string) diff --git a/src/java/org/apache/poi/util/LittleEndian.java b/src/java/org/apache/poi/util/LittleEndian.java index 95752e56a7..935fd5a668 100644 --- a/src/java/org/apache/poi/util/LittleEndian.java +++ b/src/java/org/apache/poi/util/LittleEndian.java @@ -386,7 +386,7 @@ public class LittleEndian public static void putDouble(final byte[] data, final int offset, final double value) { - putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE); + putNumber(data, offset, Double.doubleToRawLongBits(value), DOUBLE_SIZE); } diff --git a/src/testcases/org/apache/poi/util/TestLittleEndian.java b/src/testcases/org/apache/poi/util/TestLittleEndian.java index a42686cea9..56d830cc0e 100644 --- a/src/testcases/org/apache/poi/util/TestLittleEndian.java +++ b/src/testcases/org/apache/poi/util/TestLittleEndian.java @@ -147,9 +147,13 @@ public class TestLittleEndian { 56, 50, -113, -4, -63, -64, -13, 63, 76, -32, -42, -35, 60, -43, 3, 64 }; + private static final byte[] _nan_double_array = + { + (byte)0x00, (byte)0x00, (byte)0x3C, (byte)0x00, (byte)0x20, (byte)0x04, (byte)0xFF, (byte)0xFF + }; private static final double[] _doubles = { - 1.23456, 2.47912 + 1.23456, 2.47912, Double.NaN }; /** @@ -158,10 +162,21 @@ public class TestLittleEndian public void testGetDouble() { - assertEquals(_doubles[ 0 ], LittleEndian.getDouble(_double_array), - 0.000001); - assertEquals(_doubles[ 1 ], LittleEndian - .getDouble(_double_array, LittleEndian.DOUBLE_SIZE), 0.000001); + assertEquals(_doubles[ 0 ], LittleEndian.getDouble(_double_array), 0.000001 ); + assertEquals(_doubles[ 1 ], LittleEndian.getDouble( _double_array, LittleEndian.DOUBLE_SIZE), 0.000001); + assertTrue(Double.isNaN(LittleEndian.getDouble(_nan_double_array))); + + // does not work. apparently nan does not always equal nan! + //assertEquals(_doubles[ 2 ], LittleEndian.getDouble(_nan_double_array), 0.000001); + + double nan = LittleEndian.getDouble(_nan_double_array); + byte[] data = new byte[8]; + LittleEndian.putDouble(data, nan); + for ( int i = 0; i < data.length; i++ ) + { + byte b = data[i]; + assertEquals(data[i], _nan_double_array[i]); + } } /**