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 2014/02/01 22:45:49 UTC

svn commit: r1563483 - in /poi: site/src/documentation/content/xdocs/ trunk/src/java/org/apache/poi/hpsf/ trunk/src/java/org/apache/poi/poifs/filesystem/ trunk/src/testcases/org/apache/poi/poifs/ trunk/src/testcases/org/apache/poi/poifs/filesystem/ tru...

Author: kiwiwings
Date: Sat Feb  1 21:45:48 2014
New Revision: 1563483

URL: http://svn.apache.org/r1563483
Log:
Bug 51891 - Fix StringIndexOutOfBoundsException : Ole10Native.<init> (parsing word file)

Added:
    poi/trunk/test-data/poifs/20-Force-on-a-current-S00.doc   (with props)
    poi/trunk/test-data/poifs/multimedia.doc   (with props)
Modified:
    poi/site/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
    poi/trunk/src/testcases/org/apache/poi/poifs/AllPOIFSTests.java
    poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java
    poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java

Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1563483&r1=1563482&r2=1563483&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Sat Feb  1 21:45:48 2014
@@ -36,6 +36,7 @@
 
     <changes>
         <release version="3.11-beta1" date="2014-??-??">
+          <action dev="poi-developers" type="fix">51891 - Fix StringIndexOutOfBoundsException : Ole10Native.<init> (parsing word file)</action>
         </release>
         <release version="3.10-FINAL" date="2014-02-08">
           <action dev="poi-developers" type="fix">51585 - WorkbookFactory.create() hangs when creating a workbook</action>

Modified: poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java?rev=1563483&r1=1563482&r2=1563483&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java Sat Feb  1 21:45:48 2014
@@ -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}");
 	
 	
     /**

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java?rev=1563483&r1=1563482&r2=1563483&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java Sat Feb  1 21:45:48 2014
@@ -17,14 +17,13 @@
 
 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;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianOutputStream;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -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.
-   *
-   * @param poifs POI Filesystem object
-   * @return Returns an instance of this class
-   * @throws IOException on IO error
-   * @throws Ole10NativeException on invalid or unexcepted data format
-   */
-  public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
-     return createFromEmbeddedOleObject(poifs.getRoot());
-  }
-  
-  /**
-   * 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.
-   *
-   * @param directory POI Filesystem object
-   * @return Returns an instance of this class
-   * @throws IOException on IO error
-   * @throws Ole10NativeException on invalid or unexcepted data format
-   */
-  public static Ole10Native createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {
-     boolean plain = false;
-
-     try {
-        directory.getEntry("\u0001Ole10ItemName");
-        plain = true;
-     } catch (FileNotFoundException ex) {
-        plain = false;
-     }
-     
-     DocumentEntry nativeEntry = 
-        (DocumentEntry)directory.getEntry(OLE10_NATIVE);
-     byte[] data = new byte[nativeEntry.getSize()];
-     directory.createDocumentInputStream(nativeEntry).read(data);
-
-     return new Ole10Native(data, 0, plain);
-  }
+    public static final String OLE10_NATIVE = "\u0001Ole10Native";
+    protected static final String ISO1 = "ISO-8859-1";
   
-  /**
-   * 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);
-  }
+    // (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 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
-   * @throws Ole10NativeException on invalid or unexcepted data format
-   */
-  public Ole10Native(byte[] data, int offset) throws Ole10NativeException {
-    this(data, offset, false);
-  }
-  /**
-   * 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
-   * @param plain Specified 'plain' format without filename
-   * @throws Ole10NativeException on invalid or unexcepted data format
-   */
-  public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {
-    int ofs = offset;        // current offset, initialized to start
-
-    if (data.length<offset+2) {
-      throw new Ole10NativeException("data is too small");
-    }
-
-    totalSize = LittleEndian.getInt(data, ofs);
-    ofs += LittleEndianConsts.INT_SIZE;
-
-    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);
-      fileName = label;
-      command = label;
-    } 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;
+    /**
+     * the field encoding mode - merely a try-and-error guess ...
+     **/ 
+    private enum EncodingMode {
+        /**
+         * the data is stored in parsed format - including label, command, etc.
+         */
+        parsed,
+        /**
+         * the data is stored raw after the length field
+         */
+        unparsed,
+        /**
+         * the data is stored raw after the length field and the flags1 field
+         */
+        compact;
+    }
+    
+    private EncodingMode mode;
+
+    
+    
+    /**
+     * 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.
+     *
+     * @param poifs POI Filesystem object
+     * @return Returns an instance of this class
+     * @throws IOException on IO error
+     * @throws Ole10NativeException on invalid or unexcepted data format
+     */
+    public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
+       return createFromEmbeddedOleObject(poifs.getRoot());
+    }
+    
+    /**
+     * 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.
+     *
+     * @param directory POI Filesystem object
+     * @return Returns an instance of this class
+     * @throws IOException on IO error
+     * @throws Ole10NativeException on invalid or unexcepted data format
+     */
+    public static Ole10Native createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {
+       DocumentEntry nativeEntry = 
+          (DocumentEntry)directory.getEntry(OLE10_NATIVE);
+       byte[] data = new byte[nativeEntry.getSize()];
+       directory.createDocumentInputStream(nativeEntry).read(data);
+  
+       return new Ole10Native(data, 0);
     }
-  }
-
-  /*
-   * Helper - determine length of zero terminated string (ASCIIZ).
-   */
-  private static int getStringLength(byte[] data, int ofs) {
-    int len = 0;
-    while (len+ofs<data.length && data[ofs + len] != 0) {
-      len++;
-    }
-    len++;
-    return len;
-  }
-
-  /**
-   * Returns the value of the totalSize field - the total length of the structure
-   * is totalSize + 4 (value of this field + size of this field).
-   *
-   * @return the totalSize
-   */
-  public int getTotalSize() {
-    return totalSize;
-  }
-
-  /**
-   * Returns flags1 - currently unknown - usually 0x0002.
-   *
-   * @return the flags1
-   */
-  public short getFlags1() {
-    return flags1;
-  }
-
-  /**
-   * Returns the label field - usually the name of the file (without directory) but
-   * probably may be any name specified during packaging/embedding the data.
-   *
-   * @return the label
-   */
-  public String getLabel() {
-    return label;
-  }
-
-  /**
-   * Returns the fileName field - usually the name of the file being embedded
-   * including the full path.
-   *
-   * @return the fileName
-   */
-  public String getFileName() {
-    return fileName;
-  }
-
-  /**
-   * Returns flags2 - currently unknown - mostly 0x0000.
-   *
-   * @return the flags2
-   */
-  public short getFlags2() {
-    return flags2;
-  }
-
-  /**
-   * Returns unknown1 field - currently unknown.
-   *
-   * @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
-   */
-  public String getCommand() {
-    return command;
-  }
-
-  /**
-   * Returns the size of the embedded file. If the size is 0 (zero), no data has been
-   * embedded. To be sure, that no data has been embedded, check whether
-   * {@link #getDataBuffer()} returns <code>null</code>.
-   *
-   * @return the dataSize
-   */
-  public int getDataSize() {
-    return dataBuffer.length;
-  }
-
-  /**
-   * Returns the buffer containing the embedded file's data, or <code>null</code>
-   * if no data was embedded. Note that an embedding may provide information about
-   * the data, but the actual data is not included. (So label, filename etc. are
-   * available, but this method returns <code>null</code>.)
-   *
-   * @return the dataBuffer
-   */
-  public byte[] getDataBuffer() {
-    return dataBuffer;
-  }
-
-  /**
-   * Returns the flags3 - currently unknown.
-   *
-   * @return the flags3
-   */
-  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;
-  }
+    
+    /**
+     * 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);
+       mode = EncodingMode.parsed;
+    }
+
+    /**
+     * 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
+     * @param plain as of POI 3.11 this parameter is ignored
+     * @throws Ole10NativeException on invalid or unexcepted data format
+     * 
+     * @deprecated parameter plain is ignored, use {@link #Ole10Native(byte[],int)}
+     */
+    public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {
+        this(data, offset);
+    }
+    
+    /**
+     * 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
+     * @throws Ole10NativeException on invalid or unexcepted data format
+     */
+    public Ole10Native(byte[] data, int offset) throws Ole10NativeException {
+        int ofs = offset; // current offset, initialized to start
+        
+        if (data.length < offset + 2) {
+            throw new Ole10NativeException("data is too small");
+        }
+        
+        totalSize = LittleEndian.getInt(data, ofs);
+        ofs += LittleEndianConsts.INT_SIZE;
+        
+        mode = EncodingMode.unparsed;
+        if (LittleEndian.getShort(data, ofs) == 2) {
+            // some files like equations don't have a valid filename,
+            // but somehow encode the formula right away in the ole10 header
+            if (Character.isISOControl(data[ofs+LittleEndianConsts.SHORT_SIZE])) {
+                mode = EncodingMode.compact;
+            } else {
+                mode = EncodingMode.parsed;
+            }
+        }
+
+        int dataSize;
+        switch (mode) {
+        case parsed: {
+            flags1 = LittleEndian.getShort(data, ofs);
+            
+            // structured format
+            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");
+            }
+          
+            dataSize = LittleEndian.getInt(data, ofs);
+            ofs += LittleEndianConsts.INT_SIZE;
+          
+            if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
+                throw new Ole10NativeException("Invalid Ole10Native");
+            }
+            break;
+        }
+        case compact:
+            flags1 = LittleEndian.getShort(data, ofs);
+            ofs += LittleEndianConsts.SHORT_SIZE;
+            dataSize = totalSize - LittleEndianConsts.SHORT_SIZE;
+            break;
+        default:
+        case unparsed:
+            dataSize = totalSize;
+            break;
+        }
+        
+        dataBuffer = new byte[dataSize];
+        System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
+        ofs += dataSize;
+    }
+
+    /*
+     * Helper - determine length of zero terminated string (ASCIIZ).
+     */
+    private static int getStringLength(byte[] data, int ofs) {
+        int len = 0;
+        while (len + ofs < data.length && data[ofs + len] != 0) {
+            len++;
+        }
+        len++;
+        return len;
+    }
+
+    /**
+     * Returns the value of the totalSize field - the total length of the
+     * structure is totalSize + 4 (value of this field + size of this field).
+     * 
+     * @return the totalSize
+     */
+    public int getTotalSize() {
+        return totalSize;
+    }
+
+    /**
+     * Returns flags1 - currently unknown - usually 0x0002.
+     * 
+     * @return the flags1
+     */
+    public short getFlags1() {
+        return flags1;
+    }
+
+    /**
+     * Returns the label field - usually the name of the file (without
+     * directory) but probably may be any name specified during
+     * packaging/embedding the data.
+     * 
+     * @return the label
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Returns the fileName field - usually the name of the file being embedded
+     * including the full path.
+     * 
+     * @return the fileName
+     */
+    public String getFileName() {
+        return fileName;
+    }
+
+    /**
+     * Returns flags2 - currently unknown - mostly 0x0000.
+     * 
+     * @return the flags2
+     */
+    public short getFlags2() {
+        return flags2;
+    }
+
+    /**
+     * Returns unknown1 field - currently unknown.
+     * 
+     * @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
+     */
+    public String getCommand() {
+        return command;
+    }
+
+    /**
+     * Returns the size of the embedded file. If the size is 0 (zero), no data
+     * has been embedded. To be sure, that no data has been embedded, check
+     * whether {@link #getDataBuffer()} returns <code>null</code>.
+     * 
+     * @return the dataSize
+     */
+    public int getDataSize() {
+        return dataBuffer.length;
+    }
+
+    /**
+     * Returns the buffer containing the embedded file's data, or
+     * <code>null</code> if no data was embedded. Note that an embedding may
+     * provide information about the data, but the actual data is not included.
+     * (So label, filename etc. are available, but this method returns
+     * <code>null</code>.)
+     * 
+     * @return the dataBuffer
+     */
+    public byte[] getDataBuffer() {
+        return dataBuffer;
+    }
+
+    /**
+     * Returns the flags3 - currently unknown.
+     * 
+     * @return the flags3
+     */
+    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];
+
+        @SuppressWarnings("resource")
+        LittleEndianOutputStream leosOut = new LittleEndianOutputStream(out);
+        
+        switch (mode) {
+        case parsed: {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
+            // total size, will be determined later ..
+
+            leos.writeShort(getFlags1());
+            leos.write(getLabel().getBytes(ISO1));
+            leos.write(0);
+            leos.write(getFileName().getBytes(ISO1));
+            leos.write(0);
+            leos.writeShort(getFlags2());
+            leos.writeShort(getUnknown1());
+            leos.writeInt(getCommand().length() + 1);
+            leos.write(getCommand().getBytes(ISO1));
+            leos.write(0);
+            leos.writeInt(getDataSize());
+            leos.write(getDataBuffer());
+            leos.writeShort(getFlags3());
+            leos.close(); // satisfy compiler ...
+            
+            leosOut.writeInt(bos.size()); // total size
+            bos.writeTo(out);
+            break;
+        }
+        case compact:
+            leosOut.writeInt(getDataSize()+LittleEndianConsts.SHORT_SIZE);
+            leosOut.writeShort(getFlags1());
+            out.write(getDataBuffer());
+            break;
+        default:
+        case unparsed:
+            leosOut.writeInt(getDataSize());
+            out.write(getDataBuffer());
+            break;
+        }
+
+    }
 
-  public void setDataBuffer(byte dataBuffer[]) {
-      this.dataBuffer = dataBuffer;
-  }
+    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;
+    }
+
+    public void setDataBuffer(byte dataBuffer[]) {
+        this.dataBuffer = dataBuffer;
+    }
 }

Modified: poi/trunk/src/testcases/org/apache/poi/poifs/AllPOIFSTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/AllPOIFSTests.java?rev=1563483&r1=1563482&r2=1563483&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/poifs/AllPOIFSTests.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/poifs/AllPOIFSTests.java Sat Feb  1 21:45:48 2014
@@ -17,27 +17,24 @@
 
 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;
-    }
 }

Modified: poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java?rev=1563483&r1=1563482&r2=1563483&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java Sat Feb  1 21:45:48 2014
@@ -17,31 +17,27 @@
 
 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;
-    }
 }

Modified: poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java?rev=1563483&r1=1563482&r2=1563483&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java Sat Feb  1 21:45:48 2014
@@ -17,14 +17,26 @@
 
 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 Tes
         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);
+            }
+        }
+    }
 }

Added: poi/trunk/test-data/poifs/20-Force-on-a-current-S00.doc
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/poifs/20-Force-on-a-current-S00.doc?rev=1563483&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/poifs/20-Force-on-a-current-S00.doc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: poi/trunk/test-data/poifs/multimedia.doc
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/poifs/multimedia.doc?rev=1563483&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/poifs/multimedia.doc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



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