From 77002f649179f617360d3bd93a0fad01616cc093 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sat, 9 Aug 2008 22:55:33 +0000 Subject: [PATCH] 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-684370 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r684282 | nick | 2008-08-09 16:58:24 +0100 (Sat, 09 Aug 2008) | 1 line Prepare to change how we do ranges, to handle different kinds of text in the cp area ........ r684287 | nick | 2008-08-09 17:24:20 +0100 (Sat, 09 Aug 2008) | 1 line Start to document the whole FIB stuff better ........ r684293 | nick | 2008-08-09 17:46:39 +0100 (Sat, 09 Aug 2008) | 1 line Add lots more getters/setters for useful things to the FIB ........ r684299 | nick | 2008-08-09 18:23:42 +0100 (Sat, 09 Aug 2008) | 1 line More tests to show that the range based stuff is working properly ........ r684302 | nick | 2008-08-09 18:33:29 +0100 (Sat, 09 Aug 2008) | 1 line More header and footer files, this time with unicode in it too ........ r684309 | nick | 2008-08-09 18:58:35 +0100 (Sat, 09 Aug 2008) | 1 line More range tests, which show that we do have a bug in the hwpf unicode support ........ r684318 | josh | 2008-08-09 20:29:23 +0100 (Sat, 09 Aug 2008) | 1 line Converted rows map within HSSFSheet to use Integer keys ........ r684319 | nick | 2008-08-09 20:34:38 +0100 (Sat, 09 Aug 2008) | 1 line Big big unicode rationalisation in text piece code ........ r684321 | josh | 2008-08-09 20:47:39 +0100 (Sat, 09 Aug 2008) | 1 line added getRowIndex() to HSSFCell, deprecated HSSFFormulaEvaluator.setCurrentRow() ........ r684322 | nick | 2008-08-09 20:56:37 +0100 (Sat, 09 Aug 2008) | 1 line Get most of the hwpf tests passing again ........ r684336 | nick | 2008-08-09 21:31:48 +0100 (Sat, 09 Aug 2008) | 1 line Improve FIB updating on range changes, and add passing tests for non unicode paragraph properties ........ r684349 | nick | 2008-08-09 22:31:28 +0100 (Sat, 09 Aug 2008) | 1 line Start on headers/footers support ........ r684355 | nick | 2008-08-09 22:46:14 +0100 (Sat, 09 Aug 2008) | 1 line Tests to show that header stuff all works right ........ r684362 | nick | 2008-08-09 23:08:34 +0100 (Sat, 09 Aug 2008) | 1 line Add header/footer support to HWPF WordExtractor ........ r684370 | nick | 2008-08-09 23:24:47 +0100 (Sat, 09 Aug 2008) | 1 line Disable a few HWPF tests that aren't working while the unicode/paragraph bug is outstanding ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@684374 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 3 + src/documentation/content/xdocs/status.xml | 3 + .../apache/poi/hssf/model/FormulaParser.java | 5 +- .../apache/poi/hssf/usermodel/HSSFCell.java | 78 ++---- .../hssf/usermodel/HSSFFormulaEvaluator.java | 4 +- .../apache/poi/hssf/usermodel/HSSFRow.java | 26 +- .../apache/poi/hssf/usermodel/HSSFSheet.java | 30 ++- .../poi/ss/usermodel/FormulaEvaluator.java | 54 ++-- .../org/apache/poi/ss/usermodel/Cell.java | 1 + .../org/apache/poi/ss/usermodel/Cell.java | 4 +- .../apache/poi/xssf/usermodel/XSSFCell.java | 3 + .../src/org/apache/poi/hwpf/HWPFDocument.java | 65 ++++- .../org/apache/poi/hwpf/dev/HWPFLister.java | 52 ++++ .../poi/hwpf/extractor/WordExtractor.java | 68 ++++- .../poi/hwpf/model/CPSplitCalculator.java | 141 ++++++++++ .../apache/poi/hwpf/model/FIBLongHandler.java | 7 +- .../poi/hwpf/model/FIBShortHandler.java | 9 +- .../poi/hwpf/model/FileInformationBlock.java | 166 ++++++++++-- .../org/apache/poi/hwpf/model/PlexOfCps.java | 2 + .../apache/poi/hwpf/model/PropertyNode.java | 16 +- .../apache/poi/hwpf/model/SectionTable.java | 5 +- .../org/apache/poi/hwpf/model/TextPiece.java | 119 +++++--- .../apache/poi/hwpf/model/TextPieceTable.java | 83 +++--- .../poi/hwpf/model/types/FIBAbstractType.java | 2 +- .../poi/hwpf/usermodel/HeaderStories.java | 170 ++++++++++++ .../org/apache/poi/hwpf/usermodel/Range.java | 78 ++++-- .../apache/poi/hwpf/TestHWPFRangeParts.java | 253 ++++++++++++++++++ .../poi/hwpf/data/HeaderFooterUnicode.doc | Bin 0 -> 28672 bytes .../poi/hwpf/data/HeaderFooterUnicode.docx | Bin 0 -> 15079 bytes .../hwpf/extractor/TestDifferentRoutes.java | 2 +- .../poi/hwpf/extractor/TestWordExtractor.java | 76 ++++++ .../poi/hwpf/model/TestTextPieceTable.java | 132 ++++++++- .../poi/hwpf/usermodel/TestHeaderStories.java | 189 +++++++++++++ .../poi/hwpf/usermodel/TestRangeDelete.java | 22 +- .../hwpf/usermodel/TestRangeInsertion.java | 4 +- .../hwpf/usermodel/TestRangeProperties.java | 169 ++++++++++++ .../hwpf/usermodel/TestRangeReplacement.java | 4 +- .../poi/hssf/model/TestFormulaParserEval.java | 29 +- .../formula/eval/TestCircularReferences.java | 25 +- .../formula/eval/TestExternalFunction.java | 3 +- .../record/formula/eval/TestFormulaBugs.java | 21 +- .../eval/TestFormulasFromSpreadsheet.java | 40 ++- .../record/formula/eval/TestPercentEval.java | 5 +- .../formula/functions/TestCountFuncs.java | 1 - .../record/formula/functions/TestDate.java | 123 ++++----- .../record/formula/functions/TestIsBlank.java | 6 +- .../TestLookupFunctionsFromSpreadsheet.java | 47 ++-- .../poi/hssf/usermodel/TestBug42464.java | 1 - .../poi/hssf/usermodel/TestBug43093.java | 42 +-- .../apache/poi/hssf/usermodel/TestBugs.java | 152 +++++------ .../usermodel/TestFormulaEvaluatorBugs.java | 61 ++--- .../usermodel/TestFormulaEvaluatorDocs.java | 70 +++-- .../poi/hssf/usermodel/TestHSSFCell.java | 197 ++++++-------- .../hssf/usermodel/TestHSSFDataFormatter.java | 20 +- src/types/definitions/fib_type.xml | 2 +- 55 files changed, 2127 insertions(+), 763 deletions(-) create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/model/CPSplitCalculator.java create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFRangeParts.java create mode 100755 src/scratchpad/testcases/org/apache/poi/hwpf/data/HeaderFooterUnicode.doc create mode 100755 src/scratchpad/testcases/org/apache/poi/hwpf/data/HeaderFooterUnicode.docx create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 8b9af33406..61632f25ef 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -58,6 +58,9 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + Include headers and footers int he extracted text from HWPF's WordExtractor + Added support to HWPF for headers and footers + Improve how HWPF deals with unicode internally. Should avoid some odd behaviour when manipulating unicode text 45577 - Added implementations for Excel functions NOW and TODAY 45582 - Fix for workbook streams with extra bytes trailing the EOFRecord 45537 - Include headers and footers (of slides and notes) in the extracted text from HSLF diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 62b1dc4e4f..a8157894f6 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -55,6 +55,9 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + Include headers and footers int he extracted text from HWPF's WordExtractor + Added support to HWPF for headers and footers + Improve how HWPF deals with unicode internally. Should avoid some odd behaviour when manipulating unicode text 45577 - Added implementations for Excel functions NOW and TODAY 45582 - Fix for workbook streams with extra bytes trailing the EOFRecord 45537 - Include headers and footers (of slides and notes) in the extracted text from HSLF diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java index d72d08eeaf..e229f0358f 100644 --- a/src/java/org/apache/poi/hssf/model/FormulaParser.java +++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java @@ -26,6 +26,7 @@ import org.apache.poi.hssf.record.formula.*; import org.apache.poi.hssf.record.formula.function.FunctionMetadata; import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.AreaReference; import org.apache.poi.hssf.util.CellReference; @@ -113,7 +114,7 @@ public final class FormulaParser { } public static Ptg[] parse(String formula, Workbook workbook, int formulaType) { - FormulaParser fp = new FormulaParser(formula, workbook); + FormulaParser fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, formula); fp.parse(); return fp.getRPNPtg(formulaType); } @@ -817,7 +818,7 @@ end; /** * API call to execute the parsing of the formula - * @deprecated use Ptg[] FormulaParser.parse(String, Workbook) directly + * @deprecated use {@link #parse(String, Workbook)} directly */ public void parse() { pointer=0; diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index e46729d3d3..f66baf3024 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -48,6 +48,7 @@ import org.apache.poi.hssf.record.TextObjectRecord; import org.apache.poi.hssf.record.UnicodeString; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Comment; @@ -73,59 +74,24 @@ import org.apache.poi.ss.usermodel.RichTextString; * @version 1.0-pre */ public class HSSFCell implements Cell { - /** - * Numeric Cell type (0) - * @see #setCellType(int) - * @see #getCellType() - */ - - public final static int CELL_TYPE_NUMERIC = 0; - - /** - * String Cell type (1) - * @see #setCellType(int) - * @see #getCellType() - */ - - public final static int CELL_TYPE_STRING = 1; - - /** - * Formula Cell type (2) - * @see #setCellType(int) - * @see #getCellType() - */ - - public final static int CELL_TYPE_FORMULA = 2; - - /** - * Blank Cell type (3) - * @see #setCellType(int) - * @see #getCellType() - */ - - public final static int CELL_TYPE_BLANK = 3; - - /** - * Boolean Cell type (4) - * @see #setCellType(int) - * @see #getCellType() - */ - - public final static int CELL_TYPE_BOOLEAN = 4; - - /** - * Error Cell type (5) - * @see #setCellType(int) - * @see #getCellType() - */ - - public final static int CELL_TYPE_ERROR = 5; + /** Numeric Cell type (0) @see #setCellType(int) @see #getCellType() */ + public final static int CELL_TYPE_NUMERIC = 0; + /** String Cell type (1) @see #setCellType(int) @see #getCellType() */ + public final static int CELL_TYPE_STRING = 1; + /** Formula Cell type (2) @see #setCellType(int) @see #getCellType() */ + public final static int CELL_TYPE_FORMULA = 2; + /** Blank Cell type (3) @see #setCellType(int) @see #getCellType() */ + public final static int CELL_TYPE_BLANK = 3; + /** Boolean Cell type (4) @see #setCellType(int) @see #getCellType() */ + public final static int CELL_TYPE_BOOLEAN = 4; + /** Error Cell type (5) @see #setCellType(int) @see #getCellType() */ + public final static int CELL_TYPE_ERROR = 5; + public final static short ENCODING_UNCHANGED = -1; public final static short ENCODING_COMPRESSED_UNICODE = 0; public final static short ENCODING_UTF_16 = 1; private int cellType; private HSSFRichTextString stringValue; - private short encoding = ENCODING_UNCHANGED; private HSSFWorkbook book; private Sheet sheet; private CellValueRecordInterface record; @@ -195,9 +161,7 @@ public class HSSFCell implements Cell { * @param sheet - Sheet record of the sheet containing this cell * @param cval - the Cell Value Record we wish to represent */ - protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, - CellValueRecordInterface cval) - { + protected HSSFCell(HSSFWorkbook book, Sheet sheet, CellValueRecordInterface cval) { record = cval; cellType = determineType(cval); stringValue = null; @@ -269,6 +233,12 @@ public class HSSFCell implements Cell { return book.getWorkbook(); } + /** + * @return the (zero based) index of the row containing this cell + */ + public int getRowIndex() { + return record.getRow(); + } /** * Set the cell's number within the row (0 based). * @param num short the cell number @@ -984,13 +954,13 @@ public class HSSFCell implements Cell { * Errors are displayed as #ERR<errIdx> */ public String toString() { - switch (getCellType()) { + switch (getCellType()) { case CELL_TYPE_BLANK: return ""; case CELL_TYPE_BOOLEAN: return getBooleanCellValue()?"TRUE":"FALSE"; case CELL_TYPE_ERROR: - return "#ERR"+getErrorCellValue(); + return ErrorEval.getText((( BoolErrRecord ) record).getErrorValue()); case CELL_TYPE_FORMULA: return getCellFormula(); case CELL_TYPE_NUMERIC: @@ -998,7 +968,7 @@ public class HSSFCell implements Cell { if (HSSFDateUtil.isCellDateFormatted(this)) { DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy"); return sdf.format(getDateCellValue()); - }else { + } else { return getNumericCellValue() + ""; } case CELL_TYPE_STRING: diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java index 57ec250038..97e605928d 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java @@ -39,7 +39,7 @@ public class HSSFFormulaEvaluator extends FormulaEvaluator { * your needs are more complex than just having the * formula evaluated. */ - public static FormulaParser getUnderlyingParser(HSSFWorkbook workbook, String formula) { + public static FormulaParser getUnderlyingParser(Workbook workbook, String formula) { return new FormulaParser(formula, workbook); } @@ -52,7 +52,7 @@ public class HSSFFormulaEvaluator extends FormulaEvaluator { * @param workbook */ void inspectPtgs(String formula) { - HSSFWorkbook hssfWb = (HSSFWorkbook)workbook; + HSSFWorkbook hssfWb = (HSSFWorkbook)_workbook; FormulaParser fp = new FormulaParser(formula, hssfWb); fp.parse(); Ptg[] ptgs = fp.getRPNPtg(); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java index 1a2b98f430..dff82a732e 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java @@ -45,26 +45,18 @@ public final class HSSFRow implements Comparable, Row { /** * reference to low level representation */ - private RowRecord row; /** * reference to containing low level Workbook */ - private HSSFWorkbook book; /** * reference to containing Sheet */ - private Sheet sheet; - // TODO - ditch this constructor - HSSFRow() - { - } - /** * Creates new HSSFRow from scratch. Only HSSFSheet should do this. * @@ -204,14 +196,10 @@ public final class HSSFRow implements Comparable, Row { * @param cell low level cell to create the high level representation from * @return HSSFCell representing the low level record passed in */ - - protected HSSFCell createCellFromRecord(CellValueRecordInterface cell) - { - HSSFCell hcell = new HSSFCell(book, sheet, getRowNum(), cell); + protected HSSFCell createCellFromRecord(CellValueRecordInterface cell) { + HSSFCell hcell = new HSSFCell(book, sheet, cell); addCell(hcell); - - // sheet.addValueRecord(getRowNum(),cell.getCellValueRecord()); return hcell; } @@ -318,15 +306,7 @@ public final class HSSFRow implements Comparable, Row { } /** - * Get the hssfcell representing a given column (logical cell) - * 0-based. If you ask for a cell that is not defined then - * you get a null, unless you have set a different - * {@link MissingCellPolicy} on the base workbook. - * Short method signature provided to retain binary - * compatibility. - * - * @param cellnum 0 based column number - * @return HSSFCell representing that column or null if undefined. + * @deprecated (Aug 2008) use {@link #getCell(int)} */ public HSSFCell getCell(short cellnum) { int ushortCellNum = cellnum & 0x0000FFFF; // avoid sign extension diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 1fb38f4c65..72c95159af 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -98,7 +98,8 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet */ private Sheet sheet; - private TreeMap rows; // TODO - use simple key into this map + /** stores HSSFRows by Integer (zero-based row number) key */ + private TreeMap rows; protected Workbook book; protected HSSFWorkbook workbook; private int firstrow; @@ -116,7 +117,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet protected HSSFSheet(HSSFWorkbook workbook) { sheet = Sheet.createSheet(); - rows = new TreeMap(); // new ArrayList(INITIAL_CAPACITY); + rows = new TreeMap(); this.workbook = workbook; this.book = workbook.getWorkbook(); } @@ -243,7 +244,14 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet HSSFRow hrow = (HSSFRow) row; if (rows.size() > 0) { - rows.remove(row); + Integer key = new Integer(row.getRowNum()); + HSSFRow removedRow = (HSSFRow) rows.remove(key); + if (removedRow != row) { + if (removedRow != null) { + rows.put(key, removedRow); + } + throw new RuntimeException("Specified row does not belong to this sheet"); + } if (hrow.getRowNum() == getLastRowNum()) { lastrow = findLastRow(lastrow); @@ -303,7 +311,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet private void addRow(HSSFRow row, boolean addLow) { - rows.put(row, row); + rows.put(new Integer(row.getRowNum()), row); if (addLow) { sheet.addRow(row.getRowRecord()); @@ -321,17 +329,11 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet /** * Returns the logical row (not physical) 0-based. If you ask for a row that is not * defined you get a null. This is to say row 4 represents the fifth row on a sheet. - * @param rownum row to get + * @param rowIndex row to get * @return HSSFRow representing the rownumber or null if its not defined on the sheet */ - - public HSSFRow getRow(int rownum) - { - HSSFRow row = new HSSFRow(); - - //row.setRowNum((short) rownum); - row.setRowNum( rownum); - return (HSSFRow) rows.get(row); + public HSSFRow getRow(int rowIndex) { + return (HSSFRow) rows.get(new Integer(rowIndex)); } /** @@ -592,7 +594,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet public void setHorizontallyCenter(boolean value) { - sheet.getPageSettings().getHCenter().setHCenter(value); + sheet.getPageSettings().getHCenter().setHCenter(value); } /** diff --git a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java index 4fcc0ffe10..22321ff9e1 100644 --- a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java +++ b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java @@ -26,7 +26,6 @@ import java.util.Stack; import org.apache.poi.hssf.model.FormulaParser; import org.apache.poi.hssf.record.formula.Area3DPtg; import org.apache.poi.hssf.record.formula.AreaPtg; -import org.apache.poi.hssf.record.formula.AttrPtg; import org.apache.poi.hssf.record.formula.BoolPtg; import org.apache.poi.hssf.record.formula.ControlPtg; import org.apache.poi.hssf.record.formula.IntPtg; @@ -36,7 +35,6 @@ import org.apache.poi.hssf.record.formula.NamePtg; import org.apache.poi.hssf.record.formula.NameXPtg; import org.apache.poi.hssf.record.formula.NumberPtg; import org.apache.poi.hssf.record.formula.OperationPtg; -import org.apache.poi.hssf.record.formula.ParenthesisPtg; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ref3DPtg; import org.apache.poi.hssf.record.formula.RefPtg; @@ -93,18 +91,19 @@ public class FormulaEvaluator { } - protected Row row; - protected Sheet sheet; - protected Workbook workbook; + protected Sheet _sheet; + protected Workbook _workbook; public FormulaEvaluator(Sheet sheet, Workbook workbook) { - this.sheet = sheet; - this.workbook = workbook; + this._sheet = sheet; + this._workbook = workbook; } - public void setCurrentRow(Row row) { - this.row = row; - } + /** + * Does nothing + * @deprecated - not needed, since the current row can be derived from the cell + */ + public void setCurrentRow(Row row) {} /** * If cell contains a formula, the formula is evaluated and returned, @@ -119,25 +118,25 @@ public class FormulaEvaluator { if (cell != null) { switch (cell.getCellType()) { case Cell.CELL_TYPE_BLANK: - retval = new CellValue(Cell.CELL_TYPE_BLANK, workbook.getCreationHelper()); + retval = new CellValue(Cell.CELL_TYPE_BLANK, _workbook.getCreationHelper()); break; case Cell.CELL_TYPE_BOOLEAN: - retval = new CellValue(Cell.CELL_TYPE_BOOLEAN, workbook.getCreationHelper()); + retval = new CellValue(Cell.CELL_TYPE_BOOLEAN, _workbook.getCreationHelper()); retval.setBooleanValue(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_ERROR: - retval = new CellValue(Cell.CELL_TYPE_ERROR, workbook.getCreationHelper()); + retval = new CellValue(Cell.CELL_TYPE_ERROR, _workbook.getCreationHelper()); retval.setErrorValue(cell.getErrorCellValue()); break; case Cell.CELL_TYPE_FORMULA: - retval = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook), workbook.getCreationHelper()); + retval = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper()); break; case Cell.CELL_TYPE_NUMERIC: - retval = new CellValue(Cell.CELL_TYPE_NUMERIC, workbook.getCreationHelper()); + retval = new CellValue(Cell.CELL_TYPE_NUMERIC, _workbook.getCreationHelper()); retval.setNumberValue(cell.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: - retval = new CellValue(Cell.CELL_TYPE_STRING, workbook.getCreationHelper()); + retval = new CellValue(Cell.CELL_TYPE_STRING, _workbook.getCreationHelper()); retval.setRichTextStringValue(cell.getRichStringCellValue()); break; } @@ -168,7 +167,7 @@ public class FormulaEvaluator { if (cell != null) { switch (cell.getCellType()) { case Cell.CELL_TYPE_FORMULA: - CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook), workbook.getCreationHelper()); + CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper()); switch (cv.getCellType()) { case Cell.CELL_TYPE_BOOLEAN: cell.setCellValue(cv.getBooleanValue()); @@ -213,7 +212,7 @@ public class FormulaEvaluator { if (cell != null) { switch (cell.getCellType()) { case Cell.CELL_TYPE_FORMULA: - CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook), workbook.getCreationHelper()); + CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper()); switch (cv.getCellType()) { case Cell.CELL_TYPE_BOOLEAN: cell.setCellType(Cell.CELL_TYPE_BOOLEAN); @@ -258,7 +257,6 @@ public class FormulaEvaluator { for (Iterator rit = sheet.rowIterator(); rit.hasNext();) { Row r = (Row)rit.next(); - evaluator.setCurrentRow(r); for (Iterator cit = r.cellIterator(); cit.hasNext();) { Cell c = (Cell)cit.next(); @@ -312,8 +310,8 @@ public class FormulaEvaluator { * else a runtime exception will be thrown somewhere inside the method. * (Hence this is a private method.) */ - private static ValueEval internalEvaluate(Cell srcCell, Row srcRow, Sheet sheet, Workbook workbook) { - int srcRowNum = srcRow.getRowNum(); + private static ValueEval internalEvaluate(Cell srcCell, Sheet sheet, Workbook workbook) { + int srcRowNum = srcCell.getRowIndex(); short srcColNum = srcCell.getCellNum(); @@ -379,7 +377,7 @@ public class FormulaEvaluator { int rowIx = refPtg.getRow(); Row row = sheet.getRow(rowIx); Cell cell = (row != null) ? row.getCell(colIx) : null; - stack.push(createRef2DEval(refPtg, cell, row, sheet, workbook)); + stack.push(createRef2DEval(refPtg, cell, sheet, workbook)); } else if (ptg instanceof Ref3DPtg) { Ref3DPtg refPtg = (Ref3DPtg) ptg; @@ -390,7 +388,7 @@ public class FormulaEvaluator { ); Row row = xsheet.getRow(rowIx); Cell cell = (row != null) ? row.getCell(colIx) : null; - stack.push(createRef3DEval(refPtg, cell, row, xsheet, workbook)); + stack.push(createRef3DEval(refPtg, cell, xsheet, workbook)); } else if (ptg instanceof AreaPtg) { AreaPtg ap = (AreaPtg) ptg; @@ -581,7 +579,7 @@ public class FormulaEvaluator { case Cell.CELL_TYPE_STRING: return new StringEval(cell.getRichStringCellValue().getString()); case Cell.CELL_TYPE_FORMULA: - return internalEvaluate(cell, row, sheet, workbook); + return internalEvaluate(cell, sheet, workbook); case Cell.CELL_TYPE_BOOLEAN: return BoolEval.valueOf(cell.getBooleanCellValue()); case Cell.CELL_TYPE_BLANK: @@ -597,7 +595,7 @@ public class FormulaEvaluator { * Non existent cells are treated as RefEvals containing BlankEval. */ private static Ref2DEval createRef2DEval(RefPtg ptg, Cell cell, - Row row, Sheet sheet, Workbook workbook) { + Sheet sheet, Workbook workbook) { if (cell == null) { return new Ref2DEval(ptg, BlankEval.INSTANCE); } @@ -608,7 +606,7 @@ public class FormulaEvaluator { case Cell.CELL_TYPE_STRING: return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString())); case Cell.CELL_TYPE_FORMULA: - return new Ref2DEval(ptg, internalEvaluate(cell, row, sheet, workbook)); + return new Ref2DEval(ptg, internalEvaluate(cell, sheet, workbook)); case Cell.CELL_TYPE_BOOLEAN: return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue())); case Cell.CELL_TYPE_BLANK: @@ -623,7 +621,7 @@ public class FormulaEvaluator { * create a Ref3DEval for Ref3DPtg. */ private static Ref3DEval createRef3DEval(Ref3DPtg ptg, Cell cell, - Row row, Sheet sheet, Workbook workbook) { + Sheet sheet, Workbook workbook) { if (cell == null) { return new Ref3DEval(ptg, BlankEval.INSTANCE); } @@ -633,7 +631,7 @@ public class FormulaEvaluator { case Cell.CELL_TYPE_STRING: return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString())); case Cell.CELL_TYPE_FORMULA: - return new Ref3DEval(ptg, internalEvaluate(cell, row, sheet, workbook)); + return new Ref3DEval(ptg, internalEvaluate(cell, sheet, workbook)); case Cell.CELL_TYPE_BOOLEAN: return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue())); case Cell.CELL_TYPE_BLANK: diff --git a/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java b/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java index 471dca5b40..51d9874edc 100644 --- a/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java +++ b/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java @@ -77,6 +77,7 @@ public interface Cell { int getCellType(); short getCellNum(); + int getRowIndex(); String getCellFormula(); diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java index 9a5def70c1..0211a9aaa5 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java @@ -104,6 +104,8 @@ public interface Cell { short getCellNum(); + int getRowIndex(); + /** * set the cells type (numeric, formula or string) * @see #CELL_TYPE_NUMERIC @@ -294,4 +296,4 @@ public interface Cell { * @param link hypelrink associated with this cell */ public void setHyperlink(Hyperlink link); -} \ No newline at end of file +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java index db79c2d2f0..bd3f76f6d5 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -100,6 +100,9 @@ public final class XSSFCell implements Cell { public short getCellNum() { return (short)this.cellNum; } + public int getRowIndex() { + return row.getRowNum(); + } public CellStyle getCellStyle() { // Zero is the empty default diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java index c97d6a8bf0..f06786b1fc 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java @@ -50,8 +50,10 @@ import org.apache.poi.hwpf.usermodel.*; public class HWPFDocument extends POIDocument // implements Cloneable { - /** The FIB*/ + /** The FIB */ protected FileInformationBlock _fib; + /** And for making sense of CP lengths in the FIB */ + protected CPSplitCalculator _cpSplit; /** main document stream buffer*/ protected byte[] _mainStream; @@ -177,6 +179,7 @@ public class HWPFDocument extends POIDocument // Create our FIB, and check for the doc being encrypted _fib = new FileInformationBlock(_mainStream); + _cpSplit = new CPSplitCalculator(_fib); if(_fib.isFEncrypted()) { throw new EncryptedDocumentException("Cannot process encrypted word files!"); } @@ -285,19 +288,63 @@ public class HWPFDocument extends POIDocument { return _fib; } + public CPSplitCalculator getCPSplitCalculator() + { + return _cpSplit; + } public DocumentProperties getDocProperties() { return _dop; } + + /** + * Returns the range that covers all text in the + * file, including main text, footnotes, headers + * and comments + */ + public Range getOverallRange() { + // hack to get the ending cp of the document, Have to revisit this. + java.util.List text = _tpt.getTextPieces(); + PropertyNode p = (PropertyNode)text.get(text.size() - 1); - public Range getRange() - { - // hack to get the ending cp of the document, Have to revisit this. - java.util.List text = _tpt.getTextPieces(); - PropertyNode p = (PropertyNode)text.get(text.size() - 1); + return new Range(0, p.getEnd(), this); + } - return new Range(0, p.getEnd(), this); + /** + * Returns the range which covers the whole of the + * document, but excludes any headers and footers. + */ + public Range getRange() { + return new Range( + _cpSplit.getMainDocumentStart(), + _cpSplit.getMainDocumentEnd(), + this + ); + } + + /** + * Returns the range which covers all the Footnotes. + */ + public Range getFootnoteRange() { + return new Range( + _cpSplit.getFootnoteStart(), + _cpSplit.getFootnoteEnd(), + this + ); + } + + /** + * Returns the range which covers all "Header Stories". + * A header story contains a header, footer, end note + * separators and footnote separators. + */ + public Range getHeaderStoryRange() { + return new Range( + _cpSplit.getHeaderStoryStart(), + _cpSplit.getHeaderStoryEnd(), + this + ); } /** @@ -515,6 +562,10 @@ public class HWPFDocument extends POIDocument { return _dataStream; } + public byte[] getTableStream() + { + return _tableStream; + } public int registerList(HWPFList list) { diff --git a/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java b/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java new file mode 100644 index 0000000000..8d14c3613a --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java @@ -0,0 +1,52 @@ +/* ==================================================================== + 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.hwpf.dev; + +import java.io.FileInputStream; + +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.FileInformationBlock; + +/** + * Used by developers to list out key information on a + * HWPF file. End users will probably never need to + * use this program. + */ +public class HWPFLister { + private HWPFDocument doc; + public HWPFLister(HWPFDocument doc) { + this.doc = doc; + } + + public static void main(String[] args) throws Exception { + if(args.length == 0) { + System.err.println("Use:"); + System.err.println(" HWPFLister "); + System.exit(1); + } + + HWPFLister l = new HWPFLister( + new HWPFDocument(new FileInputStream(args[0])) + ); + l.dumpFIB(); + } + + public void dumpFIB() throws Exception { + FileInformationBlock fib = doc.getFileInformationBlock(); + System.out.println(fib.toString()); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java b/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java index 85009459d7..63c6a18ca7 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java @@ -25,6 +25,7 @@ import java.util.Iterator; import org.apache.poi.POIOLE2TextExtractor; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.model.TextPiece; +import org.apache.poi.hwpf.usermodel.HeaderStories; import org.apache.poi.hwpf.usermodel.Paragraph; import org.apache.poi.hwpf.usermodel.Range; import org.apache.poi.poifs.filesystem.POIFSFileSystem; @@ -115,6 +116,65 @@ public class WordExtractor extends POIOLE2TextExtractor { return ret; } + /** + * Add the header/footer text, if it's not empty + */ + private void appendHeaderFooter(String text, StringBuffer out) { + if(text == null || text.length() == 0) + return; + + text = text.replace('\r', '\n'); + if(! text.endsWith("\n")) { + out.append(text); + out.append('\n'); + return; + } + if(text.endsWith("\n\n")) { + out.append(text.substring(0, text.length()-1)); + return; + } + out.append(text); + return; + } + /** + * Grab the text from the headers + */ + public String getHeaderText() { + HeaderStories hs = new HeaderStories(doc); + + StringBuffer ret = new StringBuffer(); + if(hs.getFirstHeader() != null) { + appendHeaderFooter(hs.getFirstHeader(), ret); + } + if(hs.getEvenHeader() != null) { + appendHeaderFooter(hs.getEvenHeader(), ret); + } + if(hs.getOddHeader() != null) { + appendHeaderFooter(hs.getOddHeader(), ret); + } + + return ret.toString(); + } + /** + * Grab the text from the footers + */ + public String getFooterText() { + HeaderStories hs = new HeaderStories(doc); + + StringBuffer ret = new StringBuffer(); + if(hs.getFirstFooter() != null) { + appendHeaderFooter(hs.getFirstFooter(), ret); + } + if(hs.getEvenFooter() != null) { + appendHeaderFooter(hs.getEvenFooter(), ret); + } + if(hs.getOddFooter() != null) { + appendHeaderFooter(hs.getOddFooter(), ret); + } + + return ret.toString(); + } + /** * Grab the text out of the text pieces. Might also include various * bits of crud, but will work in cases where the text piece -> paragraph @@ -128,7 +188,7 @@ public class WordExtractor extends POIOLE2TextExtractor { TextPiece piece = (TextPiece) textPieces.next(); String encoding = "Cp1252"; - if (piece.usesUnicode()) { + if (piece.isUnicode()) { encoding = "UTF-16LE"; } try { @@ -158,10 +218,16 @@ public class WordExtractor extends POIOLE2TextExtractor { */ public String getText() { StringBuffer ret = new StringBuffer(); + + ret.append(getHeaderText()); + String[] text = getParagraphText(); for(int i=0; i " + end + ", but actually covers " + textLength + " characters!"); + } + if(end < start) { + throw new IllegalStateException("Told we're of negative size! start="+start + " end="+end); + } } + /** - * @return If this text piece uses unicode + * Create the StringBuffer from the text and unicode flag */ - public boolean usesUnicode() + private static StringBuffer buildInitSB(byte[] text, PieceDescriptor pd) { + String str; + try { + if(pd.isUnicode()) { + str = new String(text, "UTF-16LE"); + } else { + str = new String(text, "Cp1252"); + } + } catch(UnsupportedEncodingException e) { + throw new RuntimeException("Your Java is broken! It doesn't know about basic, required character encodings!"); + } + return new StringBuffer(str); + } + + /** + * @return If this text piece is unicode + */ + public boolean isUnicode() { return _usesUnicode; } @@ -67,38 +92,43 @@ public class TextPiece extends PropertyNode implements Comparable public byte[] getRawBytes() { - try - { + try { return ((StringBuffer)_buf).toString().getBytes(_usesUnicode ? "UTF-16LE" : "Cp1252"); + } catch (UnsupportedEncodingException ignore) { + throw new RuntimeException("Your Java is broken! It doesn't know about basic, required character encodings!"); } - catch (UnsupportedEncodingException ignore) - { - // shouldn't ever happen considering we wouldn't have been able to - // create the StringBuffer w/o getting this exception - return ((StringBuffer)_buf).toString().getBytes(); - } - } + /** + * Returns part of the string. + * Works only in characters, not in bytes! + * @param start Local start position, in characters + * @param end Local end position, in characters + * @return + */ public String substring(int start, int end) { - int denominator = _usesUnicode ? 2 : 1; - - return ((StringBuffer)_buf).substring(start/denominator, end/denominator); + StringBuffer buf = (StringBuffer)_buf; + + // Validate + if(start < 0) { + throw new StringIndexOutOfBoundsException("Can't request a substring before 0 - asked for " + start); + } + if(end > buf.length()) { + throw new StringIndexOutOfBoundsException("Index " + end + " out of range 0 -> " + buf.length()); + } + return buf.substring(start, end); } - public void adjustForDelete(int start, int length) - { - - // length is expected to be the number of code-points, - // not the number of characters + /** + * Adjusts the internal string for deletinging + * some characters within this. + * @param start The start position for the delete, in characters + * @param length The number of characters to delete + */ + public void adjustForDelete(int start, int length) { int numChars = length; - if (usesUnicode()) { - - start /= 2; - numChars = (length / 2); - } int myStart = getStart(); int myEnd = getEnd(); @@ -121,9 +151,18 @@ public class TextPiece extends PropertyNode implements Comparable super.adjustForDelete(start, length); } + /** + * Returns the length, in characters + */ public int characterLength() { - return (getEnd() - getStart()) / (_usesUnicode ? 2 : 1); + return (getEnd() - getStart()); + } + /** + * Returns the length, in bytes + */ + public int bytesLength() { + return (getEnd() - getStart()) * (_usesUnicode ? 2 : 1); } public boolean equals(Object o) @@ -138,9 +177,11 @@ public class TextPiece extends PropertyNode implements Comparable } + /** + * Returns the character position we start at. + */ public int getCP() { - return _cpStart; + return getStart(); } - } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java index 39f0007b67..5e903ecb8a 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java @@ -28,6 +28,11 @@ import java.util.ArrayList; import java.util.List; /** + * The piece table for matching up character positions + * to bits of text. + * This mostly works in bytes, but the TextPieces + * themselves work in characters. This does the icky + * convertion. * @author Ryan Ackley */ public class TextPieceTable @@ -36,8 +41,7 @@ public class TextPieceTable //int _multiple; int _cpMin; - public TextPieceTable() - { + public TextPieceTable() { } public TextPieceTable(byte[] documentStream, byte[] tableStream, int offset, @@ -47,7 +51,6 @@ public class TextPieceTable // get our plex of PieceDescriptors PlexOfCps pieceTable = new PlexOfCps(tableStream, offset, size, PieceDescriptor.getSizeInBytes()); - //_multiple = 2; int length = pieceTable.length(); PieceDescriptor[] pieces = new PieceDescriptor[length]; @@ -57,11 +60,6 @@ public class TextPieceTable { GenericPropertyNode node = pieceTable.getProperty(x); pieces[x] = new PieceDescriptor(node.getBytes(), 0); - -// if (!pieces[x].isUnicode()) -// { -// _multiple = 1; -// } } int firstPieceFilePosition = pieces[0].getFilePosition(); @@ -72,26 +70,28 @@ public class TextPieceTable { int start = pieces[x].getFilePosition(); PropertyNode node = pieceTable.getProperty(x); - int nodeStart = node.getStart(); - - // multiple will be 2 if there is only one piece and its unicode. Some - // type of optimization. + + // Grab the start and end, which are in characters + int nodeStartChars = node.getStart(); + int nodeEndChars = node.getEnd(); + + // What's the relationship between bytes and characters? boolean unicode = pieces[x].isUnicode(); - int multiple = 1; - if (unicode) - { + if (unicode) { multiple = 2; } - int nodeEnd = ((node.getEnd() - nodeStart) * multiple) + nodeStart; - int textSize = nodeEnd - nodeStart; + + // Figure out the length, in bytes and chars + int textSizeChars = (nodeEndChars - nodeStartChars); + int textSizeBytes = textSizeChars * multiple; + // Grab the data that makes up the piece + byte[] buf = new byte[textSizeBytes]; + System.arraycopy(documentStream, start, buf, 0, textSizeBytes); - byte[] buf = new byte[textSize]; - System.arraycopy(documentStream, start, buf, 0, textSize); - - int startFilePosition = start - firstPieceFilePosition; - _textPieces.add(new TextPiece(startFilePosition, startFilePosition+textSize, buf, pieces[x], node.getStart())); + // And now build the piece + _textPieces.add(new TextPiece(nodeStartChars, nodeEndChars, buf, pieces[x], node.getStart())); } } @@ -113,7 +113,6 @@ public class TextPieceTable //int fcMin = docStream.getOffset(); int size = _textPieces.size(); - int bumpDown = 0; for (int x = 0; x < size; x++) { TextPiece next = (TextPiece)_textPieces.get(x); @@ -134,47 +133,43 @@ public class TextPieceTable // write the text to the docstream and save the piece descriptor to the // plex which will be written later to the tableStream. - //if (_multiple == 1 && pd.isUnicode() && docStream.write(next.getRawBytes()); + // The TextPiece is already in characters, which + // makes our life much easier int nodeStart = next.getStart(); - int multiple = 1; - if (pd.isUnicode()) - { - multiple = 2; - } - textPlex.addProperty(new GenericPropertyNode(nodeStart - bumpDown, - ((next.getEnd() - nodeStart)/multiple + nodeStart) - bumpDown, + int nodeEnd = next.getEnd(); + textPlex.addProperty(new GenericPropertyNode(nodeStart, nodeEnd, pd.toByteArray())); - - if (pd.isUnicode()) - { - bumpDown += ((next.getEnd() - nodeStart)/multiple); - } - - } return textPlex.toByteArray(); } - - public int adjustForInsert(int listIndex, int length) - { + /** + * Adjust all the text piece after inserting + * some text into one of them + * @param listIndex The TextPiece that had characters inserted into + * @param length The number of characters inserted + */ + public int adjustForInsert(int listIndex, int length) { int size = _textPieces.size(); TextPiece tp = (TextPiece)_textPieces.get(listIndex); - - //The text piece stores the length on file. - length = length * (tp.usesUnicode() ? 2 : 1); + + // Update with the new end tp.setEnd(tp.getEnd() + length); + + // Now change all subsequent ones for (int x = listIndex + 1; x < size; x++) { tp = (TextPiece)_textPieces.get(x); tp.setStart(tp.getStart() + length); tp.setEnd(tp.getEnd() + length); } + + // All done return length; } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java b/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java index dc5ffff269..6615823281 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java @@ -31,7 +31,7 @@ import org.apache.poi.hdf.model.hdftypes.HDFType; import org.apache.poi.hwpf.usermodel.*; /** - * File information Block. + * Base part of the File information Block (FibBase). Holds the core part of the FIB, from the first 32 bytes. * NOTE: This source is automatically generated please do not modify this file. Either subclass or * remove the record in src/records/definitions. diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java new file mode 100644 index 0000000000..95cee57d1b --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java @@ -0,0 +1,170 @@ +/* ==================================================================== + 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.hwpf.usermodel; + +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.FileInformationBlock; +import org.apache.poi.hwpf.model.GenericPropertyNode; +import org.apache.poi.hwpf.model.PlexOfCps; + +/** + * A HeaderStory is a Header, a Footer, or footnote/endnote + * separator. + * All the Header Stories get stored in the same Range in the + * document, and this handles getting out all the individual + * parts. + * + * WARNING - you shouldn't change the headers or footers, + * as offsets are not yet updated! + */ +public class HeaderStories { + private Range headerStories; + private PlexOfCps plcfHdd; + + public HeaderStories(HWPFDocument doc) { + this.headerStories = doc.getHeaderStoryRange(); + FileInformationBlock fib = doc.getFileInformationBlock(); + + // If there's no PlcfHdd, nothing to do + if(fib.getCcpHdd() == 0) { + return; + } + if(fib.getPlcfHddSize() == 0) { + return; + } + + // Handle the PlcfHdd + plcfHdd = new PlexOfCps( + doc.getTableStream(), fib.getPlcfHddOffset(), + fib.getPlcfHddSize(), 0 + ); + } + + public String getFootnoteSeparator() { + return getAt(0); + } + public String getFootnoteContSeparator() { + return getAt(1); + } + public String getFootnoteContNote() { + return getAt(2); + } + public String getEndnoteSeparator() { + return getAt(3); + } + public String getEndnoteContSeparator() { + return getAt(4); + } + public String getEndnoteContNote() { + return getAt(5); + } + + + public String getEvenHeader() { + return getAt(6+0); + } + public String getOddHeader() { + return getAt(6+1); + } + public String getFirstHeader() { + return getAt(6+4); + } + /** + * Returns the correct, defined header for the given + * one based page + * @param pageNumber The one based page number + * @return + */ + public String getHeader(int pageNumber) { + // First page header is optional, only return + // if it's set + if(pageNumber == 1) { + if(getFirstHeader().length() > 0) { + return getFirstHeader(); + } + } + // Even page header is optional, only return + // if it's set + if(pageNumber % 2 == 0) { + if(getEvenHeader().length() > 0) { + return getEvenHeader(); + } + } + // Odd is the default + return getOddHeader(); + } + + + public String getEvenFooter() { + return getAt(6+2); + } + public String getOddFooter() { + return getAt(6+3); + } + public String getFirstFooter() { + return getAt(6+5); + } + /** + * Returns the correct, defined footer for the given + * one based page + * @param pageNumber The one based page number + * @return + */ + public String getFooter(int pageNumber) { + // First page footer is optional, only return + // if it's set + if(pageNumber == 1) { + if(getFirstFooter().length() > 0) { + return getFirstFooter(); + } + } + // Even page footer is optional, only return + // if it's set + if(pageNumber % 2 == 0) { + if(getEvenFooter().length() > 0) { + return getEvenFooter(); + } + } + // Odd is the default + return getOddFooter(); + } + + + /** + * Get the string that's pointed to by the + * given plcfHdd index + */ + private String getAt(int plcfHddIndex) { + if(plcfHdd == null) return null; + + GenericPropertyNode prop = plcfHdd.getProperty(plcfHddIndex); + if(prop.getStart() == prop.getEnd()) { + // Empty story + return ""; + } + + // Return the contents + return headerStories.text().substring(prop.getStart(), prop.getEnd()); + } + + public Range getRange() { + return headerStories; + } + protected PlexOfCps getPlcfHdd() { + return plcfHdd; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java index 0ef944f136..0b75a1da63 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java @@ -29,6 +29,8 @@ import org.apache.poi.hwpf.usermodel.Paragraph; import org.apache.poi.hwpf.usermodel.ParagraphProperties; import org.apache.poi.hwpf.usermodel.Section; +import org.apache.poi.hwpf.model.CPSplitCalculator; +import org.apache.poi.hwpf.model.FileInformationBlock; import org.apache.poi.hwpf.model.PropertyNode; import org.apache.poi.hwpf.model.StyleSheet; import org.apache.poi.hwpf.model.CHPX; @@ -41,6 +43,8 @@ import org.apache.poi.hwpf.sprm.CharacterSprmCompressor; import org.apache.poi.hwpf.sprm.ParagraphSprmCompressor; import org.apache.poi.hwpf.sprm.SprmBuffer; +import sun.security.krb5.internal.aj; + import java.util.List; import java.util.NoSuchElementException; @@ -137,7 +141,8 @@ public class Range /** * Used to construct a Range from a document. This is generally used to - * create a Range that spans the whole document. + * create a Range that spans the whole document, or at least one + * whole part of the document (eg main text, header, comment) * * @param start Starting character offset of the range. * @param end Ending character offset of the range. @@ -238,7 +243,7 @@ public class Range for (int i = _textStart; i < _textEnd; i++) { TextPiece piece = (TextPiece)_text.get(i); - if (piece.usesUnicode()) + if (piece.isUnicode()) return true; } @@ -259,15 +264,21 @@ public class Range for (int x = _textStart; x < _textEnd; x++) { TextPiece piece = (TextPiece)_text.get(x); - int start = _start > piece.getStart() ? _start - piece.getStart() : 0; - int end = _end <= piece.getEnd() ? _end - piece.getStart() : piece.getEnd() - piece.getStart(); - - if(piece.usesUnicode()) // convert the byte pointers to char pointers - { - start/=2; - end/=2; + + // Figure out where in this piece the text + // we're after lives + int rStart = 0; + int rEnd = piece.characterLength(); + if(_start > piece.getStart()) { + rStart = _start - piece.getStart(); + } + if(_end < piece.getEnd()) { + rEnd -= (piece.getEnd() - _end); } - sb.append(piece.getStringBuffer().substring(start, end)); + + // Luckily TextPieces work in characters, so we don't + // need to worry about unicode here + sb.append(piece.substring(rStart, rEnd)); } return sb.toString(); } @@ -325,8 +336,6 @@ public class Range // Since this is the first item in our list, it is safe to assume that // _start >= tp.getStart() int insertIndex = _start - tp.getStart(); - if (tp.usesUnicode()) - insertIndex /= 2; sb.insert(insertIndex, text); int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length()); @@ -335,7 +344,7 @@ public class Range _doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength); adjustForInsert(adjustedLength); - // update the FIB.CCPText field + // update the FIB.CCPText + friends fields adjustFIB(text.length()); return getCharacterRun(0); @@ -546,11 +555,8 @@ public class Range piece.adjustForDelete(_start, _end - _start); } - // update the FIB.CCPText field - if (usesUnicode()) - adjustFIB(-((_end - _start) / 2)); - else - adjustFIB(-(_end - _start)); + // update the FIB.CCPText + friends field + adjustFIB(-(_end - _start)); } /** @@ -929,16 +935,44 @@ public class Range } /** - * Adjust the value of FIB.CCPText after an insert or a delete... + * Adjust the value of the various FIB character count fields, + * eg FIB.CCPText after an insert or a delete... + * + * Works on all CCP fields from this range onwards * - * @param adjustment The (signed) value that should be added to FIB.CCPText + * @param adjustment The (signed) value that should be added to the FIB CCP fields */ protected void adjustFIB(int adjustment) { - // update the FIB.CCPText field (this should happen once per adjustment, so we don't want it in // adjustForInsert() or it would get updated multiple times if the range has a parent) // without this, OpenOffice.org (v. 2.2.x) does not see all the text in the document - _doc.getFileInformationBlock().setCcpText(_doc.getFileInformationBlock().getCcpText() + adjustment); + + CPSplitCalculator cpS = _doc.getCPSplitCalculator(); + FileInformationBlock fib = _doc.getFileInformationBlock(); + + // Do for each affected part + if(_start < cpS.getMainDocumentEnd()) { + fib.setCcpText(fib.getCcpText() + adjustment); + } + + if(_start < cpS.getCommentsEnd()) { + fib.setCcpAtn(fib.getCcpAtn() + adjustment); + } + if(_start < cpS.getEndNoteEnd()) { + fib.setCcpEdn(fib.getCcpEdn() + adjustment); + } + if(_start < cpS.getFootnoteEnd()) { + fib.setCcpFtn(fib.getCcpFtn() + adjustment); + } + if(_start < cpS.getHeaderStoryEnd()) { + fib.setCcpHdd(fib.getCcpHdd() + adjustment); + } + if(_start < cpS.getHeaderTextboxEnd()) { + fib.setCcpHdrTxtBx(fib.getCcpHdrTxtBx() + adjustment); + } + if(_start < cpS.getMainTextboxEnd()) { + fib.setCcpTxtBx(fib.getCcpTxtBx() + adjustment); + } } /** diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFRangeParts.java b/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFRangeParts.java new file mode 100644 index 0000000000..af0faf96c9 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFRangeParts.java @@ -0,0 +1,253 @@ + +/* ==================================================================== + 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.hwpf; + +import java.io.FileInputStream; + +import org.apache.poi.hwpf.usermodel.Range; + +import junit.framework.TestCase; + +/** + * Test that we pull out the right bits of a file into + * the different ranges + */ +public class TestHWPFRangeParts extends TestCase { + private static final char page_break = (char)12; + private static final String headerDef = + "\u0003\r\r" + + "\u0004\r\r" + + "\u0003\r\r" + + "\u0004\r\r" + ; + private static final String footerDef = "\r"; + private static final String endHeaderFooter = "\r\r"; + + + private static final String a_page_1 = + "This is a sample word document. It has two pages. It has a three column heading, and a three column footer\r" + + "\r" + + "HEADING TEXT\r" + + "\r" + + "More on page one\r" + + "\r\r" + + "End of page 1\r" + ; + private static final String a_page_2 = + "This is page two. It also has a three column heading, and a three column footer.\r" + ; + + private static final String a_header = + "First header column!\tMid header Right header!\r" + ; + private static final String a_footer = + "Footer Left\tFooter Middle Footer Right\r" + ; + + + private static final String u_page_1 = + "This is a fairly simple word document, over two pages, with headers and footers.\r" + + "The trick with this one is that it contains some Unicode based strings in it.\r" + + "Firstly, some currency symbols:\r" + + "\tGBP - \u00a3\r" + + "\tEUR - \u20ac\r" + + "Now, we\u2019ll have some French text, in bold and big:\r" + + "\tMoli\u00e8re\r" + + "And some normal French text:\r" + + "\tL'Avare ou l'\u00c9cole du mensonge\r" + + "That\u2019s it for page one\r" + ; + private static final String u_page_2 = + "This is page two. Les Pr\u00e9cieuses ridicules. The end.\r" + ; + + private static final String u_header = + "\r\r" + + "This is a simple header, with a \u20ac euro symbol in it.\r" + ; + private static final String u_footer = + "\r\r\r" + + "The footer, with Moli\u00e8re, has Unicode in it.\r" + + "\r\r\r\r" + ; + + /** + * A document made up only of basic ASCII text + */ + private HWPFDocument docAscii; + /** + * A document with some unicode in it too + */ + private HWPFDocument docUnicode; + + public void setUp() throws Exception { + String dirname = System.getProperty("HWPF.testdata.path"); + + String filename = dirname + "/HeaderFooterUnicode.doc"; + docUnicode = new HWPFDocument( + new FileInputStream(filename) + ); + + filename = dirname + "/ThreeColHeadFoot.doc"; + docAscii = new HWPFDocument( + new FileInputStream(filename) + ); + } + + public void testBasics() throws Exception { + // First check the start and end bits + assertEquals( + 0, + docAscii._cpSplit.getMainDocumentStart() + ); + assertEquals( + a_page_1.length() + + 2 + // page break + a_page_2.length(), + docAscii._cpSplit.getMainDocumentEnd() + ); + + assertEquals( + 238, + docAscii._cpSplit.getFootnoteStart() + ); + assertEquals( + 238, + docAscii._cpSplit.getFootnoteEnd() + ); + + assertEquals( + 238, + docAscii._cpSplit.getHeaderStoryStart() + ); + assertEquals( + 238 + headerDef.length() + a_header.length() + + footerDef.length() + a_footer.length() + endHeaderFooter.length(), + docAscii._cpSplit.getHeaderStoryEnd() + ); + } + + public void testContents() throws Exception { + Range r; + + // Now check the real ranges + r = docAscii.getRange(); + assertEquals( + a_page_1 + + page_break + "\r" + + a_page_2, + r.text() + ); + + r = docAscii.getHeaderStoryRange(); + assertEquals( + headerDef + + a_header + + footerDef + + a_footer + + endHeaderFooter, + r.text() + ); + + r = docAscii.getOverallRange(); + assertEquals( + a_page_1 + + page_break + "\r" + + a_page_2 + + headerDef + + a_header + + footerDef + + a_footer + + endHeaderFooter + + "\r", + r.text() + ); + } + + public void testBasicsUnicode() throws Exception { + // First check the start and end bits + assertEquals( + 0, + docUnicode._cpSplit.getMainDocumentStart() + ); + assertEquals( + u_page_1.length() + + 2 + // page break + u_page_2.length(), + docUnicode._cpSplit.getMainDocumentEnd() + ); + + assertEquals( + 408, + docUnicode._cpSplit.getFootnoteStart() + ); + assertEquals( + 408, + docUnicode._cpSplit.getFootnoteEnd() + ); + + assertEquals( + 408, + docUnicode._cpSplit.getHeaderStoryStart() + ); + // TODO - fix this one + assertEquals( + 408 + headerDef.length() + u_header.length() + + footerDef.length() + u_footer.length() + endHeaderFooter.length(), + docUnicode._cpSplit.getHeaderStoryEnd() + ); + } + + public void testContentsUnicode() throws Exception { + Range r; + + // Now check the real ranges + r = docUnicode.getRange(); + assertEquals( + u_page_1 + + page_break + "\r" + + u_page_2, + r.text() + ); + + r = docUnicode.getHeaderStoryRange(); + assertEquals( + headerDef + + u_header + + footerDef + + u_footer + + endHeaderFooter, + r.text() + ); + + r = docUnicode.getOverallRange(); + assertEquals( + u_page_1 + + page_break + "\r" + + u_page_2 + + headerDef + + u_header + + footerDef + + u_footer + + endHeaderFooter + + "\r", + r.text() + ); + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/HeaderFooterUnicode.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/HeaderFooterUnicode.doc new file mode 100755 index 0000000000000000000000000000000000000000..1b517f6a2e08e4584351708a950ea1234bed7b50 GIT binary patch literal 28672 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 literal 0 HcmV?d00001 diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/HeaderFooterUnicode.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/HeaderFooterUnicode.docx new file mode 100755 index 0000000000000000000000000000000000000000..643967c5e5cbbeee83aac70db610cbe0d93c0b75 GIT binary patch literal 15079 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 literal 0 HcmV?d00001 diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestDifferentRoutes.java b/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestDifferentRoutes.java index ae8c8d6b26..786fc807db 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestDifferentRoutes.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestDifferentRoutes.java @@ -87,7 +87,7 @@ public class TestDifferentRoutes extends TestCase { TextPiece piece = (TextPiece) textPieces.next(); String encoding = "Cp1252"; - if (piece.usesUnicode()) { + if (piece.isUnicode()) { encoding = "UTF-16LE"; } String text = new String(piece.getRawBytes(), encoding); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java b/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java index 06dae46dff..704b4d4dd2 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java @@ -55,6 +55,11 @@ public class TestWordExtractor extends TestCase { // A word doc embeded in an excel file private String filename3; + // With header and footer + private String filename4; + // With unicode header and footer + private String filename5; + protected void setUp() throws Exception { String dirname = System.getProperty("HWPF.testdata.path"); String pdirname = System.getProperty("POIFS.testdata.path"); @@ -62,6 +67,9 @@ public class TestWordExtractor extends TestCase { String filename = dirname + "/test2.doc"; String filename2 = dirname + "/test.doc"; filename3 = pdirname + "/excel_with_embeded.xls"; + filename4 = dirname + "/ThreeColHeadFoot.doc"; + filename5 = dirname + "/HeaderFooterUnicode.doc"; + extractor = new WordExtractor(new FileInputStream(filename)); extractor2 = new WordExtractor(new FileInputStream(filename2)); @@ -149,4 +157,72 @@ public class TestWordExtractor extends TestCase { assertEquals("Sample Doc 2", extractor3.getSummaryInformation().getTitle()); assertEquals("Another Sample Test", extractor3.getSummaryInformation().getSubject()); } + + public void testWithHeader() throws Exception { + // Non-unicode + HWPFDocument doc = new HWPFDocument( + new FileInputStream(filename4) + ); + extractor = new WordExtractor(doc); + + assertEquals( + "First header column!\tMid header Right header!\n", + extractor.getHeaderText() + ); + + String text = extractor.getText(); + assertTrue( + text.indexOf("First header column!") > -1 + ); + + + // Unicode + doc = new HWPFDocument( + new FileInputStream(filename5) + ); + extractor = new WordExtractor(doc); + + assertEquals( + "\n\nThis is a simple header, with a \u20ac euro symbol in it.\n\n", + extractor.getHeaderText() + ); + text = extractor.getText(); + assertTrue( + text.indexOf("This is a simple header") > -1 + ); + } + + public void testWithFooter() throws Exception { + // Non-unicode + HWPFDocument doc = new HWPFDocument( + new FileInputStream(filename4) + ); + extractor = new WordExtractor(doc); + + assertEquals( + "Footer Left\tFooter Middle Footer Right\n", + extractor.getFooterText() + ); + + String text = extractor.getText(); + assertTrue( + text.indexOf("Footer Left") > -1 + ); + + + // Unicode + doc = new HWPFDocument( + new FileInputStream(filename5) + ); + extractor = new WordExtractor(doc); + + assertEquals( + "\n\nThe footer, with Moli\u00e8re, has Unicode in it.\n", + extractor.getFooterText() + ); + text = extractor.getText(); + assertTrue( + text.indexOf("The footer, with") > -1 + ); + } } diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestTextPieceTable.java b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestTextPieceTable.java index 30e9ee138f..4595c4ce0e 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestTextPieceTable.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestTextPieceTable.java @@ -18,19 +18,21 @@ package org.apache.poi.hwpf.model; -import junit.framework.*; - +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.util.ArrayList; +import java.io.File; +import java.io.FileInputStream; + +import junit.framework.TestCase; -import org.apache.poi.hwpf.*; -import org.apache.poi.hwpf.model.io.*; +import org.apache.poi.hwpf.HWPFDocFixture; +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.io.HWPFFileSystem; -public class TestTextPieceTable - extends TestCase -{ +public class TestTextPieceTable extends TestCase { private HWPFDocFixture _hWPFDocFixture; + private String dirname; public TestTextPieceTable(String name) { @@ -63,9 +65,117 @@ public class TestTextPieceTable TextPieceTable newTextPieceTable = newCft.getTextPieceTable(); assertEquals(oldTextPieceTable, newTextPieceTable); - - } + + /** + * Check that we do the positions correctly when + * working with pure-ascii + */ + public void testAsciiParts() throws Exception { + HWPFDocument doc = new HWPFDocument( + new FileInputStream(new File(dirname, "ThreeColHeadFoot.doc")) + ); + TextPieceTable tbl = doc.getTextTable(); + + // All ascii, so stored in one big lump + assertEquals(1, tbl.getTextPieces().size()); + TextPiece tp = (TextPiece)tbl.getTextPieces().get(0); + + assertEquals(0, tp.getStart()); + assertEquals(339, tp.getEnd()); + assertEquals(339, tp.characterLength()); + assertEquals(339, tp.bytesLength()); + assertTrue(tp.getStringBuffer().toString().startsWith("This is a sample word document")); + + + // Save and re-load + HWPFDocument docB = saveAndReload(doc); + tbl = docB.getTextTable(); + + assertEquals(1, tbl.getTextPieces().size()); + tp = (TextPiece)tbl.getTextPieces().get(0); + + assertEquals(0, tp.getStart()); + assertEquals(339, tp.getEnd()); + assertEquals(339, tp.characterLength()); + assertEquals(339, tp.bytesLength()); + assertTrue(tp.getStringBuffer().toString().startsWith("This is a sample word document")); + } + + /** + * Check that we do the positions correctly when + * working with a mix ascii, unicode file + */ + public void testUnicodeParts() throws Exception { + HWPFDocument doc = new HWPFDocument( + new FileInputStream(new File(dirname, "HeaderFooterUnicode.doc")) + ); + TextPieceTable tbl = doc.getTextTable(); + + // In three bits, split every 512 bytes + assertEquals(3, tbl.getTextPieces().size()); + TextPiece tpA = (TextPiece)tbl.getTextPieces().get(0); + TextPiece tpB = (TextPiece)tbl.getTextPieces().get(1); + TextPiece tpC = (TextPiece)tbl.getTextPieces().get(2); + + assertTrue(tpA.isUnicode()); + assertTrue(tpB.isUnicode()); + assertTrue(tpC.isUnicode()); + + assertEquals(256, tpA.characterLength()); + assertEquals(256, tpB.characterLength()); + assertEquals(19, tpC.characterLength()); + + assertEquals(512, tpA.bytesLength()); + assertEquals(512, tpB.bytesLength()); + assertEquals(38, tpC.bytesLength()); + + assertEquals(0, tpA.getStart()); + assertEquals(256, tpA.getEnd()); + assertEquals(256, tpB.getStart()); + assertEquals(512, tpB.getEnd()); + assertEquals(512, tpC.getStart()); + assertEquals(531, tpC.getEnd()); + + + // Save and re-load + HWPFDocument docB = saveAndReload(doc); + tbl = docB.getTextTable(); + + assertEquals(3, tbl.getTextPieces().size()); + tpA = (TextPiece)tbl.getTextPieces().get(0); + tpB = (TextPiece)tbl.getTextPieces().get(1); + tpC = (TextPiece)tbl.getTextPieces().get(2); + + assertTrue(tpA.isUnicode()); + assertTrue(tpB.isUnicode()); + assertTrue(tpC.isUnicode()); + + assertEquals(256, tpA.characterLength()); + assertEquals(256, tpB.characterLength()); + assertEquals(19, tpC.characterLength()); + + assertEquals(512, tpA.bytesLength()); + assertEquals(512, tpB.bytesLength()); + assertEquals(38, tpC.bytesLength()); + + assertEquals(0, tpA.getStart()); + assertEquals(256, tpA.getEnd()); + assertEquals(256, tpB.getStart()); + assertEquals(512, tpB.getEnd()); + assertEquals(512, tpC.getStart()); + assertEquals(531, tpC.getEnd()); + } + + protected HWPFDocument saveAndReload(HWPFDocument doc) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + doc.write(baos); + + return new HWPFDocument( + new ByteArrayInputStream(baos.toByteArray()) + ); + } + protected void setUp() throws Exception { @@ -73,6 +183,8 @@ public class TestTextPieceTable _hWPFDocFixture = new HWPFDocFixture(this); _hWPFDocFixture.setUp(); + + dirname = System.getProperty("HWPF.testdata.path"); } protected void tearDown() diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java new file mode 100644 index 0000000000..d4d2517f90 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java @@ -0,0 +1,189 @@ +/* ==================================================================== + 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.hwpf.usermodel; + +import java.io.File; +import java.io.FileInputStream; + +import junit.framework.TestCase; + +import org.apache.poi.hwpf.HWPFDocument; + +/** + * Tests for the handling of header stories into + * headers, footers etc + */ +public class TestHeaderStories extends TestCase { + private HWPFDocument none; + private HWPFDocument header; + private HWPFDocument footer; + private HWPFDocument headerFooter; + private HWPFDocument oddEven; + private HWPFDocument diffFirst; + private HWPFDocument unicode; + + protected void setUp() throws Exception { + String dirname = System.getProperty("HWPF.testdata.path"); + + none = new HWPFDocument( + new FileInputStream(new File(dirname, "NoHeadFoot.doc")) + ); + header = new HWPFDocument( + new FileInputStream(new File(dirname, "ThreeColHead.doc")) + ); + footer = new HWPFDocument( + new FileInputStream(new File(dirname, "ThreeColFoot.doc")) + ); + headerFooter = new HWPFDocument( + new FileInputStream(new File(dirname, "SimpleHeadThreeColFoot.doc")) + ); + oddEven = new HWPFDocument( + new FileInputStream(new File(dirname, "PageSpecificHeadFoot.doc")) + ); + diffFirst = new HWPFDocument( + new FileInputStream(new File(dirname, "DiffFirstPageHeadFoot.doc")) + ); + unicode = new HWPFDocument( + new FileInputStream(new File(dirname, "HeaderFooterUnicode.doc")) + ); + } + + public void testNone() throws Exception { + HeaderStories hs = new HeaderStories(none); + + assertNull(hs.getPlcfHdd()); + assertEquals(0, hs.getRange().text().length()); + } + + public void testHeader() throws Exception { + HeaderStories hs = new HeaderStories(header); + + assertEquals(60, hs.getRange().text().length()); + + // Should have the usual 6 separaters + // Then all 6 of the different header/footer kinds + // Finally a terminater + assertEquals(13, hs.getPlcfHdd().length()); + + assertEquals(215, hs.getRange().getStartOffset()); + + assertEquals(0, hs.getPlcfHdd().getProperty(0).getStart()); + assertEquals(3, hs.getPlcfHdd().getProperty(1).getStart()); + assertEquals(6, hs.getPlcfHdd().getProperty(2).getStart()); + assertEquals(6, hs.getPlcfHdd().getProperty(3).getStart()); + assertEquals(9, hs.getPlcfHdd().getProperty(4).getStart()); + assertEquals(12, hs.getPlcfHdd().getProperty(5).getStart()); + + assertEquals(12, hs.getPlcfHdd().getProperty(6).getStart()); + assertEquals(12, hs.getPlcfHdd().getProperty(7).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(8).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(9).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(10).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(11).getStart()); + + assertEquals(59, hs.getPlcfHdd().getProperty(12).getStart()); + + assertEquals("\u0003\r\r", hs.getFootnoteSeparator()); + assertEquals("\u0004\r\r", hs.getFootnoteContSeparator()); + assertEquals("", hs.getFootnoteContNote()); + assertEquals("\u0003\r\r", hs.getEndnoteSeparator()); + assertEquals("\u0004\r\r", hs.getEndnoteContSeparator()); + assertEquals("", hs.getEndnoteContNote()); + + assertEquals("", hs.getFirstHeader()); + assertEquals("", hs.getEvenHeader()); + assertEquals("First header column!\tMid header Right header!\r\r", hs.getOddHeader()); + + + assertEquals("", hs.getFirstFooter()); + assertEquals("", hs.getEvenFooter()); + assertEquals("", hs.getOddFooter()); + } + + public void testFooter() throws Exception { + HeaderStories hs = new HeaderStories(footer); + + assertEquals("", hs.getFirstHeader()); + assertEquals("", hs.getEvenHeader()); + assertEquals("\r\r", hs.getOddHeader()); + + + assertEquals("", hs.getFirstFooter()); + assertEquals("", hs.getEvenFooter()); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getOddFooter()); + } + + public void testHeaderFooter() throws Exception { + HeaderStories hs = new HeaderStories(headerFooter); + + assertEquals("", hs.getFirstHeader()); + assertEquals("", hs.getEvenHeader()); + assertEquals("I am some simple header text here\r\r\r", hs.getOddHeader()); + + + assertEquals("", hs.getFirstFooter()); + assertEquals("", hs.getEvenFooter()); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getOddFooter()); + } + + public void testOddEven() throws Exception { + HeaderStories hs = new HeaderStories(oddEven); + + assertEquals("", hs.getFirstHeader()); + assertEquals("[This is an Even Page, with a Header]\u0007August 20, 2008\u0007\u0007\r\r", hs.getEvenHeader()); + assertEquals("August 20, 2008\u0007[ODD Page Header text]\u0007\u0007\r\r", hs.getOddHeader()); + + + assertEquals("", hs.getFirstFooter()); + assertEquals("\u0007Page \u0013 PAGE \\* MERGEFORMAT \u00142\u0015\u0007\u0007\u0007\u0007\u0007\u0007\u0007This is a simple footer on the second page\r\r", hs.getEvenFooter()); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getOddFooter()); + + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getFooter(1)); + assertEquals("\u0007Page \u0013 PAGE \\* MERGEFORMAT \u00142\u0015\u0007\u0007\u0007\u0007\u0007\u0007\u0007This is a simple footer on the second page\r\r", hs.getFooter(2)); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getFooter(3)); + } + + public void testFirst() throws Exception { + HeaderStories hs = new HeaderStories(diffFirst); + + assertEquals("I am the header on the first page, and I\u2019m nice and simple\r\r", hs.getFirstHeader()); + assertEquals("", hs.getEvenHeader()); + assertEquals("First header column!\tMid header Right header!\r\r", hs.getOddHeader()); + + + assertEquals("The footer of the first page\r\r", hs.getFirstFooter()); + assertEquals("", hs.getEvenFooter()); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getOddFooter()); + + assertEquals("The footer of the first page\r\r", hs.getFooter(1)); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getFooter(2)); + assertEquals("Footer Left\tFooter Middle Footer Right\r\r", hs.getFooter(3)); + } + + public void testUnicode() throws Exception { + HeaderStories hs = new HeaderStories(unicode); + + assertEquals("\r\r", hs.getFirstHeader()); + assertEquals("\r\r", 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("The footer, with Moli\u00e8re, has Unicode in it.\r\r", hs.getOddFooter()); + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java index 1becc234c3..2994b6332d 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java @@ -31,8 +31,10 @@ import junit.framework.TestCase; /** * Test to see if Range.delete() works even if the Range contains a * CharacterRun that uses Unicode characters. + * + * TODO - re-enable me when unicode paragraph stuff is fixed! */ -public class TestRangeDelete extends TestCase { +public abstract class TestRangeDelete extends TestCase { // u201c and u201d are "smart-quotes" private String originalText = @@ -67,7 +69,7 @@ public class TestRangeDelete extends TestCase { HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); - Range range = daDoc.getRange(); + Range range = daDoc.getOverallRange(); assertEquals(1, range.numSections()); Section section = range.getSection(0); @@ -78,6 +80,20 @@ public class TestRangeDelete extends TestCase { assertEquals(5, para.numCharacterRuns()); assertEquals(originalText, para.text()); + + + // Now check on just the main text + range = daDoc.getRange(); + + assertEquals(1, range.numSections()); + section = range.getSection(0); + + assertEquals(5, section.numParagraphs()); + para = section.getParagraph(2); + + assertEquals(5, para.numCharacterRuns()); + + assertEquals(originalText, para.text()); } /** @@ -87,7 +103,7 @@ public class TestRangeDelete extends TestCase { HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); - Range range = daDoc.getRange(); + Range range = daDoc.getOverallRange(); assertEquals(1, range.numSections()); Section section = range.getSection(0); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java index 0ac3ff0aa9..5f21508c9a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java @@ -31,8 +31,10 @@ import junit.framework.TestCase; /** * Test to see if Range.insertBefore() works even if the Range contains a * CharacterRun that uses Unicode characters. + * + * TODO - re-enable me when unicode paragraph stuff is fixed! */ -public class TestRangeInsertion extends TestCase { +public abstract class TestRangeInsertion extends TestCase { // u201c and u201d are "smart-quotes" private String originalText = diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java new file mode 100644 index 0000000000..1f0aad5aa5 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java @@ -0,0 +1,169 @@ +/* ==================================================================== + 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.hwpf.usermodel; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.poi.hwpf.HWPFDocument; + +import junit.framework.TestCase; + +/** + * Tests to ensure that our ranges end up with + * the right text in them, and the right font/styling + * properties applied to them. + * + * TODO - re-enable me when unicode paragraph stuff is fixed! + */ +public abstract class TestRangeProperties extends TestCase { + private static final char page_break = (char)12; + + private static final String u_page_1 = + "This is a fairly simple word document, over two pages, with headers and footers.\r" + + "The trick with this one is that it contains some Unicode based strings in it.\r" + + "Firstly, some currency symbols:\r" + + "\tGBP - \u00a3\r" + + "\tEUR - \u20ac\r" + + "Now, we\u2019ll have some French text, in bold and big:\r" + + "\tMoli\u00e8re\r" + + "And some normal French text:\r" + + "\tL'Avare ou l'\u00c9cole du mensonge\r" + + "That\u2019s it for page one\r" + ; + private static final String u_page_2 = + "This is page two. Les Pr\u00e9cieuses ridicules. The end.\r" + ; + + private static final String a_page_1 = + "I am a test document\r" + + "This is page 1\r" + + "I am Calibri (Body) in font size 11\r" + ; + private static final String a_page_2 = + "This is page two\r" + + "It\u2019s Arial Black in 16 point\r" + + "It\u2019s also in blue\r" + ; + + private HWPFDocument u; + private HWPFDocument a; + + private String dirname; + + protected void setUp() throws Exception { + dirname = System.getProperty("HWPF.testdata.path"); + u = new HWPFDocument( + new FileInputStream(new File(dirname, "HeaderFooterUnicode.doc")) + ); + a = new HWPFDocument( + new FileInputStream(new File(dirname, "SampleDoc.doc")) + ); + } + + + public void testAsciiTextParagraphs() throws Exception { + Range r = a.getRange(); + assertEquals( + a_page_1 + + page_break + "\r" + + a_page_2, + r.text() + ); + + assertEquals( + 7, + r.numParagraphs() + ); + String[] p1_parts = a_page_1.split("\r"); + String[] p2_parts = a_page_2.split("\r"); + + // Check paragraph contents + assertEquals( + p1_parts[0] + "\r", + r.getParagraph(0).text() + ); + assertEquals( + p1_parts[1] + "\r", + r.getParagraph(1).text() + ); + assertEquals( + p1_parts[2] + "\r", + r.getParagraph(2).text() + ); + + assertEquals( + page_break + "\r", + r.getParagraph(3).text() + ); + + assertEquals( + p2_parts[0] + "\r", + r.getParagraph(4).text() + ); + assertEquals( + p2_parts[1] + "\r", + r.getParagraph(5).text() + ); + assertEquals( + p2_parts[2] + "\r", + r.getParagraph(6).text() + ); + } + + public void testAsciiStyling() throws Exception { + Range r = a.getRange(); + + Paragraph p1 = r.getParagraph(0); + Paragraph p7 = r.getParagraph(6); + + assertEquals(1, p1.numCharacterRuns()); + assertEquals(1, p7.numCharacterRuns()); + + CharacterRun c1 = p1.getCharacterRun(0); + CharacterRun c7 = p7.getCharacterRun(0); + + assertEquals("Times New Roman", c1.getFontName()); // No Calibri + assertEquals("Arial Black", c7.getFontName()); + assertEquals(22, c1.getFontSize()); + assertEquals(32, c7.getFontSize()); + } + + + public void testUnicodeTextParagraphs() throws Exception { + Range r = u.getRange(); + assertEquals( + u_page_1 + + page_break + "\r" + + u_page_2, + r.text() + ); + + assertEquals( + 5, + r.numParagraphs() + ); + String[] p1_parts = u_page_1.split("\r"); + String[] p2_parts = u_page_2.split("\r"); + + System.out.println(r.getParagraph(2).text()); + // TODO + } + public void testUnicodeStyling() throws Exception { + // TODO + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java index bda615e943..67aea65be9 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java @@ -31,8 +31,10 @@ import junit.framework.TestCase; /** * Test to see if Range.replaceText() works even if the Range contains a * CharacterRun that uses Unicode characters. + * + * TODO - re-enable me when unicode paragraph stuff is fixed! */ -public class TestRangeReplacement extends TestCase { +public abstract class TestRangeReplacement extends TestCase { // u201c and u201d are "smart-quotes" private String originalText = diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java index b200515ff9..d89ffee3eb 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java @@ -38,42 +38,34 @@ import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; */ public final class TestFormulaParserEval extends TestCase { - public void testWithNamedRange() throws Exception { + public void testWithNamedRange() { HSSFWorkbook workbook = new HSSFWorkbook(); - FormulaParser fp; Ptg[] ptgs; HSSFSheet s = workbook.createSheet("Foo"); - s.createRow(0).createCell((short)0).setCellValue(1.1); - s.createRow(1).createCell((short)0).setCellValue(2.3); - s.createRow(2).createCell((short)2).setCellValue(3.1); + s.createRow(0).createCell(0).setCellValue(1.1); + s.createRow(1).createCell(0).setCellValue(2.3); + s.createRow(2).createCell(2).setCellValue(3.1); HSSFName name = workbook.createName(); name.setNameName("testName"); name.setReference("A1:A2"); - fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, "SUM(testName)"); - fp.parse(); - ptgs = fp.getRPNPtg(); + ptgs = FormulaParser.parse("SUM(testName)", workbook); assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2); assertEquals(NamePtg.class, ptgs[0].getClass()); assertEquals(FuncVarPtg.class, ptgs[1].getClass()); // Now make it a single cell name.setReference("C3"); - - fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, "SUM(testName)"); - fp.parse(); - ptgs = fp.getRPNPtg(); + ptgs = FormulaParser.parse("SUM(testName)", workbook); assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2); assertEquals(NamePtg.class, ptgs[0].getClass()); assertEquals(FuncVarPtg.class, ptgs[1].getClass()); // And make it non-contiguous name.setReference("A1:A2,C3"); - fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, "SUM(testName)"); - fp.parse(); - ptgs = fp.getRPNPtg(); + ptgs = FormulaParser.parse("SUM(testName)", workbook); assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2); assertEquals(NamePtg.class, ptgs[0].getClass()); assertEquals(FuncVarPtg.class, ptgs[1].getClass()); @@ -86,15 +78,14 @@ public final class TestFormulaParserEval extends TestCase { wb.setSheetName(0, "Sheet1"); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short)0); + HSSFCell cell = row.createCell(0); cell.setCellFormula("SUM(A32769:A32770)"); // put some values in the cells to make the evaluation more interesting - sheet.createRow(32768).createCell((short)0).setCellValue(31); - sheet.createRow(32769).createCell((short)0).setCellValue(11); + sheet.createRow(32768).createCell(0).setCellValue(31); + sheet.createRow(32769).createCell(0).setCellValue(11); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); - fe.setCurrentRow(row); CellValue result; try { result = fe.evaluate(cell); diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java index 97ddfdf220..ee20479872 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java @@ -35,10 +35,9 @@ public final class TestCircularReferences extends TestCase { /** * Translates StackOverflowError into AssertionFailedError */ - private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFSheet sheet, HSSFRow row, HSSFCell testCell) + private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFSheet sheet, HSSFCell testCell) throws AssertionFailedError { HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); - evaluator.setCurrentRow(row); try { return evaluator.evaluate(testCell); } catch (StackOverflowError e) { @@ -63,12 +62,12 @@ public final class TestCircularReferences extends TestCase { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet("Sheet1"); - short colB = 1; + int colB = 1; sheet.createRow(0).createCell(colB).setCellValue(1); sheet.createRow(1).createCell(colB).setCellValue(2); sheet.createRow(2).createCell(colB).setCellValue(3); HSSFRow row4 = sheet.createRow(3); - HSSFCell testCell = row4.createCell((short)0); + HSSFCell testCell = row4.createCell(0); // This formula should evaluate to the contents of B2, testCell.setCellFormula("INDEX(A1:B4,2,2)"); // However the range A1:B4 also includes the current cell A4. If the other parameters @@ -76,7 +75,7 @@ public final class TestCircularReferences extends TestCase { // arguments before invoking operators, POI must handle such potential cycles gracefully. - CellValue cellValue = evaluateWithCycles(wb, sheet, row4, testCell); + CellValue cellValue = evaluateWithCycles(wb, sheet, testCell); assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_NUMERIC); assertEquals(2, cellValue.getNumberValue(), 0); @@ -91,12 +90,11 @@ public final class TestCircularReferences extends TestCase { HSSFSheet sheet = wb.createSheet("Sheet1"); HSSFRow row = sheet.createRow(0); - HSSFCell testCell = row.createCell((short)0); + HSSFCell testCell = row.createCell(0); testCell.setCellFormula("A1"); HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); - evaluator.setCurrentRow(row); - CellValue cellValue = evaluateWithCycles(wb, sheet, row, testCell); + CellValue cellValue = evaluateWithCycles(wb, sheet, testCell); confirmCycleErrorCode(cellValue); } @@ -110,15 +108,14 @@ public final class TestCircularReferences extends TestCase { HSSFSheet sheet = wb.createSheet("Sheet1"); HSSFRow row = sheet.createRow(0); - row.createCell((short)0).setCellFormula("B1"); - row.createCell((short)1).setCellFormula("C1"); - row.createCell((short)2).setCellFormula("D1"); - HSSFCell testCell = row.createCell((short)3); + row.createCell(0).setCellFormula("B1"); + row.createCell(1).setCellFormula("C1"); + row.createCell(2).setCellFormula("D1"); + HSSFCell testCell = row.createCell(3); testCell.setCellFormula("A1"); HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); - evaluator.setCurrentRow(row); - CellValue cellValue = evaluateWithCycles(wb, sheet, row, testCell); + CellValue cellValue = evaluateWithCycles(wb, sheet, testCell); confirmCycleErrorCode(cellValue); } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java index 647b6330f2..9e6c7bce6a 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java @@ -40,7 +40,7 @@ public final class TestExternalFunction extends TestCase { HSSFSheet sheet = wb.createSheet(); wb.setSheetName(0, "Sheet1"); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short)0); + HSSFCell cell = row.createCell(0); HSSFName hssfName = wb.createName(); hssfName.setNameName("myFunc"); @@ -50,7 +50,6 @@ public final class TestExternalFunction extends TestCase { assertEquals("myFunc()", actualFormula); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); - fe.setCurrentRow(row); CellValue evalResult = fe.evaluate(cell); // Check the return value from ExternalFunction.evaluate() diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java index a614d6f193..da110a020c 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java @@ -67,7 +67,6 @@ public final class TestFormulaBugs extends TestCase { // We might as well evaluate the formula HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); - fe.setCurrentRow(row); CellValue cv = fe.evaluate(cell); assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); @@ -84,20 +83,20 @@ public final class TestFormulaBugs extends TestCase { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet("input"); // input row 0 - HSSFRow row = sheet.createRow((short) 0); - HSSFCell cell = row.createCell((short) 0); - cell = row.createCell((short) 1); + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell(0); + cell = row.createCell(1); cell.setCellValue(1); // B1 // input row 1 - row = sheet.createRow((short) 1); - cell = row.createCell((short) 1); + row = sheet.createRow(1); + cell = row.createCell(1); cell.setCellValue(999); // B2 int rno = 4; row = sheet.createRow(rno); - cell = row.createCell((short) 1); // B5 + cell = row.createCell(1); // B5 cell.setCellFormula("isnumber(b1)"); - cell = row.createCell((short) 3); // D5 + cell = row.createCell(3); // D5 cell.setCellFormula("IF(ISNUMBER(b1),b1,b2)"); if (false) { // set true to check excel file manually @@ -113,7 +112,6 @@ public final class TestFormulaBugs extends TestCase { // use POI's evaluator as an extra sanity check HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); - fe.setCurrentRow(row); CellValue cv; cv = fe.evaluate(cell); assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); @@ -132,7 +130,7 @@ public final class TestFormulaBugs extends TestCase { HSSFSheet sheet1 = wb.createSheet("Sheet1"); HSSFRow row = sheet1.createRow(0); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); // it's important to create the referenced sheet first HSSFSheet sheet2 = wb.createSheet("A"); // note name 'A' @@ -165,7 +163,6 @@ public final class TestFormulaBugs extends TestCase { double expectedResult = (4.0 * 8.0 + 5.0 * 9.0) / 10.0; HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet1, wb); - fe.setCurrentRow(row); CellValue cv = fe.evaluate(cell); assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); @@ -174,6 +171,6 @@ public final class TestFormulaBugs extends TestCase { private static void addCell(HSSFSheet sheet, int rowIx, int colIx, double value) { - sheet.createRow(rowIx).createCell((short) colIx).setCellValue(value); + sheet.createRow(rowIx).createCell(colIx).setCellValue(value); } } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java index 546d16d057..ffe4bffc0a 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java @@ -1,19 +1,19 @@ -/* -* 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. -*/ +/* ==================================================================== + 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.formula.eval; @@ -70,7 +70,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase { /** * Index of the column that contains the function names */ - public static final short COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B' + public static final int COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B' /** * Used to indicate when there are no more functions left @@ -97,7 +97,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase { private int _evaluationFailureCount; private int _evaluationSuccessCount; - private static final Cell getExpectedValueCell(Row row, short columnIndex) { + private static final Cell getExpectedValueCell(Row row, int columnIndex) { if (row == null) { return null; } @@ -239,10 +239,9 @@ public final class TestFormulasFromSpreadsheet extends TestCase { int result = Result.NO_EVALUATIONS_FOUND; // so far short endcolnum = formulasRow.getLastCellNum(); - evaluator.setCurrentRow(formulasRow); // iterate across the row for all the evaluation cases - for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) { + for (int colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) { Cell c = formulasRow.getCell(colnum); if (c == null || c.getCellType() != Cell.CELL_TYPE_FORMULA) { continue; @@ -298,7 +297,6 @@ public final class TestFormulasFromSpreadsheet extends TestCase { for(int i=startIx; i0,MATCH(V4:V220,V4:V220,0),\"\"))>0,1))"; cell.setCellFormula(formula); HSSFWorkbook wb_sv = writeOutAndReadBack(wb); - HSSFCell cell_sv = wb_sv.getSheetAt(0).getRow(0).getCell((short)0); + HSSFCell cell_sv = wb_sv.getSheetAt(0).getRow(0).getCell(0); assertEquals(formula, cell_sv.getCellFormula()); } - public void test36947() throws Exception { + public void test36947() { HSSFWorkbook wb = openSample("36947.xls"); assertTrue("no errors reading sample xls", true); writeOutAndReadBack(wb); @@ -948,12 +948,12 @@ public final class TestBugs extends TestCase { */ public void test42448(){ HSSFWorkbook wb = new HSSFWorkbook(); - HSSFCell cell = wb.createSheet().createRow(0).createCell((short)0); + HSSFCell cell = wb.createSheet().createRow(0).createCell(0); cell.setCellFormula("SUMPRODUCT(A!C7:A!C67, B8:B68) / B69"); assertTrue("no errors parsing formula", true); } - public void test39634() throws Exception { + public void test39634() { HSSFWorkbook wb = openSample("39634.xls"); assertTrue("no errors reading sample xls", true); writeOutAndReadBack(wb); @@ -965,7 +965,7 @@ public final class TestBugs extends TestCase { * HSSFObjectData * @throws Exception */ - public void test44840() throws Exception { + public void test44840() { HSSFWorkbook wb = openSample("WithCheckBoxes.xls"); // Take a look at the embeded objects @@ -993,7 +993,11 @@ public final class TestBugs extends TestCase { try { obj.getDirectory(); fail(); - } catch(FileNotFoundException e) {} + } catch(FileNotFoundException e) { + // expectd during successful test + } catch (IOException e) { + throw new RuntimeException(e); + } } /** @@ -1002,7 +1006,7 @@ public final class TestBugs extends TestCase { * used for printing stuff. * Currently broken, as we change the Ptg */ - public void test30978() throws Exception { + public void test30978() { HSSFWorkbook wb = openSample("30978-alt.xls"); assertEquals(1, wb.getNumberOfNames()); assertEquals(3, wb.getNumberOfSheets()); @@ -1058,15 +1062,15 @@ public final class TestBugs extends TestCase { /** * Test that fonts get added properly */ - public void test45338() throws Exception { + public void test45338() { HSSFWorkbook wb = new HSSFWorkbook(); assertEquals(4, wb.getNumberOfFonts()); HSSFSheet s = wb.createSheet(); s.createRow(0); s.createRow(1); - HSSFCell c1 = s.getRow(0).createCell((short)0); - HSSFCell c2 = s.getRow(1).createCell((short)0); + HSSFCell c1 = s.getRow(0).createCell(0); + HSSFCell c2 = s.getRow(1).createCell(0); assertEquals(4, wb.getNumberOfFonts()); @@ -1142,15 +1146,14 @@ public final class TestBugs extends TestCase { /** * From the mailing list - ensure we can handle a formula * containing a zip code, eg ="70164" - * @throws Exception */ - public void testZipCodeFormulas() throws Exception { + public void testZipCodeFormulas() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); s.createRow(0); - HSSFCell c1 = s.getRow(0).createCell((short)0); - HSSFCell c2 = s.getRow(0).createCell((short)1); - HSSFCell c3 = s.getRow(0).createCell((short)2); + HSSFCell c1 = s.getRow(0).createCell(0); + HSSFCell c2 = s.getRow(0).createCell(1); + HSSFCell c3 = s.getRow(0).createCell(2); // As number and string c1.setCellFormula("70164"); @@ -1178,7 +1181,6 @@ public final class TestBugs extends TestCase { // Now evaluate, they should all be changed HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb); - eval.setCurrentRow(s.getRow(0)); eval.evaluateFormulaCell(c1); eval.evaluateFormulaCell(c2); eval.evaluateFormulaCell(c3); @@ -1196,9 +1198,9 @@ public final class TestBugs extends TestCase { // Write and read HSSFWorkbook nwb = writeOutAndReadBack(wb); HSSFSheet ns = nwb.getSheetAt(0); - HSSFCell nc1 = ns.getRow(0).getCell((short)0); - HSSFCell nc2 = ns.getRow(0).getCell((short)1); - HSSFCell nc3 = ns.getRow(0).getCell((short)2); + HSSFCell nc1 = ns.getRow(0).getCell(0); + HSSFCell nc2 = ns.getRow(0).getCell(1); + HSSFCell nc3 = ns.getRow(0).getCell(2); // Re-check assertEquals(70164.0, nc1.getNumericCellValue(), 0.00001); @@ -1243,7 +1245,7 @@ public final class TestBugs extends TestCase { * For now, blows up with an exception from ExtPtg * Expected ExpPtg to be converted from Shared to Non-Shared... */ - public void DISABLEDtest43623() throws Exception { + public void DISABLEDtest43623() { HSSFWorkbook wb = openSample("43623.xls"); assertEquals(1, wb.getNumberOfSheets()); @@ -1274,7 +1276,7 @@ public final class TestBugs extends TestCase { * People are all getting confused about the last * row and cell number */ - public void test30635() throws Exception { + public void test30635() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); @@ -1303,17 +1305,17 @@ public final class TestBugs extends TestCase { assertEquals(0, r.getPhysicalNumberOfCells()); // Add a cell, things move off -1 - r.createCell((short)0); + r.createCell(0); assertEquals(0, r.getFirstCellNum()); assertEquals(1, r.getLastCellNum()); // last cell # + 1 assertEquals(1, r.getPhysicalNumberOfCells()); - r.createCell((short)1); + r.createCell(1); assertEquals(0, r.getFirstCellNum()); assertEquals(2, r.getLastCellNum()); // last cell # + 1 assertEquals(2, r.getPhysicalNumberOfCells()); - r.createCell((short)4); + r.createCell(4); assertEquals(0, r.getFirstCellNum()); assertEquals(5, r.getLastCellNum()); // last cell # + 1 assertEquals(3, r.getPhysicalNumberOfCells()); @@ -1322,7 +1324,7 @@ public final class TestBugs extends TestCase { /** * Data Tables - ptg 0x2 */ - public void test44958() throws Exception { + public void test44958() { HSSFWorkbook wb = openSample("44958.xls"); HSSFSheet s; HSSFRow r; @@ -1353,7 +1355,7 @@ public final class TestBugs extends TestCase { /** * 45322: HSSFSheet.autoSizeColumn fails when style.getDataFormat() returns -1 */ - public void test45322() throws Exception { + public void test45322() { HSSFWorkbook wb = openSample("44958.xls"); HSSFSheet sh = wb.getSheetAt(0); for(short i=0; i < 30; i++) sh.autoSizeColumn(i); @@ -1363,7 +1365,7 @@ public final class TestBugs extends TestCase { * We used to add too many UncalcRecords to sheets * with diagrams on. Don't any more */ - public void test45414() throws Exception { + public void test45414() { HSSFWorkbook wb = openSample("WithThreeCharts.xls"); wb.getSheetAt(0).setForceFormulaRecalculation(true); wb.getSheetAt(1).setForceFormulaRecalculation(false); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java index 318fcd2bf6..7dbb9c3e16 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java @@ -59,11 +59,11 @@ public final class TestFormulaEvaluatorBugs extends TestCase { HSSFSheet sheet = wb.getSheetAt(0); HSSFRow row = sheet.getRow(0); - row.getCell((short) 0).setCellValue(4.2); - row.getCell((short) 2).setCellValue(25); + row.getCell(0).setCellValue(4.2); + row.getCell(2).setCellValue(25); HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); - assertEquals(4.2 * 25, row.getCell((short) 3).getNumericCellValue(), 0.0001); + assertEquals(4.2 * 25, row.getCell(3).getNumericCellValue(), 0.0001); // Save File existing = new File(tmpDirName, "44636-existing.xls"); @@ -77,14 +77,14 @@ public final class TestFormulaEvaluatorBugs extends TestCase { sheet = wb.createSheet(); row = sheet.createRow(0); - row.createCell((short) 0).setCellValue(1.2); - row.createCell((short) 1).setCellValue(4.2); + row.createCell(0).setCellValue(1.2); + row.createCell(1).setCellValue(4.2); row = sheet.createRow(1); - row.createCell((short) 0).setCellFormula("SUM(A1:B1)"); + row.createCell(0).setCellFormula("SUM(A1:B1)"); HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); - assertEquals(5.4, row.getCell((short) 0).getNumericCellValue(), 0.0001); + assertEquals(5.4, row.getCell(0).getNumericCellValue(), 0.0001); // Save File scratch = new File(tmpDirName, "44636-scratch.xls"); @@ -113,57 +113,48 @@ public final class TestFormulaEvaluatorBugs extends TestCase { HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb); row = sheet.getRow(0); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("31+46", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(77, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(1); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("30+53", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(83, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(2); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("SUM(A1:A2)", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(160, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(4); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("32767+32768", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(65535, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(7); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("32744+42333", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(75077, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(8); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("327680.0/32768", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(10, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(9); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("32767+32769", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(65536, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(10); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("35000+36000", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(71000, eva.evaluate(cell).getNumberValue(), 0); row = sheet.getRow(11); - cell = row.getCell((short) 0); + cell = row.getCell(0); assertEquals("-1000000.0-3000000.0", cell.getCellFormula()); - eva.setCurrentRow(row); assertEquals(-4000000, eva.evaluate(cell).getNumberValue(), 0); } @@ -189,7 +180,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase { HSSFRow rowSUM2D = sheet.getRow(5); // Test the sum - HSSFCell cellSUM = rowSUM.getCell((short) 0); + HSSFCell cellSUM = rowSUM.getCell(0); FormulaRecordAggregate frec = (FormulaRecordAggregate) cellSUM.getCellValueRecord(); List ops = frec.getFormulaRecord().getParsedExpression(); @@ -210,7 +201,6 @@ public final class TestFormulaEvaluatorBugs extends TestCase { // rows it covers as we don't have the sheet // to hand when turning the Ptgs into a string assertEquals("SUM(C:C)", cellSUM.getCellFormula()); - eva.setCurrentRow(rowSUM); // But the evaluator knows the sheet, so it // can do it properly @@ -219,15 +209,13 @@ public final class TestFormulaEvaluatorBugs extends TestCase { // Test the index // Again, the formula string will be right but // lacking row count, evaluated will be right - HSSFCell cellIDX = rowIDX.getCell((short) 0); + HSSFCell cellIDX = rowIDX.getCell(0); assertEquals("INDEX(C:C,2,1)", cellIDX.getCellFormula()); - eva.setCurrentRow(rowIDX); assertEquals(2, eva.evaluate(cellIDX).getNumberValue(), 0); // Across two colums - HSSFCell cellSUM2D = rowSUM2D.getCell((short) 0); + HSSFCell cellSUM2D = rowSUM2D.getCell(0); assertEquals("SUM(C:D)", cellSUM2D.getCellFormula()); - eva.setCurrentRow(rowSUM2D); assertEquals(66, eva.evaluate(cellSUM2D).getNumberValue(), 0); } @@ -239,12 +227,11 @@ public final class TestFormulaEvaluatorBugs extends TestCase { HSSFSheet sheet = wb.createSheet(); wb.setSheetName(0, "Sheet1"); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); cell.setCellFormula("1=1"); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); - fe.setCurrentRow(row); try { fe.evaluateInCell(cell); } catch (NumberFormatException e) { @@ -267,7 +254,6 @@ public final class TestFormulaEvaluatorBugs extends TestCase { for (Iterator rows = s.rowIterator(); rows.hasNext();) { HSSFRow r = (HSSFRow) rows.next(); - eval.setCurrentRow(r); for (Iterator cells = r.cellIterator(); cells.hasNext();) { HSSFCell c = (HSSFCell) cells.next(); @@ -281,10 +267,9 @@ public final class TestFormulaEvaluatorBugs extends TestCase { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet("Sheet1"); HSSFRow row = sheet.createRow(1); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); cell.setCellFormula("na()"); // this formula evaluates to an Excel error code '#N/A' HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); - fe.setCurrentRow(row); try { fe.evaluateInCell(cell); } catch (NumberFormatException e) { @@ -320,8 +305,6 @@ public final class TestFormulaEvaluatorBugs extends TestCase { final HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); - evaluator.setCurrentRow(excelRow); - now = System.currentTimeMillis(); evaluator.evaluate(excelCell); then = System.currentTimeMillis(); @@ -333,8 +316,6 @@ public final class TestFormulaEvaluatorBugs extends TestCase { final HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); - evaluator.setCurrentRow(excelRow); - now = System.currentTimeMillis(); evaluator.evaluate(excelCell); then = System.currentTimeMillis(); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java index 6c2e3b6412..bed8869d54 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java @@ -1,3 +1,20 @@ +/* ==================================================================== + 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.usermodel; import java.util.Iterator; @@ -9,15 +26,12 @@ import junit.framework.TestCase; * http://poi.apache.org/hssf/eval.html * all actually works as we'd expect them to */ -public class TestFormulaEvaluatorDocs extends TestCase { - protected void setUp() throws Exception { - super.setUp(); - } +public final class TestFormulaEvaluatorDocs extends TestCase { /** * http://poi.apache.org/hssf/eval.html#EvaluateAll */ - public void testEvaluateAll() throws Exception { + public void testEvaluateAll() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s1 = wb.createSheet(); HSSFSheet s2 = wb.createSheet(); @@ -28,21 +42,21 @@ public class TestFormulaEvaluatorDocs extends TestCase { HSSFRow s1r2 = s1.createRow(1); HSSFRow s2r1 = s2.createRow(0); - HSSFCell s1r1c1 = s1r1.createCell((short)0); - HSSFCell s1r1c2 = s1r1.createCell((short)1); - HSSFCell s1r1c3 = s1r1.createCell((short)2); + HSSFCell s1r1c1 = s1r1.createCell(0); + HSSFCell s1r1c2 = s1r1.createCell(1); + HSSFCell s1r1c3 = s1r1.createCell(2); s1r1c1.setCellValue(22.3); s1r1c2.setCellValue(33.4); s1r1c3.setCellFormula("SUM(A1:B1)"); - HSSFCell s1r2c1 = s1r2.createCell((short)0); - HSSFCell s1r2c2 = s1r2.createCell((short)1); - HSSFCell s1r2c3 = s1r2.createCell((short)2); + HSSFCell s1r2c1 = s1r2.createCell(0); + HSSFCell s1r2c2 = s1r2.createCell(1); + HSSFCell s1r2c3 = s1r2.createCell(2); s1r2c1.setCellValue(-1.2); s1r2c2.setCellValue(-3.4); s1r2c3.setCellFormula("SUM(A2:B2)"); - HSSFCell s2r1c1 = s2r1.createCell((short)0); + HSSFCell s2r1c1 = s2r1.createCell(0); s2r1c1.setCellFormula("S1!A1"); // Not evaluated yet @@ -58,7 +72,6 @@ public class TestFormulaEvaluatorDocs extends TestCase { for(Iterator rit = sheet.rowIterator(); rit.hasNext();) { HSSFRow r = (HSSFRow)rit.next(); - evaluator.setCurrentRow(r); for(Iterator cit = r.cellIterator(); cit.hasNext();) { HSSFCell c = (HSSFCell)cit.next(); @@ -73,17 +86,17 @@ public class TestFormulaEvaluatorDocs extends TestCase { } // Check now as expected - assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell((short)2).getNumericCellValue(), 0); - assertEquals("SUM(A1:B1)", wb.getSheetAt(0).getRow(0).getCell((short)2).getCellFormula()); - assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(0).getCell((short)2).getCellType()); + assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell(2).getNumericCellValue(), 0); + assertEquals("SUM(A1:B1)", wb.getSheetAt(0).getRow(0).getCell(2).getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(0).getCell(2).getCellType()); - assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell((short)2).getNumericCellValue(), 0); - assertEquals("SUM(A2:B2)", wb.getSheetAt(0).getRow(1).getCell((short)2).getCellFormula()); - assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType()); + assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell(2).getNumericCellValue(), 0); + assertEquals("SUM(A2:B2)", wb.getSheetAt(0).getRow(1).getCell(2).getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(1).getCell(2).getCellType()); - assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0); - assertEquals("'S1'!A1", wb.getSheetAt(1).getRow(0).getCell((short)0).getCellFormula()); - assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType()); + assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell(0).getNumericCellValue(), 0); + assertEquals("'S1'!A1", wb.getSheetAt(1).getRow(0).getCell(0).getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(1).getRow(0).getCell(0).getCellType()); // Now do the alternate call, which zaps the formulas @@ -94,7 +107,6 @@ public class TestFormulaEvaluatorDocs extends TestCase { for(Iterator rit = sheet.rowIterator(); rit.hasNext();) { HSSFRow r = (HSSFRow)rit.next(); - evaluator.setCurrentRow(r); for(Iterator cit = r.cellIterator(); cit.hasNext();) { HSSFCell c = (HSSFCell)cit.next(); @@ -105,13 +117,13 @@ public class TestFormulaEvaluatorDocs extends TestCase { } } - assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell((short)2).getNumericCellValue(), 0); - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(0).getCell((short)2).getCellType()); + assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell(2).getNumericCellValue(), 0); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(0).getCell(2).getCellType()); - assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell((short)2).getNumericCellValue(), 0); - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType()); + assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell(2).getNumericCellValue(), 0); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(1).getCell(2).getCellType()); - assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0); - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType()); + assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell(0).getNumericCellValue(), 0); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(1).getRow(0).getCell(0).getCellType()); } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java index c3d73cf4a7..da5d2cc6a9 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java @@ -17,12 +17,6 @@ package org.apache.poi.hssf.usermodel; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.util.Date; import java.util.GregorianCalendar; @@ -32,7 +26,6 @@ import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.util.HSSFColor; -import org.apache.poi.util.TempFile; /** * Tests various functionity having to do with HSSFCell. For instance support for @@ -47,23 +40,15 @@ public final class TestHSSFCell extends TestCase { return HSSFTestDataSamples.openSampleWorkbook(sampleFileName); } private static HSSFWorkbook writeOutAndReadBack(HSSFWorkbook original) { - - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); - original.write(baos); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - return new HSSFWorkbook(bais); - } catch (IOException e) { - throw new RuntimeException(e); - } + return HSSFTestDataSamples.writeOutAndReadBack(original); } - public void testSetValues() throws Exception { + public void testSetValues() { HSSFWorkbook book = new HSSFWorkbook(); HSSFSheet sheet = book.createSheet("test"); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short)0); + HSSFCell cell = row.createCell(0); cell.setCellValue(1.2); assertEquals(1.2, cell.getNumericCellValue(), 0.0001); @@ -85,54 +70,42 @@ public final class TestHSSFCell extends TestCase { /** * test that Boolean and Error types (BoolErrRecord) are supported properly. */ - public void testBoolErr() - throws java.io.IOException { - - File file = TempFile.createTempFile("testBoolErr",".xls"); - FileOutputStream out = new FileOutputStream(file); - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet s = wb.createSheet("testSheet1"); - HSSFRow r = null; - HSSFCell c = null; - r = s.createRow((short)0); - c=r.createCell((short)1); - //c.setCellType(HSSFCell.CELL_TYPE_BOOLEAN); - c.setCellValue(true); - - c=r.createCell((short)2); - //c.setCellType(HSSFCell.CELL_TYPE_BOOLEAN); - c.setCellValue(false); - - r = s.createRow((short)1); - c=r.createCell((short)1); - //c.setCellType(HSSFCell.CELL_TYPE_ERROR); - c.setCellErrorValue((byte)0); - - c=r.createCell((short)2); - //c.setCellType(HSSFCell.CELL_TYPE_ERROR); - c.setCellErrorValue((byte)7); - - - wb.write(out); - out.close(); - - assertTrue("file exists",file.exists()); - - FileInputStream in = new FileInputStream(file); - wb = new HSSFWorkbook(in); - s = wb.getSheetAt(0); - r = s.getRow(0); - c = r.getCell((short)1); - assertTrue("boolean value 0,1 = true",c.getBooleanCellValue()); - c = r.getCell((short)2); - assertTrue("boolean value 0,2 = false",c.getBooleanCellValue()==false); - r = s.getRow(1); - c = r.getCell((short)1); - assertTrue("boolean value 0,1 = 0",c.getErrorCellValue() == 0); - c = r.getCell((short)2); - assertTrue("boolean value 0,2 = 7",c.getErrorCellValue() == 7); - - in.close(); + public void testBoolErr() { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet s = wb.createSheet("testSheet1"); + HSSFRow r = null; + HSSFCell c = null; + r = s.createRow((short)0); + c=r.createCell(1); + //c.setCellType(HSSFCell.CELL_TYPE_BOOLEAN); + c.setCellValue(true); + + c=r.createCell(2); + //c.setCellType(HSSFCell.CELL_TYPE_BOOLEAN); + c.setCellValue(false); + + r = s.createRow((short)1); + c=r.createCell(1); + //c.setCellType(HSSFCell.CELL_TYPE_ERROR); + c.setCellErrorValue((byte)0); + + c=r.createCell(2); + //c.setCellType(HSSFCell.CELL_TYPE_ERROR); + c.setCellErrorValue((byte)7); + + wb = writeOutAndReadBack(wb); + s = wb.getSheetAt(0); + r = s.getRow(0); + c = r.getCell(1); + assertTrue("boolean value 0,1 = true",c.getBooleanCellValue()); + c = r.getCell(2); + assertTrue("boolean value 0,2 = false",c.getBooleanCellValue()==false); + r = s.getRow(1); + c = r.getCell(1); + assertTrue("boolean value 0,1 = 0",c.getErrorCellValue() == 0); + c = r.getCell(2); + assertTrue("boolean value 0,2 = 7",c.getErrorCellValue() == 7); } /** @@ -140,7 +113,7 @@ public final class TestHSSFCell extends TestCase { * is working properly. Conversion of the date is also an issue, * but there's a separate unit test for that. */ - public void testDateWindowingRead() throws Exception { + public void testDateWindowingRead() { GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000 Date date = cal.getTime(); @@ -150,7 +123,7 @@ public final class TestHSSFCell extends TestCase { assertEquals("Date from file using 1900 Date Windowing", date.getTime(), - sheet.getRow(0).getCell((short)0) + sheet.getRow(0).getCell(0) .getDateCellValue().getTime()); // now check a file with 1904 Date Windowing @@ -159,7 +132,7 @@ public final class TestHSSFCell extends TestCase { assertEquals("Date from file using 1904 Date Windowing", date.getTime(), - sheet.getRow(0).getCell((short)0) + sheet.getRow(0).getCell(0) .getDateCellValue().getTime()); } @@ -169,7 +142,7 @@ public final class TestHSSFCell extends TestCase { * previous test ({@link #testDateWindowingRead}) fails, the * results of this test are meaningless. */ - public void testDateWindowingWrite() throws Exception { + public void testDateWindowingWrite() { GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000 Date date = cal.getTime(); @@ -199,7 +172,7 @@ public final class TestHSSFCell extends TestCase { HSSFCell cell = row.getCell(colIdx); if (cell == null) { - cell = row.createCell((short)colIdx); + cell = row.createCell(colIdx); } cell.setCellValue(date); } @@ -214,8 +187,7 @@ public final class TestHSSFCell extends TestCase { /** * Tests that the active cell can be correctly read and set */ - public void testActiveCell() throws Exception - { + public void testActiveCell() { //read in sample HSSFWorkbook book = openSample("Simple.xls"); @@ -228,7 +200,7 @@ public final class TestHSSFCell extends TestCase { 1, s.getActiveCellRow()); //modify position through HSSFCell - HSSFCell cell = umSheet.createRow(3).createCell((short) 2); + HSSFCell cell = umSheet.createRow(3).createCell(2); cell.setAsActiveCell(); assertEquals("After modify, active cell should be in col 2", (short) 2, s.getActiveCellCol()); @@ -270,14 +242,14 @@ public final class TestHSSFCell extends TestCase { cs.setBorderBottom((short)1); r = s.createRow((short)0); - c=r.createCell((short)0); + c=r.createCell(0); c.setCellStyle(cs); c.setCellFormula("2*3"); wb = writeOutAndReadBack(wb); s = wb.getSheetAt(0); r = s.getRow(0); - c = r.getCell((short)0); + c = r.getCell(0); assertTrue("Formula Cell at 0,0", (c.getCellType()==c.CELL_TYPE_FORMULA)); cs = c.getCellStyle(); @@ -298,7 +270,7 @@ public final class TestHSSFCell extends TestCase { HSSFWorkbook wb = openSample("WithHyperlink.xls"); HSSFSheet sheet = wb.getSheetAt(0); - HSSFCell cell = sheet.getRow(4).getCell((short)0); + HSSFCell cell = sheet.getRow(4).getCell(0); HSSFHyperlink link = cell.getHyperlink(); assertNotNull(link); @@ -311,13 +283,13 @@ public final class TestHSSFCell extends TestCase { /** * Test reading hyperlinks */ - public void testWithTwoHyperlinks() throws Exception { + public void testWithTwoHyperlinks() { HSSFWorkbook wb = openSample("WithTwoHyperLinks.xls"); HSSFSheet sheet = wb.getSheetAt(0); - HSSFCell cell1 = sheet.getRow(4).getCell((short)0); + HSSFCell cell1 = sheet.getRow(4).getCell(0); HSSFHyperlink link1 = cell1.getHyperlink(); assertNotNull(link1); assertEquals("Foo", link1.getLabel()); @@ -325,55 +297,46 @@ public final class TestHSSFCell extends TestCase { assertEquals(4, link1.getFirstRow()); assertEquals(0, link1.getFirstColumn()); - HSSFCell cell2 = sheet.getRow(8).getCell((short)1); + HSSFCell cell2 = sheet.getRow(8).getCell(1); HSSFHyperlink link2 = cell2.getHyperlink(); assertNotNull(link2); assertEquals("Bar", link2.getLabel()); assertEquals("http://poi.apache.org/hssf/", link2.getAddress()); assertEquals(8, link2.getFirstRow()); assertEquals(1, link2.getFirstColumn()); - } /*tests the toString() method of HSSFCell*/ - public void testToString() throws Exception { + public void testToString() { HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet s = wb.createSheet("Sheet1"); - HSSFRow r = s.createRow(0); - HSSFCell c; - c=r.createCell((short) 0); c.setCellValue(true); - assertEquals("Boolean", "TRUE", c.toString()); - c=r.createCell((short) 1); c.setCellValue(1.5); - assertEquals("Numeric", "1.5", c.toString()); - c=r.createCell((short)(2)); c.setCellValue(new HSSFRichTextString("Astring")); - assertEquals("String", "Astring", c.toString()); - c=r.createCell((short) 3); c.setCellErrorValue((byte) 7); - assertEquals("Error", "#ERR7", c.toString()); - c=r.createCell((short)4); c.setCellFormula("A1+B1"); - assertEquals("Formula", "A1+B1", c.toString()); - + HSSFRow r = wb.createSheet("Sheet1").createRow(0); + + r.createCell(0).setCellValue(true); + r.createCell(1).setCellValue(1.5); + r.createCell(2).setCellValue(new HSSFRichTextString("Astring")); + r.createCell(3).setCellErrorValue((byte)HSSFErrorConstants.ERROR_DIV_0); + r.createCell(4).setCellFormula("A1+B1"); + + assertEquals("Boolean", "TRUE", r.getCell(0).toString()); + assertEquals("Numeric", "1.5", r.getCell(1).toString()); + assertEquals("String", "Astring", r.getCell(2).toString()); + assertEquals("Error", "#DIV/0!", r.getCell(3).toString()); + assertEquals("Formula", "A1+B1", r.getCell(4).toString()); + //Write out the file, read it in, and then check cell values - File f = File.createTempFile("testCellToString",".xls"); - wb.write(new FileOutputStream(f)); - wb = new HSSFWorkbook(new FileInputStream(f)); - assertTrue("File exists and can be read", f.canRead()); - - s = wb.getSheetAt(0);r=s.getRow(0); - c=r.getCell((short) 0); - assertEquals("Boolean", "TRUE", c.toString()); - c=r.getCell((short) 1); - assertEquals("Numeric", "1.5", c.toString()); - c=r.getCell((short)(2)); - assertEquals("String", "Astring", c.toString()); - c=r.getCell((short) 3); - assertEquals("Error", "#ERR7", c.toString()); - c=r.getCell((short)4); - assertEquals("Formula", "A1+B1", c.toString()); + wb = writeOutAndReadBack(wb); + + r = wb.getSheetAt(0).getRow(0); + assertEquals("Boolean", "TRUE", r.getCell(0).toString()); + assertEquals("Numeric", "1.5", r.getCell(1).toString()); + assertEquals("String", "Astring", r.getCell(2).toString()); + assertEquals("Error", "#DIV/0!", r.getCell(3).toString()); + assertEquals("Formula", "A1+B1", r.getCell(4).toString()); } public void testSetStringInFormulaCell_bug44606() { HSSFWorkbook wb = new HSSFWorkbook(); - HSSFCell cell = wb.createSheet("Sheet1").createRow(0).createCell((short)0); + HSSFCell cell = wb.createSheet("Sheet1").createRow(0).createCell(0); cell.setCellFormula("B1&C1"); try { cell.setCellValue(new HSSFRichTextString("hello")); @@ -404,8 +367,8 @@ public final class TestHSSFCell extends TestCase { fail(); } catch(IllegalArgumentException e) {} - HSSFCell cellA = wbA.createSheet().createRow(0).createCell((short)0); - HSSFCell cellB = wbB.createSheet().createRow(0).createCell((short)0); + HSSFCell cellA = wbA.createSheet().createRow(0).createCell(0); + HSSFCell cellB = wbB.createSheet().createRow(0).createCell(0); cellA.setCellStyle(styA); cellB.setCellStyle(styB); @@ -418,9 +381,5 @@ public final class TestHSSFCell extends TestCase { fail(); } catch(IllegalArgumentException e) {} } - - public static void main(String [] args) { - junit.textui.TestRunner.run(TestHSSFCell.class); - } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java index e24f30da61..f1be47fd1b 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java @@ -19,7 +19,6 @@ package org.apache.poi.hssf.usermodel; import java.text.DecimalFormat; import java.text.Format; -import java.util.Date; import java.util.Iterator; import junit.framework.TestCase; @@ -96,7 +95,7 @@ public final class TestHSSFDataFormatter extends TestCase { // create cells with good date patterns for (int i = 0; i < goodDatePatterns.length; i++) { - HSSFCell cell = row.createCell((short) i); + HSSFCell cell = row.createCell(i); cell.setCellValue(dateNum); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(format.getFormat(goodDatePatterns[i])); @@ -106,7 +105,7 @@ public final class TestHSSFDataFormatter extends TestCase { // create cells with num patterns for (int i = 0; i < goodNumPatterns.length; i++) { - HSSFCell cell = row.createCell((short) i); + HSSFCell cell = row.createCell(i); cell.setCellValue(-1234567890.12345); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(format.getFormat(goodNumPatterns[i])); @@ -116,7 +115,7 @@ public final class TestHSSFDataFormatter extends TestCase { // create cells with bad num patterns for (int i = 0; i < badNumPatterns.length; i++) { - HSSFCell cell = row.createCell((short) i); + HSSFCell cell = row.createCell(i); cell.setCellValue(1234567890.12345); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(format.getFormat(badNumPatterns[i])); @@ -127,7 +126,7 @@ public final class TestHSSFDataFormatter extends TestCase { { // Zip + 4 format row = sheet.createRow(3); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); cell.setCellValue(123456789); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(format.getFormat("00000-0000")); @@ -136,7 +135,7 @@ public final class TestHSSFDataFormatter extends TestCase { { // Phone number format row = sheet.createRow(4); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); cell.setCellValue(5551234567D); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(format.getFormat("[<=9999999]###-####;(###) ###-####")); @@ -145,7 +144,7 @@ public final class TestHSSFDataFormatter extends TestCase { { // SSN format row = sheet.createRow(5); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); cell.setCellValue(444551234); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat(format.getFormat("000-00-0000")); @@ -154,7 +153,7 @@ public final class TestHSSFDataFormatter extends TestCase { { // formula cell row = sheet.createRow(6); - HSSFCell cell = row.createCell((short) 0); + HSSFCell cell = row.createCell(0); cell.setCellType(HSSFCell.CELL_TYPE_FORMULA); cell.setCellFormula("SUM(12.25,12.25)/100"); HSSFCellStyle cellStyle = wb.createCellStyle(); @@ -231,7 +230,6 @@ public final class TestHSSFDataFormatter extends TestCase { // null test-- null cell should result in empty String assertEquals(formatter.formatCellValue(null), ""); - } public void testGetFormattedCellValueHSSFCellHSSFFormulaEvaluator() { @@ -246,14 +244,10 @@ public final class TestHSSFDataFormatter extends TestCase { // now with a formula evaluator HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb.getSheetAt(0), wb); - //! must set current row ! - evaluator.setCurrentRow(row); log(formatter.formatCellValue(cell, evaluator) + "\t\t\t (with evaluator)"); assertEquals("24.50%", formatter.formatCellValue(cell,evaluator)); } - - /** * Test using a default number format. The format should be used when a * format pattern cannot be parsed by DecimalFormat. diff --git a/src/types/definitions/fib_type.xml b/src/types/definitions/fib_type.xml index fe3f11d9db..6558ac090c 100644 --- a/src/types/definitions/fib_type.xml +++ b/src/types/definitions/fib_type.xml @@ -20,7 +20,7 @@ AbstractType HDFType - File information Block. + Base part of the File information Block (FibBase). Holds the core part of the FIB, from the first 32 bytes. Andrew C. Oliver