Author: kiwiwings
Date: Sun May 14 22:25:33 2017
New Revision: 1795123

URL: http://svn.apache.org/viewvc?rev=1795123&view=rev
Log:
#52117 - Invalid "last printed" summary field value - added helper method to 
identify undefined dates
HPSF: fixed uid listing in Section.toString()
HPSF: moved timestamp based "utility" methods to Filetime class
HPSF: preserve original datastream for unchanged property sets

Removed:
    poi/trunk/src/java/org/apache/poi/hpsf/Util.java
Modified:
    poi/site/src/documentation/content/xdocs/status.xml
    poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java
    
poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java
    poi/trunk/src/java/org/apache/poi/hpsf/Filetime.java
    poi/trunk/src/java/org/apache/poi/hpsf/Property.java
    poi/trunk/src/java/org/apache/poi/hpsf/PropertySet.java
    poi/trunk/src/java/org/apache/poi/hpsf/Section.java
    poi/trunk/src/java/org/apache/poi/hpsf/SummaryInformation.java
    poi/trunk/src/java/org/apache/poi/hpsf/VariantSupport.java
    poi/trunk/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
    poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java
    poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java
    poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java
    poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
    poi/trunk/src/testcases/org/apache/poi/hpsf/basic/Util.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=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Sun May 14 22:25:33 2017
@@ -58,6 +58,7 @@
 
     <release version="3.17-beta1" date="2017-07-??">
       <actions>
+        <action dev="PD" type="fix" fixes-bug="52117" module="HPSF">Invalid 
"last printed" summary field value</action>
         <action dev="PD" type="fix" fixes-bug="60352" module="XSSF">Text 
extraction: Don't include the text "null" for empty cells</action>
         <action dev="PD" type="fix" fixes-bug="52372" 
module="HPSF">OutOfMemoryError parsing a word file</action>
         <action dev="PD" type="fix" fixes-bug="61062" module="HPSF">Various 
HPSF related fixes</action>

Modified: 
poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java 
(original)
+++ poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java 
Sun May 14 22:25:33 2017
@@ -36,7 +36,6 @@ import org.apache.poi.hpsf.MutableProper
 import org.apache.poi.hpsf.NoPropertySetStreamException;
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.Util;
 import org.apache.poi.hpsf.WritingNotSupportedException;
 import org.apache.poi.poifs.eventfilesystem.POIFSReader;
 import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
@@ -352,13 +351,11 @@ public class CopyCompare
 
             /* According to the definition of the processPOIFSReaderEvent 
method
              * we cannot pass checked exceptions to the caller. The following
-             * lines check whether a checked exception occured and throws an
+             * lines check whether a checked exception occurred and throws an
              * unchecked exception. The message of that exception is that of
              * the underlying checked exception. */
             if (t != null) {
-                throw new HPSFRuntimeException
-                    ("Could not read file \"" + path + "/" + name +
-                     "\". Reason: " + Util.toString(t));
+                throw new HPSFRuntimeException("Could not read file \"" + path 
+ "/" + name, t);
             }
         }
 

Modified: 
poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- 
poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java
 (original)
+++ 
poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java
 Sun May 14 22:25:33 2017
@@ -36,7 +36,6 @@ import org.apache.poi.hpsf.NoPropertySet
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.PropertySetFactory;
 import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.Util;
 import org.apache.poi.hpsf.Variant;
 import org.apache.poi.hpsf.WritingNotSupportedException;
 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
@@ -211,9 +210,7 @@ public class WriteAuthorAndTitle
              * unchecked exception. The message of that exception is that of
              * the underlying checked exception. */
             if (t != null) {
-                throw new HPSFRuntimeException
-                    ("Could not read file \"" + path + "/" + name +
-                     "\". Reason: " + Util.toString(t));
+                throw new HPSFRuntimeException("Could not read file \"" + path 
+ "/" + name, t);
             }
         }
 

Modified: poi/trunk/src/java/org/apache/poi/hpsf/Filetime.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/Filetime.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/Filetime.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/Filetime.java Sun May 14 22:25:33 
2017
@@ -18,24 +18,40 @@ package org.apache.poi.hpsf;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.Date;
 
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
 
-class Filetime {
-    private static final int SIZE = LittleEndian.INT_SIZE * 2;
+public class Filetime {
+    /**
+     * The difference between the Windows epoch (1601-01-01
+     * 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in
+     * milliseconds.
+     */
+    private static final long EPOCH_DIFF = -11644473600000L;
 
+    private static final int SIZE = LittleEndian.INT_SIZE * 2;
+    private static final long UINT_MASK = 0x00000000FFFFFFFFL;
+    private static final long NANO_100 = 1000L * 10L;
+    
     private int _dwHighDateTime;
     private int _dwLowDateTime;
-    
-    Filetime() {}
 
+    Filetime() {}
+    
     Filetime( int low, int high ) {
         _dwLowDateTime = low;
         _dwHighDateTime = high;
     }
 
+    Filetime( Date date ) {
+        long filetime = Filetime.dateToFileTime(date);
+        _dwHighDateTime = (int) ((filetime >>> 32) & UINT_MASK);
+        _dwLowDateTime = (int) (filetime & UINT_MASK);
+    }
+    
 
     void read( LittleEndianByteArrayInputStream lei ) {
         _dwLowDateTime = lei.readInt();
@@ -53,8 +69,7 @@ class Filetime {
     byte[] toByteArray() {
         byte[] result = new byte[SIZE];
         LittleEndian.putInt( result, 0 * LittleEndianConsts.INT_SIZE, 
_dwLowDateTime );
-        LittleEndian
-                .putInt( result, 1 * LittleEndianConsts.INT_SIZE, 
_dwHighDateTime );
+        LittleEndian.putInt( result, 1 * LittleEndianConsts.INT_SIZE, 
_dwHighDateTime );
         return result;
     }
 
@@ -63,4 +78,49 @@ class Filetime {
         LittleEndian.putInt( _dwHighDateTime, out );
         return SIZE;
     }
+
+    Date getJavaValue() {
+        long l = (((long)_dwHighDateTime) << 32) | (_dwLowDateTime & 
UINT_MASK);
+        return filetimeToDate( l );
+    }
+    
+    /**
+     * Converts a Windows FILETIME into a {@link Date}. The Windows
+     * FILETIME structure holds a date and time associated with a
+     * file. The structure identifies a 64-bit integer specifying the
+     * number of 100-nanosecond intervals which have passed since
+     * January 1, 1601.
+     *
+     * @param filetime The filetime to convert.
+     * @return The Windows FILETIME as a {@link Date}.
+     */
+    public static Date filetimeToDate(final long filetime) {
+        final long ms_since_16010101 = filetime / NANO_100;
+        final long ms_since_19700101 = ms_since_16010101 + EPOCH_DIFF;
+        return new Date(ms_since_19700101);
+    }
+
+    /**
+     * Converts a {@link Date} into a filetime.
+     *
+     * @param date The date to be converted
+     * @return The filetime
+     *
+     * @see #filetimeToDate(long)
+     */
+    public static long dateToFileTime(final Date date) {
+        long ms_since_19700101 = date.getTime();
+        long ms_since_16010101 = ms_since_19700101 - EPOCH_DIFF;
+        return ms_since_16010101 * NANO_100;
+    }
+    
+    /**
+     * Return {@code true} if the date is undefined
+     *
+     * @param date the date
+     * @return {@code true} if the date is undefined
+     */
+    public static boolean isUndefined(Date date) {
+        return (date == null || dateToFileTime(date) == 0);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hpsf/Property.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/Property.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/Property.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/Property.java Sun May 14 22:25:33 
2017
@@ -22,7 +22,11 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
-import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+import javax.xml.bind.DatatypeConverter;
 
 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
 import org.apache.poi.util.CodePageUtil;
@@ -377,15 +381,18 @@ public class Property {
      */
     @Override
     public String toString() {
-        return toString(Property.DEFAULT_CODEPAGE);
+        return toString(Property.DEFAULT_CODEPAGE, null);
     }
     
-    public String toString(int codepage) {
-        final StringBuffer b = new StringBuffer();
+    public String toString(int codepage, PropertyIDMap idMap) {
+        final StringBuilder b = new StringBuilder();
         b.append("Property[");
         b.append("id: ");
-        b.append(getID());
-        String idName = getNameFromID();
+        b.append(id);
+        String idName = (idMap == null) ? null : idMap.get(id);
+        if (idName == null) {
+            idName = PropertyIDMap.getFallbackProperties().get(id);
+        }
         if (idName != null) {
             b.append(" (");
             b.append(idName);
@@ -399,6 +406,7 @@ public class Property {
         final Object value = getValue();
         b.append(", value: ");
         if (value instanceof String) {
+            b.append((String)value);
             b.append("\n");
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             try {
@@ -407,13 +415,11 @@ public class Property {
                 LOG.log(POILogger.WARN, "can't serialize string", e);
             }
             
-            b.append(" [");
             // skip length field
             if(bos.size() > 2*LittleEndianConsts.INT_SIZE) {
                 final String hex = HexDump.dump(bos.toByteArray(), 
-2*LittleEndianConsts.INT_SIZE, 2*LittleEndianConsts.INT_SIZE);
                 b.append(hex);
             }
-            b.append("]");
         } else if (value instanceof byte[]) {
             b.append("\n");
             byte[] bytes = (byte[])value;
@@ -421,7 +427,32 @@ public class Property {
                 String hex = HexDump.dump(bytes, 0L, 0);
                 b.append(hex);
             }
-        } else if (type == Variant.VT_EMPTY || type == Variant.VT_NULL) {
+        } else if (value instanceof java.util.Date) {
+            java.util.Date d = (java.util.Date)value;
+            long filetime = Filetime.dateToFileTime(d);
+            if (Filetime.isUndefined(d)) {
+                b.append("<undefined>");
+            } else if ((filetime >>> 32) == 0) {
+                // if the upper dword isn't set, we deal with time intervals
+                long l = filetime*100;
+                TimeUnit tu = TimeUnit.NANOSECONDS;
+                final long hr  = tu.toHours(l);
+                l -= TimeUnit.HOURS.toNanos(hr);
+                final long min = tu.toMinutes(l);
+                l -= TimeUnit.MINUTES.toNanos(min);
+                final long sec = tu.toSeconds(l);
+                l -= TimeUnit.SECONDS.toNanos(sec);
+                final long ms  = tu.toMillis(l);
+                
+                String str = String.format(Locale.ROOT, 
"%02d:%02d:%02d.%03d",hr,min,sec,ms);
+                b.append(str);
+            } else {
+                Calendar cal = Calendar.getInstance(LocaleUtil.TIMEZONE_UTC, 
Locale.ROOT);
+                cal.setTime(d);
+                // use ISO-8601 timestamp format
+                b.append(DatatypeConverter.printDateTime(cal));
+            }
+        } else if (type == Variant.VT_EMPTY || type == Variant.VT_NULL || 
value == null) {
             b.append("null");
         } else {
             b.append(value.toString());
@@ -458,45 +489,6 @@ public class Property {
         return null;
     }
     
-    private String getNameFromID() {
-        switch ((int)getID()) {
-        case PropertyIDMap.PID_DICTIONARY: return "PID_DICTIONARY";
-        case PropertyIDMap.PID_CODEPAGE: return "PID_CODEPAGE";
-        case PropertyIDMap.PID_CATEGORY: return "PID_CATEGORY";
-        case PropertyIDMap.PID_PRESFORMAT: return "PID_PRESFORMAT";
-        case PropertyIDMap.PID_BYTECOUNT: return "PID_BYTECOUNT";
-        case PropertyIDMap.PID_LINECOUNT: return "PID_LINECOUNT";
-        case PropertyIDMap.PID_PARCOUNT: return "PID_PARCOUNT";
-        case PropertyIDMap.PID_SLIDECOUNT: return "PID_SLIDECOUNT";
-        case PropertyIDMap.PID_NOTECOUNT: return "PID_NOTECOUNT";
-        case PropertyIDMap.PID_HIDDENCOUNT: return "PID_HIDDENCOUNT";
-        case PropertyIDMap.PID_MMCLIPCOUNT: return "PID_MMCLIPCOUNT";
-        case PropertyIDMap.PID_SCALE: return "PID_SCALE";
-        case PropertyIDMap.PID_HEADINGPAIR: return "PID_HEADINGPAIR";
-        case PropertyIDMap.PID_DOCPARTS: return "PID_DOCPARTS";
-        case PropertyIDMap.PID_MANAGER: return "PID_MANAGER";
-        case PropertyIDMap.PID_COMPANY: return "PID_COMPANY";
-        case PropertyIDMap.PID_LINKSDIRTY: return "PID_LINKSDIRTY";
-        case PropertyIDMap.PID_CCHWITHSPACES: return "PID_CCHWITHSPACES";
-        // 0x12 Unused
-        // 0x13 GKPIDDSI_SHAREDDOC - Must be False
-        // 0x14 GKPIDDSI_LINKBASE - Must not be written
-        // 0x15 GKPIDDSI_HLINKS - Must not be written
-        case PropertyIDMap.PID_HYPERLINKSCHANGED: return 
"PID_HYPERLINKSCHANGED";
-        case PropertyIDMap.PID_VERSION: return "PID_VERSION";
-        case PropertyIDMap.PID_DIGSIG: return "PID_DIGSIG";
-        // 0x19 Unused
-        case PropertyIDMap.PID_CONTENTTYPE: return "PID_CONTENTTYPE";
-        case PropertyIDMap.PID_CONTENTSTATUS: return "PID_CONTENTSTATUS";
-        case PropertyIDMap.PID_LANGUAGE: return "PID_LANGUAGE";
-        case PropertyIDMap.PID_DOCVERSION: return "PID_DOCVERSION";
-        case PropertyIDMap.PID_MAX: return "PID_MAX";
-        case PropertyIDMap.PID_LOCALE: return "PID_LOCALE";
-        case PropertyIDMap.PID_BEHAVIOUR: return "PID_BEHAVIOUR";
-        default: return null;
-        }
-    }
-
     /**
      * Writes the property to an output stream.
      *

Modified: poi/trunk/src/java/org/apache/poi/hpsf/PropertySet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/PropertySet.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/PropertySet.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/PropertySet.java Sun May 14 22:25:33 
2017
@@ -871,7 +871,7 @@ public class PropertySet {
         b.append(sectionCount);
         b.append(", sections: [\n");
         for (Section section: getSections()) {
-            b.append(section);
+            b.append(section.toString(getPropertySetIDMap()));
         }
         b.append(']');
         b.append(']');

Modified: poi/trunk/src/java/org/apache/poi/hpsf/Section.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/Section.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/Section.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/Section.java Sun May 14 22:25:33 2017
@@ -55,18 +55,13 @@ public class Section {
      * The section's format ID, {@link #getFormatID}.
      */
     private ClassID formatID;
-    /**
-     * If the "dirty" flag is true, the section's size must be
-     * (re-)calculated before the section is written.
-     */
-    private boolean dirty = true;
 
     /**
      * Contains the bytes making out the section. This byte array is
      * established when the section's size is calculated and can be reused
-     * later. It is valid only if the "dirty" flag is false.
+     * later. If the array is empty, the section was modified and the bytes 
need to be regenerated.
      */
-    private byte[] sectionBytes;
+    private final ByteArrayOutputStream sectionBytes = new 
ByteArrayOutputStream();
 
     /**
      * The offset of the section in the stream.
@@ -74,11 +69,6 @@ public class Section {
     private final long _offset;
 
     /**
-     * The section's size in bytes.
-     */
-    private int size;
-
-    /**
      * This section's properties.
      */
     private final Map<Long,Property> properties = new 
LinkedHashMap<Long,Property>();
@@ -126,7 +116,6 @@ public class Section {
      * @exception UnsupportedEncodingException if the section's codepage is not
      * supported.
      */
-    @SuppressWarnings("unchecked")
     public Section(final byte[] src, final int offset) throws 
UnsupportedEncodingException {
         /*
          * Read the format ID.
@@ -154,7 +143,7 @@ public class Section {
         /*
          * Read the section length.
          */
-        size = (int)leis.readUInt();
+        int size = (int)Math.min(leis.readUInt(), src.length-_offset);
 
         /*
          * Read the number of properties.
@@ -213,6 +202,7 @@ public class Section {
 
             /* Read the codepage number. */
             codepage =  leis.readUShort();
+            setCodepage(codepage);
         }
 
 
@@ -222,6 +212,10 @@ public class Section {
             long off = me.getKey();
             long id = me.getValue();
 
+            if (id == PropertyIDMap.PID_CODEPAGE) {
+                continue;
+            }
+            
             int pLen = propLen(offset2Id, off, size);
             leis.setReadIndex((int)(this._offset + off));
 
@@ -239,12 +233,13 @@ public class Section {
                         LOG.log(POILogger.INFO, "Dictionary fallback failed - 
ignoring property");
                     }
                 };
-            } else if (id == PropertyIDMap.PID_CODEPAGE) {
-                setCodepage(codepage);
             } else {
                 setProperty(new MutableProperty(id, leis, pLen, codepage));
             }
         }
+        
+        sectionBytes.write(src, (int)_offset, size);
+        padSectionBytes();
     }
 
     /**
@@ -338,9 +333,8 @@ public class Section {
     public void setProperties(final Property[] properties) {
         this.properties.clear();
         for (Property p : properties) {
-            this.properties.put(p.getID(), p);
+            setProperty(p);
         }
-        dirty = true;
     }
 
     /**
@@ -448,7 +442,7 @@ public class Section {
         Property old = properties.get(p.getID());
         if (old == null || !old.equals(p)) {
             properties.put(p.getID(), p);
-            dirty = true;
+            sectionBytes.reset();
         }
     }
 
@@ -543,17 +537,17 @@ public class Section {
      * @return the section's size in bytes.
      */
     public int getSize() {
-        if (dirty) {
-            try {
-                size = calcSize();
-                dirty = false;
-            } catch (HPSFRuntimeException ex) {
-                throw ex;
-            } catch (Exception ex) {
-                throw new HPSFRuntimeException(ex);
-            }
+        int size = sectionBytes.size();
+        if (size > 0) {
+            return size;
+        }
+        try {
+            return calcSize();
+        } catch (HPSFRuntimeException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            throw new HPSFRuntimeException(ex);
         }
-        return size;
     }
 
     /**
@@ -566,18 +560,21 @@ public class Section {
      * @throws IOException
      */
     private int calcSize() throws WritingNotSupportedException, IOException {
-        final ByteArrayOutputStream out = new ByteArrayOutputStream();
-        write(out);
-        out.close();
+        sectionBytes.reset();
+        write(sectionBytes);
+        padSectionBytes();
+        return sectionBytes.size();
+    }
+
+    private void padSectionBytes() {
+        byte[] padArray = { 0, 0, 0 };
         /* Pad to multiple of 4 bytes so that even the Windows shell (explorer)
          * shows custom properties. */
-        sectionBytes = Util.pad4(out.toByteArray());
-        return sectionBytes.length;
+        int pad = (4 - (sectionBytes.size() & 0x3)) & 0x3;
+        sectionBytes.write(padArray, 0, pad);
     }
 
 
-
-
     /**
      * Checks whether the property which the last call to {@link
      * #getPropertyIntValue} or {@link #getProperty} tried to access
@@ -623,12 +620,8 @@ public class Section {
      * Removes all properties from the section including 0 (dictionary) and
      * 1 (codepage).
      */
-    public void clear()
-    {
-        final Property[] properties = getProperties();
-        for (int i = 0; i < properties.length; i++)
-        {
-            final Property p = properties[i];
+    public void clear() {
+        for (Property p : getProperties()) {
             removeProperty(p.getID());
         }
     }
@@ -639,17 +632,17 @@ public class Section {
      *
      * <ul>
      *
-     * <li>The other object is not a {@link Section}.</li>
+     * <li>The other object is not a {@link Section}.
      *
-     * <li>The format IDs of the two sections are not equal.</li>
+     * <li>The format IDs of the two sections are not equal.
      *
      * <li>The sections have a different number of properties. However,
-     * properties with ID 1 (codepage) are not counted.</li>
+     * properties with ID 1 (codepage) are not counted.
      *
-     * <li>The other object is not a {@link Section}.</li>
+     * <li>The other object is not a {@link Section}.
      *
      * <li>The properties have different values. The order of the properties
-     * is irrelevant.</li>
+     * is irrelevant.
      *
      * </ul>
      *
@@ -695,7 +688,9 @@ public class Section {
      * @param id The ID of the property to be removed
      */
     public void removeProperty(final long id) {
-        dirty |= (properties.remove(id) != null);
+        if (properties.remove(id) != null) {
+            sectionBytes.reset();
+        }
     }
 
     /**
@@ -716,9 +711,9 @@ public class Section {
     public int write(final OutputStream out) throws 
WritingNotSupportedException, IOException {
         /* Check whether we have already generated the bytes making out the
          * section. */
-        if (!dirty && sectionBytes != null) {
-            out.write(sectionBytes);
-            return sectionBytes.length;
+        if (sectionBytes.size() > 0) {
+            sectionBytes.writeTo(out);
+            return sectionBytes.size();
         }
 
         /* Writing the section's dictionary it tricky. If there is a dictionary
@@ -971,6 +966,10 @@ public class Section {
      */
     @Override
     public String toString() {
+        return toString(null);
+    }
+    
+    public String toString(PropertyIDMap idMap) {
         final StringBuffer b = new StringBuffer();
         final Property[] pa = getProperties();
         b.append("\n\n\n");
@@ -990,7 +989,7 @@ public class Section {
             codepage = Property.DEFAULT_CODEPAGE;
         }
         for (Property p : pa) {
-            b.append(p.toString(codepage));
+            b.append(p.toString(codepage, idMap));
             b.append(",\n");
         }
         b.append(']');

Modified: poi/trunk/src/java/org/apache/poi/hpsf/SummaryInformation.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/SummaryInformation.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/SummaryInformation.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/SummaryInformation.java Sun May 14 
22:25:33 2017
@@ -351,7 +351,7 @@ public final class SummaryInformation ex
         if (d == null) {
             return 0;
         }
-        return Util.dateToFileTime(d);
+        return Filetime.dateToFileTime(d);
     }
 
 
@@ -362,7 +362,7 @@ public final class SummaryInformation ex
      * @param time The time to set.
      */
     public void setEditTime(final long time) {
-        final Date d = Util.filetimeToDate(time);
+        final Date d = Filetime.filetimeToDate(time);
         getFirstSection().setProperty(PropertyIDMap.PID_EDITTIME, 
Variant.VT_FILETIME, d);
     }
 

Modified: poi/trunk/src/java/org/apache/poi/hpsf/VariantSupport.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/VariantSupport.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/VariantSupport.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/VariantSupport.java Sun May 14 
22:25:33 2017
@@ -207,7 +207,7 @@ public class VariantSupport extends Vari
 
             case Variant.VT_FILETIME:
                 Filetime filetime = (Filetime) typedPropertyValue.getValue();
-                return Util.filetimeToDate( (int) filetime.getHigh(), (int) 
filetime.getLow() );
+                return filetime.getJavaValue();
 
             case Variant.VT_LPSTR:
                 CodePageString cpString = (CodePageString) 
typedPropertyValue.getValue();
@@ -413,13 +413,8 @@ public class VariantSupport extends Vari
                 break;
 
             case Variant.VT_FILETIME:
-                if (value instanceof Date) {
-                    long filetime = Util.dateToFileTime((Date) value);
-                    int high = (int) ((filetime >> 32) & 0x00000000FFFFFFFFL);
-                    int low = (int) (filetime & 0x00000000FFFFFFFFL);
-                    Filetime filetimeValue = new Filetime( low, high);
-                    length = filetimeValue.write( out );
-                }
+                Filetime filetimeValue = (value instanceof Date) ? new 
Filetime((Date)value) : new Filetime();
+                length = filetimeValue.write( out );
                 break;
 
             default:

Modified: poi/trunk/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java Sun May 
14 22:25:33 2017
@@ -17,9 +17,14 @@
 
 package org.apache.poi.hpsf.wellknown;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
+
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.SummaryInformation;
 
 /**
  * This is a dictionary which maps property ID values to property
@@ -31,7 +36,7 @@ import java.util.Map;
  * should treat them as unmodifiable, copy them and modifiy the
  * copies.
  */
-public class PropertyIDMap extends HashMap<Long,String> {
+public class PropertyIDMap implements Map<Long,String> {
 
     /*
      * The following definitions are for property IDs in the first
@@ -317,6 +322,26 @@ public class PropertyIDMap extends HashM
      * details!
      */
     private static PropertyIDMap summaryInformationProperties;
+    private static final Object[][] summaryInformationIdValues = {
+        { (long)PID_TITLE, "PID_TITLE" },
+        { (long)PID_SUBJECT, "PID_SUBJECT" },
+        { (long)PID_AUTHOR, "PID_AUTHOR" },
+        { (long)PID_KEYWORDS, "PID_KEYWORDS" },
+        { (long)PID_COMMENTS, "PID_COMMENTS" },
+        { (long)PID_TEMPLATE, "PID_TEMPLATE" },
+        { (long)PID_LASTAUTHOR, "PID_LASTAUTHOR" },
+        { (long)PID_REVNUMBER, "PID_REVNUMBER" },
+        { (long)PID_EDITTIME, "PID_EDITTIME" },
+        { (long)PID_LASTPRINTED, "PID_LASTPRINTED" },
+        { (long)PID_CREATE_DTM, "PID_CREATE_DTM" },
+        { (long)PID_LASTSAVE_DTM, "PID_LASTSAVE_DTM" },
+        { (long)PID_PAGECOUNT, "PID_PAGECOUNT" },
+        { (long)PID_WORDCOUNT, "PID_WORDCOUNT" },
+        { (long)PID_CHARCOUNT, "PID_CHARCOUNT" },
+        { (long)PID_THUMBNAIL, "PID_THUMBNAIL" },
+        { (long)PID_APPNAME, "PID_APPNAME" },
+        { (long)PID_SECURITY, "PID_SECURITY" },
+    };
 
     /**
      * Contains the summary information property ID values and
@@ -324,144 +349,181 @@ public class PropertyIDMap extends HashM
      * details!
      */
     private static PropertyIDMap documentSummaryInformationProperties;
-
-
-
+    private static final Object[][] documentSummaryInformationIdValues = {
+        { (long)PID_DICTIONARY, "PID_DICTIONARY" },
+        { (long)PID_CODEPAGE, "PID_CODEPAGE" },
+        { (long)PID_CATEGORY, "PID_CATEGORY" },
+        { (long)PID_PRESFORMAT, "PID_PRESFORMAT" },
+        { (long)PID_BYTECOUNT, "PID_BYTECOUNT" },
+        { (long)PID_LINECOUNT, "PID_LINECOUNT" },
+        { (long)PID_PARCOUNT, "PID_PARCOUNT" },
+        { (long)PID_SLIDECOUNT, "PID_SLIDECOUNT" },
+        { (long)PID_NOTECOUNT, "PID_NOTECOUNT" },
+        { (long)PID_HIDDENCOUNT, "PID_HIDDENCOUNT" },
+        { (long)PID_MMCLIPCOUNT, "PID_MMCLIPCOUNT" },
+        { (long)PID_SCALE, "PID_SCALE" },
+        { (long)PID_HEADINGPAIR, "PID_HEADINGPAIR" },
+        { (long)PID_DOCPARTS, "PID_DOCPARTS" },
+        { (long)PID_MANAGER, "PID_MANAGER" },
+        { (long)PID_COMPANY, "PID_COMPANY" },
+        { (long)PID_LINKSDIRTY, "PID_LINKSDIRTY" },
+    };
+    
+    
     /**
-     * Creates a {@link PropertyIDMap}.
-     *
-     * @param initialCapacity The initial capacity as defined for
-     * {@link HashMap}
-     * @param loadFactor The load factor as defined for {@link HashMap}
-     */
-    public PropertyIDMap(final int initialCapacity, final float loadFactor)
-    {
-        super(initialCapacity, loadFactor);
-    }
-
+     * Contains the fallback property ID values and associated strings.
+     * This is only used for lookups and not for initializing a property set
+     */
+    private static PropertyIDMap fallbackProperties;
+    private static final Object[][] fallbackIdValues = {
+        { (long)PID_DICTIONARY, "PID_DICTIONARY" },
+        { (long)PID_CODEPAGE, "PID_CODEPAGE" },
+        { (long)PID_CATEGORY, "PID_CATEGORY" },
+        { (long)PID_PRESFORMAT, "PID_PRESFORMAT" },
+        { (long)PID_BYTECOUNT, "PID_BYTECOUNT" },
+        { (long)PID_LINECOUNT, "PID_LINECOUNT" },
+        { (long)PID_PARCOUNT, "PID_PARCOUNT" },
+        { (long)PID_SLIDECOUNT, "PID_SLIDECOUNT" },
+        { (long)PID_NOTECOUNT, "PID_NOTECOUNT" },
+        { (long)PID_HIDDENCOUNT, "PID_HIDDENCOUNT" },
+        { (long)PID_MMCLIPCOUNT, "PID_MMCLIPCOUNT" },
+        { (long)PID_SCALE, "PID_SCALE" },
+        { (long)PID_HEADINGPAIR, "PID_HEADINGPAIR" },
+        { (long)PID_DOCPARTS, "PID_DOCPARTS" },
+        { (long)PID_MANAGER, "PID_MANAGER" },
+        { (long)PID_COMPANY, "PID_COMPANY" },
+        { (long)PID_LINKSDIRTY, "PID_LINKSDIRTY" },
+        { (long)PID_CCHWITHSPACES, "PID_CCHWITHSPACES" },
+  // 0x12 Unused
+  // 0x13 GKPIDDSI_SHAREDDOC - Must be False
+  // 0x14 GKPIDDSI_LINKBASE - Must not be written
+  // 0x15 GKPIDDSI_HLINKS - Must not be written
+        { (long)PID_HYPERLINKSCHANGED, "PID_HYPERLINKSCHANGED" },
+        { (long)PID_VERSION, "PID_VERSION" },
+        { (long)PID_DIGSIG, "PID_DIGSIG" },
+  // 0x19 Unused
+        { (long)PID_CONTENTTYPE, "PID_CONTENTTYPE" },
+        { (long)PID_CONTENTSTATUS, "PID_CONTENTSTATUS" },
+        { (long)PID_LANGUAGE, "PID_LANGUAGE" },
+        { (long)PID_DOCVERSION, "PID_DOCVERSION" },
+        { (long)PID_MAX, "PID_MAX" },
+        { (long)PID_LOCALE, "PID_LOCALE" },
+        { (long)PID_BEHAVIOUR, "PID_BEHAVIOUR" },
+    };
 
+    private final Map<Long,String> idMap;
+    
 
     /**
      * Creates a {@link PropertyIDMap} backed by another map.
      *
      * @param map The instance to be created is backed by this map.
      */
-    public PropertyIDMap(final Map<Long,String> map)
-    {
-        super(map);
+    private PropertyIDMap(Object[][] idValues) {
+        Map<Long,String> m = new HashMap<Long,String>(idValues.length);
+        for (Object[] idValue : idValues) {
+            m.put((Long)idValue[0], (String)idValue[1]);
+        }
+        idMap = Collections.unmodifiableMap(m);
     }
 
+    /**
+     * @return the Summary Information properties singleton
+     */
+    public static synchronized PropertyIDMap getSummaryInformationProperties() 
{
+        if (summaryInformationProperties == null) {
+            summaryInformationProperties = new 
PropertyIDMap(summaryInformationIdValues);
+        }
+        return summaryInformationProperties;
+    }
 
+    /**
+     * @return The Document Summary Information properties singleton.
+     */
+    public static synchronized PropertyIDMap 
getDocumentSummaryInformationProperties() {
+        if (documentSummaryInformationProperties == null) {
+            documentSummaryInformationProperties = new 
PropertyIDMap(documentSummaryInformationIdValues);
+        }
+        return documentSummaryInformationProperties;
+    }
 
     /**
-     * Puts a ID string for an ID into the {@link
-     * PropertyIDMap}.
-     *
-     * @param id The ID.
-     * @param idString The ID string.
-     * @return As specified by the {@link java.util.Map} interface, this method
-     * returns the previous value associated with the specified
-     * <var>id</var>, or <code>null</code> if there was no mapping for
-     * key.
+     * Returns a property map, which is only used as a fallback, i.e. if 
available, the correct map
+     * for {@link DocumentSummaryInformation} or {@link SummaryInformation} 
should be used.
      */
-    public Object put(final long id, final String idString)
-    {
-        return put(Long.valueOf(id), idString);
+    public static synchronized PropertyIDMap getFallbackProperties() {
+        if (fallbackProperties == null) {
+            fallbackProperties = new PropertyIDMap(fallbackIdValues);
+        }
+        return fallbackProperties;
+    }
+    
+    @Override
+    public int size() {
+        return idMap.size();
     }
 
+    @Override
+    public boolean isEmpty() {
+        return idMap.isEmpty();
+    }
 
+    @Override
+    public boolean containsKey(Object key) {
+        return idMap.containsKey(key);
+    }
 
-    /**
-     * Gets the ID string for an ID from the {@link
-     * PropertyIDMap}.
-     *
-     * @param id The ID.
-     * @return The ID string associated with <var>id</var>.
-     */
-    public Object get(final long id)
-    {
-        return get(Long.valueOf(id));
+    @Override
+    public boolean containsValue(Object value) {
+        return idMap.containsValue(value);
     }
 
+    @Override
+    public String get(Object key) {
+        return idMap.get(key);
+    }
 
+    @Override
+    public String put(Long key, String value) {
+        return idMap.put(key, value);
+    }
 
-    /**
-     * @return the Summary Information properties singleton
-     */
-    public static synchronized PropertyIDMap getSummaryInformationProperties()
-    {
-        if (summaryInformationProperties == null)
-        {
-            PropertyIDMap m = new PropertyIDMap(18, (float) 1.0);
-            m.put(PID_TITLE, "PID_TITLE");
-            m.put(PID_SUBJECT, "PID_SUBJECT");
-            m.put(PID_AUTHOR, "PID_AUTHOR");
-            m.put(PID_KEYWORDS, "PID_KEYWORDS");
-            m.put(PID_COMMENTS, "PID_COMMENTS");
-            m.put(PID_TEMPLATE, "PID_TEMPLATE");
-            m.put(PID_LASTAUTHOR, "PID_LASTAUTHOR");
-            m.put(PID_REVNUMBER, "PID_REVNUMBER");
-            m.put(PID_EDITTIME, "PID_EDITTIME");
-            m.put(PID_LASTPRINTED, "PID_LASTPRINTED");
-            m.put(PID_CREATE_DTM, "PID_CREATE_DTM");
-            m.put(PID_LASTSAVE_DTM, "PID_LASTSAVE_DTM");
-            m.put(PID_PAGECOUNT, "PID_PAGECOUNT");
-            m.put(PID_WORDCOUNT, "PID_WORDCOUNT");
-            m.put(PID_CHARCOUNT, "PID_CHARCOUNT");
-            m.put(PID_THUMBNAIL, "PID_THUMBNAIL");
-            m.put(PID_APPNAME, "PID_APPNAME");
-            m.put(PID_SECURITY, "PID_SECURITY");
-            summaryInformationProperties =
-                new PropertyIDMap(Collections.unmodifiableMap(m));
-        }
-        return summaryInformationProperties;
+    @Override
+    public String remove(Object key) {
+        return idMap.remove(key);
     }
 
+    @Override
+    public void putAll(Map<? extends Long, ? extends String> m) {
+        idMap.putAll(m);
+    }
 
+    @Override
+    public void clear() {
+        idMap.clear();
+    }
 
-    /**
-     * Returns the Document Summary Information properties
-     * singleton.
-     *
-     * @return The Document Summary Information properties singleton.
-     */
-    public static synchronized PropertyIDMap 
getDocumentSummaryInformationProperties()
-    {
-        if (documentSummaryInformationProperties == null)
-        {
-            PropertyIDMap m = new PropertyIDMap(17, (float) 1.0);
-            m.put(PID_DICTIONARY, "PID_DICTIONARY");
-            m.put(PID_CODEPAGE, "PID_CODEPAGE");
-            m.put(PID_CATEGORY, "PID_CATEGORY");
-            m.put(PID_PRESFORMAT, "PID_PRESFORMAT");
-            m.put(PID_BYTECOUNT, "PID_BYTECOUNT");
-            m.put(PID_LINECOUNT, "PID_LINECOUNT");
-            m.put(PID_PARCOUNT, "PID_PARCOUNT");
-            m.put(PID_SLIDECOUNT, "PID_SLIDECOUNT");
-            m.put(PID_NOTECOUNT, "PID_NOTECOUNT");
-            m.put(PID_HIDDENCOUNT, "PID_HIDDENCOUNT");
-            m.put(PID_MMCLIPCOUNT, "PID_MMCLIPCOUNT");
-            m.put(PID_SCALE, "PID_SCALE");
-            m.put(PID_HEADINGPAIR, "PID_HEADINGPAIR");
-            m.put(PID_DOCPARTS, "PID_DOCPARTS");
-            m.put(PID_MANAGER, "PID_MANAGER");
-            m.put(PID_COMPANY, "PID_COMPANY");
-            m.put(PID_LINKSDIRTY, "PID_LINKSDIRTY");
-            documentSummaryInformationProperties =
-                new PropertyIDMap(Collections.unmodifiableMap(m));
-        }
-        return documentSummaryInformationProperties;
+    @Override
+    public Set<Long> keySet() {
+        return idMap.keySet();
     }
 
+    @Override
+    public Collection<String> values() {
+        return idMap.values();
+    }
 
+    @Override
+    public Set<Entry<Long, String>> entrySet() {
+        return idMap.entrySet();
+    }
 
     /**
      * For the most basic testing.
      *
      * @param args The command-line arguments
      */
-    public static void main(final String[] args)
-    {
+    public static void main(final String[] args) {
         PropertyIDMap s1 = getSummaryInformationProperties();
         PropertyIDMap s2 = getDocumentSummaryInformationProperties();
         System.out.println("s1: " + s1);

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- 
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
 (original)
+++ 
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIDateAttribute.java
 Sun May 14 22:25:33 2017
@@ -25,7 +25,7 @@ import java.util.Locale;
 
 import org.apache.poi.hmef.Attachment;
 import org.apache.poi.hmef.HMEFMessage;
-import org.apache.poi.hpsf.Util;
+import org.apache.poi.hpsf.Filetime;
 import org.apache.poi.hsmf.datatypes.MAPIProperty;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LocaleUtil;
@@ -53,7 +53,7 @@ public final class MAPIDateAttribute ext
       super(property, type, data);
       
       // The value is a 64 bit Windows Filetime
-      this.data = Util.filetimeToDate(
+      this.data = Filetime.filetimeToDate(
             LittleEndian.getLong(data, 0)
       );
    }

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- 
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
 (original)
+++ 
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFDateAttribute.java
 Sun May 14 22:25:33 2017
@@ -28,7 +28,7 @@ import java.util.Locale;
 
 import org.apache.poi.hmef.Attachment;
 import org.apache.poi.hmef.HMEFMessage;
-import org.apache.poi.hpsf.Util;
+import org.apache.poi.hpsf.Filetime;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LocaleUtil;
 import org.apache.poi.util.POILogFactory;
@@ -52,7 +52,7 @@ public final class TNEFDateAttribute ext
       byte[] binData = getData();
       if(binData.length == 8) {
          // The value is a 64 bit Windows Filetime
-         this.data = Util.filetimeToDate(
+         this.data = Filetime.filetimeToDate(
                LittleEndian.getLong(getData(), 0)
          );
       } else if(binData.length == 14) {

Modified: poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java Sun May 14 
22:25:33 2017
@@ -17,7 +17,6 @@
 
 package org.apache.poi.hpsf.basic;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -28,10 +27,13 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
+import java.util.Date;
 import java.util.List;
 
 import org.apache.poi.POIDataSamples;
+import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.Filetime;
 import org.apache.poi.hpsf.HPSFException;
 import org.apache.poi.hpsf.MarkUnsupportedException;
 import org.apache.poi.hpsf.NoPropertySetStreamException;
@@ -48,33 +50,24 @@ import org.junit.Test;
  */
 public final class TestBasic {
 
-    private static final String POI_FS = "TestGermanWord90.doc";
-    private static final String[] POI_FILES = new String[]
-        {
-            "\005SummaryInformation",
-            "\005DocumentSummaryInformation",
-            "WordDocument",
-            "\001CompObj",
-            "1Table"
-        };
-    private static final int BYTE_ORDER = 0xfffe;
-    private static final int FORMAT     = 0x0000;
-    private static final int OS_VERSION = 0x00020A04;
-    private static final byte[] CLASS_ID =
-        {
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
-        };
-    private static final int[] SECTION_COUNT =
-        {1, 2};
-    private static final boolean[] IS_SUMMARY_INFORMATION =
-        {true, false};
-    private static final boolean[] IS_DOCUMENT_SUMMARY_INFORMATION =
-        {false, true};
+    private static final POIDataSamples samples = 
POIDataSamples.getHPSFInstance();
+
+    private static final String[] POI_FILES = {
+        "\005SummaryInformation",
+        "\005DocumentSummaryInformation",
+        "WordDocument",
+        "\001CompObj",
+        "1Table"
+    };
+    private static final int BYTE_ORDER   = 0xfffe;
+    private static final int FORMAT       = 0x0000;
+    private static final int OS_VERSION   = 0x00020A04;
+    private static final ClassID CLASS_ID = new 
ClassID("{00000000-0000-0000-0000-000000000000}");
+    private static final int[] SECTION_COUNT = {1, 2};
+    private static final boolean[] IS_SUMMARY_INFORMATION = {true, false};
+    private static final boolean[] IS_DOCUMENT_SUMMARY_INFORMATION = {false, 
true};
 
-    private POIFile[] poiFiles;
+    private List<POIFile> poiFiles;
 
 
     /**
@@ -84,10 +77,8 @@ public final class TestBasic {
      * @exception IOException if any other I/O exception occurs.
      */
     @Before
-    public void setUp() throws IOException
-    {
-        POIDataSamples samples = POIDataSamples.getHPSFInstance();
-        final File data = samples.getFile(POI_FS);
+    public void setUp() throws IOException {
+        final File data = samples.getFile("TestGermanWord90.doc");
         poiFiles = Util.readPOIFiles(data);
     }
 
@@ -96,11 +87,11 @@ public final class TestBasic {
      * are expected to be in a certain order.</p>
      */
     @Test
-    public void testReadFiles()
-    {
+    public void testReadFiles() {
         String[] expected = POI_FILES;
-        for (int i = 0; i < expected.length; i++)
-            assertEquals(poiFiles[i].getName(), expected[i]);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(poiFiles.get(i).getName(), expected[i]);
+        }
     }
 
     /**
@@ -119,30 +110,22 @@ public final class TestBasic {
      */
     @Test
     public void testCreatePropertySets()
-    throws UnsupportedEncodingException, IOException
-    {
-        Class<?>[] expected = new Class[]
-            {
-                SummaryInformation.class,
-                DocumentSummaryInformation.class,
-                NoPropertySetStreamException.class,
-                NoPropertySetStreamException.class,
-                NoPropertySetStreamException.class
-            };
-        for (int i = 0; i < expected.length; i++)
-        {
-            InputStream in = new ByteArrayInputStream(poiFiles[i].getBytes());
+    throws UnsupportedEncodingException, IOException {
+        Class<?>[] expected = {
+            SummaryInformation.class,
+            DocumentSummaryInformation.class,
+            NoPropertySetStreamException.class,
+            NoPropertySetStreamException.class,
+            NoPropertySetStreamException.class
+        };
+        for (int i = 0; i < expected.length; i++) {
+            InputStream in = new 
ByteArrayInputStream(poiFiles.get(i).getBytes());
             Object o;
-            try
-            {
+            try {
                 o = PropertySetFactory.create(in);
-            }
-            catch (NoPropertySetStreamException ex)
-            {
+            } catch (NoPropertySetStreamException ex) {
                 o = ex;
-            }
-            catch (MarkUnsupportedException ex)
-            {
+            } catch (MarkUnsupportedException ex) {
                 o = ex;
             }
             in.close();
@@ -159,17 +142,15 @@ public final class TestBasic {
      * @exception HPSFException if any HPSF exception occurs
      */
     @Test
-    public void testPropertySetMethods() throws IOException, HPSFException
-    {
+    public void testPropertySetMethods() throws IOException, HPSFException {
         /* Loop over the two property sets. */
-        for (int i = 0; i < 2; i++)
-        {
-            byte[] b = poiFiles[i].getBytes();
+        for (int i = 0; i < 2; i++) {
+            byte[] b = poiFiles.get(i).getBytes();
             PropertySet ps = PropertySetFactory.create(new 
ByteArrayInputStream(b));
             assertEquals(BYTE_ORDER, ps.getByteOrder());
             assertEquals(FORMAT, ps.getFormat());
             assertEquals(OS_VERSION, ps.getOSVersion());
-            assertArrayEquals(CLASS_ID, ps.getClassID().getBytes());
+            assertEquals(CLASS_ID, ps.getClassID());
             assertEquals(SECTION_COUNT[i], ps.getSectionCount());
             assertEquals(IS_SUMMARY_INFORMATION[i], ps.isSummaryInformation());
             assertEquals(IS_DOCUMENT_SUMMARY_INFORMATION[i], 
ps.isDocumentSummaryInformation());
@@ -185,11 +166,9 @@ public final class TestBasic {
      * @exception HPSFException if any HPSF exception occurs
      */
     @Test
-    public void testSectionMethods() throws IOException, HPSFException
-    {
-        final SummaryInformation si = (SummaryInformation)
-            PropertySetFactory.create(new ByteArrayInputStream
-                (poiFiles[0].getBytes()));
+    public void testSectionMethods() throws IOException, HPSFException {
+        InputStream is = new ByteArrayInputStream(poiFiles.get(0).getBytes());
+        final SummaryInformation si = 
(SummaryInformation)PropertySetFactory.create(is);
         final List<Section> sections = si.getSections();
         final Section s = sections.get(0);
         assertEquals(s.getFormatID(), SectionIDMap.SUMMARY_INFORMATION_ID);
@@ -198,4 +177,16 @@ public final class TestBasic {
         assertEquals("Titel", s.getProperty(2));
         assertEquals(1764, s.getSize());
     }
+    
+    @Test
+    public void bug52117LastPrinted() throws IOException, HPSFException {
+        File f = samples.getFile("TestBug52117.doc");
+        POIFile poiFile = Util.readPOIFiles(f, new 
String[]{POI_FILES[0]}).get(0);
+        InputStream in = new ByteArrayInputStream(poiFile.getBytes());
+        SummaryInformation si = 
(SummaryInformation)PropertySetFactory.create(in);
+        Date lastPrinted = si.getLastPrinted();
+        long editTime = si.getEditTime();
+        assertTrue(Filetime.isUndefined(lastPrinted));
+        assertEquals(1800000000L, editTime);
+    }
 }

Modified: 
poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java 
(original)
+++ poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java 
Sun May 14 22:25:33 2017
@@ -17,14 +17,17 @@
 
 package org.apache.poi.hpsf.basic;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
-
-import junit.framework.TestCase;
+import java.util.List;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.hpsf.DocumentSummaryInformation;
@@ -35,27 +38,29 @@ import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.PropertySetFactory;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hpsf.Variant;
+import org.junit.Before;
+import org.junit.Test;
 
 /**
- * <p>Test case for OLE2 files with empty properties. An empty property's type
- * is {@link Variant#VT_EMPTY}.</p>
+ * Test case for OLE2 files with empty properties.
+ * An empty property's type is {@link Variant#VT_EMPTY}.
  */
-public final class TestEmptyProperties extends TestCase {
+public final class TestEmptyProperties {
+
+    private static final POIDataSamples samples = 
POIDataSamples.getHPSFInstance();
 
     /**
-     * <p>This test file's summary information stream contains some empty
-     * properties.</p>
+     * This test file's summary information stream contains some empty 
properties.
      */
        private static final String POI_FS = "TestCorel.shw";
 
-       private static final String[] POI_FILES = new String[]
-        {
-            "PerfectOffice_MAIN",
-            "\005SummaryInformation",
-            "Main"
-        };
+       private static final String[] POI_FILES = {
+        "PerfectOffice_MAIN",
+        "\005SummaryInformation",
+        "Main"
+    };
 
-       private POIFile[] poiFiles;
+       private List<POIFile> poiFiles;
 
     /**
      * <p>Read a the test file from the "data" directory.</p>
@@ -64,24 +69,21 @@ public final class TestEmptyProperties e
      * does not exist
      * @exception IOException if an I/O exception occurs
      */
-    @Override
-    public void setUp() throws FileNotFoundException, IOException
-    {
-        POIDataSamples samples = POIDataSamples.getHPSFInstance();
+    @Before
+    public void setUp() throws IOException {
         final File data = samples.getFile(POI_FS);
-
         poiFiles = Util.readPOIFiles(data);
     }
 
     /**
-     * <p>Checks the names of the files in the POI filesystem. They
-     * are expected to be in a certain order.</p>
+     * Checks the names of the files in the POI filesystem. They
+     * are expected to be in a certain order.
      */
-    public void testReadFiles()
-    {
+    @Test
+    public void testReadFiles() {
         String[] expected = POI_FILES;
         for (int i = 0; i < expected.length; i++)
-            assertEquals(poiFiles[i].getName(), expected[i]);
+            assertEquals(poiFiles.get(i).getName(), expected[i]);
     }
 
     /**
@@ -98,29 +100,22 @@ public final class TestEmptyProperties e
      * @exception UnsupportedEncodingException if a character encoding is not
      * supported.
      */
+    @Test
     public void testCreatePropertySets()
-    throws UnsupportedEncodingException, IOException
-    {
-        Class<?>[] expected = new Class[]
-            {
-                NoPropertySetStreamException.class,
-                SummaryInformation.class,
-                NoPropertySetStreamException.class
-            };
-        for (int i = 0; i < expected.length; i++)
-        {
-            InputStream in = new ByteArrayInputStream(poiFiles[i].getBytes());
+    throws UnsupportedEncodingException, IOException {
+        Class<?>[] expected =  {
+            NoPropertySetStreamException.class,
+            SummaryInformation.class,
+            NoPropertySetStreamException.class
+        };
+        for (int i = 0; i < expected.length; i++) {
+            InputStream in = new 
ByteArrayInputStream(poiFiles.get(i).getBytes());
             Object o;
-            try
-            {
+            try {
                 o = PropertySetFactory.create(in);
-            }
-            catch (NoPropertySetStreamException ex)
-            {
+            } catch (NoPropertySetStreamException ex) {
                 o = ex;
-            }
-            catch (MarkUnsupportedException ex)
-            {
+            } catch (MarkUnsupportedException ex) {
                 o = ex;
             }
             in.close();
@@ -136,11 +131,10 @@ public final class TestEmptyProperties e
      * @exception IOException if an I/O exception occurs
      * @exception HPSFException if an HPSF operation fails
      */
-    public void testPropertySetMethods() throws IOException, HPSFException
-    {
-        byte[] b = poiFiles[1].getBytes();
-        PropertySet ps =
-            PropertySetFactory.create(new ByteArrayInputStream(b));
+    @Test
+    public void testPropertySetMethods() throws IOException, HPSFException {
+        byte[] b = poiFiles.get(1).getBytes();
+        PropertySet ps = PropertySetFactory.create(new 
ByteArrayInputStream(b));
         SummaryInformation s = (SummaryInformation) ps;
         assertNull(s.getTitle());
         assertNull(s.getSubject());

Modified: poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java 
(original)
+++ poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java Sun May 
14 22:25:33 2017
@@ -17,13 +17,14 @@
 
 package org.apache.poi.hpsf.basic;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 
-import junit.framework.TestCase;
-
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.hpsf.DocumentSummaryInformation;
 import org.apache.poi.hpsf.HPSFException;
@@ -32,30 +33,30 @@ import org.apache.poi.hpsf.PropertySetFa
 import org.apache.poi.hpsf.Section;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.util.CodePageUtil;
+import org.junit.Before;
+import org.junit.Test;
 
 /**
- * <p>Tests whether Unicode string can be read from a
- * DocumentSummaryInformation.</p>
+ * Tests whether Unicode string can be read from a DocumentSummaryInformation.
  */
-public class TestUnicode extends TestCase {
+public class TestUnicode {
 
     static final String POI_FS = "TestUnicode.xls";
-    static final String[] POI_FILES = new String[]
-        {
-            "\005DocumentSummaryInformation",
-        };
+    static final String[] POI_FILES =  {
+        "\005DocumentSummaryInformation",
+    };
     File data;
     POIFile[] poiFiles;
 
 
     /**
-     * <p>Read a the test file from the "data" directory.</p>
+     * Read a the test file from the "data" directory.
      *
      * @exception FileNotFoundException if the file to be read does not exist.
      * @exception IOException if any other I/O exception occurs
      */
-    @Override
-    protected void setUp() {
+    @Before
+    public void setUp() {
         POIDataSamples samples = POIDataSamples.getHPSFInstance();
         data = samples.getFile(POI_FS);
     }
@@ -63,31 +64,25 @@ public class TestUnicode extends TestCas
 
 
     /**
-     * <p>Tests the {@link PropertySet} methods. The test file has two
+     * Tests the {@link PropertySet} methods. The test file has two
      * property set: the first one is a {@link SummaryInformation},
-     * the second one is a {@link DocumentSummaryInformation}.</p>
+     * the second one is a {@link DocumentSummaryInformation}.
      *
      * @exception IOException if an I/O exception occurs
      * @exception HPSFException if an HPSF exception occurs
      */
-    public void testPropertySetMethods() throws IOException, HPSFException
-    {
-        POIFile poiFile = Util.readPOIFiles(data, POI_FILES)[0];
+    @Test
+    public void testPropertySetMethods() throws IOException, HPSFException {
+        POIFile poiFile = Util.readPOIFiles(data, POI_FILES).get(0);
         byte[] b = poiFile.getBytes();
-        PropertySet ps =
-            PropertySetFactory.create(new ByteArrayInputStream(b));
+        PropertySet ps = PropertySetFactory.create(new 
ByteArrayInputStream(b));
         assertTrue(ps.isDocumentSummaryInformation());
         assertEquals(ps.getSectionCount(), 2);
         Section s = ps.getSections().get(1);
-        assertEquals(s.getProperty(1),
-                            Integer.valueOf(CodePageUtil.CP_UTF16));
-        assertEquals(s.getProperty(2),
-                            Integer.valueOf(-96070278));
-        assertEquals(s.getProperty(3),
-                            "MCon_Info zu Office bei Schreiner");
-        assertEquals(s.getProperty(4),
-                            "[email protected]");
-        assertEquals(s.getProperty(5),
-                            "Petrovitsch, Wilhelm");
+        assertEquals(s.getProperty(1), CodePageUtil.CP_UTF16);
+        assertEquals(s.getProperty(2), -96070278);
+        assertEquals(s.getProperty(3), "MCon_Info zu Office bei Schreiner");
+        assertEquals(s.getProperty(4), "[email protected]");
+        assertEquals(s.getProperty(5), "Petrovitsch, Wilhelm");
     }
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java Sun May 14 
22:25:33 2017
@@ -237,7 +237,7 @@ public class TestWrite {
                 try {
                     psa[0] = PropertySetFactory.create(event.getStream());
                 } catch (Exception ex) {
-                    fail(org.apache.poi.hpsf.Util.toString(ex));
+                    fail(ex.getMessage());
                 }
             }},
             SummaryInformation.DEFAULT_STREAM_NAME
@@ -340,7 +340,7 @@ public class TestWrite {
             try {
                 PropertySetFactory.create(event.getStream());
             } catch (Exception ex) {
-                fail(org.apache.poi.hpsf.Util.toString(ex));
+                fail(ex.getMessage());
             }
         }
     }

Modified: poi/trunk/src/testcases/org/apache/poi/hpsf/basic/Util.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hpsf/basic/Util.java?rev=1795123&r1=1795122&r2=1795123&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hpsf/basic/Util.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hpsf/basic/Util.java Sun May 14 
22:25:33 2017
@@ -18,17 +18,13 @@
 
 package org.apache.poi.hpsf.basic;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Properties;
 
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.poifs.eventfilesystem.POIFSReader;
@@ -44,31 +40,6 @@ import org.apache.poi.util.IOUtils;
 final class Util {
 
     /**
-     * <p>Reads all files from a POI filesystem and returns them as an
-     * array of {@link POIFile} instances. This method loads all files
-     * into memory and thus does not cope well with large POI
-     * filessystems.</p>
-     * 
-     * @param poiFs The name of the POI filesystem as seen by the
-     * operating system. (This is the "filename".)
-     *
-     * @return The POI files. The elements are ordered in the same way
-     * as the files in the POI filesystem.
-     * 
-     * @exception FileNotFoundException if the file containing the POI 
-     * filesystem does not exist
-     * 
-     * @exception IOException if an I/O exception occurs
-     */
-    public static POIFile[] readPOIFiles(final File poiFs)
-        throws FileNotFoundException, IOException
-    {
-        return readPOIFiles(poiFs, null);
-    }
-
-
-
-    /**
      * <p>Reads a set of files from a POI filesystem and returns them
      * as an array of {@link POIFile} instances. This method loads all
      * files into memory and thus does not cope well with large POI
@@ -87,42 +58,34 @@ final class Util {
      * 
      * @exception IOException if an I/O exception occurs
      */
-    public static POIFile[] readPOIFiles(final File poiFs,
-                                         final String[] poiFiles)
-        throws FileNotFoundException, IOException
-    {
+    public static List<POIFile> readPOIFiles(final File poiFs, final String... 
poiFiles)
+    throws FileNotFoundException, IOException {
         final List<POIFile> files = new ArrayList<POIFile>();
         POIFSReader r = new POIFSReader();
-        POIFSReaderListener pfl = new POIFSReaderListener()
-        {
+        POIFSReaderListener pfl = new POIFSReaderListener() {
             @Override
-            public void processPOIFSReaderEvent(final POIFSReaderEvent event)
-            {
-                try
-                {
+            public void processPOIFSReaderEvent(final POIFSReaderEvent event) {
+                try {
                     final POIFile f = new POIFile();
                     f.setName(event.getName());
                     f.setPath(event.getPath());
                     final InputStream in = event.getStream();
-                    final ByteArrayOutputStream out =
-                        new ByteArrayOutputStream();
-                    IOUtils.copy(in, out);
-                    out.close();
-                    f.setBytes(out.toByteArray());
+                    f.setBytes(IOUtils.toByteArray(in));
+                    in.close();
                     files.add(f);
-                }
-                catch (IOException ex)
-                {
+                } catch (IOException ex) {
                     throw new RuntimeException(ex);
                 }
             }
         };
-        if (poiFiles == null)
+        if (poiFiles.length == 0) {
             /* Register the listener for all POI files. */
             r.registerListener(pfl);
-        else
-            for (String poiFile : poiFiles)
+        } else {
+            for (String poiFile : poiFiles) {
                 r.registerListener(pfl, poiFile);
+            }
+        }
 
         /* Read the POI filesystem. */
         FileInputStream stream = new FileInputStream(poiFs);
@@ -131,10 +94,7 @@ final class Util {
         } finally {
             stream.close();
         }
-        POIFile[] result = new POIFile[files.size()];
-        for (int i = 0; i < result.length; i++)
-            result[i] = files.get(i);
-        return result;
+        return files;
     }
 
 
@@ -155,18 +115,7 @@ final class Util {
      * 
      * @exception IOException if an I/O exception occurs
      */
-    public static List<POIFile> readPropertySets(final File poiFs)
-    throws FileNotFoundException, IOException {
-        FileInputStream stream = new FileInputStream(poiFs);
-        try {
-            return readPropertySets(stream);
-        } finally {
-            stream.close();
-        }
-    }
-            
-    public static List<POIFile> readPropertySets(final InputStream poiFs)
-    throws FileNotFoundException, IOException {
+    public static List<POIFile> readPropertySets(final File poiFs) throws 
IOException {
         final List<POIFile> files = new ArrayList<POIFile>(7);
         final POIFSReader r = new POIFSReader();
         POIFSReaderListener pfl = new POIFSReaderListener() {
@@ -191,28 +140,13 @@ final class Util {
         r.registerListener(pfl);
 
         /* Read the POI filesystem. */
-        r.read(poiFs);
+        InputStream is = new FileInputStream(poiFs);
+        try {
+            r.read(is);
+        } finally {
+            is.close();
+        }
 
         return files;
     }
-
-
-
-    /**
-     * <p>Prints the system properties to System.out.</p>
-     */
-    public static void printSystemProperties()
-    {
-        final Properties p = System.getProperties();
-        final List<String> names = new LinkedList<String>();
-        for (String name : p.stringPropertyNames())
-            names.add(name);
-        Collections.sort(names);
-        for (String name : names) {
-            String value = p.getProperty(name);
-            System.out.println(name + ": " + value);
-        }
-        System.out.println("Current directory: " +
-                           System.getProperty("user.dir"));
-    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to