From c2ead4458b0aa5b56ab718cbccdb006a7287ac3b Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sun, 6 Jul 2008 13:10:09 +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-674287 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r671322 | nick | 2008-06-24 20:53:53 +0100 (Tue, 24 Jun 2008) | 1 line Make a start on being able to process formulas in the eventusermodel code ........ r672230 | nick | 2008-06-27 11:12:11 +0100 (Fri, 27 Jun 2008) | 1 line Add MethodNotFound exceptions to the faq ........ r672550 | nick | 2008-06-28 18:04:09 +0100 (Sat, 28 Jun 2008) | 1 line Finish the EventWorkbookBuilder, now does sheet references in formulas properly ........ r672553 | nick | 2008-06-28 18:12:38 +0100 (Sat, 28 Jun 2008) | 1 line Update changelog about EventWorkbookBuilder, and tweak XLS2CSVmra to use it if formulas required ........ r672562 | nick | 2008-06-28 19:21:21 +0100 (Sat, 28 Jun 2008) | 1 line Avoid spurious missing lines with the MissingRecordAware event code, and odd files that contain RowRecords in the middle of the cell Records. ........ r672567 | nick | 2008-06-28 19:48:35 +0100 (Sat, 28 Jun 2008) | 1 line Patch from dnapoletano from bug #45175 - Support for variable length operands in org.apache.poi.hwpf.sprm.SprmOperation ........ r672569 | nick | 2008-06-28 19:54:02 +0100 (Sat, 28 Jun 2008) | 1 line Patch from N. Hira from bug #45001 - Further fix for HWPF Range.delete() and unicode characters ........ r672570 | nick | 2008-06-28 19:58:23 +0100 (Sat, 28 Jun 2008) | 1 line Patch from N.Hira from bug #45252 - Improvement for HWPF Range.replaceText() ........ r673050 | yegor | 2008-07-01 11:32:29 +0100 (Tue, 01 Jul 2008) | 1 line updated status of the latest release, 3.1-FINAL ........ r673853 | josh | 2008-07-03 23:20:18 +0100 (Thu, 03 Jul 2008) | 1 line Fix for bug 45334 - formula parser needs to handle dots in identifiers ........ r673863 | josh | 2008-07-04 00:09:08 +0100 (Fri, 04 Jul 2008) | 1 line Fix for bug 45334 - added impl for ERROR.TYPE() ........ r673987 | nick | 2008-07-04 10:58:21 +0100 (Fri, 04 Jul 2008) | 1 line Fix bug #45336 - Fix HSSFColor.getTripletHash() ........ r673997 | nick | 2008-07-04 11:46:59 +0100 (Fri, 04 Jul 2008) | 1 line Fix bug #45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@674296 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 13 +- src/documentation/content/xdocs/faq.xml | 30 +++ src/documentation/content/xdocs/index.xml | 42 ++-- src/documentation/content/xdocs/status.xml | 13 +- .../eventusermodel/examples/XLS2CSVmra.java | 27 ++- .../eventusermodel/EventWorkbookBuilder.java | 199 ++++++++++++++++++ .../MissingRecordAwareHSSFListener.java | 68 +++--- .../apache/poi/hssf/model/FormulaParser.java | 89 ++++++-- .../record/formula/functions/Errortype.java | 95 +++++++-- .../poi/hssf/usermodel/HSSFWorkbook.java | 43 ++-- .../org/apache/poi/hssf/util/HSSFColor.java | 12 +- .../org/apache/poi/hwpf/model/TextPiece.java | 16 +- .../apache/poi/hwpf/sprm/SprmOperation.java | 9 +- .../org/apache/poi/hwpf/usermodel/Range.java | 32 ++- .../apache/poi/hwpf/data/testRangeDelete.doc | Bin 0 -> 104448 bytes .../poi/hwpf/usermodel/TestRangeDelete.java | 196 +++++++++++++++++ .../hwpf/usermodel/TestRangeReplacement.java | 43 +++- .../org/apache/poi/hssf/data/3dFormulas.xls | Bin 0 -> 6144 bytes .../poi/hssf/data/FormulaEvalTestData.xls | Bin 136704 -> 137216 bytes .../org/apache/poi/hssf/data/MRExtraLines.xls | Bin 0 -> 25088 bytes .../TestEventWorkbookBuilder.java | 160 ++++++++++++++ .../TestMissingRecordAwareHSSFListener.java | 74 ++++++- .../poi/hssf/model/TestFormulaParser.java | 25 ++- .../apache/poi/hssf/usermodel/TestBugs.java | 84 ++++++++ .../apache/poi/hssf/util/TestHSSFColor.java | 52 +++++ 25 files changed, 1179 insertions(+), 143 deletions(-) create mode 100644 src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeDelete.doc create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java create mode 100644 src/testcases/org/apache/poi/hssf/data/3dFormulas.xls create mode 100644 src/testcases/org/apache/poi/hssf/data/MRExtraLines.xls create mode 100644 src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java create mode 100644 src/testcases/org/apache/poi/hssf/util/TestHSSFColor.java diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 561ab0d4d2..4ed05d00f1 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -36,7 +36,7 @@ - + 45018 - Support for fetching embeded documents from within an OOXML file Port support for setting a policy on missing / blank cells when fetching, to XSSF too Common text extraction factory, which returns the correct POITextExtractor for the supplied data @@ -45,8 +45,15 @@ Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx - - + + 45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts + 45336 - Fix HSSFColor.getTripletHash() + 45334 - Fixed formula parser to handle dots in identifiers + 45252 - Improvement for HWPF Range.replaceText() + 45001 - Further fix for HWPF Range.delete() and unicode characters + 45175 - Support for variable length operands in org.apache.poi.hwpf.sprm.SprmOperation + Avoid spurious missing lines with the MissingRecordAware event code, and odd files that contain RowRecords in the middle of the cell Records. + Support for parsing formulas during EventUserModel processing, via the new EventWorkbookBuilder 30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d diff --git a/src/documentation/content/xdocs/faq.xml b/src/documentation/content/xdocs/faq.xml index e74b6f0901..22c1a4cb4d 100644 --- a/src/documentation/content/xdocs/faq.xml +++ b/src/documentation/content/xdocs/faq.xml @@ -20,6 +20,36 @@ + + + My code uses some new HSSF feature, compiles fine but fails when live with a "MethodNotFoundException" + + +

You almost certainly have an older version of POI earlier + on your classpath. Quite a few runtimes and other packages + will ship an older version of POI, so this is an easy problem + to hit without realising.

+

The best way to identify the offending earlier jar file is + with a few lines of java. These will load one of the core POI + classes, and report where it came from.

+ +ClassLoader classloader = org.apache.poi.poifs.filesystem.POIFSFileSystem.class.getClassLoader(); +URL res = classloader.getResource("org/apache/poi/poifs/filesystem/POIFSFileSystem.class"> +String path = res.getPath(); +System.out.println("Core POI came from " + path); + +
+
+ + + My code uses the scratchpad, compiles fine but fails to run with a "MethodNotFoundException" + + +

You almost certainly have an older version earlier on your + classpath. See the answer to the similar question above for + how to track this down.

+
+
Why is reading a simple sheet taking so long? diff --git a/src/documentation/content/xdocs/index.xml b/src/documentation/content/xdocs/index.xml index b881cc0a2a..b632fb93ff 100644 --- a/src/documentation/content/xdocs/index.xml +++ b/src/documentation/content/xdocs/index.xml @@ -31,35 +31,24 @@ -
Office Open XML Support +
POI 3.5.1 beta 1, and Office Open XML Support (2008-07-11)

We are currently working to support the new Office Open XML file formats, such as XLSX and PPTX, which were introduced in Office 2007.

-

Support for these is currently only available in an svn branch, - but we hope to have a full release including it by the summer. - People interested should follow the +

Development for this is in a svn branch, but we are please to + announce our first preview release containing this support. + Users interested in the OOXML support should download the + POI 3.5.1 beta 1 + the source and binaries from their + local mirror. + People interested should also follow the dev list to track progress.

-
POI 3.1-BETA2 Released (2008-05-28) +
POI 3.1-FINAL Released (2008-06-29)

- The POI team is pleased to announce the release of 3.1 BETA2 which is one of the final steps before 3.1 FINAL. - The status of this release is a beta, meaning that we encourage users to try it out. - If you find any bugs, please report them to the POI bug database or to - the POI Developer List. -

A full list of changes is available in - the changelog, and - download - the source and binaries from your - local mirror. -

-

- The release is also available from the central Maven repository - under Group ID "org.apache.poi" and Version "3.1-beta2". -

-
-
POI 3.0.2 Released -

The POI team is pleased to announce POI 3.0.2, the latest release of Apache POI. - There have been many important bug fixes since the 3.0.1 release and a lot of new features. A full list of changes is available in + The POI team is pleased to announce the release of 3.1 FINAL, the latest release of Apache POI. + There have been many important bug fixes since the 3.0.2 release and a lot of new features. +

A full list of changes is available in the changelog, and download the source and binaries from your @@ -67,13 +56,8 @@

The release is also available from the central Maven repository - under Group ID "org.apache.poi" and Version "3.0.2-FINAL". + under Group ID "org.apache.poi" and Version "3.1-FINAL".

-

We would also like to confirm that verions 3.0 and 3.0.1 of Apache - POI do - not contain any viruses. Users of broken virus checkers - which do detect a 94 byte file, sci_cec.db, as containing one are - advised to contact their vendor for a fix.

Purpose diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index ca47e0f209..f96dfc33ab 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -33,7 +33,7 @@ - + 45018 - Support for fetching embeded documents from within an OOXML file Port support for setting a policy on missing / blank cells when fetching, to XSSF too Common text extraction factory, which returns the correct POITextExtractor for the supplied data @@ -42,8 +42,15 @@ Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx - - + + 45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts + 45336 - Fix HSSFColor.getTripletHash() + 45334 - Fixed formula parser to handle dots in identifiers + 45252 - Improvement for HWPF Range.replaceText() + 45001 - Further fix for HWPF Range.delete() and unicode characters + 45175 - Support for variable length operands in org.apache.poi.hwpf.sprm.SprmOperation + Avoid spurious missing lines with the MissingRecordAware event code, and odd files that contain RowRecords in the middle of the cell Records. + Support for parsing formulas during EventUserModel processing, via the new EventWorkbookBuilder 30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d diff --git a/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java b/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java index 9bebd3a837..1c9b220356 100644 --- a/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java +++ b/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java @@ -30,9 +30,11 @@ import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; import org.apache.poi.hssf.eventusermodel.HSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFRequest; import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; +import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.CellValueRecordInterface; @@ -46,6 +48,7 @@ import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.SSTRecord; import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** @@ -64,6 +67,10 @@ public class XLS2CSVmra implements HSSFListener { /** Should we output the formula, or the value it has? */ private boolean outputFormulaValues = true; + /** For parsing Formulas */ + private SheetRecordCollectingListener workbookBuildingListener; + private HSSFWorkbook stubWorkbook; + // Records we pick up as we process private SSTRecord sstRecord; private FormatTrackingHSSFListener formatListener; @@ -108,7 +115,13 @@ public class XLS2CSVmra implements HSSFListener { HSSFEventFactory factory = new HSSFEventFactory(); HSSFRequest request = new HSSFRequest(); - request.addListenerForAllRecords(formatListener); + + if(outputFormulaValues) { + request.addListenerForAllRecords(formatListener); + } else { + workbookBuildingListener = new SheetRecordCollectingListener(formatListener); + request.addListenerForAllRecords(workbookBuildingListener); + } factory.processWorkbookEvents(request, fs); } @@ -124,6 +137,16 @@ public class XLS2CSVmra implements HSSFListener { switch (record.getSid()) { + case BOFRecord.sid: + BOFRecord br = (BOFRecord)record; + if(br.getType() == BOFRecord.TYPE_WORKSHEET) { + // Create sub workbook if required + if(workbookBuildingListener != null && stubWorkbook == null) { + stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); + } + } + break; + case SSTRecord.sid: sstRecord = (SSTRecord) record; break; @@ -161,7 +184,7 @@ public class XLS2CSVmra implements HSSFListener { } } else { thisStr = '"' + - FormulaParser.toFormulaString(null, frec.getParsedExpression()) + '"'; + FormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"'; } break; case StringRecord.sid: diff --git a/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java b/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java new file mode 100644 index 0000000000..0ae5f3f260 --- /dev/null +++ b/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java @@ -0,0 +1,199 @@ +/* ==================================================================== + 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.eventusermodel; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.ExternSheetRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SSTRecord; +import org.apache.poi.hssf.record.SupBookRecord; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * When working with the EventUserModel, if you want to + * process formulas, you need an instance of + * {@link Workbook} to pass to a {@link HSSFWorkbook}, + * to finally give to {@link FormulaParser}, + * and this will build you stub ones. + * Since you're working with the EventUserModel, you + * wouldn't want to get a full {@link Workbook} and + * {@link HSSFWorkbook}, as they would eat too much memory. + * Instead, you should collect a few key records as they + * go past, then call this once you have them to build a + * stub {@link Workbook}, and from that a stub + * {@link HSSFWorkbook}, to use with the {@link FormulaParser}. + * + * The records you should collect are: + * * {@link ExternSheetRecord} + * * {@link BoundSheetRecord} + * You should probably also collect {@link SSTRecord}, + * but it's not required to pass this in. + * + * To help, this class includes a HSSFListener wrapper + * that will do the collecting for you. + */ +public class EventWorkbookBuilder { + /** + * Wraps up your stub {@link Workbook} as a stub + * {@link HSSFWorkbook}, ready for passing to + * {@link FormulaParser} + * @param workbook A stub {@link Workbook} + */ + public static HSSFWorkbook createStubHSSFWorkbook(Workbook workbook) { + return new StubHSSFWorkbook(workbook); + } + + /** + * Creates a stub Workbook from the supplied records, + * suitable for use with the {@link FormulaParser} + * @param externs The ExternSheetRecords in your file + * @param bounds The BoundSheetRecords in your file + * @param sst The SSTRecord in your file. + * @return A stub Workbook suitable for use with {@link FormulaParser} + */ + public static Workbook createStubWorkbook(ExternSheetRecord[] externs, + BoundSheetRecord[] bounds, SSTRecord sst) { + List wbRecords = new ArrayList(); + + // Core Workbook records go first + if(bounds != null) { + for(int i=0; i -1) { + for(int i=lastCellRow; i + * Note - identifiers in Excel can contain dots, so this method may return a String + * which may need to be converted to an area reference. For example, this method + * may return a value like "A1..B2", in which case the caller must convert it to + * an area reference like "A1:B2" + */ + private String parseIdentifier() { StringBuffer Token = new StringBuffer(); if (!IsAlpha(look) && look != '\'') { throw expected("Name"); @@ -201,7 +209,9 @@ public final class FormulaParser { } else { - while (IsAlNum(look)) { + // allow for any sequence of dots and identifier chars + // special case of two consecutive dots is best treated in the calling code + while (IsAlNum(look) || look == '.') { Token.append(look); GetChar(); } @@ -220,15 +230,22 @@ public final class FormulaParser { return value.length() == 0 ? null : value.toString(); } - private ParseNode parseFunctionOrIdentifier() { - String name = GetName(); + private ParseNode parseFunctionReferenceOrName() { + String name = parseIdentifier(); if (look == '('){ //This is a function return function(name); } - return new ParseNode(parseIdentifier(name)); + return new ParseNode(parseNameOrReference(name)); } - private Ptg parseIdentifier(String name) { + + private Ptg parseNameOrReference(String name) { + + AreaReference areaRef = parseArea(name); + if (areaRef != null) { + // will happen if dots are used instead of colon + return new AreaPtg(areaRef.formatAsString()); + } if (look == ':' || look == '.') { // this is a AreaReference GetChar(); @@ -238,23 +255,28 @@ public final class FormulaParser { } String first = name; - String second = GetName(); + String second = parseIdentifier(); return new AreaPtg(first+":"+second); } if (look == '!') { Match('!'); String sheetName = name; - String first = GetName(); + String first = parseIdentifier(); short externIdx = (short)book.getExternalSheetIndex(book.getSheetIndex(sheetName)); + areaRef = parseArea(name); + if (areaRef != null) { + // will happen if dots are used instead of colon + return new Area3DPtg(areaRef.formatAsString(), externIdx); + } if (look == ':') { Match(':'); - String second=GetName(); + String second=parseIdentifier(); if (look == '!') { //The sheet name was included in both of the areas. Only really //need it once Match('!'); - String third=GetName(); + String third=parseIdentifier(); if (!sheetName.equals(second)) throw new RuntimeException("Unhandled double sheet reference."); @@ -271,9 +293,7 @@ public final class FormulaParser { // This can be either a cell ref or a named range // Try to spot which it is - boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches(); - - if (cellRef) { + if (isValidCellReference(name)) { return new RefPtg(name); } @@ -287,6 +307,41 @@ public final class FormulaParser { + name + "\", but that named range wasn't defined!"); } + /** + * @return null if name cannot be split at a dot + */ + private AreaReference parseArea(String name) { + int dotPos = name.indexOf('.'); + if (dotPos < 0) { + return null; + } + int dotCount = 1; + while (dotCount3) { + // four or more consecutive dots does not convert to ':' + return null; + } + } + String partA = name.substring(0, dotPos); + if (!isValidCellReference(partA)) { + return null; + } + String partB = name.substring(dotPos+dotCount); + if (!isValidCellReference(partB)) { + return null; + } + CellReference topLeft = new CellReference(partA); + CellReference bottomRight = new CellReference(partB); + return new AreaReference(topLeft, bottomRight); + } + + private static boolean isValidCellReference(String str) { + // TODO - exact rules for recognising cell references may be too complicated for regex + return CELL_REFERENCE_PATTERN.matcher(str).matches(); + } + + /** * Note - Excel function names are 'case aware but not case sensitive'. This method may end * up creating a defined name record in the workbook if the specified name is not an internal @@ -465,7 +520,7 @@ public final class FormulaParser { return new ParseNode(parseStringLiteral()); } if (IsAlpha(look) || look == '\''){ - return parseFunctionOrIdentifier(); + return parseFunctionReferenceOrName(); } // else - assume number return new ParseNode(parseNumber()); @@ -510,7 +565,7 @@ public final class FormulaParser { private ErrPtg parseErrorLiteral() { Match('#'); - String part1 = GetName().toUpperCase(); + String part1 = parseIdentifier().toUpperCase(); switch(part1.charAt(0)) { case 'V': diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Errortype.java b/src/java/org/apache/poi/hssf/record/formula/functions/Errortype.java index 51268c9aa0..dd72eb5c79 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Errortype.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Errortype.java @@ -1,25 +1,78 @@ -/* -* 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. -*/ -/* - * Created on May 15, 2005 - * - */ +/* ==================================================================== + 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.functions; -public class Errortype extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.EvaluationException; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.OperandResolver; +import org.apache.poi.hssf.usermodel.HSSFErrorConstants; + +/** + * Implementation for the ERROR.TYPE() Excel function.

+ * + * Syntax:
+ * ERROR.TYPE(errorValue)

+ * + * Returns a number corresponding to the error type of the supplied argument.

+ * + * + * + * + * + * + * + * + * + * + * + *
errorValueReturn Value
#NULL!1
#DIV/0!2
#VALUE!3
#REF!4
#NAME?5
#NUM!6
#N/A!7
everything else#N/A!
+ * + * Note - the results of ERROR.TYPE() are different to the constants defined in + * HSSFErrorConstants. + * + * @author Josh Micich + */ +public final class Errortype implements Function { + + public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) { + + try { + OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol); + return ErrorEval.NA; + } catch (EvaluationException e) { + int result = translateErrorCodeToErrorTypeValue(e.getErrorEval().getErrorCode()); + return new NumberEval(result); + } + } + + private int translateErrorCodeToErrorTypeValue(int errorCode) { + switch (errorCode) { + case HSSFErrorConstants.ERROR_NULL: return 1; + case HSSFErrorConstants.ERROR_DIV_0: return 2; + case HSSFErrorConstants.ERROR_VALUE: return 3; + case HSSFErrorConstants.ERROR_REF: return 4; + case HSSFErrorConstants.ERROR_NAME: return 5; + case HSSFErrorConstants.ERROR_NUM: return 6; + case HSSFErrorConstants.ERROR_NA : return 7; + } + throw new IllegalArgumentException("Invalid error code (" + errorCode + ")"); + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 3aac4b5992..b80ccb7905 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -24,6 +24,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Stack; @@ -105,6 +106,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm */ private ArrayList names; + + /** + * this holds the HSSFFont objects attached to this workbook. + * We only create these from the low level records as required. + */ + private Hashtable fonts; /** * holds whether or not to preserve other nodes in the POIFS. Used @@ -1021,9 +1028,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm if(fontindex == Short.MAX_VALUE){ throw new IllegalArgumentException("Maximum number of fonts was exceeded"); } - HSSFFont retval = new HSSFFont(fontindex, font); - - return retval; + + // Ask getFontAt() to build it for us, + // so it gets properly cached + return getFontAt(fontindex); } /** @@ -1033,15 +1041,11 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm String name, boolean italic, boolean strikeout, short typeOffset, byte underline) { -// System.out.println( boldWeight + ", " + color + ", " + fontHeight + ", " + name + ", " + italic + ", " + strikeout + ", " + typeOffset + ", " + underline ); - for (short i = 0; i < workbook.getNumberOfFontRecords(); i++) - { - if (i == 4) - continue; - - FontRecord font = workbook.getFontRecordAt(i); - HSSFFont hssfFont = new HSSFFont(i, font); -// System.out.println( hssfFont.getBoldweight() + ", " + hssfFont.getColor() + ", " + hssfFont.getFontHeight() + ", " + hssfFont.getFontName() + ", " + hssfFont.getItalic() + ", " + hssfFont.getStrikeout() + ", " + hssfFont.getTypeOffset() + ", " + hssfFont.getUnderline() ); + for (short i=0; i<=getNumberOfFonts(); i++) { + // Remember - there is no 4! + if(i == 4) continue; + + HSSFFont hssfFont = getFontAt(i); if (hssfFont.getBoldweight() == boldWeight && hssfFont.getColor() == color && hssfFont.getFontHeight() == fontHeight @@ -1051,12 +1055,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm && hssfFont.getTypeOffset() == typeOffset && hssfFont.getUnderline() == underline) { -// System.out.println( "Found font" ); return hssfFont; } } -// System.out.println( "No font found" ); return null; } @@ -1071,15 +1073,26 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm } /** - * get the font at the given index number + * Get the font at the given index number * @param idx index number * @return HSSFFont at the index */ public HSSFFont getFontAt(short idx) { + if(fonts == null) fonts = new Hashtable(); + + // So we don't confuse users, give them back + // the same object every time, but create + // them lazily + Short sIdx = Short.valueOf(idx); + if(fonts.containsKey(sIdx)) { + return (HSSFFont)fonts.get(sIdx); + } + FontRecord font = workbook.getFontRecordAt(idx); HSSFFont retval = new HSSFFont(idx, font); + fonts.put(sIdx, retval); return retval; } diff --git a/src/java/org/apache/poi/hssf/util/HSSFColor.java b/src/java/org/apache/poi/hssf/util/HSSFColor.java index 2c51b3d208..d13baecf80 100644 --- a/src/java/org/apache/poi/hssf/util/HSSFColor.java +++ b/src/java/org/apache/poi/hssf/util/HSSFColor.java @@ -155,8 +155,12 @@ public class HSSFColor implements Color { String hexString = color.getHexString(); if (result.containsKey(hexString)) { - throw new RuntimeException("Dup color hexString (" + hexString - + ") for color (" + color.getClass().getName() + ")"); + HSSFColor other = (HSSFColor)result.get(hexString); + throw new RuntimeException( + "Dup color hexString (" + hexString + + ") for color (" + color.getClass().getName() + ") - " + + " already taken by (" + other.getClass().getName() + ")" + ); } result.put(hexString, color); } @@ -1511,9 +1515,9 @@ public class HSSFColor implements Color { public final static short index = 0x19; public final static short[] triplet = { - 153, 51, 102 + 127, 0, 0 }; - public final static String hexString = "9999:3333:6666"; + public final static String hexString = "8000:0:0"; public short getIndex() { diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java index bc33954dff..227200ab5d 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java @@ -91,15 +91,18 @@ public class TextPiece extends PropertyNode implements Comparable public void adjustForDelete(int start, int length) { + // length is expected to be the number of code-points, + // not the number of characters + int numChars = length; if (usesUnicode()) { start /= 2; - length /= 2; + numChars = (length / 2); } int myStart = getStart(); int myEnd = getEnd(); - int end = start + length; + int end = start + numChars; /* do we have to delete from this text piece? */ if (start <= myEnd && end >= myStart) { @@ -108,9 +111,14 @@ public class TextPiece extends PropertyNode implements Comparable int overlapStart = Math.max(myStart, start); int overlapEnd = Math.min(myEnd, end); ((StringBuffer)_buf).delete(overlapStart, overlapEnd); - - super.adjustForDelete(start, length); } + + // We need to invoke this even if text from this piece is not being + // deleted because the adjustment must propagate to all subsequent + // text pieces i.e., if text from tp[n] is being deleted, then + // tp[n + 1], tp[n + 2], etc. will need to be adjusted. + // The superclass is expected to use a separate sentry for this. + super.adjustForDelete(start, length); } public int characterLength() diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/SprmOperation.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/SprmOperation.java index cacbbaaa38..764fc06c4d 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/SprmOperation.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/SprmOperation.java @@ -101,7 +101,14 @@ public class SprmOperation case 3: return LittleEndian.getInt(_grpprl, _gOffset); case 6: - throw new UnsupportedOperationException("This SPRM contains a variable length operand"); + byte operandLength = _grpprl[_gOffset + 1]; //surely shorter than an int... + + byte [] codeBytes = new byte[LittleEndian.INT_SIZE]; //initialized to zeros by JVM + for(int i = 0; i < operandLength; i++) + if(_gOffset + i < _grpprl.length) + codeBytes[i] = _grpprl[_gOffset + 1 + i]; + + return LittleEndian.getInt(codeBytes, 0); case 7: byte threeByteInt[] = new byte[4]; threeByteInt[0] = _grpprl[_gOffset]; 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 80e9b7526c..0ef944f136 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java @@ -333,7 +333,7 @@ public class Range _doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength); _doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength); _doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength); - adjustForInsert(text.length()); + adjustForInsert(adjustedLength); // update the FIB.CCPText field adjustFIB(text.length()); @@ -656,8 +656,15 @@ public class Range ); } + // this Range isn't a proper parent of the subRange() so we'll have to keep + // track of an updated endOffset on our own + int previousEndOffset = subRange.getEndOffset(); + subRange.insertBefore(pValue); + if (subRange.getEndOffset() != previousEndOffset) + _end += (subRange.getEndOffset() - previousEndOffset); + // re-create the sub-range so we can delete it subRange = new Range( (absPlaceHolderIndex + pValue.length()), @@ -671,9 +678,30 @@ public class Range (pValue.length() * 2)), getDocument() ); + // deletes are automagically propagated subRange.delete(); } + /** + * Replace (all instances of) a piece of text with another... + * + * @param pPlaceHolder The text to be replaced (e.g., "${organization}") + * @param pValue The replacement text (e.g., "Apache Software Foundation") + */ + public void replaceText(String pPlaceHolder, String pValue) + { + boolean keepLooking = true; + while (keepLooking) { + + String text = text(); + int offset = text.indexOf(pPlaceHolder); + if (offset >= 0) + replaceText(pPlaceHolder, pValue, offset); + else + keepLooking = false; + } + } + /** * Gets the character run at index. The index is relative to this range. * @@ -915,7 +943,7 @@ public class Range /** * adjust this range after an insert happens. - * @param length the length to adjust for + * @param length the length to adjust for (expected to be a count of code-points, not necessarily chars) */ private void adjustForInsert(int length) { diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeDelete.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeDelete.doc new file mode 100644 index 0000000000000000000000000000000000000000..896108397cc74c26f901312de84ed809c4e205f2 GIT binary patch literal 104448 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 literal 0 HcmV?d00001 diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java new file mode 100644 index 0000000000..1becc234c3 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java @@ -0,0 +1,196 @@ + +/* ==================================================================== + 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.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.util.List; + +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.PicturesTable; +import org.apache.poi.hwpf.usermodel.Picture; + +import junit.framework.TestCase; + +/** + * Test to see if Range.delete() works even if the Range contains a + * CharacterRun that uses Unicode characters. + */ +public class TestRangeDelete extends TestCase { + + // u201c and u201d are "smart-quotes" + private String originalText = + "It is used to confirm that text delete works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} ${delete} and all the POI contributors for their assistance in this matter.\r"; + private String searchText = "${delete}"; + private String expectedText1 = " This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r"; + private String expectedText2 = + "It is used to confirm that text delete works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r"; + private String expectedText3 = "Thank you, ${organization} !\r"; + + private String illustrativeDocFile; + + protected void setUp() throws Exception { + + String dirname = System.getProperty("HWPF.testdata.path"); + + illustrativeDocFile = dirname + "/testRangeDelete.doc"; + } + + /** + * Test just opening the files + */ + public void testOpen() throws Exception { + + HWPFDocument docA = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + } + + /** + * Test (more "confirm" than test) that we have the general structure that we expect to have. + */ + public void testDocStructure() throws Exception { + + HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + + Range range = daDoc.getRange(); + + assertEquals(1, range.numSections()); + Section section = range.getSection(0); + + assertEquals(5, section.numParagraphs()); + Paragraph para = section.getParagraph(2); + + assertEquals(5, para.numCharacterRuns()); + + assertEquals(originalText, para.text()); + } + + /** + * Test that we can delete text (one instance) from our Range with Unicode text. + */ + public void testRangeDeleteOne() throws Exception { + + HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + + Range range = daDoc.getRange(); + assertEquals(1, range.numSections()); + + Section section = range.getSection(0); + assertEquals(5, section.numParagraphs()); + + Paragraph para = section.getParagraph(2); + + String text = para.text(); + assertEquals(originalText, text); + + int offset = text.indexOf(searchText); + assertEquals(192, offset); + + int absOffset = para.getStartOffset() + offset; + if (para.usesUnicode()) + absOffset = para.getStartOffset() + (offset * 2); + + Range subRange = new Range(absOffset, (absOffset + searchText.length()), para.getDocument()); + if (subRange.usesUnicode()) + subRange = new Range(absOffset, (absOffset + (searchText.length() * 2)), para.getDocument()); + + assertEquals(searchText, subRange.text()); + + subRange.delete(); + + // we need to let the model re-calculate the Range before we evaluate it + range = daDoc.getRange(); + + assertEquals(1, range.numSections()); + section = range.getSection(0); + + assertEquals(5, section.numParagraphs()); + para = section.getParagraph(2); + + text = para.text(); + assertEquals(expectedText2, text); + + // this can lead to a StringBufferOutOfBoundsException, so we will add it + // even though we don't have an assertion for it + Range daRange = daDoc.getRange(); + daRange.text(); + } + + /** + * Test that we can delete text (all instances of) from our Range with Unicode text. + */ + public void testRangeDeleteAll() throws Exception { + + HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + + Range range = daDoc.getRange(); + assertEquals(1, range.numSections()); + + Section section = range.getSection(0); + assertEquals(5, section.numParagraphs()); + + Paragraph para = section.getParagraph(2); + + String text = para.text(); + assertEquals(originalText, text); + + boolean keepLooking = true; + while (keepLooking) { + + int offset = range.text().indexOf(searchText); + if (offset >= 0) { + + int absOffset = range.getStartOffset() + offset; + if (range.usesUnicode()) + absOffset = range.getStartOffset() + (offset * 2); + + Range subRange = new Range( + absOffset, (absOffset + searchText.length()), range.getDocument()); + if (subRange.usesUnicode()) + subRange = new Range( + absOffset, (absOffset + (searchText.length() * 2)), range.getDocument()); + + assertEquals(searchText, subRange.text()); + + subRange.delete(); + + } else + keepLooking = false; + } + + // we need to let the model re-calculate the Range before we use it + range = daDoc.getRange(); + + assertEquals(1, range.numSections()); + section = range.getSection(0); + + assertEquals(5, section.numParagraphs()); + + para = section.getParagraph(1); + text = para.text(); + assertEquals(expectedText1, text); + + para = section.getParagraph(2); + text = para.text(); + assertEquals(expectedText2, text); + + para = section.getParagraph(3); + text = para.text(); + assertEquals(expectedText3, text); + } +} 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 4b2b9ce370..bda615e943 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java @@ -39,8 +39,9 @@ public class TestRangeReplacement extends TestCase { "It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r"; private String searchText = "${organization}"; private String replacementText = "Apache Software Foundation"; - private String expectedText = + private String expectedText2 = "It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the Apache Software Foundation and all the POI contributors for their assistance in this matter.\r"; + private String expectedText3 = "Thank you, Apache Software Foundation!\r"; private String illustrativeDocFile; @@ -84,7 +85,7 @@ public class TestRangeReplacement extends TestCase { /** * Test that we can replace text in our Range with Unicode text. */ - public void testRangeReplacement() throws Exception { + public void testRangeReplacementOne() throws Exception { HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); @@ -104,16 +105,46 @@ public class TestRangeReplacement extends TestCase { para.replaceText(searchText, replacementText, offset); - // we need to let the model re-calculate the Range before we evaluate it - range = daDoc.getRange(); - assertEquals(1, range.numSections()); section = range.getSection(0); + assertEquals(4, section.numParagraphs()); + para = section.getParagraph(2); + + text = para.text(); + assertEquals(expectedText2, text); + } + + /** + * Test that we can replace text in our Range with Unicode text. + */ + public void testRangeReplacementAll() throws Exception { + + HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + + Range range = daDoc.getRange(); + assertEquals(1, range.numSections()); + + Section section = range.getSection(0); + assertEquals(5, section.numParagraphs()); + + Paragraph para = section.getParagraph(2); + + String text = para.text(); + assertEquals(originalText, text); + + range.replaceText(searchText, replacementText); + + assertEquals(1, range.numSections()); + section = range.getSection(0); assertEquals(5, section.numParagraphs()); + para = section.getParagraph(2); + text = para.text(); + assertEquals(expectedText2, text); + para = section.getParagraph(3); text = para.text(); - assertEquals(expectedText, text); + assertEquals(expectedText3, text); } } diff --git a/src/testcases/org/apache/poi/hssf/data/3dFormulas.xls b/src/testcases/org/apache/poi/hssf/data/3dFormulas.xls new file mode 100644 index 0000000000000000000000000000000000000000..82519ed83906854c2d4ba935f8797d8159ef0a28 GIT binary patch literal 6144 zcmeHLO>9(E6h7~DW;&$>+CpiefJ1+#Gt&ZX2LY+jp-R-mpN2{#ASs1*fDpj&vv8q# z{?xG0L?uBdAyJk}f`5r_TnsBT8KNOUq6-4Xl`ABgh$%e3@7(t~ueGfO!$RP^Irrz> z^K;+1=bn4teE(h5<&&Q+xFX|Vos`H;w@e}dx`lR`->(#jqD|UO*L6vr0YvjY{Es|P z7R5qF!g8eLT(@HK5)ngaV3yf^t zI5fDeIJ{6wrPd!_)*g^W2jWZcG7HC!2Q?U`<&wf9{fVYj%%6dF65304X{TXn17_Br z$n-;Rnh3O@S|P2nJYdR~^sRYpNvke6Y<~8bW373l|fyGKLE?2uGCB`)hKC!%$=6ViH)Q>wK%qV-%S>~2S1u;g9jK$Am| z))k}xtuGxbQb4hK?>l{;&DNjEcyj1gke5xsy@}A zI%ow#Dp!EK>*gefzMF$A^ty$dq_eK13kA@@P0RtaP@m1o@#Dt@43f@)kj4*~Qv@xY zle1^f$}n>3no`(CuIbx7G<3LQ7&*V4M>_IiU+1ut%dh3^m0&#mri9=cOHNxM5Ufxw zwp59-azhy4cpVaT3@cHl+)A&g^)1v%y$+Ta2P0kFm~?^**%}=VV*;MmidxR4C^tF~ z=^}?OH&5jvm=Wg$sHoLh7X?R0B3&Fef+H|VHN>#M(9-oCUft=!8&Ro)hbk~ix0sW& za?HtDZkvpQVI*Y(=W%7437r-sZ5fo=+OE>F5;{jd`tAHvJ9@kOm6Ad!$aXAWRf+>1 zADR)lbj>RmITM--U6@V$$@nAjt_*HA3JwRinv8!+&iYJ6SG z_^8IK-7SH30_{^D6aMN>2HGd30agdqOM>=hdo!m8xY}K;H$it)UQ++q(o|MshU{5d zn|mb1qBd?EfD%SE!J4f!F8p{J-*!BWnu4^KZ4FYq_%e)`o`v3)(VmUo8|X!35mrIa zGZ4?1x>UB1EP2B~VFN2OruG;tkAeCWoXl7TTNyZMUjqY+01fK0e5oBBjV+qvHkyRl z3Nm*_q*?gt9`lET8R`{;fJQI^JumqlY{!cTfbDpnhcWnrdq|)8?mD|#zNEZlfcm>u+-p&9{Uhq(S9NVM>g_<(-_Shb zFRAG<8tB7|Sd4a+)|Jy%2Bq&`T{&i0lJxnnE9a$3IXd&+TRGg0$K@;Ct?G3@Us-{b zBh9#eY!0JTkgu4VKF0`ql&XFppF67iPTMgsJRb9{%9k z^=Echo_YuNTfX@5PT0TAY2P(sy3TkT1{0SN_Z?&&b9><_!2f%AzVhnFn-7u$Zi+m1 z%=+VtRll|8pyu6&#}mF)`9Z3&G9UEM7K+EbJNjWTg(B5xEwOsAlr)@%DXwoLXCLi}k!*Xl( i#w$&D_L+yLYky6^KG%%06YYQQ7awm>`F*(SJn%QD%Pk}T literal 0 HcmV?d00001 diff --git a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls index ce94050789f600447ede6c710dd38492496b5e5e..7be92c5fa43389d199e7ad4e75b75e1c7a2043f7 100644 GIT binary patch delta 23768 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 avrcVKwoh9p-%K85telb^DXQ%$(*7TUMuNxy delta 23374 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 PEuV=U7VMX(ZP5Q8q~)nI diff --git a/src/testcases/org/apache/poi/hssf/data/MRExtraLines.xls b/src/testcases/org/apache/poi/hssf/data/MRExtraLines.xls new file mode 100644 index 0000000000000000000000000000000000000000..e82e4f6f4085b9aaceffe8b1ec44a8b1d1e0d6ae GIT binary patch literal 25088 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 A^8f$< literal 0 HcmV?d00001 diff --git a/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java b/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java new file mode 100644 index 0000000000..adf084331a --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java @@ -0,0 +1,160 @@ +/* ==================================================================== + 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.eventusermodel; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.model.Workbook; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.formula.Ref3DPtg; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.SheetReferences; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +/** + * Tests for {@link EventWorkbookBuilder} + */ +public final class TestEventWorkbookBuilder extends TestCase { + private MockHSSFListener mockListen; + private SheetRecordCollectingListener listener; + + public void setUp() { + HSSFRequest req = new HSSFRequest(); + mockListen = new MockHSSFListener(); + listener = new SheetRecordCollectingListener(mockListen); + req.addListenerForAllRecords(listener); + + HSSFEventFactory factory = new HSSFEventFactory(); + try { + InputStream is = HSSFTestDataSamples.openSampleFileStream("3dFormulas.xls"); + POIFSFileSystem fs = new POIFSFileSystem(is); + factory.processWorkbookEvents(req, fs); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void testBasics() throws Exception { + assertNotNull(listener.getSSTRecord()); + assertNotNull(listener.getBoundSheetRecords()); + assertNotNull(listener.getExternSheetRecords()); + } + + public void testGetStubWorkbooks() throws Exception { + assertNotNull(listener.getStubWorkbook()); + assertNotNull(listener.getStubHSSFWorkbook()); + + assertNotNull(listener.getStubWorkbook().getSheetReferences()); + assertNotNull(listener.getStubHSSFWorkbook().getSheetReferences()); + } + + public void testContents() throws Exception { + assertEquals(2, listener.getSSTRecord().getNumStrings()); + assertEquals(3, listener.getBoundSheetRecords().length); + assertEquals(1, listener.getExternSheetRecords().length); + + assertEquals(3, listener.getStubWorkbook().getNumSheets()); + + SheetReferences ref = listener.getStubWorkbook().getSheetReferences(); + assertEquals("Sh3", ref.getSheetName(0)); + assertEquals("Sheet1", ref.getSheetName(1)); + assertEquals("S2", ref.getSheetName(2)); + } + + public void testFormulas() throws Exception { + FormulaRecord fr; + + // Check our formula records + assertEquals(6, mockListen._frecs.size()); + + Workbook stubWB = listener.getStubWorkbook(); + assertNotNull(stubWB); + HSSFWorkbook stubHSSF = listener.getStubHSSFWorkbook(); + assertNotNull(stubHSSF); + + // Check these stubs have the right stuff on them + assertEquals("Sheet1", stubWB.getSheetName(0)); + assertEquals("S2", stubWB.getSheetName(1)); + assertEquals("Sh3", stubWB.getSheetName(2)); + + // Check we can get the formula without breaking + for(int i=0; i 100); + } + public void openAlt() { + HSSFRequest req = new HSSFRequest(); + MockHSSFListener mockListen = new MockHSSFListener(); + MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen); + req.addListenerForAllRecords(listener); + + HSSFEventFactory factory = new HSSFEventFactory(); + try { + InputStream is = HSSFTestDataSamples.openSampleFileStream("MRExtraLines.xls"); + POIFSFileSystem fs = new POIFSFileSystem(is); + factory.processWorkbookEvents(req, fs); + } catch (IOException e) { + throw new RuntimeException(e); + } + + r = mockListen.getRecords(); + assertTrue(r.length > 100); } public void testMissingRowRecords() throws Exception { + openNormal(); // We have rows 0, 1, 2, 20 and 21 int row0 = -1; @@ -108,6 +127,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase { } public void testEndOfRowRecords() throws Exception { + openNormal(); // Find the cell at 0,0 int cell00 = -1; @@ -194,7 +214,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase { assertTrue(r[cell00+57] instanceof LastCellOfRowDummyRecord); // Check the numbers of the last seen columns - LastCellOfRowDummyRecord[] lrs = new LastCellOfRowDummyRecord[23]; + LastCellOfRowDummyRecord[] lrs = new LastCellOfRowDummyRecord[24]; int lrscount = 0; for(int i=0; i 0); + assertTrue(HSSFColor.YELLOW.index2 > 0); + } + + public void testContents() { + assertEquals(3, HSSFColor.YELLOW.triplet.length); + assertEquals(255, HSSFColor.YELLOW.triplet[0]); + assertEquals(255, HSSFColor.YELLOW.triplet[1]); + assertEquals(0, HSSFColor.YELLOW.triplet[2]); + + assertEquals("FFFF:FFFF:0", HSSFColor.YELLOW.hexString); + } + + public void testTrippletHash() { + Hashtable tripplets = HSSFColor.getTripletHash(); + + assertEquals( + HSSFColor.MAROON.class, + tripplets.get(HSSFColor.MAROON.hexString).getClass() + ); + assertEquals( + HSSFColor.YELLOW.class, + tripplets.get(HSSFColor.YELLOW.hexString).getClass() + ); + } +} -- 2.39.5