You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2016/08/19 20:57:56 UTC

svn commit: r1756967 [3/3] - in /poi/branches/hssf_cryptoapi: ./ sonar/ sonar/examples/ sonar/excelant/ sonar/main/ sonar/ooxml-schema-encryption/ sonar/ooxml-schema-security/ sonar/ooxml-schema/ sonar/ooxml/ sonar/scratchpad/ src/ooxml/java/org/apache...

Modified: poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
URL: http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java?rev=1756967&r1=1756966&r2=1756967&view=diff
==============================================================================
--- poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java (original)
+++ poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java Fri Aug 19 20:57:56 2016
@@ -22,32 +22,10 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Iterator;
 
 import org.apache.poi.hpsf.DocumentSummaryInformation;
 import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hwpf.model.BookmarksTables;
-import org.apache.poi.hwpf.model.CHPBinTable;
-import org.apache.poi.hwpf.model.ComplexFileTable;
-import org.apache.poi.hwpf.model.DocumentProperties;
-import org.apache.poi.hwpf.model.EscherRecordHolder;
-import org.apache.poi.hwpf.model.FSPADocumentPart;
-import org.apache.poi.hwpf.model.FSPATable;
-import org.apache.poi.hwpf.model.FieldsTables;
-import org.apache.poi.hwpf.model.FontTable;
-import org.apache.poi.hwpf.model.ListTables;
-import org.apache.poi.hwpf.model.NoteType;
-import org.apache.poi.hwpf.model.NotesTables;
-import org.apache.poi.hwpf.model.PAPBinTable;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.model.RevisionMarkAuthorTable;
-import org.apache.poi.hwpf.model.SavedByTable;
-import org.apache.poi.hwpf.model.SectionTable;
-import org.apache.poi.hwpf.model.SinglentonTextPiece;
-import org.apache.poi.hwpf.model.StyleSheet;
-import org.apache.poi.hwpf.model.SubdocumentType;
-import org.apache.poi.hwpf.model.TextPiece;
-import org.apache.poi.hwpf.model.TextPieceTable;
+import org.apache.poi.hwpf.model.*;
 import org.apache.poi.hwpf.model.io.HWPFFileSystem;
 import org.apache.poi.hwpf.model.io.HWPFOutputStream;
 import org.apache.poi.hwpf.usermodel.Bookmarks;
@@ -572,12 +550,27 @@ public final class HWPFDocument extends
     }
 
     /**
-     * Warning - not currently implemented for HWPF!
+     * Write out the word file that is represented by this class, to the 
+     *  currently open {@link File}, via the writeable {@link POIFSFileSystem}
+     *  it was opened as. 
+     *  
+     * <p>This will fail (with an {@link IllegalStateException} if the
+     *  Document was opened read-only, opened from an {@link InputStream}
+     *   instead of a File, or if this is not the root document. For those cases, 
+     *   you must use {@link #write(OutputStream)} or {@link #write(File)} to 
+     *   write to a brand new document.
+     *         
+     * @since 3.15
      */
     @Override
     public void write() throws IOException {
-        // TODO Implement
-        throw new IllegalStateException("Coming soon!");
+        validateInPlaceWritePossible();
+        
+        // Update the Document+Properties streams in the file
+        write(directory.getFileSystem(), false);
+        
+        // Sync with the File on disk
+        directory.getFileSystem().writeFilesystem();
     }
     
     /**
@@ -912,23 +905,18 @@ public final class HWPFDocument extends
             dataBuf = tempBuf;
         }
 
-        // create new document preserving order of entries
-        // TODO Check "copyOtherEntries" and tweak behaviour based on that
-        // TODO That's needed for in-place write
+        // Create a new document preserving order of entries / Update existing
         boolean docWritten = false;
         boolean dataWritten = false;
         boolean objectPoolWritten = false;
         boolean tableWritten = false;
         boolean propertiesWritten = false;
-        for ( Iterator<Entry> iter = directory.getEntries(); iter.hasNext(); )
-        {
-            Entry entry = iter.next();
+        for (Entry entry : directory) {
             if ( entry.getName().equals( STREAM_WORD_DOCUMENT ) )
             {
                 if ( !docWritten )
                 {
-                    pfs.createDocument( new ByteArrayInputStream( mainBuf ),
-                            STREAM_WORD_DOCUMENT );
+                    write(pfs, mainBuf, STREAM_WORD_DOCUMENT);
                     docWritten = true;
                 }
             }
@@ -936,7 +924,11 @@ public final class HWPFDocument extends
             {
                 if ( !objectPoolWritten )
                 {
-                    _objectPool.writeTo( pfs.getRoot() );
+                    if ( copyOtherEntries ) {
+                        _objectPool.writeTo( pfs.getRoot() );
+                    } else {
+                        // Object pool is already there, no need to change/copy
+                    }
                     objectPoolWritten = true;
                 }
             }
@@ -945,8 +937,7 @@ public final class HWPFDocument extends
             {
                 if ( !tableWritten )
                 {
-                    pfs.createDocument( new ByteArrayInputStream( tableBuf ),
-                            STREAM_TABLE_1 );
+                    write(pfs, tableBuf, STREAM_TABLE_1);
                     tableWritten = true;
                 }
             }
@@ -965,29 +956,25 @@ public final class HWPFDocument extends
             {
                 if ( !dataWritten )
                 {
-                    pfs.createDocument( new ByteArrayInputStream( dataBuf ),
-                            STREAM_DATA );
+                    write(pfs, dataBuf, STREAM_DATA);
                     dataWritten = true;
                 }
             }
-            else
+            else if ( copyOtherEntries )
             {
                 EntryUtils.copyNodeRecursively( entry, pfs.getRoot() );
             }
         }
 
         if ( !docWritten )
-            pfs.createDocument( new ByteArrayInputStream( mainBuf ),
-                    STREAM_WORD_DOCUMENT );
+            write(pfs, mainBuf, STREAM_WORD_DOCUMENT);
         if ( !tableWritten )
-            pfs.createDocument( new ByteArrayInputStream( tableBuf ),
-                    STREAM_TABLE_1 );
+            write(pfs, tableBuf, STREAM_TABLE_1);
         if ( !propertiesWritten )
             writeProperties( pfs );
         if ( !dataWritten )
-            pfs.createDocument( new ByteArrayInputStream( dataBuf ),
-                    STREAM_DATA );
-        if ( !objectPoolWritten )
+            write(pfs, dataBuf, STREAM_DATA);
+        if ( !objectPoolWritten && copyOtherEntries )
             _objectPool.writeTo( pfs.getRoot() );
 
         this.directory = pfs.getRoot();
@@ -1000,6 +987,9 @@ public final class HWPFDocument extends
         this._tableStream = tableStream.toByteArray();
         this._dataStream = dataBuf;
     }
+    private static void write(NPOIFSFileSystem pfs, byte[] data, String name) throws IOException {
+        pfs.createOrUpdateDocument(new ByteArrayInputStream(data), name);
+    }
 
     @Internal
     public byte[] getDataStream()

Modified: poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java
URL: http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java?rev=1756967&r1=1756966&r2=1756967&view=diff
==============================================================================
--- poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java (original)
+++ poi/branches/hssf_cryptoapi/src/scratchpad/src/org/apache/poi/hwpf/sprm/SectionSprmUncompressor.java Fri Aug 19 20:57:56 2016
@@ -24,11 +24,12 @@ import org.apache.poi.util.Internal;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 
+
 @Internal
 public final class SectionSprmUncompressor extends SprmUncompressor
 {
   private static final POILogger logger = POILogFactory.getLogger(SectionSprmUncompressor.class);
-  
+
   public SectionSprmUncompressor()
   {
   }
@@ -58,15 +59,14 @@ public final class SectionSprmUncompress
    */
   static void unCompressSEPOperation (SectionProperties newSEP, SprmOperation sprm)
   {
-    final int operation = sprm.getOperation();
-    final int operand = sprm.getOperand();
+    int operation = sprm.getOperation();
     switch (operation)
     {
       case 0:
-        newSEP.setCnsPgn ((byte) operand);
+        newSEP.setCnsPgn ((byte) sprm.getOperand());
         break;
       case 0x1:
-        newSEP.setIHeadingPgn ((byte) operand);
+        newSEP.setIHeadingPgn ((byte) sprm.getOperand());
         break;
       case 0x2:
         byte[] buf = new byte[sprm.size() - 3];
@@ -80,110 +80,110 @@ public final class SectionSprmUncompress
         //not quite sure
         break;
       case 0x5:
-        newSEP.setFEvenlySpaced (getFlag (operand));
+        newSEP.setFEvenlySpaced (getFlag (sprm.getOperand()));
         break;
       case 0x6:
-        newSEP.setFUnlocked (getFlag (operand));
+        newSEP.setFUnlocked (getFlag (sprm.getOperand()));
         break;
       case 0x7:
-        newSEP.setDmBinFirst ((short) operand);
+        newSEP.setDmBinFirst ((short) sprm.getOperand());
         break;
       case 0x8:
-        newSEP.setDmBinOther ((short) operand);
+        newSEP.setDmBinOther ((short) sprm.getOperand());
         break;
       case 0x9:
-        newSEP.setBkc ((byte) operand);
+        newSEP.setBkc ((byte) sprm.getOperand());
         break;
       case 0xa:
-        newSEP.setFTitlePage (getFlag (operand));
+        newSEP.setFTitlePage (getFlag (sprm.getOperand()));
         break;
       case 0xb:
-        newSEP.setCcolM1 ((short) operand);
+        newSEP.setCcolM1 ((short) sprm.getOperand());
         break;
       case 0xc:
-        newSEP.setDxaColumns (operand);
+        newSEP.setDxaColumns (sprm.getOperand());
         break;
       case 0xd:
-        newSEP.setFAutoPgn (getFlag (operand));
+        newSEP.setFAutoPgn (getFlag (sprm.getOperand()));
         break;
       case 0xe:
-        newSEP.setNfcPgn ((byte) operand);
+        newSEP.setNfcPgn ((byte) sprm.getOperand());
         break;
       case 0xf:
-        newSEP.setDyaPgn ((short) operand);
+        newSEP.setDyaPgn ((short) sprm.getOperand());
         break;
       case 0x10:
-        newSEP.setDxaPgn ((short) operand);
+        newSEP.setDxaPgn ((short) sprm.getOperand());
         break;
       case 0x11:
-        newSEP.setFPgnRestart (getFlag (operand));
+        newSEP.setFPgnRestart (getFlag (sprm.getOperand()));
         break;
       case 0x12:
-        newSEP.setFEndNote (getFlag (operand));
+        newSEP.setFEndNote (getFlag (sprm.getOperand()));
         break;
       case 0x13:
-        newSEP.setLnc ((byte) operand);
+        newSEP.setLnc ((byte) sprm.getOperand());
         break;
       case 0x14:
-        newSEP.setGrpfIhdt ((byte) operand);
+        newSEP.setGrpfIhdt ((byte) sprm.getOperand());
         break;
       case 0x15:
-        newSEP.setNLnnMod ((short) operand);
+        newSEP.setNLnnMod ((short) sprm.getOperand());
         break;
       case 0x16:
-        newSEP.setDxaLnn (operand);
+        newSEP.setDxaLnn (sprm.getOperand());
         break;
       case 0x17:
-        newSEP.setDyaHdrTop (operand);
+        newSEP.setDyaHdrTop (sprm.getOperand());
         break;
       case 0x18:
-        newSEP.setDyaHdrBottom (operand);
+        newSEP.setDyaHdrBottom (sprm.getOperand());
         break;
       case 0x19:
-        newSEP.setFLBetween (getFlag (operand));
+        newSEP.setFLBetween (getFlag (sprm.getOperand()));
         break;
       case 0x1a:
-        newSEP.setVjc ((byte) operand);
+        newSEP.setVjc ((byte) sprm.getOperand());
         break;
       case 0x1b:
-        newSEP.setLnnMin ((short) operand);
+        newSEP.setLnnMin ((short) sprm.getOperand());
         break;
       case 0x1c:
-        newSEP.setPgnStart ((short) operand);
+        newSEP.setPgnStart ((short) sprm.getOperand());
         break;
       case 0x1d:
-        newSEP.setDmOrientPage( operand != 0 );
+        newSEP.setDmOrientPage( sprm.getOperand() != 0 );
         break;
       case 0x1e:
 
         //nothing
         break;
       case 0x1f:
-        newSEP.setXaPage (operand);
+        newSEP.setXaPage (sprm.getOperand());
         break;
       case 0x20:
-        newSEP.setYaPage (operand);
+        newSEP.setYaPage (sprm.getOperand());
         break;
       case 0x21:
-        newSEP.setDxaLeft (operand);
+        newSEP.setDxaLeft (sprm.getOperand());
         break;
       case 0x22:
-        newSEP.setDxaRight (operand);
+        newSEP.setDxaRight (sprm.getOperand());
         break;
       case 0x23:
-        newSEP.setDyaTop (operand);
+        newSEP.setDyaTop (sprm.getOperand());
         break;
       case 0x24:
-        newSEP.setDyaBottom (operand);
+        newSEP.setDyaBottom (sprm.getOperand());
         break;
       case 0x25:
-        newSEP.setDzaGutter (operand);
+        newSEP.setDzaGutter (sprm.getOperand());
         break;
       case 0x26:
-        newSEP.setDmPaperReq ((short) operand);
+        newSEP.setDmPaperReq ((short) sprm.getOperand());
         break;
       case 0x27:
-        newSEP.setFPropMark (getFlag (operand));
+        newSEP.setFPropMark (getFlag (sprm.getOperand()));
         break;
       case 0x28:
         break;
@@ -204,40 +204,40 @@ public final class SectionSprmUncompress
         newSEP.setBrcRight(new BorderCode(sprm.getGrpprl(), sprm.getGrpprlOffset()));
         break;
       case 0x2f:
-        newSEP.setPgbProp (operand);
+        newSEP.setPgbProp (sprm.getOperand());
         break;
       case 0x30:
-        newSEP.setDxtCharSpace (operand);
+        newSEP.setDxtCharSpace (sprm.getOperand());
         break;
       case 0x31:
-        newSEP.setDyaLinePitch (operand);
+        newSEP.setDyaLinePitch (sprm.getOperand());
         break;
       case 0x33:
-        newSEP.setWTextFlow ((short) operand);
+        newSEP.setWTextFlow ((short) sprm.getOperand());
         break;
       case 0x3C:
         // [MS-DOC], v20140721, 2.6.4, sprmSRncFtn        
-        newSEP.setRncFtn((short) operand);
+        newSEP.setRncFtn((short) sprm.getOperand());
         break;
       case 0x3E:
         // [MS-DOC], v20140721, 2.6.4, sprmSRncEdn        
-        newSEP.setRncEdn((short) operand);
+        newSEP.setRncEdn((short) sprm.getOperand());
         break;
       case 0x3F:
         // [MS-DOC], v20140721, 2.6.4, sprmSNFtn
-        newSEP.setNFtn(operand);
+        newSEP.setNFtn((int) sprm.getOperand());
         break;
       case 0x40:
         // [MS-DOC], v20140721, 2.6.4, sprmSNFtnRef
-        newSEP.setNfcFtnRef(operand);
+        newSEP.setNfcFtnRef((int) sprm.getOperand());
         break;
       case 0x41:
         // [MS-DOC], v20140721, 2.6.4, sprmSNEdn
-        newSEP.setNEdn(operand);
+        newSEP.setNEdn((int) sprm.getOperand());
         break;
       case 0x42:
         // [MS-DOC], v20140721, 2.6.4, sprmSNEdnRef
-        newSEP.setNfcEdnRef(operand);
+        newSEP.setNfcEdnRef((int) sprm.getOperand());
         break;
       default:
         logger.log(POILogger.INFO, "Unsupported Sprm operation: " + operation + " (" + HexDump.byteToHex(operation) + ")");

Modified: poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
URL: http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java?rev=1756967&r1=1756966&r2=1756967&view=diff
==============================================================================
--- poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java (original)
+++ poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java Fri Aug 19 20:57:56 2016
@@ -18,6 +18,7 @@
 package org.apache.poi.hslf.extractor;
 
 import static org.apache.poi.POITestCase.assertContains;
+import static org.apache.poi.POITestCase.assertContainsIgnoreCase;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -26,7 +27,6 @@ import static org.junit.Assert.assertTru
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.util.List;
-import java.util.Locale;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.hslf.model.OLEShape;
@@ -355,7 +355,7 @@ public final class TestExtractor {
        ppe = new PowerPointExtractor(hslf);
        
        text = ppe.getText();
-       assertContains(text.toLowerCase(Locale.ROOT), "master");
+       assertContainsIgnoreCase(text, "master");
        assertContains(text, masterText);
     }
 

Modified: poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java
URL: http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java?rev=1756967&r1=1756966&r2=1756967&view=diff
==============================================================================
--- poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java (original)
+++ poi/branches/hssf_cryptoapi/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java Fri Aug 19 20:57:56 2016
@@ -21,11 +21,16 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 
+import org.apache.poi.POIDataSamples;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.HWPFTestCase;
 import org.apache.poi.hwpf.HWPFTestDataSamples;
+import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
+import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.TempFile;
 
 /**
@@ -75,7 +80,65 @@ public final class TestHWPFWrite extends
        r = doc.getRange();
        assertEquals("I am a test document\r", r.getParagraph(0).text());
        doc.close();
-    }
+   }
    
-   // TODO In-place write positive and negative checks
+   /**
+    * Writing to the file we opened from - note, uses a temp file to
+    *  avoid changing our test files!
+    */
+   @SuppressWarnings("resource")
+   public void testInPlaceWrite() throws Exception {
+       // Setup as a copy of a known-good file
+       final File file = TempFile.createTempFile("TestDocument", ".doc");
+       IOUtils.copy(
+               POIDataSamples.getDocumentInstance().openResourceAsStream("SampleDoc.doc"),
+               new FileOutputStream(file)
+       );
+
+       // Open from the temp file in read-write mode
+       HWPFDocument doc = new HWPFDocument(new NPOIFSFileSystem(file, false).getRoot());
+       Range r = doc.getRange();
+       assertEquals("I am a test document\r", r.getParagraph(0).text());
+
+       // Change
+       r.replaceText("X XX a test document\r", false);
+
+       // Save in-place, close, re-open and check
+       doc.write();
+       doc.close();
+
+       doc = new HWPFDocument(new NPOIFSFileSystem(file).getRoot());
+       assertEquals("X XX a test document\r", r.getParagraph(0).text());
+   }
+
+   @SuppressWarnings("resource")
+   public void testInvalidInPlaceWrite() throws Exception {
+       HWPFDocument doc;
+
+       // Can't work for InputStream opened files
+       doc = new HWPFDocument(
+               POIDataSamples.getDocumentInstance().openResourceAsStream("SampleDoc.doc"));
+       try {
+           doc.write();
+           fail("Shouldn't work for InputStream");
+       } catch (IllegalStateException e) {}
+
+       // Can't work for OPOIFS
+       OPOIFSFileSystem ofs = new OPOIFSFileSystem(
+               POIDataSamples.getDocumentInstance().openResourceAsStream("SampleDoc.doc"));
+       doc = new HWPFDocument(ofs.getRoot());
+       try {
+           doc.write();
+           fail("Shouldn't work for OPOIFSFileSystem");
+       } catch (IllegalStateException e) {}
+
+       // Can't work for Read-Only files
+       NPOIFSFileSystem fs = new NPOIFSFileSystem(
+               POIDataSamples.getDocumentInstance().getFile("SampleDoc.doc"), true);
+       doc = new HWPFDocument(fs.getRoot());
+       try {
+           doc.write();
+           fail("Shouldn't work for Read Only");
+       } catch (IllegalStateException e) {}
+   }
 }

Modified: poi/branches/hssf_cryptoapi/src/testcases/org/apache/poi/POITestCase.java
URL: http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/testcases/org/apache/poi/POITestCase.java?rev=1756967&r1=1756966&r2=1756967&view=diff
==============================================================================
--- poi/branches/hssf_cryptoapi/src/testcases/org/apache/poi/POITestCase.java (original)
+++ poi/branches/hssf_cryptoapi/src/testcases/org/apache/poi/POITestCase.java Fri Aug 19 20:57:56 2016
@@ -32,13 +32,16 @@ import java.security.PrivilegedActionExc
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import org.apache.poi.util.SuppressForbidden;
+import org.apache.poi.util.Internal;
 
 /**
  * Util class for POI JUnit TestCases, which provide additional features 
  */
+@Internal
 public final class POITestCase {
     public static void assertContains(String haystack, String needle) {
         assertNotNull(haystack);
@@ -47,6 +50,19 @@ public final class POITestCase {
               haystack.contains(needle)
         );
     }
+
+    public static void assertContainsIgnoreCase(String haystack, String needle, Locale locale) {
+        assertNotNull(haystack);
+        assertNotNull(needle);
+        String hay = haystack.toLowerCase(locale);
+        String n = needle.toLowerCase(locale);
+        assertTrue("Unable to find expected text '" + needle + "' in text:\n" + haystack,
+                hay.contains(n)
+        );
+    }
+    public static void assertContainsIgnoreCase(String haystack, String needle) {
+        assertContainsIgnoreCase(haystack, needle, Locale.ROOT);
+    }
     
     public static void assertNotContained(String haystack, String needle) {
         assertNotNull(haystack);



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org