From 56051c3e44486c2b54cc53cf2c91a1f94555f14f Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Wed, 17 Sep 2014 21:12:36 +0000 Subject: [PATCH] merge with trunk git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1625828 13f79535-47bb-0310-9956-ffa450edef68 --- KEYS | 43 + build.xml | 16 +- .../eventusermodel/examples/FromHowTo.java | 1 + .../org/apache/poi/hssf/dev/BiffViewer.java | 2 +- .../record/AbstractEscherHolderRecord.java | 15 +- .../apache/poi/hssf/record/DConRefRecord.java | 7 +- .../poi/hssf/record/DrawingGroupRecord.java | 2 +- .../poi/hssf/record/PasswordRecord.java | 23 +- .../aggregates/WorksheetProtectionBlock.java | 3 +- .../poi/hssf/usermodel/HSSFCellStyle.java | 23 + .../poi/hssf/usermodel/HSSFClientAnchor.java | 12 +- .../poi/hssf/usermodel/HSSFPatriarch.java | 4 + .../apache/poi/hssf/usermodel/HSSFShape.java | 5 + .../poi/poifs/crypt/CryptoFunctions.java | 83 +- .../apache/poi/poifs/crypt/HashAlgorithm.java | 7 + .../poifs/filesystem/NPOIFSFileSystem.java | 29 +- .../org/apache/poi/ss/SpreadsheetVersion.java | 185 ++- .../poi/ss/formula/WorkbookEvaluator.java | 8 +- src/java/org/apache/poi/util/ArrayUtil.java | 85 - src/java/org/apache/poi/util/XMLHelper.java | 32 +- .../java/org/apache/poi/POIXMLProperties.java | 162 +- .../poi/POIXMLPropertiesTextExtractor.java | 7 +- .../opc/PackageRelationshipCollection.java | 4 +- .../opc/internal/ContentTypeManager.java | 3 +- .../PackagePropertiesUnmarshaller.java | 4 +- .../poi/poifs/crypt/dsig/SignatureInfo.java | 6 +- .../org/apache/poi/util/DocumentHelper.java | 75 +- .../java/org/apache/poi/util/SAXHelper.java | 72 +- .../org/apache/poi/xslf/XSLFSlideShow.java | 18 +- .../extractor/XSLFPowerPointExtractor.java | 3 +- .../poi/xslf/model/geom/CustomGeometry.java | 16 +- .../poi/xslf/usermodel/DrawingTable.java | 9 +- .../poi/xslf/usermodel/DrawingTableRow.java | 9 +- .../poi/xslf/usermodel/DrawingTextBody.java | 9 +- .../poi/xslf/usermodel/RenderableShape.java | 41 +- .../poi/xslf/usermodel/XMLSlideShow.java | 17 +- .../xslf/usermodel/XSLFCommentAuthors.java | 7 +- .../poi/xslf/usermodel/XSLFComments.java | 2 +- .../xslf/usermodel/XSLFCommonSlideData.java | 17 +- .../poi/xslf/usermodel/XSLFFreeformShape.java | 13 +- .../poi/xslf/usermodel/XSLFPictureShape.java | 2 +- .../apache/poi/xslf/usermodel/XSLFTable.java | 6 +- .../poi/xslf/usermodel/XSLFTableRow.java | 14 +- .../poi/xslf/usermodel/XSLFTableStyles.java | 18 +- .../poi/xslf/usermodel/XSLFTextShape.java | 19 +- .../ReadOnlySharedStringsTable.java | 7 +- .../eventusermodel/XSSFSheetXMLHandler.java | 6 +- .../XSSFEventBasedExcelExtractor.java | 7 +- .../poi/xssf/extractor/XSSFExportToXml.java | 32 +- .../poi/xssf/extractor/XSSFImportFromXML.java | 9 +- .../apache/poi/xssf/model/CommentsTable.java | 25 +- .../org/apache/poi/xssf/model/MapInfo.java | 7 +- .../apache/poi/xssf/model/SingleXmlCells.java | 3 +- .../apache/poi/xssf/model/ThemesTable.java | 74 +- .../apache/poi/xssf/usermodel/XSSFChart.java | 30 +- .../apache/poi/xssf/usermodel/XSSFColor.java | 162 +- .../usermodel/XSSFPivotCacheDefinition.java | 2 +- .../poi/xssf/usermodel/XSSFPivotTable.java | 26 +- .../apache/poi/xssf/usermodel/XSSFRow.java | 14 +- .../apache/poi/xssf/usermodel/XSSFSheet.java | 695 ++++---- .../XSSFSheetConditionalFormatting.java | 29 +- .../apache/poi/xssf/usermodel/XSSFTable.java | 9 +- .../poi/xssf/usermodel/XSSFWorkbook.java | 97 +- .../xssf/usermodel/helpers/ColumnHelper.java | 126 +- .../usermodel/helpers/XSSFPaswordHelper.java | 128 ++ .../usermodel/helpers/XSSFRowShifter.java | 43 +- .../apache/poi/xssf/util/CTColComparator.java | 38 +- .../poi/xwpf/model/XWPFCommentsDecorator.java | 4 +- .../xwpf/model/XWPFHyperlinkDecorator.java | 6 +- .../poi/xwpf/usermodel/AbstractXWPFSDT.java | 13 +- .../poi/xwpf/usermodel/XWPFComment.java | 3 +- .../poi/xwpf/usermodel/XWPFDocument.java | 24 +- .../poi/xwpf/usermodel/XWPFFootnote.java | 7 +- .../poi/xwpf/usermodel/XWPFFootnotes.java | 4 +- .../poi/xwpf/usermodel/XWPFHeaderFooter.java | 7 +- .../poi/xwpf/usermodel/XWPFLatentStyles.java | 6 +- .../poi/xwpf/usermodel/XWPFNumbering.java | 7 +- .../poi/xwpf/usermodel/XWPFParagraph.java | 22 +- .../apache/poi/xwpf/usermodel/XWPFRun.java | 27 +- .../poi/xwpf/usermodel/XWPFSDTContent.java | 4 +- .../apache/poi/xwpf/usermodel/XWPFStyles.java | 6 +- .../apache/poi/xwpf/usermodel/XWPFTable.java | 9 +- .../poi/xwpf/usermodel/XWPFTableCell.java | 21 +- .../poi/xwpf/usermodel/XWPFTableRow.java | 7 +- .../org/apache/poi/TestPOIXMLProperties.java | 5 +- .../apache/poi/openxml4j/opc/TestPackage.java | 3 +- .../apache/poi/poifs/crypt/PkiTestUtils.java | 44 +- .../poi/poifs/crypt/TestSignatureInfo.java | 4 +- .../apache/poi/xslf/TestXSLFSlideShow.java | 18 +- .../poi/xslf/usermodel/TestXMLSlideShow.java | 10 +- .../xslf/usermodel/TestXSLFSimpleShape.java | 16 +- .../apache/poi/xssf/TestSheetProtection.java | 35 +- .../poi/xssf/TestWorkbookProtection.java | 128 +- .../xssf/extractor/TestXSSFExportToXML.java | 36 +- .../poi/xssf/model/TestCalculationChain.java | 4 +- .../apache/poi/xssf/model/TestMapInfo.java | 2 +- .../poi/xssf/model/TestThemesTable.java | 78 + .../poi/xssf/usermodel/TestXSSFBugs.java | 4 +- .../xssf/usermodel/TestXSSFColGrouping.java | 6 +- .../poi/xssf/usermodel/TestXSSFColor.java | 62 +- .../poi/xssf/usermodel/TestXSSFFont.java | 10 +- .../usermodel/TestXSSFFormulaEvaluation.java | 249 ++- .../usermodel/TestXSSFRichTextString.java | 26 +- .../poi/xssf/usermodel/TestXSSFSheet.java | 131 +- .../usermodel/TestXSSFSheetShiftRows.java | 12 + .../poi/xssf/usermodel/TestXSSFTable.java | 25 +- .../poi/xssf/usermodel/TestXSSFWorkbook.java | 2 +- .../extensions/TestXSSFCellFill.java | 73 +- .../usermodel/helpers/TestColumnHelper.java | 2 +- .../poi/xssf/util/TestCTColComparator.java | 12 +- .../poi/xwpf/usermodel/TestXWPFDocument.java | 10 +- .../poi/xwpf/usermodel/TestXWPFParagraph.java | 11 +- .../poi/xwpf/usermodel/TestXWPFRun.java | 6 +- .../poi/xwpf/usermodel/TestXWPFStyles.java | 2 +- .../poi/hwpf/model/NilPICFAndBinData.java | 7 +- .../src/org/apache/poi/hwpf/model/PlfLfo.java | 5 +- .../src/org/apache/poi/hwpf/model/Sttb.java | 5 +- .../poi/hssf/model/TestDrawingShapes.java | 1471 +++++++++-------- .../poi/hssf/record/TestDConRefRecord.java | 3 +- .../BaseTestConditionalFormatting.java | 31 +- test-data/spreadsheet/56730.xlsx | Bin 0 -> 9808 bytes test-data/spreadsheet/Themes.xlsx | Bin 0 -> 9506 bytes ...orkbookProtection-sheet_password-2013.xlsx | Bin 0 -> 9196 bytes ...bookProtection-workbook_password-2013.xlsx | Bin 0 -> 8171 bytes ...ion-workbook_password_user_range-2010.xlsx | Bin 0 -> 11207 bytes 125 files changed, 3303 insertions(+), 2129 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java create mode 100644 src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java create mode 100644 test-data/spreadsheet/56730.xlsx create mode 100644 test-data/spreadsheet/Themes.xlsx create mode 100644 test-data/spreadsheet/workbookProtection-sheet_password-2013.xlsx create mode 100644 test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx create mode 100644 test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx diff --git a/KEYS b/KEYS index 5c1de0c2a3..340f8504db 100644 --- a/KEYS +++ b/KEYS @@ -1753,3 +1753,46 @@ W45jdvBkYoPdQtS+8Vy+q0997zobctz8i5hfXzxg51/IuSU4uNtgr26XapsoLDur 7PoqJGZ6UdBVwyb0qZqs6KLGQkEyJ8358ivjJsjxUR8diK027wWnW/s= =/Vu1 -----END PGP PUBLIC KEY BLOCK----- +pub 2048R/26062CE3 2014-08-17 [expires: 2016-08-16] +uid Andreas Beeker +uid Andreas Beeker (kiwiwings) +sub 2048R/EE864ED6 2014-08-17 [expires: 2016-08-16] + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +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 +=0DjT +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build.xml b/build.xml index 8f27b57feb..8be3cb707d 100644 --- a/build.xml +++ b/build.xml @@ -164,13 +164,17 @@ under the License. - + + + + + @@ -254,6 +258,7 @@ under the License. + @@ -261,6 +266,7 @@ under the License. + @@ -268,6 +274,7 @@ under the License. + @@ -300,6 +307,7 @@ under the License. + @@ -372,6 +380,7 @@ under the License. + @@ -388,6 +397,7 @@ under the License. + @@ -438,6 +448,10 @@ under the License. + + + + diff --git a/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java index fc6604c649..4df63448ed 100644 --- a/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java +++ b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java @@ -115,6 +115,7 @@ public class FromHowTo { if(nextIsString) { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); + nextIsString = false; } // v => contents of a cell diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index 19cdd02942..5451b27899 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -145,7 +145,7 @@ public final class BiffViewer { case DatRecord.sid: return new DatRecord(in); case DataFormatRecord.sid: return new DataFormatRecord(in); case DateWindow1904Record.sid: return new DateWindow1904Record(in); - case DConRefRecord.sid: return new DConRefRecord(in); + case DConRefRecord.sid: return new DConRefRecord(in); case DefaultColWidthRecord.sid:return new DefaultColWidthRecord(in); case DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in); case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in); diff --git a/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java b/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java index 078f0205d7..d3263834c7 100644 --- a/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java +++ b/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java @@ -57,20 +57,19 @@ public abstract class AbstractEscherHolderRecord extends Record { public AbstractEscherHolderRecord(RecordInputStream in) { escherRecords = new ArrayList(); - if (! DESERIALISE ) - { + if (! DESERIALISE ) { rawDataContainer.concatenate(in.readRemainder()); - } - else - { + } else { byte[] data = in.readAllContinuedRemainder(); convertToEscherRecords( 0, data.length, data ); } } protected void convertRawBytesToEscherRecords() { - byte[] rawData = getRawData(); - convertToEscherRecords(0, rawData.length, rawData); + if (! DESERIALISE ) { + byte[] rawData = getRawData(); + convertToEscherRecords(0, rawData.length, rawData); + } } private void convertToEscherRecords( int offset, int size, byte[] data ) { @@ -224,7 +223,7 @@ public abstract class AbstractEscherHolderRecord extends Record { public EscherRecord getEscherRecord(int index) { - return (EscherRecord) escherRecords.get(index); + return escherRecords.get(index); } /** diff --git a/src/java/org/apache/poi/hssf/record/DConRefRecord.java b/src/java/org/apache/poi/hssf/record/DConRefRecord.java index 629dc00e51..deccff347b 100644 --- a/src/java/org/apache/poi/hssf/record/DConRefRecord.java +++ b/src/java/org/apache/poi/hssf/record/DConRefRecord.java @@ -18,10 +18,11 @@ */ package org.apache.poi.hssf.record; -import org.apache.poi.util.ArrayUtil; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianOutput; +import java.util.Arrays; + /** * DConRef records specify a range in a workbook (internal or external) that serves as a data source * for pivot tables or data consolidation. @@ -273,7 +274,7 @@ public class DConRefRecord extends StandardRecord */ public byte[] getPath() { - return ArrayUtil.copyOf(path, path.length); + return Arrays.copyOf(path, path.length); } /** @@ -291,7 +292,7 @@ public class DConRefRecord extends StandardRecord { offset++; } - String out = new String(ArrayUtil.copyOfRange(path, offset, path.length)); + String out = new String(Arrays.copyOfRange(path, offset, path.length)); //UNC paths have \u0003 chars as path separators. out = out.replaceAll("\u0003", "/"); return out; diff --git a/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java b/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java index 1264b60bcc..eeddf5e21a 100644 --- a/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java +++ b/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java @@ -118,7 +118,7 @@ public final class DrawingGroupRecord extends AbstractEscherHolderRecord { writeHeader( data, offset, segmentLength ); writtenActualData += 4; offset += 4; - ArrayUtil.arraycopy( rawData, writtenRawData, data, offset, segmentLength ); + System.arraycopy( rawData, writtenRawData, data, offset, segmentLength ); offset += segmentLength; writtenRawData += segmentLength; writtenActualData += segmentLength; diff --git a/src/java/org/apache/poi/hssf/record/PasswordRecord.java b/src/java/org/apache/poi/hssf/record/PasswordRecord.java index 9baff6f97d..c38a1230ca 100644 --- a/src/java/org/apache/poi/hssf/record/PasswordRecord.java +++ b/src/java/org/apache/poi/hssf/record/PasswordRecord.java @@ -17,6 +17,7 @@ package org.apache.poi.hssf.record; +import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndianOutput; @@ -39,23 +40,13 @@ public final class PasswordRecord extends StandardRecord { field_1_password = in.readShort(); } - //this is the world's lamest "security". thanks to Wouter van Vugt for making me - //not have to try real hard. -ACO + /** + * Return the password hash + * + * @deprecated use {@link CryptoFunctions#createXorVerifier1(String)} + */ public static short hashPassword(String password) { - byte[] passwordCharacters = password.getBytes(); - int hash = 0; - if (passwordCharacters.length > 0) { - int charIndex = passwordCharacters.length; - while (charIndex-- > 0) { - hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff); - hash ^= passwordCharacters[charIndex]; - } - // also hash with charcount - hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff); - hash ^= passwordCharacters.length; - hash ^= (0x8000 | ('N' << 8) | 'K'); - } - return (short)hash; + return (short)CryptoFunctions.createXorVerifier1(password); } /** diff --git a/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java b/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java index f838485f74..275fbf123a 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java @@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.ProtectRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RecordFormatException; import org.apache.poi.hssf.record.ScenarioProtectRecord; +import org.apache.poi.poifs.crypt.CryptoFunctions; /** * Groups the sheet protection records for a worksheet. @@ -186,7 +187,7 @@ public final class WorksheetProtectionBlock extends RecordAggregate { ProtectRecord prec = getProtect(); PasswordRecord pass = getPassword(); prec.setProtect(true); - pass.setPassword(PasswordRecord.hashPassword(password)); + pass.setPassword((short)CryptoFunctions.createXorVerifier1(password)); if (_objectProtectRecord == null && shouldProtectObjects) { ObjectProtectRecord rec = createObjectProtect(); rec.setProtect(true); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java index de18107683..a69efe4eec 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java @@ -827,6 +827,29 @@ public final class HSSFCellStyle implements CellStyle { return _format.getShrinkToFit(); } + /** + * Get the reading order, for RTL/LTR ordering of + * the text. + *

0 means Context (Default), 1 means Left To Right, + * and 2 means Right to Left

+ * + * @return order - the reading order (0,1,2) + */ + public short getReadingOrder() { + return _format.getReadingOrder(); + } + /** + * Sets the reading order, for RTL/LTR ordering of + * the text. + *

0 means Context (Default), 1 means Left To Right, + * and 2 means Right to Left

+ * + * @param order - the reading order (0,1,2) + */ + public void setReadingOrder(short order) { + _format.setReadingOrder(order); + } + /** * Verifies that this style belongs to the supplied Workbook. * Will throw an exception if it belongs to a different one. diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java index 0a65bbd8ff..c46f7b7a92 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java @@ -42,6 +42,10 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor { /** * Creates a new client anchor and sets the top-left and bottom-right * coordinates of the anchor. + * + * Note: Microsoft Excel seems to sometimes disallow + * higher y1 than y2 or higher x1 than x2, you might need to + * reverse them and draw shapes vertically or horizontally flipped! * * @param dx1 the x coordinate within the first cell. * @param dy1 the y coordinate within the first cell. @@ -186,8 +190,12 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor { } /** - * Dets the top-left and bottom-right - * coordinates of the anchor. + * Sets the top-left and bottom-right coordinates of + * the anchor. + * + * Note: Microsoft Excel seems to sometimes disallow + * higher y1 than y2 or higher x1 than x2, you might need to + * reverse them and draw shapes vertically or horizontally flipped! * * @param x1 the x coordinate within the first cell. * @param y1 the y coordinate within the first cell. diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java index 7745801fd2..dda4b39575 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java @@ -171,6 +171,10 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing { /** * Creates a simple shape. This includes such shapes as lines, rectangles, * and ovals. + * + * Note: Microsoft Excel seems to sometimes disallow + * higher y1 than y2 or higher x1 than x2 in the anchor, you might need to + * reverse them and draw shapes vertically or horizontally flipped! * * @param anchor the client anchor describes how this group is attached * to the sheet. diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java index 4ea7d31e6a..4775122f82 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java @@ -27,6 +27,11 @@ import java.io.IOException; /** * An abstract shape. + * + * Note: Microsoft Excel seems to sometimes disallow + * higher y1 than y2 or higher x1 than x2 in the anchor, you might need to + * reverse them and draw shapes vertically or horizontally flipped via + * setFlipVertical() or setFlipHorizontally(). */ public abstract class HSSFShape { public static final int LINEWIDTH_ONE_PT = 12700; diff --git a/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java b/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java index c84431fd85..875ade3ab9 100644 --- a/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java +++ b/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java @@ -181,14 +181,20 @@ public class CryptoFunctions { } /** - * + * Initialize a new cipher object with the given cipher properties + * If the given algorithm is not implemented in the JCE, it will try to load it from the bouncy castle + * provider. * - * @param key - * @param chain - * @param vec + * @param key the secrect key + * @param cipherAlgorithm the cipher algorithm + * @param chain the chaining mode + * @param vec the initialization vector (IV), can be null * @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE + * @param padding * @return the requested cipher * @throws GeneralSecurityException + * @throws EncryptedDocumentException if the initialization failed or if an algorithm was specified, + * which depends on a missing bouncy castle provider */ public static Cipher getCipher(Key key, CipherAlgorithm cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode, String padding) { int keySizeInBytes = key.getEncoded().length; @@ -227,10 +233,26 @@ public class CryptoFunctions { } } + /** + * Returns a new byte array with a truncated to the given size. + * If the hash has less then size bytes, it will be filled with 0x36-bytes + * + * @param hash the to be truncated/filled hash byte array + * @param size the size of the returned byte array + * @return the padded hash + */ public static byte[] getBlock36(byte[] hash, int size) { return getBlockX(hash, size, (byte)0x36); } + /** + * Returns a new byte array with a truncated to the given size. + * If the hash has less then size bytes, it will be filled with 0-bytes + * + * @param hash the to be truncated/filled hash byte array + * @param size the size of the returned byte array + * @return the padded hash + */ public static byte[] getBlock0(byte[] hash, int size) { return getBlockX(hash, size, (byte)0); } @@ -334,11 +356,11 @@ public class CryptoFunctions { byte[] generatedKey = new byte[4]; //Maximum length of the password is 15 chars. - final int intMaxPasswordLength = 15; + final int maxPasswordLength = 15; if (!"".equals(password)) { // Truncate the password to 15 characters - password = password.substring(0, Math.min(password.length(), intMaxPasswordLength)); + password = password.substring(0, Math.min(password.length(), maxPasswordLength)); // Construct a new NULL-terminated string consisting of single-byte characters: // -- > Get the single-byte values by iterating through the Unicode characters of the truncated Password. @@ -362,7 +384,7 @@ public class CryptoFunctions { // the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from // the Encryption Matrix for (int i = 0; i < arrByteChars.length; i++) { - int tmp = intMaxPasswordLength - arrByteChars.length + i; + int tmp = maxPasswordLength - arrByteChars.length + i; for (int intBit = 0; intBit < 7; intBit++) { if ((arrByteChars[i] & (0x0001 << intBit)) != 0) { highOrderWord ^= EncryptionMatrix[tmp][intBit]; @@ -372,22 +394,28 @@ public class CryptoFunctions { // Compute the low-order word of the new key: - // Initialize with 0 - int lowOrderWord = 0; + // SET Verifier TO 0x0000 + short verifier = 0; - // For each character in the password, going backwards - for (int i = arrByteChars.length - 1; i >= 0; i--) { - // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character - lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[i]; + // 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]; } - // Lastly,low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR password length XOR 0xCE4B. - lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.length ^ 0xCE4B; + // 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') // The byte order of the result shall be reversed [password "Example": 0x64CEED7E becomes 7EEDCE64], // and that value shall be hashed as defined by the attribute values. - LittleEndian.putShort(generatedKey, 0, (short)lowOrderWord); + LittleEndian.putShort(generatedKey, 0, verifier); LittleEndian.putShort(generatedKey, 2, (short)highOrderWord); } @@ -424,7 +452,7 @@ public class CryptoFunctions { * @see 2.3.7.4 Binary Document Password Verifier Derivation Method 2 * * @param password the password - * @return the verifier + * @return the verifier (actually a short value) */ public static int createXorVerifier1(String password) { // the verifier for method 1 is part of the verifier for method 2 @@ -483,4 +511,25 @@ public class CryptoFunctions { private static byte rotateLeft(byte bits, int shift) { return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 - shift))); } + + private static short rotateLeftBase15Bit(short verifier) { + /* + * IF (Verifier BITWISE AND 0x4000) is 0x0000 + * SET Intermediate1 TO 0 + * ELSE + * SET Intermediate1 TO 1 + * ENDIF + */ + short intermediate1 = (short)(((verifier & 0x4000) == 0) ? 0 : 1); + /* + * SET Intermediate2 TO Verifier MULTIPLED BY 2 + * SET most significant bit of Intermediate2 TO 0 + */ + short intermediate2 = (short)((verifier<<1) & 0x7FFF); + /* + * SET Intermediate3 TO Intermediate1 BITWISE OR Intermediate2 + */ + short intermediate3 = (short)(intermediate1 | intermediate2); + return intermediate3; + } } diff --git a/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java b/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java index e69f8f0736..8f2efc2f71 100644 --- a/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java +++ b/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java @@ -68,4 +68,11 @@ public enum HashAlgorithm { } throw new EncryptedDocumentException("hash algorithm not found"); } + + public static HashAlgorithm fromString(String string) { + for (HashAlgorithm ha : values()) { + if (ha.ecmaString.equalsIgnoreCase(string) || ha.jceId.equalsIgnoreCase(string)) return ha; + } + throw new EncryptedDocumentException("hash algorithm not found"); + } } \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java index 6099bb1ece..f21f6a39a0 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java @@ -153,7 +153,8 @@ public class NPOIFSFileSystem extends BlockStore * when you're done to have the underlying file closed, as the file is * kept open during normal operation to read the data out.

* - * @param file the File from which to read the data + * @param file the File from which to read or read/write the data + * @param readOnly whether the POIFileSystem will only be used in read-only mode * * @exception IOException on errors reading, or on invalid data */ @@ -165,20 +166,40 @@ public class NPOIFSFileSystem extends BlockStore /** *

Creates a POIFSFileSystem from an open FileChannel. This uses - * less memory than creating from an InputStream.

+ * less memory than creating from an InputStream. The stream will + * be used in read-only mode.

* *

Note that with this constructor, you will need to call {@link #close()} * when you're done to have the underlying Channel closed, as the channel is * kept open during normal operation to read the data out.

* - * @param channel the FileChannel from which to read and write the data + * @param channel the FileChannel from which to read the data * * @exception IOException on errors reading, or on invalid data */ public NPOIFSFileSystem(FileChannel channel) throws IOException { - this(channel, null, false, false); + this(channel, true); + } + + /** + *

Creates a POIFSFileSystem from an open FileChannel. This uses + * less memory than creating from an InputStream.

+ * + *

Note that with this constructor, you will need to call {@link #close()} + * when you're done to have the underlying Channel closed, as the channel is + * kept open during normal operation to read the data out.

+ * + * @param channel the FileChannel from which to read or read/write the data + * @param readOnly whether the POIFileSystem will only be used in read-only mode + * + * @exception IOException on errors reading, or on invalid data + */ + public NPOIFSFileSystem(FileChannel channel, boolean readOnly) + throws IOException + { + this(channel, null, readOnly, false); } private NPOIFSFileSystem(FileChannel channel, File srcFile, boolean readOnly, boolean closeChannelOnError) diff --git a/src/java/org/apache/poi/ss/SpreadsheetVersion.java b/src/java/org/apache/poi/ss/SpreadsheetVersion.java index 8030e02283..45594d3c26 100644 --- a/src/java/org/apache/poi/ss/SpreadsheetVersion.java +++ b/src/java/org/apache/poi/ss/SpreadsheetVersion.java @@ -21,105 +21,111 @@ import org.apache.poi.ss.util.CellReference; /** * This enum allows spreadsheets from multiple Excel versions to be handled by the common code. - * Properties of this enum correspond to attributes of the spreadsheet that are easily + *

Properties of this enum correspond to attributes of the spreadsheet that are easily * discernable to the user. It is not intended to deal with low-level issues like file formats. - *

- * - * @author Josh Micich - * @author Yegor Kozlov */ public enum SpreadsheetVersion { - /** - * Excel97 format aka BIFF8 - *

    - *
  • The total number of available columns is 256 (2^8)
  • - *
  • The total number of available rows is 64k (2^16)
  • - *
  • The maximum number of arguments to a function is 30
  • - *
  • Number of conditional format conditions on a cell is 3
  • + /** + * Excel97 format aka BIFF8 + *
      + *
    • The total number of available columns is 256 (2^8)
    • + *
    • The total number of available rows is 64k (2^16)
    • + *
    • The maximum number of arguments to a function is 30
    • + *
    • Number of conditional format conditions on a cell is 3
    • + *
    • Number of cell styles is 4000
    • *
    • Length of text cell contents is 32767
    • - *
    - */ - EXCEL97(0x10000, 0x0100, 30, 3, 32767), - - /** - * Excel2007 - * - *
      - *
    • The total number of available columns is 16K (2^14)
    • - *
    • The total number of available rows is 1M (2^20)
    • - *
    • The maximum number of arguments to a function is 255
    • - *
    • Number of conditional format conditions on a cell is unlimited - * (actually limited by available memory in Excel)
    • + *
    + */ + EXCEL97(0x10000, 0x0100, 30, 3, 4000, 32767), + + /** + * Excel2007 + * + *
      + *
    • The total number of available columns is 16K (2^14)
    • + *
    • The total number of available rows is 1M (2^20)
    • + *
    • The maximum number of arguments to a function is 255
    • + *
    • Number of conditional format conditions on a cell is unlimited + * (actually limited by available memory in Excel)
    • + *
    • Number of cell styles is 64000
    • *
    • Length of text cell contents is 32767
    • - *
        - */ - EXCEL2007(0x100000, 0x4000, 255, Integer.MAX_VALUE, 32767); - - private final int _maxRows; - private final int _maxColumns; - private final int _maxFunctionArgs; - private final int _maxCondFormats; + *
          + */ + EXCEL2007(0x100000, 0x4000, 255, Integer.MAX_VALUE, 64000, 32767); + + private final int _maxRows; + private final int _maxColumns; + private final int _maxFunctionArgs; + private final int _maxCondFormats; + private final int _maxCellStyles; private final int _maxTextLength; - private SpreadsheetVersion(int maxRows, int maxColumns, int maxFunctionArgs, int maxCondFormats, int maxText) { - _maxRows = maxRows; - _maxColumns = maxColumns; - _maxFunctionArgs = maxFunctionArgs; - _maxCondFormats = maxCondFormats; + private SpreadsheetVersion(int maxRows, int maxColumns, int maxFunctionArgs, int maxCondFormats, int maxCellStyles, int maxText) { + _maxRows = maxRows; + _maxColumns = maxColumns; + _maxFunctionArgs = maxFunctionArgs; + _maxCondFormats = maxCondFormats; + _maxCellStyles = maxCellStyles; _maxTextLength = maxText; } - /** - * @return the maximum number of usable rows in each spreadsheet - */ - public int getMaxRows() { - return _maxRows; - } - - /** - * @return the last (maximum) valid row index, equals to getMaxRows() - 1 - */ - public int getLastRowIndex() { - return _maxRows - 1; - } - - /** - * @return the maximum number of usable columns in each spreadsheet - */ - public int getMaxColumns() { - return _maxColumns; - } - - /** - * @return the last (maximum) valid column index, equals to getMaxColumns() - 1 - */ - public int getLastColumnIndex() { - return _maxColumns - 1; - } - - /** - * @return the maximum number arguments that can be passed to a multi-arg function (e.g. COUNTIF) - */ - public int getMaxFunctionArgs() { - return _maxFunctionArgs; - } - - /** - * - * @return the maximum number of conditional format conditions on a cell - */ - public int getMaxConditionalFormats() { - return _maxCondFormats; - } - - /** - * - * @return the last valid column index in a ALPHA-26 representation - * (IV or XFD). - */ - public String getLastColumnName() { - return CellReference.convertNumToColString(getLastColumnIndex()); - } + /** + * @return the maximum number of usable rows in each spreadsheet + */ + public int getMaxRows() { + return _maxRows; + } + + /** + * @return the last (maximum) valid row index, equals to getMaxRows() - 1 + */ + public int getLastRowIndex() { + return _maxRows - 1; + } + + /** + * @return the maximum number of usable columns in each spreadsheet + */ + public int getMaxColumns() { + return _maxColumns; + } + + /** + * @return the last (maximum) valid column index, equals to getMaxColumns() - 1 + */ + public int getLastColumnIndex() { + return _maxColumns - 1; + } + + /** + * @return the maximum number arguments that can be passed to a multi-arg function (e.g. COUNTIF) + */ + public int getMaxFunctionArgs() { + return _maxFunctionArgs; + } + + /** + * @return the maximum number of conditional format conditions on a cell + */ + public int getMaxConditionalFormats() { + return _maxCondFormats; + } + + /** + * @return the maximum number of cell styles per spreadsheet + */ + public int getMaxCellStyles() { + return _maxCellStyles; + } + + /** + * + * @return the last valid column index in a ALPHA-26 representation + * (IV or XFD). + */ + public String getLastColumnName() { + return CellReference.convertNumToColString(getLastColumnIndex()); + } /** * @return the maximum length of a text cell @@ -127,5 +133,4 @@ public enum SpreadsheetVersion { public int getMaxTextLength() { return _maxTextLength; } - } diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java index 8a32c9c8b1..7cc1408776 100644 --- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java +++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java @@ -39,6 +39,7 @@ import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.OperandResolver; import org.apache.poi.ss.formula.eval.StringEval; import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.function.FunctionMetadataRegistry; import org.apache.poi.ss.formula.functions.Choose; import org.apache.poi.ss.formula.functions.FreeRefFunction; import org.apache.poi.ss.formula.functions.Function; @@ -486,12 +487,15 @@ public final class WorkbookEvaluator { continue; } if (evaluatedPredicate) { - // nothing to skip - true param folows + // nothing to skip - true param follows } else { int dist = attrPtg.getData(); i+= countTokensToBeSkipped(ptgs, i, dist); Ptg nextPtg = ptgs[i+1]; - if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg) { + if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg && + // in order to verify that there is no third param, we need to check + // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()! + ((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) { // this is an if statement without a false param (as opposed to MissingArgPtg as the false param) i++; stack.push(BoolEval.FALSE); diff --git a/src/java/org/apache/poi/util/ArrayUtil.java b/src/java/org/apache/poi/util/ArrayUtil.java index c8d46e1341..17f6a2964a 100644 --- a/src/java/org/apache/poi/util/ArrayUtil.java +++ b/src/java/org/apache/poi/util/ArrayUtil.java @@ -106,89 +106,4 @@ public class ArrayUtil // We're done - array will now have everything moved as required } - /** - * Copies the specified array, truncating or padding with zeros (if - * necessary) so the copy has the specified length. This method is temporary - * replace for Arrays.copyOf() until we start to require JDK 1.6. - * - * @param source - * the array to be copied - * @param newLength - * the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros to - * obtain the specified length - * @throws NegativeArraySizeException - * if newLength is negative - * @throws NullPointerException - * if original is null - */ - public static byte[] copyOf( byte[] source, int newLength ) - { - byte[] result = new byte[newLength]; - System.arraycopy( source, 0, result, 0, - Math.min( source.length, newLength ) ); - return result; - } - - /** - * Copies the specified array into specified result array, truncating or - * padding with zeros (if necessary) so the copy has the specified length. - * This method is temporary replace for Arrays.copyOf() until we start to - * require JDK 1.6. - * - * @param source - * the array to be copied - * @param result - * the array to be filled and returned - * @throws NegativeArraySizeException - * if newLength is negative - * @throws NullPointerException - * if original is null - */ - public static T[] copyOf( T[] source, T[] result ) - { - System.arraycopy( source, 0, result, 0, - Math.min( source.length, result.length ) ); - return result; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range (from) must lie between zero - * and original.length, inclusive. The value at - * original[from] is placed into the initial element of the copy - * (unless from == original.length or from == to). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * (to), which must be greater than or equal to from, - * may be greater than original.length, in which case - * (byte)0 is placed in all elements of the copy whose index is - * greater than or equal to original.length - from. The length - * of the returned array will be to - from. - * - * This method is temporary - * replace for Arrays.copyOfRange() until we start to require JDK 1.6. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if from < 0 - * or from > original.length() - * @throws IllegalArgumentException if from > to - * @throws NullPointerException if original is null - * @since 1.6 - */ - public static byte[] copyOfRange(byte[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - byte[] copy = new byte[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - } diff --git a/src/java/org/apache/poi/util/XMLHelper.java b/src/java/org/apache/poi/util/XMLHelper.java index f2da607762..3e97cee0b3 100644 --- a/src/java/org/apache/poi/util/XMLHelper.java +++ b/src/java/org/apache/poi/util/XMLHelper.java @@ -19,7 +19,6 @@ package org.apache.poi.util; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; /** * Helper methods for working with javax.xml classes. @@ -27,22 +26,31 @@ import javax.xml.parsers.ParserConfigurationException; */ public final class XMLHelper { + private static POILogger logger = POILogFactory.getLogger(XMLHelper.class); + /** * Creates a new DocumentBuilderFactory, with sensible defaults */ public static DocumentBuilderFactory getDocumentBuilderFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setExpandEntityReferences(false); + trySetSAXFeature(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true); + trySetSAXFeature(factory, "http://xml.org/sax/features/external-general-entities", false); + trySetSAXFeature(factory, "http://xml.org/sax/features/external-parameter-entities", false); + trySetSAXFeature(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + trySetSAXFeature(factory, "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); + return factory; + } + + private static void trySetSAXFeature(DocumentBuilderFactory documentBuilderFactory, String feature, boolean enabled) { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setXIncludeAware(false); - factory.setExpandEntityReferences(false); - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); - return factory; - } catch (ParserConfigurationException e) { - throw new RuntimeException("Broken XML Setup", e); + documentBuilderFactory.setFeature(feature, enabled); + } catch (Exception e) { + logger.log(POILogger.WARN, "SAX Feature unsupported", feature, e); + } catch (AbstractMethodError ame) { + logger.log(POILogger.WARN, "Cannot set SAX feature because outdated XML parser in classpath", feature, ame); } } + + } diff --git a/src/ooxml/java/org/apache/poi/POIXMLProperties.java b/src/ooxml/java/org/apache/poi/POIXMLProperties.java index d7a1719123..27c1c49d11 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLProperties.java +++ b/src/ooxml/java/org/apache/poi/POIXMLProperties.java @@ -285,6 +285,117 @@ public class POIXMLProperties { public org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties getUnderlyingProperties() { return props.getProperties(); } + + public String getTemplate() { + if (props.getProperties().isSetTemplate()) { + return props.getProperties().getTemplate(); + } + return null; + } + public String getManager() { + if (props.getProperties().isSetManager()) { + return props.getProperties().getManager(); + } + return null; + } + public String getCompany() { + if (props.getProperties().isSetCompany()) { + return props.getProperties().getCompany(); + } + return null; + } + public String getPresentationFormat() { + if (props.getProperties().isSetPresentationFormat()) { + return props.getProperties().getPresentationFormat(); + } + return null; + } + public String getApplication() { + if (props.getProperties().isSetApplication()) { + return props.getProperties().getApplication(); + } + return null; + } + public String getAppVersion() { + if (props.getProperties().isSetAppVersion()) { + return props.getProperties().getAppVersion(); + } + return null; + } + + public int getPages() { + if (props.getProperties().isSetPages()) { + return props.getProperties().getPages(); + } + return -1; + } + public int getWords() { + if (props.getProperties().isSetWords()) { + return props.getProperties().getWords(); + } + return -1; + } + public int getCharacters() { + if (props.getProperties().isSetCharacters()) { + return props.getProperties().getCharacters(); + } + return -1; + } + public int getCharactersWithSpaces() { + if (props.getProperties().isSetCharactersWithSpaces()) { + return props.getProperties().getCharactersWithSpaces(); + } + return -1; + } + public int getLines() { + if (props.getProperties().isSetLines()) { + return props.getProperties().getLines(); + } + return -1; + } + public int getParagraphs() { + if (props.getProperties().isSetParagraphs()) { + return props.getProperties().getParagraphs(); + } + return -1; + } + public int getSlides() { + if (props.getProperties().isSetSlides()) { + return props.getProperties().getSlides(); + } + return -1; + } + public int getNotes() { + if (props.getProperties().isSetNotes()) { + return props.getProperties().getNotes(); + } + return -1; + } + public int getTotalTime() { + if (props.getProperties().isSetTotalTime()) { + return props.getProperties().getTotalTime(); + } + return -1; + } + public int getHiddenSlides() { + if (props.getProperties().isSetHiddenSlides()) { + return props.getProperties().getHiddenSlides(); + } + return -1; + } + public int getMMClips() { + if (props.getProperties().isSetMMClips()) { + return props.getProperties().getMMClips(); + } + return -1; + } + + public String getHyperlinkBase() { + if (props.getProperties().isSetHyperlinkBase()) { + return props.getProperties().getHyperlinkBase(); + } + return null; + } } /** @@ -371,25 +482,46 @@ public class POIXMLProperties { * * @return next property id starting with 2 */ - protected int nextPid(){ + @SuppressWarnings("deprecation") + protected int nextPid(){ int propid = 1; - for(CTProperty p : props.getProperties().getPropertyList()){ + for(CTProperty p : props.getProperties().getPropertyArray()){ if(p.getPid() > propid) propid = p.getPid(); } return propid + 1; } - /** - * Check if a property with this name already exists in the collection of custom properties - * - * @param name the name to check - * @return whether a property with the given name exists in the custom properties - */ - public boolean contains(String name){ - for(CTProperty p : props.getProperties().getPropertyList()){ - if(p.getName().equals(name)) return true; - } - return false; - } - } + /** + * Check if a property with this name already exists in the collection of custom properties + * + * @param name the name to check + * @return whether a property with the given name exists in the custom properties + */ + @SuppressWarnings("deprecation") + public boolean contains(String name) { + for(CTProperty p : props.getProperties().getPropertyArray()){ + if(p.getName().equals(name)) return true; + } + return false; + } + + /** + * Retrieve the custom property with this name, or null if none exists. + * + * You will need to test the various isSetX methods to work out + * what the type of the property is, before fetching the + * appropriate value for it. + * + * @param name the name of the property to fetch + */ + @SuppressWarnings("deprecation") + public CTProperty getProperty(String name) { + for(CTProperty p : props.getProperties().getPropertyArray()){ + if(p.getName().equals(name)) { + return p; + } + } + return null; + } + } } diff --git a/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java b/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java index 51a4399f3f..ce576439f2 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java +++ b/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java @@ -19,7 +19,6 @@ package org.apache.poi; import java.math.BigDecimal; import java.util.Date; -import java.util.List; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty; @@ -126,13 +125,13 @@ public class POIXMLPropertiesTextExtractor extends POIXMLTextExtractor { * Returns the custom document properties, if * there are any */ + @SuppressWarnings("deprecation") public String getCustomPropertiesText() { - StringBuffer text = new StringBuffer(); + StringBuilder text = new StringBuilder(); org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperties props = getDocument().getProperties().getCustomProperties().getUnderlyingProperties(); - List properties = props.getPropertyList(); - for(CTProperty property : properties) { + for(CTProperty property : props.getPropertyArray()) { String val = "(not implemented!)"; if (property.isSetLpwstr()) { diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java index 2732c825ea..08d82fbaab 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java @@ -24,9 +24,9 @@ import java.util.TreeMap; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidOperationException; +import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; -import org.apache.poi.util.SAXHelper; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -311,7 +311,7 @@ public final class PackageRelationshipCollection implements throws InvalidFormatException { try { logger.log(POILogger.DEBUG, "Parsing relationship: " + relPart.getPartName()); - Document xmlRelationshipsDoc = SAXHelper.readSAXDocument(relPart.getInputStream()); + Document xmlRelationshipsDoc = DocumentHelper.readDocument(relPart.getInputStream()); // Browse default types Element root = xmlRelationshipsDoc.getDocumentElement(); 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 8aa4b7d1dd..59801d3aee 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 @@ -33,7 +33,6 @@ 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.util.DocumentHelper; -import org.apache.poi.util.SAXHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -370,7 +369,7 @@ public abstract class ContentTypeManager { private void parseContentTypesFile(InputStream in) throws InvalidFormatException { try { - Document xmlContentTypetDoc = SAXHelper.readSAXDocument(in); + Document xmlContentTypetDoc = DocumentHelper.readDocument(in); // Default content types NodeList defaultTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagName(DEFAULT_TAG_NAME); diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java index b4e3e83723..eb94f680e6 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java @@ -31,7 +31,7 @@ import org.apache.poi.openxml4j.opc.ZipPackage; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.apache.poi.openxml4j.opc.internal.PartUnmarshaller; import org.apache.poi.openxml4j.opc.internal.ZipHelper; -import org.apache.poi.util.SAXHelper; +import org.apache.poi.util.DocumentHelper; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -105,7 +105,7 @@ public final class PackagePropertiesUnmarshaller implements PartUnmarshaller { Document xmlDoc; try { - xmlDoc = SAXHelper.readSAXDocument(in); + xmlDoc = DocumentHelper.readDocument(in); /* Check OPC compliance */ diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java index e7eb140e1a..d5dc363e73 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java @@ -57,9 +57,9 @@ import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService; import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService; import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; +import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; -import org.apache.poi.util.SAXHelper; import org.apache.xml.security.Init; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlException; @@ -127,7 +127,7 @@ public class SignatureInfo { throws NoSuchAlgorithmException, IOException, MarshalException, ParserConfigurationException, XmlException { XmlSignatureService signatureService = createSignatureService(hashAlgo, pkg); - Document document = SAXHelper.getDocumentBuilder().newDocument(); + Document document = DocumentHelper.createDocument(); // operate List x509Chain = Collections.singletonList(x509); @@ -181,7 +181,7 @@ public class SignatureInfo { KeyInfoKeySelector keySelector = new KeyInfoKeySelector(); try { - Document doc = SAXHelper.readSAXDocument(signaturePart.getInputStream()); + Document doc = DocumentHelper.readDocument(signaturePart.getInputStream()); // dummy call to createSignatureService to tweak document afterwards createSignatureService(HashAlgorithm.sha1, pkg).registerIds(doc); diff --git a/src/ooxml/java/org/apache/poi/util/DocumentHelper.java b/src/ooxml/java/org/apache/poi/util/DocumentHelper.java index 22bdd4e0fd..0c18b5d009 100644 --- a/src/ooxml/java/org/apache/poi/util/DocumentHelper.java +++ b/src/ooxml/java/org/apache/poi/util/DocumentHelper.java @@ -17,6 +17,10 @@ package org.apache.poi.util; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; + import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -25,20 +29,81 @@ import javax.xml.stream.events.Namespace; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.SAXException; -public class DocumentHelper { +public final class DocumentHelper { + private static POILogger logger = POILogFactory.getLogger(DocumentHelper.class); + + private DocumentHelper() {} - private static final DocumentBuilder newDocumentBuilder; - static { + /** + * Creates a new document builder, with sensible defaults + */ + public static synchronized DocumentBuilder newDocumentBuilder() { try { - newDocumentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + documentBuilder.setEntityResolver(SAXHelper.IGNORING_ENTITY_RESOLVER); + return documentBuilder; } catch (ParserConfigurationException e) { throw new IllegalStateException("cannot create a DocumentBuilder", e); } } + private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + static { + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setValidating(false); + trySetSAXFeature(documentBuilderFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true); + trySetXercesSecurityManager(documentBuilderFactory); + } + + private static void trySetSAXFeature(DocumentBuilderFactory documentBuilderFactory, String feature, boolean enabled) { + try { + documentBuilderFactory.setFeature(feature, enabled); + } catch (Exception e) { + logger.log(POILogger.WARN, "SAX Feature unsupported", feature, e); + } catch (AbstractMethodError ame) { + logger.log(POILogger.WARN, "Cannot set SAX feature because outdated XML parser in classpath", feature, ame); + } + } + + private static void trySetXercesSecurityManager(DocumentBuilderFactory documentBuilderFactory) { + // Try built-in JVM one first, standalone if not + for (String securityManagerClassName : new String[] { + "com.sun.org.apache.xerces.internal.util.SecurityManager", + "org.apache.xerces.util.SecurityManager" + }) { + try { + Object mgr = Class.forName(securityManagerClassName).newInstance(); + Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE); + setLimit.invoke(mgr, 4096); + documentBuilderFactory.setAttribute("http://apache.org/xml/properties/security-manager", mgr); + // Stop once one can be setup without error + return; + } catch (Exception e) { + logger.log(POILogger.WARN, "SAX Security Manager could not be setup", e); + } + } + } + + /** + * Parses the given stream via the default (sensible) + * DocumentBuilder + * @param inp Stream to read the XML data from + * @return the parsed Document + */ + public static Document readDocument(InputStream inp) throws IOException, SAXException { + return newDocumentBuilder().parse(inp); + } + + // must only be used to create empty documents, do not use it for parsing! + private static final DocumentBuilder documentBuilderSingleton = newDocumentBuilder(); + + /** + * Creates a new DOM Document + */ public static synchronized Document createDocument() { - return newDocumentBuilder.newDocument(); + return documentBuilderSingleton.newDocument(); } /** diff --git a/src/ooxml/java/org/apache/poi/util/SAXHelper.java b/src/ooxml/java/org/apache/poi/util/SAXHelper.java index 81049a9a2e..d4d016cb3b 100644 --- a/src/ooxml/java/org/apache/poi/util/SAXHelper.java +++ b/src/ooxml/java/org/apache/poi/util/SAXHelper.java @@ -18,19 +18,17 @@ package org.apache.poi.util; import java.io.IOException; -import java.io.InputStream; import java.io.StringReader; import java.lang.reflect.Method; import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; -import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; /** @@ -39,43 +37,45 @@ import org.xml.sax.SAXException; public final class SAXHelper { private static POILogger logger = POILogFactory.getLogger(SAXHelper.class); - private static final EntityResolver IGNORING_ENTITY_RESOLVER = new EntityResolver() { + private SAXHelper() {} + + /** + * Creates a new SAX XMLReader, with sensible defaults + */ + public static synchronized XMLReader newXMLReader() throws SAXException, ParserConfigurationException { + XMLReader xmlReader = saxFactory.newSAXParser().getXMLReader(); + xmlReader.setEntityResolver(IGNORING_ENTITY_RESOLVER); + trySetSAXFeature(xmlReader, XMLConstants.FEATURE_SECURE_PROCESSING, true); + trySetXercesSecurityManager(xmlReader); + return xmlReader; + } + + static final EntityResolver IGNORING_ENTITY_RESOLVER = new EntityResolver() { @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { return new InputSource(new StringReader("")); } }; - - private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + + private static final SAXParserFactory saxFactory; static { - documentBuilderFactory.setNamespaceAware(true); - documentBuilderFactory.setValidating(false); - trySetSAXFeature(documentBuilderFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true); - trySetXercesSecurityManager(documentBuilderFactory); - } - - /** - * Creates a new document builder, with sensible defaults - */ - public static synchronized DocumentBuilder getDocumentBuilder() { - try { - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - documentBuilder.setEntityResolver(IGNORING_ENTITY_RESOLVER); - return documentBuilder; - } catch (ParserConfigurationException e) { - throw new IllegalStateException("cannot create a DocumentBuilder", e); - } + saxFactory = SAXParserFactory.newInstance(); + saxFactory.setValidating(false); + saxFactory.setNamespaceAware(true); } - - private static void trySetSAXFeature(DocumentBuilderFactory documentBuilderFactory, String feature, boolean enabled) { + + private static void trySetSAXFeature(XMLReader xmlReader, String feature, boolean enabled) { try { - documentBuilderFactory.setFeature(feature, enabled); + xmlReader.setFeature(feature, enabled); } catch (Exception e) { - logger.log(POILogger.INFO, "SAX Feature unsupported", feature, e); + logger.log(POILogger.WARN, "SAX Feature unsupported", feature, e); + } catch (AbstractMethodError ame) { + logger.log(POILogger.WARN, "Cannot set SAX feature because outdated XML parser in classpath", feature, ame); } } - private static void trySetXercesSecurityManager(DocumentBuilderFactory documentBuilderFactory) { + + private static void trySetXercesSecurityManager(XMLReader xmlReader) { // Try built-in JVM one first, standalone if not for (String securityManagerClassName : new String[] { "com.sun.org.apache.xerces.internal.util.SecurityManager", @@ -85,22 +85,12 @@ public final class SAXHelper { Object mgr = Class.forName(securityManagerClassName).newInstance(); Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE); setLimit.invoke(mgr, 4096); - documentBuilderFactory.setAttribute("http://apache.org/xml/properties/security-manager", mgr); + xmlReader.setProperty("http://apache.org/xml/properties/security-manager", mgr); // Stop once one can be setup without error return; } catch (Exception e) { - logger.log(POILogger.INFO, "SAX Security Manager could not be setup", e); + logger.log(POILogger.WARN, "SAX Security Manager could not be setup", e); } } } - - /** - * Parses the given stream via the default (sensible) - * SAX Reader - * @param inp Stream to read the XML data from - * @return the SAX processed Document - */ - public static Document readSAXDocument(InputStream inp) throws IOException, SAXException { - return getDocumentBuilder().parse(inp); - } } diff --git a/src/ooxml/java/org/apache/poi/xslf/XSLFSlideShow.java b/src/ooxml/java/org/apache/poi/xslf/XSLFSlideShow.java index b6523bedde..7f0f1b773c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/XSLFSlideShow.java +++ b/src/ooxml/java/org/apache/poi/xslf/XSLFSlideShow.java @@ -31,7 +31,20 @@ import org.apache.poi.util.Internal; import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.poi.xslf.usermodel.XSLFRelation; import org.apache.xmlbeans.XmlException; -import org.openxmlformats.schemas.presentationml.x2006.main.*; +import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentList; +import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesSlide; +import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation; +import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide; +import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdList; +import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry; +import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster; +import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdList; +import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdListEntry; +import org.openxmlformats.schemas.presentationml.x2006.main.CmLstDocument; +import org.openxmlformats.schemas.presentationml.x2006.main.NotesDocument; +import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument; +import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument; +import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; /** * Experimental class to do low level processing of pptx files. @@ -53,6 +66,7 @@ public class XSLFSlideShow extends POIXMLDocument { */ private List embedds; + @SuppressWarnings("deprecation") public XSLFSlideShow(OPCPackage container) throws OpenXML4JException, IOException, XmlException { super(container); @@ -64,7 +78,7 @@ public class XSLFSlideShow extends POIXMLDocument { PresentationDocument.Factory.parse(getCorePart().getInputStream()); embedds = new LinkedList(); - for (CTSlideIdListEntry ctSlide : getSlideReferences().getSldIdList()) { + for (CTSlideIdListEntry ctSlide : getSlideReferences().getSldIdArray()) { PackagePart corePart = getCorePart(); PackagePart slidePart = corePart.getRelatedPart( corePart.getRelationship(ctSlide.getId2())); diff --git a/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java b/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java index 4c3693d3e5..67f1067b71 100644 --- a/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java +++ b/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java @@ -118,6 +118,7 @@ public class XSLFPowerPointExtractor extends POIXMLTextExtractor { * @param notesText Should we retrieve text from notes? * @param masterText Should we retrieve text from master slides? */ + @SuppressWarnings("deprecation") public String getText(boolean slideText, boolean notesText, boolean masterText) { StringBuffer text = new StringBuffer(); @@ -150,7 +151,7 @@ public class XSLFPowerPointExtractor extends POIXMLTextExtractor { // If the slide has comments, do those too if (comments != null) { - for (CTComment comment : comments.getCTCommentsList().getCmList()) { + for (CTComment comment : comments.getCTCommentsList().getCmArray()) { // Do the author if we can if (commentAuthors != null) { CTCommentAuthor author = commentAuthors.getAuthorById(comment.getAuthorId()); diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java index 5a81c307a5..4e30ac90d9 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java @@ -19,12 +19,17 @@ package org.apache.poi.xslf.model.geom; -import org.openxmlformats.schemas.drawingml.x2006.main.*; - import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.openxmlformats.schemas.drawingml.x2006.main.CTCustomGeometry2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuideList; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomRect; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPath2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPath2DList; + /** * Definition of a custom geometric shape * @@ -36,19 +41,20 @@ public class CustomGeometry implements Iterable{ List paths = new ArrayList(); Path textBounds; + @SuppressWarnings("deprecation") public CustomGeometry(CTCustomGeometry2D geom) { CTGeomGuideList avLst = geom.getAvLst(); - if(avLst != null) for(CTGeomGuide gd : avLst.getGdList()){ + if(avLst != null) for(CTGeomGuide gd : avLst.getGdArray()){ adjusts.add(new AdjustValue(gd)); } CTGeomGuideList gdLst = geom.getGdLst(); - if(gdLst != null) for(CTGeomGuide gd : gdLst.getGdList()){ + if(gdLst != null) for(CTGeomGuide gd : gdLst.getGdArray()){ guides.add(new Guide(gd)); } CTPath2DList pathLst = geom.getPathLst(); - if(pathLst != null) for(CTPath2D spPath : pathLst.getPathList()){ + if(pathLst != null) for(CTPath2D spPath : pathLst.getPathArray()){ paths.add(new Path(spPath)); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/DrawingTable.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/DrawingTable.java index c6d7da9f2b..2cc7724c79 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/DrawingTable.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/DrawingTable.java @@ -20,8 +20,6 @@ package org.apache.poi.xslf.usermodel; import org.openxmlformats.schemas.drawingml.x2006.main.CTTable; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow; -import java.util.List; - public class DrawingTable { private final CTTable table; @@ -29,12 +27,13 @@ public class DrawingTable { this.table = table; } + @SuppressWarnings("deprecation") public DrawingTableRow[] getRows() { - List ctTableRows = table.getTrList(); - DrawingTableRow[] o = new DrawingTableRow[ctTableRows.size()]; + CTTableRow[] ctTableRows = table.getTrArray(); + DrawingTableRow[] o = new DrawingTableRow[ctTableRows.length]; for (int i=0; i ctTableCells = row.getTcList(); - DrawingTableCell[] o = new DrawingTableCell[ctTableCells.size()]; + CTTableCell[] ctTableCells = row.getTcArray(); + DrawingTableCell[] o = new DrawingTableCell[ctTableCells.length]; for (int i=0; i paragraphs = textBody.getPList(); - DrawingParagraph[] o = new DrawingParagraph[paragraphs.size()]; + CTTextParagraph[] paragraphs = textBody.getPArray(); + DrawingParagraph[] o = new DrawingParagraph[paragraphs.length]; for (int i=0; i computeOutlines(Graphics2D graphics) { Collection lst = new ArrayList(); @@ -576,7 +577,7 @@ class RenderableShape { public Guide getAdjustValue(String name) { CTPresetGeometry2D prst = _shape.getSpPr().getPrstGeom(); if (prst.isSetAvLst()) { - for (CTGeomGuide g : prst.getAvLst().getGdList()) { + for (CTGeomGuide g : prst.getAvLst().getGdArray()) { if (g.getName().equals(name)) { return new Guide(g); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java index de31fb2fd6..69dc029523 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java @@ -115,6 +115,7 @@ public class XMLSlideShow extends POIXMLDocument { } @Override + @SuppressWarnings("deprecation") protected void onDocumentRead() throws IOException { try { PresentationDocument doc = @@ -140,8 +141,7 @@ public class XMLSlideShow extends POIXMLDocument { _slides = new ArrayList(); if (_presentation.isSetSldIdLst()) { - List slideIds = _presentation.getSldIdLst().getSldIdList(); - for (CTSlideIdListEntry slId : slideIds) { + for (CTSlideIdListEntry slId : _presentation.getSldIdLst().getSldIdArray()) { XSLFSlide sh = shIdMap.get(slId.getId2()); if (sh == null) { _logger.log(POILogger.WARN, "Slide with r:id " + slId.getId() + " was defined, but didn't exist in package, skipping"); @@ -201,13 +201,14 @@ public class XMLSlideShow extends POIXMLDocument { * @param layout * @return created slide */ + @SuppressWarnings("deprecation") public XSLFSlide createSlide(XSLFSlideLayout layout) { int slideNumber = 256, cnt = 1; CTSlideIdList slideList; if (!_presentation.isSetSldIdLst()) slideList = _presentation.addNewSldIdLst(); else { slideList = _presentation.getSldIdLst(); - for(CTSlideIdListEntry slideId : slideList.getSldIdList()){ + for(CTSlideIdListEntry slideId : slideList.getSldIdArray()){ slideNumber = (int)Math.max(slideId.getId() + 1, slideNumber); cnt++; } @@ -283,16 +284,16 @@ public class XMLSlideShow extends POIXMLDocument { _slides.add(newIndex, _slides.remove(oldIndex)); // fix ordering in the low-level xml - List slideIds = _presentation.getSldIdLst().getSldIdList(); - CTSlideIdListEntry oldEntry = slideIds.get(oldIndex); - slideIds.add(newIndex, oldEntry); - slideIds.remove(oldEntry); + CTSlideIdList sldIdLst = _presentation.getSldIdLst(); + CTSlideIdListEntry oldEntry = sldIdLst.getSldIdArray(oldIndex); + sldIdLst.insertNewSldId(newIndex).set(oldEntry); + sldIdLst.removeSldId(oldIndex); } public XSLFSlide removeSlide(int index){ XSLFSlide slide = _slides.remove(index); removeRelation(slide); - _presentation.getSldIdLst().getSldIdList().remove(index); + _presentation.getSldIdLst().removeSldId(index); return slide; } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommentAuthors.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommentAuthors.java index 23ddb4d534..e52b9ec651 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommentAuthors.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommentAuthors.java @@ -17,6 +17,8 @@ package org.apache.poi.xslf.usermodel; +import java.io.IOException; + import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; @@ -26,8 +28,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthor; import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthorList; import org.openxmlformats.schemas.presentationml.x2006.main.CmAuthorLstDocument; -import java.io.IOException; - @Beta public class XSLFCommentAuthors extends POIXMLDocumentPart { private final CTCommentAuthorList _authors; @@ -61,9 +61,10 @@ public class XSLFCommentAuthors extends POIXMLDocumentPart { return _authors; } + @SuppressWarnings("deprecation") public CTCommentAuthor getAuthorById(long id) { // TODO Have a map - for (CTCommentAuthor author : _authors.getCmAuthorList()) { + for (CTCommentAuthor author : _authors.getCmAuthorArray()) { if (author.getId() == id) { return author; } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java index 9eed7ec7e0..df3ca7ad05 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFComments.java @@ -66,6 +66,6 @@ public class XSLFComments extends POIXMLDocumentPart { } public CTComment getCommentAt(int pos) { - return _comments.getCmList().get(pos); + return _comments.getCmArray(pos); } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommonSlideData.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommonSlideData.java index b099b64571..0033665aa5 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommonSlideData.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFCommonSlideData.java @@ -17,6 +17,10 @@ package org.apache.poi.xslf.usermodel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.apache.poi.POIXMLException; import org.apache.poi.util.Beta; import org.apache.xmlbeans.XmlCursor; @@ -32,10 +36,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - @Beta public class XSLFCommonSlideData { private final CTCommonSlideData data; @@ -44,6 +44,7 @@ public class XSLFCommonSlideData { this.data = data; } + @SuppressWarnings("deprecation") public List getDrawingText() { CTGroupShape gs = data.getSpTree(); @@ -51,11 +52,11 @@ public class XSLFCommonSlideData { processShape(gs, out); - for (CTGroupShape shape : gs.getGrpSpList()) { + for (CTGroupShape shape : gs.getGrpSpArray()) { processShape(shape, out); } - for (CTGraphicalObjectFrame frame: gs.getGraphicFrameList()) { + for (CTGraphicalObjectFrame frame: gs.getGraphicFrameArray()) { CTGraphicalObjectData data = frame.getGraphic().getGraphicData(); XmlCursor c = data.newCursor(); c.selectPath("declare namespace pic='"+CTTable.type.getName().getNamespaceURI()+"' .//pic:tbl"); @@ -97,9 +98,9 @@ public class XSLFCommonSlideData { return paragraphs; } + @SuppressWarnings("deprecation") private void processShape(CTGroupShape gs, List out) { - List shapes = gs.getSpList(); - for (CTShape shape : shapes) { + for (CTShape shape : gs.getSpArray()) { CTTextBody ctTextBody = shape.getTxBody(); if (ctTextBody==null) { continue; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java index 36afac5f8c..a95e0bbb92 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java @@ -19,6 +19,11 @@ package org.apache.poi.xslf.usermodel; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; + import org.apache.poi.util.Beta; import org.apache.poi.util.Units; import org.apache.xmlbeans.XmlObject; @@ -35,11 +40,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; - /** * Represents a custom geometric shape. * This shape will consist of a series of lines and curves described within a creation path. @@ -120,12 +120,13 @@ public class XSLFFreeformShape extends XSLFAutoShape { * * @return the path */ + @SuppressWarnings("deprecation") public GeneralPath getPath() { GeneralPath path = new GeneralPath(); Rectangle2D bounds = getAnchor(); CTCustomGeometry2D geom = getSpPr().getCustGeom(); - for(CTPath2D spPath : geom.getPathLst().getPathList()){ + for(CTPath2D spPath : geom.getPathLst().getPathArray()){ double scaleW = bounds.getWidth() / Units.toPoints(spPath.getW()); double scaleH = bounds.getHeight() / Units.toPoints(spPath.getH()); for(XmlObject ch : spPath.selectPath("*")){ diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java index 6d6e631b52..43d151c66d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java @@ -213,7 +213,7 @@ public class XSLFPictureShape extends XSLFSimpleShape { if(blip.isSetExtLst()) { CTOfficeArtExtensionList extLst = blip.getExtLst(); - for(CTOfficeArtExtension ext : extLst.getExtList()){ + for(CTOfficeArtExtension ext : extLst.getExtArray()){ String xpath = "declare namespace a14='http://schemas.microsoft.com/office/drawing/2010/main' $this//a14:imgProps/a14:imgLayer"; XmlObject[] obj = ext.selectPath(xpath); if(obj != null && obj.length == 1){ diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java index b8b2690509..a6ec8bcfe7 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java @@ -51,6 +51,7 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable _rows; + @SuppressWarnings("deprecation") /*package*/ XSLFTable(CTGraphicalObjectFrame shape, XSLFSheet sheet){ super(shape, sheet); @@ -71,8 +72,9 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable(_table.sizeOfTrArray()); - for(CTTableRow row : _table.getTrList()) _rows.add(new XSLFTableRow(row, this)); + CTTableRow[] trArray = _table.getTrArray(); + _rows = new ArrayList(trArray.length); + for(CTTableRow row : trArray) _rows.add(new XSLFTableRow(row, this)); } @Internal diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java index c0067e9c75..04e9742aa3 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java @@ -19,15 +19,15 @@ package org.apache.poi.xslf.usermodel; -import org.apache.poi.util.Units; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import org.apache.poi.util.Units; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow; + /** * Represents a table in a .pptx presentation * @@ -38,11 +38,13 @@ public class XSLFTableRow implements Iterable { private List _cells; private XSLFTable _table; + @SuppressWarnings("deprecation") /*package*/ XSLFTableRow(CTTableRow row, XSLFTable table){ _row = row; _table = table; - _cells = new ArrayList(_row.sizeOfTcArray()); - for(CTTableCell cell : _row.getTcList()) { + CTTableCell[] tcArray = _row.getTcArray(); + _cells = new ArrayList(tcArray.length); + for(CTTableCell cell : tcArray) { _cells.add(new XSLFTableCell(cell, table.getSheet())); } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java index 4ab67e2de5..245bbaae9d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java @@ -16,6 +16,12 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; @@ -24,12 +30,6 @@ import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleList; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - @Beta public class XSLFTableStyles extends POIXMLDocumentPart implements Iterable{ private CTTableStyleList _tblStyleLst; @@ -39,12 +39,14 @@ public class XSLFTableStyles extends POIXMLDocumentPart implements Iterable(_tblStyleLst.sizeOfTblStyleArray()); - for(CTTableStyle c : _tblStyleLst.getTblStyleList()){ + CTTableStyle[] tblStyleArray = _tblStyleLst.getTblStyleArray(); + _styles = new ArrayList(tblStyleArray.length); + for(CTTableStyle c : tblStyleArray){ _styles.add(new XSLFTableStyle(c)); } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java index af1c174c6a..d5ae1a2527 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java @@ -19,6 +19,14 @@ package org.apache.poi.xslf.usermodel; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.apache.poi.POIXMLException; import org.apache.poi.util.Beta; import org.apache.poi.util.Units; @@ -36,14 +44,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - /** * Represents a shape that can hold text. * @@ -58,13 +58,14 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable< */ private boolean _isTextBroken; + @SuppressWarnings("deprecation") /*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) { super(shape, sheet); _paragraphs = new ArrayList(); CTTextBody txBody = getTextBody(false); if (txBody != null) { - for (CTTextParagraph p : txBody.getPList()) { + for (CTTextParagraph p : txBody.getPArray()) { _paragraphs.add(new XSLFTextParagraph(p, this)); } } diff --git a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java index a8973dd32e..5263473bca 100644 --- a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/ReadOnlySharedStringsTable.java @@ -22,12 +22,11 @@ import java.util.ArrayList; import java.util.List; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.util.SAXHelper; import org.apache.poi.xssf.usermodel.XSSFRelation; import org.xml.sax.Attributes; import org.xml.sax.InputSource; @@ -134,10 +133,8 @@ public class ReadOnlySharedStringsTable extends DefaultHandler { */ public void readFrom(InputStream is) throws IOException, SAXException { InputSource sheetSource = new InputSource(is); - SAXParserFactory saxFactory = SAXParserFactory.newInstance(); try { - SAXParser saxParser = saxFactory.newSAXParser(); - XMLReader sheetParser = saxParser.getXMLReader(); + XMLReader sheetParser = SAXHelper.newXMLReader(); sheetParser.setContentHandler(this); sheetParser.parse(sheetSource); } catch(ParserConfigurationException e) { diff --git a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java index baaac30406..7677426876 100644 --- a/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java +++ b/src/ooxml/java/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.java @@ -18,7 +18,6 @@ package org.apache.poi.xssf.eventusermodel; import java.util.Comparator; import java.util.LinkedList; -import java.util.List; import java.util.Queue; import org.apache.poi.ss.usermodel.BuiltinFormats; @@ -159,11 +158,11 @@ public class XSSFSheetXMLHandler extends DefaultHandler { this(styles, strings, sheetContentsHandler, new DataFormatter(), formulasNotResults); } + @SuppressWarnings("deprecation") private void init() { if (commentsTable != null) { commentCellRefs = new LinkedList(); - List commentList = commentsTable.getCTComments().getCommentList().getCommentList(); - for (CTComment comment : commentList) { + for (CTComment comment : commentsTable.getCTComments().getCommentList().getCommentArray()) { commentCellRefs.add(new CellReference(comment.getRef())); } } @@ -187,6 +186,7 @@ public class XSSFSheetXMLHandler extends DefaultHandler { } @Override + @SuppressWarnings("unused") public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java index b70c4abb34..c52bed687d 100644 --- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java +++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFEventBasedExcelExtractor.java @@ -24,8 +24,6 @@ import java.util.Locale; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import org.apache.poi.POIXMLProperties; import org.apache.poi.POIXMLProperties.CoreProperties; @@ -35,6 +33,7 @@ import org.apache.poi.POIXMLTextExtractor; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.util.SAXHelper; import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler; @@ -174,10 +173,8 @@ public class XSSFEventBasedExcelExtractor extends POIXMLTextExtractor } InputSource sheetSource = new InputSource(sheetInputStream); - SAXParserFactory saxFactory = SAXParserFactory.newInstance(); try { - SAXParser saxParser = saxFactory.newSAXParser(); - XMLReader sheetParser = saxParser.getXMLReader(); + XMLReader sheetParser = SAXHelper.newXMLReader(); ContentHandler handler = new XSSFSheetXMLHandler( styles, comments, strings, sheetContentsExtractor, formatter, formulasNotResults); sheetParser.setContentHandler(handler); 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 e9b75e5365..d608f96157 100644 --- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java +++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java @@ -28,8 +28,6 @@ import java.util.List; import java.util.Map; import java.util.Vector; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; @@ -45,7 +43,7 @@ import javax.xml.validation.Validator; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.util.XMLHelper; +import org.apache.poi.util.DocumentHelper; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFMap; import org.apache.poi.xssf.usermodel.XSSFRow; @@ -106,15 +104,6 @@ public class XSSFExportToXml implements Comparator{ exportToXML(os, "UTF-8", validate); } - private Document getEmptyDocument() throws ParserConfigurationException{ - - DocumentBuilderFactory dbfac = XMLHelper.getDocumentBuilderFactory(); - DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); - Document doc = docBuilder.newDocument(); - - return doc; - } - /** * Exports the data in an XML stream * @@ -132,7 +121,7 @@ public class XSSFExportToXml implements Comparator{ String rootElement = map.getCtMap().getRootElement(); - Document doc = getEmptyDocument(); + Document doc = DocumentHelper.createDocument(); Element root = null; @@ -459,8 +448,8 @@ public class XSSFExportToXml implements Comparator{ Node node = list.item(i); if (node instanceof Element) { if (node.getLocalName().equals("element")) { - Node nameAttribute = node.getAttributes().getNamedItem("name"); - if (nameAttribute.getNodeValue().equals(removeNamespace(elementName))) { + Node element = getNameOrRefElement(node); + if (element.getNodeValue().equals(removeNamespace(elementName))) { indexOf = i; break; } @@ -471,6 +460,15 @@ public class XSSFExportToXml implements Comparator{ return indexOf; } + private Node getNameOrRefElement(Node node) { + Node returnNode = node.getAttributes().getNamedItem("name"); + if(returnNode != null) { + return returnNode; + } + + return node.getAttributes().getNamedItem("ref"); + } + private Node getComplexTypeForElement(String elementName,Node xmlSchema,Node localComplexTypeRootNode) { String elementNameWithoutNamespace = removeNamespace(elementName); @@ -494,7 +492,7 @@ public class XSSFExportToXml implements Comparator{ Node node = list.item(i); if ( node instanceof Element) { if (node.getLocalName().equals("element")) { - Node nameAttribute = node.getAttributes().getNamedItem("name"); + Node nameAttribute = getNameOrRefElement(node); if (nameAttribute.getNodeValue().equals(elementNameWithoutNamespace)) { Node complexTypeAttribute = node.getAttributes().getNamedItem("type"); if (complexTypeAttribute!=null) { @@ -515,7 +513,7 @@ public class XSSFExportToXml implements Comparator{ Node node = complexTypeList.item(i); if ( node instanceof Element) { if (node.getLocalName().equals("complexType")) { - Node nameAttribute = node.getAttributes().getNamedItem("name"); + Node nameAttribute = getNameOrRefElement(node); if (nameAttribute.getNodeValue().equals(complexTypeName)) { NodeList complexTypeChildList =node.getChildNodes(); diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java index 945f1677ca..534ef0d83e 100644 --- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java +++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java @@ -24,16 +24,15 @@ import java.util.List; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; -import org.apache.poi.util.XMLHelper; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFMap; import org.apache.poi.xssf.usermodel.XSSFRow; @@ -76,11 +75,9 @@ public class XSSFImportFromXML { * @throws ParserConfigurationException if there are problems with XML parser configuration * @throws IOException if there are problems reading the input string */ - public void importFromXML(String xmlInputString) throws SAXException, XPathExpressionException, ParserConfigurationException, IOException { + public void importFromXML(String xmlInputString) throws SAXException, XPathExpressionException, IOException { - DocumentBuilderFactory factory = XMLHelper.getDocumentBuilderFactory(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); + DocumentBuilder builder = DocumentHelper.newDocumentBuilder(); Document doc = builder.parse(new InputSource(new StringReader(xmlInputString.trim()))); diff --git a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java index f3799ab24e..95bbf2907c 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java @@ -98,9 +98,11 @@ public class CommentsTable extends POIXMLDocumentPart { return comments.getAuthors().getAuthorArray((int)authorId); } + @SuppressWarnings("deprecation") public int findAuthor(String author) { - for (int i = 0 ; i < comments.getAuthors().sizeOfAuthorArray() ; i++) { - if (comments.getAuthors().getAuthorArray(i).equals(author)) { + String[] authorArray = comments.getAuthors().getAuthorArray(); + for (int i = 0 ; i < authorArray.length; i++) { + if (authorArray[i].equals(author)) { return i; } } @@ -149,15 +151,18 @@ public class CommentsTable extends POIXMLDocumentPart { public boolean removeComment(String cellRef) { CTCommentList lst = comments.getCommentList(); - if(lst != null) for(int i=0; i < lst.sizeOfCommentArray(); i++) { - CTComment comment = lst.getCommentArray(i); - if (cellRef.equals(comment.getRef())) { - lst.removeComment(i); - - if(commentRefs != null) { - commentRefs.remove(cellRef); + if(lst != null) { + CTComment[] commentArray = lst.getCommentArray(); + for (int i = 0; i < commentArray.length; i++) { + CTComment comment = commentArray[i]; + if (cellRef.equals(comment.getRef())) { + lst.removeComment(i); + + if(commentRefs != null) { + commentRefs.remove(cellRef); + } + return true; } - return true; } } return false; diff --git a/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java b/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java index f664f6bbc0..33c161b4c3 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; - import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; @@ -66,13 +65,14 @@ public class MapInfo extends POIXMLDocumentPart { readFrom(part.getInputStream()); } + @SuppressWarnings("deprecation") public void readFrom(InputStream is) throws IOException { try { MapInfoDocument doc = MapInfoDocument.Factory.parse(is); mapInfo = doc.getMapInfo(); maps= new HashMap(); - for(CTMap map :mapInfo.getMapList()){ + for(CTMap map :mapInfo.getMapArray()){ maps.put((int)map.getID(), new XSSFMap(map,this)); } @@ -104,10 +104,11 @@ public class MapInfo extends POIXMLDocumentPart { * @param schemaId the schema ID * @return CTSchema by it's ID */ + @SuppressWarnings("deprecation") public CTSchema getCTSchemaById(String schemaId){ CTSchema xmlSchema = null; - for(CTSchema schema: mapInfo.getSchemaList()){ + for(CTSchema schema: mapInfo.getSchemaArray()){ if(schema.getID().equals(schemaId)){ xmlSchema = schema; break; diff --git a/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java b/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java index 63c514b130..cb1542e87b 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java @@ -94,10 +94,11 @@ public class SingleXmlCells extends POIXMLDocumentPart { * * @return all the SimpleXmlCell contained in this SingleXmlCells element */ + @SuppressWarnings("deprecation") public List getAllSimpleXmlCell(){ List list = new Vector(); - for(CTSingleXmlCell singleXmlCell: singleXMLCells.getSingleXmlCellList()){ + for(CTSingleXmlCell singleXmlCell: singleXMLCells.getSingleXmlCellArray()){ list.add(new XSSFSingleXmlCell(singleXmlCell,this)); } return list; diff --git a/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java b/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java index 3bd00f4a2f..0e8f906339 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/ThemesTable.java @@ -23,20 +23,22 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.xssf.usermodel.XSSFColor; import org.apache.xmlbeans.XmlException; -import org.apache.xmlbeans.XmlObject; +import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; import org.openxmlformats.schemas.drawingml.x2006.main.CTColorScheme; import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument; -import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; /** * Class that represents theme of XLSX document. The theme includes specific * colors and fonts. - * - * @author Petr Udalau(Petr.Udalau at exigenservices.com) - theme colors */ public class ThemesTable extends POIXMLDocumentPart { private ThemeDocument theme; + /** + * Construct a ThemesTable. + * @param part A PackagePart. + * @param rel A PackageRelationship. + */ public ThemesTable(PackagePart part, PackageRelationship rel) throws IOException { super(part, rel); @@ -47,38 +49,56 @@ public class ThemesTable extends POIXMLDocumentPart { } } + /** + * Construct a ThemesTable from an existing ThemeDocument. + * @param theme A ThemeDocument. + */ public ThemesTable(ThemeDocument theme) { this.theme = theme; } + /** + * Convert a theme "index" into a color. + * @param idx A theme "index" + * @return The mapped XSSFColor, or null if not mapped. + */ public XSSFColor getThemeColor(int idx) { + // Theme color references are NOT positional indices into the color scheme, + // i.e. these keys are NOT the same as the order in which theme colors appear + // in theme1.xml. They are keys to a mapped color. CTColorScheme colorScheme = theme.getTheme().getThemeElements().getClrScheme(); - CTColor ctColor = null; - int cnt = 0; - for (XmlObject obj : colorScheme.selectPath("./*")) { - if (obj instanceof org.openxmlformats.schemas.drawingml.x2006.main.CTColor) { - if (cnt == idx) { - ctColor = (org.openxmlformats.schemas.drawingml.x2006.main.CTColor) obj; - - byte[] rgb = null; - if (ctColor.getSrgbClr() != null) { - // Colour is a regular one - rgb = ctColor.getSrgbClr().getVal(); - } else if (ctColor.getSysClr() != null) { - // Colour is a tint of white or black - rgb = ctColor.getSysClr().getLastClr(); - } + CTColor ctColor; + switch (idx) { + case 0: ctColor = colorScheme.getLt1(); break; + case 1: ctColor = colorScheme.getDk1(); break; + case 2: ctColor = colorScheme.getLt2(); break; + case 3: ctColor = colorScheme.getDk2(); break; + case 4: ctColor = colorScheme.getAccent1(); break; + case 5: ctColor = colorScheme.getAccent2(); break; + case 6: ctColor = colorScheme.getAccent3(); break; + case 7: ctColor = colorScheme.getAccent4(); break; + case 8: ctColor = colorScheme.getAccent5(); break; + case 9: ctColor = colorScheme.getAccent6(); break; + case 10: ctColor = colorScheme.getHlink(); break; + case 11: ctColor = colorScheme.getFolHlink(); break; + default: return null; + } - return new XSSFColor(rgb); - } - cnt++; - } + byte[] rgb = null; + if (ctColor.isSetSrgbClr()) { + // Color is a regular one + rgb = ctColor.getSrgbClr().getVal(); + } else if (ctColor.isSetSysClr()) { + // Color is a tint of white or black + rgb = ctColor.getSysClr().getLastClr(); + } else { + return null; } - return null; + return new XSSFColor(rgb); } /** - * If the colour is based on a theme, then inherit + * If the colour is based on a theme, then inherit * information (currently just colours) from it as * required. */ @@ -91,13 +111,13 @@ public class ThemesTable extends POIXMLDocumentPart { // No theme set, nothing to do return; } - + // Get the theme colour XSSFColor themeColor = getThemeColor(color.getTheme()); // Set the raw colour, not the adjusted one // Do a raw set, no adjusting at the XSSFColor layer either color.getCTColor().setRgb(themeColor.getCTColor().getRgb()); - + // All done } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java index bc5c6707dd..41038114f6 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java @@ -19,40 +19,40 @@ package org.apache.poi.xssf.usermodel; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; import java.util.List; -import java.util.ArrayList; +import java.util.Map; import javax.xml.namespace.QName; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; -import org.apache.poi.util.Internal; import org.apache.poi.ss.usermodel.Chart; +import org.apache.poi.ss.usermodel.charts.AxisPosition; import org.apache.poi.ss.usermodel.charts.ChartAxis; import org.apache.poi.ss.usermodel.charts.ChartAxisFactory; +import org.apache.poi.ss.usermodel.charts.ChartData; +import org.apache.poi.util.Internal; import org.apache.poi.xssf.usermodel.charts.XSSFCategoryAxis; -import org.apache.poi.xssf.usermodel.charts.XSSFChartDataFactory; import org.apache.poi.xssf.usermodel.charts.XSSFChartAxis; -import org.apache.poi.xssf.usermodel.charts.XSSFValueAxis; -import org.apache.poi.xssf.usermodel.charts.XSSFManualLayout; +import org.apache.poi.xssf.usermodel.charts.XSSFChartDataFactory; import org.apache.poi.xssf.usermodel.charts.XSSFChartLegend; -import org.apache.poi.ss.usermodel.charts.ChartData; -import org.apache.poi.ss.usermodel.charts.AxisPosition; +import org.apache.poi.xssf.usermodel.charts.XSSFManualLayout; +import org.apache.poi.xssf.usermodel.charts.XSSFValueAxis; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx; import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart; import org.openxmlformats.schemas.drawingml.x2006.chart.CTChartSpace; -import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle; -import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTPageMargins; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea; -import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPrintSettings; -import org.openxmlformats.schemas.drawingml.x2006.chart.CTPageMargins; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx; +import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; import org.w3c.dom.NodeList; import org.w3c.dom.Text; @@ -306,14 +306,16 @@ public final class XSSFChart extends POIXMLDocumentPart implements Chart, ChartA parseValueAxis(); } + @SuppressWarnings("deprecation") private void parseCategoryAxis() { - for (CTCatAx catAx : chart.getPlotArea().getCatAxList()) { + for (CTCatAx catAx : chart.getPlotArea().getCatAxArray()) { axis.add(new XSSFCategoryAxis(this, catAx)); } } + @SuppressWarnings("deprecation") private void parseValueAxis() { - for (CTValAx valAx : chart.getPlotArea().getValAxList()) { + for (CTValAx valAx : chart.getPlotArea().getValAxArray()) { axis.add(new XSSFValueAxis(this, valAx)); } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java index b15eaa55ba..3082e53878 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java @@ -25,16 +25,16 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; * Represents a color in SpreadsheetML */ public class XSSFColor implements Color { - - private CTColor ctColor; + + private CTColor ctColor; /** * Create an instance of XSSFColor from the supplied XML bean */ public XSSFColor(CTColor color) { - this.ctColor = color; - } - + this.ctColor = color; + } + /** * Create an new instance of XSSFColor */ @@ -56,50 +56,29 @@ public class XSSFColor implements Color { * A boolean value indicating the ctColor is automatic and system ctColor dependent. */ public boolean isAuto() { - return ctColor.getAuto(); - } - + return ctColor.getAuto(); + } + /** * A boolean value indicating the ctColor is automatic and system ctColor dependent. */ - public void setAuto(boolean auto) { - ctColor.setAuto(auto); - } + public void setAuto(boolean auto) { + ctColor.setAuto(auto); + } /** * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. */ public short getIndexed() { - return (short)ctColor.getIndexed(); - } - + return (short)ctColor.getIndexed(); + } + /** * Indexed ctColor value. Only used for backwards compatibility. References a ctColor in indexedColors. */ - public void setIndexed(int indexed) { - ctColor.setIndexed(indexed); - } - - /** - * For RGB colours, but not ARGB (we think...) - * Excel gets black and white the wrong way around, so switch them - */ - private byte[] correctRGB(byte[] rgb) { - if(rgb.length == 4) { - // Excel doesn't appear to get these wrong - // Nothing to change - return rgb; - } else { - // Excel gets black and white the wrong way around, so switch them - if (rgb[0] == 0 && rgb[1] == 0 && rgb[2] == 0) { - rgb = new byte[] {-1, -1, -1}; - } - else if (rgb[0] == -1 && rgb[1] == -1 && rgb[2] == -1) { - rgb = new byte[] {0, 0, 0}; - } - return rgb; - } - } + public void setIndexed(int indexed) { + ctColor.setIndexed(indexed); + } /** * Standard Red Green Blue ctColor value (RGB). @@ -108,7 +87,7 @@ public class XSSFColor implements Color { public byte[] getRgb() { byte[] rgb = getRGBOrARGB(); if(rgb == null) return null; - + if(rgb.length == 4) { // Need to trim off the alpha byte[] tmp = new byte[3]; @@ -125,7 +104,7 @@ public class XSSFColor implements Color { public byte[] getARgb() { byte[] rgb = getRGBOrARGB(); if(rgb == null) return null; - + if(rgb.length == 3) { // Pad with the default Alpha byte[] tmp = new byte[4]; @@ -136,7 +115,7 @@ public class XSSFColor implements Color { return rgb; } } - + private byte[] getRGBOrARGB() { byte[] rgb = null; @@ -150,7 +129,7 @@ public class XSSFColor implements Color { return rgb; } } - + if (!ctColor.isSetRgb()) { // No colour is available, sorry return null; @@ -158,9 +137,7 @@ public class XSSFColor implements Color { // Grab the colour rgb = ctColor.getRgb(); - - // Correct it as needed, and return - return correctRGB(rgb); + return rgb; } /** @@ -181,64 +158,63 @@ public class XSSFColor implements Color { } return rgb; } - + /** * Return the ARGB value in hex format, eg FF00FF00. - * Works for both regular and indexed colours. + * Works for both regular and indexed colours. */ - public String getARGBHex() { - StringBuffer sb = new StringBuffer(); - byte[] rgb = getARgb(); - if(rgb == null) { - return null; - } - for(byte c : rgb) { - int i = (int)c; - if(i < 0) { - i += 256; - } - String cs = Integer.toHexString(i); - if(cs.length() == 1) { - sb.append('0'); - } - sb.append(cs); - } - return sb.toString().toUpperCase(); - } - - private static byte applyTint(int lum, double tint){ - if(tint > 0){ - return (byte)(lum * (1.0-tint) + (255 - 255 * (1.0-tint))); - } else if (tint < 0){ - return (byte)(lum*(1+tint)); - } else { - return (byte)lum; - } - } + public String getARGBHex() { + StringBuffer sb = new StringBuffer(); + byte[] rgb = getARgb(); + if(rgb == null) { + return null; + } + for(byte c : rgb) { + int i = (int)c; + if(i < 0) { + i += 256; + } + String cs = Integer.toHexString(i); + if(cs.length() == 1) { + sb.append('0'); + } + sb.append(cs); + } + return sb.toString().toUpperCase(); + } + + private static byte applyTint(int lum, double tint){ + if(tint > 0){ + return (byte)(lum * (1.0-tint) + (255 - 255 * (1.0-tint))); + } else if (tint < 0){ + return (byte)(lum*(1+tint)); + } else { + return (byte)lum; + } + } /** * Standard Alpha Red Green Blue ctColor value (ARGB). */ - public void setRgb(byte[] rgb) { - // Correct it and save - ctColor.setRgb(correctRGB(rgb)); - } - + public void setRgb(byte[] rgb) { + ctColor.setRgb(rgb); + } + /** * Index into the collection, referencing a particular or * value expressed in the Theme part. */ public int getTheme() { return (int)ctColor.getTheme(); - } - + } + /** * Index into the collection, referencing a particular or * value expressed in the Theme part. */ - public void setTheme(int theme) { - ctColor.setTheme(theme); - } + public void setTheme(int theme) { + ctColor.setTheme(theme); + } /** * Specifies the tint value applied to the ctColor. @@ -282,9 +258,9 @@ public class XSSFColor implements Color { * @return the tint value */ public double getTint() { - return ctColor.getTint(); - } - + return ctColor.getTint(); + } + /** * Specifies the tint value applied to the ctColor. * @@ -326,9 +302,9 @@ public class XSSFColor implements Color { * * @param tint the tint value */ - public void setTint(double tint) { - ctColor.setTint(tint); - } + public void setTint(double tint) { + ctColor.setTint(tint); + } /** * Returns the underlying XML bean @@ -339,7 +315,7 @@ public class XSSFColor implements Color { public CTColor getCTColor(){ return ctColor; } - + public int hashCode(){ return ctColor.toString().hashCode(); } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotCacheDefinition.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotCacheDefinition.java index e80dc7ee6d..d63a18588d 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotCacheDefinition.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotCacheDefinition.java @@ -127,7 +127,7 @@ public class XSSFPivotCacheDefinition extends POIXMLDocumentPart{ for(int i=columnStart; i<=columnEnd; i++) { CTCacheField cf = cFields.addNewCacheField(); if(i==columnEnd){ - cFields.setCount(cFields.getCacheFieldList().size()); + cFields.setCount(cFields.sizeOfCacheFieldArray()); } //General number format cf.setNumFmtId(0); diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java index d31ae3f68a..278e66e3d3 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java @@ -240,7 +240,6 @@ public class XSSFPivotTable extends POIXMLDocumentPart { } CTPivotFields pivotFields = pivotTableDefinition.getPivotFields(); - List pivotFieldList = pivotTableDefinition.getPivotFields().getPivotFieldList(); CTPivotField pivotField = CTPivotField.Factory.newInstance(); CTItems items = pivotField.addNewItems(); @@ -249,10 +248,8 @@ public class XSSFPivotTable extends POIXMLDocumentPart { for(int i = 0; i <= lastRowIndex; i++) { items.addNewItem().setT(STItemType.DEFAULT); } - items.setCount(items.getItemList().size()); - pivotFieldList.set(columnIndex, pivotField); - - pivotFields.setPivotFieldArray(pivotFieldList.toArray(new CTPivotField[pivotFieldList.size()])); + items.setCount(items.sizeOfItemArray()); + pivotFields.setPivotFieldArray(columnIndex, pivotField); CTRowFields rowFields; if(pivotTableDefinition.getRowFields() != null) { @@ -262,7 +259,7 @@ public class XSSFPivotTable extends POIXMLDocumentPart { } rowFields.addNewField().setX(columnIndex); - rowFields.setCount(rowFields.getFieldList().size()); + rowFields.setCount(rowFields.sizeOfFieldArray()); } @Beta @@ -307,7 +304,7 @@ public class XSSFPivotTable extends POIXMLDocumentPart { colFields = pivotTableDefinition.addNewColFields(); } colFields.addNewField().setX(-2); - colFields.setCount(colFields.getFieldList().size()); + colFields.setCount(colFields.sizeOfFieldArray()); } } @@ -338,7 +335,7 @@ public class XSSFPivotTable extends POIXMLDocumentPart { cell.setCellType(Cell.CELL_TYPE_STRING); dataField.setName(function.getName()); dataField.setFld(columnIndex); - dataFields.setCount(dataFields.getDataFieldList().size()); + dataFields.setCount(dataFields.sizeOfDataFieldArray()); } /** @@ -354,13 +351,11 @@ public class XSSFPivotTable extends POIXMLDocumentPart { throw new IndexOutOfBoundsException(); } CTPivotFields pivotFields = pivotTableDefinition.getPivotFields(); - List pivotFieldList = pivotFields.getPivotFieldList(); CTPivotField pivotField = CTPivotField.Factory.newInstance(); pivotField.setDataField(isDataField); pivotField.setShowAll(false); - pivotFieldList.set(columnIndex, pivotField); - pivotFields.setPivotFieldArray(pivotFieldList.toArray(new CTPivotField[pivotFieldList.size()])); + pivotFields.setPivotFieldArray(columnIndex, pivotField); } /** @@ -378,7 +373,6 @@ public class XSSFPivotTable extends POIXMLDocumentPart { } CTPivotFields pivotFields = pivotTableDefinition.getPivotFields(); - List pivotFieldList = pivotTableDefinition.getPivotFields().getPivotFieldList(); CTPivotField pivotField = CTPivotField.Factory.newInstance(); CTItems items = pivotField.addNewItems(); @@ -387,8 +381,8 @@ public class XSSFPivotTable extends POIXMLDocumentPart { for(int i = 0; i <= lastRowIndex; i++) { items.addNewItem().setT(STItemType.DEFAULT); } - items.setCount(items.getItemList().size()); - pivotFieldList.set(columnIndex, pivotField); + items.setCount(items.sizeOfItemArray()); + pivotFields.setPivotFieldArray(columnIndex, pivotField); CTPageFields pageFields; if (pivotTableDefinition.getPageFields()!= null) { @@ -402,7 +396,7 @@ public class XSSFPivotTable extends POIXMLDocumentPart { pageField.setHier(-1); pageField.setFld(columnIndex); - pageFields.setCount(pageFields.getPageFieldList().size()); + pageFields.setCount(pageFields.sizeOfPageFieldArray()); pivotTableDefinition.getLocation().setColPageCount(pageFields.getCount()); } @@ -459,6 +453,6 @@ public class XSSFPivotTable extends POIXMLDocumentPart { pivotField.setDataField(false); pivotField.setShowAll(false); } - pivotFields.setCount(pivotFields.getPivotFieldList().size()); + pivotFields.setCount(pivotFields.sizeOfPivotFieldArray()); } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java index f21b1aa6d2..44070b1b55 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java @@ -439,16 +439,18 @@ public class XSSFRow implements Row, Comparable { * * @see org.apache.poi.xssf.usermodel.XSSFSheet#write(java.io.OutputStream) () */ + @SuppressWarnings("deprecation") protected void onDocumentWrite(){ // check if cells in the CTRow are ordered boolean isOrdered = true; - if(_row.sizeOfCArray() != _cells.size()) { + CTCell[] cArray = _row.getCArray(); + if (cArray.length != _cells.size()) { isOrdered = false; } else { int i = 0; for (XSSFCell cell : _cells.values()) { CTCell c1 = cell.getCTCell(); - CTCell c2 = _row.getCArray(i++); + CTCell c2 = cArray[i++]; String r1 = c1.getR(); String r2 = c2.getR(); @@ -460,17 +462,17 @@ public class XSSFRow implements Row, Comparable { } if(!isOrdered){ - CTCell[] cArray = new CTCell[_cells.size()]; + cArray = new CTCell[_cells.size()]; int i = 0; - for (Map.Entry entry : _cells.entrySet()) { - cArray[i] = (CTCell) entry.getValue().getCTCell().copy(); + for (XSSFCell xssfCell : _cells.values()) { + cArray[i] = (CTCell) xssfCell.getCTCell().copy(); // we have to copy and re-create the XSSFCell here because the // elements as otherwise setCArray below invalidates all the columns! // see Bug 56170, XMLBeans seems to always release previous objects // in the CArray, so we need to provide completely new ones here! //_cells.put(entry.getKey(), new XSSFCell(this, cArray[i])); - entry.getValue().setCTCell(cArray[i]); + xssfCell.setCTCell(cArray[i]); i++; } 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 fb5c6ef601..e625d83963 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -17,6 +17,9 @@ package org.apache.poi.xssf.usermodel; +import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword; +import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -26,13 +29,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import javax.xml.namespace.QName; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLException; -import org.apache.poi.hssf.record.PasswordRecord; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException; @@ -40,6 +43,7 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; import org.apache.poi.openxml4j.opc.TargetMode; +import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.SheetNameFormatter; @@ -60,7 +64,6 @@ import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.SSCellRange; import org.apache.poi.ss.util.SheetUtil; import org.apache.poi.util.Beta; -import org.apache.poi.util.HexDump; import org.apache.poi.util.Internal; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -110,7 +113,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex; import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument; /** @@ -649,6 +651,28 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return null; } + @SuppressWarnings("deprecation") + private int[] getBreaks(CTPageBreak ctPageBreak) { + CTBreak[] brkArray = ctPageBreak.getBrkArray(); + int[] breaks = new int[brkArray.length]; + for (int i = 0 ; i < brkArray.length ; i++) { + breaks[i] = (int) brkArray[i].getId() - 1; + } + return breaks; + } + + @SuppressWarnings("deprecation") + private void removeBreak(int index, CTPageBreak ctPageBreak) { + int index1 = index + 1; + CTBreak[] brkArray = ctPageBreak.getBrkArray(); + for (int i = 0 ; i < brkArray.length ; i++) { + if (brkArray[i].getId() == index1) { + ctPageBreak.removeBrk(i); + // TODO: check if we can break here, i.e. if a page can have more than 1 break on the same id + } + } + } + /** * Vertical page break information used for print layout view, page layout view, drawing print breaks * in normal view, and for printing the worksheet. @@ -656,20 +680,8 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @return column indexes of all the vertical page breaks, never null */ @Override - @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public int[] getColumnBreaks() { - if (!worksheet.isSetColBreaks() || worksheet.getColBreaks().sizeOfBrkArray() == 0) { - return new int[0]; - } - - CTBreak[] brkArray = worksheet.getColBreaks().getBrkArray(); - - int[] breaks = new int[brkArray.length]; - for (int i = 0 ; i < brkArray.length ; i++) { - CTBreak brk = brkArray[i]; - breaks[i] = (int)brk.getId() - 1; - } - return breaks; + return worksheet.isSetColBreaks() ? getBreaks(worksheet.getColBreaks()) : new int[0]; } /** @@ -752,8 +764,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @param value true for right to left, false otherwise. */ @Override - public void setRightToLeft(boolean value) - { + public void setRightToLeft(boolean value) { CTSheetView view = getDefaultSheetView(); view.setRightToLeft(value); } @@ -764,10 +775,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @return whether the text is displayed in right-to-left mode in the window */ @Override - public boolean isRightToLeft() - { + public boolean isRightToLeft() { CTSheetView view = getDefaultSheetView(); - return view == null ? false : view.getRightToLeft(); + return view != null && view.getRightToLeft(); } /** @@ -804,7 +814,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { @Override public boolean isDisplayZeros(){ CTSheetView view = getDefaultSheetView(); - return view == null ? true : view.getShowZeros(); + return view == null || view.getShowZeros(); } /** @@ -826,7 +836,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public int getFirstRowNum() { - return _rows.size() == 0 ? 0 : _rows.firstKey(); + return _rows.isEmpty() ? 0 : _rows.firstKey(); } /** @@ -944,7 +954,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { @Override public int getLastRowNum() { - return _rows.size() == 0 ? 0 : _rows.lastKey(); + return _rows.isEmpty() ? 0 : _rows.lastKey(); } @Override @@ -1079,9 +1089,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } /** - * Returns the number of phsyically defined rows (NOT the number of rows in the sheet) + * Returns the number of physically defined rows (NOT the number of rows in the sheet) * - * @return the number of phsyically defined rows + * @return the number of physically defined rows */ @Override public int getPhysicalNumberOfRows() { @@ -1105,7 +1115,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public boolean getProtect() { - return worksheet.isSetSheetProtection() && sheetProtectionEnabled(); + return isSheetLocked(); } /** @@ -1117,10 +1127,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public void protectSheet(String password) { - - if(password != null) { - CTSheetProtection sheetProtection = worksheet.addNewSheetProtection(); - sheetProtection.xsetPassword(stringToExcelPassword(password)); + if (password != null) { + CTSheetProtection sheetProtection = safeGetProtectionField(); + setSheetPassword(password, null); // defaults to xor password sheetProtection.setSheet(true); sheetProtection.setScenarios(true); sheetProtection.setObjects(true); @@ -1130,18 +1139,27 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } /** - * Converts a String to a {@link STUnsignedShortHex} value that contains the {@link PasswordRecord#hashPassword(String)} - * value in hexadecimal format - * - * @param password the password string you wish convert to an {@link STUnsignedShortHex} - * @return {@link STUnsignedShortHex} that contains Excel hashed password in Hex format + * Sets the sheet password. + * + * @param password if null, the password will be removed + * @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier) + * otherwise the given algorithm is used for calculating the hash password (Excel 2013) */ - private STUnsignedShortHex stringToExcelPassword(String password) { - STUnsignedShortHex hexPassword = STUnsignedShortHex.Factory.newInstance(); - hexPassword.setStringValue(String.valueOf(HexDump.shortToHex(PasswordRecord.hashPassword(password))).substring(2)); - return hexPassword; + public void setSheetPassword(String password, HashAlgorithm hashAlgo) { + if (password == null && !isSheetProtectionEnabled()) return; + setPassword(safeGetProtectionField(), password, hashAlgo, null); } + /** + * Validate the password against the stored hash, the hashing method will be determined + * by the existing password attributes + * @return true, if the hashes match (... though original password may differ ...) + */ + public boolean validateSheetPassword(String password) { + if (!isSheetProtectionEnabled()) return (password == null); + return validatePassword(safeGetProtectionField(), password, null); + } + /** * Returns the logical row ( 0-based). If you ask for a row that is not * defined you get a null. This is to say row 4 represents the fifth row on a sheet. @@ -1161,19 +1179,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @return row indexes of all the horizontal page breaks, never null */ @Override - @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public int[] getRowBreaks() { - if (!worksheet.isSetRowBreaks() || worksheet.getRowBreaks().sizeOfBrkArray() == 0) { - return new int[0]; - } + return worksheet.isSetRowBreaks() ? getBreaks(worksheet.getRowBreaks()) : new int[0]; - CTBreak[] brkArray = worksheet.getRowBreaks().getBrkArray(); - int[] breaks = new int[brkArray.length]; - for (int i = 0 ; i < brkArray.length ; i++) { - CTBreak brk = brkArray[i]; - breaks[i] = (int)brk.getId() - 1; - } - return breaks; } /** @@ -1342,8 +1350,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { /** * Do not leave the width attribute undefined (see #52186). */ + @SuppressWarnings("deprecation") private void setColWidthAttribute(CTCols ctCols) { - for (CTCol col : ctCols.getColList()) { + for (CTCol col : ctCols.getColArray()) { if (!col.isSetWidth()) { col.setWidth(getDefaultColumnWidth()); col.setCustomWidth(false); @@ -1372,21 +1381,22 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } private short getMaxOutlineLevelRows(){ - short outlineLevel=0; - for(XSSFRow xrow : _rows.values()){ - outlineLevel=xrow.getCTRow().getOutlineLevel()>outlineLevel? xrow.getCTRow().getOutlineLevel(): outlineLevel; + int outlineLevel = 0; + for (XSSFRow xrow : _rows.values()) { + outlineLevel = Math.max(outlineLevel, xrow.getCTRow().getOutlineLevel()); } - return outlineLevel; + return (short) outlineLevel; } + @SuppressWarnings("deprecation") private short getMaxOutlineLevelCols() { CTCols ctCols = worksheet.getColsArray(0); - short outlineLevel = 0; - for (CTCol col : ctCols.getColList()) { - outlineLevel = col.getOutlineLevel() > outlineLevel ? col.getOutlineLevel() : outlineLevel; + int outlineLevel = 0; + for (CTCol col : ctCols.getColArray()) { + outlineLevel = Math.max(outlineLevel, col.getOutlineLevel()); } - return outlineLevel; + return (short) outlineLevel; } /** @@ -1394,8 +1404,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public boolean isColumnBroken(int column) { - int[] colBreaks = getColumnBreaks(); - for (int colBreak : colBreaks) { + for (int colBreak : getColumnBreaks()) { if (colBreak == column) { return true; } @@ -1514,8 +1523,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public boolean isRowBroken(int row) { - int[] rowBreaks = getRowBreaks(); - for (int rowBreak : rowBreaks) { + for (int rowBreak : getRowBreaks()) { if (rowBreak == row) { return true; } @@ -1523,6 +1531,17 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return false; } + private void setBreak(int id, CTPageBreak ctPgBreak, int lastIndex) { + CTBreak brk = ctPgBreak.addNewBrk(); + brk.setId(id + 1); // this is id of the element which is 1-based: + brk.setMan(true); + brk.setMax(lastIndex); //end column of the break + + int nPageBreaks = ctPgBreak.sizeOfBrkArray(); + ctPgBreak.setCount(nPageBreaks); + ctPgBreak.setManualBreakCount(nPageBreaks); + } + /** * Sets a page break at the indicated row * Breaks occur above the specified row and left of the specified column inclusive. @@ -1536,15 +1555,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public void setRowBreak(int row) { - CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks(); - if (! isRowBroken(row)) { - CTBreak brk = pgBreak.addNewBrk(); - brk.setId(row + 1); // this is id of the row element which is 1-based: - brk.setMan(true); - brk.setMax(SpreadsheetVersion.EXCEL2007.getLastColumnIndex()); //end column of the break - - pgBreak.setCount(pgBreak.sizeOfBrkArray()); - pgBreak.setManualBreakCount(pgBreak.sizeOfBrkArray()); + if (!isRowBroken(row)) { + CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks(); + setBreak(row, pgBreak, SpreadsheetVersion.EXCEL2007.getLastColumnIndex()); } } @@ -1552,20 +1565,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * Removes a page break at the indicated column */ @Override - @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public void removeColumnBreak(int column) { - if (!worksheet.isSetColBreaks()) { - // no breaks - return; - } - - CTPageBreak pgBreak = worksheet.getColBreaks(); - CTBreak[] brkArray = pgBreak.getBrkArray(); - for (int i = 0 ; i < brkArray.length ; i++) { - if (brkArray[i].getId() == (column + 1)) { - pgBreak.removeBrk(i); - } - } + if (worksheet.isSetColBreaks()) { + removeBreak(column, worksheet.getColBreaks()); + } // else no breaks } /** @@ -1574,22 +1577,46 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @param index of the region to unmerge */ @Override + @SuppressWarnings("deprecation") public void removeMergedRegion(int index) { + if (!worksheet.isSetMergeCells()) return; + CTMergeCells ctMergeCells = worksheet.getMergeCells(); + int size = ctMergeCells.sizeOfMergeCellArray(); + assert(0 <= index && index < size); + if (size > 1) { + ctMergeCells.removeMergeCell(index); + } else { + worksheet.unsetMergeCells(); + } + } - CTMergeCell[] mergeCellsArray = new CTMergeCell[ctMergeCells.sizeOfMergeCellArray() - 1]; - for (int i = 0 ; i < ctMergeCells.sizeOfMergeCellArray() ; i++) { - if (i < index) { - mergeCellsArray[i] = ctMergeCells.getMergeCellArray(i); - } - else if (i > index) { - mergeCellsArray[i - 1] = ctMergeCells.getMergeCellArray(i); - } + /** + * Removes a number of merged regions of cells (hence letting them free) + * + * This method can be used to bulk-remove merged regions in a way + * much faster than calling removeMergedRegion() for every single + * merged region. + * + * @param indices A set of the regions to unmerge + */ + @SuppressWarnings("deprecation") + public void removeMergedRegions(Set indices) { + if (!worksheet.isSetMergeCells()) return; + + CTMergeCells ctMergeCells = worksheet.getMergeCells(); + List newMergeCells = new ArrayList(ctMergeCells.sizeOfMergeCellArray()); + + int idx = 0; + for (CTMergeCell mc : ctMergeCells.getMergeCellArray()) { + if (!indices.contains(idx++)) newMergeCells.add(mc); } - if(mergeCellsArray.length > 0){ - ctMergeCells.setMergeCellArray(mergeCellsArray); - } else{ + + if (newMergeCells.isEmpty()) { worksheet.unsetMergeCells(); + } else{ + CTMergeCell[] newMergeCellsArray = new CTMergeCell[newMergeCells.size()]; + ctMergeCells.setMergeCellArray(newMergeCells.toArray(newMergeCellsArray)); } } @@ -1618,18 +1645,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * Removes the page break at the indicated row */ @Override - @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public void removeRowBreak(int row) { - if(!worksheet.isSetRowBreaks()) { - return; - } - CTPageBreak pgBreak = worksheet.getRowBreaks(); - CTBreak[] brkArray = pgBreak.getBrkArray(); - for (int i = 0 ; i < brkArray.length ; i++) { - if (brkArray[i].getId() == (row + 1)) { - pgBreak.removeBrk(i); - } - } + if (worksheet.isSetRowBreaks()) { + removeBreak(row, worksheet.getRowBreaks()); + } // else no breaks } /** @@ -1743,15 +1762,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ @Override public void setColumnBreak(int column) { - if (! isColumnBroken(column)) { + if (!isColumnBroken(column)) { CTPageBreak pgBreak = worksheet.isSetColBreaks() ? worksheet.getColBreaks() : worksheet.addNewColBreaks(); - CTBreak brk = pgBreak.addNewBrk(); - brk.setId(column + 1); // this is id of the row element which is 1-based: - brk.setMan(true); - brk.setMax(SpreadsheetVersion.EXCEL2007.getLastRowIndex()); //end row of the break - - pgBreak.setCount(pgBreak.sizeOfBrkArray()); - pgBreak.setManualBreakCount(pgBreak.sizeOfBrkArray()); + setBreak(column, pgBreak, SpreadsheetVersion.EXCEL2007.getLastRowIndex()); } } @@ -1781,23 +1794,23 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { .getOutlineLevel(), true); // write collapse field - setColumn(lastColMax + 1, null, 0, null, null, Boolean.TRUE); + setColumn(lastColMax + 1, 0, null, null, Boolean.TRUE); } - private void setColumn(int targetColumnIx, Short xfIndex, Integer style, - Integer level, Boolean hidden, Boolean collapsed) { + @SuppressWarnings("deprecation") + private void setColumn(int targetColumnIx, Integer style, + Integer level, Boolean hidden, Boolean collapsed) { CTCols cols = worksheet.getColsArray(0); CTCol ci = null; - int k = 0; - for (k = 0; k < cols.sizeOfColArray(); k++) { - CTCol tci = cols.getColArray(k); - if (tci.getMin() >= targetColumnIx - && tci.getMax() <= targetColumnIx) { + for (CTCol tci : cols.getColArray()) { + long tciMin = tci.getMin(); + long tciMax = tci.getMax(); + if (tciMin >= targetColumnIx && tciMax <= targetColumnIx) { ci = tci; break; } - if (tci.getMin() > targetColumnIx) { + if (tciMin > targetColumnIx) { // call column infos after k are for later columns break; // exit now so k will be the correct insert pos } @@ -1814,36 +1827,32 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return; } - boolean styleChanged = style != null - && ci.getStyle() != style; - boolean levelChanged = level != null - && ci.getOutlineLevel() != level; - boolean hiddenChanged = hidden != null - && ci.getHidden() != hidden; - boolean collapsedChanged = collapsed != null - && ci.getCollapsed() != collapsed; - boolean columnChanged = levelChanged || hiddenChanged - || collapsedChanged || styleChanged; + boolean styleChanged = style != null && ci.getStyle() != style; + boolean levelChanged = level != null && ci.getOutlineLevel() != level; + boolean hiddenChanged = hidden != null && ci.getHidden() != hidden; + boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed; + boolean columnChanged = levelChanged || hiddenChanged || collapsedChanged || styleChanged; if (!columnChanged) { // do nothing...nothing changed. return; } - if (ci.getMin() == targetColumnIx && ci.getMax() == targetColumnIx) { + long ciMin = ci.getMin(); + long ciMax = ci.getMax(); + if (ciMin == targetColumnIx && ciMax == targetColumnIx) { // ColumnInfo ci for a single column, the target column unsetCollapsed(collapsed, ci); return; } - if (ci.getMin() == targetColumnIx || ci.getMax() == targetColumnIx) { + if (ciMin == targetColumnIx || ciMax == targetColumnIx) { // The target column is at either end of the multi-column ColumnInfo // ci // we'll just divide the info and create a new one - if (ci.getMin() == targetColumnIx) { + if (ciMin == targetColumnIx) { ci.setMin(targetColumnIx + 1); } else { ci.setMax(targetColumnIx - 1); - k++; // adjust insert pos to insert after } CTCol nci = columnHelper.cloneCol(cols, ci); nci.setMin(targetColumnIx); @@ -1852,12 +1861,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } else { // split to 3 records - CTCol ciStart = ci; CTCol ciMid = columnHelper.cloneCol(cols, ci); CTCol ciEnd = columnHelper.cloneCol(cols, ci); - int lastcolumn = (int) ci.getMax(); + int lastcolumn = (int) ciMax; - ciStart.setMax(targetColumnIx - 1); + ci.setMax(targetColumnIx - 1); ciMid.setMin(targetColumnIx); ciMid.setMax(targetColumnIx); @@ -1886,14 +1894,16 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * the col info index of the start of the outline group * @return the column index of the last column in the outline group */ + @SuppressWarnings("deprecation") private int setGroupHidden(int pIdx, int level, boolean hidden) { CTCols cols = worksheet.getColsArray(0); int idx = pIdx; - CTCol columnInfo = cols.getColArray(idx); - while (idx < cols.sizeOfColArray()) { + CTCol[] colArray = cols.getColArray(); + CTCol columnInfo = colArray[idx]; + while (idx < colArray.length) { columnInfo.setHidden(hidden); - if (idx + 1 < cols.sizeOfColArray()) { - CTCol nextColumnInfo = cols.getColArray(idx + 1); + if (idx + 1 < colArray.length) { + CTCol nextColumnInfo = colArray[idx + 1]; if (!isAdjacentBefore(columnInfo, nextColumnInfo)) { break; @@ -1910,17 +1920,19 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } private boolean isAdjacentBefore(CTCol col, CTCol other_col) { - return (col.getMax() == (other_col.getMin() - 1)); + return col.getMax() == other_col.getMin() - 1; } + @SuppressWarnings("deprecation") private int findStartOfColumnOutlineGroup(int pIdx) { // Find the start of the group. CTCols cols = worksheet.getColsArray(0); - CTCol columnInfo = cols.getColArray(pIdx); + CTCol[] colArray = cols.getColArray(); + CTCol columnInfo = colArray[pIdx]; int level = columnInfo.getOutlineLevel(); int idx = pIdx; while (idx != 0) { - CTCol prevColumnInfo = cols.getColArray(idx - 1); + CTCol prevColumnInfo = colArray[idx - 1]; if (!isAdjacentBefore(prevColumnInfo, columnInfo)) { break; } @@ -1933,14 +1945,17 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return idx; } + @SuppressWarnings("deprecation") private int findEndOfColumnOutlineGroup(int colInfoIndex) { CTCols cols = worksheet.getColsArray(0); // Find the end of the group. - CTCol columnInfo = cols.getColArray(colInfoIndex); + CTCol[] colArray = cols.getColArray(); + CTCol columnInfo = colArray[colInfoIndex]; int level = columnInfo.getOutlineLevel(); int idx = colInfoIndex; - while (idx < cols.sizeOfColArray() - 1) { - CTCol nextColumnInfo = cols.getColArray(idx + 1); + int lastIdx = colArray.length - 1; + while (idx < lastIdx) { + CTCol nextColumnInfo = colArray[idx + 1]; if (!isAdjacentBefore(columnInfo, nextColumnInfo)) { break; } @@ -1953,6 +1968,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return idx; } + @SuppressWarnings("deprecation") private void expandColumn(int columnIndex) { CTCols cols = worksheet.getColsArray(0); CTCol col = columnHelper.getColumn(columnIndex, false); @@ -1983,12 +1999,13 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { // is the enclosing group // hidden bit only is altered for this outline level. ie. don't // uncollapse contained groups - CTCol columnInfo = cols.getColArray(endIdx); + CTCol[] colArray = cols.getColArray(); + CTCol columnInfo = colArray[endIdx]; if (!isColumnGroupHiddenByParent(idx)) { - int outlineLevel = columnInfo.getOutlineLevel(); + short outlineLevel = columnInfo.getOutlineLevel(); boolean nestedGroup = false; for (int i = startIdx; i <= endIdx; i++) { - CTCol ci = cols.getColArray(i); + CTCol ci = colArray[i]; if (outlineLevel == ci.getOutlineLevel()) { ci.unsetHidden(); if (nestedGroup) { @@ -2002,20 +2019,21 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } // Write collapse flag (stored in a single col info record after this // outline group) - setColumn((int) columnInfo.getMax() + 1, null, null, null, + setColumn((int) columnInfo.getMax() + 1, null, null, Boolean.FALSE, Boolean.FALSE); } + @SuppressWarnings("deprecation") private boolean isColumnGroupHiddenByParent(int idx) { CTCols cols = worksheet.getColsArray(0); // Look out outline details of end int endLevel = 0; boolean endHidden = false; int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx); - if (endOfOutlineGroupIdx < cols.sizeOfColArray()) { - CTCol nextInfo = cols.getColArray(endOfOutlineGroupIdx + 1); - if (isAdjacentBefore(cols.getColArray(endOfOutlineGroupIdx), - nextInfo)) { + CTCol[] colArray = cols.getColArray(); + if (endOfOutlineGroupIdx < colArray.length) { + CTCol nextInfo = colArray[endOfOutlineGroupIdx + 1]; + if (isAdjacentBefore(colArray[endOfOutlineGroupIdx], nextInfo)) { endLevel = nextInfo.getOutlineLevel(); endHidden = nextInfo.getHidden(); } @@ -2025,10 +2043,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { boolean startHidden = false; int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup(idx); if (startOfOutlineGroupIdx > 0) { - CTCol prevInfo = cols.getColArray(startOfOutlineGroupIdx - 1); + CTCol prevInfo = colArray[startOfOutlineGroupIdx - 1]; - if (isAdjacentBefore(prevInfo, cols - .getColArray(startOfOutlineGroupIdx))) { + if (isAdjacentBefore(prevInfo, colArray[startOfOutlineGroupIdx])) { startLevel = prevInfo.getOutlineLevel(); startHidden = prevInfo.getHidden(); } @@ -2040,6 +2057,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return startHidden; } + @SuppressWarnings("deprecation") private int findColInfoIdx(int columnValue, int fromColInfoIdx) { CTCols cols = worksheet.getColsArray(0); @@ -2052,8 +2070,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { "fromIdx parameter out of range: " + fromColInfoIdx); } - for (int k = fromColInfoIdx; k < cols.sizeOfColArray(); k++) { - CTCol ci = cols.getColArray(k); + CTCol[] colArray = cols.getColArray(); + for (int k = fromColInfoIdx; k < colArray.length; k++) { + CTCol ci = colArray[k]; if (containsColumn(ci, columnValue)) { return k; @@ -2078,16 +2097,18 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @param idx * @return a boolean represented if the column is collapsed */ + @SuppressWarnings("deprecation") private boolean isColumnGroupCollapsed(int idx) { CTCols cols = worksheet.getColsArray(0); + CTCol[] colArray = cols.getColArray(); int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx); int nextColInfoIx = endOfOutlineGroupIdx + 1; - if (nextColInfoIx >= cols.sizeOfColArray()) { + if (nextColInfoIx >= colArray.length) { return false; } - CTCol nextColInfo = cols.getColArray(nextColInfoIx); + CTCol nextColInfo = colArray[nextColInfoIx]; - CTCol col = cols.getColArray(endOfOutlineGroupIdx); + CTCol col = colArray[endOfOutlineGroupIdx]; if (!isAdjacentBefore(col, nextColInfo)) { return false; } @@ -2294,7 +2315,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { */ private int findStartOfRowOutlineGroup(int rowIndex) { // Find the start of the group. - int level = getRow(rowIndex).getCTRow().getOutlineLevel(); + short level = getRow(rowIndex).getCTRow().getOutlineLevel(); int currentRow = rowIndex; while (getRow(currentRow) != null) { if (getRow(currentRow).getCTRow().getOutlineLevel() < level) @@ -2305,7 +2326,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } private int writeHidden(XSSFRow xRow, int rowIndex, boolean hidden) { - int level = xRow.getCTRow().getOutlineLevel(); + short level = xRow.getCTRow().getOutlineLevel(); for (Iterator it = rowIterator(); it.hasNext();) { xRow = (XSSFRow) it.next(); @@ -2352,10 +2373,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { // is the enclosing group // hidden bit only is altered for this outline level. ie. don't // un-collapse contained groups + short level = row.getCTRow().getOutlineLevel(); if (!isRowGroupHiddenByParent(rowNumber)) { for (int i = startIdx; i < endIdx; i++) { - if (row.getCTRow().getOutlineLevel() == getRow(i).getCTRow() - .getOutlineLevel()) { + if (level == getRow(i).getCTRow().getOutlineLevel()) { getRow(i).getCTRow().unsetHidden(); } else if (!isRowGroupCollapsed(i)) { getRow(i).getCTRow().unsetHidden(); @@ -2374,7 +2395,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @param row the zero based row index to find from */ public int findEndOfRowOutlineGroup(int row) { - int level = getRow(row).getCTRow().getOutlineLevel(); + short level = getRow(row).getCTRow().getOutlineLevel(); int currentRow; for (currentRow = row; currentRow < getLastRowNum(); currentRow++) { if (getRow(currentRow) == null @@ -2630,11 +2651,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { for (int i = fromRow; i <= toRow; i++) { XSSFRow xrow = getRow(i); if (xrow != null) { - CTRow ctrow = xrow.getCTRow(); - short outlinelevel = ctrow.getOutlineLevel(); - ctrow.setOutlineLevel((short) (outlinelevel - 1)); + CTRow ctRow = xrow.getCTRow(); + int outlineLevel = ctRow.getOutlineLevel(); + ctRow.setOutlineLevel((short) (outlineLevel - 1)); //remove a row only if the row has no cell and if the outline level is 0 - if (ctrow.getOutlineLevel() == 0 && xrow.getFirstCellNum() == -1) { + if (outlineLevel == 1 && xrow.getFirstCellNum() == -1) { removeRow(xrow); } } @@ -2746,13 +2767,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * so we can decide about writing it to disk or not */ public boolean hasComments() { - if(sheetComments == null) { return false; } - return (sheetComments.getNumberOfComments() > 0); + return sheetComments != null && sheetComments.getNumberOfComments() > 0; } protected int getNumberOfComments() { - if(sheetComments == null) { return 0; } - return sheetComments.getNumberOfComments(); + return sheetComments == null ? 0 : sheetComments.getNumberOfComments(); } private CTSelection getSheetTypeSelection() { @@ -2851,7 +2870,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { CTCellFormula sf = (CTCellFormula)f.copy(); CellRangeAddress sfRef = CellRangeAddress.valueOf(sf.getRef()); CellReference cellRef = new CellReference(cell); - // If the shared formula range preceeds the master cell then the preceding part is discarded, e.g. + // If the shared formula range precedes the master cell then the preceding part is discarded, e.g. // if the cell is E60 and the shared formula range is C60:M85 then the effective range is E60:M85 // see more details in https://issues.apache.org/bugzilla/show_bug.cgi?id=51710 if(cellRef.getCol() > sfRef.getFirstColumn() || cellRef.getRow() > sfRef.getFirstRow()){ @@ -2929,304 +2948,392 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * @return true when Autofilters are locked and the sheet is protected. */ public boolean isAutoFilterLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getAutoFilter(); + return isSheetLocked() && safeGetProtectionField().getAutoFilter(); } /** * @return true when Deleting columns is locked and the sheet is protected. */ public boolean isDeleteColumnsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getDeleteColumns(); + return isSheetLocked() && safeGetProtectionField().getDeleteColumns(); } /** * @return true when Deleting rows is locked and the sheet is protected. */ public boolean isDeleteRowsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getDeleteRows(); + return isSheetLocked() && safeGetProtectionField().getDeleteRows(); } /** * @return true when Formatting cells is locked and the sheet is protected. */ public boolean isFormatCellsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getFormatCells(); + return isSheetLocked() && safeGetProtectionField().getFormatCells(); } /** * @return true when Formatting columns is locked and the sheet is protected. */ public boolean isFormatColumnsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getFormatColumns(); + return isSheetLocked() && safeGetProtectionField().getFormatColumns(); } /** * @return true when Formatting rows is locked and the sheet is protected. */ public boolean isFormatRowsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getFormatRows(); + return isSheetLocked() && safeGetProtectionField().getFormatRows(); } /** * @return true when Inserting columns is locked and the sheet is protected. */ public boolean isInsertColumnsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getInsertColumns(); + return isSheetLocked() && safeGetProtectionField().getInsertColumns(); } /** * @return true when Inserting hyperlinks is locked and the sheet is protected. */ public boolean isInsertHyperlinksLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getInsertHyperlinks(); + return isSheetLocked() && safeGetProtectionField().getInsertHyperlinks(); } /** * @return true when Inserting rows is locked and the sheet is protected. */ public boolean isInsertRowsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getInsertRows(); + return isSheetLocked() && safeGetProtectionField().getInsertRows(); } /** * @return true when Pivot tables are locked and the sheet is protected. */ public boolean isPivotTablesLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getPivotTables(); + return isSheetLocked() && safeGetProtectionField().getPivotTables(); } /** * @return true when Sorting is locked and the sheet is protected. */ public boolean isSortLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getSort(); + return isSheetLocked() && safeGetProtectionField().getSort(); } /** * @return true when Objects are locked and the sheet is protected. */ public boolean isObjectsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getObjects(); + return isSheetLocked() && safeGetProtectionField().getObjects(); } /** * @return true when Scenarios are locked and the sheet is protected. */ public boolean isScenariosLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getScenarios(); + return isSheetLocked() && safeGetProtectionField().getScenarios(); } /** * @return true when Selection of locked cells is locked and the sheet is protected. */ public boolean isSelectLockedCellsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getSelectLockedCells(); + return isSheetLocked() && safeGetProtectionField().getSelectLockedCells(); } /** * @return true when Selection of unlocked cells is locked and the sheet is protected. */ public boolean isSelectUnlockedCellsLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getSelectUnlockedCells(); + return isSheetLocked() && safeGetProtectionField().getSelectUnlockedCells(); } /** * @return true when Sheet is Protected. */ public boolean isSheetLocked() { - createProtectionFieldIfNotPresent(); - return sheetProtectionEnabled() && worksheet.getSheetProtection().getSheet(); + return worksheet.isSetSheetProtection() && safeGetProtectionField().getSheet(); } /** * Enable sheet protection */ public void enableLocking() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setSheet(true); + safeGetProtectionField().setSheet(true); } /** * Disable sheet protection */ public void disableLocking() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setSheet(false); + safeGetProtectionField().setSheet(false); } /** * Enable Autofilters locking. - * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * @deprecated use {@link #lockAutoFilter(boolean)} */ public void lockAutoFilter() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setAutoFilter(true); + lockAutoFilter(true); } /** - * Enable Deleting columns locking. + * Enable or disable Autofilters locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockAutoFilter(boolean enabled) { + safeGetProtectionField().setAutoFilter(enabled); + } + + /** + * Enable Deleting columns locking. + * @deprecated use {@link #lockDeleteColumns(boolean)} */ public void lockDeleteColumns() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setDeleteColumns(true); + lockDeleteColumns(true); } /** - * Enable Deleting rows locking. + * Enable or disable Deleting columns locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockDeleteColumns(boolean enabled) { + safeGetProtectionField().setDeleteColumns(enabled); + } + + /** + * Enable Deleting rows locking. + * @deprecated use {@link #lockDeleteRows(boolean)} */ public void lockDeleteRows() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setDeleteRows(true); + lockDeleteRows(true); } /** - * Enable Formatting cells locking. + * Enable or disable Deleting rows locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockDeleteRows(boolean enabled) { + safeGetProtectionField().setDeleteRows(enabled); + } + + /** + * Enable Formatting cells locking. + * @deprecated use {@link #lockFormatCells(boolean)} */ public void lockFormatCells() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setDeleteColumns(true); + lockFormatCells(true); } /** - * Enable Formatting columns locking. + * Enable or disable Formatting cells locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockFormatCells(boolean enabled) { + safeGetProtectionField().setFormatCells(enabled); + } + + /** + * Enable Formatting columns locking. + * @deprecated use {@link #lockFormatColumns(boolean)} */ public void lockFormatColumns() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setFormatColumns(true); + lockFormatColumns(true); } /** - * Enable Formatting rows locking. + * Enable or disable Formatting columns locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockFormatColumns(boolean enabled) { + safeGetProtectionField().setFormatColumns(enabled); + } + + /** + * Enable Formatting rows locking. + * @deprecated use {@link #lockFormatRows(boolean)} */ public void lockFormatRows() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setFormatRows(true); + lockFormatRows(true); } /** - * Enable Inserting columns locking. + * Enable or disable Formatting rows locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockFormatRows(boolean enabled) { + safeGetProtectionField().setFormatRows(enabled); + } + + /** + * Enable Inserting columns locking. + * @deprecated use {@link #lockInsertColumns(boolean)} */ public void lockInsertColumns() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setInsertColumns(true); + lockInsertColumns(true); } /** - * Enable Inserting hyperlinks locking. + * Enable or disable Inserting columns locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockInsertColumns(boolean enabled) { + safeGetProtectionField().setInsertColumns(enabled); + } + + /** + * Enable Inserting hyperlinks locking. + * @deprecated use {@link #lockInsertHyperlinks(boolean)} */ public void lockInsertHyperlinks() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setInsertHyperlinks(true); + lockInsertHyperlinks(true); } /** - * Enable Inserting rows locking. + * Enable or disable Inserting hyperlinks locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockInsertHyperlinks(boolean enabled) { + safeGetProtectionField().setInsertHyperlinks(enabled); + } + + /** + * Enable Inserting rows locking. + * @deprecated use {@link #lockInsertRows(boolean)} */ public void lockInsertRows() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setInsertRows(true); + lockInsertRows(true); } /** - * Enable Pivot Tables locking. + * Enable or disable Inserting rows locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockInsertRows(boolean enabled) { + safeGetProtectionField().setInsertRows(enabled); + } + + /** + * Enable Pivot Tables locking. + * @deprecated use {@link #lockPivotTables(boolean)} */ public void lockPivotTables() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setPivotTables(true); + lockPivotTables(true); } /** - * Enable Sort locking. + * Enable or disable Pivot Tables locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockPivotTables(boolean enabled) { + safeGetProtectionField().setPivotTables(enabled); + } + + /** + * Enable Sort locking. + * @deprecated use {@link #lockSort(boolean)} */ public void lockSort() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setSort(true); + lockSort(true); } /** - * Enable Objects locking. + * Enable or disable Sort locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockSort(boolean enabled) { + safeGetProtectionField().setSort(enabled); + } + + /** + * Enable Objects locking. + * @deprecated use {@link #lockObjects(boolean)} */ public void lockObjects() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setObjects(true); + lockObjects(true); } /** - * Enable Scenarios locking. + * Enable or disable Objects locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockObjects(boolean enabled) { + safeGetProtectionField().setObjects(enabled); + } + + /** + * Enable Scenarios locking. + * @deprecated use {@link #lockScenarios(boolean)} */ public void lockScenarios() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setScenarios(true); + lockScenarios(true); } /** - * Enable Selection of locked cells locking. + * Enable or disable Scenarios locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockScenarios(boolean enabled) { + safeGetProtectionField().setScenarios(enabled); + } + + /** + * Enable Selection of locked cells locking. + * @deprecated use {@link #lockSelectLockedCells(boolean)} */ public void lockSelectLockedCells() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setSelectLockedCells(true); + lockSelectLockedCells(true); } /** - * Enable Selection of unlocked cells locking. + * Enable or disable Selection of locked cells locking. * This does not modify sheet protection status. - * To enforce this locking, call {@link #enableLocking()} + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockSelectLockedCells(boolean enabled) { + safeGetProtectionField().setSelectLockedCells(enabled); + } + + /** + * Enable Selection of unlocked cells locking. + * @deprecated use {@link #lockSelectUnlockedCells(boolean)} */ public void lockSelectUnlockedCells() { - createProtectionFieldIfNotPresent(); - worksheet.getSheetProtection().setSelectUnlockedCells(true); + lockSelectUnlockedCells(true); } - private void createProtectionFieldIfNotPresent() { - if (worksheet.getSheetProtection() == null) { - worksheet.setSheetProtection(CTSheetProtection.Factory.newInstance()); + /** + * Enable or disable Selection of unlocked cells locking. + * This does not modify sheet protection status. + * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()} + */ + public void lockSelectUnlockedCells(boolean enabled) { + safeGetProtectionField().setSelectUnlockedCells(enabled); + } + + private CTSheetProtection safeGetProtectionField() { + if (!isSheetProtectionEnabled()) { + return worksheet.addNewSheetProtection(); } + return worksheet.getSheetProtection(); } - private boolean sheetProtectionEnabled() { - return worksheet.getSheetProtection().getSheet(); + /* package */ boolean isSheetProtectionEnabled() { + return (worksheet.isSetSheetProtection()); } /* package */ boolean isCellInArrayFormulaContext(XSSFCell cell) { @@ -3403,10 +3510,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * Returns any tables associated with this Sheet */ public List getTables() { - List tableList = new ArrayList( - tables.values() - ); - return tableList; + return new ArrayList(tables.values()); } @Override @@ -3529,21 +3633,20 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { String c = ""; String r = ""; - if(startC == -1 && endC == -1) { - } else { + if (startC != -1 || endC != -1) { c = escapedName + "!$" + colRef.getCellRefParts()[2] + ":$" + colRef2.getCellRefParts()[2]; } - if (startR == -1 && endR == -1) { - - } else if (!rowRef.getCellRefParts()[1].equals("0") - && !rowRef2.getCellRefParts()[1].equals("0")) { - r = escapedName + "!$" + rowRef.getCellRefParts()[1] - + ":$" + rowRef2.getCellRefParts()[1]; + if (startR != -1 || endR != -1) { + if (!rowRef.getCellRefParts()[1].equals("0") + && !rowRef2.getCellRefParts()[1].equals("0")) { + r = escapedName + "!$" + rowRef.getCellRefParts()[1] + + ":$" + rowRef2.getCellRefParts()[1]; + } } - StringBuffer rng = new StringBuffer(); + StringBuilder rng = new StringBuilder(); rng.append(c); if(rng.length() > 0 && r.length() > 0) { rng.append(','); diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java index be812c3dbf..8c83f6f164 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java @@ -19,21 +19,21 @@ package org.apache.poi.xssf.usermodel; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hssf.record.cf.CellRangeUtil; +import org.apache.poi.ss.SpreadsheetVersion; +import org.apache.poi.ss.usermodel.ComparisonOperator; import org.apache.poi.ss.usermodel.ConditionalFormatting; import org.apache.poi.ss.usermodel.ConditionalFormattingRule; import org.apache.poi.ss.usermodel.SheetConditionalFormatting; -import org.apache.poi.ss.usermodel.ComparisonOperator; import org.apache.poi.ss.util.CellRangeAddress; -import org.apache.poi.ss.SpreadsheetVersion; -import org.apache.poi.hssf.record.cf.CellRangeUtil; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCfType; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTConditionalFormatting; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.STConditionalFormattingOperator; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; - -import java.util.List; -import java.util.ArrayList; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCfType; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STConditionalFormattingOperator; /** * @author Yegor Kozlov @@ -115,6 +115,7 @@ public class XSSFSheetConditionalFormatting implements SheetConditionalFormattin return rule; } + @SuppressWarnings("deprecation") public int addConditionalFormatting(CellRangeAddress[] regions, ConditionalFormattingRule[] cfRules) { if (regions == null) { throw new IllegalArgumentException("regions must not be null"); @@ -130,21 +131,15 @@ public class XSSFSheetConditionalFormatting implements SheetConditionalFormattin if (cfRules.length > 3) { throw new IllegalArgumentException("Number of rules must not exceed 3"); } - XSSFConditionalFormattingRule[] hfRules; - if(cfRules instanceof XSSFConditionalFormattingRule[]) hfRules = (XSSFConditionalFormattingRule[])cfRules; - else { - hfRules = new XSSFConditionalFormattingRule[cfRules.length]; - System.arraycopy(cfRules, 0, hfRules, 0, hfRules.length); - } + CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(regions); CTConditionalFormatting cf = _sheet.getCTWorksheet().addNewConditionalFormatting(); List refs = new ArrayList(); for(CellRangeAddress a : mergeCellRanges) refs.add(a.formatAsString()); cf.setSqref(refs); - int priority = 1; - for(CTConditionalFormatting c : _sheet.getCTWorksheet().getConditionalFormattingList()){ + for(CTConditionalFormatting c : _sheet.getCTWorksheet().getConditionalFormattingArray()){ priority += c.sizeOfCfRuleArray(); } @@ -220,7 +215,7 @@ public class XSSFSheetConditionalFormatting implements SheetConditionalFormattin */ public void removeConditionalFormatting(int index) { checkIndex(index); - _sheet.getCTWorksheet().getConditionalFormattingList().remove(index); + _sheet.getCTWorksheet().removeConditionalFormatting(index); } private void checkIndex(int index) { diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java index ed1d9a27c5..d228cf9519 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java @@ -128,13 +128,14 @@ public class XSSFTable extends POIXMLDocumentPart { * * @return the xpath of the table's root element */ + @SuppressWarnings("deprecation") public String getCommonXpath() { if(commonXPath == null){ String[] commonTokens ={}; - for(CTTableColumn column :ctTable.getTableColumns().getTableColumnList()){ + for(CTTableColumn column :ctTable.getTableColumns().getTableColumnArray()){ if(column.getXmlColumnPr()!=null){ String xpath = column.getXmlColumnPr().getXpath(); String[] tokens = xpath.split("/"); @@ -173,11 +174,12 @@ public class XSSFTable extends POIXMLDocumentPart { } + @SuppressWarnings("deprecation") public List getXmlColumnPrs() { if(xmlColumnPr==null){ xmlColumnPr = new ArrayList(); - for (CTTableColumn column:ctTable.getTableColumns().getTableColumnList()){ + for (CTTableColumn column:ctTable.getTableColumns().getTableColumnArray()){ if (column.getXmlColumnPr()!=null){ XSSFXmlColumnPr columnPr = new XSSFXmlColumnPr(this,column,column.getXmlColumnPr()); xmlColumnPr.add(columnPr); @@ -285,6 +287,7 @@ public class XSSFTable extends POIXMLDocumentPart { * Headers must be in sync, otherwise Excel will display a * "Found unreadable content" message on startup. */ + @SuppressWarnings("deprecation") public void updateHeaders(){ XSSFSheet sheet = (XSSFSheet)getParent(); CellReference ref = getStartCellReference(); @@ -296,7 +299,7 @@ public class XSSFTable extends POIXMLDocumentPart { if (row != null && row.getCTRow().validate()) { int cellnum = firstHeaderColumn; - for (CTTableColumn col : getCTTable().getTableColumns().getTableColumnList()) { + for (CTTableColumn col : getCTTable().getTableColumns().getTableColumnArray()) { XSSFCell cell = row.getCell(cellnum); if (cell != null) { col.setName(cell.getStringCellValue()); 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 60e1ea415e..a51b40675f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java @@ -17,6 +17,9 @@ package org.apache.poi.xssf.usermodel; +import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword; +import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -47,6 +50,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.openxml4j.opc.TargetMode; +import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.ss.formula.SheetNameFormatter; import org.apache.poi.ss.formula.udf.IndexedUDFFinder; import org.apache.poi.ss.formula.udf.UDFFinder; @@ -1366,6 +1370,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable(); if(workbook.isSetDefinedNames()) { - for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameList()) { + for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) { namedRanges.add(new XSSFName(ctName, this)); } } @@ -1735,60 +1742,108 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable colsList = worksheet.getColsList(); - assert(colsList != null); + CTCols[] colsArray = worksheet.getColsArray(); + assert(colsArray != null); - for (CTCols cols : colsList) { - for (CTCol col : cols.getColList()) { + for (CTCols cols : colsArray) { + for (CTCol col : cols.getColArray()) { cloneCol(aggregateCols, col); } } sortColumns(aggregateCols); - CTCol[] colArray = new CTCol[aggregateCols.getColList().size()]; - aggregateCols.getColList().toArray(colArray); + CTCol[] colArray = aggregateCols.getColArray(); sweepCleanColumns(newCols, colArray, null); - int i = colsList.size(); + int i = colsArray.length; for (int y = i - 1; y >= 0; y--) { worksheet.removeCols(y); } worksheet.addNewCols(); worksheet.setColsArray(0, newCols); } - - private static class CTColByMaxComparator implements Comparator { - - public int compare(CTCol arg0, CTCol arg1) { - if (arg0.getMax() < arg1.getMax()) { - return -1; - } else { - if (arg0.getMax() > arg1.getMax()) return 1; - else return 0; - } - } - - } /** * @see Sweep line algorithm */ private void sweepCleanColumns(CTCols cols, CTCol[] flattenedColsArray, CTCol overrideColumn) { List flattenedCols = new ArrayList(Arrays.asList(flattenedColsArray)); - TreeSet currentElements = new TreeSet(new CTColByMaxComparator()); + TreeSet currentElements = new TreeSet(CTColComparator.BY_MAX); ListIterator flIter = flattenedCols.listIterator(); CTCol haveOverrideColumn = null; long lastMaxIndex = 0; @@ -103,7 +89,8 @@ public class ColumnHelper { while (flIter.hasNext()) { CTCol col = flIter.next(); long currentIndex = col.getMin(); - long nextIndex = (col.getMax() > currentMax) ? col.getMax() : currentMax; + long colMax = col.getMax(); + long nextIndex = (colMax > currentMax) ? colMax : currentMax; if (flIter.hasNext()) { nextIndex = flIter.next().getMin(); flIter.previous(); @@ -116,10 +103,10 @@ public class ColumnHelper { } if (!currentElements.isEmpty() && lastMaxIndex < currentIndex) { // we need to process previous elements first - insertCol(cols, lastMaxIndex, currentIndex - 1, currentElements.toArray(new CTCol[]{}), true, haveOverrideColumn); + insertCol(cols, lastMaxIndex, currentIndex - 1, currentElements.toArray(new CTCol[currentElements.size()]), true, haveOverrideColumn); } currentElements.add(col); - if (col.getMax() > currentMax) currentMax = col.getMax(); + if (colMax > currentMax) currentMax = colMax; if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; while (currentIndex <= nextIndex && !currentElements.isEmpty()) { Set currentIndexElements = new HashSet(); @@ -130,26 +117,21 @@ public class ColumnHelper { CTCol currentElem = currentElements.first(); currentElemIndex = currentElem.getMax(); currentIndexElements.add(currentElem); - - for (CTCol cc : currentElements.tailSet(currentElem)) { - if (cc == null || cc.getMax() == currentElemIndex) break; - currentIndexElements.add(cc); - if (col.getMax() > currentMax) currentMax = col.getMax(); + + while (true) { + CTCol higherElem = currentElements.higher(currentElem); + if (higherElem == null || higherElem.getMax() != currentElemIndex) + break; + currentElem = higherElem; + currentIndexElements.add(currentElem); + if (colMax > currentMax) currentMax = colMax; if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; } - - // JDK 6 code - // while (currentElements.higher(currentElem) != null && currentElements.higher(currentElem).getMax() == currentElemIndex) { - // currentElem = currentElements.higher(currentElem); - // currentIndexElements.add(currentElem); - // if (col.getMax() > currentMax) currentMax = col.getMax(); - // if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; - // } } if (currentElemIndex < nextIndex || !flIter.hasNext()) { - insertCol(cols, currentIndex, currentElemIndex, currentElements.toArray(new CTCol[]{}), true, haveOverrideColumn); + insertCol(cols, currentIndex, currentElemIndex, currentElements.toArray(new CTCol[currentElements.size()]), true, haveOverrideColumn); if (flIter.hasNext()) { if (nextIndex > currentElemIndex) { currentElements.removeAll(currentIndexElements); @@ -170,10 +152,10 @@ public class ColumnHelper { sortColumns(cols); } + @SuppressWarnings("deprecation") public static void sortColumns(CTCols newCols) { - CTCol[] colArray = new CTCol[newCols.getColList().size()]; - newCols.getColList().toArray(colArray); - Arrays.sort(colArray, new CTColComparator()); + CTCol[] colArray = newCols.getColArray(); + Arrays.sort(colArray, CTColComparator.BY_MIN_MAX); newCols.setColArray(colArray); } @@ -198,46 +180,46 @@ public class ColumnHelper { * as 1 based. */ public CTCol getColumn1Based(long index1, boolean splitColumns) { - CTCols colsArray = worksheet.getColsArray(0); + CTCols cols = worksheet.getColsArray(0); // Fetching the array is quicker than working on the new style // list, assuming we need to read many of them (which we often do), // and assuming we're not making many changes (which we're not) @SuppressWarnings("deprecation") - CTCol[] cols = colsArray.getColArray(); - - for (int i = 0; i < cols.length; i++) { - CTCol colArray = cols[i]; - if (colArray.getMin() <= index1 && colArray.getMax() >= index1) { + CTCol[] colArray = cols.getColArray(); + + for (CTCol col : colArray) { + long colMin = col.getMin(); + long colMax = col.getMax(); + if (colMin <= index1 && colMax >= index1) { if (splitColumns) { - if (colArray.getMin() < index1) { - insertCol(colsArray, colArray.getMin(), (index1 - 1), new CTCol[]{colArray}); + if (colMin < index1) { + insertCol(cols, colMin, (index1 - 1), new CTCol[]{col}); } - if (colArray.getMax() > index1) { - insertCol(colsArray, (index1 + 1), colArray.getMax(), new CTCol[]{colArray}); + if (colMax > index1) { + insertCol(cols, (index1 + 1), colMax, new CTCol[]{col}); } - colArray.setMin(index1); - colArray.setMax(index1); + col.setMin(index1); + col.setMax(index1); } - return colArray; + return col; } } return null; } - + + @SuppressWarnings("deprecation") public CTCols addCleanColIntoCols(CTCols cols, CTCol col) { CTCols newCols = CTCols.Factory.newInstance(); - for (CTCol c : cols.getColList()) { + for (CTCol c : cols.getColArray()) { cloneCol(newCols, c); } cloneCol(newCols, col); sortColumns(newCols); - CTCol[] colArray = new CTCol[newCols.getColList().size()]; - newCols.getColList().toArray(colArray); + CTCol[] colArray = newCols.getColArray(); CTCols returnCols = CTCols.Factory.newInstance(); sweepCleanColumns(returnCols, colArray, col); - colArray = new CTCol[returnCols.getColList().size()]; - returnCols.getColList().toArray(colArray); + colArray = returnCols.getColArray(); cols.setColArray(colArray); return returnCols; } @@ -272,9 +254,11 @@ public class ColumnHelper { public boolean columnExists(CTCols cols, long index) { return columnExists1Based(cols, index+1); } + + @SuppressWarnings("deprecation") private boolean columnExists1Based(CTCols cols, long index1) { - for (int i = 0; i < cols.sizeOfColArray(); i++) { - if (cols.getColArray(i).getMin() == index1) { + for (CTCol col : cols.getColArray()) { + if (col.getMin() == index1) { return true; } } @@ -343,20 +327,24 @@ public class ColumnHelper { return -1; } + @SuppressWarnings("deprecation") private boolean columnExists(CTCols cols, long min, long max) { - for (int i = 0; i < cols.sizeOfColArray(); i++) { - if (cols.getColArray(i).getMin() == min && cols.getColArray(i).getMax() == max) { + for (CTCol col : cols.getColArray()) { + if (col.getMin() == min && col.getMax() == max) { return true; } } return false; } - - public int getIndexOfColumn(CTCols cols, CTCol col) { - for (int i = 0; i < cols.sizeOfColArray(); i++) { - if (cols.getColArray(i).getMin() == col.getMin() && cols.getColArray(i).getMax() == col.getMax()) { + + @SuppressWarnings("deprecation") + public int getIndexOfColumn(CTCols cols, CTCol searchCol) { + int i = 0; + for (CTCol col : cols.getColArray()) { + if (col.getMin() == searchCol.getMin() && col.getMax() == searchCol.getMax()) { return i; } + i++; } return -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 new file mode 100644 index 0000000000..c887129b69 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java @@ -0,0 +1,128 @@ +/* + * ==================================================================== + * 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 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()); + } 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/XSSFRowShifter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFRowShifter.java index 1b51568867..cfa0a77771 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 @@ -18,7 +18,9 @@ package org.apache.poi.xssf.usermodel.helpers; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.poi.ss.formula.FormulaParseException; import org.apache.poi.ss.formula.FormulaParser; @@ -43,6 +45,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTConditionalFormatting; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType; /** @@ -66,8 +69,10 @@ public final class XSSFRowShifter { */ public List shiftMerged(int startRow, int endRow, int n) { List shiftedRegions = new ArrayList(); + Set removedIndices = new HashSet(); //move merged regions completely if they fall within the new region boundaries when they are shifted - for (int i = 0; i < sheet.getNumMergedRegions(); i++) { + int size = sheet.getNumMergedRegions(); + for (int i = 0; i < size; i++) { CellRangeAddress merged = sheet.getMergedRegion(i); boolean inStart = (merged.getFirstRow() >= startRow || merged.getLastRow() >= startRow); @@ -84,10 +89,13 @@ public final class XSSFRowShifter { merged.setLastRow(merged.getLastRow() + n); //have to remove/add it back shiftedRegions.add(merged); - sheet.removeMergedRegion(i); - i = i - 1; // we have to back up now since we removed one + removedIndices.add(i); } } + + if(!removedIndices.isEmpty()) { + sheet.removeMergedRegions(removedIndices); + } //read so it doesn't get shifted again for (CellRangeAddress region : shiftedRegions) { @@ -213,28 +221,29 @@ public final class XSSFRowShifter { } } + @SuppressWarnings("deprecation") public void updateConditionalFormatting(FormulaShifter shifter) { XSSFWorkbook wb = sheet.getWorkbook(); int sheetIndex = wb.getSheetIndex(sheet); - XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb); - List cfList = sheet.getCTWorksheet().getConditionalFormattingList(); - for(int j = 0; j< cfList.size(); j++){ - CTConditionalFormatting cf = cfList.get(j); + CTWorksheet ctWorksheet = sheet.getCTWorksheet(); + CTConditionalFormatting[] conditionalFormattingArray = ctWorksheet.getConditionalFormattingArray(); + // iterate backwards due to possible calls to ctWorksheet.removeConditionalFormatting(j) + for (int j = conditionalFormattingArray.length - 1; j >= 0; j--) { + CTConditionalFormatting cf = conditionalFormattingArray[j]; ArrayList cellRanges = new ArrayList(); for (Object stRef : cf.getSqref()) { String[] regions = stRef.toString().split(" "); - for (int i = 0; i < regions.length; i++) { - cellRanges.add(CellRangeAddress.valueOf(regions[i])); + for (String region : regions) { + cellRanges.add(CellRangeAddress.valueOf(region)); } } boolean changed = false; List temp = new ArrayList(); - for (int i = 0; i < cellRanges.size(); i++) { - CellRangeAddress craOld = cellRanges.get(i); + for (CellRangeAddress craOld : cellRanges) { CellRangeAddress craNew = shiftRange(shifter, craOld, sheetIndex); if (craNew == null) { changed = true; @@ -249,7 +258,7 @@ public final class XSSFRowShifter { if (changed) { int nRanges = temp.size(); if (nRanges == 0) { - cfList.remove(j); + ctWorksheet.removeConditionalFormatting(j); continue; } List refs = new ArrayList(); @@ -257,14 +266,14 @@ public final class XSSFRowShifter { cf.setSqref(refs); } - for(CTCfRule cfRule : cf.getCfRuleList()){ - List formulas = cfRule.getFormulaList(); - for (int i = 0; i < formulas.size(); i++) { - String formula = formulas.get(i); + for(CTCfRule cfRule : cf.getCfRuleArray()){ + String[] formulaArray = cfRule.getFormulaArray(); + for (int i = 0; i < formulaArray.length; i++) { + String formula = formulaArray[i]; Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex); if (shifter.adjustFormula(ptgs, sheetIndex)) { String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs); - formulas.set(i, shiftedFmla); + cfRule.setFormulaArray(i, shiftedFmla); } } } diff --git a/src/ooxml/java/org/apache/poi/xssf/util/CTColComparator.java b/src/ooxml/java/org/apache/poi/xssf/util/CTColComparator.java index 50d5c8f9f7..5368eb0e6e 100644 --- a/src/ooxml/java/org/apache/poi/xssf/util/CTColComparator.java +++ b/src/ooxml/java/org/apache/poi/xssf/util/CTColComparator.java @@ -21,26 +21,26 @@ import java.util.Comparator; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; -public class CTColComparator implements Comparator{ +public class CTColComparator { - public int compare(CTCol o1, CTCol o2) { - if (o1.getMin() < o2.getMin()) { - return -1; - } - else if (o1.getMin() > o2.getMin()) { - return 1; + private CTColComparator() {} + + public static final Comparator BY_MAX = new Comparator() { + @Override + public int compare(CTCol col1, CTCol col2) { + long col1max = col1.getMax(); + long col2max = col2.getMax(); + return col1max < col2max ? -1 : col1max > col2max ? 1 : 0; } - else { - if (o1.getMax() < o2.getMax()) { - return -1; - } - if (o1.getMax() > o2.getMax()) { - return 1; - } - return 0; + }; + + public static final Comparator BY_MIN_MAX = new Comparator() { + @Override + public int compare(CTCol col1, CTCol col2) { + long col11min = col1.getMin(); + long col2min = col2.getMin(); + return col11min < col2min ? -1 : col11min > col2min ? 1 : BY_MAX.compare(col1, col2); } - } - - - + }; + } diff --git a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFCommentsDecorator.java b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFCommentsDecorator.java index be7bf0408e..502a3b7861 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFCommentsDecorator.java +++ b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFCommentsDecorator.java @@ -33,13 +33,15 @@ public class XWPFCommentsDecorator extends XWPFParagraphDecorator { public XWPFCommentsDecorator(XWPFParagraphDecorator nextDecorator) { this(nextDecorator.paragraph, nextDecorator); } + + @SuppressWarnings("deprecation") public XWPFCommentsDecorator(XWPFParagraph paragraph, XWPFParagraphDecorator nextDecorator) { super(paragraph, nextDecorator); XWPFComment comment; commentText = new StringBuffer(); - for(CTMarkupRange anchor : paragraph.getCTP().getCommentRangeStartList()) + for(CTMarkupRange anchor : paragraph.getCTP().getCommentRangeStartArray()) { if((comment = paragraph.getDocument().getCommentByID(anchor.getId().toString())) != null) commentText.append("\tComment by " + comment.getAuthor()+": "+comment.getText()); diff --git a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHyperlinkDecorator.java b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHyperlinkDecorator.java index 628ff37c94..d8120340f5 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHyperlinkDecorator.java +++ b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHyperlinkDecorator.java @@ -52,10 +52,10 @@ public class XWPFHyperlinkDecorator extends XWPFParagraphDecorator { hyperlinkText = new StringBuffer(); // loop over hyperlink anchors - for(CTHyperlink link : paragraph.getCTP().getHyperlinkList()){ - for (CTR r : link.getRList()) { + for(CTHyperlink link : paragraph.getCTP().getHyperlinkArray()){ + for (CTR r : link.getRArray()) { // Loop over text runs - for (CTText text : r.getTList()){ + for (CTText text : r.getTArray()){ hyperlinkText.append(text.getStringValue()); } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/AbstractXWPFSDT.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/AbstractXWPFSDT.java index 9c668e8453..e69b0244e7 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/AbstractXWPFSDT.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/AbstractXWPFSDT.java @@ -35,17 +35,18 @@ public abstract class AbstractXWPFSDT implements ISDTContents { private final String tag; private final IBody part; + @SuppressWarnings("deprecation") public AbstractXWPFSDT(CTSdtPr pr, IBody part){ - List aliases = pr.getAliasList(); - if (aliases != null && aliases.size() > 0){ - title = aliases.get(0).getVal(); + CTString[] aliases = pr.getAliasArray(); + if (aliases != null && aliases.length > 0){ + title = aliases[0].getVal(); } else { title = ""; } - List tags = pr.getTagList(); - if (tags != null && tags.size() > 0){ - tag = tags.get(0).getVal(); + CTString[] tags = pr.getTagArray(); + if (tags != null && tags.length > 0){ + tag = tags[0].getVal(); } else { tag = ""; } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComment.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComment.java index d193983c79..84ebc36bb1 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComment.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComment.java @@ -31,13 +31,14 @@ public class XWPFComment protected String author; protected StringBuffer text; + @SuppressWarnings("deprecation") public XWPFComment(CTComment comment, XWPFDocument document) { text = new StringBuffer(); id = comment.getId().toString(); author = comment.getAuthor(); - for(CTP ctp : comment.getPList()) + for(CTP ctp : comment.getPArray()) { XWPFParagraph p = new XWPFParagraph(ctp, document); text.append(p.getText()); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index 568681dee4..9adc397048 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -184,7 +184,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } else if (relation.equals(XWPFRelation.COMMENT.getRelation())) { // TODO Create according XWPFComment class, extending POIXMLDocumentPart CommentsDocument cmntdoc = CommentsDocument.Factory.parse(p.getPackagePart().getInputStream()); - for (CTComment ctcomment : cmntdoc.getComments().getCommentList()) { + for (CTComment ctcomment : cmntdoc.getComments().getCommentArray()) { comments.add(new XWPFComment(ctcomment, this)); } } else if (relation.equals(XWPFRelation.SETTINGS.getRelation())) { @@ -232,6 +232,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } } + @SuppressWarnings("deprecation") private void initFootnotes() throws XmlException, IOException { for(POIXMLDocumentPart p : getRelations()){ String relation = p.getPackageRelationship().getRelationshipType(); @@ -241,7 +242,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } else if (relation.equals(XWPFRelation.ENDNOTE.getRelation())){ EndnotesDocument endnotesDocument = EndnotesDocument.Factory.parse(p.getPackagePart().getInputStream()); - for(CTFtnEdn ctFtnEdn : endnotesDocument.getEndnotes().getEndnoteList()) { + for(CTFtnEdn ctFtnEdn : endnotesDocument.getEndnotes().getEndnoteArray()) { endnotes.put(ctFtnEdn.getId().intValue(), new XWPFFootnote(this, ctFtnEdn)); } } @@ -364,10 +365,8 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } public XWPFHyperlink getHyperlinkByID(String id) { - Iterator iter = hyperlinks.iterator(); - while (iter.hasNext()) { - XWPFHyperlink link = iter.next(); - if(link.getId().equals(id)) + for (XWPFHyperlink link : hyperlinks) { + if (link.getId().equals(id)) return link; } @@ -396,10 +395,8 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } public XWPFComment getCommentByID(String id) { - Iterator iter = comments.iterator(); - while (iter.hasNext()) { - XWPFComment comment = iter.next(); - if(comment.getId().equals(id)) + for (XWPFComment comment : comments) { + if (comment.getId().equals(id)) return comment; } @@ -1187,14 +1184,15 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * @param table */ @Override + @SuppressWarnings("deprecation") public void insertTable(int pos, XWPFTable table) { bodyElements.add(pos, table); - int i; - for (i = 0; i < ctDocument.getBody().getTblList().size(); i++) { - CTTbl tbl = ctDocument.getBody().getTblArray(i); + int i = 0; + for (CTTbl tbl : ctDocument.getBody().getTblArray()) { if (tbl == table.getCTTbl()) { break; } + i++; } tables.add(i, table); } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java index 7ecb4d77cd..5f0367d6bf 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java @@ -123,14 +123,15 @@ public class XWPFFootnote implements Iterable,IBody { * @param table * @see org.apache.poi.xwpf.usermodel.IBody#insertTable(int pos, XWPFTable table) */ + @SuppressWarnings("deprecation") public void insertTable(int pos, XWPFTable table) { bodyElements.add(pos, table); - int i; - for (i = 0; i < ctFtnEdn.getTblList().size(); i++) { - CTTbl tbl = ctFtnEdn.getTblArray(i); + int i = 0; + for (CTTbl tbl : ctFtnEdn.getTblArray()) { if(tbl == table.getCTTbl()){ break; } + i++; } tables.add(i, table); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnotes.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnotes.java index 74dd12613d..8647454f28 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnotes.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnotes.java @@ -34,7 +34,6 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; - import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFtnEdn; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFootnotes; import org.openxmlformats.schemas.wordprocessingml.x2006.main.FootnotesDocument; @@ -68,6 +67,7 @@ public class XWPFFootnotes extends POIXMLDocumentPart { * Read document */ @Override + @SuppressWarnings("deprecation") protected void onDocumentRead () throws IOException { FootnotesDocument notesDoc; try { @@ -79,7 +79,7 @@ public class XWPFFootnotes extends POIXMLDocumentPart { } // Find our footnotes - for(CTFtnEdn note : ctFootnotes.getFootnoteList()) { + for(CTFtnEdn note : ctFootnotes.getFootnoteArray()) { listFootnote.add(new XWPFFootnote(note, this)); } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java index 5fc2fdcd07..e6dee2fef3 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java @@ -436,14 +436,15 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBo * @param pos * @param table */ + @SuppressWarnings("deprecation") public void insertTable(int pos, XWPFTable table) { bodyElements.add(pos, table); - int i; - for (i = 0; i < headerFooter.getTblList().size(); i++) { - CTTbl tbl = headerFooter.getTblArray(i); + int i = 0; + for (CTTbl tbl : headerFooter.getTblArray()) { if(tbl == table.getCTTbl()){ break; } + i++; } tables.add(i, table); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java index a0a586313b..83b898c1be 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java @@ -38,10 +38,12 @@ public class XWPFLatentStyles { /** * checks wheter specific LatentStyleID is a latentStyle */ + @SuppressWarnings("deprecation") protected boolean isLatentStyle(String latentStyleID){ - for ( CTLsdException lsd: latentStyles.getLsdExceptionList()) { - if(lsd.getName().equals(latentStyleID)); + for ( CTLsdException lsd: latentStyles.getLsdExceptionArray()) { + if(lsd.getName().equals(latentStyleID)) { return true; + } } return false; } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java index 2b4ca7049a..1bc8af5aed 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java @@ -71,6 +71,7 @@ public class XWPFNumbering extends POIXMLDocumentPart { * read numbering form an existing package */ @Override + @SuppressWarnings("deprecation") protected void onDocumentRead() throws IOException{ NumberingDocument numberingDoc = null; InputStream is; @@ -79,10 +80,10 @@ public class XWPFNumbering extends POIXMLDocumentPart { numberingDoc = NumberingDocument.Factory.parse(is); ctNumbering = numberingDoc.getNumbering(); //get any Nums - for(CTNum ctNum : ctNumbering.getNumList()) { + for(CTNum ctNum : ctNumbering.getNumArray()) { nums.add(new XWPFNum(ctNum, this)); } - for(CTAbstractNum ctAbstractNum : ctNumbering.getAbstractNumList()){ + for(CTAbstractNum ctAbstractNum : ctNumbering.getAbstractNumArray()){ abstractNums.add(new XWPFAbstractNum(ctAbstractNum, this)); } isNew = false; @@ -144,7 +145,7 @@ public class XWPFNumbering extends POIXMLDocumentPart { */ public BigInteger addNum(XWPFNum num){ ctNumbering.addNewNum(); - int pos = (ctNumbering.getNumList().size()) - 1; + int pos = ctNumbering.sizeOfNumArray() - 1; ctNumbering.setNumArray(pos, num.getCTNum()); nums.add(num); return num.getCTNum().getNumId(); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java index 98b9dccc46..5a4d7b33b7 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java @@ -137,7 +137,7 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents { } if (o instanceof CTHyperlink) { CTHyperlink link = (CTHyperlink) o; - for (CTR r : link.getRList()) { + for (CTR r : link.getRArray()) { XWPFHyperlinkRun hr = new XWPFHyperlinkRun(link, r, this); runs.add(hr); iruns.add(hr); @@ -152,14 +152,14 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents { iruns.add(cc); } if (o instanceof CTRunTrackChange) { - for (CTR r : ((CTRunTrackChange) o).getRList()) { + for (CTR r : ((CTRunTrackChange) o).getRArray()) { XWPFRun cr = new XWPFRun(r, this); runs.add(cr); iruns.add(cr); } } if (o instanceof CTSimpleField) { - for (CTR r : ((CTSimpleField) o).getRList()) { + for (CTR r : ((CTSimpleField) o).getRArray()) { XWPFRun cr = new XWPFRun(r, this); runs.add(cr); iruns.add(cr); @@ -1170,7 +1170,7 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents { */ protected void addRun(CTR run){ int pos; - pos = paragraph.getRList().size(); + pos = paragraph.sizeOfRArray(); paragraph.addNewR(); paragraph.setRArray(pos, run); } @@ -1230,9 +1230,10 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents { startChar = startPos.getChar(); int beginRunPos = 0, candCharPos = 0; boolean newList = false; - for (int runPos=startRun; runPos drawingList = r.getDrawingList(); - for (CTDrawing ctDrawing : drawingList) { - List anchorList = ctDrawing.getAnchorList(); - for (CTAnchor anchor : anchorList) { + for (CTDrawing ctDrawing : r.getDrawingArray()) { + for (CTAnchor anchor : ctDrawing.getAnchorArray()) { if (anchor.getDocPr() != null) { getDocument().getDrawingIdManager().reserve(anchor.getDocPr().getId()); } } - List inlineList = ctDrawing.getInlineList(); - for (CTInline inline : inlineList) { + for (CTInline inline : ctDrawing.getInlineArray()) { if (inline.getDocPr() != null) { getDocument().getDrawingIdManager().reserve(inline.getDocPr().getId()); } @@ -120,17 +119,17 @@ public class XWPFRun implements ISDTContents, IRunElement{ } // Look for any text in any of our pictures or drawings - StringBuffer text = new StringBuffer(); + StringBuilder text = new StringBuilder(); List pictTextObjs = new ArrayList(); - pictTextObjs.addAll(r.getPictList()); - pictTextObjs.addAll(drawingList); + pictTextObjs.addAll(Arrays.asList(r.getPictArray())); + pictTextObjs.addAll(Arrays.asList(r.getDrawingArray())); for(XmlObject o : pictTextObjs) { - XmlObject[] t = o.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:t"); - for (int m = 0; m < t.length; m++) { - NodeList kids = t[m].getDomNode().getChildNodes(); + XmlObject[] ts = o.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:t"); + for (XmlObject t : ts) { + NodeList kids = t.getDomNode().getChildNodes(); for (int n = 0; n < kids.getLength(); n++) { if (kids.item(n) instanceof Text) { - if(text.length() > 0) + if (text.length() > 0) text.append("\n"); text.append(kids.item(n).getNodeValue()); } @@ -317,7 +316,7 @@ public class XWPFRun implements ISDTContents, IRunElement{ * @param value the literal text which shall be displayed in the document */ public void setText(String value) { - setText(value,run.getTList().size()); + setText(value,run.sizeOfTArray()); } /** diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSDTContent.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSDTContent.java index 59a0abba9f..42c56b3773 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSDTContent.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSDTContent.java @@ -50,8 +50,8 @@ public class XWPFSDTContent implements ISDTContent { private List bodyElements = new ArrayList(); public XWPFSDTContent(CTSdtContentRun sdtRun, IBody part, IRunBody parent){ - for (CTR ctr : sdtRun.getRList()){ - XWPFRun run = new XWPFRun((CTR) ctr, parent); + for (CTR ctr : sdtRun.getRArray()){ + XWPFRun run = new XWPFRun(ctr, parent); runs.add(run); bodyElements.add(run); } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java index 35a0c6027e..359f4ece24 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java @@ -37,7 +37,6 @@ import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles; import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument; - import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPrDefault; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLanguage; @@ -74,6 +73,7 @@ public class XWPFStyles extends POIXMLDocumentPart{ * Read document */ @Override + @SuppressWarnings("deprecation") protected void onDocumentRead() throws IOException{ StylesDocument stylesDoc; try { @@ -86,7 +86,7 @@ public class XWPFStyles extends POIXMLDocumentPart{ } // Build up all the style objects - for(CTStyle style : ctStyles.getStyleList()) { + for(CTStyle style : ctStyles.getStyleArray()) { listStyle.add(new XWPFStyle(style, this)); } } @@ -137,7 +137,7 @@ public class XWPFStyles extends POIXMLDocumentPart{ public void addStyle(XWPFStyle style){ listStyle.add(style); ctStyles.addNewStyle(); - int pos = (ctStyles.getStyleList().size()) - 1; + int pos = ctStyles.sizeOfStyleArray() - 1; ctStyles.setStyleArray(pos, style.getCTStyle()); } /** diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java index 554e7bef2c..643d28ffa9 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java @@ -93,6 +93,7 @@ public class XWPFTable implements IBodyElement, ISDTContents { } } + @SuppressWarnings("deprecation") public XWPFTable(CTTbl table, IBody part){ this.part = part; this.ctTbl = table; @@ -103,12 +104,12 @@ public class XWPFTable implements IBodyElement, ISDTContents { if (table.sizeOfTrArray() == 0) createEmptyTable(table); - for (CTRow row : table.getTrList()) { - StringBuffer rowText = new StringBuffer(); + for (CTRow row : table.getTrArray()) { + StringBuilder rowText = new StringBuilder(); XWPFTableRow tabRow = new XWPFTableRow(row, this); tableRows.add(tabRow); - for (CTTc cell : row.getTcList()) { - for (CTP ctp : cell.getPList()) { + for (CTTc cell : row.getTcArray()) { + for (CTP ctp : cell.getPArray()) { XWPFParagraph p = new XWPFParagraph(ctp, part); if (rowText.length() > 0) { rowText.append('\t'); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java index e1b46fecd2..c1f0d4f447 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java @@ -79,7 +79,7 @@ public class XWPFTableCell implements IBody, ICell { this.part = part; this.tableRow = tableRow; // NB: If a table cell does not include at least one block-level element, then this document shall be considered corrupt. - if(cell.getPList().size()<1) + if(cell.sizeOfPArray()<1) cell.addNewP(); bodyElements = new ArrayList(); paragraphs = new ArrayList(); @@ -398,16 +398,17 @@ public class XWPFTableCell implements IBody, ICell { * inserts an existing XWPFTable to the arrays bodyElements and tables * @see org.apache.poi.xwpf.usermodel.IBody#insertTable(int, org.apache.poi.xwpf.usermodel.XWPFTable) */ + @SuppressWarnings("deprecation") public void insertTable(int pos, XWPFTable table) { - bodyElements.add(pos, table); - int i; - for (i = 0; i < ctTc.getTblList().size(); i++) { - CTTbl tbl = ctTc.getTblArray(i); - if(tbl == table.getCTTbl()){ - break; - } - } - tables.add(i, table); + bodyElements.add(pos, table); + int i = 0; + for (CTTbl tbl : ctTc.getTblArray()) { + if (tbl == table.getCTTbl()) { + break; + } + i++; + } + tables.add(i, table); } public String getText(){ diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java index 56ea38745f..627ee3c8d3 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java @@ -152,10 +152,11 @@ public class XWPFTableRow { * who belongs to this row * @return a list of {@link XWPFTableCell} */ + @SuppressWarnings("deprecation") public List getTableCells(){ if(tableCells == null){ List cells = new ArrayList(); - for (CTTc tableCell : ctRow.getTcList()) { + for (CTTc tableCell : ctRow.getTcArray()) { cells.add(new XWPFTableCell(tableCell, this, table.getBody())); } //TODO: it is possible to have an SDT that contains a cell in within a row @@ -201,7 +202,7 @@ public class XWPFTableRow { boolean isCant = false; CTTrPr trpr = getTrPr(); if (trpr.sizeOfCantSplitArray() > 0) { - CTOnOff onoff = trpr.getCantSplitList().get(0); + CTOnOff onoff = trpr.getCantSplitArray(0); isCant = onoff.getVal().equals(STOnOff.ON); } return isCant; @@ -229,7 +230,7 @@ public class XWPFTableRow { boolean repeat = false; CTTrPr trpr = getTrPr(); if (trpr.sizeOfTblHeaderArray() > 0) { - CTOnOff rpt = trpr.getTblHeaderList().get(0); + CTOnOff rpt = trpr.getTblHeaderArray(0); repeat = rpt.getVal().equals(STOnOff.ON); } return repeat; diff --git a/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java b/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java index c7215a4061..e185543020 100644 --- a/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java +++ b/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java @@ -80,13 +80,14 @@ public final class TestPOIXMLProperties extends TestCase { org.apache.poi.POIXMLProperties.ExtendedProperties newProperties = newProps.getExtendedProperties(); + assertEquals(application, newProperties.getApplication()); + assertEquals(appVersion, newProperties.getAppVersion()); + org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties newCtProps = newProperties.getUnderlyingProperties(); assertEquals(application, newCtProps.getApplication()); assertEquals(appVersion, newCtProps.getAppVersion()); - - } diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java index 1c64fd8629..c42ce63d43 100644 --- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java +++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java @@ -42,7 +42,6 @@ import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; -import org.apache.poi.util.SAXHelper; import org.apache.poi.util.TempFile; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -218,7 +217,7 @@ public final class TestPackage extends TestCase { PackagePartName relName = PackagingURIHelper.createPartName(PackageRelationship.getContainerPartRelationship()); PackagePart relPart = pkg.getPart(relName); - Document xmlRelationshipsDoc = SAXHelper.readSAXDocument(relPart.getInputStream()); + Document xmlRelationshipsDoc = DocumentHelper.readDocument(relPart.getInputStream()); Element root = xmlRelationshipsDoc.getDocumentElement(); NodeList nodeList = root.getElementsByTagName(PackageRelationship.RELATIONSHIP_TAG_NAME); diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/PkiTestUtils.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/PkiTestUtils.java index 24d002d27f..afd70f08e5 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/PkiTestUtils.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/PkiTestUtils.java @@ -30,6 +30,7 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Date; @@ -45,8 +46,6 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; @@ -69,6 +68,7 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.cert.X509CRLHolder; import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509ExtensionUtils; import org.bouncycastle.cert.X509v2CRLBuilder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CRLConverter; @@ -83,6 +83,8 @@ import org.bouncycastle.cert.ocsp.OCSPResp; import org.bouncycastle.cert.ocsp.OCSPRespBuilder; import org.bouncycastle.cert.ocsp.Req; import org.bouncycastle.cert.ocsp.RevokedStatus; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.DigestCalculator; import org.bouncycastle.operator.OperatorCreationException; @@ -108,24 +110,6 @@ public class PkiTestUtils { return keyPair; } - @SuppressWarnings("resource") - private static SubjectKeyIdentifier createSubjectKeyId(PublicKey publicKey) - throws IOException { - ASN1InputStream asnObj = new ASN1InputStream(publicKey.getEncoded()); - SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(asnObj.readObject()); - SubjectKeyIdentifier keyId = SubjectKeyIdentifier.getInstance(info.getEncoded()); - return keyId; - } - - @SuppressWarnings("resource") - private static AuthorityKeyIdentifier createAuthorityKeyId(PublicKey publicKey) - throws IOException { - ASN1InputStream asnObj = new ASN1InputStream(publicKey.getEncoded()); - SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(asnObj.readObject()); - AuthorityKeyIdentifier keyId = AuthorityKeyIdentifier.getInstance(info); - return keyId; - } - static X509Certificate generateCertificate(PublicKey subjectPublicKey, String subjectDn, Date notBefore, Date notAfter, X509Certificate issuerCertificate, PrivateKey issuerPrivateKey, @@ -140,9 +124,15 @@ public class PkiTestUtils { } else { issuerName = new X500Name(subjectDn); } + + RSAPublicKey rsaPubKey = (RSAPublicKey)subjectPublicKey; + RSAKeyParameters rsaSpec = new RSAKeyParameters(false, rsaPubKey.getModulus(), rsaPubKey.getPublicExponent()); - SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo( - ASN1Sequence.getInstance(subjectPublicKey.getEncoded())); + SubjectPublicKeyInfo subjectPublicKeyInfo = + SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(rsaSpec); + + DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder() + .setProvider("BC").build().get(CertificateID.HASH_SHA1); X509v3CertificateBuilder certificateGenerator = new X509v3CertificateBuilder( issuerName @@ -153,8 +143,14 @@ public class PkiTestUtils { , subjectPublicKeyInfo ); - certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyId(subjectPublicKey)); - certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, createAuthorityKeyId(subjectPublicKey)); + X509ExtensionUtils exUtils = new X509ExtensionUtils(digestCalc); + SubjectKeyIdentifier subKeyId = exUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo); + AuthorityKeyIdentifier autKeyId = (issuerCertificate != null) + ? exUtils.createAuthorityKeyIdentifier(new X509CertificateHolder(issuerCertificate.getEncoded())) + : exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo); + + certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId); + certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId); if (caFlag) { BasicConstraints bc; diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java index 34def89b8b..fe5e4d30c1 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java @@ -70,10 +70,10 @@ import org.apache.poi.poifs.crypt.dsig.services.TimeStampService; import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator; import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService; import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; +import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.IOUtils; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; -import org.apache.poi.util.SAXHelper; import org.apache.xmlbeans.XmlObject; import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.cert.ocsp.OCSPResp; @@ -336,7 +336,7 @@ public class TestSignatureInfo { signatureService.initFacets(cal.getTime()); initKeyPair(alias, signerDn); - Document document = SAXHelper.getDocumentBuilder().newDocument(); + Document document = DocumentHelper.createDocument(); // operate List x509Chain = Collections.singletonList(x509); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFSlideShow.java b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFSlideShow.java index f82ed00ce0..b34a0d1c4e 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFSlideShow.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFSlideShow.java @@ -17,6 +17,7 @@ package org.apache.poi.xslf; import junit.framework.TestCase; + import org.apache.poi.POIDataSamples; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; @@ -61,22 +62,19 @@ public class TestXSLFSlideShow extends TestCase { ); } + @SuppressWarnings("deprecation") public void testSlideBasics() throws Exception { XSLFSlideShow xml = new XSLFSlideShow(pack); // Should have 1 master assertEquals(1, xml.getSlideMasterReferences().sizeOfSldMasterIdArray()); - assertEquals(1, xml.getSlideMasterReferences().getSldMasterIdList().size()); - + // Should have three sheets assertEquals(2, xml.getSlideReferences().sizeOfSldIdArray()); - assertEquals(2, xml.getSlideReferences().getSldIdList().size()); - + // Check they're as expected - CTSlideIdListEntry[] slides = new CTSlideIdListEntry[ - xml.getSlideReferences().getSldIdList().size()]; - xml.getSlideReferences().getSldIdList().toArray(slides); - + CTSlideIdListEntry[] slides = xml.getSlideReferences().getSldIdArray(); + assertEquals(256, slides[0].getId()); assertEquals(257, slides[1].getId()); assertEquals("rId2", slides[0].getId2()); @@ -91,9 +89,7 @@ public class TestXSLFSlideShow extends TestCase { assertNotNull(xml.getNotes(slides[1])); // And again for the master - CTSlideMasterIdListEntry[] masters = new CTSlideMasterIdListEntry[ - xml.getSlideMasterReferences().getSldMasterIdList().size()]; - xml.getSlideMasterReferences().getSldMasterIdList().toArray(masters); + CTSlideMasterIdListEntry[] masters = xml.getSlideMasterReferences().getSldMasterIdArray(); assertEquals(2147483648l, masters[0].getId()); assertEquals("rId1", masters[0].getId2()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java index 0fc4b20aaa..604f68fffb 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java @@ -17,6 +17,7 @@ package org.apache.poi.xslf.usermodel; import junit.framework.TestCase; + import org.apache.poi.POIDataSamples; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; @@ -58,6 +59,7 @@ public class TestXMLSlideShow extends TestCase { assertTrue(xml.getSlideMasters().length > 0); } + @SuppressWarnings("deprecation") public void testSlideBasics() throws Exception { XMLSlideShow xml = new XMLSlideShow(pack); @@ -68,9 +70,7 @@ public class TestXMLSlideShow extends TestCase { assertEquals(2, xml.getSlides().length); // Check they're as expected - CTSlideIdListEntry[] slides = new CTSlideIdListEntry[ - xml.getCTPresentation().getSldIdLst().getSldIdList().size()]; - xml.getCTPresentation().getSldIdLst().getSldIdList().toArray(slides); + CTSlideIdListEntry[] slides = xml.getCTPresentation().getSldIdLst().getSldIdArray(); assertEquals(256, slides[0].getId()); assertEquals(257, slides[1].getId()); @@ -86,9 +86,7 @@ public class TestXMLSlideShow extends TestCase { assertNotNull(xml.getSlides()[1].getNotes()); // Next up look for the slide master - CTSlideMasterIdListEntry[] masters = new CTSlideMasterIdListEntry[ - xml.getCTPresentation().getSldMasterIdLst().getSldMasterIdList().size()]; - xml.getCTPresentation().getSldMasterIdLst().getSldMasterIdList().toArray(masters); + CTSlideMasterIdListEntry[] masters = xml.getCTPresentation().getSldMasterIdLst().getSldMasterIdArray(); assertEquals(2147483648l, masters[0].getId()); assertEquals("rId1", masters[0].getId2()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java index f0d57241db..838db8137b 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java @@ -16,12 +16,19 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; +import java.awt.Color; + import junit.framework.TestCase; + import org.apache.poi.util.Units; import org.apache.poi.xslf.XSLFTestDataSamples; -import org.openxmlformats.schemas.drawingml.x2006.main.*; - -import java.awt.Color; +import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem; +import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleList; +import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix; +import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; +import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; /** * @author Yegor Kozlov @@ -243,13 +250,14 @@ public class TestXSLFSimpleShape extends TestCase { } + @SuppressWarnings({ "deprecation", "unused" }) public void testShadowEffects(){ XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); CTStyleMatrix styleMatrix = slide.getTheme().getXmlObject().getThemeElements().getFmtScheme(); CTEffectStyleList lst = styleMatrix.getEffectStyleLst(); assertNotNull(lst); - for(CTEffectStyleItem ef : lst.getEffectStyleList()){ + for(CTEffectStyleItem ef : lst.getEffectStyleArray()){ CTOuterShadowEffect obj = ef.getEffectLst().getOuterShdw(); } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java b/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java index 156c0dec49..f90804fa4c 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java @@ -16,12 +16,11 @@ ==================================================================== */ package org.apache.poi.xssf; -import org.apache.poi.xssf.usermodel.XSSFSheet; +import junit.framework.TestCase; +import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import junit.framework.TestCase; - public class TestSheetProtection extends TestCase { private XSSFSheet sheet; @@ -75,6 +74,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isAutoFilterLocked()); sheet.enableLocking(); assertTrue(sheet.isAutoFilterLocked()); + sheet.lockAutoFilter(false); + assertFalse(sheet.isAutoFilterLocked()); } public void testWriteDeleteColumns() throws Exception { @@ -83,6 +84,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isDeleteColumnsLocked()); sheet.enableLocking(); assertTrue(sheet.isDeleteColumnsLocked()); + sheet.lockDeleteColumns(false); + assertFalse(sheet.isDeleteColumnsLocked()); } public void testWriteDeleteRows() throws Exception { @@ -91,6 +94,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isDeleteRowsLocked()); sheet.enableLocking(); assertTrue(sheet.isDeleteRowsLocked()); + sheet.lockDeleteRows(false); + assertFalse(sheet.isDeleteRowsLocked()); } public void testWriteFormatCells() throws Exception { @@ -99,6 +104,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isFormatCellsLocked()); sheet.enableLocking(); assertTrue(sheet.isFormatCellsLocked()); + sheet.lockFormatCells(false); + assertFalse(sheet.isFormatCellsLocked()); } public void testWriteFormatColumns() throws Exception { @@ -107,6 +114,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isFormatColumnsLocked()); sheet.enableLocking(); assertTrue(sheet.isFormatColumnsLocked()); + sheet.lockFormatColumns(false); + assertFalse(sheet.isFormatColumnsLocked()); } public void testWriteFormatRows() throws Exception { @@ -115,6 +124,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isFormatRowsLocked()); sheet.enableLocking(); assertTrue(sheet.isFormatRowsLocked()); + sheet.lockFormatRows(false); + assertFalse(sheet.isFormatRowsLocked()); } public void testWriteInsertColumns() throws Exception { @@ -123,6 +134,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isInsertColumnsLocked()); sheet.enableLocking(); assertTrue(sheet.isInsertColumnsLocked()); + sheet.lockInsertColumns(false); + assertFalse(sheet.isInsertColumnsLocked()); } public void testWriteInsertHyperlinks() throws Exception { @@ -131,6 +144,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isInsertHyperlinksLocked()); sheet.enableLocking(); assertTrue(sheet.isInsertHyperlinksLocked()); + sheet.lockInsertHyperlinks(false); + assertFalse(sheet.isInsertHyperlinksLocked()); } public void testWriteInsertRows() throws Exception { @@ -139,6 +154,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isInsertRowsLocked()); sheet.enableLocking(); assertTrue(sheet.isInsertRowsLocked()); + sheet.lockInsertRows(false); + assertFalse(sheet.isInsertRowsLocked()); } public void testWritePivotTables() throws Exception { @@ -147,6 +164,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isPivotTablesLocked()); sheet.enableLocking(); assertTrue(sheet.isPivotTablesLocked()); + sheet.lockPivotTables(false); + assertFalse(sheet.isPivotTablesLocked()); } public void testWriteSort() throws Exception { @@ -155,6 +174,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isSortLocked()); sheet.enableLocking(); assertTrue(sheet.isSortLocked()); + sheet.lockSort(false); + assertFalse(sheet.isSortLocked()); } public void testWriteObjects() throws Exception { @@ -163,6 +184,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isObjectsLocked()); sheet.enableLocking(); assertTrue(sheet.isObjectsLocked()); + sheet.lockObjects(false); + assertFalse(sheet.isObjectsLocked()); } public void testWriteScenarios() throws Exception { @@ -171,6 +194,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isScenariosLocked()); sheet.enableLocking(); assertTrue(sheet.isScenariosLocked()); + sheet.lockScenarios(false); + assertFalse(sheet.isScenariosLocked()); } public void testWriteSelectLockedCells() throws Exception { @@ -179,6 +204,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isSelectLockedCellsLocked()); sheet.enableLocking(); assertTrue(sheet.isSelectLockedCellsLocked()); + sheet.lockSelectLockedCells(false); + assertFalse(sheet.isSelectLockedCellsLocked()); } public void testWriteSelectUnlockedCells() throws Exception { @@ -187,6 +214,8 @@ public class TestSheetProtection extends TestCase { assertFalse(sheet.isSelectUnlockedCellsLocked()); sheet.enableLocking(); assertTrue(sheet.isSelectUnlockedCellsLocked()); + sheet.lockSelectUnlockedCells(false); + assertFalse(sheet.isSelectUnlockedCellsLocked()); } public void testWriteSelectEnableLocking() throws Exception { diff --git a/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java b/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java index 642fe30748..969061932b 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java @@ -16,42 +16,94 @@ ==================================================================== */ package org.apache.poi.xssf; -import java.io.File; - -import java.io.FileInputStream; -import java.io.FileOutputStream; - -import junit.framework.TestCase; - -import org.apache.poi.util.TempFile; +import static org.apache.poi.xssf.XSSFTestDataSamples.openSampleWorkbook; +import static org.apache.poi.xssf.XSSFTestDataSamples.writeOutAndReadBack; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.apache.poi.poifs.crypt.CryptoFunctions; +import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.xssf.usermodel.XSSFWorkbook; - -public class TestWorkbookProtection extends TestCase { - - public void testShouldReadWorkbookProtection() throws Exception { - XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx"); +import org.junit.Test; + +public class TestWorkbookProtection { + + @Test + public void workbookAndRevisionPassword() throws Exception { + XSSFWorkbook workbook; + String password = "test"; + + // validate password with an actual office file (Excel 2010) + workbook = openSampleWorkbook("workbookProtection-workbook_password_user_range-2010.xlsx"); + assertTrue(workbook.validateWorkbookPassword(password)); + + // validate with another office file (Excel 2013) + workbook = openSampleWorkbook("workbookProtection-workbook_password-2013.xlsx"); + assertTrue(workbook.validateWorkbookPassword(password)); + + + workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx"); + + // setting a null password shouldn't introduce the protection element + workbook.setWorkbookPassword(null, null); + assertNull(workbook.getCTWorkbook().getWorkbookProtection()); + + // compare the hashes + workbook.setWorkbookPassword(password, null); + int hashVal = CryptoFunctions.createXorVerifier1(password); + int actualVal = Integer.parseInt(workbook.getCTWorkbook().getWorkbookProtection().xgetWorkbookPassword().getStringValue(),16); + assertEquals(hashVal, actualVal); + assertTrue(workbook.validateWorkbookPassword(password)); + + // removing the password again + workbook.setWorkbookPassword(null, null); + assertFalse(workbook.getCTWorkbook().getWorkbookProtection().isSetWorkbookPassword()); + + // removing the whole protection structure + workbook.unLock(); + assertNull(workbook.getCTWorkbook().getWorkbookProtection()); + + // setting a null password shouldn't introduce the protection element + workbook.setRevisionsPassword(null, null); + assertNull(workbook.getCTWorkbook().getWorkbookProtection()); + + // compare the hashes + password = "T\u0400ST\u0100passwordWhichIsLongerThan15Chars"; + workbook.setRevisionsPassword(password, null); + hashVal = CryptoFunctions.createXorVerifier1(password); + actualVal = Integer.parseInt(workbook.getCTWorkbook().getWorkbookProtection().xgetRevisionsPassword().getStringValue(),16); + assertEquals(hashVal, actualVal); + assertTrue(workbook.validateRevisionsPassword(password)); + } + + @Test + public void shouldReadWorkbookProtection() throws Exception { + XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx"); assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isRevisionLocked()); - workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx"); + workbook = openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx"); assertTrue(workbook.isStructureLocked()); assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isRevisionLocked()); - workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx"); + workbook = openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx"); assertTrue(workbook.isWindowsLocked()); assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isRevisionLocked()); - workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx"); + workbook = openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx"); assertTrue(workbook.isRevisionLocked()); assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isStructureLocked()); } - public void testShouldWriteStructureLock() throws Exception { - XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx"); + @Test + public void shouldWriteStructureLock() throws Exception { + XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx"); assertFalse(workbook.isStructureLocked()); workbook.lockStructure(); @@ -63,8 +115,9 @@ public class TestWorkbookProtection extends TestCase { assertFalse(workbook.isStructureLocked()); } - public void testShouldWriteWindowsLock() throws Exception { - XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx"); + @Test + public void shouldWriteWindowsLock() throws Exception { + XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx"); assertFalse(workbook.isWindowsLocked()); workbook.lockWindows(); @@ -76,8 +129,9 @@ public class TestWorkbookProtection extends TestCase { assertFalse(workbook.isWindowsLocked()); } - public void testShouldWriteRevisionLock() throws Exception { - XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx"); + @Test + public void shouldWriteRevisionLock() throws Exception { + XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx"); assertFalse(workbook.isRevisionLocked()); workbook.lockRevision(); @@ -89,22 +143,32 @@ public class TestWorkbookProtection extends TestCase { assertFalse(workbook.isRevisionLocked()); } + @SuppressWarnings("resource") + @Test + public void testHashPassword() throws Exception { + XSSFWorkbook wb = new XSSFWorkbook(); + wb.lockRevision(); + wb.setRevisionsPassword("test", HashAlgorithm.sha1); + + wb = writeOutAndReadBack(wb); + + assertTrue(wb.isRevisionLocked()); + assertTrue(wb.validateRevisionsPassword("test")); + } + + @SuppressWarnings("resource") + @Test public void testIntegration() throws Exception { XSSFWorkbook wb = new XSSFWorkbook(); wb.createSheet("Testing purpose sheet"); assertFalse(wb.isRevisionLocked()); wb.lockRevision(); + wb.setRevisionsPassword("test", null); - File tempFile = TempFile.createTempFile("workbookProtection", ".xlsx"); - FileOutputStream out = new FileOutputStream(tempFile); - wb.write(out); - out.close(); - - FileInputStream inputStream = new FileInputStream(tempFile); - XSSFWorkbook workbook = new XSSFWorkbook(inputStream); - inputStream.close(); - - assertTrue(workbook.isRevisionLocked()); + wb = writeOutAndReadBack(wb); + + assertTrue(wb.isRevisionLocked()); + assertTrue(wb.validateRevisionsPassword("test")); } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java index 9621b91eb4..d0e118ae20 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java @@ -49,7 +49,8 @@ import org.xml.sax.SAXException; * @author Roberto Manicardi */ public final class TestXSSFExportToXML extends TestCase { - public void testExportToXML() throws Exception { + + public void testExportToXML() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings.xlsx"); @@ -580,4 +581,37 @@ public final class TestXSSFExportToXML extends TestCase { } assertTrue(found); } + + public void testRefElementsInXmlSchema_Bugzilla_56730() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56730.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + assertEquals("2014-12-31", xmlData.split("")[1].split("")[0].trim()); + assertEquals("12.5", xmlData.split("")[1].split("")[0].trim()); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java index 80e5f52510..0932177e00 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java @@ -32,7 +32,7 @@ public final class TestCalculationChain extends TestCase { CalculationChain chain = wb.getCalculationChain(); //the bean holding the reference to the formula to be deleted CTCalcCell c = chain.getCTCalcChain().getCArray(0); - int cnt = chain.getCTCalcChain().getCList().size(); + int cnt = chain.getCTCalcChain().sizeOfCArray(); assertEquals(10, c.getI()); assertEquals("E1", c.getR()); @@ -44,7 +44,7 @@ public final class TestCalculationChain extends TestCase { //the count of items is less by one c = chain.getCTCalcChain().getCArray(0); - int cnt2 = chain.getCTCalcChain().getCList().size(); + int cnt2 = chain.getCTCalcChain().sizeOfCArray(); assertEquals(cnt - 1, cnt2); //the first item in the calculation chain is the former second one assertEquals(10, c.getI()); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestMapInfo.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestMapInfo.java index 7a4e98320f..33e91e8d3f 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/model/TestMapInfo.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/model/TestMapInfo.java @@ -50,7 +50,7 @@ public final class TestMapInfo extends TestCase { assertNotNull(ctMapInfo); - assertEquals(1, ctMapInfo.getSchemaList().size()); + assertEquals(1, ctMapInfo.sizeOfSchemaArray()); for (XSSFMap map : mapInfo.getAllXSSFMaps()) { Node xmlSchema = map.getSchema(); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java new file mode 100644 index 0000000000..40ab5b46e5 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/model/TestThemesTable.java @@ -0,0 +1,78 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.xssf.model; + +import static org.junit.Assert.assertEquals; + +import java.io.FileOutputStream; + +import org.apache.commons.codec.binary.Hex; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.XSSFTestDataSamples; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Test; + +public class TestThemesTable { + private String testFile = "Themes.xlsx"; + + @Test + public void testThemesTableColors() throws Exception { + XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook(testFile); + String rgbExpected[] = { + "ffffff", // Lt1 + "000000", // Dk1 + "eeece1", // Lt2 + "1f497d", // DK2 + "4f81bd", // Accent1 + "c0504d", // Accent2 + "9bbb59", // Accent3 + "8064a2", // Accent4 + "4bacc6", // Accent5 + "f79646", // Accent6 + "0000ff", // Hlink + "800080" // FolHlink + }; + boolean createFile = false; + int i=0; + for (Row row : workbook.getSheetAt(0)) { + XSSFFont font = ((XSSFRow)row).getCell(0).getCellStyle().getFont(); + XSSFColor color = font.getXSSFColor(); + assertEquals("Failed color theme "+i, rgbExpected[i], Hex.encodeHexString(color.getRgb())); + long themeIdx = font.getCTFont().getColorArray(0).getTheme(); + assertEquals("Failed color theme "+i, i, themeIdx); + if (createFile) { + XSSFCellStyle cs = (XSSFCellStyle)row.getSheet().getWorkbook().createCellStyle(); + cs.setFillForegroundColor(color); + cs.setFillPattern(CellStyle.SOLID_FOREGROUND); + row.createCell(1).setCellStyle(cs); + } + i++; + } + + if (createFile) { + FileOutputStream fos = new FileOutputStream("foobaa.xlsx"); + workbook.write(fos); + fos.close(); + } + } +} \ No newline at end of file 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 a08dffd2d1..79bbc4ea6d 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -964,9 +964,9 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { assertEquals(text, cell.getStringCellValue()); assertEquals(4, cell.getRichStringCellValue().numFormattingRuns()); - assertEquals("Use", cell.getRichStringCellValue().getCTRst().getRList().get(0).getT()); + assertEquals("Use", cell.getRichStringCellValue().getCTRst().getRArray(0).getT()); - String r3 = cell.getRichStringCellValue().getCTRst().getRList().get(2).getT(); + String r3 = cell.getRichStringCellValue().getCTRst().getRArray(2).getT(); assertEquals("line.\n", r3.substring(r3.length()-6)); // Save and re-check diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java index f99d007090..92fc298ab5 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColGrouping.java @@ -45,6 +45,7 @@ public class TestXSSFColGrouping extends TestCase { * Tests that POI doesn't produce "col" elements without "width" attribute. * POI-52186 */ + @SuppressWarnings("deprecation") public void testNoColsWithoutWidthWhenGrouping() { XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = wb.createSheet("test"); @@ -60,7 +61,7 @@ public class TestXSSFColGrouping extends TestCase { CTCols cols = sheet.getCTWorksheet().getColsArray(0); logger.log(POILogger.DEBUG, "test52186/cols:" + cols); - for (CTCol col : cols.getColList()) { + for (CTCol col : cols.getColArray()) { assertTrue("Col width attribute is unset: " + col.toString(), col.isSetWidth()); } } @@ -69,6 +70,7 @@ public class TestXSSFColGrouping extends TestCase { * Tests that POI doesn't produce "col" elements without "width" attribute. * POI-52186 */ + @SuppressWarnings("deprecation") public void testNoColsWithoutWidthWhenGroupingAndCollapsing() { XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = wb.createSheet("test"); @@ -90,7 +92,7 @@ public class TestXSSFColGrouping extends TestCase { assertEquals("Unexpected width of column "+ i, 5000, sheet.getColumnWidth(i)); } cols = sheet.getCTWorksheet().getColsArray(0); - for (CTCol col : cols.getColList()) { + for (CTCol col : cols.getColArray()) { assertTrue("Col width attribute is unset: " + col.toString(), col.isSetWidth()); } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java index b2aa11447b..6f31cc49f4 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFColor.java @@ -24,49 +24,49 @@ import org.apache.poi.xssf.XSSFTestDataSamples; public final class TestXSSFColor extends TestCase { public void testIndexedColour() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("48779.xlsx"); - + // Check the CTColor is as expected XSSFColor indexed = wb.getCellStyleAt((short)1).getFillBackgroundXSSFColor(); assertEquals(true, indexed.getCTColor().isSetIndexed()); assertEquals(64, indexed.getCTColor().getIndexed()); assertEquals(false, indexed.getCTColor().isSetRgb()); assertEquals(null, indexed.getCTColor().getRgb()); - + // Now check the XSSFColor // Note - 64 is a special "auto" one with no rgb equiv assertEquals(64, indexed.getIndexed()); assertEquals(null, indexed.getRgb()); assertEquals(null, indexed.getRgbWithTint()); assertEquals(null, indexed.getARGBHex()); - + // Now move to one with indexed rgb values indexed.setIndexed(59); assertEquals(true, indexed.getCTColor().isSetIndexed()); assertEquals(59, indexed.getCTColor().getIndexed()); assertEquals(false, indexed.getCTColor().isSetRgb()); assertEquals(null, indexed.getCTColor().getRgb()); - + assertEquals(59, indexed.getIndexed()); assertEquals("FF333300", indexed.getARGBHex()); - + assertEquals(3, indexed.getRgb().length); assertEquals(0x33, indexed.getRgb()[0]); assertEquals(0x33, indexed.getRgb()[1]); assertEquals(0x00, indexed.getRgb()[2]); - + assertEquals(4, indexed.getARgb().length); assertEquals(-1, indexed.getARgb()[0]); assertEquals(0x33, indexed.getARgb()[1]); assertEquals(0x33, indexed.getARgb()[2]); assertEquals(0x00, indexed.getARgb()[3]); - + // You don't get tinted indexed colours, sorry... assertEquals(null, indexed.getRgbWithTint()); } - + public void testRGBColour() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("50299.xlsx"); - + // Check the CTColor is as expected XSSFColor rgb3 = wb.getCellStyleAt((short)25).getFillForegroundXSSFColor(); assertEquals(false, rgb3.getCTColor().isSetIndexed()); @@ -75,37 +75,39 @@ public final class TestXSSFColor extends TestCase { assertEquals(-0.34999, rgb3.getCTColor().getTint(), 0.00001); assertEquals(true, rgb3.getCTColor().isSetRgb()); assertEquals(3, rgb3.getCTColor().getRgb().length); - + // Now check the XSSFColor assertEquals(0, rgb3.getIndexed()); assertEquals(-0.34999, rgb3.getTint(), 0.00001); - + assertEquals("FFFFFFFF", rgb3.getARGBHex()); assertEquals(3, rgb3.getRgb().length); assertEquals(-1, rgb3.getRgb()[0]); assertEquals(-1, rgb3.getRgb()[1]); assertEquals(-1, rgb3.getRgb()[2]); - + assertEquals(4, rgb3.getARgb().length); assertEquals(-1, rgb3.getARgb()[0]); assertEquals(-1, rgb3.getARgb()[1]); assertEquals(-1, rgb3.getARgb()[2]); assertEquals(-1, rgb3.getARgb()[3]); - + // Tint doesn't have the alpha + // tint = -0.34999 + // 255 * (1 + tint) = 165 truncated + // or (byte) -91 (which is 165 - 256) assertEquals(3, rgb3.getRgbWithTint().length); - assertEquals(0, rgb3.getRgbWithTint()[0]); - assertEquals(0, rgb3.getRgbWithTint()[1]); - assertEquals(0, rgb3.getRgbWithTint()[2]); - - // Set the colour to black, will get translated internally - // (Excel stores 3 colour white and black wrong!) - rgb3.setRgb(new byte[] {-1,-1,-1}); - assertEquals("FFFFFFFF", rgb3.getARGBHex()); + assertEquals(-91, rgb3.getRgbWithTint()[0]); + assertEquals(-91, rgb3.getRgbWithTint()[1]); + assertEquals(-91, rgb3.getRgbWithTint()[2]); + + // Set the color to black (no theme). + rgb3.setRgb(new byte[] {0, 0, 0}); + assertEquals("FF000000", rgb3.getARGBHex()); assertEquals(0, rgb3.getCTColor().getRgb()[0]); assertEquals(0, rgb3.getCTColor().getRgb()[1]); assertEquals(0, rgb3.getCTColor().getRgb()[2]); - + // Set another, is fine rgb3.setRgb(new byte[] {16,17,18}); assertEquals("FF101112", rgb3.getARGBHex()); @@ -113,45 +115,45 @@ public final class TestXSSFColor extends TestCase { assertEquals(0x11, rgb3.getCTColor().getRgb()[1]); assertEquals(0x12, rgb3.getCTColor().getRgb()[2]); } - + public void testARGBColour() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("48779.xlsx"); - + // Check the CTColor is as expected XSSFColor rgb4 = wb.getCellStyleAt((short)1).getFillForegroundXSSFColor(); assertEquals(false, rgb4.getCTColor().isSetIndexed()); assertEquals(0, rgb4.getCTColor().getIndexed()); assertEquals(true, rgb4.getCTColor().isSetRgb()); assertEquals(4, rgb4.getCTColor().getRgb().length); - + // Now check the XSSFColor assertEquals(0, rgb4.getIndexed()); assertEquals(0.0, rgb4.getTint()); - + assertEquals("FFFF0000", rgb4.getARGBHex()); assertEquals(3, rgb4.getRgb().length); assertEquals(-1, rgb4.getRgb()[0]); assertEquals(0, rgb4.getRgb()[1]); assertEquals(0, rgb4.getRgb()[2]); - + assertEquals(4, rgb4.getARgb().length); assertEquals(-1, rgb4.getARgb()[0]); assertEquals(-1, rgb4.getARgb()[1]); assertEquals(0, rgb4.getARgb()[2]); assertEquals(0, rgb4.getARgb()[3]); - + // Tint doesn't have the alpha assertEquals(3, rgb4.getRgbWithTint().length); assertEquals(-1, rgb4.getRgbWithTint()[0]); assertEquals(0, rgb4.getRgbWithTint()[1]); assertEquals(0, rgb4.getRgbWithTint()[2]); - + // Turn on tinting, and check it behaves // TODO These values are suspected to be wrong... rgb4.setTint(0.4); assertEquals(0.4, rgb4.getTint()); - + assertEquals(3, rgb4.getRgbWithTint().length); assertEquals(-1, rgb4.getRgbWithTint()[0]); assertEquals(102, rgb4.getRgbWithTint()[1]); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFont.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFont.java index 5d93fa1215..3bbe6f2788 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFont.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFont.java @@ -65,7 +65,7 @@ public final class TestXSSFFont extends BaseTestFont{ xssfFont.setBold(true); - assertEquals(ctFont.getBList().size(),1); + assertEquals(ctFont.sizeOfBArray(),1); assertEquals(true, ctFont.getBArray(0).getVal()); } @@ -135,7 +135,7 @@ public final class TestXSSFFont extends BaseTestFont{ assertEquals(false, xssfFont.getItalic()); xssfFont.setItalic(true); - assertEquals(ctFont.getIList().size(),1); + assertEquals(ctFont.sizeOfIArray(),1); assertEquals(true, ctFont.getIArray(0).getVal()); assertEquals(true,ctFont.getIArray(0).getVal()); } @@ -150,7 +150,7 @@ public final class TestXSSFFont extends BaseTestFont{ assertEquals(false, xssfFont.getStrikeout()); xssfFont.setStrikeout(true); - assertEquals(ctFont.getStrikeList().size(),1); + assertEquals(ctFont.sizeOfStrikeArray(),1); assertEquals(true, ctFont.getStrikeArray(0).getVal()); assertEquals(true,ctFont.getStrikeArray(0).getVal()); } @@ -191,11 +191,11 @@ public final class TestXSSFFont extends BaseTestFont{ assertEquals(Font.U_SINGLE, xssfFont.getUnderline()); xssfFont.setUnderline(Font.U_DOUBLE); - assertEquals(ctFont.getUList().size(),1); + assertEquals(ctFont.sizeOfUArray(),1); assertEquals(STUnderlineValues.DOUBLE,ctFont.getUArray(0).getVal()); xssfFont.setUnderline(FontUnderline.DOUBLE_ACCOUNTING); - assertEquals(ctFont.getUList().size(),1); + assertEquals(ctFont.sizeOfUArray(),1); assertEquals(STUnderlineValues.DOUBLE_ACCOUNTING,ctFont.getUArray(0).getVal()); } 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 e5cf432fbe..a813bce816 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java @@ -17,6 +17,7 @@ package org.apache.poi.xssf.usermodel; +import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -288,48 +289,212 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator { } } - public void testMultisheetFormulaEval() { + public void testMultisheetFormulaEval() throws IOException { XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet1 = wb.createSheet("Sheet1"); - XSSFSheet sheet2 = wb.createSheet("Sheet2"); - XSSFSheet sheet3 = wb.createSheet("Sheet3"); - - // sheet1 A1 - XSSFCell cell = sheet1.createRow(0).createCell(0); - cell.setCellType(Cell.CELL_TYPE_NUMERIC); - cell.setCellValue(1.0); - - // sheet2 A1 - cell = sheet2.createRow(0).createCell(0); - cell.setCellType(Cell.CELL_TYPE_NUMERIC); - cell.setCellValue(1.0); - - // sheet2 B1 - cell = sheet2.getRow(0).createCell(1); - cell.setCellType(Cell.CELL_TYPE_NUMERIC); - cell.setCellValue(1.0); - - // sheet3 A1 - cell = sheet3.createRow(0).createCell(0); - cell.setCellType(Cell.CELL_TYPE_NUMERIC); - cell.setCellValue(1.0); - - // sheet1 A2 formulae - cell = sheet1.createRow(1).createCell(0); - cell.setCellType(Cell.CELL_TYPE_FORMULA); - cell.setCellFormula("SUM(Sheet1:Sheet3!A1)"); - - // sheet1 A3 formulae - cell = sheet1.createRow(2).createCell(0); - cell.setCellType(Cell.CELL_TYPE_FORMULA); - cell.setCellFormula("SUM(Sheet1:Sheet3!A1:B1)"); - - wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); - - cell = sheet1.getRow(1).getCell(0); - assertEquals(3.0, cell.getNumericCellValue()); - - cell = sheet1.getRow(2).getCell(0); - assertEquals(4.0, cell.getNumericCellValue()); + try { + XSSFSheet sheet1 = wb.createSheet("Sheet1"); + XSSFSheet sheet2 = wb.createSheet("Sheet2"); + XSSFSheet sheet3 = wb.createSheet("Sheet3"); + + // sheet1 A1 + XSSFCell cell = sheet1.createRow(0).createCell(0); + cell.setCellType(Cell.CELL_TYPE_NUMERIC); + cell.setCellValue(1.0); + + // sheet2 A1 + cell = sheet2.createRow(0).createCell(0); + cell.setCellType(Cell.CELL_TYPE_NUMERIC); + cell.setCellValue(1.0); + + // sheet2 B1 + cell = sheet2.getRow(0).createCell(1); + cell.setCellType(Cell.CELL_TYPE_NUMERIC); + cell.setCellValue(1.0); + + // sheet3 A1 + cell = sheet3.createRow(0).createCell(0); + cell.setCellType(Cell.CELL_TYPE_NUMERIC); + cell.setCellValue(1.0); + + // sheet1 A2 formulae + cell = sheet1.createRow(1).createCell(0); + cell.setCellType(Cell.CELL_TYPE_FORMULA); + cell.setCellFormula("SUM(Sheet1:Sheet3!A1)"); + + // sheet1 A3 formulae + cell = sheet1.createRow(2).createCell(0); + cell.setCellType(Cell.CELL_TYPE_FORMULA); + cell.setCellFormula("SUM(Sheet1:Sheet3!A1:B1)"); + + wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); + + cell = sheet1.getRow(1).getCell(0); + assertEquals(3.0, cell.getNumericCellValue()); + + cell = sheet1.getRow(2).getCell(0); + assertEquals(4.0, cell.getNumericCellValue()); + } finally { + wb.close(); + } } + + public void testBug55843() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + cellA2.setCellFormula("IF(B1=0,\"\",((ROW()-ROW(A$1))*12))"); + CellValue evaluate = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluate); + assertEquals("12.0", evaluate.formatAsString()); + + cellA2.setCellFormula("IF(NOT(B1=0),((ROW()-ROW(A$1))*12),\"\")"); + CellValue evaluateN = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluateN); + + assertEquals(evaluate.toString(), evaluateN.toString()); + assertEquals("12.0", evaluateN.formatAsString()); + } finally { + wb.close(); + } + } + + public void testBug55843a() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + cellA2.setCellFormula("IF(B1=0,\"\",((ROW(A$1))))"); + CellValue evaluate = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluate); + assertEquals("1.0", evaluate.formatAsString()); + + cellA2.setCellFormula("IF(NOT(B1=0),((ROW(A$1))),\"\")"); + CellValue evaluateN = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluateN); + + assertEquals(evaluate.toString(), evaluateN.toString()); + assertEquals("1.0", evaluateN.formatAsString()); + } finally { + wb.close(); + } + } + + public void testBug55843b() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + + cellA2.setCellFormula("IF(B1=0,\"\",((ROW())))"); + CellValue evaluate = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluate); + assertEquals("2.0", evaluate.formatAsString()); + + cellA2.setCellFormula("IF(NOT(B1=0),((ROW())),\"\")"); + CellValue evaluateN = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluateN); + + assertEquals(evaluate.toString(), evaluateN.toString()); + assertEquals("2.0", evaluateN.formatAsString()); + } finally { + wb.close(); + } + } + + public void testBug55843c() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + + cellA2.setCellFormula("IF(NOT(B1=0),((ROW())))"); + CellValue evaluateN = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluateN); + assertEquals("2.0", evaluateN.formatAsString()); + } finally { + wb.close(); + } + } + + public void testBug55843d() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + + cellA2.setCellFormula("IF(NOT(B1=0),((ROW())),\"\")"); + CellValue evaluateN = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluateN); + assertEquals("2.0", evaluateN.formatAsString()); + } finally { + wb.close(); + } + } + + public void testBug55843e() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + + cellA2.setCellFormula("IF(B1=0,\"\",((ROW())))"); + CellValue evaluate = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluate); + assertEquals("2.0", evaluate.formatAsString()); + } finally { + wb.close(); + } + } + + + public void testBug55843f() throws IOException { + XSSFWorkbook wb = new XSSFWorkbook(); + try { + XSSFSheet sheet = wb.createSheet("test"); + XSSFRow row = sheet.createRow(0); + XSSFRow row2 = sheet.createRow(1); + XSSFCell cellA2 = row2.createCell(0, Cell.CELL_TYPE_FORMULA); + XSSFCell cellB1 = row.createCell(1, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(10); + XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + + cellA2.setCellFormula("IF(B1=0,\"\",IF(B1=10,3,4))"); + CellValue evaluate = formulaEvaluator.evaluate(cellA2); + System.out.println(evaluate); + assertEquals("3.0", evaluate.formatAsString()); + } finally { + wb.close(); + } + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRichTextString.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRichTextString.java index 40f8b065ad..5a45219ac3 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRichTextString.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRichTextString.java @@ -308,22 +308,22 @@ public final class TestXSSFRichTextString extends TestCase { str = new XSSFRichTextString("Incorrect\nLine-Breaking"); str.applyFont(0, 8, font); - t1 = str.getCTRst().getRList().get(0).xgetT(); - t2 = str.getCTRst().getRList().get(1).xgetT(); + t1 = str.getCTRst().getRArray(0).xgetT(); + t2 = str.getCTRst().getRArray(1).xgetT(); assertEquals("Incorrec", t1.xmlText()); assertEquals("t\nLine-Breaking", t2.xmlText()); str = new XSSFRichTextString("Incorrect\nLine-Breaking"); str.applyFont(0, 9, font); - t1 = str.getCTRst().getRList().get(0).xgetT(); - t2 = str.getCTRst().getRList().get(1).xgetT(); + t1 = str.getCTRst().getRArray(0).xgetT(); + t2 = str.getCTRst().getRArray(1).xgetT(); assertEquals("Incorrect", t1.xmlText()); assertEquals("\nLine-Breaking", t2.xmlText()); str = new XSSFRichTextString("Incorrect\n Line-Breaking"); str.applyFont(0, 9, font); - t1 = str.getCTRst().getRList().get(0).xgetT(); - t2 = str.getCTRst().getRList().get(1).xgetT(); + t1 = str.getCTRst().getRArray(0).xgetT(); + t2 = str.getCTRst().getRArray(1).xgetT(); assertEquals("Incorrect", t1.xmlText()); assertEquals("\n Line-Breaking", t2.xmlText()); @@ -333,15 +333,15 @@ public final class TestXSSFRichTextString extends TestCase { assertEquals("Tab\tseparated\n", t1.xmlText()); str.applyFont(0, 3, font); - t1 = str.getCTRst().getRList().get(0).xgetT(); - t2 = str.getCTRst().getRList().get(1).xgetT(); + t1 = str.getCTRst().getRArray(0).xgetT(); + t2 = str.getCTRst().getRArray(1).xgetT(); assertEquals("Tab", t1.xmlText()); assertEquals("\tseparated\n", t2.xmlText()); str = new XSSFRichTextString("Tab\tseparated\n"); str.applyFont(0, 4, font); - t1 = str.getCTRst().getRList().get(0).xgetT(); - t2 = str.getCTRst().getRList().get(1).xgetT(); + t1 = str.getCTRst().getRArray(0).xgetT(); + t2 = str.getCTRst().getRArray(1).xgetT(); // YK: don't know why, but XmlBeans converts leading tab characters to spaces //assertEquals("Tab\t", t1.xmlText()); assertEquals("separated\n", t2.xmlText()); @@ -349,9 +349,9 @@ public final class TestXSSFRichTextString extends TestCase { str = new XSSFRichTextString("\n\n\nNew Line\n\n"); str.applyFont(0, 3, font); str.applyFont(11, 13, font); - t1 = str.getCTRst().getRList().get(0).xgetT(); - t2 = str.getCTRst().getRList().get(1).xgetT(); - t3 = str.getCTRst().getRList().get(2).xgetT(); + t1 = str.getCTRst().getRArray(0).xgetT(); + t2 = str.getCTRst().getRArray(1).xgetT(); + t3 = str.getCTRst().getRArray(2).xgetT(); // YK: don't know why, but XmlBeans converts leading tab characters to spaces assertEquals("\n\n\n", t1.xmlText()); assertEquals("New Line", t2.xmlText()); 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 44342781a8..5c91032def 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java @@ -19,6 +19,8 @@ package org.apache.poi.xssf.usermodel; import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; +import static org.apache.poi.xssf.XSSFTestDataSamples.openSampleWorkbook; +import static org.apache.poi.xssf.XSSFTestDataSamples.writeOutAndReadBack; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; @@ -26,10 +28,14 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.PasswordRecord; +import org.apache.poi.poifs.crypt.CryptoFunctions; +import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.ss.usermodel.AutoFilter; import org.apache.poi.ss.usermodel.BaseTestSheet; import org.apache.poi.ss.usermodel.Cell; @@ -41,7 +47,6 @@ import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; -import org.apache.poi.util.HexDump; import org.apache.poi.xssf.SXSSFITestDataProvider; import org.apache.poi.xssf.XSSFITestDataProvider; import org.apache.poi.xssf.XSSFTestDataSamples; @@ -293,6 +298,7 @@ public final class TestXSSFSheet extends BaseTestSheet { CellRangeAddress region_1 = CellRangeAddress.valueOf("A1:B2"); CellRangeAddress region_2 = CellRangeAddress.valueOf("C3:D4"); CellRangeAddress region_3 = CellRangeAddress.valueOf("E5:F6"); + CellRangeAddress region_4 = CellRangeAddress.valueOf("G7:H8"); sheet.addMergedRegion(region_1); sheet.addMergedRegion(region_2); sheet.addMergedRegion(region_3); @@ -306,6 +312,17 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(0, sheet.getNumMergedRegions()); assertNull(" CTMergeCells should be deleted after removing the last merged " + "region on the sheet.", sheet.getCTWorksheet().getMergeCells()); + sheet.addMergedRegion(region_1); + sheet.addMergedRegion(region_2); + sheet.addMergedRegion(region_3); + sheet.addMergedRegion(region_4); + // test invalid indexes OOBE + Set rmIdx = new HashSet(Arrays.asList(5,6)); + sheet.removeMergedRegions(rmIdx); + rmIdx = new HashSet(Arrays.asList(1,3)); + sheet.removeMergedRegions(rmIdx); + assertEquals("A1:B2", ctWorksheet.getMergeCells().getMergeCellArray(0).getRef()); + assertEquals("E5:F6", ctWorksheet.getMergeCells().getMergeCellArray(1).getRef()); } @Test @@ -335,6 +352,7 @@ public final class TestXSSFSheet extends BaseTestSheet { @Test + @SuppressWarnings("deprecation") public void groupUngroupColumn() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); @@ -344,36 +362,36 @@ public final class TestXSSFSheet extends BaseTestSheet { sheet.groupColumn(10, 11); CTCols cols = sheet.getCTWorksheet().getColsArray(0); assertEquals(2, cols.sizeOfColArray()); - List colArray = cols.getColList(); + CTCol[] colArray = cols.getColArray(); assertNotNull(colArray); - assertEquals(2 + 1, colArray.get(0).getMin()); // 1 based - assertEquals(7 + 1, colArray.get(0).getMax()); // 1 based - assertEquals(1, colArray.get(0).getOutlineLevel()); + assertEquals(2 + 1, colArray[0].getMin()); // 1 based + assertEquals(7 + 1, colArray[0].getMax()); // 1 based + assertEquals(1, colArray[0].getOutlineLevel()); //two level sheet.groupColumn(1, 2); cols = sheet.getCTWorksheet().getColsArray(0); assertEquals(4, cols.sizeOfColArray()); - colArray = cols.getColList(); - assertEquals(2, colArray.get(1).getOutlineLevel()); + colArray = cols.getColArray(); + assertEquals(2, colArray[1].getOutlineLevel()); //three level sheet.groupColumn(6, 8); sheet.groupColumn(2, 3); cols = sheet.getCTWorksheet().getColsArray(0); assertEquals(7, cols.sizeOfColArray()); - colArray = cols.getColList(); - assertEquals(3, colArray.get(1).getOutlineLevel()); + colArray = cols.getColArray(); + assertEquals(3, colArray[1].getOutlineLevel()); assertEquals(3, sheet.getCTWorksheet().getSheetFormatPr().getOutlineLevelCol()); sheet.ungroupColumn(8, 10); - colArray = cols.getColList(); + colArray = cols.getColArray(); //assertEquals(3, colArray[1].getOutlineLevel()); sheet.ungroupColumn(4, 6); sheet.ungroupColumn(2, 2); - colArray = cols.getColList(); - assertEquals(4, colArray.size()); + colArray = cols.getColArray(); + assertEquals(4, colArray.length); assertEquals(2, sheet.getCTWorksheet().getSheetFormatPr().getOutlineLevelCol()); } @@ -758,9 +776,8 @@ public final class TestXSSFSheet extends BaseTestSheet { XSSFSheet xs = sheet; CTWorksheet cts = xs.getCTWorksheet(); - List cols_s = cts.getColsList(); - assertEquals(1, cols_s.size()); - CTCols cols = cols_s.get(0); + assertEquals(1, cts.sizeOfColsArray()); + CTCols cols = cts.getColsArray(0); assertEquals(1, cols.sizeOfColArray()); CTCol col = cols.getColArray(0); @@ -773,9 +790,8 @@ public final class TestXSSFSheet extends BaseTestSheet { // Now set another sheet.setColumnWidth(3, 33 * 256); - cols_s = cts.getColsList(); - assertEquals(1, cols_s.size()); - cols = cols_s.get(0); + assertEquals(1, cts.sizeOfColsArray()); + cols = cts.getColsArray(0); assertEquals(2, cols.sizeOfColArray()); col = cols.getColArray(0); @@ -960,6 +976,7 @@ public final class TestXSSFSheet extends BaseTestSheet { * but CTRows are kept in ascending order */ @Test + @SuppressWarnings("deprecation") public void createRow() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); @@ -983,27 +1000,27 @@ public final class TestXSSFSheet extends BaseTestSheet { row3.createCell(5); - List xrow = sheetData.getRowList(); - assertEquals(3, xrow.size()); + CTRow[] xrow = sheetData.getRowArray(); + assertEquals(3, xrow.length); //rows are sorted: {0, 1, 2} - assertEquals(4, xrow.get(0).sizeOfCArray()); - assertEquals(1, xrow.get(0).getR()); - assertTrue(xrow.get(0).equals(row3.getCTRow())); + assertEquals(4, xrow[0].sizeOfCArray()); + assertEquals(1, xrow[0].getR()); + assertTrue(xrow[0].equals(row3.getCTRow())); - assertEquals(3, xrow.get(1).sizeOfCArray()); - assertEquals(2, xrow.get(1).getR()); - assertTrue(xrow.get(1).equals(row2.getCTRow())); + assertEquals(3, xrow[1].sizeOfCArray()); + assertEquals(2, xrow[1].getR()); + assertTrue(xrow[1].equals(row2.getCTRow())); - assertEquals(2, xrow.get(2).sizeOfCArray()); - assertEquals(3, xrow.get(2).getR()); - assertTrue(xrow.get(2).equals(row1.getCTRow())); + assertEquals(2, xrow[2].sizeOfCArray()); + assertEquals(3, xrow[2].getR()); + assertTrue(xrow[2].equals(row1.getCTRow())); - List xcell = xrow.get(0).getCList(); - assertEquals("D1", xcell.get(0).getR()); - assertEquals("A1", xcell.get(1).getR()); - assertEquals("C1", xcell.get(2).getR()); - assertEquals("F1", xcell.get(3).getR()); + CTCell[] xcell = xrow[0].getCArray(); + assertEquals("D1", xcell[0].getR()); + assertEquals("A1", xcell[1].getR()); + assertEquals("C1", xcell[2].getR()); + assertEquals("F1", xcell[3].getR()); //re-creating a row does NOT add extra data to the parent row2 = sheet.createRow(1); @@ -1015,25 +1032,25 @@ public final class TestXSSFSheet extends BaseTestSheet { workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook); sheet = workbook.getSheetAt(0); wsh = sheet.getCTWorksheet(); - xrow = sheetData.getRowList(); - assertEquals(3, xrow.size()); + xrow = sheetData.getRowArray(); + assertEquals(3, xrow.length); //rows are sorted: {0, 1, 2} - assertEquals(4, xrow.get(0).sizeOfCArray()); - assertEquals(1, xrow.get(0).getR()); + assertEquals(4, xrow[0].sizeOfCArray()); + assertEquals(1, xrow[0].getR()); //cells are now sorted - xcell = xrow.get(0).getCList(); - assertEquals("A1", xcell.get(0).getR()); - assertEquals("C1", xcell.get(1).getR()); - assertEquals("D1", xcell.get(2).getR()); - assertEquals("F1", xcell.get(3).getR()); + xcell = xrow[0].getCArray(); + assertEquals("A1", xcell[0].getR()); + assertEquals("C1", xcell[1].getR()); + assertEquals("D1", xcell[2].getR()); + assertEquals("F1", xcell[3].getR()); - assertEquals(0, xrow.get(1).sizeOfCArray()); - assertEquals(2, xrow.get(1).getR()); + assertEquals(0, xrow[1].sizeOfCArray()); + assertEquals(2, xrow[1].getR()); - assertEquals(2, xrow.get(2).sizeOfCArray()); - assertEquals(3, xrow.get(2).getR()); + assertEquals(2, xrow[2].sizeOfCArray()); + assertEquals(3, xrow[2].getR()); } @@ -1068,13 +1085,27 @@ public final class TestXSSFSheet extends BaseTestSheet { assertTrue("sheet protection should be on", pr.isSetSheet()); assertTrue("object protection should be on", pr.isSetObjects()); assertTrue("scenario protection should be on", pr.isSetScenarios()); - String hash = String.valueOf(HexDump.shortToHex(PasswordRecord.hashPassword(password))).substring(2); - assertEquals("well known value for top secret hash should be "+ hash, hash, pr.xgetPassword().getStringValue()); + int hashVal = CryptoFunctions.createXorVerifier1(password); + int actualVal = Integer.parseInt(pr.xgetPassword().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()); } + @Test + public void protectSheet_lowlevel_2013() { + String password = "test"; + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet xs = wb.createSheet(); + xs.setSheetPassword(password, HashAlgorithm.sha384); + wb = writeOutAndReadBack(wb); + assertTrue(wb.getSheetAt(0).validateSheetPassword(password)); + + wb = openSampleWorkbook("workbookProtection-sheet_password-2013.xlsx"); + assertTrue(wb.getSheetAt(0).validateSheetPassword("pwd")); + } + @Test public void bug49966() { diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java index d7bfc2f769..d3729e0c92 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetShiftRows.java @@ -25,9 +25,11 @@ import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellUtil; import org.apache.poi.xssf.XSSFITestDataProvider; import org.apache.poi.xssf.XSSFTestDataSamples; +import org.junit.Test; /** * @author Yegor Kozlov @@ -187,4 +189,14 @@ public final class TestXSSFSheetShiftRows extends BaseTestSheetShiftRows { assertEquals("Amdocs", comment.getAuthor()); assertEquals("Amdocs:\ntest\n", comment.getString().getString()); } + + @Test + public void testBug55280() { + Workbook w = new XSSFWorkbook(); + Sheet s = w.createSheet(); + for (int row = 0; row < 5000; ++row) + s.addMergedRegion(new CellRangeAddress(row, row, 0, 3)); + + s.shiftRows(0, 4999, 1); // takes a long time... + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java index de7eff6be7..ccde542245 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java @@ -17,13 +17,8 @@ package org.apache.poi.xssf.usermodel; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.xssf.XSSFTestDataSamples; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.util.TempFile; -import org.junit.Test; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileInputStream; @@ -32,8 +27,13 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.util.TempFile; +import org.apache.poi.xssf.XSSFTestDataSamples; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.junit.Test; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; public final class TestXSSFTable { @@ -41,6 +41,7 @@ public final class TestXSSFTable { } @Test + @SuppressWarnings("deprecation") public void bug56274() throws IOException { // read sample file XSSFWorkbook inputWorkbook = XSSFTestDataSamples.openSampleWorkbook("56274.xlsx"); @@ -60,13 +61,13 @@ public final class TestXSSFTable { // re-read the saved file and make sure headers in the xml are in the original order inputWorkbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(new FileInputStream(outputFile)); CTTable ctTable = inputWorkbook.getSheetAt(0).getTables().get(0).getCTTable(); - List ctTableColumnList = ctTable.getTableColumns().getTableColumnList(); + CTTableColumn[] ctTableColumnArray = ctTable.getTableColumns().getTableColumnArray(); assertEquals("number of headers in xml table should match number of header cells in worksheet", - headers.size(), ctTableColumnList.size()); + headers.size(), ctTableColumnArray.length); for (int i = 0; i < headers.size(); i++) { assertEquals("header name in xml table should match number of header cells in worksheet", - headers.get(i), ctTableColumnList.get(i).getName()); + headers.get(i), ctTableColumnArray[i].getName()); } assertTrue(outputFile.delete()); } 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 f50fb5dfa5..fd41ac6721 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java @@ -704,7 +704,7 @@ public final class TestXSSFWorkbook extends BaseTestWorkbook { CTPivotCache pivotCache = wb.addPivotCache("0"); //Ensures that pivotCaches is initiated assertTrue(ctWb.isSetPivotCaches()); - assertSame(pivotCache, ctWb.getPivotCaches().getPivotCacheList().get(0)); + assertSame(pivotCache, ctWb.getPivotCaches().getPivotCacheArray(0)); assertEquals("0", pivotCache.getId()); } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java index 2ad4f5645d..b268410bfa 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/extensions/TestXSSFCellFill.java @@ -31,34 +31,34 @@ import junit.framework.TestCase; public class TestXSSFCellFill extends TestCase { - - public void testGetFillBackgroundColor() { - CTFill ctFill = CTFill.Factory.newInstance(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); - CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); - CTColor bgColor = ctPatternFill.addNewBgColor(); - assertNotNull(cellFill.getFillBackgroundColor()); - bgColor.setIndexed(2); - assertEquals(2, cellFill.getFillBackgroundColor().getIndexed()); - } - - public void testGetFillForegroundColor() { - CTFill ctFill = CTFill.Factory.newInstance(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); - CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); - CTColor fgColor = ctPatternFill.addNewFgColor(); - assertNotNull(cellFill.getFillForegroundColor()); - fgColor.setIndexed(8); - assertEquals(8, cellFill.getFillForegroundColor().getIndexed()); - } - - public void testGetSetPatternType() { - CTFill ctFill = CTFill.Factory.newInstance(); - XSSFCellFill cellFill = new XSSFCellFill(ctFill); - CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); - ctPatternFill.setPatternType(STPatternType.SOLID); - //assertEquals(FillPatternType.SOLID_FOREGROUND.ordinal(), cellFill.getPatternType().ordinal()); - } + + public void testGetFillBackgroundColor() { + CTFill ctFill = CTFill.Factory.newInstance(); + XSSFCellFill cellFill = new XSSFCellFill(ctFill); + CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); + CTColor bgColor = ctPatternFill.addNewBgColor(); + assertNotNull(cellFill.getFillBackgroundColor()); + bgColor.setIndexed(2); + assertEquals(2, cellFill.getFillBackgroundColor().getIndexed()); + } + + public void testGetFillForegroundColor() { + CTFill ctFill = CTFill.Factory.newInstance(); + XSSFCellFill cellFill = new XSSFCellFill(ctFill); + CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); + CTColor fgColor = ctPatternFill.addNewFgColor(); + assertNotNull(cellFill.getFillForegroundColor()); + fgColor.setIndexed(8); + assertEquals(8, cellFill.getFillForegroundColor().getIndexed()); + } + + public void testGetSetPatternType() { + CTFill ctFill = CTFill.Factory.newInstance(); + XSSFCellFill cellFill = new XSSFCellFill(ctFill); + CTPatternFill ctPatternFill = ctFill.addNewPatternFill(); + ctPatternFill.setPatternType(STPatternType.SOLID); + //assertEquals(FillPatternType.SOLID_FOREGROUND.ordinal(), cellFill.getPatternType().ordinal()); + } public void testGetNotModifies() { CTFill ctFill = CTFill.Factory.newInstance(); @@ -75,11 +75,16 @@ public class TestXSSFCellFill extends TestCase { XSSFColor foregroundColor = cellWithThemeColor.getCellStyle().getFillForegroundXSSFColor(); byte[] rgb = foregroundColor.getRgb(); byte[] rgbWithTint = foregroundColor.getRgbWithTint(); - assertEquals(rgb[0],-18); - assertEquals(rgb[1],-20); - assertEquals(rgb[2],-31); - assertEquals(rgbWithTint[0],-12); - assertEquals(rgbWithTint[1],-13); - assertEquals(rgbWithTint[2],-20); + // Dk2 + assertEquals(rgb[0],31); + assertEquals(rgb[1],73); + assertEquals(rgb[2],125); + // Dk2, lighter 40% (tint is about 0.39998) + // 31 * (1.0 - 0.39998) + (255 - 255 * (1.0 - 0.39998)) = 120.59552 => 120 (byte) + // 73 * (1.0 - 0.39998) + (255 - 255 * (1.0 - 0.39998)) = 145.79636 => -111 (byte) + // 125 * (1.0 - 0.39998) + (255 - 255 * (1.0 - 0.39998)) = 176.99740 => -80 (byte) + assertEquals(rgbWithTint[0],120); + assertEquals(rgbWithTint[1],-111); + assertEquals(rgbWithTint[2],-80); } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java index 8ca6fc6f9b..a99e0f75eb 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java @@ -186,7 +186,7 @@ public final class TestColumnHelper extends TestCase { helper.addCleanColIntoCols(cols1, col9); // TODO - assert something interesting - assertEquals(12, cols1.getColList().size()); + assertEquals(12, cols1.sizeOfColArray()); assertEquals(1, cols1.getColArray(0).getMin()); assertEquals(16750, cols1.getColArray(11).getMax()); } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/util/TestCTColComparator.java b/src/ooxml/testcases/org/apache/poi/xssf/util/TestCTColComparator.java index 64f43c4a75..9fa8320bba 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/util/TestCTColComparator.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/util/TestCTColComparator.java @@ -27,39 +27,37 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; public final class TestCTColComparator extends TestCase { public void testCompare() { - CTColComparator comparator = new CTColComparator(); CTCol o1 = CTCol.Factory.newInstance(); o1.setMin(1); o1.setMax(10); CTCol o2 = CTCol.Factory.newInstance(); o2.setMin(11); o2.setMax(12); - assertEquals(-1, comparator.compare(o1, o2)); + assertEquals(-1, CTColComparator.BY_MIN_MAX.compare(o1, o2)); CTCol o3 = CTCol.Factory.newInstance(); o3.setMin(5); o3.setMax(8); CTCol o4 = CTCol.Factory.newInstance(); o4.setMin(5); o4.setMax(80); - assertEquals(-1, comparator.compare(o3, o4)); + assertEquals(-1, CTColComparator.BY_MIN_MAX.compare(o3, o4)); } public void testArraysSort() { - CTColComparator comparator = new CTColComparator(); CTCol o1 = CTCol.Factory.newInstance(); o1.setMin(1); o1.setMax(10); CTCol o2 = CTCol.Factory.newInstance(); o2.setMin(11); o2.setMax(12); - assertEquals(-1, comparator.compare(o1, o2)); + assertEquals(-1, CTColComparator.BY_MIN_MAX.compare(o1, o2)); CTCol o3 = CTCol.Factory.newInstance(); o3.setMin(5); o3.setMax(80); CTCol o4 = CTCol.Factory.newInstance(); o4.setMin(5); o4.setMax(8); - assertEquals(1, comparator.compare(o3, o4)); + assertEquals(1, CTColComparator.BY_MIN_MAX.compare(o3, o4)); CTCol[] cols = new CTCol[4]; cols[0] = o1; cols[1] = o2; @@ -67,7 +65,7 @@ public final class TestCTColComparator extends TestCase { cols[3] = o4; assertEquals(80, cols[2].getMax()); assertEquals(8, cols[3].getMax()); - Arrays.sort(cols, comparator); + Arrays.sort(cols, CTColComparator.BY_MIN_MAX); assertEquals(12, cols[3].getMax()); assertEquals(8, cols[1].getMax()); assertEquals(80, cols[2].getMax()); diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java index 09c1c1636f..7621404b8d 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java @@ -19,6 +19,7 @@ package org.apache.poi.xwpf.usermodel; import java.io.IOException; import java.io.OutputStream; +import java.util.Arrays; import java.util.List; import junit.framework.TestCase; @@ -32,7 +33,6 @@ import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.openxml4j.opc.TargetMode; -import org.apache.poi.util.ArrayUtil; import org.apache.poi.xwpf.XWPFTestDataSamples; import org.apache.xmlbeans.XmlCursor; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; @@ -234,7 +234,7 @@ public final class TestXWPFDocument extends TestCase { OutputStream os = newImagePart.getOutputStream(); os.write(nature1); os.close(); - XWPFHeader xwpfHeader = doc.getHeaderList().get(0); + XWPFHeader xwpfHeader = doc.getHeaderArray(0); PackageRelationship relationship = xwpfHeader.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, jpgRelation.getRelation()); XWPFPictureData newPicData = new XWPFPictureData(newImagePart,relationship); /* new part is now ready to rumble */ @@ -307,7 +307,7 @@ public final class TestXWPFDocument extends TestCase { String id1 = doc.addPictureData(newPic, Document.PICTURE_TYPE_JPEG); assertEquals(2,doc.getAllPackagePictures().size()); /* copy data, to avoid instance-equality */ - byte[] newPicCopy = ArrayUtil.copyOf(newPic, newPic.length); + byte[] newPicCopy = Arrays.copyOf(newPic, newPic.length); String id2 = doc.addPictureData(newPicCopy, Document.PICTURE_TYPE_JPEG); assertEquals(id1,id2); doc.getPackage().revert(); @@ -317,13 +317,13 @@ public final class TestXWPFDocument extends TestCase { XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("issue_51265_2.docx"); assertEquals(1,doc.getAllPictures().size()); assertEquals(1,doc.getAllPackagePictures().size()); - assertEquals(1,doc.getHeaderList().get(0).getAllPictures().size()); + assertEquals(1,doc.getHeaderArray(0).getAllPictures().size()); doc.getPackage().revert(); } public void testPictureHandlingComplex() throws IOException, InvalidFormatException { XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("issue_51265_3.docx"); - XWPFHeader xwpfHeader = doc.getHeaderList().get(0); + XWPFHeader xwpfHeader = doc.getHeaderArray(0); assertEquals(3,doc.getAllPictures().size()); assertEquals(3,xwpfHeader.getAllPictures().size()); diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java index 7d6e83c303..c8f179680f 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java @@ -24,6 +24,9 @@ import java.util.List; import junit.framework.TestCase; import org.apache.poi.xwpf.XWPFTestDataSamples; +import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; +import org.openxmlformats.schemas.drawingml.x2006.picture.PicDocument; +import org.openxmlformats.schemas.drawingml.x2006.picture.impl.PicDocumentImpl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd; @@ -39,9 +42,6 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextAlignment; -import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; -import org.openxmlformats.schemas.drawingml.x2006.picture.PicDocument; -import org.openxmlformats.schemas.drawingml.x2006.picture.impl.PicDocumentImpl; /** * Tests for XWPF Paragraphs @@ -62,7 +62,7 @@ public final class TestXWPFParagraph extends TestCase { assertEquals(1, ps.size()); XWPFParagraph p = ps.get(0); - assertEquals(5, p.getCTP().getRList().size()); + assertEquals(5, p.getCTP().sizeOfRArray()); assertEquals("First header column!\tMid header\tRight header!", p .getText()); } @@ -234,6 +234,7 @@ public final class TestXWPFParagraph extends TestCase { assertEquals(STOnOff.TRUE, ppr.getPageBreakBefore().getVal()); } + @SuppressWarnings("deprecation") public void testBookmarks() throws IOException { XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("bookmarks.docx"); XWPFParagraph paragraph = doc.getParagraphs().get(0); @@ -242,7 +243,7 @@ public final class TestXWPFParagraph extends TestCase { assertEquals(0, paragraph.getCTP().sizeOfBookmarkEndArray()); CTBookmark ctBookmark = paragraph.getCTP().getBookmarkStartArray(0); assertEquals("poi", ctBookmark.getName()); - for(CTBookmark bookmark : paragraph.getCTP().getBookmarkStartList()) { + for(CTBookmark bookmark : paragraph.getCTP().getBookmarkStartArray()) { assertEquals("poi", bookmark.getName()); } } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java index d3c42e912f..618618f92c 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java @@ -180,7 +180,7 @@ public class TestXWPFRun extends TestCase { run.addCarriageReturn(); run.setText("T2"); run.addCarriageReturn(); - assertEquals(3, run.getCTR().getCrList().size()); + assertEquals(3, run.getCTR().sizeOfCrArray()); assertEquals("T1\n\nT2\n", run.toString()); } @@ -200,8 +200,8 @@ public class TestXWPFRun extends TestCase { run.setText("T2"); run.addTab(); run.setText("T3"); - assertEquals(1, run.getCTR().getCrList().size()); - assertEquals(1, run.getCTR().getTabList().size()); + assertEquals(1, run.getCTR().sizeOfCrArray()); + assertEquals(1, run.getCTR().sizeOfTabArray()); assertEquals("T1\nT2\tT3", run.toString()); } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java index 5d13185cfc..fc2c3a28e6 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java @@ -116,6 +116,6 @@ public class TestXWPFStyles extends TestCase { ex.setName("ex1"); XWPFLatentStyles ls = new XWPFLatentStyles(latentStyles); assertEquals(true, ls.isLatentStyle("ex1")); - + assertEquals(false, ls.isLatentStyle("notex1")); } } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java b/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java index 58cf567a58..918afdb3c8 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java @@ -16,11 +16,12 @@ ==================================================================== */ package org.apache.poi.hwpf.model; -import org.apache.poi.util.ArrayUtil; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; +import java.util.Arrays; + public class NilPICFAndBinData { @@ -52,8 +53,8 @@ public class NilPICFAndBinData // skip the 62 ignored bytes int binaryLength = lcb - cbHeader; - this._binData = ArrayUtil.copyOfRange( data, offset + cbHeader, - offset + cbHeader + binaryLength ); + this._binData = Arrays.copyOfRange(data, offset + cbHeader, + offset + cbHeader + binaryLength); } public byte[] getBinData() diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java index 6e114d8dab..5f02c1ed4a 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PlfLfo.java @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.NoSuchElementException; import org.apache.poi.hwpf.model.io.HWPFOutputStream; -import org.apache.poi.util.ArrayUtil; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -118,10 +117,10 @@ public class PlfLfo { final int newLfoMac = _lfoMac + 1; - _rgLfo = ArrayUtil.copyOf( _rgLfo, new LFO[newLfoMac] ); + _rgLfo = Arrays.copyOf(_rgLfo, newLfoMac); _rgLfo[_lfoMac + 1] = lfo; - _rgLfoData = ArrayUtil.copyOf( _rgLfoData, new LFOData[_lfoMac + 1] ); + _rgLfoData = Arrays.copyOf(_rgLfoData, newLfoMac); _rgLfoData[_lfoMac + 1] = lfoData; this._lfoMac = newLfoMac; diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java b/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java index 5f721f92be..01c5d22e5d 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java @@ -16,10 +16,11 @@ ==================================================================== */ package org.apache.poi.hwpf.model; -import org.apache.poi.util.ArrayUtil; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; +import java.util.Arrays; + /** * The STTB is a string table that is made up of a header that is followed by an * array of elements. The cData value specifies the number of elements that are @@ -64,7 +65,7 @@ public class Sttb { this._cDataLength = cDataLength; - this._data = ArrayUtil.copyOf( data, new String[data.length] ); + this._data = Arrays.copyOf(data, data.length); this._cbExtra = 0; this._extraData = null; diff --git a/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java b/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java index 8b84477286..c829159a5c 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java +++ b/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java @@ -1,662 +1,809 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.hssf.model; - -import junit.framework.TestCase; -import org.apache.poi.ddf.*; -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.CommonObjectDataSubRecord; -import org.apache.poi.hssf.record.EscherAggregate; -import org.apache.poi.hssf.record.ObjRecord; -import org.apache.poi.hssf.usermodel.*; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.util.HexDump; - -import java.io.IOException; - -/** - * @author Evgeniy Berlog - * date: 12.06.12 - */ -public class TestDrawingShapes extends TestCase { - - /** - * HSSFShape tree bust be built correctly - * Check file with such records structure: - * -patriarch - * --shape - * --group - * ---group - * ----shape - * ----shape - * ---shape - * ---group - * ----shape - * ----shape - */ - public void testDrawingGroups() { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); - HSSFSheet sheet = wb.getSheet("groups"); - HSSFPatriarch patriarch = sheet.getDrawingPatriarch(); - assertEquals(patriarch.getChildren().size(), 2); - HSSFShapeGroup group = (HSSFShapeGroup) patriarch.getChildren().get(1); - assertEquals(3, group.getChildren().size()); - HSSFShapeGroup group1 = (HSSFShapeGroup) group.getChildren().get(0); - assertEquals(2, group1.getChildren().size()); - group1 = (HSSFShapeGroup) group.getChildren().get(2); - assertEquals(2, group1.getChildren().size()); - } - - public void testHSSFShapeCompatibility() { - HSSFSimpleShape shape = new HSSFSimpleShape(null, new HSSFClientAnchor()); - shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); - assertEquals(0x08000040, shape.getLineStyleColor()); - assertEquals(0x08000009, shape.getFillColor()); - assertEquals(HSSFShape.LINEWIDTH_DEFAULT, shape.getLineWidth()); - assertEquals(HSSFShape.LINESTYLE_SOLID, shape.getLineStyle()); - assertFalse(shape.isNoFill()); - - AbstractShape sp = AbstractShape.createShape(shape, 1); - EscherContainerRecord spContainer = sp.getSpContainer(); - EscherOptRecord opt = - spContainer.getChildById(EscherOptRecord.RECORD_ID); - - assertEquals(7, opt.getEscherProperties().size()); - assertEquals(true, - ((EscherBoolProperty) opt.lookup(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE)).isTrue()); - assertEquals(0x00000004, - ((EscherSimpleProperty) opt.lookup(EscherProperties.GEOMETRY__SHAPEPATH)).getPropertyValue()); - assertEquals(0x08000009, - ((EscherSimpleProperty) opt.lookup(EscherProperties.FILL__FILLCOLOR)).getPropertyValue()); - assertEquals(true, - ((EscherBoolProperty) opt.lookup(EscherProperties.FILL__NOFILLHITTEST)).isTrue()); - assertEquals(0x08000040, - ((EscherSimpleProperty) opt.lookup(EscherProperties.LINESTYLE__COLOR)).getPropertyValue()); - assertEquals(true, - ((EscherBoolProperty) opt.lookup(EscherProperties.LINESTYLE__NOLINEDRAWDASH)).isTrue()); - assertEquals(true, - ((EscherBoolProperty) opt.lookup(EscherProperties.GROUPSHAPE__PRINT)).isTrue()); - } - - public void testDefaultPictureSettings() { - HSSFPicture picture = new HSSFPicture(null, new HSSFClientAnchor()); - assertEquals(picture.getLineWidth(), HSSFShape.LINEWIDTH_DEFAULT); - assertEquals(picture.getFillColor(), HSSFShape.FILL__FILLCOLOR_DEFAULT); - assertEquals(picture.getLineStyle(), HSSFShape.LINESTYLE_NONE); - assertEquals(picture.getLineStyleColor(), HSSFShape.LINESTYLE__COLOR_DEFAULT); - assertEquals(picture.isNoFill(), false); - assertEquals(picture.getPictureIndex(), -1);//not set yet - } - - /** - * No NullPointerException should appear - */ - public void testDefaultSettingsWithEmptyContainer() { - EscherContainerRecord container = new EscherContainerRecord(); - EscherOptRecord opt = new EscherOptRecord(); - opt.setRecordId(EscherOptRecord.RECORD_ID); - container.addChildRecord(opt); - ObjRecord obj = new ObjRecord(); - CommonObjectDataSubRecord cod = new CommonObjectDataSubRecord(); - cod.setObjectType(HSSFSimpleShape.OBJECT_TYPE_PICTURE); - obj.addSubRecord(cod); - HSSFPicture picture = new HSSFPicture(container, obj); - - assertEquals(picture.getLineWidth(), HSSFShape.LINEWIDTH_DEFAULT); - assertEquals(picture.getFillColor(), HSSFShape.FILL__FILLCOLOR_DEFAULT); - assertEquals(picture.getLineStyle(), HSSFShape.LINESTYLE_DEFAULT); - assertEquals(picture.getLineStyleColor(), HSSFShape.LINESTYLE__COLOR_DEFAULT); - assertEquals(picture.isNoFill(), HSSFShape.NO_FILL_DEFAULT); - assertEquals(picture.getPictureIndex(), -1);//not set yet - } - - /** - * create a rectangle, save the workbook, read back and verify that all shape properties are there - */ - public void testReadWriteRectangle() throws IOException { - - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - - HSSFPatriarch drawing = sheet.createDrawingPatriarch(); - HSSFClientAnchor anchor = new HSSFClientAnchor(10, 10, 50, 50, (short) 2, 2, (short) 4, 4); - anchor.setAnchorType(2); - assertEquals(anchor.getAnchorType(), 2); - - HSSFSimpleShape rectangle = drawing.createSimpleShape(anchor); - rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); - rectangle.setLineWidth(10000); - rectangle.setFillColor(777); - assertEquals(rectangle.getFillColor(), 777); - assertEquals(10000, rectangle.getLineWidth()); - rectangle.setLineStyle(10); - assertEquals(10, rectangle.getLineStyle()); - assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_SQUARE); - rectangle.setLineStyleColor(1111); - rectangle.setNoFill(true); - rectangle.setWrapText(HSSFSimpleShape.WRAP_NONE); - rectangle.setString(new HSSFRichTextString("teeeest")); - assertEquals(rectangle.getLineStyleColor(), 1111); - assertEquals(((EscherSimpleProperty)((EscherOptRecord)HSSFTestHelper.getEscherContainer(rectangle).getChildById(EscherOptRecord.RECORD_ID)) - .lookup(EscherProperties.TEXT__TEXTID)).getPropertyValue(), "teeeest".hashCode()); - assertEquals(rectangle.isNoFill(), true); - assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_NONE); - assertEquals(rectangle.getString().getString(), "teeeest"); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - drawing = sheet.getDrawingPatriarch(); - assertEquals(1, drawing.getChildren().size()); - - HSSFSimpleShape rectangle2 = - (HSSFSimpleShape) drawing.getChildren().get(0); - assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, - rectangle2.getShapeType()); - assertEquals(10000, rectangle2.getLineWidth()); - assertEquals(10, rectangle2.getLineStyle()); - assertEquals(anchor, rectangle2.getAnchor()); - assertEquals(rectangle2.getLineStyleColor(), 1111); - assertEquals(rectangle2.getFillColor(), 777); - assertEquals(rectangle2.isNoFill(), true); - assertEquals(rectangle2.getString().getString(), "teeeest"); - assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_NONE); - - rectangle2.setFillColor(3333); - rectangle2.setLineStyle(9); - rectangle2.setLineStyleColor(4444); - rectangle2.setNoFill(false); - rectangle2.setLineWidth(77); - rectangle2.getAnchor().setDx1(2); - rectangle2.getAnchor().setDx2(3); - rectangle2.getAnchor().setDy1(4); - rectangle2.getAnchor().setDy2(5); - rectangle.setWrapText(HSSFSimpleShape.WRAP_BY_POINTS); - rectangle2.setString(new HSSFRichTextString("test22")); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - drawing = sheet.getDrawingPatriarch(); - assertEquals(1, drawing.getChildren().size()); - rectangle2 = (HSSFSimpleShape) drawing.getChildren().get(0); - assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, rectangle2.getShapeType()); - assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_BY_POINTS); - assertEquals(77, rectangle2.getLineWidth()); - assertEquals(9, rectangle2.getLineStyle()); - assertEquals(rectangle2.getLineStyleColor(), 4444); - assertEquals(rectangle2.getFillColor(), 3333); - assertEquals(rectangle2.getAnchor().getDx1(), 2); - assertEquals(rectangle2.getAnchor().getDx2(), 3); - assertEquals(rectangle2.getAnchor().getDy1(), 4); - assertEquals(rectangle2.getAnchor().getDy2(), 5); - assertEquals(rectangle2.isNoFill(), false); - assertEquals(rectangle2.getString().getString(), "test22"); - - HSSFSimpleShape rect3 = drawing.createSimpleShape(new HSSFClientAnchor()); - rect3.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - - drawing = wb.getSheetAt(0).getDrawingPatriarch(); - assertEquals(drawing.getChildren().size(), 2); - } - - public void testReadExistingImage() { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); - HSSFSheet sheet = wb.getSheet("pictures"); - HSSFPatriarch drawing = sheet.getDrawingPatriarch(); - assertEquals(1, drawing.getChildren().size()); - HSSFPicture picture = (HSSFPicture) drawing.getChildren().get(0); - - assertEquals(picture.getPictureIndex(), 2); - assertEquals(picture.getLineStyleColor(), HSSFShape.LINESTYLE__COLOR_DEFAULT); - assertEquals(picture.getFillColor(), 0x5DC943); - assertEquals(picture.getLineWidth(), HSSFShape.LINEWIDTH_DEFAULT); - assertEquals(picture.getLineStyle(), HSSFShape.LINESTYLE_DEFAULT); - assertEquals(picture.isNoFill(), false); - - picture.setPictureIndex(2); - assertEquals(picture.getPictureIndex(), 2); - } - - - /* assert shape properties when reading shapes from a existing workbook */ - public void testReadExistingRectangle() { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); - HSSFSheet sheet = wb.getSheet("rectangles"); - HSSFPatriarch drawing = sheet.getDrawingPatriarch(); - assertEquals(1, drawing.getChildren().size()); - - HSSFSimpleShape shape = (HSSFSimpleShape) drawing.getChildren().get(0); - assertEquals(shape.isNoFill(), false); - assertEquals(shape.getLineStyle(), HSSFShape.LINESTYLE_DASHDOTGEL); - assertEquals(shape.getLineStyleColor(), 0x616161); - assertEquals(HexDump.toHex(shape.getFillColor()), shape.getFillColor(), 0x2CE03D); - assertEquals(shape.getLineWidth(), HSSFShape.LINEWIDTH_ONE_PT * 2); - assertEquals(shape.getString().getString(), "POItest"); - assertEquals(shape.getRotationDegree(), 27); - } - - public void testShapeIds() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet1 = wb.createSheet(); - HSSFPatriarch patriarch1 = sheet1.createDrawingPatriarch(); - for (int i = 0; i < 2; i++) { - patriarch1.createSimpleShape(new HSSFClientAnchor()); - } - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet1 = wb.getSheetAt(0); - patriarch1 = sheet1.getDrawingPatriarch(); - - EscherAggregate agg1 = HSSFTestHelper.getEscherAggregate(patriarch1); - // last shape ID cached in EscherDgRecord - EscherDgRecord dg1 = - agg1.getEscherContainer().getChildById(EscherDgRecord.RECORD_ID); - assertEquals(1026, dg1.getLastMSOSPID()); - - // iterate over shapes and check shapeId - EscherContainerRecord spgrContainer = - agg1.getEscherContainer().getChildContainers().get(0); - // root spContainer + 2 spContainers for shapes - assertEquals(3, spgrContainer.getChildRecords().size()); - - EscherSpRecord sp0 = - ((EscherContainerRecord) spgrContainer.getChild(0)).getChildById(EscherSpRecord.RECORD_ID); - assertEquals(1024, sp0.getShapeId()); - - EscherSpRecord sp1 = - ((EscherContainerRecord) spgrContainer.getChild(1)).getChildById(EscherSpRecord.RECORD_ID); - assertEquals(1025, sp1.getShapeId()); - - EscherSpRecord sp2 = - ((EscherContainerRecord) spgrContainer.getChild(2)).getChildById(EscherSpRecord.RECORD_ID); - assertEquals(1026, sp2.getShapeId()); - } - - /** - * Test get new id for shapes from existing file - * File already have for 1 shape on each sheet, because document must contain EscherDgRecord for each sheet - */ - public void testAllocateNewIds() { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("empty.xls"); - HSSFSheet sheet = wb.getSheetAt(0); - HSSFPatriarch patriarch = sheet.getDrawingPatriarch(); - - /** - * 2048 - main SpContainer id - * 2049 - existing shape id - */ - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 2050); - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 2051); - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 2052); - - sheet = wb.getSheetAt(1); - patriarch = sheet.getDrawingPatriarch(); - - /** - * 3072 - main SpContainer id - * 3073 - existing shape id - */ - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 3074); - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 3075); - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 3076); - - - sheet = wb.getSheetAt(2); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 1026); - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 1027); - assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 1028); - } - - public void testOpt() throws Exception { - HSSFWorkbook wb = new HSSFWorkbook(); - - // create a sheet with a text box - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - HSSFTextbox textbox = patriarch.createTextbox(new HSSFClientAnchor()); - EscherOptRecord opt1 = HSSFTestHelper.getOptRecord(textbox); - EscherOptRecord opt2 = HSSFTestHelper.getEscherContainer(textbox).getChildById(EscherOptRecord.RECORD_ID); - assertSame(opt1, opt2); - } - - public void testCorrectOrderInOptRecord(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - HSSFTextbox textbox = patriarch.createTextbox(new HSSFClientAnchor()); - EscherOptRecord opt = HSSFTestHelper.getOptRecord(textbox); - - String opt1Str = opt.toXml(); - - textbox.setFillColor(textbox.getFillColor()); - EscherContainerRecord container = HSSFTestHelper.getEscherContainer(textbox); - EscherOptRecord optRecord = container.getChildById(EscherOptRecord.RECORD_ID); - assertEquals(opt1Str, optRecord.toXml()); - textbox.setLineStyle(textbox.getLineStyle()); - assertEquals(opt1Str, optRecord.toXml()); - textbox.setLineWidth(textbox.getLineWidth()); - assertEquals(opt1Str, optRecord.toXml()); - textbox.setLineStyleColor(textbox.getLineStyleColor()); - assertEquals(opt1Str, optRecord.toXml()); - } - - public void testDgRecordNumShapes(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - EscherAggregate aggregate = HSSFTestHelper.getEscherAggregate(patriarch); - EscherDgRecord dgRecord = (EscherDgRecord) aggregate.getEscherRecord(0).getChild(0); - assertEquals(dgRecord.getNumShapes(), 1); - } - - public void testTextForSimpleShape(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - HSSFSimpleShape shape = patriarch.createSimpleShape(new HSSFClientAnchor()); - shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); - - EscherAggregate agg = HSSFTestHelper.getEscherAggregate(patriarch); - assertEquals(agg.getShapeToObjMapping().size(), 2); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - shape = (HSSFSimpleShape) patriarch.getChildren().get(0); - - agg = HSSFTestHelper.getEscherAggregate(patriarch); - assertEquals(agg.getShapeToObjMapping().size(), 2); - - shape.setString(new HSSFRichTextString("string1")); - assertEquals(shape.getString().getString(), "string1"); - - assertNotNull(HSSFTestHelper.getEscherContainer(shape).getChildById(EscherTextboxRecord.RECORD_ID)); - assertEquals(agg.getShapeToObjMapping().size(), 2); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - shape = (HSSFSimpleShape) patriarch.getChildren().get(0); - - assertNotNull(HSSFTestHelper.getTextObjRecord(shape)); - assertEquals(shape.getString().getString(), "string1"); - assertNotNull(HSSFTestHelper.getEscherContainer(shape).getChildById(EscherTextboxRecord.RECORD_ID)); - assertEquals(agg.getShapeToObjMapping().size(), 2); - } - - public void testRemoveShapes(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - HSSFSimpleShape rectangle = patriarch.createSimpleShape(new HSSFClientAnchor()); - rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); - - int idx = wb.addPicture(new byte[]{1,2,3}, Workbook.PICTURE_TYPE_JPEG); - patriarch.createPicture(new HSSFClientAnchor(), idx); - - patriarch.createCellComment(new HSSFClientAnchor()); - - HSSFPolygon polygon = patriarch.createPolygon(new HSSFClientAnchor()); - polygon.setPoints(new int[]{1,2}, new int[]{2,3}); - - patriarch.createTextbox(new HSSFClientAnchor()); - - HSSFShapeGroup group = patriarch.createGroup(new HSSFClientAnchor()); - group.createTextbox(new HSSFChildAnchor()); - group.createPicture(new HSSFChildAnchor(), idx); - - assertEquals(patriarch.getChildren().size(), 6); - assertEquals(group.getChildren().size(), 2); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 12); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 12); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - - assertEquals(patriarch.getChildren().size(), 6); - - group = (HSSFShapeGroup) patriarch.getChildren().get(5); - group.removeShape(group.getChildren().get(0)); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 10); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 10); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - - group = (HSSFShapeGroup) patriarch.getChildren().get(5); - patriarch.removeShape(group); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 8); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 8); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - assertEquals(patriarch.getChildren().size(), 5); - - HSSFShape shape = patriarch.getChildren().get(0); - patriarch.removeShape(shape); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 6); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - assertEquals(patriarch.getChildren().size(), 4); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 6); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - assertEquals(patriarch.getChildren().size(), 4); - - HSSFPicture picture = (HSSFPicture) patriarch.getChildren().get(0); - patriarch.removeShape(picture); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 5); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - assertEquals(patriarch.getChildren().size(), 3); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 5); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); - assertEquals(patriarch.getChildren().size(), 3); - - HSSFComment comment = (HSSFComment) patriarch.getChildren().get(0); - patriarch.removeShape(comment); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 3); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 2); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 3); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 2); - - polygon = (HSSFPolygon) patriarch.getChildren().get(0); - patriarch.removeShape(polygon); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 2); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 1); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 2); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 1); - - HSSFTextbox textbox = (HSSFTextbox) patriarch.getChildren().get(0); - patriarch.removeShape(textbox); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 0); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 0); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 0); - assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 0); - } - - public void testShapeFlip(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - HSSFSimpleShape rectangle = patriarch.createSimpleShape(new HSSFClientAnchor()); - rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); - - assertEquals(rectangle.isFlipVertical(), false); - assertEquals(rectangle.isFlipHorizontal(), false); - - rectangle.setFlipVertical(true); - assertEquals(rectangle.isFlipVertical(), true); - rectangle.setFlipHorizontal(true); - assertEquals(rectangle.isFlipHorizontal(), true); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - rectangle = (HSSFSimpleShape) patriarch.getChildren().get(0); - - assertEquals(rectangle.isFlipHorizontal(), true); - rectangle.setFlipHorizontal(false); - assertEquals(rectangle.isFlipHorizontal(), false); - - assertEquals(rectangle.isFlipVertical(), true); - rectangle.setFlipVertical(false); - assertEquals(rectangle.isFlipVertical(), false); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - rectangle = (HSSFSimpleShape) patriarch.getChildren().get(0); - - assertEquals(rectangle.isFlipVertical(), false); - assertEquals(rectangle.isFlipHorizontal(), false); - } - - public void testRotation() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - HSSFSimpleShape rectangle = patriarch.createSimpleShape(new HSSFClientAnchor(0,0,100,100, (short) 0,0,(short)5,5)); - rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); - - assertEquals(rectangle.getRotationDegree(), 0); - rectangle.setRotationDegree((short) 45); - assertEquals(rectangle.getRotationDegree(), 45); - rectangle.setFlipHorizontal(true); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - rectangle = (HSSFSimpleShape) patriarch.getChildren().get(0); - assertEquals(rectangle.getRotationDegree(), 45); - rectangle.setRotationDegree((short) 30); - assertEquals(rectangle.getRotationDegree(), 30); - - patriarch.setCoordinates(0, 0, 10, 10); - rectangle.setString(new HSSFRichTextString("1234")); - } - - public void testShapeContainerImplementsIterable(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - patriarch.createSimpleShape(new HSSFClientAnchor()); - patriarch.createSimpleShape(new HSSFClientAnchor()); - - int i=2; - - for (HSSFShape shape: patriarch){ - i--; - } - assertEquals(i, 0); - } - - public void testClearShapesForPatriarch(){ - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); - - patriarch.createSimpleShape(new HSSFClientAnchor()); - patriarch.createSimpleShape(new HSSFClientAnchor()); - patriarch.createCellComment(new HSSFClientAnchor()); - - EscherAggregate agg = HSSFTestHelper.getEscherAggregate(patriarch); - - assertEquals(agg.getShapeToObjMapping().size(), 6); - assertEquals(agg.getTailRecords().size(), 1); - assertEquals(patriarch.getChildren().size(), 3); - - patriarch.clear(); - - assertEquals(agg.getShapeToObjMapping().size(), 0); - assertEquals(agg.getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 0); - - wb = HSSFTestDataSamples.writeOutAndReadBack(wb); - sheet = wb.getSheetAt(0); - patriarch = sheet.getDrawingPatriarch(); - - assertEquals(agg.getShapeToObjMapping().size(), 0); - assertEquals(agg.getTailRecords().size(), 0); - assertEquals(patriarch.getChildren().size(), 0); - } -} +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.model; + +import java.io.IOException; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.poi.ddf.EscherBoolProperty; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.ddf.EscherDgRecord; +import org.apache.poi.ddf.EscherOptRecord; +import org.apache.poi.ddf.EscherProperties; +import org.apache.poi.ddf.EscherSimpleProperty; +import org.apache.poi.ddf.EscherSpRecord; +import org.apache.poi.ddf.EscherTextboxRecord; +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.record.CommonObjectDataSubRecord; +import org.apache.poi.hssf.record.EscherAggregate; +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.util.HexDump; + + +/** + * @author Evgeniy Berlog + * date: 12.06.12 + */ +public class TestDrawingShapes extends TestCase { + static { + //System.setProperty("poi.deserialize.escher", "true"); + } + + /** + * HSSFShape tree bust be built correctly + * Check file with such records structure: + * -patriarch + * --shape + * --group + * ---group + * ----shape + * ----shape + * ---shape + * ---group + * ----shape + * ----shape + */ + public void testDrawingGroups() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); + HSSFSheet sheet = wb.getSheet("groups"); + HSSFPatriarch patriarch = sheet.getDrawingPatriarch(); + assertEquals(patriarch.getChildren().size(), 2); + HSSFShapeGroup group = (HSSFShapeGroup) patriarch.getChildren().get(1); + assertEquals(3, group.getChildren().size()); + HSSFShapeGroup group1 = (HSSFShapeGroup) group.getChildren().get(0); + assertEquals(2, group1.getChildren().size()); + group1 = (HSSFShapeGroup) group.getChildren().get(2); + assertEquals(2, group1.getChildren().size()); + } + + public void testHSSFShapeCompatibility() { + HSSFSimpleShape shape = new HSSFSimpleShape(null, new HSSFClientAnchor()); + shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); + assertEquals(0x08000040, shape.getLineStyleColor()); + assertEquals(0x08000009, shape.getFillColor()); + assertEquals(HSSFShape.LINEWIDTH_DEFAULT, shape.getLineWidth()); + assertEquals(HSSFShape.LINESTYLE_SOLID, shape.getLineStyle()); + assertFalse(shape.isNoFill()); + + AbstractShape sp = AbstractShape.createShape(shape, 1); + EscherContainerRecord spContainer = sp.getSpContainer(); + EscherOptRecord opt = + spContainer.getChildById(EscherOptRecord.RECORD_ID); + + assertEquals(7, opt.getEscherProperties().size()); + assertEquals(true, + ((EscherBoolProperty) opt.lookup(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE)).isTrue()); + assertEquals(0x00000004, + ((EscherSimpleProperty) opt.lookup(EscherProperties.GEOMETRY__SHAPEPATH)).getPropertyValue()); + assertEquals(0x08000009, + ((EscherSimpleProperty) opt.lookup(EscherProperties.FILL__FILLCOLOR)).getPropertyValue()); + assertEquals(true, + ((EscherBoolProperty) opt.lookup(EscherProperties.FILL__NOFILLHITTEST)).isTrue()); + assertEquals(0x08000040, + ((EscherSimpleProperty) opt.lookup(EscherProperties.LINESTYLE__COLOR)).getPropertyValue()); + assertEquals(true, + ((EscherBoolProperty) opt.lookup(EscherProperties.LINESTYLE__NOLINEDRAWDASH)).isTrue()); + assertEquals(true, + ((EscherBoolProperty) opt.lookup(EscherProperties.GROUPSHAPE__PRINT)).isTrue()); + } + + public void testDefaultPictureSettings() { + HSSFPicture picture = new HSSFPicture(null, new HSSFClientAnchor()); + assertEquals(picture.getLineWidth(), HSSFShape.LINEWIDTH_DEFAULT); + assertEquals(picture.getFillColor(), HSSFShape.FILL__FILLCOLOR_DEFAULT); + assertEquals(picture.getLineStyle(), HSSFShape.LINESTYLE_NONE); + assertEquals(picture.getLineStyleColor(), HSSFShape.LINESTYLE__COLOR_DEFAULT); + assertEquals(picture.isNoFill(), false); + assertEquals(picture.getPictureIndex(), -1);//not set yet + } + + /** + * No NullPointerException should appear + */ + public void testDefaultSettingsWithEmptyContainer() { + EscherContainerRecord container = new EscherContainerRecord(); + EscherOptRecord opt = new EscherOptRecord(); + opt.setRecordId(EscherOptRecord.RECORD_ID); + container.addChildRecord(opt); + ObjRecord obj = new ObjRecord(); + CommonObjectDataSubRecord cod = new CommonObjectDataSubRecord(); + cod.setObjectType(HSSFSimpleShape.OBJECT_TYPE_PICTURE); + obj.addSubRecord(cod); + HSSFPicture picture = new HSSFPicture(container, obj); + + assertEquals(picture.getLineWidth(), HSSFShape.LINEWIDTH_DEFAULT); + assertEquals(picture.getFillColor(), HSSFShape.FILL__FILLCOLOR_DEFAULT); + assertEquals(picture.getLineStyle(), HSSFShape.LINESTYLE_DEFAULT); + assertEquals(picture.getLineStyleColor(), HSSFShape.LINESTYLE__COLOR_DEFAULT); + assertEquals(picture.isNoFill(), HSSFShape.NO_FILL_DEFAULT); + assertEquals(picture.getPictureIndex(), -1);//not set yet + } + + /** + * create a rectangle, save the workbook, read back and verify that all shape properties are there + */ + public void testReadWriteRectangle() throws IOException { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + HSSFPatriarch drawing = sheet.createDrawingPatriarch(); + HSSFClientAnchor anchor = new HSSFClientAnchor(10, 10, 50, 50, (short) 2, 2, (short) 4, 4); + anchor.setAnchorType(2); + assertEquals(anchor.getAnchorType(), 2); + + HSSFSimpleShape rectangle = drawing.createSimpleShape(anchor); + rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + rectangle.setLineWidth(10000); + rectangle.setFillColor(777); + assertEquals(rectangle.getFillColor(), 777); + assertEquals(10000, rectangle.getLineWidth()); + rectangle.setLineStyle(10); + assertEquals(10, rectangle.getLineStyle()); + assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_SQUARE); + rectangle.setLineStyleColor(1111); + rectangle.setNoFill(true); + rectangle.setWrapText(HSSFSimpleShape.WRAP_NONE); + rectangle.setString(new HSSFRichTextString("teeeest")); + assertEquals(rectangle.getLineStyleColor(), 1111); + assertEquals(((EscherSimpleProperty)((EscherOptRecord)HSSFTestHelper.getEscherContainer(rectangle).getChildById(EscherOptRecord.RECORD_ID)) + .lookup(EscherProperties.TEXT__TEXTID)).getPropertyValue(), "teeeest".hashCode()); + assertEquals(rectangle.isNoFill(), true); + assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_NONE); + assertEquals(rectangle.getString().getString(), "teeeest"); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + + HSSFSimpleShape rectangle2 = + (HSSFSimpleShape) drawing.getChildren().get(0); + assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, + rectangle2.getShapeType()); + assertEquals(10000, rectangle2.getLineWidth()); + assertEquals(10, rectangle2.getLineStyle()); + assertEquals(anchor, rectangle2.getAnchor()); + assertEquals(rectangle2.getLineStyleColor(), 1111); + assertEquals(rectangle2.getFillColor(), 777); + assertEquals(rectangle2.isNoFill(), true); + assertEquals(rectangle2.getString().getString(), "teeeest"); + assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_NONE); + + rectangle2.setFillColor(3333); + rectangle2.setLineStyle(9); + rectangle2.setLineStyleColor(4444); + rectangle2.setNoFill(false); + rectangle2.setLineWidth(77); + rectangle2.getAnchor().setDx1(2); + rectangle2.getAnchor().setDx2(3); + rectangle2.getAnchor().setDy1(4); + rectangle2.getAnchor().setDy2(5); + rectangle.setWrapText(HSSFSimpleShape.WRAP_BY_POINTS); + rectangle2.setString(new HSSFRichTextString("test22")); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + rectangle2 = (HSSFSimpleShape) drawing.getChildren().get(0); + assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, rectangle2.getShapeType()); + assertEquals(rectangle.getWrapText(), HSSFSimpleShape.WRAP_BY_POINTS); + assertEquals(77, rectangle2.getLineWidth()); + assertEquals(9, rectangle2.getLineStyle()); + assertEquals(rectangle2.getLineStyleColor(), 4444); + assertEquals(rectangle2.getFillColor(), 3333); + assertEquals(rectangle2.getAnchor().getDx1(), 2); + assertEquals(rectangle2.getAnchor().getDx2(), 3); + assertEquals(rectangle2.getAnchor().getDy1(), 4); + assertEquals(rectangle2.getAnchor().getDy2(), 5); + assertEquals(rectangle2.isNoFill(), false); + assertEquals(rectangle2.getString().getString(), "test22"); + + HSSFSimpleShape rect3 = drawing.createSimpleShape(new HSSFClientAnchor()); + rect3.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + + drawing = wb.getSheetAt(0).getDrawingPatriarch(); + assertEquals(drawing.getChildren().size(), 2); + } + + public void testReadExistingImage() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); + HSSFSheet sheet = wb.getSheet("pictures"); + HSSFPatriarch drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + HSSFPicture picture = (HSSFPicture) drawing.getChildren().get(0); + + assertEquals(picture.getPictureIndex(), 2); + assertEquals(picture.getLineStyleColor(), HSSFShape.LINESTYLE__COLOR_DEFAULT); + assertEquals(picture.getFillColor(), 0x5DC943); + assertEquals(picture.getLineWidth(), HSSFShape.LINEWIDTH_DEFAULT); + assertEquals(picture.getLineStyle(), HSSFShape.LINESTYLE_DEFAULT); + assertEquals(picture.isNoFill(), false); + + picture.setPictureIndex(2); + assertEquals(picture.getPictureIndex(), 2); + } + + + /* assert shape properties when reading shapes from a existing workbook */ + public void testReadExistingRectangle() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); + HSSFSheet sheet = wb.getSheet("rectangles"); + HSSFPatriarch drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + + HSSFSimpleShape shape = (HSSFSimpleShape) drawing.getChildren().get(0); + assertEquals(shape.isNoFill(), false); + assertEquals(shape.getLineStyle(), HSSFShape.LINESTYLE_DASHDOTGEL); + assertEquals(shape.getLineStyleColor(), 0x616161); + assertEquals(HexDump.toHex(shape.getFillColor()), shape.getFillColor(), 0x2CE03D); + assertEquals(shape.getLineWidth(), HSSFShape.LINEWIDTH_ONE_PT * 2); + assertEquals(shape.getString().getString(), "POItest"); + assertEquals(shape.getRotationDegree(), 27); + } + + public void testShapeIds() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet1 = wb.createSheet(); + HSSFPatriarch patriarch1 = sheet1.createDrawingPatriarch(); + for (int i = 0; i < 2; i++) { + patriarch1.createSimpleShape(new HSSFClientAnchor()); + } + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet1 = wb.getSheetAt(0); + patriarch1 = sheet1.getDrawingPatriarch(); + + EscherAggregate agg1 = HSSFTestHelper.getEscherAggregate(patriarch1); + // last shape ID cached in EscherDgRecord + EscherDgRecord dg1 = + agg1.getEscherContainer().getChildById(EscherDgRecord.RECORD_ID); + assertEquals(1026, dg1.getLastMSOSPID()); + + // iterate over shapes and check shapeId + EscherContainerRecord spgrContainer = + agg1.getEscherContainer().getChildContainers().get(0); + // root spContainer + 2 spContainers for shapes + assertEquals(3, spgrContainer.getChildRecords().size()); + + EscherSpRecord sp0 = + ((EscherContainerRecord) spgrContainer.getChild(0)).getChildById(EscherSpRecord.RECORD_ID); + assertEquals(1024, sp0.getShapeId()); + + EscherSpRecord sp1 = + ((EscherContainerRecord) spgrContainer.getChild(1)).getChildById(EscherSpRecord.RECORD_ID); + assertEquals(1025, sp1.getShapeId()); + + EscherSpRecord sp2 = + ((EscherContainerRecord) spgrContainer.getChild(2)).getChildById(EscherSpRecord.RECORD_ID); + assertEquals(1026, sp2.getShapeId()); + } + + /** + * Test get new id for shapes from existing file + * File already have for 1 shape on each sheet, because document must contain EscherDgRecord for each sheet + */ + public void testAllocateNewIds() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("empty.xls"); + HSSFSheet sheet = wb.getSheetAt(0); + HSSFPatriarch patriarch = sheet.getDrawingPatriarch(); + + /** + * 2048 - main SpContainer id + * 2049 - existing shape id + */ + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 2050); + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 2051); + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 2052); + + sheet = wb.getSheetAt(1); + patriarch = sheet.getDrawingPatriarch(); + + /** + * 3072 - main SpContainer id + * 3073 - existing shape id + */ + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 3074); + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 3075); + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 3076); + + + sheet = wb.getSheetAt(2); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 1026); + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 1027); + assertEquals(HSSFTestHelper.allocateNewShapeId(patriarch), 1028); + } + + public void testOpt() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook(); + + try { + // create a sheet with a text box + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + HSSFTextbox textbox = patriarch.createTextbox(new HSSFClientAnchor()); + EscherOptRecord opt1 = HSSFTestHelper.getOptRecord(textbox); + EscherOptRecord opt2 = HSSFTestHelper.getEscherContainer(textbox).getChildById(EscherOptRecord.RECORD_ID); + assertSame(opt1, opt2); + } finally { + wb.close(); + } + } + + public void testCorrectOrderInOptRecord() throws IOException{ + HSSFWorkbook wb = new HSSFWorkbook(); + + try { + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + HSSFTextbox textbox = patriarch.createTextbox(new HSSFClientAnchor()); + EscherOptRecord opt = HSSFTestHelper.getOptRecord(textbox); + + String opt1Str = opt.toXml(); + + textbox.setFillColor(textbox.getFillColor()); + EscherContainerRecord container = HSSFTestHelper.getEscherContainer(textbox); + EscherOptRecord optRecord = container.getChildById(EscherOptRecord.RECORD_ID); + assertEquals(opt1Str, optRecord.toXml()); + textbox.setLineStyle(textbox.getLineStyle()); + assertEquals(opt1Str, optRecord.toXml()); + textbox.setLineWidth(textbox.getLineWidth()); + assertEquals(opt1Str, optRecord.toXml()); + textbox.setLineStyleColor(textbox.getLineStyleColor()); + assertEquals(opt1Str, optRecord.toXml()); + } finally { + wb.close(); + } + } + + public void testDgRecordNumShapes() throws IOException{ + HSSFWorkbook wb = new HSSFWorkbook(); + try { + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + EscherAggregate aggregate = HSSFTestHelper.getEscherAggregate(patriarch); + EscherDgRecord dgRecord = (EscherDgRecord) aggregate.getEscherRecord(0).getChild(0); + assertEquals(dgRecord.getNumShapes(), 1); + } finally { + wb.close(); + } + } + + public void testTextForSimpleShape(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + HSSFSimpleShape shape = patriarch.createSimpleShape(new HSSFClientAnchor()); + shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + + EscherAggregate agg = HSSFTestHelper.getEscherAggregate(patriarch); + assertEquals(agg.getShapeToObjMapping().size(), 2); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + shape = (HSSFSimpleShape) patriarch.getChildren().get(0); + + agg = HSSFTestHelper.getEscherAggregate(patriarch); + assertEquals(agg.getShapeToObjMapping().size(), 2); + + shape.setString(new HSSFRichTextString("string1")); + assertEquals(shape.getString().getString(), "string1"); + + assertNotNull(HSSFTestHelper.getEscherContainer(shape).getChildById(EscherTextboxRecord.RECORD_ID)); + assertEquals(agg.getShapeToObjMapping().size(), 2); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + shape = (HSSFSimpleShape) patriarch.getChildren().get(0); + + assertNotNull(HSSFTestHelper.getTextObjRecord(shape)); + assertEquals(shape.getString().getString(), "string1"); + assertNotNull(HSSFTestHelper.getEscherContainer(shape).getChildById(EscherTextboxRecord.RECORD_ID)); + assertEquals(agg.getShapeToObjMapping().size(), 2); + } + + public void testRemoveShapes(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + HSSFSimpleShape rectangle = patriarch.createSimpleShape(new HSSFClientAnchor()); + rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + + int idx = wb.addPicture(new byte[]{1,2,3}, Workbook.PICTURE_TYPE_JPEG); + patriarch.createPicture(new HSSFClientAnchor(), idx); + + patriarch.createCellComment(new HSSFClientAnchor()); + + HSSFPolygon polygon = patriarch.createPolygon(new HSSFClientAnchor()); + polygon.setPoints(new int[]{1,2}, new int[]{2,3}); + + patriarch.createTextbox(new HSSFClientAnchor()); + + HSSFShapeGroup group = patriarch.createGroup(new HSSFClientAnchor()); + group.createTextbox(new HSSFChildAnchor()); + group.createPicture(new HSSFChildAnchor(), idx); + + assertEquals(patriarch.getChildren().size(), 6); + assertEquals(group.getChildren().size(), 2); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 12); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 12); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + + assertEquals(patriarch.getChildren().size(), 6); + + group = (HSSFShapeGroup) patriarch.getChildren().get(5); + group.removeShape(group.getChildren().get(0)); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 10); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 10); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + + group = (HSSFShapeGroup) patriarch.getChildren().get(5); + patriarch.removeShape(group); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 8); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 8); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + assertEquals(patriarch.getChildren().size(), 5); + + HSSFShape shape = patriarch.getChildren().get(0); + patriarch.removeShape(shape); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 6); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + assertEquals(patriarch.getChildren().size(), 4); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 6); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + assertEquals(patriarch.getChildren().size(), 4); + + HSSFPicture picture = (HSSFPicture) patriarch.getChildren().get(0); + patriarch.removeShape(picture); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 5); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + assertEquals(patriarch.getChildren().size(), 3); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 5); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 1); + assertEquals(patriarch.getChildren().size(), 3); + + HSSFComment comment = (HSSFComment) patriarch.getChildren().get(0); + patriarch.removeShape(comment); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 3); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 2); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 3); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 2); + + polygon = (HSSFPolygon) patriarch.getChildren().get(0); + patriarch.removeShape(polygon); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 2); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 1); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 2); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 1); + + HSSFTextbox textbox = (HSSFTextbox) patriarch.getChildren().get(0); + patriarch.removeShape(textbox); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 0); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 0); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getShapeToObjMapping().size(), 0); + assertEquals(HSSFTestHelper.getEscherAggregate(patriarch).getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 0); + } + + public void testShapeFlip(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + HSSFSimpleShape rectangle = patriarch.createSimpleShape(new HSSFClientAnchor()); + rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + + assertEquals(rectangle.isFlipVertical(), false); + assertEquals(rectangle.isFlipHorizontal(), false); + + rectangle.setFlipVertical(true); + assertEquals(rectangle.isFlipVertical(), true); + rectangle.setFlipHorizontal(true); + assertEquals(rectangle.isFlipHorizontal(), true); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + rectangle = (HSSFSimpleShape) patriarch.getChildren().get(0); + + assertEquals(rectangle.isFlipHorizontal(), true); + rectangle.setFlipHorizontal(false); + assertEquals(rectangle.isFlipHorizontal(), false); + + assertEquals(rectangle.isFlipVertical(), true); + rectangle.setFlipVertical(false); + assertEquals(rectangle.isFlipVertical(), false); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + rectangle = (HSSFSimpleShape) patriarch.getChildren().get(0); + + assertEquals(rectangle.isFlipVertical(), false); + assertEquals(rectangle.isFlipHorizontal(), false); + } + + public void testRotation() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + HSSFSimpleShape rectangle = patriarch.createSimpleShape(new HSSFClientAnchor(0,0,100,100, (short) 0,0,(short)5,5)); + rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + + assertEquals(rectangle.getRotationDegree(), 0); + rectangle.setRotationDegree((short) 45); + assertEquals(rectangle.getRotationDegree(), 45); + rectangle.setFlipHorizontal(true); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + rectangle = (HSSFSimpleShape) patriarch.getChildren().get(0); + assertEquals(rectangle.getRotationDegree(), 45); + rectangle.setRotationDegree((short) 30); + assertEquals(rectangle.getRotationDegree(), 30); + + patriarch.setCoordinates(0, 0, 10, 10); + rectangle.setString(new HSSFRichTextString("1234")); + } + + public void testShapeContainerImplementsIterable() throws IOException{ + HSSFWorkbook wb = new HSSFWorkbook(); + + try { + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + patriarch.createSimpleShape(new HSSFClientAnchor()); + patriarch.createSimpleShape(new HSSFClientAnchor()); + + int i=2; + + for (HSSFShape shape: patriarch){ + i--; + } + assertEquals(i, 0); + } finally { + wb.close(); + } + } + + public void testClearShapesForPatriarch(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + patriarch.createSimpleShape(new HSSFClientAnchor()); + patriarch.createSimpleShape(new HSSFClientAnchor()); + patriarch.createCellComment(new HSSFClientAnchor()); + + EscherAggregate agg = HSSFTestHelper.getEscherAggregate(patriarch); + + assertEquals(agg.getShapeToObjMapping().size(), 6); + assertEquals(agg.getTailRecords().size(), 1); + assertEquals(patriarch.getChildren().size(), 3); + + patriarch.clear(); + + assertEquals(agg.getShapeToObjMapping().size(), 0); + assertEquals(agg.getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 0); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + patriarch = sheet.getDrawingPatriarch(); + + assertEquals(agg.getShapeToObjMapping().size(), 0); + assertEquals(agg.getTailRecords().size(), 0); + assertEquals(patriarch.getChildren().size(), 0); + } + + public void testBug45312() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook(); + try { + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + + { + HSSFClientAnchor a1 = new HSSFClientAnchor(); + a1.setAnchor( (short)1, 1, 0, 0, (short) 1, 1, 512, 100); + HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1); + shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); + } + { + HSSFClientAnchor a1 = new HSSFClientAnchor(); + a1.setAnchor( (short)1, 1, 512, 0, (short) 1, 1, 1024, 100); + HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1); + shape1.setFlipVertical(true); + shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); + } + + { + HSSFClientAnchor a1 = new HSSFClientAnchor(); + a1.setAnchor( (short)2, 2, 0, 0, (short) 2, 2, 512, 100); + HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1); + shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); + } + { + HSSFClientAnchor a1 = new HSSFClientAnchor(); + a1.setAnchor( (short)2, 2, 0, 100, (short) 2, 2, 512, 200); + HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1); + shape1.setFlipHorizontal(true); + shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); + } + + /*OutputStream stream = new FileOutputStream("/tmp/45312.xls"); + try { + wb.write(stream); + } finally { + stream.close(); + }*/ + + checkWorkbookBack(wb); + } finally { + wb.close(); + } + } + + private void checkWorkbookBack(HSSFWorkbook wb) { + HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb); + assertNotNull(wbBack); + + HSSFSheet sheetBack = wbBack.getSheetAt(0); + assertNotNull(sheetBack); + + HSSFPatriarch patriarchBack = sheetBack.getDrawingPatriarch(); + assertNotNull(patriarchBack); + + List children = patriarchBack.getChildren(); + assertEquals(4, children.size()); + HSSFShape hssfShape = children.get(0); + assertTrue(hssfShape instanceof HSSFSimpleShape); + HSSFAnchor anchor = hssfShape.getAnchor(); + assertTrue(anchor instanceof HSSFClientAnchor); + assertEquals(0, anchor.getDx1()); + assertEquals(512, anchor.getDx2()); + assertEquals(0, anchor.getDy1()); + assertEquals(100, anchor.getDy2()); + HSSFClientAnchor cAnchor = (HSSFClientAnchor) anchor; + assertEquals(1, cAnchor.getCol1()); + assertEquals(1, cAnchor.getCol2()); + assertEquals(1, cAnchor.getRow1()); + assertEquals(1, cAnchor.getRow2()); + + hssfShape = children.get(1); + assertTrue(hssfShape instanceof HSSFSimpleShape); + anchor = hssfShape.getAnchor(); + assertTrue(anchor instanceof HSSFClientAnchor); + assertEquals(512, anchor.getDx1()); + assertEquals(1024, anchor.getDx2()); + assertEquals(0, anchor.getDy1()); + assertEquals(100, anchor.getDy2()); + cAnchor = (HSSFClientAnchor) anchor; + assertEquals(1, cAnchor.getCol1()); + assertEquals(1, cAnchor.getCol2()); + assertEquals(1, cAnchor.getRow1()); + assertEquals(1, cAnchor.getRow2()); + + hssfShape = children.get(2); + assertTrue(hssfShape instanceof HSSFSimpleShape); + anchor = hssfShape.getAnchor(); + assertTrue(anchor instanceof HSSFClientAnchor); + assertEquals(0, anchor.getDx1()); + assertEquals(512, anchor.getDx2()); + assertEquals(0, anchor.getDy1()); + assertEquals(100, anchor.getDy2()); + cAnchor = (HSSFClientAnchor) anchor; + assertEquals(2, cAnchor.getCol1()); + assertEquals(2, cAnchor.getCol2()); + assertEquals(2, cAnchor.getRow1()); + assertEquals(2, cAnchor.getRow2()); + + hssfShape = children.get(3); + assertTrue(hssfShape instanceof HSSFSimpleShape); + anchor = hssfShape.getAnchor(); + assertTrue(anchor instanceof HSSFClientAnchor); + assertEquals(0, anchor.getDx1()); + assertEquals(512, anchor.getDx2()); + assertEquals(100, anchor.getDy1()); + assertEquals(200, anchor.getDy2()); + cAnchor = (HSSFClientAnchor) anchor; + assertEquals(2, cAnchor.getCol1()); + assertEquals(2, cAnchor.getCol2()); + assertEquals(2, cAnchor.getRow1()); + assertEquals(2, cAnchor.getRow2()); + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/TestDConRefRecord.java b/src/testcases/org/apache/poi/hssf/record/TestDConRefRecord.java index 9518f3fff2..b101a4ee2b 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestDConRefRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestDConRefRecord.java @@ -23,7 +23,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; import junit.framework.TestCase; -import org.apache.poi.util.ArrayUtil; import org.apache.poi.util.LittleEndianOutputStream; /** @@ -288,7 +287,7 @@ public class TestDConRefRecord extends TestCase public void testGetPath() { DConRefRecord instance = new DConRefRecord(TestcaseRecordInputStream.create(81, data1)); - byte[] expResult = ArrayUtil.copyOfRange(data1, 9, data1.length); + byte[] expResult = Arrays.copyOfRange(data1, 9, data1.length); byte[] result = instance.getPath(); assertTrue("get path", Arrays.equals(expResult, result)); } diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java index 5c6af7b261..b6e6ca932e 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java @@ -390,7 +390,6 @@ public abstract class BaseTestConditionalFormatting extends TestCase { } public void testShiftRows() { - Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -403,30 +402,42 @@ public abstract class BaseTestConditionalFormatting extends TestCase { PatternFormatting patternFmt = rule1.createPatternFormatting(); patternFmt.setFillBackgroundColor(IndexedColors.YELLOW.index); - ConditionalFormattingRule [] cfRules = { rule1, }; + + ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule( + ComparisonOperator.BETWEEN, "SUM(A10:A15)", "1+SUM(B16:B30)"); + BorderFormatting borderFmt = rule2.createBorderFormatting(); + borderFmt.setBorderDiagonal((short) 2); CellRangeAddress [] regions = { new CellRangeAddress(2, 4, 0, 0), // A3:A5 }; - sheetCF.addConditionalFormatting(regions, cfRules); + sheetCF.addConditionalFormatting(regions, rule1); + sheetCF.addConditionalFormatting(regions, rule2); // This row-shift should destroy the CF region sheet.shiftRows(10, 20, -9); assertEquals(0, sheetCF.getNumConditionalFormattings()); // re-add the CF - sheetCF.addConditionalFormatting(regions, cfRules); + sheetCF.addConditionalFormatting(regions, rule1); + sheetCF.addConditionalFormatting(regions, rule2); // This row shift should only affect the formulas sheet.shiftRows(14, 17, 8); - ConditionalFormatting cf = sheetCF.getConditionalFormattingAt(0); - assertEquals("SUM(A10:A23)", cf.getRule(0).getFormula1()); - assertEquals("1+SUM(B24:B30)", cf.getRule(0).getFormula2()); + ConditionalFormatting cf1 = sheetCF.getConditionalFormattingAt(0); + assertEquals("SUM(A10:A23)", cf1.getRule(0).getFormula1()); + assertEquals("1+SUM(B24:B30)", cf1.getRule(0).getFormula2()); + ConditionalFormatting cf2 = sheetCF.getConditionalFormattingAt(1); + assertEquals("SUM(A10:A23)", cf2.getRule(0).getFormula1()); + assertEquals("1+SUM(B24:B30)", cf2.getRule(0).getFormula2()); sheet.shiftRows(0, 8, 21); - cf = sheetCF.getConditionalFormattingAt(0); - assertEquals("SUM(A10:A21)", cf.getRule(0).getFormula1()); - assertEquals("1+SUM(#REF!)", cf.getRule(0).getFormula2()); + cf1 = sheetCF.getConditionalFormattingAt(0); + assertEquals("SUM(A10:A21)", cf1.getRule(0).getFormula1()); + assertEquals("1+SUM(#REF!)", cf1.getRule(0).getFormula2()); + cf2 = sheetCF.getConditionalFormattingAt(1); + assertEquals("SUM(A10:A21)", cf2.getRule(0).getFormula1()); + assertEquals("1+SUM(#REF!)", cf2.getRule(0).getFormula2()); } protected void testRead(String filename){ diff --git a/test-data/spreadsheet/56730.xlsx b/test-data/spreadsheet/56730.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9883de4f6671df377b4d959fd0a9ee71fdcf95e3 GIT binary patch literal 9808 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 b_w>i?ttb;k!L5LDWi7tB7i0C#5Az0CZ=)DvC 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 literal 0 HcmV?d00001 diff --git a/test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx b/test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..978210787c5f033b350fe8c52c9584416c554423 GIT binary patch literal 8171 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 literal 0 HcmV?d00001 diff --git a/test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx b/test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2712913380d250eccdf4de8943ac970d2d976683 GIT binary patch literal 11207 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