();
}
/**
@@ -1280,9 +1280,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
/**
* Closes the underlying {@link NPOIFSFileSystem} from which
- * the Workbook was read, if any. Has no effect on Workbooks
- * opened from an InputStream, or newly created ones.
- * Once {@link #close()} has been called, no further
+ * the Workbook was read, if any.
+ *
+ *
Once this has been called, no further
* operations, updates or reads should be performed on the
* Workbook.
*/
@@ -1531,6 +1531,11 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
return names.get(nameIndex);
}
+ @Override
+ public List getAllNames() {
+ return Collections.unmodifiableList(names);
+ }
+
public NameRecord getNameRecord(int nameIndex) {
return getWorkbook().getNameRecord(nameIndex);
}
@@ -1702,8 +1707,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
*
* @param name the name to remove.
*/
- void removeName(HSSFName name) {
- int index = getNameIndex(name);
+ @Override
+ public void removeName(Name name) {
+ int index = getNameIndex((HSSFName) name);
removeName(index);
}
diff --git a/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java b/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
index f681f3ad1e..69f8d6768b 100644
--- a/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
+++ b/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
@@ -374,20 +374,22 @@ public class CryptoFunctions {
// SET Verifier TO 0x0000
short verifier = 0;
- // FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
- for (int i = arrByteChars.length-1; i >= 0; i--) {
- // SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
+ if (!"".equals(password)) {
+ // FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
+ for (int i = arrByteChars.length-1; i >= 0; i--) {
+ // SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
+ verifier = rotateLeftBase15Bit(verifier);
+ verifier ^= arrByteChars[i];
+ }
+
+ // as we haven't prepended the password length into the input array
+ // we need to do it now separately ...
verifier = rotateLeftBase15Bit(verifier);
- verifier ^= arrByteChars[i];
+ verifier ^= arrByteChars.length;
+
+ // RETURN Verifier BITWISE XOR 0xCE4B
+ verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
}
-
- // as we haven't prepended the password length into the input array
- // we need to do it now separately ...
- verifier = rotateLeftBase15Bit(verifier);
- verifier ^= arrByteChars.length;
-
- // RETURN Verifier BITWISE XOR 0xCE4B
- verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
return verifier & 0xFFFF;
}
diff --git a/src/java/org/apache/poi/ss/formula/BaseFormulaEvaluator.java b/src/java/org/apache/poi/ss/formula/BaseFormulaEvaluator.java
new file mode 100644
index 0000000000..8746ba7fa0
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/BaseFormulaEvaluator.java
@@ -0,0 +1,194 @@
+/* ====================================================================
+ 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.ss.formula;
+
+import java.util.Map;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Common functionality across file formats for evaluating formula cells.
+ */
+public abstract class BaseFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
+ protected final WorkbookEvaluator _bookEvaluator;
+
+ protected BaseFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
+ this._bookEvaluator = bookEvaluator;
+ }
+
+ /**
+ * Coordinates several formula evaluators together so that formulas that involve external
+ * references can be evaluated.
+ * @param workbookNames the simple file names used to identify the workbooks in formulas
+ * with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
+ * @param evaluators all evaluators for the full set of workbooks required by the formulas.
+ */
+ public static void setupEnvironment(String[] workbookNames, BaseFormulaEvaluator[] evaluators) {
+ WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length];
+ for (int i = 0; i < wbEvals.length; i++) {
+ wbEvals[i] = evaluators[i]._bookEvaluator;
+ }
+ CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
+ }
+
+ @Override
+ public void setupReferencedWorkbooks(Map evaluators) {
+ CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
+ }
+
+ @Override
+ public WorkbookEvaluator _getWorkbookEvaluator() {
+ return _bookEvaluator;
+ }
+
+ /**
+ * Should be called whenever there are major changes (e.g. moving sheets) to input cells
+ * in the evaluated workbook. If performance is not critical, a single call to this method
+ * may be used instead of many specific calls to the notify~ methods.
+ *
+ * Failure to call this method after changing cell values will cause incorrect behaviour
+ * of the evaluate~ methods of this class
+ */
+ @Override
+ public void clearAllCachedResultValues() {
+ _bookEvaluator.clearAllCachedResultValues();
+ }
+
+ /**
+ * If cell contains a formula, the formula is evaluated and returned,
+ * else the CellValue simply copies the appropriate cell value from
+ * the cell and also its cell type. This method should be preferred over
+ * evaluateInCell() when the call should not modify the contents of the
+ * original cell.
+ *
+ * @param cell may be null
signifying that the cell is not present (or blank)
+ * @return null
if the supplied cell is null
or blank
+ */
+ @Override
+ public CellValue evaluate(Cell cell) {
+ if (cell == null) {
+ return null;
+ }
+
+ switch (cell.getCellTypeEnum()) {
+ case BOOLEAN:
+ return CellValue.valueOf(cell.getBooleanCellValue());
+ case ERROR:
+ return CellValue.getError(cell.getErrorCellValue());
+ case FORMULA:
+ return evaluateFormulaCellValue(cell);
+ case NUMERIC:
+ return new CellValue(cell.getNumericCellValue());
+ case STRING:
+ return new CellValue(cell.getRichStringCellValue().getString());
+ case BLANK:
+ return null;
+ default:
+ throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
+ }
+ }
+
+ protected abstract CellValue evaluateFormulaCellValue(Cell cell);
+
+ /**
+ * If cell contains formula, it evaluates the formula, and saves the result of the formula. The
+ * cell remains as a formula cell. If the cell does not contain formula, this method returns -1
+ * and leaves the cell unchanged.
+ *
+ * Note that the type of the formula result is returned, so you know what kind of
+ * cached formula result is also stored with the formula.
+ *
+ * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
+ *
+ * Be aware that your cell will hold both the formula, and the result. If you want the cell
+ * replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
+ * @param cell The cell to evaluate
+ * @return -1 for non-formula cells, or the type of the formula result
+ */
+ @Override
+ public int evaluateFormulaCell(Cell cell) {
+ return evaluateFormulaCellEnum(cell).getCode();
+ }
+
+ protected static void setCellType(Cell cell, CellValue cv) {
+ CellType cellType = cv.getCellType();
+ switch (cellType) {
+ case BOOLEAN:
+ case ERROR:
+ case NUMERIC:
+ case STRING:
+ cell.setCellType(cellType);
+ return;
+ case BLANK:
+ // never happens - blanks eventually get translated to zero
+ throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
+ case FORMULA:
+ // this will never happen, we have already evaluated the formula
+ throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
+ default:
+ throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
+ }
+ }
+
+ /**
+ * Loops over all cells in all sheets of the supplied
+ * workbook.
+ * For cells that contain formulas, their formulas are
+ * evaluated, and the results are saved. These cells
+ * remain as formula cells.
+ * For cells that do not contain formulas, no changes
+ * are made.
+ * This is a helpful wrapper around looping over all
+ * cells, and calling evaluateFormulaCell on each one.
+ */
+ public static void evaluateAllFormulaCells(Workbook wb) {
+ FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+ evaluateAllFormulaCells(wb, evaluator);
+ }
+ protected static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
+ for(int i=0; i
*
@@ -61,7 +67,6 @@ import org.apache.poi.ss.formula.eval.ValueEval;
public class Subtotal implements Function {
private static Function findFunction(int functionCode) throws EvaluationException {
- Function func;
switch (functionCode) {
case 1: return subtotalInstance(AggregateFunction.AVERAGE);
case 2: return Count.subtotalInstance();
@@ -87,7 +92,7 @@ public class Subtotal implements Function {
return ErrorEval.VALUE_INVALID;
}
- Function innerFunc;
+ final Function innerFunc;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex);
int functionCode = OperandResolver.coerceValueToInt(ve);
@@ -96,9 +101,24 @@ public class Subtotal implements Function {
return e.getErrorEval();
}
- ValueEval[] innerArgs = new ValueEval[nInnerArgs];
- System.arraycopy(args, 1, innerArgs, 0, nInnerArgs);
+ // ignore the first arg, this is the function-type, we check for the length above
+ final List list = new ArrayList(Arrays.asList(args).subList(1, args.length));
- return innerFunc.evaluate(innerArgs, srcRowIndex, srcColumnIndex);
+ Iterator it = list.iterator();
+
+ // See https://support.office.com/en-us/article/SUBTOTAL-function-7b027003-f060-4ade-9040-e478765b9939
+ // "If there are other subtotals within ref1, ref2,... (or nested subtotals), these nested subtotals are ignored to avoid double counting."
+ // For array references it is handled in other evaluation steps, but we need to handle this here for references to subtotal-functions
+ while(it.hasNext()) {
+ ValueEval eval = it.next();
+ if(eval instanceof LazyRefEval) {
+ LazyRefEval lazyRefEval = (LazyRefEval) eval;
+ if(lazyRefEval.isSubTotal()) {
+ it.remove();
+ }
+ }
+ }
+
+ return innerFunc.evaluate(list.toArray(new ValueEval[list.size()]), srcRowIndex, srcColumnIndex);
}
}
diff --git a/src/java/org/apache/poi/ss/usermodel/CellStyle.java b/src/java/org/apache/poi/ss/usermodel/CellStyle.java
index c82ffb98eb..b6c9719790 100644
--- a/src/java/org/apache/poi/ss/usermodel/CellStyle.java
+++ b/src/java/org/apache/poi/ss/usermodel/CellStyle.java
@@ -81,7 +81,7 @@ public interface CellStyle {
/**
* vertically justified vertical alignment
- * @deprecated POI 3.15 beta 3. Use {@link VerticalAlignment#TOP} instead.
+ * @deprecated POI 3.15 beta 3. Use {@link VerticalAlignment#JUSTIFY} instead.
*/
static final short VERTICAL_JUSTIFY = 0x3; //VerticalAlignment.JUSTIFY.getCode();
diff --git a/src/java/org/apache/poi/ss/usermodel/Workbook.java b/src/java/org/apache/poi/ss/usermodel/Workbook.java
index 1fcc29a3eb..e52615fb1a 100644
--- a/src/java/org/apache/poi/ss/usermodel/Workbook.java
+++ b/src/java/org/apache/poi/ss/usermodel/Workbook.java
@@ -341,9 +341,11 @@ public interface Workbook extends Closeable, Iterable {
/**
* Close the underlying input resource (File or Stream),
- * from which the Workbook was read. After closing, the
- * Workbook should no longer be used.
- * This will have no effect newly created Workbooks.
+ * from which the Workbook was read.
+ *
+ *
Once this has been called, no further
+ * operations, updates or reads should be performed on the
+ * Workbook.
*/
@Override
void close() throws IOException;
@@ -367,6 +369,13 @@ public interface Workbook extends Closeable, Iterable {
*/
List extends Name> getNames(String name);
+ /**
+ * Returns all defined names.
+ *
+ * @return a list of the defined names. An empty list is returned if none is found.
+ */
+ List extends Name> getAllNames();
+
/**
* @param nameIndex position of the named range (0-based)
* @return the defined name at the specified index
@@ -405,6 +414,13 @@ public interface Workbook extends Closeable, Iterable {
*/
void removeName(String name);
+ /**
+ * Remove a defined name
+ *
+ * @param name the name of the defined name
+ */
+ void removeName(Name name);
+
/**
* Adds the linking required to allow formulas referencing
* the specified external workbook to be added to this one.
diff --git a/src/java/org/apache/poi/util/CommonsLogger.java b/src/java/org/apache/poi/util/CommonsLogger.java
index 16a48f28f6..1cbb9628ca 100644
--- a/src/java/org/apache/poi/util/CommonsLogger.java
+++ b/src/java/org/apache/poi/util/CommonsLogger.java
@@ -27,19 +27,13 @@ import org.apache.commons.logging.LogFactory;
* developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log
* message.
- *
- * @author Marc Johnson (mjohnson at apache dot org)
- * @author Glen Stampoultzis (glens at apache.org)
- * @author Nicola Ken Barozzi (nicolaken at apache.org)
*/
-
public class CommonsLogger extends POILogger
{
-
private static LogFactory _creator = LogFactory.getFactory();
private Log log = null;
-
+ @Override
public void initialize(final String cat)
{
this.log = _creator.getInstance(cat);
@@ -51,6 +45,7 @@ public class CommonsLogger extends POILogger
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log.
*/
+ @Override
public void log(final int level, final Object obj1)
{
if(level==FATAL)
@@ -104,6 +99,7 @@ public class CommonsLogger extends POILogger
* @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
+ @Override
public void log(final int level, final Object obj1,
final Throwable exception)
{
@@ -175,7 +171,7 @@ public class CommonsLogger extends POILogger
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
*/
-
+ @Override
public boolean check(final int level)
{
if(level==FATAL)
diff --git a/src/java/org/apache/poi/util/NullLogger.java b/src/java/org/apache/poi/util/NullLogger.java
index 24643c8fde..fe0979cfef 100644
--- a/src/java/org/apache/poi/util/NullLogger.java
+++ b/src/java/org/apache/poi/util/NullLogger.java
@@ -22,14 +22,10 @@ package org.apache.poi.util;
* developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log
* message.
- *
- * @author Marc Johnson (mjohnson at apache dot org)
- * @author Glen Stampoultzis (glens at apache.org)
- * @author Nicola Ken Barozzi (nicolaken at apache.org)
*/
public class NullLogger extends POILogger {
@Override
- public void initialize(final String cat){
+ public void initialize(final String cat) {
// do nothing
}
@@ -41,8 +37,7 @@ public class NullLogger extends POILogger {
*/
@Override
- public void log(final int level, final Object obj1)
- {
+ public void log(final int level, final Object obj1) {
// do nothing
}
@@ -53,6 +48,7 @@ public class NullLogger extends POILogger {
* @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
+ @Override
public void log(int level, Object obj1, final Throwable exception) {
// do nothing
}
diff --git a/src/java/org/apache/poi/util/SystemOutLogger.java b/src/java/org/apache/poi/util/SystemOutLogger.java
index e665ba6324..36d96ca038 100644
--- a/src/java/org/apache/poi/util/SystemOutLogger.java
+++ b/src/java/org/apache/poi/util/SystemOutLogger.java
@@ -24,15 +24,12 @@ package org.apache.poi.util;
* developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log
* message.
- *
- * @author Marc Johnson (mjohnson at apache dot org)
- * @author Glen Stampoultzis (glens at apache.org)
- * @author Nicola Ken Barozzi (nicolaken at apache.org)
*/
public class SystemOutLogger extends POILogger
{
private String _cat;
+ @Override
public void initialize(final String cat)
{
this._cat=cat;
@@ -44,7 +41,7 @@ public class SystemOutLogger extends POILogger
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log.
*/
-
+ @Override
public void log(final int level, final Object obj1)
{
log(level, obj1, null);
@@ -57,6 +54,7 @@ public class SystemOutLogger extends POILogger
* @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
+ @Override
@SuppressForbidden("uses printStackTrace")
public void log(final int level, final Object obj1,
final Throwable exception) {
@@ -78,6 +76,7 @@ public class SystemOutLogger extends POILogger
* @see #ERROR
* @see #FATAL
*/
+ @Override
public boolean check(final int level)
{
int currentLevel;
diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocument.java b/src/ooxml/java/org/apache/poi/POIXMLDocument.java
index 55b1a4d186..4ec3d442ed 100644
--- a/src/ooxml/java/org/apache/poi/POIXMLDocument.java
+++ b/src/ooxml/java/org/apache/poi/POIXMLDocument.java
@@ -193,8 +193,12 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart implements Close
/**
* Closes the underlying {@link OPCPackage} from which this
* document was read, if there is one
- *
- * @throws IOException for writable packages, if an IO exception occur during the saving process.
+ *
+ *
Once this has been called, no further
+ * operations, updates or reads should be performed on the
+ * document.
+ *
+ * @throws IOException for writable packages, if an IO exception occur during the saving process.
*/
@Override
public void close() throws IOException {
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
index a438c061ff..e029d7dece 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
@@ -382,8 +382,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
}
// Creates a new package
- OPCPackage pkg = null;
- pkg = new ZipPackage();
+ OPCPackage pkg = new ZipPackage();
pkg.originalPackagePath = file.getAbsolutePath();
configurePackage(pkg);
@@ -391,8 +390,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
}
public static OPCPackage create(OutputStream output) {
- OPCPackage pkg = null;
- pkg = new ZipPackage();
+ OPCPackage pkg = new ZipPackage();
pkg.originalPackagePath = null;
pkg.output = output;
@@ -542,7 +540,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
// Create the thumbnail part name
String contentType = ContentTypes
.getContentTypeFromFileExtension(filename);
- PackagePartName thumbnailPartName = null;
+ PackagePartName thumbnailPartName;
try {
thumbnailPartName = PackagingURIHelper.createPartName("/docProps/"
+ filename);
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java
index 537dd15e91..750f9cd71a 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java
@@ -29,10 +29,7 @@ import java.util.TreeMap;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.openxml4j.opc.PackagePartName;
-import org.apache.poi.openxml4j.opc.PackagingURIHelper;
+import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.util.DocumentHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -54,7 +51,7 @@ public abstract class ContentTypeManager {
/**
* Content type namespace
*/
- public static final String TYPES_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/content-types";
+ public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
/* Xml elements in content type part */
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
index 3652b89b17..08022e976c 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
@@ -304,13 +304,13 @@ implements XSLFShapeContainer, GroupShape {
@Override
public boolean getFlipHorizontal(){
CTGroupTransform2D xfrm = getXfrm();
- return (xfrm == null || !xfrm.isSetFlipH()) ? false : xfrm.getFlipH();
+ return !(xfrm == null || !xfrm.isSetFlipH()) && xfrm.getFlipH();
}
@Override
public boolean getFlipVertical(){
CTGroupTransform2D xfrm = getXfrm();
- return (xfrm == null || !xfrm.isSetFlipV()) ? false : xfrm.getFlipV();
+ return !(xfrm == null || !xfrm.isSetFlipV()) && xfrm.getFlipV();
}
@Override
@@ -333,7 +333,7 @@ implements XSLFShapeContainer, GroupShape {
// recursively update each shape
for(XSLFShape shape : gr.getShapes()) {
- XSLFShape newShape = null;
+ XSLFShape newShape;
if (shape instanceof XSLFTextBox) {
newShape = createTextBox();
} else if (shape instanceof XSLFAutoShape) {
diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
index abba81430f..2277d600a7 100644
--- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
+++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
@@ -41,7 +41,6 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.DocumentHelper;
@@ -55,7 +54,6 @@ import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
@@ -117,8 +115,7 @@ public class XSSFExportToXml implements Comparator{
* @param validate if true, validates the XML againts the XML Schema
* @throws SAXException
* @throws ParserConfigurationException
- * @throws TransformerException
- * @throws InvalidFormatException
+ * @throws TransformerException
*/
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{
List singleXMLCells = map.getRelatedSingleXMLCell();
@@ -128,10 +125,10 @@ public class XSSFExportToXml implements Comparator{
Document doc = DocumentHelper.createDocument();
- Element root = null;
+ final Element root;
if (isNamespaceDeclared()) {
- root=doc.createElementNS(getNamespace(),rootElement);
+ root = doc.createElementNS(getNamespace(),rootElement);
} else {
root = doc.createElementNS("", rootElement);
}
@@ -152,7 +149,6 @@ public class XSSFExportToXml implements Comparator{
tableMappings.put(commonXPath, table);
}
-
Collections.sort(xpaths,this);
for(String xpath : xpaths) {
@@ -167,8 +163,7 @@ public class XSSFExportToXml implements Comparator{
XSSFCell cell = simpleXmlCell.getReferencedCell();
if (cell!=null) {
Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false);
- STXmlDataType.Enum dataType = simpleXmlCell.getXmlDataType();
- mapCellOnNode(cell,currentNode,dataType);
+ mapCellOnNode(cell,currentNode);
//remove nodes which are empty in order to keep the output xml valid
if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) {
@@ -202,22 +197,15 @@ public class XSSFExportToXml implements Comparator{
XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex);
String localXPath = pointer.getLocalXPath();
Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
- STXmlDataType.Enum dataType = pointer.getXmlDataType();
-
- mapCellOnNode(cell,currentNode,dataType);
+ mapCellOnNode(cell,currentNode);
}
-
}
-
}
-
-
-
}
- } else {
+ } /*else {
// TODO: implement filtering management in xpath
- }
+ }*/
}
boolean isValid = true;
@@ -225,8 +213,6 @@ public class XSSFExportToXml implements Comparator{
isValid =isValid(doc);
}
-
-
if (isValid) {
/////////////////
@@ -275,7 +261,7 @@ public class XSSFExportToXml implements Comparator{
}
- private void mapCellOnNode(XSSFCell cell, Node node, STXmlDataType.Enum outputDataType) {
+ private void mapCellOnNode(XSSFCell cell, Node node) {
String value ="";
switch (cell.getCellTypeEnum()) {
@@ -349,11 +335,7 @@ public class XSSFExportToXml implements Comparator{
}
currentNode = selectedNode;
} else {
-
-
- Node attribute = createAttribute(doc, currentNode, axisName);
-
- currentNode = attribute;
+ currentNode = createAttribute(doc, currentNode, axisName);
}
}
return currentNode;
@@ -421,12 +403,11 @@ public class XSSFExportToXml implements Comparator{
for(int i =1;i {
}if ( leftIndex > rightIndex) {
return 1;
}
- } else {
+ } /*else {
// NOTE: the xpath doesn't match correctly in the schema
- }
+ }*/
}
}
@@ -483,7 +464,7 @@ public class XSSFExportToXml implements Comparator{
// Note: we expect that all the complex types are defined at root level
Node complexTypeNode = null;
if (!"".equals(complexTypeName)) {
- complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, complexTypeNode, complexTypeName);
+ complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, null, complexTypeName);
}
return complexTypeNode;
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
index 6c6574443a..6174af54ba 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
@@ -338,7 +338,11 @@ public class SXSSFCell implements Cell {
}
if(_value.getType()==CellType.FORMULA)
- ((StringFormulaValue)_value).setPreEvaluatedValue(value);
+ if(_value instanceof NumericFormulaValue) {
+ ((NumericFormulaValue) _value).setPreEvaluatedValue(Double.parseDouble(value));
+ } else {
+ ((StringFormulaValue) _value).setPreEvaluatedValue(value);
+ }
else
((PlainStringValue)_value).setValue(value);
} else {
@@ -956,6 +960,7 @@ public class SXSSFCell implements Cell {
}
/*package*/ void setFormulaType(CellType type)
{
+ Value prevValue = _value;
switch(type)
{
case NUMERIC:
@@ -983,7 +988,13 @@ public class SXSSFCell implements Cell {
throw new IllegalArgumentException("Illegal type " + type);
}
}
+
+ // if we had a Formula before, we should copy over the _value of the formula
+ if(prevValue instanceof FormulaValue) {
+ ((FormulaValue)_value)._value = ((FormulaValue)prevValue)._value;
+ }
}
+
//TODO: implement this correctly
@NotImplemented
/*package*/ CellType computeTypeFromFormula(String formula)
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
index 6993579cc0..331ad9a0fd 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
@@ -893,8 +893,11 @@ public class SXSSFWorkbook implements Workbook {
/**
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage}
- * on which this Workbook is based, if any. Has no effect on Workbooks
- * created from scratch.
+ * on which this Workbook is based, if any.
+ *
+ * Once this has been called, no further
+ * operations, updates or reads should be performed on the
+ * Workbook.
*/
@Override
public void close() throws IOException {
@@ -1003,12 +1006,25 @@ public class SXSSFWorkbook implements Workbook {
return _wb.getNames(name);
}
+ /**
+ * Returns all defined names
+ *
+ * @return all defined names
+ */
+ @Override
+ public List extends Name> getAllNames()
+ {
+ return _wb.getAllNames();
+ }
+
/**
* @param nameIndex position of the named range (0-based)
* @return the defined name at the specified index
* @throws IllegalArgumentException if the supplied index is invalid
+ * @deprecated 3.16. New projects should avoid accessing named ranges by index.
*/
@Override
+ @Deprecated
public Name getNameAt(int nameIndex)
{
return _wb.getNameAt(nameIndex);
@@ -1033,8 +1049,12 @@ public class SXSSFWorkbook implements Workbook {
*
* @param name the name of the defined name
* @return zero based index of the defined name. -1
if not found.
+ *
+ * @deprecated 3.16. New projects should avoid accessing named ranges by index.
+ * Use {@link #getName(String)} instead.
*/
@Override
+ @Deprecated
public int getNameIndex(String name)
{
return _wb.getNameIndex(name);
@@ -1044,8 +1064,11 @@ public class SXSSFWorkbook implements Workbook {
* Remove the defined name at the specified index
*
* @param index named range index (0 based)
+ *
+ * @deprecated 3.16. New projects should use {@link #removeName(Name)}.
*/
@Override
+ @Deprecated
public void removeName(int index)
{
_wb.removeName(index);
@@ -1054,10 +1077,24 @@ public class SXSSFWorkbook implements Workbook {
/**
* Remove a defined name by name
*
- * @param name the name of the defined name
+ * @param name the name of the defined name
+ *
+ * @deprecated 3.16. New projects should use {@link #removeName(Name)}.
*/
@Override
+ @Deprecated
public void removeName(String name)
+ {
+ _wb.removeName(name);
+ }
+
+ /**
+ * Remove the given defined name
+ *
+ * @param name the name to remove
+ */
+ @Override
+ public void removeName(Name name)
{
_wb.removeName(name);
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java
index f3c6bc2673..9c5e6ffb10 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java
@@ -232,7 +232,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
// Otherwise, try it as a named range
if (sheet == null) {
- if (_uBook.getNameIndex(name) > -1) {
+ if (!_uBook.getNames(name).isEmpty()) {
return new NameXPxg(null, name);
}
return null;
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFFormulaEvaluator.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFFormulaEvaluator.java
index 5fe8660b1d..c6c030b957 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFFormulaEvaluator.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFFormulaEvaluator.java
@@ -17,12 +17,9 @@
package org.apache.poi.xssf.usermodel;
-import java.util.Map;
-
-import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
+import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.WorkbookEvaluator;
-import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NumberEval;
@@ -31,28 +28,16 @@ import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.util.Internal;
/**
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
*/
-public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
- private WorkbookEvaluator _bookEvaluator;
-
+public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
- _bookEvaluator = bookEvaluator;
+ super(bookEvaluator);
}
- /**
- * Should be called whenever there are major changes (e.g. moving sheets) to input cells
- * in the evaluated workbook.
- * Failure to call this method after changing cell values will cause incorrect behaviour
- * of the evaluate~ methods of this class
- */
- public void clearAllCachedResultValues() {
- _bookEvaluator.clearAllCachedResultValues();
- }
public void notifySetFormula(Cell cell) {
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
}
@@ -63,60 +48,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
}
- /**
- * If cell contains a formula, the formula is evaluated and returned,
- * else the CellValue simply copies the appropriate cell value from
- * the cell and also its cell type. This method should be preferred over
- * evaluateInCell() when the call should not modify the contents of the
- * original cell.
- * @param cell
- */
- public CellValue evaluate(Cell cell) {
- if (cell == null) {
- return null;
- }
-
- switch (cell.getCellTypeEnum()) {
- case BOOLEAN:
- return CellValue.valueOf(cell.getBooleanCellValue());
- case ERROR:
- return CellValue.getError(cell.getErrorCellValue());
- case FORMULA:
- return evaluateFormulaCellValue(cell);
- case NUMERIC:
- return new CellValue(cell.getNumericCellValue());
- case STRING:
- return new CellValue(cell.getRichStringCellValue().getString());
- case BLANK:
- return null;
- default:
- throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
- }
- }
-
-
- /**
- * If cell contains formula, it evaluates the formula,
- * and saves the result of the formula. The cell
- * remains as a formula cell.
- * Else if cell does not contain formula, this method leaves
- * the cell unchanged.
- * Note that the type of the formula result is returned,
- * so you know what kind of value is also stored with
- * the formula.
- *
- * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
- *
- * Be aware that your cell will hold both the formula,
- * and the result. If you want the cell replaced with
- * the result of the formula, use {@link #evaluate(org.apache.poi.ss.usermodel.Cell)} }
- * @param cell The cell to evaluate
- * @return The type of the formula result (the cell's type remains as CellType.FORMULA however)
- */
- public int evaluateFormulaCell(Cell cell) {
- return evaluateFormulaCellEnum(cell).getCode();
- }
-
/**
* If cell contains formula, it evaluates the formula,
* and saves the result of the formula. The cell
@@ -164,27 +95,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
setCellValue(cell, cv);
}
}
- private static void setCellType(Cell cell, CellValue cv) {
- CellType cellType = cv.getCellType();
- switch (cellType) {
- case BOOLEAN:
- case ERROR:
- case NUMERIC:
- case STRING:
- cell.setCellType(cellType);
- return;
- case BLANK:
- // never happens - blanks eventually get translated to zero
- throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
- case FORMULA:
- // this will never happen, we have already evaluated the formula
- throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
- default:
- throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
-
- }
-
- }
private static void setCellValue(Cell cell, CellValue cv) {
CellType cellType = cv.getCellType();
@@ -218,7 +128,7 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
/**
* Returns a CellValue wrapper around the supplied ValueEval instance.
*/
- private CellValue evaluateFormulaCellValue(Cell cell) {
+ protected CellValue evaluateFormulaCellValue(Cell cell) {
EvaluationCell evalCell = toEvaluationCell(cell);
ValueEval eval = _bookEvaluator.evaluate(evalCell);
if (eval instanceof NumberEval) {
@@ -238,22 +148,4 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
}
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
}
-
- public void setupReferencedWorkbooks(Map evaluators) {
- CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
- }
-
- public WorkbookEvaluator _getWorkbookEvaluator() {
- return _bookEvaluator;
- }
-
- /** {@inheritDoc} */
- public void setIgnoreMissingWorkbooks(boolean ignore){
- _bookEvaluator.setIgnoreMissingWorkbooks(ignore);
- }
-
- /** {@inheritDoc} */
- public void setDebugEvaluationOutputForNextEval(boolean value){
- _bookEvaluator.setDebugEvaluationOutputForNextEval(value);
- }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
index ec9ecd4621..fc456b7e58 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
@@ -17,7 +17,7 @@
package org.apache.poi.xssf.usermodel;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.IStabilityClassifier;
import org.apache.poi.ss.formula.WorkbookEvaluator;
@@ -88,7 +88,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
* cells, and calling evaluateFormulaCell on each one.
*/
public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
- HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
+ BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
}
/**
* Loops over all cells in all sheets of the supplied
@@ -102,7 +102,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
* cells, and calling evaluateFormulaCell on each one.
*/
public void evaluateAll() {
- HSSFFormulaEvaluator.evaluateAllFormulaCells(_book);
+ evaluateAllFormulaCells(_book, this);
}
/**
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFName.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFName.java
index 462bd6517f..0710626201 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFName.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFName.java
@@ -167,19 +167,18 @@ public final class XSSFName implements Name {
public void setNameName(String name) {
validateName(name);
+ String oldName = getNameName();
int sheetIndex = getSheetIndex();
- int numberOfNames = _workbook.getNumberOfNames();
//Check to ensure no other names have the same case-insensitive name at the same scope
- for (int i = 0; i < numberOfNames; i++) {
- XSSFName nm = _workbook.getNameAt(i);
- if ((nm != this)
- && name.equalsIgnoreCase(nm.getNameName())
- && (sheetIndex == nm.getSheetIndex())) {
+ for (XSSFName foundName : _workbook.getNames(name)) {
+ if (foundName.getSheetIndex() == sheetIndex && foundName != this) {
String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name;
throw new IllegalArgumentException(msg);
}
}
_ctName.setName(name);
+ //Need to update the name -> named ranges map
+ _workbook.updateName(this, oldName);
}
public String getRefersToFormula() {
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
index 2271e0b4d8..5f1da12ecc 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
@@ -18,8 +18,8 @@
package org.apache.poi.xssf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
-import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
-import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
+import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;
+import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
index 1e9b3d6cee..afddcd9c4b 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
@@ -18,8 +18,8 @@
package org.apache.poi.xssf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
-import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
-import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
+import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;
+import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -29,16 +29,20 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
import javax.xml.namespace.QName;
+import org.apache.commons.collections4.ListValuedMap;
+import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
@@ -59,6 +63,7 @@ import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.usermodel.Sheet;
@@ -140,6 +145,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/
private List sheets;
+ /**
+ * this holds the XSSFName objects attached to this workbook, keyed by lower-case name
+ */
+ private ListValuedMap namedRangesByName;
+
/**
* this holds the XSSFName objects attached to this workbook
*/
@@ -442,6 +452,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
stylesSource.setWorkbook(this);
namedRanges = new ArrayList();
+ namedRangesByName = new ArrayListValuedHashMap();
sheets = new ArrayList();
pivotTables = new ArrayList();
}
@@ -733,8 +744,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public XSSFName createName() {
CTDefinedName ctName = CTDefinedName.Factory.newInstance();
ctName.setName("");
+ return createAndStoreName(ctName);
+ }
+
+ private XSSFName createAndStoreName(CTDefinedName ctName) {
XSSFName name = new XSSFName(ctName, this);
namedRanges.add(name);
+ namedRangesByName.put(ctName.getName().toLowerCase(Locale.ENGLISH), name);
return name;
}
@@ -938,28 +954,47 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
return stylesSource.getFontAt(idx);
}
+ /**
+ * Get the first named range with the given name.
+ *
+ * Note: names of named ranges are not unique as they are scoped by sheet.
+ * {@link #getNames(String name)} returns all named ranges with the given name.
+ *
+ * @param name named range name
+ * @return XSSFName with the given name. null
is returned no named range could be found.
+ */
@Override
public XSSFName getName(String name) {
- int nameIndex = getNameIndex(name);
- if (nameIndex < 0) {
+ Collection list = getNames(name);
+ if (list.isEmpty()) {
return null;
}
- return namedRanges.get(nameIndex);
+ return list.iterator().next();
}
+ /**
+ * Get the named ranges with the given name.
+ * Note:Excel named ranges are case-insensitive and
+ * this method performs a case-insensitive search.
+ *
+ * @param name named range name
+ * @return list of XSSFNames with the given name. An empty list if no named ranges could be found
+ */
@Override
public List getNames(String name) {
- List names = new ArrayList();
- for(XSSFName nr : namedRanges) {
- if(nr.getNameName().equals(name)) {
- names.add(nr);
- }
- }
-
- return names;
+ return Collections.unmodifiableList(namedRangesByName.get(name.toLowerCase(Locale.ENGLISH)));
}
+ /**
+ * Get the named range at the given index.
+ *
+ * @param nameIndex the index of the named range
+ * @return the XSSFName at the given index
+ *
+ * @deprecated 3.16. New projects should avoid accessing named ranges by index.
+ */
@Override
+ @Deprecated
public XSSFName getNameAt(int nameIndex) {
int nNames = namedRanges.size();
if (nNames < 1) {
@@ -973,21 +1008,30 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
}
/**
- * Gets the named range index by his name
- * Note:Excel named ranges are case-insensitive and
- * this method performs a case-insensitive search.
+ * Get a list of all the named ranges in the workbook.
*
- * @param name named range name
- * @return named range index
+ * @return list of XSSFNames in the workbook
*/
@Override
+ public List getAllNames() {
+ return Collections.unmodifiableList(namedRanges);
+ }
+
+ /**
+ * Gets the named range index by name.
+ *
+ * @param name named range name
+ * @return named range index. -1
is returned if no named ranges could be found.
+ *
+ * @deprecated 3.16. New projects should avoid accessing named ranges by index.
+ * Use {@link #getName(String)} instead.
+ */
+ @Override
+ @Deprecated
public int getNameIndex(String name) {
- int i = 0;
- for(XSSFName nr : namedRanges) {
- if(nr.getNameName().equals(name)) {
- return i;
- }
- i++;
+ XSSFName nm = getName(name);
+ if (nm != null) {
+ return namedRanges.indexOf(nm);
}
return -1;
}
@@ -1258,22 +1302,40 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
return getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
}
+ /**
+ * Remove the named range at the given index.
+ *
+ * @param nameIndex the index of the named range name to remove
+ *
+ * @deprecated 3.16. New projects should use {@link #removeName(Name)}.
+ */
@Override
+ @Deprecated
public void removeName(int nameIndex) {
- namedRanges.remove(nameIndex);
+ removeName(getNameAt(nameIndex));
}
+ /**
+ * Remove the first named range found with the given name.
+ *
+ * Note: names of named ranges are not unique (name + sheet
+ * index is unique), so {@link #removeName(Name)} should
+ * be used if possible.
+ *
+ * @param name the named range name to remove
+ *
+ * @throws IllegalArgumentException if no named range could be found
+ *
+ * @deprecated 3.16. New projects should use {@link #removeName(Name)}.
+ */
@Override
+ @Deprecated
public void removeName(String name) {
- int idx = 0;
- for (XSSFName nm : namedRanges) {
- if(nm.getNameName().equalsIgnoreCase(name)) {
- removeName(idx);
- return;
- }
- idx++;
+ List names = namedRangesByName.get(name.toLowerCase(Locale.ENGLISH));
+ if (names.isEmpty()) {
+ throw new IllegalArgumentException("Named range was not found: " + name);
}
- throw new IllegalArgumentException("Named range was not found: " + name);
+ removeName(names.get(0));
}
@@ -1282,13 +1344,24 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
* (name + sheet index is unique), this method is more accurate.
*
* @param name the name to remove.
+ *
+ * @throws IllegalArgumentException if the named range is not a part of this XSSFWorkbook
*/
- void removeName(XSSFName name) {
- if (!namedRanges.remove(name)) {
+ @Override
+ public void removeName(Name name) {
+ if (!namedRangesByName.removeMapping(name.getNameName().toLowerCase(Locale.ENGLISH), name)
+ || !namedRanges.remove(name)) {
throw new IllegalArgumentException("Name was not found: " + name);
}
}
+ void updateName(XSSFName name, String oldName) {
+ if (!namedRangesByName.removeMapping(oldName.toLowerCase(Locale.ENGLISH), name)) {
+ throw new IllegalArgumentException("Name was not found: " + name);
+ }
+ namedRangesByName.put(name.getNameName().toLowerCase(Locale.ENGLISH), name);
+ }
+
/**
* Delete the printarea for the sheet specified
@@ -1297,13 +1370,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/
@Override
public void removePrintArea(int sheetIndex) {
- int cont = 0;
- for (XSSFName name : namedRanges) {
- if (name.getNameName().equals(XSSFName.BUILTIN_PRINT_AREA) && name.getSheetIndex() == sheetIndex) {
- namedRanges.remove(cont);
- break;
- }
- cont++;
+ XSSFName name = getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);
+ if (name != null) {
+ removeName(name);
}
}
@@ -1369,17 +1438,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
}
//adjust indices of names ranges
- for (Iterator it = namedRanges.iterator(); it.hasNext();) {
- XSSFName nm = it.next();
+ List toRemove = new ArrayList();
+ for (XSSFName nm : namedRanges) {
CTDefinedName ct = nm.getCTName();
if(!ct.isSetLocalSheetId()) continue;
if (ct.getLocalSheetId() == index) {
- it.remove();
+ toRemove.add(nm);
} else if (ct.getLocalSheetId() > index){
// Bump down by one, so still points at the same sheet
ct.setLocalSheetId(ct.getLocalSheetId()-1);
}
}
+ for (XSSFName nm : toRemove) {
+ removeName(nm);
+ }
}
/**
@@ -1514,8 +1586,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
}
XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
- for (XSSFName name : namedRanges) {
- if (name.getNameName().equalsIgnoreCase(builtInCode) && name.getSheetIndex() == sheetNumber) {
+ for (XSSFName name : namedRangesByName.get(builtInCode.toLowerCase(Locale.ENGLISH))) {
+ if (name.getSheetIndex() == sheetNumber) {
return name;
}
}
@@ -1537,15 +1609,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
nameRecord.setName(builtInName);
nameRecord.setLocalSheetId(sheetNumber);
- XSSFName name = new XSSFName(nameRecord, this);
- for (XSSFName nr : namedRanges) {
- if (nr.equals(name))
- throw new POIXMLException("Builtin (" + builtInName
- + ") already exists for sheet (" + sheetNumber + ")");
+ if (getBuiltInName(builtInName, sheetNumber) != null) {
+ throw new POIXMLException("Builtin (" + builtInName
+ + ") already exists for sheet (" + sheetNumber + ")");
}
- namedRanges.add(name);
- return name;
+ return createAndStoreName(nameRecord);
}
/**
@@ -1665,10 +1734,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
}
private void reprocessNamedRanges() {
+ namedRangesByName = new ArrayListValuedHashMap();
namedRanges = new ArrayList();
if(workbook.isSetDefinedNames()) {
for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
- namedRanges.add(new XSSFName(ctName, this));
+ createAndStoreName(ctName);
}
}
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFFormulaUtils.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFFormulaUtils.java
index 1d146c09c6..ef0c5ea633 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFFormulaUtils.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFFormulaUtils.java
@@ -65,9 +65,7 @@ public final class XSSFFormulaUtils {
*/
public void updateSheetName(final int sheetIndex, final String oldName, final String newName) {
// update named ranges
- final int numberOfNames = _wb.getNumberOfNames();
- for (int i = 0; i < numberOfNames; i++) {
- XSSFName nm = _wb.getNameAt(i);
+ for (XSSFName nm : _wb.getAllNames()) {
if (nm.getSheetIndex() == -1 || nm.getSheetIndex() == sheetIndex) {
updateName(nm, oldName, newName);
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPasswordHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPasswordHelper.java
new file mode 100644
index 0000000000..46e47f688d
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPasswordHelper.java
@@ -0,0 +1,136 @@
+/*
+ * ====================================================================
+ * 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.xssf.usermodel.helpers;
+
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Locale;
+
+import javax.xml.bind.DatatypeConverter;
+import javax.xml.namespace.QName;
+
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.util.Internal;
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+
+@Internal(since="3.15 beta 3")
+public final class XSSFPasswordHelper {
+ private XSSFPasswordHelper() {
+ // no instances of this static class
+ }
+
+ /**
+ * Sets the XORed or hashed password
+ *
+ * @param xobj the xmlbeans object which contains the password attributes
+ * @param password the password, if null, the password attributes will be removed
+ * @param hashAlgo the hash algorithm, if null the password will be XORed
+ * @param prefix the prefix of the password attributes, may be null
+ */
+ public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
+ XmlCursor cur = xobj.newCursor();
+
+ if (password == null) {
+ cur.removeAttribute(getAttrName(prefix, "password"));
+ cur.removeAttribute(getAttrName(prefix, "algorithmName"));
+ cur.removeAttribute(getAttrName(prefix, "hashValue"));
+ cur.removeAttribute(getAttrName(prefix, "saltValue"));
+ cur.removeAttribute(getAttrName(prefix, "spinCount"));
+ return;
+ }
+
+ cur.toFirstContentToken();
+ if (hashAlgo == null) {
+ int hash = CryptoFunctions.createXorVerifier1(password);
+ cur.insertAttributeWithValue(getAttrName(prefix, "password"),
+ String.format(Locale.ROOT, "%04X", hash).toUpperCase(Locale.ROOT));
+ } else {
+ SecureRandom random = new SecureRandom();
+ byte salt[] = random.generateSeed(16);
+
+ // Iterations specifies the number of times the hashing function shall be iteratively run (using each
+ // iteration's result as the input for the next iteration).
+ int spinCount = 100000;
+
+ // Implementation Notes List:
+ // --> In this third stage, the reversed byte order legacy hash from the second stage shall
+ // be converted to Unicode hex string representation
+ byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
+
+ cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
+ cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
+ cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
+ cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
+ }
+ cur.dispose();
+ }
+
+ /**
+ * Validates the password, i.e.
+ * calculates the hash of the given password and compares it against the stored hash
+ *
+ * @param xobj the xmlbeans object which contains the password attributes
+ * @param password the password, if null the method will always return false,
+ * even if there's no password set
+ * @param prefix the prefix of the password attributes, may be null
+ *
+ * @return true, if the hashes match
+ */
+ public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
+ // TODO: is "velvetSweatshop" the default password?
+ if (password == null) return false;
+
+ XmlCursor cur = xobj.newCursor();
+ String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
+ String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
+ String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
+ String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
+ String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
+ cur.dispose();
+
+ if (xorHashVal != null) {
+ int hash1 = Integer.parseInt(xorHashVal, 16);
+ int hash2 = CryptoFunctions.createXorVerifier1(password);
+ return hash1 == hash2;
+ } else {
+ if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
+ return false;
+ }
+
+ byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
+ HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
+ byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
+ int spinCnt = Integer.parseInt(spinCount);
+ byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
+ return Arrays.equals(hash1, hash2);
+ }
+ }
+
+
+ private static QName getAttrName(String prefix, String name) {
+ if (prefix == null || "".equals(prefix)) {
+ return new QName(name);
+ } else {
+ return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
+ }
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
index c910499485..4e3c90819c 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
@@ -1,130 +1,60 @@
-/*
- * ====================================================================
- * 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.xssf.usermodel.helpers;
-
-import java.security.SecureRandom;
-import java.util.Arrays;
-import java.util.Locale;
-
-import javax.xml.bind.DatatypeConverter;
-import javax.xml.namespace.QName;
-
-import org.apache.poi.poifs.crypt.CryptoFunctions;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-import org.apache.xmlbeans.XmlCursor;
-import org.apache.xmlbeans.XmlObject;
-
-public class XSSFPaswordHelper {
- /**
- * Sets the XORed or hashed password
- *
- * @param xobj the xmlbeans object which contains the password attributes
- * @param password the password, if null, the password attributes will be removed
- * @param hashAlgo the hash algorithm, if null the password will be XORed
- * @param prefix the prefix of the password attributes, may be null
- */
- public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
- XmlCursor cur = xobj.newCursor();
-
- if (password == null) {
- cur.removeAttribute(getAttrName(prefix, "password"));
- cur.removeAttribute(getAttrName(prefix, "algorithmName"));
- cur.removeAttribute(getAttrName(prefix, "hashValue"));
- cur.removeAttribute(getAttrName(prefix, "saltValue"));
- cur.removeAttribute(getAttrName(prefix, "spinCount"));
- return;
- }
-
- cur.toFirstContentToken();
- if (hashAlgo == null) {
- int hash = CryptoFunctions.createXorVerifier1(password);
- cur.insertAttributeWithValue(getAttrName(prefix, "password"),
- Integer.toHexString(hash).toUpperCase(Locale.ROOT));
- } else {
- SecureRandom random = new SecureRandom();
- byte salt[] = random.generateSeed(16);
-
- // Iterations specifies the number of times the hashing function shall be iteratively run (using each
- // iteration's result as the input for the next iteration).
- int spinCount = 100000;
-
- // Implementation Notes List:
- // --> In this third stage, the reversed byte order legacy hash from the second stage shall
- // be converted to Unicode hex string representation
- byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
-
- cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
- cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
- cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
- cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
- }
- cur.dispose();
- }
-
- /**
- * Validates the password, i.e.
- * calculates the hash of the given password and compares it against the stored hash
- *
- * @param xobj the xmlbeans object which contains the password attributes
- * @param password the password, if null the method will always return false,
- * even if there's no password set
- * @param prefix the prefix of the password attributes, may be null
- *
- * @return true, if the hashes match
- */
- public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
- // TODO: is "velvetSweatshop" the default password?
- if (password == null) return false;
-
- XmlCursor cur = xobj.newCursor();
- String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
- String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
- String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
- String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
- String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
- cur.dispose();
-
- if (xorHashVal != null) {
- int hash1 = Integer.parseInt(xorHashVal, 16);
- int hash2 = CryptoFunctions.createXorVerifier1(password);
- return hash1 == hash2;
- } else {
- if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
- return false;
- }
-
- byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
- HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
- byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
- int spinCnt = Integer.parseInt(spinCount);
- byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
- return Arrays.equals(hash1, hash2);
- }
- }
-
-
- private static QName getAttrName(String prefix, String name) {
- if (prefix == null || "".equals(prefix)) {
- return new QName(name);
- } else {
- return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
- }
- }
-}
+/*
+ * ====================================================================
+ * 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.xssf.usermodel.helpers;
+
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Removal;
+import org.apache.xmlbeans.XmlObject;
+
+/**
+ * @deprecated POI 3.15 beta 3. Use {@link XSSFPasswordHelper} instead.
+ */
+@Internal(since="3.15 beta 3")
+@Deprecated
+@Removal(version="3.17")
+public class XSSFPaswordHelper {
+ /**
+ * Sets the XORed or hashed password
+ *
+ * @param xobj the xmlbeans object which contains the password attributes
+ * @param password the password, if null, the password attributes will be removed
+ * @param hashAlgo the hash algorithm, if null the password will be XORed
+ * @param prefix the prefix of the password attributes, may be null
+ */
+ public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
+ XSSFPasswordHelper.setPassword(xobj, password, hashAlgo, prefix);
+ }
+
+ /**
+ * Validates the password, i.e.
+ * calculates the hash of the given password and compares it against the stored hash
+ *
+ * @param xobj the xmlbeans object which contains the password attributes
+ * @param password the password, if null the method will always return false,
+ * even if there's no password set
+ * @param prefix the prefix of the password attributes, may be null
+ *
+ * @return true, if the hashes match
+ */
+ public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
+ return XSSFPasswordHelper.validatePassword(xobj, password, prefix);
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java
index 63104dd9e2..d11ed1fa81 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java
@@ -83,9 +83,7 @@ public final class XSSFRowShifter extends RowShifter {
public void updateNamedRanges(FormulaShifter shifter) {
Workbook wb = sheet.getWorkbook();
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);
- final int numberOfNames = wb.getNumberOfNames();
- for (int i = 0; i < numberOfNames; i++) {
- Name name = wb.getNameAt(i);
+ for (Name name : wb.getAllNames()) {
String formula = name.getRefersToFormula();
int sheetIndex = name.getSheetIndex();
final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references
diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/internal/TestContentTypeManager.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/internal/TestContentTypeManager.java
index 9acf0d10bc..936d0f9e8c 100644
--- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/internal/TestContentTypeManager.java
+++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/internal/TestContentTypeManager.java
@@ -18,6 +18,7 @@
package org.apache.poi.openxml4j.opc.internal;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
@@ -44,16 +45,21 @@ public final class TestContentTypeManager {
// Retrieves core properties part
OPCPackage p = OPCPackage.open(filepath, PackageAccess.READ);
- PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
- PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
- PackagePart coreDocument = p.getPart(corePropertiesRelationship);
-
- assertEquals("application/vnd.openxmlformats-package.core-properties+xml", coreDocument.getContentType());
+ try {
+ PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
+ PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
+ PackagePart coreDocument = p.getPart(corePropertiesRelationship);
- // TODO - finish writing this test
- assumeTrue("finish writing this test", false);
-
- ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
+ assertEquals("application/vnd.openxmlformats-package.core-properties+xml", coreDocument.getContentType());
+
+ // TODO - finish writing this test
+ assumeTrue("finish writing this test", false);
+
+ ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
+ assertNotNull(ctm);
+ } finally {
+ p.close();
+ }
}
/**
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
index 3280a9121b..2be21e830c 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
@@ -115,25 +115,25 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
assertFalse(wb.isMacroEnabled());
assertEquals(3, wb.getNumberOfNames());
- assertEquals(0, wb.getNameAt(0).getCTName().getLocalSheetId());
- assertFalse(wb.getNameAt(0).getCTName().isSetLocalSheetId());
- assertEquals("SheetA!$A$1", wb.getNameAt(0).getRefersToFormula());
- assertEquals("SheetA", wb.getNameAt(0).getSheetName());
+ assertEquals(0, wb.getName("SheetAA1").getCTName().getLocalSheetId());
+ assertFalse(wb.getName("SheetAA1").getCTName().isSetLocalSheetId());
+ assertEquals("SheetA!$A$1", wb.getName("SheetAA1").getRefersToFormula());
+ assertEquals("SheetA", wb.getName("SheetAA1").getSheetName());
- assertEquals(0, wb.getNameAt(1).getCTName().getLocalSheetId());
- assertFalse(wb.getNameAt(1).getCTName().isSetLocalSheetId());
- assertEquals("SheetB!$A$1", wb.getNameAt(1).getRefersToFormula());
- assertEquals("SheetB", wb.getNameAt(1).getSheetName());
+ assertEquals(0, wb.getName("SheetBA1").getCTName().getLocalSheetId());
+ assertFalse(wb.getName("SheetBA1").getCTName().isSetLocalSheetId());
+ assertEquals("SheetB!$A$1", wb.getName("SheetBA1").getRefersToFormula());
+ assertEquals("SheetB", wb.getName("SheetBA1").getSheetName());
- assertEquals(0, wb.getNameAt(2).getCTName().getLocalSheetId());
- assertFalse(wb.getNameAt(2).getCTName().isSetLocalSheetId());
- assertEquals("SheetC!$A$1", wb.getNameAt(2).getRefersToFormula());
- assertEquals("SheetC", wb.getNameAt(2).getSheetName());
+ assertEquals(0, wb.getName("SheetCA1").getCTName().getLocalSheetId());
+ assertFalse(wb.getName("SheetCA1").getCTName().isSetLocalSheetId());
+ assertEquals("SheetC!$A$1", wb.getName("SheetCA1").getRefersToFormula());
+ assertEquals("SheetC", wb.getName("SheetCA1").getSheetName());
// Save and re-load, still there
XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
assertEquals(3, nwb.getNumberOfNames());
- assertEquals("SheetA!$A$1", nwb.getNameAt(0).getRefersToFormula());
+ assertEquals("SheetA!$A$1", nwb.getName("SheetAA1").getRefersToFormula());
nwb.close();
wb.close();
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
index 566944d18d..6dcaef9603 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
@@ -154,7 +154,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
evaluator.evaluate(cXSL_cell);
fail("Without a fix for #56752, shouldn't be able to evaluate a " +
"reference to a non-provided linked workbook");
- } catch(Exception e) {}
+ } catch(Exception e) {
+ // expected here
+ }
// Setup the environment
Map evaluators = new HashMap();
@@ -171,8 +173,19 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
evaluator.evaluate(c);
}
}
+ // And evaluate the other way too
+ evaluator.evaluateAll();
- // Evaluate and check results
+ // Static evaluator won't work, as no references passed in
+ try {
+ XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
+ fail("Static method lacks references, shouldn't work");
+ } catch(Exception e) {
+ // expected here
+ }
+
+
+ // Evaluate specific cells and check results
assertEquals("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
@@ -196,7 +209,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
try {
cXSLX_nw_cell.setCellFormula("[alt.xlsx]Sheet1!$A$1");
fail("New workbook not linked, shouldn't be able to add");
- } catch (Exception e) {}
+ } catch (Exception e) {
+ // expected here
+ }
// Link and re-try
Workbook alt = new XSSFWorkbook();
@@ -651,4 +666,20 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
private Cell getCell(Sheet sheet, int rowNo, int column) {
return sheet.getRow(rowNo).getCell(column);
}
+
+ @Test
+ public void test59736() {
+ Workbook wb = XSSFTestDataSamples.openSampleWorkbook("59736.xlsx");
+ FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+ Cell cell = wb.getSheetAt(0).getRow(0).getCell(0);
+ assertEquals(1, cell.getNumericCellValue(), 0.001);
+
+ cell = wb.getSheetAt(0).getRow(1).getCell(0);
+ CellValue value = evaluator.evaluate(cell);
+ assertEquals(1, value.getNumberValue(), 0.001);
+
+ cell = wb.getSheetAt(0).getRow(2).getCell(0);
+ value = evaluator.evaluate(cell);
+ assertEquals(1, value.getNumberValue(), 0.001);
+ }
}
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java
index 3e0f0b1651..a188a11ed3 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java
@@ -53,9 +53,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
//sheet.createFreezePane(0, 3);
}
assertEquals(1, wb.getNumberOfNames());
- XSSFName nr1 = wb.getNameAt(0);
+ XSSFName nr1 = wb.getName(XSSFName.BUILTIN_PRINT_TITLE);
- assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr1.getNameName());
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
//remove the columns part
@@ -77,9 +76,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
wb.close();
assertEquals(1, nwb.getNumberOfNames());
- nr1 = nwb.getNameAt(0);
+ nr1 = nwb.getName(XSSFName.BUILTIN_PRINT_TITLE);
- assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr1.getNameName());
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
// check that setting RR&C on a second sheet causes a new Print_Titles built-in
@@ -89,7 +87,7 @@ public final class TestXSSFName extends BaseTestNamedRange {
sheet2.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));
assertEquals(2, nwb.getNumberOfNames());
- XSSFName nr2 = nwb.getNameAt(1);
+ XSSFName nr2 = nwb.getNames(XSSFName.BUILTIN_PRINT_TITLE).get(1);
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr2.getNameName());
assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula());
@@ -98,4 +96,38 @@ public final class TestXSSFName extends BaseTestNamedRange {
sheet2.setRepeatingColumns(null);
nwb.close();
}
+
+ @Test
+ public void testSetNameName() throws Exception {
+ // Test that renaming named ranges doesn't break our new named range map
+ XSSFWorkbook wb = new XSSFWorkbook();
+ wb.createSheet("First Sheet");
+
+ // Two named ranges called "name1", one scoped to sheet1 and one globally
+ XSSFName nameSheet1 = wb.createName();
+ nameSheet1.setNameName("name1");
+ nameSheet1.setRefersToFormula("'First Sheet'!$A$1");
+ nameSheet1.setSheetIndex(0);
+
+ XSSFName nameGlobal = wb.createName();
+ nameGlobal.setNameName("name1");
+ nameGlobal.setRefersToFormula("'First Sheet'!$B$1");
+
+ // Rename sheet-scoped name to "name2", check everything is updated properly
+ // and that the other name is unaffected
+ nameSheet1.setNameName("name2");
+ assertEquals(1, wb.getNames("name1").size());
+ assertEquals(1, wb.getNames("name2").size());
+ assertEquals(nameGlobal, wb.getName("name1"));
+ assertEquals(nameSheet1, wb.getName("name2"));
+
+ // Rename the other name to "name" and check everything again
+ nameGlobal.setNameName("name2");
+ assertEquals(0, wb.getNames("name1").size());
+ assertEquals(2, wb.getNames("name2").size());
+ assertTrue(wb.getNames("name2").contains(nameGlobal));
+ assertTrue(wb.getNames("name2").contains(nameSheet1));
+
+ wb.close();
+ }
}
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
index a9b0d1f0b5..689e999bcb 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
@@ -80,6 +80,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex;
public final class TestXSSFSheet extends BaseTestXSheet {
@@ -1099,6 +1100,30 @@ public final class TestXSSFSheet extends BaseTestXSheet {
wb.close();
}
+ @Test
+ public void protectSheet_emptyPassword() throws IOException {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ XSSFSheet sheet = wb.createSheet();
+ CTSheetProtection pr = sheet.getCTWorksheet().getSheetProtection();
+ assertNull("CTSheetProtection should be null by default", pr);
+ String password = "";
+ sheet.protectSheet(password);
+ pr = sheet.getCTWorksheet().getSheetProtection();
+ assertNotNull("CTSheetProtection should be not null", pr);
+ assertTrue("sheet protection should be on", pr.isSetSheet());
+ assertTrue("object protection should be on", pr.isSetObjects());
+ assertTrue("scenario protection should be on", pr.isSetScenarios());
+ int hashVal = CryptoFunctions.createXorVerifier1(password);
+ STUnsignedShortHex xpassword = pr.xgetPassword();
+ int actualVal = Integer.parseInt(xpassword.getStringValue(),16);
+ assertEquals("well known value for top secret hash should match", hashVal, actualVal);
+
+ sheet.protectSheet(null);
+ assertNull("protectSheet(null) should unset CTSheetProtection", sheet.getCTWorksheet().getSheetProtection());
+
+ wb.close();
+ }
+
@Test
public void protectSheet_lowlevel_2013() throws IOException {
String password = "test";
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
index c3420c780a..7f832c4d9c 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
@@ -1140,4 +1140,44 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
wb.close();
}
+
+ @Test
+ public void testRemoveSheet() throws IOException {
+ // Test removing a sheet maintains the named ranges correctly
+ XSSFWorkbook wb = new XSSFWorkbook();
+ wb.createSheet("Sheet1");
+ wb.createSheet("Sheet2");
+
+ XSSFName sheet1Name = wb.createName();
+ sheet1Name.setNameName("name1");
+ sheet1Name.setSheetIndex(0);
+ sheet1Name.setRefersToFormula("Sheet1!$A$1");
+
+ XSSFName sheet2Name = wb.createName();
+ sheet2Name.setNameName("name1");
+ sheet2Name.setSheetIndex(1);
+ sheet2Name.setRefersToFormula("Sheet2!$A$1");
+
+ assertTrue(wb.getAllNames().contains(sheet1Name));
+ assertTrue(wb.getAllNames().contains(sheet2Name));
+
+ assertEquals(2, wb.getNames("name1").size());
+ assertEquals(sheet1Name, wb.getNames("name1").get(0));
+ assertEquals(sheet2Name, wb.getNames("name1").get(1));
+
+ // Remove sheet1, we should only have sheet2Name now
+ wb.removeSheetAt(0);
+
+ assertFalse(wb.getAllNames().contains(sheet1Name));
+ assertTrue(wb.getAllNames().contains(sheet2Name));
+ assertEquals(1, wb.getNames("name1").size());
+ assertEquals(sheet2Name, wb.getNames("name1").get(0));
+
+ // Check by index as well for sanity
+ assertEquals(1, wb.getNumberOfNames());
+ assertEquals(0, wb.getNameIndex("name1"));
+ assertEquals(sheet2Name, wb.getNameAt(0));
+
+ wb.close();
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
index f9d53dcbda..fe22c03eff 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
@@ -571,20 +571,39 @@ public final class HWPFDocument extends HWPFDocumentCore {
return _fields;
}
+ /**
+ * Warning - not currently implemented for HWPF!
+ */
@Override
public void write() throws IOException {
+ // TODO Implement
throw new IllegalStateException("Coming soon!");
}
+
+ /**
+ * Writes out the word file that is represented by an instance of this class.
+ *
+ * If the {@link File} exists, it will be replaced, otherwise a new one
+ * will be created
+ *
+ * @param newFile The File to write to.
+ * @throws IOException If there is an unexpected IOException from writing
+ * to the File.
+ *
+ * @since 3.15 beta 3
+ */
@Override
public void write(File newFile) throws IOException {
- throw new IllegalStateException("Coming soon!");
+ NPOIFSFileSystem pfs = POIFSFileSystem.create(newFile);
+ write(pfs, true);
+ pfs.writeFilesystem();
}
/**
* Writes out the word file that is represented by an instance of this class.
*
- * If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
- * or has a high cost/latency associated with each written byte,
+ * For better performance when writing to files, use {@link #write(File)}.
+ * If {@code stream} has a high cost/latency associated with each written byte,
* consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
* to improve write performance.
*
@@ -592,9 +611,12 @@ public final class HWPFDocument extends HWPFDocumentCore {
* @throws IOException If there is an unexpected IOException from the passed
* in OutputStream.
*/
- public void write(OutputStream out)
- throws IOException
- {
+ public void write(OutputStream out) throws IOException {
+ NPOIFSFileSystem pfs = new NPOIFSFileSystem();
+ write(pfs, true);
+ pfs.writeFilesystem( out );
+ }
+ private void write(NPOIFSFileSystem pfs, boolean copyOtherEntries) throws IOException {
// initialize our streams for writing.
HWPFFileSystem docSys = new HWPFFileSystem();
HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
@@ -891,7 +913,8 @@ public final class HWPFDocument extends HWPFDocumentCore {
}
// create new document preserving order of entries
- NPOIFSFileSystem pfs = new NPOIFSFileSystem();
+ // TODO Check "copyOtherEntries" and tweak behaviour based on that
+ // TODO That's needed for in-place write
boolean docWritten = false;
boolean dataWritten = false;
boolean objectPoolWritten = false;
@@ -967,7 +990,6 @@ public final class HWPFDocument extends HWPFDocumentCore {
if ( !objectPoolWritten )
_objectPool.writeTo( pfs.getRoot() );
- pfs.writeFilesystem( out );
this.directory = pfs.getRoot();
/*
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java
new file mode 100644
index 0000000000..95d7919e33
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java
@@ -0,0 +1,81 @@
+/* ====================================================================
+ 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.HWPFTestCase;
+import org.apache.poi.hwpf.HWPFTestDataSamples;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.TempFile;
+
+/**
+ * Test various write situations
+ */
+public final class TestHWPFWrite extends HWPFTestCase {
+ /**
+ * Write to a stream
+ */
+ public void testWriteStream() throws Exception {
+ HWPFDocument doc = HWPFTestDataSamples.openSampleFile("SampleDoc.doc");
+
+ Range r = doc.getRange();
+ assertEquals("I am a test document\r", r.getParagraph(0).text());
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ doc.write(baos);
+ doc.close();
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ doc = new HWPFDocument(bais);
+ r = doc.getRange();
+ assertEquals("I am a test document\r", r.getParagraph(0).text());
+ doc.close();
+ }
+
+ /**
+ * Write to a new file
+ */
+ public void testWriteNewFile() throws Exception {
+ HWPFDocument doc = HWPFTestDataSamples.openSampleFile("SampleDoc.doc");
+
+ Range r = doc.getRange();
+ assertEquals("I am a test document\r", r.getParagraph(0).text());
+
+ File file = TempFile.createTempFile("TestDocument", ".doc");
+ doc.write(file);
+ doc.close();
+
+ // Check reading from File and Stream
+ doc = new HWPFDocument(new FileInputStream(file));
+ r = doc.getRange();
+ assertEquals("I am a test document\r", r.getParagraph(0).text());
+ doc.close();
+
+ doc = new HWPFDocument(new POIFSFileSystem(file));
+ r = doc.getRange();
+ assertEquals("I am a test document\r", r.getParagraph(0).text());
+ doc.close();
+ }
+
+ // TODO In-place write positive and negative checks
+}
diff --git a/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java b/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java
index 404e0da07e..e02260844a 100644
--- a/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java
+++ b/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java
@@ -50,14 +50,20 @@ public abstract class BaseTestSlideShow {
@Test
public void addPicture_Stream() throws IOException {
SlideShow,?> show = createSlideShow();
- InputStream stream = slTests.openResourceAsStream("clock.jpg");
-
- assertEquals(0, show.getPictureData().size());
- PictureData picture = show.addPicture(stream, PictureType.JPEG);
- assertEquals(1, show.getPictureData().size());
- assertSame(picture, show.getPictureData().get(0));
-
- show.close();
+ try {
+ InputStream stream = slTests.openResourceAsStream("clock.jpg");
+ try {
+ assertEquals(0, show.getPictureData().size());
+ PictureData picture = show.addPicture(stream, PictureType.JPEG);
+ assertEquals(1, show.getPictureData().size());
+ assertSame(picture, show.getPictureData().get(0));
+
+ } finally {
+ stream.close();
+ }
+ } finally {
+ show.close();
+ }
}
@Test
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestIndirect.java b/src/testcases/org/apache/poi/ss/formula/functions/TestIndirect.java
index 8e93152c81..ea5ac9c7aa 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestIndirect.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestIndirect.java
@@ -27,6 +27,7 @@ import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
@@ -105,6 +106,7 @@ public final class TestIndirect {
// non-error cases
confirm(feA, c, "INDIRECT(\"C2\")", 23);
+ confirm(feA, c, "INDIRECT(\"C2\", TRUE)", 23);
confirm(feA, c, "INDIRECT(\"$C2\")", 23);
confirm(feA, c, "INDIRECT(\"C$2\")", 23);
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
@@ -149,7 +151,7 @@ public final class TestIndirect {
// confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", ErrorEval.REF_INVALID); // bad row
// }
confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", ErrorEval.REF_INVALID); // space in cell ref
-
+
wbA.close();
}
@@ -203,4 +205,9 @@ public final class TestIndirect {
+ "' but got '" + cv.formatAsString() + "'.");
}
}
+
+ @Test
+ public void testInvalidInput() {
+ assertEquals(ErrorEval.VALUE_INVALID, Indirect.instance.evaluate(new ValueEval[] {}, null));
+ }
}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java b/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java
index 7b63eaf799..f2750b591c 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java
@@ -20,9 +20,8 @@ package org.apache.poi.ss.formula.functions;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.formula.eval.AreaEval;
-import org.apache.poi.ss.formula.eval.NumberEval;
-import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.FormulaParseException;
+import org.apache.poi.ss.formula.eval.*;
import junit.framework.TestCase;
import org.apache.poi.ss.usermodel.*;
@@ -75,7 +74,6 @@ public final class TestSubtotal extends TestCase {
}
public void testAvg(){
-
Workbook wb = new HSSFWorkbook();
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
@@ -95,16 +93,18 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(1,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(1,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(1,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(2.0, a3.getNumericCellValue());
assertEquals(8.0, a6.getNumericCellValue());
assertEquals(3.0, a7.getNumericCellValue());
+ assertEquals(3.0, a8.getNumericCellValue());
}
public void testSum(){
-
Workbook wb = new HSSFWorkbook();
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
@@ -124,12 +124,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(9,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(9,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(9,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(4.0, a3.getNumericCellValue());
assertEquals(26.0, a6.getNumericCellValue());
assertEquals(12.0, a7.getNumericCellValue());
+ assertEquals(12.0, a8.getNumericCellValue());
}
public void testCount(){
@@ -147,18 +150,21 @@ public final class TestSubtotal extends TestCase {
a3.setCellFormula("SUBTOTAL(2,B2:B3)");
Cell a4 = sh.createRow(4).createCell(1);
a4.setCellValue("POI"); // A4 is string and not counted
- Cell a5 = sh.createRow(5).createCell(1); // A5 is blank and not counted
+ /*Cell a5 =*/ sh.createRow(5).createCell(1); // A5 is blank and not counted
Cell a6 = sh.createRow(6).createCell(1);
a6.setCellFormula("SUBTOTAL(2,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(2,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(2,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(2.0, a3.getNumericCellValue());
assertEquals(6.0, a6.getNumericCellValue());
assertEquals(2.0, a7.getNumericCellValue());
+ assertEquals(2.0, a8.getNumericCellValue());
}
public void testCounta(){
@@ -176,18 +182,21 @@ public final class TestSubtotal extends TestCase {
a3.setCellFormula("SUBTOTAL(3,B2:B3)");
Cell a4 = sh.createRow(4).createCell(1);
a4.setCellValue("POI"); // A4 is string and not counted
- Cell a5 = sh.createRow(5).createCell(1); // A5 is blank and not counted
+ /*Cell a5 =*/ sh.createRow(5).createCell(1); // A5 is blank and not counted
Cell a6 = sh.createRow(6).createCell(1);
a6.setCellFormula("SUBTOTAL(3,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(3,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(3,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(2.0, a3.getNumericCellValue());
assertEquals(8.0, a6.getNumericCellValue());
assertEquals(3.0, a7.getNumericCellValue());
+ assertEquals(3.0, a8.getNumericCellValue());
}
public void testMax(){
@@ -211,12 +220,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(4,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(4,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(4,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(3.0, a3.getNumericCellValue());
assertEquals(16.0, a6.getNumericCellValue());
assertEquals(7.0, a7.getNumericCellValue());
+ assertEquals(7.0, a8.getNumericCellValue());
}
public void testMin(){
@@ -240,12 +252,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(5,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(5,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(5,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(1.0, a3.getNumericCellValue());
assertEquals(4.0, a6.getNumericCellValue());
assertEquals(1.0, a7.getNumericCellValue());
+ assertEquals(1.0, a8.getNumericCellValue());
}
public void testStdev(){
@@ -269,12 +284,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(7,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(7,B2:B7)");
+ Cell a8 = sh.createRow(8).createCell(1);
+ a8.setCellFormula("SUBTOTAL(7,B2,B3,B4,B5,B6,B7,B8)");
fe.evaluateAll();
assertEquals(1.41421, a3.getNumericCellValue(), 0.0001);
assertEquals(7.65685, a6.getNumericCellValue(), 0.0001);
assertEquals(2.82842, a7.getNumericCellValue(), 0.0001);
+ assertEquals(2.82842, a8.getNumericCellValue(), 0.0001);
}
public void test50209(){
@@ -328,4 +346,69 @@ public final class TestSubtotal extends TestCase {
confirmExpectedResult(evaluator, "SUBTOTAL(COUNT;B2:B8,C2:C8)", cellC2, 3.0);
confirmExpectedResult(evaluator, "SUBTOTAL(COUNTA;B2:B8,C2:C8)", cellC3, 5.0);
}
+
+ public void testUnimplemented(){
+ Workbook wb = new HSSFWorkbook();
+
+ FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
+
+ Sheet sh = wb.createSheet();
+ Cell a3 = sh.createRow(3).createCell(1);
+ a3.setCellFormula("SUBTOTAL(8,B2:B3)");
+
+ try {
+ fe.evaluateAll();
+ fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
+ } catch (NotImplementedException e) {
+ // expected here
+ }
+
+ a3.setCellFormula("SUBTOTAL(10,B2:B3)");
+
+ try {
+ fe.evaluateAll();
+ fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
+ } catch (NotImplementedException e) {
+ // expected here
+ }
+
+ a3.setCellFormula("SUBTOTAL(11,B2:B3)");
+
+ try {
+ fe.evaluateAll();
+ fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
+ } catch (NotImplementedException e) {
+ // expected here
+ }
+
+ a3.setCellFormula("SUBTOTAL(107,B2:B3)");
+
+ try {
+ fe.evaluateAll();
+ fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
+ } catch (NotImplementedException e) {
+ // expected here
+ }
+
+ a3.setCellFormula("SUBTOTAL(0,B2:B3)");
+ fe.evaluateAll();
+ assertEquals(FormulaError.VALUE.getCode(), a3.getErrorCellValue());
+
+ try {
+ a3.setCellFormula("SUBTOTAL(9)");
+ fail("Should catch an exception here");
+ } catch (FormulaParseException e) {
+ // expected here
+ }
+
+ try {
+ a3.setCellFormula("SUBTOTAL()");
+ fail("Should catch an exception here");
+ } catch (FormulaParseException e) {
+ // expected here
+ }
+
+ Subtotal subtotal = new Subtotal();
+ assertEquals(ErrorEval.VALUE_INVALID, subtotal.evaluate(new ValueEval[] {}, 0, 0));
+ }
}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestWeekdayFunc.java b/src/testcases/org/apache/poi/ss/formula/functions/TestWeekdayFunc.java
new file mode 100644
index 0000000000..c6c797c186
--- /dev/null
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestWeekdayFunc.java
@@ -0,0 +1,66 @@
+/* ====================================================================
+ 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.ss.formula.functions;
+
+import org.apache.poi.ss.formula.eval.*;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class TestWeekdayFunc {
+ @Test
+ public void testEvaluate() throws Exception {
+ assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(2.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(0.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(3.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(11.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(7.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(12.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(6.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(13.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(5.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(14.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(4.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(15.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(16.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(17.0)}, 0, 0)).getNumberValue(), 0.001);
+
+ assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(2.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(3.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(11.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(12.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(7.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(13.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(6.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(14.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(5.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(15.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(4.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(16.0)}, 0, 0)).getNumberValue(), 0.001);
+ assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(17.0)}, 0, 0)).getNumberValue(), 0.001);
+ }
+
+ @Test
+ public void testEvaluateInvalid() throws Exception {
+ assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{}, 0, 0));
+ assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(1.0), new NumberEval(1.0)}, 0, 0));
+
+ assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(-1.0)}, 0, 0));
+ assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("")}, 0, 0));
+ assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("1"), new StringEval("")}, 0, 0));
+ assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("2"), BlankEval.instance}, 0, 0));
+ assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("3"), MissingArgEval.instance}, 0, 0));
+ assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(18.0)}, 0, 0));
+ }
+}
\ No newline at end of file
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
index a832635c1a..bdd09bfd6c 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
@@ -33,9 +33,12 @@ import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
+import java.io.FileInputStream;
import java.io.IOException;
import java.text.AttributedString;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
@@ -1606,4 +1609,78 @@ public abstract class BaseTestBugzillaIssues {
assertNull("Sheet0 after write", wb2.getPrintArea(0)); // CURRENTLY FAILS with "Sheet0!$A$1:$C$6"
assertEquals("Sheet1 after write", "Sheet1!$A$1:$A$1", wb2.getPrintArea(1));
}
-}
+
+
+ @Test
+ public void test55384() throws Exception {
+ Workbook wb = _testDataProvider.createWorkbook();
+ try {
+ Sheet sh = wb.createSheet();
+ for (int rownum = 0; rownum < 10; rownum++) {
+ org.apache.poi.ss.usermodel.Row row = sh.createRow(rownum);
+ for (int cellnum = 0; cellnum < 3; cellnum++) {
+ Cell cell = row.createCell(cellnum);
+ cell.setCellValue(rownum + cellnum);
+ }
+ }
+ Row row = sh.createRow(10);
+ // setting no precalculated value works just fine.
+ Cell cell1 = row.createCell(0);
+ cell1.setCellFormula("SUM(A1:A10)");
+
+ // but setting a precalculated STRING value fails totally in SXSSF
+ Cell cell2 = row.createCell(1);
+ cell2.setCellFormula("SUM(B1:B10)");
+ cell2.setCellValue("55");
+
+ // setting a precalculated int value works as expected
+ Cell cell3 = row.createCell(2);
+ cell3.setCellFormula("SUM(C1:C10)");
+ cell3.setCellValue(65);
+
+ assertEquals(CellType.FORMULA, cell1.getCellTypeEnum());
+ assertEquals(CellType.FORMULA, cell2.getCellTypeEnum());
+ assertEquals(CellType.FORMULA, cell3.getCellTypeEnum());
+
+ assertEquals("SUM(A1:A10)", cell1.getCellFormula());
+ assertEquals("SUM(B1:B10)", cell2.getCellFormula());
+ assertEquals("SUM(C1:C10)", cell3.getCellFormula());
+
+ /*String name = wb.getClass().getCanonicalName();
+ String ext = (wb instanceof HSSFWorkbook) ? ".xls" : ".xlsx";
+ OutputStream output = new FileOutputStream("/tmp" + name + ext);
+ try {
+ wb.write(output);
+ } finally {
+ output.close();
+ }*/
+
+ Workbook wbBack = _testDataProvider.writeOutAndReadBack(wb);
+ checkFormulaPreevaluatedString(wbBack);
+ wbBack.close();
+ } finally {
+ wb.close();
+ }
+ }
+
+ private void checkFormulaPreevaluatedString(Workbook readFile) {
+ Sheet sheet = readFile.getSheetAt(0);
+ Row row = sheet.getRow(sheet.getLastRowNum());
+ assertEquals(10, row.getRowNum());
+
+ for (Cell cell : row) {
+ String cellValue = null;
+ switch (cell.getCellTypeEnum()) {
+ case STRING:
+ cellValue = cell.getRichStringCellValue().getString();
+ break;
+ case FORMULA:
+ cellValue = cell.getCellFormula();
+ break;
+ }
+ assertNotNull(cellValue);
+ cellValue = cellValue.isEmpty() ? null : cellValue;
+ assertNotNull(cellValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java
index 75fb77e827..92e362df57 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java
@@ -201,11 +201,7 @@ public abstract class BaseTestNamedRange {
assertEquals("The sheet already contains this name: aaa", e.getMessage());
}
- int cnt = 0;
- for (int i = 0; i < wb.getNumberOfNames(); i++) {
- if("aaa".equals(wb.getNameAt(i).getNameName())) cnt++;
- }
- assertEquals(3, cnt);
+ assertEquals(3, wb.getNames("aaa").size());
wb.close();
}
@@ -250,11 +246,11 @@ public abstract class BaseTestNamedRange {
// Write the workbook to a file
// Read the Excel file and verify its content
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
- Name nm1 = wb2.getNameAt(wb2.getNameIndex("RangeTest1"));
+ Name nm1 = wb2.getName("RangeTest1");
assertTrue("Name is "+nm1.getNameName(),"RangeTest1".equals(nm1.getNameName()));
assertTrue("Reference is "+nm1.getRefersToFormula(),(wb2.getSheetName(0)+"!$A$1:$L$41").equals(nm1.getRefersToFormula()));
- Name nm2 = wb2.getNameAt(wb2.getNameIndex("RangeTest2"));
+ Name nm2 = wb2.getName("RangeTest2");
assertTrue("Name is "+nm2.getNameName(),"RangeTest2".equals(nm2.getNameName()));
assertTrue("Reference is "+nm2.getRefersToFormula(),(wb2.getSheetName(1)+"!$A$1:$O$21").equals(nm2.getRefersToFormula()));
@@ -466,11 +462,11 @@ public abstract class BaseTestNamedRange {
wb1.getNameAt(0);
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
- Name nm =wb2.getNameAt(wb2.getNameIndex("RangeTest"));
+ Name nm =wb2.getName("RangeTest");
assertTrue("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName()));
assertTrue("Reference is "+nm.getRefersToFormula(),(wb2.getSheetName(0)+"!$D$4:$E$8").equals(nm.getRefersToFormula()));
- nm = wb2.getNameAt(wb2.getNameIndex("AnotherTest"));
+ nm = wb2.getName("AnotherTest");
assertTrue("Name is "+nm.getNameName(),"AnotherTest".equals(nm.getNameName()));
assertTrue("Reference is "+nm.getRefersToFormula(),newNamedRange2.getRefersToFormula().equals(nm.getRefersToFormula()));
@@ -499,8 +495,7 @@ public abstract class BaseTestNamedRange {
namedCell.setRefersToFormula(reference);
// retrieve the newly created named range
- int namedCellIdx = wb.getNameIndex(cellName);
- Name aNamedCell = wb.getNameAt(namedCellIdx);
+ Name aNamedCell = wb.getName(cellName);
assertNotNull(aNamedCell);
// retrieve the cell at the named range and test its contents
@@ -540,8 +535,7 @@ public abstract class BaseTestNamedRange {
namedCell.setRefersToFormula(reference);
// retrieve the newly created named range
- int namedCellIdx = wb.getNameIndex(cname);
- Name aNamedCell = wb.getNameAt(namedCellIdx);
+ Name aNamedCell = wb.getName(cname);
assertNotNull(aNamedCell);
// retrieve the cell at the named range and test its contents
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftRows.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftRows.java
index 3f8febb11a..efae0d80c6 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftRows.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetShiftRows.java
@@ -261,17 +261,17 @@ public abstract class BaseTestSheetShiftRows {
name4.setSheetIndex(1);
sheet1.shiftRows(0, 1, 2); //shift down the top row on Sheet1.
- name1 = wb.getNameAt(0);
+ name1 = wb.getName("name1");
assertEquals("Sheet1!$A$3+Sheet1!$B$3", name1.getRefersToFormula());
- name2 = wb.getNameAt(1);
+ name2 = wb.getName("name2");
assertEquals("Sheet1!$A$3", name2.getRefersToFormula());
//name3 and name4 refer to Sheet2 and should not be affected
- name3 = wb.getNameAt(2);
+ name3 = wb.getName("name3");
assertEquals("Sheet2!$A$1", name3.getRefersToFormula());
- name4 = wb.getNameAt(3);
+ name4 = wb.getName("name4");
assertEquals("A1", name4.getRefersToFormula());
wb.close();
diff --git a/src/testcases/org/apache/poi/ss/util/BaseTestCellUtil.java b/src/testcases/org/apache/poi/ss/util/BaseTestCellUtil.java
index ed0c1da7e4..a63ce5a605 100644
--- a/src/testcases/org/apache/poi/ss/util/BaseTestCellUtil.java
+++ b/src/testcases/org/apache/poi/ss/util/BaseTestCellUtil.java
@@ -78,14 +78,16 @@ public class BaseTestCellUtil {
@Test(expected=RuntimeException.class)
public void setCellStylePropertyWithInvalidValue() throws IOException {
Workbook wb = _testDataProvider.createWorkbook();
- Sheet s = wb.createSheet();
- Row r = s.createRow(0);
- Cell c = r.createCell(0);
+ try {
+ Sheet s = wb.createSheet();
+ Row r = s.createRow(0);
+ Cell c = r.createCell(0);
- // An invalid BorderStyle constant
- CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
-
- wb.close();
+ // An invalid BorderStyle constant
+ CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
+ } finally {
+ wb.close();
+ }
}
@Test()
@@ -352,10 +354,8 @@ public class BaseTestCellUtil {
CellUtil.setFont(A1, font2);
fail("setFont not allowed if font belongs to a different workbook");
} catch (final IllegalArgumentException e) {
- if (e.getMessage().startsWith("Font does not belong to this workbook")) {
- // expected
- }
- else {
+ // one specific message is expected
+ if (!e.getMessage().startsWith("Font does not belong to this workbook")) {
throw e;
}
} finally {
@@ -371,7 +371,7 @@ public class BaseTestCellUtil {
*/
// bug 55555
@Test
- public void setFillForegroundColorBeforeFillBackgroundColor() {
+ public void setFillForegroundColorBeforeFillBackgroundColor() throws IOException {
Workbook wb1 = _testDataProvider.createWorkbook();
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
Map properties = new HashMap();
@@ -386,13 +386,14 @@ public class BaseTestCellUtil {
assertEquals("fill pattern", CellStyle.BRICKS, style.getFillPattern());
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
+ wb1.close();
}
/**
* bug 55555
* @since POI 3.15 beta 3
*/
@Test
- public void setFillForegroundColorBeforeFillBackgroundColorEnum() {
+ public void setFillForegroundColorBeforeFillBackgroundColorEnum() throws IOException {
Workbook wb1 = _testDataProvider.createWorkbook();
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
Map properties = new HashMap();
@@ -407,5 +408,7 @@ public class BaseTestCellUtil {
assertEquals("fill pattern", FillPatternType.BRICKS, style.getFillPatternEnum());
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
+
+ wb1.close();
}
}
diff --git a/src/testcases/org/apache/poi/util/DummyPOILogger.java b/src/testcases/org/apache/poi/util/DummyPOILogger.java
index 976c7d918e..c8566fe663 100644
--- a/src/testcases/org/apache/poi/util/DummyPOILogger.java
+++ b/src/testcases/org/apache/poi/util/DummyPOILogger.java
@@ -30,16 +30,20 @@ public class DummyPOILogger extends POILogger {
logged = new ArrayList();
}
+ @Override
public boolean check(int level) {
return true;
}
+ @Override
public void initialize(String cat) {}
+ @Override
public void log(int level, Object obj1) {
logged.add(level + " - " + obj1);
}
+ @Override
public void log(int level, Object obj1, Throwable exception) {
logged.add(level + " - " + obj1 + " - " + exception);
}
diff --git a/src/testcases/org/apache/poi/util/TestPOILogger.java b/src/testcases/org/apache/poi/util/TestPOILogger.java
index a53de44eb4..3914b76436 100644
--- a/src/testcases/org/apache/poi/util/TestPOILogger.java
+++ b/src/testcases/org/apache/poi/util/TestPOILogger.java
@@ -26,10 +26,6 @@ import org.junit.Test;
/**
* Tests the log class.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- * @author Marc Johnson (mjohnson at apache dot org)
- * @author Nicola Ken Barozzi (nicolaken at apache.org)
*/
public final class TestPOILogger extends POILogger {
private String lastLog = "";
@@ -61,20 +57,26 @@ public final class TestPOILogger extends POILogger {
POILogFactory._loggerClassName = oldLCN;
}
}
+
+ // ---------- POI Logger methods implemented for testing ----------
+ @Override
public void initialize(String cat) {
}
+ @Override
public void log(int level, Object obj1) {
lastLog = (obj1 == null) ? "" : obj1.toString();
lastEx = null;
}
+ @Override
public void log(int level, Object obj1, Throwable exception) {
lastLog = (obj1 == null) ? "" : obj1.toString();
lastEx = exception;
}
+ @Override
public boolean check(int level) {
return true;
}
diff --git a/test-data/spreadsheet/59736.xlsx b/test-data/spreadsheet/59736.xlsx
new file mode 100644
index 0000000000..1f29d54c50
Binary files /dev/null and b/test-data/spreadsheet/59736.xlsx differ