From cd6236c74b55763a27e3e9b5f269c28bc9c98419 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Tue, 2 May 2017 23:32:13 +0000 Subject: [PATCH] #52372 - OutOfMemoryError parsing a word file git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1793602 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/poi/hpsf/Section.java | 473 +++++++++++----------- test-data/hpsf/TestBug52372.doc | Bin 0 -> 87040 bytes 2 files changed, 245 insertions(+), 228 deletions(-) create mode 100644 test-data/hpsf/TestBug52372.doc diff --git a/src/java/org/apache/poi/hpsf/Section.java b/src/java/org/apache/poi/hpsf/Section.java index 830d94465b..59150afb53 100644 --- a/src/java/org/apache/poi/hpsf/Section.java +++ b/src/java/org/apache/poi/hpsf/Section.java @@ -22,7 +22,11 @@ import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import org.apache.commons.collections4.bidimap.TreeBidiMap; @@ -30,11 +34,16 @@ import org.apache.poi.hpsf.wellknown.PropertyIDMap; import org.apache.poi.hpsf.wellknown.SectionIDMap; import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianByteArrayInputStream; +import org.apache.poi.util.LittleEndianConsts; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; /** * Represents a section in a {@link PropertySet}. */ public class Section { + private static final POILogger LOG = POILogFactory.getLogger(Section.class); /** * Maps property IDs to section-private PID strings. These @@ -62,7 +71,7 @@ public class Section { /** * The offset of the section in the stream. */ - private long offset = -1; + private final long _offset; /** * The section's size in bytes. @@ -72,7 +81,7 @@ public class Section { /** * This section's properties. */ - private final Map properties = new TreeMap(); + private final Map properties = new LinkedHashMap(); /** * This member is {@code true} if the last call to {@link @@ -85,6 +94,7 @@ public class Section { * Creates an empty {@link Section}. */ public Section() { + this._offset = -1; } /** @@ -96,6 +106,7 @@ public class Section { * @param s The section set to copy */ public Section(final Section s) { + this._offset = -1; setFormatID(s.getFormatID()); for (Property p : s.properties.values()) { properties.put(p.getID(), new MutableProperty(p)); @@ -117,32 +128,38 @@ public class Section { */ @SuppressWarnings("unchecked") public Section(final byte[] src, final int offset) throws UnsupportedEncodingException { - int o1 = offset; - /* * Read the format ID. */ - formatID = new ClassID(src, o1); - o1 += ClassID.LENGTH; + formatID = new ClassID(src, offset); /* * Read the offset from the stream's start and positions to * the section header. */ - this.offset = LittleEndian.getUInt(src, o1); - o1 = (int) this.offset; + int offFix = (int)LittleEndian.getUInt(src, offset + ClassID.LENGTH); + + // some input files have a invalid (padded?) offset, which need to be fixed + // search for beginning of size field + if (src[offFix] == 0) { + for (int i=0; i<3 && src[offFix] == 0; i++,offFix++); + // cross check with propertyCount field and the property list field + for (int i=0; i<3 && (src[offFix+3] != 0 || src[offFix+7] != 0 || src[offFix+11] != 0); i++,offFix--); + } + + this._offset = offFix; + + LittleEndianByteArrayInputStream leis = new LittleEndianByteArrayInputStream(src, offFix); /* * Read the section length. */ - size = (int) LittleEndian.getUInt(src, o1); - o1 += LittleEndian.INT_SIZE; + size = (int)leis.readUInt(); /* * Read the number of properties. */ - final int propertyCount = (int) LittleEndian.getUInt(src, o1); - o1 += LittleEndian.INT_SIZE; + final int propertyCount = (int)leis.readUInt(); /* * Read the properties. The offset is positioned at the first @@ -169,64 +186,65 @@ public class Section { * seconds pass reads the other properties. */ /* Pass 1: Read the property list. */ - int pass1Offset = o1; - long cpOffset = -1; final TreeBidiMap offset2Id = new TreeBidiMap(); for (int i = 0; i < propertyCount; i++) { /* Read the property ID. */ - long id = LittleEndian.getUInt(src, pass1Offset); - pass1Offset += LittleEndian.INT_SIZE; + long id = (int)leis.readUInt(); /* Offset from the section's start. */ - long off = LittleEndian.getUInt(src, pass1Offset); - pass1Offset += LittleEndian.INT_SIZE; + long off = (int)leis.readUInt(); offset2Id.put(off, id); - - if (id == PropertyIDMap.PID_CODEPAGE) { - cpOffset = off; - } } + Long cpOffset = offset2Id.getKey((long)PropertyIDMap.PID_CODEPAGE); + /* Look for the codepage. */ int codepage = -1; - if (cpOffset != -1) { + if (cpOffset != null) { /* Read the property's value type. It must be VT_I2. */ - long o = this.offset + cpOffset; - final long type = LittleEndian.getUInt(src, (int)o); - o += LittleEndian.INT_SIZE; + leis.setReadIndex((int)(this._offset + cpOffset)); + final long type = leis.readUInt(); if (type != Variant.VT_I2) { throw new HPSFRuntimeException - ("Value type of property ID 1 is not VT_I2 but " + - type + "."); + ("Value type of property ID 1 is not VT_I2 but " + type + "."); } /* Read the codepage number. */ - codepage = LittleEndian.getUShort(src, (int)o); + codepage = leis.readUShort(); } - + /* Pass 2: Read all properties - including the codepage property, * if available. */ for (Map.Entry me : offset2Id.entrySet()) { long off = me.getKey(); long id = me.getValue(); - Property p; - if (id == PropertyIDMap.PID_CODEPAGE) { - p = new Property(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); + + int pLen = propLen(offset2Id, off, size); + leis.setReadIndex((int)(this._offset + off)); + + if (id == PropertyIDMap.PID_DICTIONARY) { + leis.mark(100000); + if (!readDictionary(leis, pLen, codepage)) { + // there was an error reading the dictionary, maybe because the pid (0) was used wrong + // try reading a property instead + leis.reset(); + try { + // fix id + id = Math.max(PropertyIDMap.PID_MAX, offset2Id.inverseBidiMap().lastKey())+1; + setProperty(new MutableProperty(id, leis, pLen, codepage)); + } catch (RuntimeException e) { + LOG.log(POILogger.INFO, "Dictionary fallback failed - ignoring property"); + } + }; + } else if (id == PropertyIDMap.PID_CODEPAGE) { + setCodepage(codepage); } else { - int pLen = propLen(offset2Id, off, size); - long o = this.offset + off; - p = new Property(id, src, o, pLen, codepage); + setProperty(new MutableProperty(id, leis, pLen, codepage)); } - properties.put(id, p); } - - /* - * Extract the dictionary (if available). - */ - dictionary = (Map) getProperty(0); } /** @@ -291,7 +309,7 @@ public class Section { * @return The offset of the section in the stream. */ public long getOffset() { - return offset; + return _offset; } /** @@ -344,11 +362,10 @@ public class Section { * Sets the string value of the property with the specified ID. * * @param id The property's ID - * @param value The property's value. It will be written as a Unicode - * string. + * @param value The property's value. */ public void setProperty(final int id, final String value) { - setProperty(id, Variant.VT_LPWSTR, value); + setProperty(id, Variant.VT_LPSTR, value); } /** @@ -411,8 +428,9 @@ public class Section { * @see #getProperty * @see Variant */ + @SuppressWarnings("deprecation") public void setProperty(final int id, final long variantType, final Object value) { - setProperty(new Property(id, variantType, value)); + setProperty(new MutableProperty(id, variantType, value)); } @@ -591,11 +609,12 @@ public class Section { */ public String getPIDString(final long pid) { String s = null; - if (dictionary != null) { - s = dictionary.get(Long.valueOf(pid)); + Map dic = getDictionary(); + if (dic != null) { + s = dic.get(pid); } if (s == null) { - s = SectionIDMap.getPIDString(getFormatID().getBytes(), pid); + s = SectionIDMap.getPIDString(getFormatID(), pid); } return s; } @@ -614,19 +633,6 @@ public class Section { } } - /** - * Sets the codepage. - * - * @param codepage the codepage - */ - public void setCodepage(final int codepage) - { - setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, - Integer.valueOf(codepage)); - } - - - /** * Checks whether this section is equal to another object. The result is * {@code false} if one of the the following conditions holds: @@ -651,8 +657,9 @@ public class Section { * @return {@code true} if the objects are equal, {@code false} if * not */ + @Override public boolean equals(final Object o) { - if (o == null || !(o instanceof Section)) { + if (!(o instanceof Section)) { return false; } final Section s = (Section) o; @@ -660,59 +667,26 @@ public class Section { return false; } - /* Compare all properties except 0 and 1 as they must be handled - * specially. */ - Property[] pa1 = new Property[getProperties().length]; - Property[] pa2 = new Property[s.getProperties().length]; - System.arraycopy(getProperties(), 0, pa1, 0, pa1.length); - System.arraycopy(s.getProperties(), 0, pa2, 0, pa2.length); - - /* Extract properties 0 and 1 and remove them from the copy of the - * arrays. */ - Property p10 = null; - Property p20 = null; - for (int i = 0; i < pa1.length; i++) { - final long id = pa1[i].getID(); - if (id == 0) { - p10 = pa1[i]; - pa1 = remove(pa1, i); - i--; - } - if (id == 1) { - pa1 = remove(pa1, i); - i--; + /* Compare all properties except the dictionary (id 0) and + * the codepage (id 1 / ignored) as they must be handled specially. */ + Set propIds = new HashSet(properties.keySet()); + propIds.addAll(s.properties.keySet()); + propIds.remove(0L); + propIds.remove(1L); + + for (Long id : propIds) { + Property p1 = properties.get(id); + Property p2 = s.properties.get(id); + if (p1 == null || p2 == null || !p1.equals(p2)) { + return false; } } - for (int i = 0; i < pa2.length; i++) { - final long id = pa2[i].getID(); - if (id == 0) { - p20 = pa2[i]; - pa2 = remove(pa2, i); - i--; - } - if (id == 1) { - pa2 = remove(pa2, i); - i--; - } - } - - /* If the number of properties (not counting property 1) is unequal the - * sections are unequal. */ - if (pa1.length != pa2.length) { - return false; - } /* If the dictionaries are unequal the sections are unequal. */ - boolean dictionaryEqual = true; - if (p10 != null && p20 != null) { - dictionaryEqual = p10.getValue().equals(p20.getValue()); - } else if (p10 != null || p20 != null) { - dictionaryEqual = false; - } - if (dictionaryEqual) { - return Util.equals(pa1, pa2); - } - return false; + Map d1 = getDictionary(); + Map d2 = s.getDictionary(); + + return (d1 == null && d2 == null) || (d1 != null && d2 != null && d1.equals(d2)); } /** @@ -724,22 +698,6 @@ public class Section { dirty |= (properties.remove(id) != null); } - /** - * Removes a field from a property array. The resulting array is - * compactified and returned. - * - * @param pa The property array. - * @param i The index of the field to be removed. - * @return the compactified array. - */ - private Property[] remove(final Property[] pa, final int i) { - final Property[] h = new Property[pa.length - 1]; - if (i > 0) { - System.arraycopy(pa, 0, h, 0, i); - } - System.arraycopy(pa, i + 1, h, i, h.length - i); - return h; - } /** * Writes this section into an output stream.

* @@ -763,6 +721,17 @@ public class Section { return sectionBytes.length; } + /* Writing the section's dictionary it tricky. If there is a dictionary + * (property 0) the codepage property (property 1) must be set, too. */ + int codepage = getCodepage(); + if (codepage == -1) { + String msg = + "The codepage property is not set although a dictionary is present. "+ + "Defaulting to ISO-8859-1."; + LOG.log(POILogger.WARN, msg); + codepage = Property.DEFAULT_CODEPAGE; + } + /* The properties are written to this stream. */ final ByteArrayOutputStream propertyStream = new ByteArrayOutputStream(); @@ -777,79 +746,120 @@ public class Section { /* Increase the position variable by the size of the property list so * that it points behind the property list and to the beginning of the * properties themselves. */ - position += 2 * LittleEndian.INT_SIZE + getPropertyCount() * 2 * LittleEndian.INT_SIZE; + position += 2 * LittleEndianConsts.INT_SIZE + getPropertyCount() * 2 * LittleEndianConsts.INT_SIZE; - /* Writing the section's dictionary it tricky. If there is a dictionary - * (property 0) the codepage property (property 1) must be set, too. */ - int codepage = -1; - if (getProperty(PropertyIDMap.PID_DICTIONARY) != null) { - final Object p1 = getProperty(PropertyIDMap.PID_CODEPAGE); - if (p1 != null) { - if (!(p1 instanceof Integer)) { - throw new IllegalPropertySetDataException - ("The codepage property (ID = 1) must be an " + - "Integer object."); - } - } else { - /* Warning: The codepage property is not set although a - * dictionary is present. In order to cope with this problem we - * add the codepage property and set it to Unicode. */ - setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, - Integer.valueOf(CodePageUtil.CP_UNICODE)); - } - codepage = getCodepage(); - } - /* Write the properties and the property list into their respective * streams: */ for (Property p : properties.values()) { final long id = p.getID(); /* Write the property list entry. */ - TypeWriter.writeUIntToStream(propertyListStream, p.getID()); - TypeWriter.writeUIntToStream(propertyListStream, position); + LittleEndian.putUInt(id, propertyListStream); + LittleEndian.putUInt(position, propertyListStream); /* If the property ID is not equal 0 we write the property and all * is fine. However, if it equals 0 we have to write the section's * dictionary which has an implicit type only and an explicit * value. */ - if (id != 0) + if (id != 0) { /* Write the property and update the position to the next * property. */ - position += p.write(propertyStream, getCodepage()); - else - { - if (codepage == -1) - throw new IllegalPropertySetDataException - ("Codepage (property 1) is undefined."); - position += writeDictionary(propertyStream, dictionary, - codepage); + position += p.write(propertyStream, codepage); + } else { + if (codepage == -1) { + throw new IllegalPropertySetDataException("Codepage (property 1) is undefined."); + } + position += writeDictionary(propertyStream, codepage); } } - propertyStream.close(); - propertyListStream.close(); /* Write the section: */ - byte[] pb1 = propertyListStream.toByteArray(); - byte[] pb2 = propertyStream.toByteArray(); + int streamLength = LittleEndianConsts.INT_SIZE * 2 + propertyListStream.size() + propertyStream.size(); /* Write the section's length: */ - TypeWriter.writeToStream(out, LittleEndian.INT_SIZE * 2 + - pb1.length + pb2.length); + LittleEndian.putInt(streamLength, out); /* Write the section's number of properties: */ - TypeWriter.writeToStream(out, getPropertyCount()); + LittleEndian.putInt(getPropertyCount(), out); /* Write the property list: */ - out.write(pb1); + propertyListStream.writeTo(out); /* Write the properties: */ - out.write(pb2); + propertyStream.writeTo(out); - int streamLength = LittleEndian.INT_SIZE * 2 + pb1.length + pb2.length; return streamLength; } + /** + * Reads a dictionary. + * + * @param leis The byte stream containing the bytes making out the dictionary. + * @param length The dictionary contains at most this many bytes. + * @param codepage The codepage of the string values. + * + * @return {@code true} if dictionary was read successful, {@code false} otherwise + * + * @throws UnsupportedEncodingException if the dictionary's codepage is not + * (yet) supported. + */ + private boolean readDictionary(LittleEndianByteArrayInputStream leis, final int length, final int codepage) + throws UnsupportedEncodingException { + Map dic = new HashMap(); + + /* + * Read the number of dictionary entries. + */ + final long nrEntries = leis.readUInt(); + + long id = -1; + boolean isCorrupted = false; + for (int i = 0; i < nrEntries; i++) { + String errMsg = + "The property set's dictionary contains bogus data. " + + "All dictionary entries starting with the one with ID " + + id + " will be ignored."; + + /* The key. */ + id = leis.readUInt(); + + /* The value (a string). The length is the either the + * number of (two-byte) characters if the character set is Unicode + * or the number of bytes if the character set is not Unicode. + * The length includes terminating 0x00 bytes which we have to strip + * off to create a Java string. */ + long sLength = leis.readUInt(); + + /* Read the string - Strip 0x00 characters from the end of the string. */ + int cp = (codepage == -1) ? Property.DEFAULT_CODEPAGE : codepage; + int nrBytes = (int)((sLength-1) * (cp == CodePageUtil.CP_UNICODE ? 2 : 1)); + if (nrBytes > 0xFFFFFF) { + LOG.log(POILogger.WARN, errMsg); + isCorrupted = true; + break; + } + + try { + byte buf[] = new byte[nrBytes]; + leis.readFully(buf, 0, nrBytes); + final String str = CodePageUtil.getStringFromCodePage(buf, 0, nrBytes, cp); + + int pad = 1; + if (cp == CodePageUtil.CP_UNICODE) { + pad = 2+((4 - ((nrBytes+2) & 0x3)) & 0x3); + } + leis.skip(pad); + + dic.put(id, str); + } catch (RuntimeException ex) { + LOG.log(POILogger.WARN, errMsg, ex); + isCorrupted = true; + break; + } + } + setDictionary(dic); + return !isCorrupted; + } /** @@ -861,48 +871,37 @@ public class Section { * @return The number of bytes written * @exception IOException if an I/O exception occurs. */ - private static int writeDictionary(final OutputStream out, final Map dictionary, final int codepage) + private int writeDictionary(final OutputStream out, final int codepage) throws IOException { - int length = TypeWriter.writeUIntToStream(out, dictionary.size()); - for (Map.Entry ls : dictionary.entrySet()) { - final Long key = ls.getKey(); - final String value = ls.getValue(); + final byte padding[] = new byte[4]; + Map dic = getDictionary(); + + LittleEndian.putUInt(dic.size(), out); + int length = LittleEndianConsts.INT_SIZE; + for (Map.Entry ls : dic.entrySet()) { + + LittleEndian.putUInt(ls.getKey(), out); + length += LittleEndianConsts.INT_SIZE; + + String value = ls.getValue()+"\0"; + LittleEndian.putUInt( value.length(), out ); + length += LittleEndianConsts.INT_SIZE; + + byte bytes[] = CodePageUtil.getBytesInCodePage(value, codepage); + out.write(bytes); + length += bytes.length; if (codepage == CodePageUtil.CP_UNICODE) { - /* Write the dictionary item in Unicode. */ - int sLength = value.length() + 1; - if ((sLength & 1) == 1) { - sLength++; - } - length += TypeWriter.writeUIntToStream(out, key.longValue()); - length += TypeWriter.writeUIntToStream(out, sLength); - final byte[] ca = CodePageUtil.getBytesInCodePage(value, codepage); - for (int j = 2; j < ca.length; j += 2) { - out.write(ca[j+1]); - out.write(ca[j]); - length += 2; - } - sLength -= value.length(); - while (sLength > 0) { - out.write(0x00); - out.write(0x00); - length += 2; - sLength--; - } - } else { - /* Write the dictionary item in another codepage than - * Unicode. */ - length += TypeWriter.writeUIntToStream(out, key.longValue()); - length += TypeWriter.writeUIntToStream(out, value.length() + 1L); - final byte[] ba = CodePageUtil.getBytesInCodePage(value, codepage); - for (int j = 0; j < ba.length; j++) { - out.write(ba[j]); - length++; - } - out.write(0x00); - length++; + int pad = (4 - (length & 0x3)) & 0x3; + out.write(padding, 0, pad); + length += pad; } } + + int pad = (4 - (length & 0x3)) & 0x3; + out.write(padding, 0, pad); + length += pad; + return length; } @@ -924,25 +923,27 @@ public class Section { */ public void setDictionary(final Map dictionary) throws IllegalPropertySetDataException { if (dictionary != null) { - this.dictionary = dictionary; + if (this.dictionary == null) { + this.dictionary = new TreeMap(); + } + this.dictionary.putAll(dictionary); + + /* If the codepage property (ID 1) for the strings (keys and values) + * used in the dictionary is not yet defined, set it to ISO-8859-1. */ + int cp = getCodepage(); + if (cp == -1) { + setCodepage(Property.DEFAULT_CODEPAGE); + } /* Set the dictionary property (ID 0). Please note that the second * parameter in the method call below is unused because dictionaries * don't have a type. */ setProperty(PropertyIDMap.PID_DICTIONARY, -1, dictionary); - - /* If the codepage property (ID 1) for the strings (keys and - * values) used in the dictionary is not yet defined, set it to - * Unicode. */ - final Integer codepage = (Integer) getProperty(PropertyIDMap.PID_CODEPAGE); - if (codepage == null) { - setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, - Integer.valueOf(CodePageUtil.CP_UNICODE)); - } } else { /* Setting the dictionary to null means to remove property 0. * However, it does not mean to remove property 1 (codepage). */ removeProperty(PropertyIDMap.PID_DICTIONARY); + this.dictionary = null; } } @@ -951,6 +952,7 @@ public class Section { /** * @see Object#hashCode() */ + @Override public int hashCode() { long hashCode = 0; hashCode += getFormatID().hashCode(); @@ -967,9 +969,11 @@ public class Section { /** * @see Object#toString() */ + @Override public String toString() { final StringBuffer b = new StringBuffer(); final Property[] pa = getProperties(); + b.append("\n\n\n"); b.append(getClass().getName()); b.append('['); b.append("formatID: "); @@ -981,8 +985,12 @@ public class Section { b.append(", size: "); b.append(getSize()); b.append(", properties: [\n"); - for (int i = 0; i < pa.length; i++) { - b.append(pa[i]); + int codepage = getCodepage(); + if (codepage == -1) { + codepage = Property.DEFAULT_CODEPAGE; + } + for (Property p : pa) { + b.append(p.toString(codepage)); b.append(",\n"); } b.append(']'); @@ -1002,7 +1010,12 @@ public class Section { * @return the dictionary or {@code null} if the section does not have * a dictionary. */ + @SuppressWarnings("unchecked") public Map getDictionary() { + if (dictionary == null) { + dictionary = (Map) getProperty(PropertyIDMap.PID_DICTIONARY); + } + return dictionary; } @@ -1013,13 +1026,17 @@ public class Section { * * @return The section's codepage if one is defined, else -1. */ - public int getCodepage() - { + public int getCodepage() { final Integer codepage = (Integer) getProperty(PropertyIDMap.PID_CODEPAGE); - if (codepage == null) { - return -1; - } - int cp = codepage.intValue(); - return cp; + return (codepage == null) ? -1 : codepage.intValue(); + } + + /** + * Sets the codepage. + * + * @param codepage the codepage + */ + public void setCodepage(final int codepage) { + setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); } } diff --git a/test-data/hpsf/TestBug52372.doc b/test-data/hpsf/TestBug52372.doc new file mode 100644 index 0000000000000000000000000000000000000000..ddaaf5ee9e07f5752cffa47968e73a1df155edef GIT binary patch literal 87040 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