]> source.dussan.org Git - poi.git/commitdiff
Bug 51891 - Fix StringIndexOutOfBoundsException : Ole10Native.<init> (parsing word...
authorAndreas Beeker <kiwiwings@apache.org>
Sat, 1 Feb 2014 21:45:48 +0000 (21:45 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sat, 1 Feb 2014 21:45:48 +0000 (21:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1563483 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hpsf/ClassID.java
src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
src/testcases/org/apache/poi/poifs/AllPOIFSTests.java
src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java
src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java
test-data/poifs/20-Force-on-a-current-S00.doc [new file with mode: 0644]
test-data/poifs/multimedia.doc [new file with mode: 0644]

index a49d9df588ccbd24f86f3f2d0fb48f4a337a3fce..c78702c3c1ac90ee9a8b8108cf48c9bb97c1caf6 100644 (file)
@@ -40,6 +40,7 @@ public class ClassID
     public static final ClassID WORD95       = new ClassID("{00020900-0000-0000-C000-000000000046}");
     public static final ClassID POWERPOINT97 = new ClassID("{64818D10-4F9B-11CF-86EA-00AA00B929E8}");
     public static final ClassID POWERPOINT95 = new ClassID("{EA7BAE70-FB3B-11CD-A903-00AA00510EA3}");
+    public static final ClassID EQUATION30   = new ClassID("{0002CE02-0000-0000-C000-000000000046}");
        
        
     /**
index 2c950da3ff06951b4b1066ad1910d525fa30dcb0..122eb0a5aecea8347346ee12f17b73e073c8555f 100644 (file)
 
 package org.apache.poi.poifs.filesystem;
 
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.poi.util.HexDump;
-import org.apache.poi.util.LittleEndian;
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
 import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianOutputStream;\r
 import org.apache.poi.util.StringUtil;\r
 \r
 /**\r
@@ -35,341 +34,378 @@ import org.apache.poi.util.StringUtil;
  */
 public class Ole10Native {
 
-  public static final String OLE10_NATIVE = "\u0001Ole10Native";
-  protected static final String ISO1 = "ISO-8859-1";
-
-  // (the fields as they appear in the raw record:)
-  private int totalSize;             // 4 bytes, total size of record not including this field
-  private short flags1 = 2;          // 2 bytes, unknown, mostly [02 00]
-  private String label;              // ASCIIZ, stored in this field without the terminating zero
-  private String fileName;           // ASCIIZ, stored in this field without the terminating zero
-  private short flags2 = 0;          // 2 bytes, unknown, mostly [00 00]
-  private short unknown1 = 3;        // see below
-  private String command;            // ASCIIZ, stored in this field without the terminating zero
-  private byte[] dataBuffer;         // varying size, the actual native data
-  private short flags3 = 0;          // some final flags? or zero terminators?, sometimes not there
-
-  /**
-   * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
-   * to include a stream &quot;{01}Ole10Native&quot; which contains the actual
-   * data relevant for this class.\r
-   *\r
-   * @param poifs POI Filesystem object\r
-   * @return Returns an instance of this class\r
-   * @throws IOException on IO error\r
-   * @throws Ole10NativeException on invalid or unexcepted data format\r
-   */\r
-  public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {\r
-     return createFromEmbeddedOleObject(poifs.getRoot());\r
-  }\r
+    public static final String OLE10_NATIVE = "\u0001Ole10Native";
+    protected static final String ISO1 = "ISO-8859-1";
+  
+    // (the fields as they appear in the raw record:)\r
+    private int totalSize;             // 4 bytes, total size of record not including this field
+    private short flags1 = 2;          // 2 bytes, unknown, mostly [02 00]
+    private String label;              // ASCIIZ, stored in this field without the terminating zero
+    private String fileName;           // ASCIIZ, stored in this field without the terminating zero
+    private short flags2 = 0;          // 2 bytes, unknown, mostly [00 00]
+    private short unknown1 = 3;        // see below
+    private String command;            // ASCIIZ, stored in this field without the terminating zero
+    private byte[] dataBuffer;         // varying size, the actual native data
+    private short flags3 = 0;          // some final flags? or zero terminators?, sometimes not there
+  
+    /**\r
+     * the field encoding mode - merely a try-and-error guess ...\r
+     **/ \r
+    private enum EncodingMode {\r
+        /**\r
+         * the data is stored in parsed format - including label, command, etc.\r
+         */\r
+        parsed,\r
+        /**\r
+         * the data is stored raw after the length field\r
+         */\r
+        unparsed,\r
+        /**\r
+         * the data is stored raw after the length field and the flags1 field\r
+         */\r
+        compact;\r
+    }\r
+    \r
+    private EncodingMode mode;\r
+\r
+    \r
+    \r
+    /**
+     * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
+     * to include a stream &quot;{01}Ole10Native&quot; which contains the actual
+     * data relevant for this class.\r
+     *\r
+     * @param poifs POI Filesystem object\r
+     * @return Returns an instance of this class\r
+     * @throws IOException on IO error\r
+     * @throws Ole10NativeException on invalid or unexcepted data format\r
+     */\r
+    public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {\r
+       return createFromEmbeddedOleObject(poifs.getRoot());\r
+    }\r
+    \r
+    /**\r
+     * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected\r
+     * to include a stream &quot;{01}Ole10Native&quot; which contains the actual\r
+     * data relevant for this class.\r
+     *\r
+     * @param directory POI Filesystem object\r
+     * @return Returns an instance of this class\r
+     * @throws IOException on IO error\r
+     * @throws Ole10NativeException on invalid or unexcepted data format\r
+     */\r
+    public static Ole10Native createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {\r
+       DocumentEntry nativeEntry = \r
+          (DocumentEntry)directory.getEntry(OLE10_NATIVE);\r
+       byte[] data = new byte[nativeEntry.getSize()];\r
+       directory.createDocumentInputStream(nativeEntry).read(data);\r
   \r
-  /**\r
-   * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected\r
-   * to include a stream &quot;{01}Ole10Native&quot; which contains the actual\r
-   * data relevant for this class.\r
-   *\r
-   * @param directory POI Filesystem object\r
-   * @return Returns an instance of this class\r
-   * @throws IOException on IO error\r
-   * @throws Ole10NativeException on invalid or unexcepted data format\r
-   */\r
-  public static Ole10Native createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {\r
-     boolean plain = false;\r
+       return new Ole10Native(data, 0);\r
+    }
+    
+    /**
+     * Creates an instance and fills the fields based on ... the fields
+     */
+    public Ole10Native(String label, String filename, String command, byte[] data) {
+       setLabel(label);
+       setFileName(filename);
+       setCommand(command);
+       setDataBuffer(data);\r
+       mode = EncodingMode.parsed;
+    }
 \r
-     try {\r
-        directory.getEntry("\u0001Ole10ItemName");\r
-        plain = true;\r
-     } catch (FileNotFoundException ex) {\r
-        plain = false;\r
-     }\r
-     \r
-     DocumentEntry nativeEntry = \r
-        (DocumentEntry)directory.getEntry(OLE10_NATIVE);\r
-     byte[] data = new byte[nativeEntry.getSize()];\r
-     directory.createDocumentInputStream(nativeEntry).read(data);\r
+    /**\r
+     * Creates an instance and fills the fields based on the data in the given buffer.\r
+     *\r
+     * @param data   The buffer containing the Ole10Native record\r
+     * @param offset The start offset of the record in the buffer\r
+     * @param plain as of POI 3.11 this parameter is ignored\r
+     * @throws Ole10NativeException on invalid or unexcepted data format\r
+     * \r
+     * @deprecated parameter plain is ignored, use {@link #Ole10Native(byte[],int)}\r
+     */\r
+    public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {\r
+        this(data, offset);\r
+    }\r
+    
+    /**
+     * Creates an instance and fills the fields based on the data in the given buffer.
+     *
+     * @param data   The buffer containing the Ole10Native record
+     * @param offset The start offset of the record in the buffer\r
+     * @throws Ole10NativeException on invalid or unexcepted data format\r
+     */\r
+    public Ole10Native(byte[] data, int offset) throws Ole10NativeException {\r
+        int ofs = offset; // current offset, initialized to start\r
+        \r
+        if (data.length < offset + 2) {\r
+            throw new Ole10NativeException("data is too small");\r
+        }\r
+        \r
+        totalSize = LittleEndian.getInt(data, ofs);\r
+        ofs += LittleEndianConsts.INT_SIZE;\r
+        \r
+        mode = EncodingMode.unparsed;\r
+        if (LittleEndian.getShort(data, ofs) == 2) {\r
+            // some files like equations don't have a valid filename,\r
+            // but somehow encode the formula right away in the ole10 header\r
+            if (Character.isISOControl(data[ofs+LittleEndianConsts.SHORT_SIZE])) {\r
+                mode = EncodingMode.compact;\r
+            } else {\r
+                mode = EncodingMode.parsed;\r
+            }\r
+        }\r
 \r
-     return new Ole10Native(data, 0, plain);\r
-  }
-  
-  /**
-   * Creates an instance and fills the fields based on ... the fields
-   */
-  public Ole10Native(String label, String filename, String command, byte[] data) {
-         setLabel(label);
-         setFileName(filename);
-         setCommand(command);
-         setDataBuffer(data);
-  }
-  
-  /**
-   * Creates an instance and fills the fields based on the data in the given buffer.
-   *
-   * @param data   The buffer containing the Ole10Native record
-   * @param offset The start offset of the record in the buffer\r
-   * @throws Ole10NativeException on invalid or unexcepted data format\r
-   */\r
-  public Ole10Native(byte[] data, int offset) throws Ole10NativeException {\r
-    this(data, offset, false);\r
-  }\r
-  /**\r
-   * Creates an instance and fills the fields based on the data in the given buffer.\r
-   *\r
-   * @param data   The buffer containing the Ole10Native record\r
-   * @param offset The start offset of the record in the buffer\r
-   * @param plain Specified 'plain' format without filename\r
-   * @throws Ole10NativeException on invalid or unexcepted data format\r
-   */\r
-  public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {\r
-    int ofs = offset;        // current offset, initialized to start\r
+        int dataSize;\r
+        switch (mode) {\r
+        case parsed: {\r
+            flags1 = LittleEndian.getShort(data, ofs);\r
+            \r
+            // structured format\r
+            ofs += LittleEndianConsts.SHORT_SIZE;\r
+        \r
+            int len = getStringLength(data, ofs);\r
+            label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);\r
+            ofs += len;\r
+            \r
+            len = getStringLength(data, ofs);\r
+            fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);\r
+            ofs += len;\r
+    \r
+            flags2 = LittleEndian.getShort(data, ofs);\r
+            ofs += LittleEndianConsts.SHORT_SIZE;
+            
+            unknown1 = LittleEndian.getShort(data, ofs);
+            ofs += LittleEndianConsts.SHORT_SIZE;
+          
+            len = LittleEndian.getInt(data, ofs);
+            ofs += LittleEndianConsts.INT_SIZE;\r
+            command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+            ofs += len;
+            
+            if (totalSize < ofs) {
+                throw new Ole10NativeException("Invalid Ole10Native");
+            }
+          
+            dataSize = LittleEndian.getInt(data, ofs);
+            ofs += LittleEndianConsts.INT_SIZE;
+          
+            if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
+                throw new Ole10NativeException("Invalid Ole10Native");
+            }\r
+            break;\r
+        }\r
+        case compact:\r
+            flags1 = LittleEndian.getShort(data, ofs);\r
+            ofs += LittleEndianConsts.SHORT_SIZE;\r
+            dataSize = totalSize - LittleEndianConsts.SHORT_SIZE;\r
+            break;\r
+        default:\r
+        case unparsed:\r
+            dataSize = totalSize;\r
+            break;\r
+        }
+        
+        dataBuffer = new byte[dataSize];
+        System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
+        ofs += dataSize;
+    }\r
 \r
-    if (data.length<offset+2) {\r
-      throw new Ole10NativeException("data is too small");\r
+    /*\r
+     * Helper - determine length of zero terminated string (ASCIIZ).\r
+     */\r
+    private static int getStringLength(byte[] data, int ofs) {\r
+        int len = 0;\r
+        while (len + ofs < data.length && data[ofs + len] != 0) {\r
+            len++;\r
+        }\r
+        len++;\r
+        return len;\r
     }\r
 \r
-    totalSize = LittleEndian.getInt(data, ofs);\r
-    ofs += LittleEndianConsts.INT_SIZE;\r
+    /**\r
+     * Returns the value of the totalSize field - the total length of the\r
+     * structure is totalSize + 4 (value of this field + size of this field).\r
+     * \r
+     * @return the totalSize\r
+     */\r
+    public int getTotalSize() {\r
+        return totalSize;\r
+    }\r
 \r
-    if (plain) {
-      dataBuffer = new byte[totalSize-4];
-      System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
-      // int dataSize = totalSize - 4;
-      
-      byte[] oleLabel = new byte[8];
-      System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
-      label = "ole-"+ HexDump.toHex(oleLabel);\r
-      fileName = label;\r
-      command = label;\r
-    } else {
-      flags1 = LittleEndian.getShort(data, ofs);
-      ofs += LittleEndianConsts.SHORT_SIZE;
-      
-      int len = getStringLength(data, ofs);
-      label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
-      ofs += len;
-      
-      len = getStringLength(data, ofs);
-      fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
-      ofs += len;
-      
-      flags2 = LittleEndian.getShort(data, ofs);
-      ofs += LittleEndianConsts.SHORT_SIZE;
-      
-      unknown1 = LittleEndian.getShort(data, ofs);
-      ofs += LittleEndianConsts.SHORT_SIZE;
-
-      len = LittleEndian.getInt(data, ofs);
-      ofs += LittleEndianConsts.INT_SIZE;
-
-      command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
-      ofs += len;
-      
-      if (totalSize < ofs) {
-          throw new Ole10NativeException("Invalid Ole10Native");
-      }
-
-      int dataSize = LittleEndian.getInt(data, ofs);
-      ofs += LittleEndianConsts.INT_SIZE;
-
-      if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
-          throw new Ole10NativeException("Invalid Ole10Native");
-      }
-      
-      dataBuffer = new byte[dataSize];
-      System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
-      ofs += dataSize;
-    }
-  }
-
-  /*\r
-   * Helper - determine length of zero terminated string (ASCIIZ).\r
-   */\r
-  private static int getStringLength(byte[] data, int ofs) {\r
-    int len = 0;\r
-    while (len+ofs<data.length && data[ofs + len] != 0) {\r
-      len++;\r
+    /**\r
+     * Returns flags1 - currently unknown - usually 0x0002.\r
+     * \r
+     * @return the flags1\r
+     */\r
+    public short getFlags1() {\r
+        return flags1;\r
     }\r
-    len++;\r
-    return len;\r
-  }\r
 \r
-  /**\r
-   * Returns the value of the totalSize field - the total length of the structure\r
-   * is totalSize + 4 (value of this field + size of this field).\r
-   *\r
-   * @return the totalSize\r
-   */\r
-  public int getTotalSize() {\r
-    return totalSize;\r
-  }\r
+    /**\r
+     * Returns the label field - usually the name of the file (without\r
+     * directory) but probably may be any name specified during\r
+     * packaging/embedding the data.\r
+     * \r
+     * @return the label\r
+     */\r
+    public String getLabel() {\r
+        return label;\r
+    }\r
 \r
-  /**\r
-   * Returns flags1 - currently unknown - usually 0x0002.\r
-   *\r
-   * @return the flags1\r
-   */\r
-  public short getFlags1() {\r
-    return flags1;\r
-  }\r
+    /**\r
+     * Returns the fileName field - usually the name of the file being embedded\r
+     * including the full path.\r
+     * \r
+     * @return the fileName\r
+     */\r
+    public String getFileName() {\r
+        return fileName;\r
+    }\r
 \r
-  /**\r
-   * Returns the label field - usually the name of the file (without directory) but\r
-   * probably may be any name specified during packaging/embedding the data.\r
-   *\r
-   * @return the label\r
-   */\r
-  public String getLabel() {\r
-    return label;\r
-  }\r
+    /**\r
+     * Returns flags2 - currently unknown - mostly 0x0000.\r
+     * \r
+     * @return the flags2\r
+     */\r
+    public short getFlags2() {\r
+        return flags2;\r
+    }\r
 \r
-  /**\r
-   * Returns the fileName field - usually the name of the file being embedded\r
-   * including the full path.\r
-   *\r
-   * @return the fileName\r
-   */\r
-  public String getFileName() {\r
-    return fileName;\r
-  }\r
+    /**\r
+     * Returns unknown1 field - currently unknown.\r
+     * \r
+     * @return the unknown1\r
+     */\r
+    public short getUnknown1() {\r
+        return unknown1;\r
+    }\r
 \r
-  /**\r
-   * Returns flags2 - currently unknown - mostly 0x0000.\r
-   *\r
-   * @return the flags2\r
-   */\r
-  public short getFlags2() {\r
-    return flags2;\r
-  }\r
+    /**\r
+     * Returns the command field - usually the name of the file being embedded\r
+     * including the full path, may be a command specified during embedding the\r
+     * file.\r
+     * \r
+     * @return the command\r
+     */\r
+    public String getCommand() {\r
+        return command;\r
+    }\r
 \r
-  /**\r
-   * Returns unknown1 field - currently unknown.\r
-   *
-   * @return the unknown1
-   */
-  public short getUnknown1() {
-    return unknown1;
-  }
-
-  /**
-   * Returns the command field - usually the name of the file being embedded
-   * including the full path, may be a command specified during embedding the file.
-   *
-   * @return the command\r
-   */\r
-  public String getCommand() {\r
-    return command;\r
-  }\r
+    /**\r
+     * Returns the size of the embedded file. If the size is 0 (zero), no data\r
+     * has been embedded. To be sure, that no data has been embedded, check\r
+     * whether {@link #getDataBuffer()} returns <code>null</code>.\r
+     * \r
+     * @return the dataSize\r
+     */\r
+    public int getDataSize() {\r
+        return dataBuffer.length;\r
+    }\r
 \r
-  /**\r
-   * Returns the size of the embedded file. If the size is 0 (zero), no data has been\r
-   * embedded. To be sure, that no data has been embedded, check whether\r
-   * {@link #getDataBuffer()} returns <code>null</code>.\r
-   *\r
-   * @return the dataSize
-   */
-  public int getDataSize() {
-    return dataBuffer.length;
-  }
-
-  /**
-   * Returns the buffer containing the embedded file's data, or <code>null</code>\r
-   * if no data was embedded. Note that an embedding may provide information about\r
-   * the data, but the actual data is not included. (So label, filename etc. are\r
-   * available, but this method returns <code>null</code>.)\r
-   *\r
-   * @return the dataBuffer\r
-   */\r
-  public byte[] getDataBuffer() {\r
-    return dataBuffer;\r
-  }\r
+    /**\r
+     * Returns the buffer containing the embedded file's data, or\r
+     * <code>null</code> if no data was embedded. Note that an embedding may\r
+     * provide information about the data, but the actual data is not included.\r
+     * (So label, filename etc. are available, but this method returns\r
+     * <code>null</code>.)\r
+     * \r
+     * @return the dataBuffer\r
+     */\r
+    public byte[] getDataBuffer() {\r
+        return dataBuffer;\r
+    }\r
 \r
-  /**\r
-   * Returns the flags3 - currently unknown.\r
-   *\r
-   * @return the flags3\r
-   */\r
-  public short getFlags3() {
-    return flags3;
-  }
-
-  /**
-   * Have the contents printer out into an OutputStream, used when writing a
-   * file back out to disk (Normally, atom classes will keep their bytes
-   * around, but non atom classes will just request the bytes from their
-   * children, then chuck on their header and return)
-   */
-  public void writeOut(OutputStream out) throws IOException {
-      byte intbuf[] = new byte[LittleEndianConsts.INT_SIZE];
-      byte shortbuf[] = new byte[LittleEndianConsts.SHORT_SIZE];
-
-      ByteArrayOutputStream bos = new ByteArrayOutputStream();
-      bos.write(intbuf); // total size, will be determined later ..
-
-      LittleEndian.putShort(shortbuf, 0, getFlags1());
-      bos.write(shortbuf);
-
-      bos.write(getLabel().getBytes(ISO1));
-      bos.write(0);
-
-      bos.write(getFileName().getBytes(ISO1));
-      bos.write(0);
-
-      LittleEndian.putShort(shortbuf, 0, getFlags2());
-      bos.write(shortbuf);
-
-      LittleEndian.putShort(shortbuf, 0, getUnknown1());
-      bos.write(shortbuf);
-
-      LittleEndian.putInt(intbuf, 0, getCommand().length()+1);
-      bos.write(intbuf);
-
-      bos.write(getCommand().getBytes(ISO1));
-      bos.write(0);
-
-      LittleEndian.putInt(intbuf, 0, getDataBuffer().length);
-      bos.write(intbuf);
-
-      bos.write(getDataBuffer());
-
-      LittleEndian.putShort(shortbuf, 0, getFlags3());
-      bos.write(shortbuf);
-
-      // update total size - length of length-field (4 bytes)
-      byte data[] = bos.toByteArray();
-      totalSize = data.length - LittleEndianConsts.INT_SIZE;
-      LittleEndian.putInt(data, 0, totalSize);
-
-      out.write(data);
-  }
-
-  public void setFlags1(short flags1) {
-      this.flags1 = flags1;
-  }
-
-  public void setFlags2(short flags2) {
-      this.flags2 = flags2;
-  }
-
-  public void setFlags3(short flags3) {
-      this.flags3 = flags3;
-  }
-
-  public void setLabel(String label) {
-      this.label = label;
-  }
-
-  public void setFileName(String fileName) {
-      this.fileName = fileName;
-  }
-
-  public void setCommand(String command) {
-      this.command = command;
-  }
-
-  public void setUnknown1(short unknown1) {
-      this.unknown1 = unknown1;
-  }
+    /**\r
+     * Returns the flags3 - currently unknown.\r
+     * \r
+     * @return the flags3\r
+     */\r
+    public short getFlags3() {\r
+        return flags3;\r
+    }\r
+\r
+    /**
+     * Have the contents printer out into an OutputStream, used when writing a
+     * file back out to disk (Normally, atom classes will keep their bytes
+     * around, but non atom classes will just request the bytes from their
+     * children, then chuck on their header and return)
+     */
+    public void writeOut(OutputStream out) throws IOException {\r
+        // byte intbuf[] = new byte[LittleEndianConsts.INT_SIZE];\r
+        // byte shortbuf[] = new byte[LittleEndianConsts.SHORT_SIZE];\r
+\r
+        @SuppressWarnings("resource")\r
+        LittleEndianOutputStream leosOut = new LittleEndianOutputStream(out);\r
+        \r
+        switch (mode) {\r
+        case parsed: {\r
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
+            LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);\r
+            // total size, will be determined later ..\r
+\r
+            leos.writeShort(getFlags1());\r
+            leos.write(getLabel().getBytes(ISO1));\r
+            leos.write(0);\r
+            leos.write(getFileName().getBytes(ISO1));\r
+            leos.write(0);\r
+            leos.writeShort(getFlags2());\r
+            leos.writeShort(getUnknown1());\r
+            leos.writeInt(getCommand().length() + 1);\r
+            leos.write(getCommand().getBytes(ISO1));\r
+            leos.write(0);\r
+            leos.writeInt(getDataSize());\r
+            leos.write(getDataBuffer());\r
+            leos.writeShort(getFlags3());\r
+            leos.close(); // satisfy compiler ...\r
+            \r
+            leosOut.writeInt(bos.size()); // total size\r
+            bos.writeTo(out);\r
+            break;\r
+        }\r
+        case compact:\r
+            leosOut.writeInt(getDataSize()+LittleEndianConsts.SHORT_SIZE);\r
+            leosOut.writeShort(getFlags1());\r
+            out.write(getDataBuffer());\r
+            break;\r
+        default:\r
+        case unparsed:\r
+            leosOut.writeInt(getDataSize());\r
+            out.write(getDataBuffer());\r
+            break;\r
+        }\r
+\r
+    }\r
 
-  public void setDataBuffer(byte dataBuffer[]) {
-      this.dataBuffer = dataBuffer;
-  }
+    public void setFlags1(short flags1) {\r
+        this.flags1 = flags1;\r
+    }\r
+\r
+    public void setFlags2(short flags2) {\r
+        this.flags2 = flags2;\r
+    }\r
+\r
+    public void setFlags3(short flags3) {\r
+        this.flags3 = flags3;\r
+    }\r
+\r
+    public void setLabel(String label) {\r
+        this.label = label;\r
+    }\r
+\r
+    public void setFileName(String fileName) {\r
+        this.fileName = fileName;\r
+    }\r
+\r
+    public void setCommand(String command) {\r
+        this.command = command;\r
+    }\r
+\r
+    public void setUnknown1(short unknown1) {\r
+        this.unknown1 = unknown1;\r
+    }\r
+\r
+    public void setDataBuffer(byte dataBuffer[]) {\r
+        this.dataBuffer = dataBuffer;\r
+    }\r
 }
index d4f81f7ee22295b542ce92767aa3700877abdb0e..012cc3b644605f7a54af6ef056bf036d9dcecb44 100644 (file)
 
 package org.apache.poi.poifs;
 
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
 import org.apache.poi.poifs.eventfilesystem.TestPOIFSReaderRegistry;
 import org.apache.poi.poifs.filesystem.AllPOIFSFileSystemTests;
 import org.apache.poi.poifs.nio.TestDataSource;
 import org.apache.poi.poifs.property.AllPOIFSPropertyTests;
 import org.apache.poi.poifs.storage.AllPOIFSStorageTests;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
 /**
  * Test suite for all sub-packages of org.apache.poi.poifs
- * 
- * @author Josh Micich
  */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+      TestPOIFSReaderRegistry.class
+    , TestDataSource.class
+    , AllPOIFSFileSystemTests.class
+    , AllPOIFSPropertyTests.class
+    , AllPOIFSStorageTests.class
+})
 public final class AllPOIFSTests {
-    public static Test suite() {
-        TestSuite result = new TestSuite("Tests for org.apache.poi.poifs");
-        result.addTestSuite(TestPOIFSReaderRegistry.class);
-        result.addTestSuite(TestDataSource.class);
-        result.addTest(AllPOIFSFileSystemTests.suite());
-        result.addTest(AllPOIFSPropertyTests.suite());
-        result.addTest(AllPOIFSStorageTests.suite());
-        return result;
-    }
 }
index bc46e17c9ab6fb66c55fd75f50884c40e963cb14..364aa1a6e20fa5b43aafc55238d7eb08b4ca3afb 100644 (file)
 
 package org.apache.poi.poifs.filesystem;
 
-import junit.framework.Test;
-import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
 
 /**
  * Tests for org.apache.poi.poifs.filesystem<br/>
- *
- * @author Josh Micich
  */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+      TestDirectoryNode.class
+    , TestDocument.class
+    , TestDocumentDescriptor.class
+    , TestDocumentInputStream.class
+    , TestDocumentNode.class
+    , TestDocumentOutputStream.class
+    , TestEmptyDocument.class
+    , TestOffice2007XMLException.class
+    , TestPOIFSDocumentPath.class
+    , TestPOIFSFileSystem.class
+    , TestNPOIFSFileSystem.class
+    , TestPropertySorter.class
+    , TestOle10Native.class
+})
 public final class AllPOIFSFileSystemTests {
-
-    public static Test suite() {
-        TestSuite result = new TestSuite("Tests for org.apache.poi.poifs.filesystem");
-        result.addTestSuite(TestDirectoryNode.class);
-        result.addTestSuite(TestDocument.class);
-        result.addTestSuite(TestDocumentDescriptor.class);
-        result.addTestSuite(TestDocumentInputStream.class);
-        result.addTestSuite(TestDocumentNode.class);
-        result.addTestSuite(TestDocumentOutputStream.class);
-        result.addTestSuite(TestEmptyDocument.class);
-        result.addTestSuite(TestOffice2007XMLException.class);
-        result.addTestSuite(TestPOIFSDocumentPath.class);
-        result.addTestSuite(TestPOIFSFileSystem.class);
-        result.addTestSuite(TestNPOIFSFileSystem.class);
-        result.addTestSuite(TestPropertySorter.class);
-        result.addTestSuite(TestOle10Native.class);
-        return result;
-    }
 }
index 1ff45be73fc0cea56d64b1b330438b4b63c92e4e..32f0f96ab62ad0ae0af07dc531f55ba6ce06dbfe 100644 (file)
 
 package org.apache.poi.poifs.filesystem;
 
-import junit.framework.TestCase;
-import org.apache.poi.POIDataSamples;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
+import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.util.IOUtils;
+import org.junit.Test;
 
-public class TestOle10Native extends TestCase {
+public class TestOle10Native {
     private static final POIDataSamples dataSamples = POIDataSamples.getPOIFSInstance();
 
+    @Test
     public void testOleNative() throws IOException, Ole10NativeException {
         POIFSFileSystem fs = new POIFSFileSystem(dataSamples.openResourceAsStream("oleObject1.bin"));
 
@@ -33,4 +45,66 @@ public class TestOle10Native extends TestCase {
         assertEquals("File1.svg", ole.getLabel());
         assertEquals("D:\\Documents and Settings\\rsc\\My Documents\\file1.svg", ole.getCommand());
     }
+
+    @Test
+    public void testFiles() throws IOException, Ole10NativeException {
+        File files[] = {
+            // bug 51891
+            POIDataSamples.getPOIFSInstance().getFile("multimedia.doc"),
+            // tika bug 1072
+            POIDataSamples.getPOIFSInstance().getFile("20-Force-on-a-current-S00.doc"),
+            // other files containing ole10native records ...
+            POIDataSamples.getDocumentInstance().getFile("Bug53380_3.doc"),
+            POIDataSamples.getDocumentInstance().getFile("Bug47731.doc")
+        };
+        
+        for (File f : files) {
+            NPOIFSFileSystem fs = new NPOIFSFileSystem(f, true);
+            List<Entry> entries = new ArrayList<Entry>();
+            findOle10(entries, fs.getRoot(), "/", "");
+            
+            for (Entry e : entries) {
+                ByteArrayOutputStream bosExp = new ByteArrayOutputStream();
+                InputStream is = ((DirectoryNode)e.getParent()).createDocumentInputStream(e);
+                IOUtils.copy(is,bosExp);
+                is.close();
+                
+                Ole10Native ole = Ole10Native.createFromEmbeddedOleObject((DirectoryNode)e.getParent());
+                
+                ByteArrayOutputStream bosAct = new ByteArrayOutputStream();
+                ole.writeOut(bosAct);
+                
+                assertThat(bosExp.toByteArray(), equalTo(bosAct.toByteArray()));
+            }
+            
+            fs.close();
+        }
+    }
+
+    /*
+    void searchOle10Files() throws Exception {
+        File dir = new File("test-data/document");
+        for (File file : dir.listFiles(new FileFilter(){
+            public boolean accept(File pathname) {
+                return pathname.getName().endsWith("doc");
+            }
+        })) {
+            NPOIFSFileSystem fs = new NPOIFSFileSystem(file, true);
+            findOle10(null, fs.getRoot(), "/", file.getName());
+            fs.close();
+        }
+    }*/
+    
+    void findOle10(List<Entry> entries, DirectoryNode dn, String path, String filename) {
+        Iterator<Entry> iter = dn.getEntries();
+        while (iter.hasNext()) {
+            Entry e = iter.next();
+            if (Ole10Native.OLE10_NATIVE.equals(e.getName())) {
+                if (entries != null) entries.add(e);
+                // System.out.println(filename+" : "+path);
+            } else if (e.isDirectoryEntry()) {
+                findOle10(entries, (DirectoryNode)e, path+e.getName()+"/", filename);
+            }
+        }
+    }
 }
diff --git a/test-data/poifs/20-Force-on-a-current-S00.doc b/test-data/poifs/20-Force-on-a-current-S00.doc
new file mode 100644 (file)
index 0000000..3ad75eb
Binary files /dev/null and b/test-data/poifs/20-Force-on-a-current-S00.doc differ
diff --git a/test-data/poifs/multimedia.doc b/test-data/poifs/multimedia.doc
new file mode 100644 (file)
index 0000000..51b356d
Binary files /dev/null and b/test-data/poifs/multimedia.doc differ