diff options
author | Peter Hancock <phancock@apache.org> | 2011-05-17 11:07:06 +0000 |
---|---|---|
committer | Peter Hancock <phancock@apache.org> | 2011-05-17 11:07:06 +0000 |
commit | 98264493c4bf2806bb710586b2c4726369080245 (patch) | |
tree | 8968533241acf7aa290f0af53d270ccf9d6fdbe7 /src/java | |
parent | 418ed80ccbe885fe2e52cafd71daee26f203addc (diff) | |
download | xmlgraphics-fop-98264493c4bf2806bb710586b2c4726369080245.tar.gz xmlgraphics-fop-98264493c4bf2806bb710586b2c4726369080245.zip |
Fixed io exception in MODCAParser caused by the improper use of mark() and reset()
on the MODCA data input stream. See bugzilla 50909.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1104135 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
4 files changed, 373 insertions, 354 deletions
diff --git a/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java b/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java index 0adffcd8b..7a2b8ed36 100644 --- a/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java +++ b/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java @@ -55,9 +55,10 @@ public class FontPatternExtractor { UnparsedStructuredField strucField; while ((strucField = parser.readNextStructuredField()) != null) { if (strucField.getSfTypeID() == 0xD3EE89) { + byte[] sfData = strucField.getData(); println(strucField.toString()); - HexDump.dump(strucField.getData(), 0, printStream, 0); - baout.write(strucField.getData()); + HexDump.dump(sfData, 0, printStream, 0); + baout.write(sfData); } } diff --git a/src/java/org/apache/fop/afp/parser/MODCAParser.java b/src/java/org/apache/fop/afp/parser/MODCAParser.java index 356d4f169..d0d0eced9 100644 --- a/src/java/org/apache/fop/afp/parser/MODCAParser.java +++ b/src/java/org/apache/fop/afp/parser/MODCAParser.java @@ -20,15 +20,23 @@ package org.apache.fop.afp.parser; import java.io.DataInputStream; -import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.afp.parser.UnparsedStructuredField.Introducer; + /** * An simple MO:DCA/AFP parser. */ public class MODCAParser { + private static final Log LOG = LogFactory.getLog(MODCAParser.class); + + private static final int INTRODUCER_LENGTH = 8; + /** The carriage control character (0x5A) used to indicate the start of a structured field. */ public static final byte CARRIAGE_CONTROL_CHAR = (byte)(0x5A & 0xFF); @@ -39,19 +47,9 @@ public class MODCAParser { * @param in the {@link InputStream} to read the AFP file from. */ public MODCAParser(InputStream in) { - if (!in.markSupported()) { - in = new java.io.BufferedInputStream(in); - } this.din = new DataInputStream(in); } - /** - * Returns the {@link DataInputStream} used for parsing structured fields. - * @return the data input stream - */ - public DataInputStream getDataInputStream() { - return this.din; - } /** * Reads the next structured field from the input stream. @@ -61,20 +59,46 @@ public class MODCAParser { * @throws IOException if an I/O error occurs */ public UnparsedStructuredField readNextStructuredField() throws IOException { - try { - while (true) { - byte b = din.readByte(); //Skip 0x5A character if necessary (ex. AFP) - if (b == 0x0D || b == 0x0A) { - //CR and LF may be used as field delimiters - continue; - } else if (b == CARRIAGE_CONTROL_CHAR) { - break; //Signals the start of a new structured field - } + + //Find the SF delimiter + do { + //Exhausted streams and so no next SF + // - null return represents this case + // TODO should this happen? + if (din.available() == 0) { + return null; + } + } while (din.readByte() != CARRIAGE_CONTROL_CHAR); + + //Read introducer as byte array to preserve any data not parsed below + byte[] introducerData = new byte[INTRODUCER_LENGTH]; //Length of introducer + din.readFully(introducerData); + + Introducer introducer = new Introducer(introducerData); + + int dataLength = introducer.getLength() - INTRODUCER_LENGTH; + + //Handle optional extension + byte[] extData = null; + if (introducer.isExtensionPresent()) { + short extLength = 0; + extLength = (short)((din.readByte()) & 0xFF); + if (extLength > 0) { + extData = new byte[extLength - 1]; + din.readFully(extData); + dataLength -= extLength; } - } catch (EOFException eof) { - return null; } - return UnparsedStructuredField.readStructuredField(getDataInputStream()); - } + //Read payload + byte[] data = new byte[dataLength]; + din.readFully(data); + UnparsedStructuredField sf = new UnparsedStructuredField(introducer, data, extData); + + if (LOG.isTraceEnabled()) { + LOG.trace(sf); + } + + return sf; + } } diff --git a/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java b/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java index f775c05ee..4f782c5b1 100644 --- a/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java +++ b/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java @@ -19,337 +19,331 @@ package org.apache.fop.afp.parser; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; -import java.io.EOFException; import java.io.IOException; import java.io.OutputStream; -import java.io.PrintStream; import java.text.DecimalFormat; -import org.apache.commons.io.HexDump; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - /** - * Represents an unparsed (generic) AFP structured field. - */ -public class UnparsedStructuredField { - - private static final Log LOG = LogFactory.getLog(UnparsedStructuredField.class); - - private static final int INTRODUCER_LENGTH = 8; - - private short sfLength; - private byte sfClassCode; - private byte sfTypeCode; - private byte sfCategoryCode; - private boolean sfiExtensionPresent; - private boolean sfiSegmentedData; - private boolean sfiPaddingPresent; - private short extLength; - private byte[] introducerData; - private byte[] extData; - private byte[] data; - - /** - * Default constructor. - */ - public UnparsedStructuredField() { - //nop - } - - /** - * Reads a structured field from a {@link DataInputStream}. The resulting object can be - * further interpreted be follow-up code. - * @param din the stream to read from - * @return the generic structured field - * @throws IOException if an I/O error occurs - */ - public static UnparsedStructuredField readStructuredField(DataInputStream din) - throws IOException { - UnparsedStructuredField sf = new UnparsedStructuredField(); - - //Read introducer as byte array to preserve any data not parsed below - din.mark(INTRODUCER_LENGTH); - sf.introducerData = new byte[INTRODUCER_LENGTH]; //Length of introducer - din.readFully(sf.introducerData); - din.reset(); - - //Parse the introducer - short len; - try { - len = din.readShort(); - } catch (EOFException eof) { - return null; - } - sf.sfLength = len; - sf.sfClassCode = din.readByte(); - sf.sfTypeCode = din.readByte(); - sf.sfCategoryCode = din.readByte(); - - //Flags - byte f = din.readByte(); - sf.sfiExtensionPresent = (f & 0x01) != 0; - sf.sfiSegmentedData = (f & 0x04) != 0; - sf.sfiPaddingPresent = (f & 0x10) != 0; - din.skip(2); //Reserved - - int dataLength = sf.sfLength - INTRODUCER_LENGTH; - - //Handle optional extension - if (sf.sfiExtensionPresent) { - sf.extLength = (short)(((short)din.readByte()) & 0xFF); - if (sf.extLength > 0) { - sf.extData = new byte[sf.extLength - 1]; - din.readFully(sf.extData); - dataLength -= sf.extLength; - } - } - - //Read payload - sf.data = new byte[dataLength]; - din.readFully(sf.data); - - if (LOG.isTraceEnabled()) { - LOG.trace(sf); - } - - return sf; - } - - /** {@inheritDoc} */ - public String toString() { - StringBuffer sb = new StringBuffer("Structured Field: "); - sb.append(Integer.toHexString(getSfTypeID()).toUpperCase()); - sb.append(", len="); - sb.append(new DecimalFormat("00000").format(getSfLength())); - sb.append(" ").append(getTypeCodeAsString()); - sb.append(" ").append(getCategoryCodeAsString()); - if (isSfiExtensionPresent()) { - sb.append(", SFI extension present"); - } - if (isSfiSegmentedData()) { - sb.append(", segmented data"); - } - if (isSfiPaddingPresent()) { - sb.append(", with padding"); - } - return sb.toString(); - } - - /** - * Dump the structured field as hex data to the given {@link PrintStream}. - * @param out the {@link PrintStream} to dump to - * @throws IOException if an I/O error occurs - */ - public void dump(PrintStream out) throws IOException { - out.println(toString()); - HexDump.dump(getData(), 0, out, 0); - } - - /** - * Dump the structured field as hex data to <code>System.out</code>. - * @throws IOException if an I/O error occurs - */ - public void dump() throws IOException { - dump(System.out); - } - - /** - * Returns type code function name for this field. - * @return the type code function name - */ - public String getTypeCodeAsString() { - switch ((int)getSfTypeCode() & 0xFF) { - case 0xA0: return "Attribute"; - case 0xA2: return "CopyCount"; - case 0xA6: return "Descriptor"; - case 0xA7: return "Control"; - case 0xA8: return "Begin"; - case 0xA9: return "End"; - case 0xAB: return "Map"; - case 0xAC: return "Position"; - case 0xAD: return "Process"; - case 0xAF: return "Include"; - case 0xB0: return "Table"; - case 0xB1: return "Migration"; - case 0xB2: return "Variable"; - case 0xB4: return "Link"; - case 0xEE: return "Data"; - default: return "Unknown:" + Integer.toHexString((int)getSfTypeCode()).toUpperCase(); - } - } - - /** - * Returns category code function name for this field. - * @return the category code function name - */ - public String getCategoryCodeAsString() { - switch ((int)getSfCategoryCode() & 0xFF) { - case 0x5F: return "Page Segment"; - case 0x6B: return "Object Area"; - case 0x77: return "Color Attribute Table"; - case 0x7B: return "IM Image"; - case 0x88: return "Medium"; - case 0x89: return "Font"; - case 0x8A: return "Coded Font"; - case 0x90: return "Process Element"; - case 0x92: return "Object Container"; - case 0x9B: return "Presentation Text"; - case 0xA7: return "Index"; - case 0xA8: return "Document"; - case 0xAD: return "Page Group"; - case 0xAF: return "Page"; - case 0xBB: return "Graphics"; - case 0xC3: return "Data Resource"; - case 0xC4: return "Document Environment Group (DEG)"; - case 0xC6: return "Resource Group"; - case 0xC7: return "Object Environment Group (OEG)"; - case 0xC9: return "Active Environment Group (AEG)"; - case 0xCC: return "Medium Map"; - case 0xCD: return "Form Map"; - case 0xCE: return "Name Resource"; - case 0xD8: return "Page Overlay"; - case 0xD9: return "Resource Environment Group (REG)"; - case 0xDF: return "Overlay"; - case 0xEA: return "Data Supression"; - case 0xEB: return "Bar Code"; - case 0xEE: return "No Operation"; - case 0xFB: return "Image"; - default: return "Unknown:" + Integer.toHexString((int)getSfTypeCode()).toUpperCase(); - } - } - - /** - * Returns the structured field's length. - * @return the field length - */ - public short getSfLength() { - return this.sfLength; - } - - /** - * Returns the structured field's identifier. - * @return the field identifier - */ - public int getSfTypeID() { - return ((getSfClassCode() & 0xFF) << 16) - | ((getSfTypeCode() & 0xFF) << 8) - | (getSfCategoryCode() & 0xFF); - } - - /** - * Returns the structured field's class code. - * @return the field class code - */ - public byte getSfClassCode() { - return this.sfClassCode; - } - - /** - * Returns the structured field's type code. - * @return the type code - */ - public byte getSfTypeCode() { - return this.sfTypeCode; - } - - /** - * Returns the structured field's category code. - * @return the sfCategoryCode - */ - public byte getSfCategoryCode() { - return this.sfCategoryCode; - } - - /** - * Indicates whether an field introducer extension is present. - * @return true if an field introducer extension is present - */ - public boolean isSfiExtensionPresent() { - return this.sfiExtensionPresent && (this.extData != null); - } - - /** - * Indicates whether segmented data is present. - * @return true if the data is segmented - */ - public boolean isSfiSegmentedData() { - return this.sfiSegmentedData; - } - - /** - * Indicates whether the data is padded. - * @return true if the data is padded - */ - public boolean isSfiPaddingPresent() { - return this.sfiPaddingPresent; - } - - /** - * Returns the length of the extension if present. - * @return the length of the extension (or 0 if no extension is present) - */ - public short getExtLength() { - return this.extLength; - } - - /** - * Returns the extension data if present. - * @return the extension data (or null if no extension is present) - */ - public byte[] getExtData() { - return this.extData; - } - - /** - * Returns the structured field's payload. - * @return the field's data - */ - public byte[] getData() { - return this.data; - } - - /** - * Returns the structured field's introducer data. - * @return the introducer data - */ - public byte[] getIntroducerData() { - return this.introducerData; - } - - /** - * Returns the complete structured field as a byte array. - * @return the complete field data - */ - public byte[] getCompleteFieldAsBytes() { - int len = INTRODUCER_LENGTH; - if (isSfiExtensionPresent()) { - len += getExtLength(); - } - len += getData().length; - byte[] bytes = new byte[len]; - int pos = 0; - System.arraycopy(getIntroducerData(), 0, bytes, pos, INTRODUCER_LENGTH); - pos += INTRODUCER_LENGTH; - if (isSfiExtensionPresent()) { - System.arraycopy(getExtData(), 0, bytes, pos, getExtLength()); - pos += getExtLength(); - } - System.arraycopy(getData(), 0, bytes, pos, getData().length); - return bytes; - } - - /** - * Writes this structured field to the given {@link OutputStream}. - * @param out the output stream - * @throws IOException if an I/O error occurs - */ - public void writeTo(OutputStream out) throws IOException { - out.write(this.introducerData); - if (isSfiExtensionPresent()) { - out.write(this.extData); - } - out.write(this.data); - } +* Represents an unparsed (generic) AFP structured field. +*/ +public final class UnparsedStructuredField { + + private final Introducer introducer; + private final byte[] extData; + private final byte[] data; + + /** + * + * @param Structured field introducer + * @param data Structured field data + * @param extData Structured field extension data + */ + UnparsedStructuredField(Introducer introducer, + byte[] data, byte[] extData) { + this.introducer = introducer; + this.data = data; + if (extData != null) { + this.extData = extData; + } else { + this.extData = null; + } + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer("Structured Field: "); + sb.append(Integer.toHexString(getSfTypeID()).toUpperCase()); + sb.append(", len="); + sb.append(new DecimalFormat("00000").format(getSfLength())); + sb.append(" ").append(getTypeCodeAsString()); + sb.append(" ").append(getCategoryCodeAsString()); + if (isSfiExtensionPresent()) { + sb.append(", SFI extension present"); + } + if (isSfiSegmentedData()) { + sb.append(", segmented data"); + } + if (isSfiPaddingPresent()) { + sb.append(", with padding"); + } + return sb.toString(); + } + + + /** + * Returns type code function name for this field. + * @return the type code function name + */ + private String getTypeCodeAsString() { + switch (getSfTypeCode() & 0xFF) { + case 0xA0: return "Attribute"; + case 0xA2: return "CopyCount"; + case 0xA6: return "Descriptor"; + case 0xA7: return "Control"; + case 0xA8: return "Begin"; + case 0xA9: return "End"; + case 0xAB: return "Map"; + case 0xAC: return "Position"; + case 0xAD: return "Process"; + case 0xAF: return "Include"; + case 0xB0: return "Table"; + case 0xB1: return "Migration"; + case 0xB2: return "Variable"; + case 0xB4: return "Link"; + case 0xEE: return "Data"; + default: return "Unknown:" + Integer.toHexString(getSfTypeCode()).toUpperCase(); + } + } + + /** + * Returns category code function name for this field. + * @return the category code function name + */ + private String getCategoryCodeAsString() { + switch (getSfCategoryCode() & 0xFF) { + case 0x5F: return "Page Segment"; + case 0x6B: return "Object Area"; + case 0x77: return "Color Attribute Table"; + case 0x7B: return "IM Image"; + case 0x88: return "Medium"; + case 0x89: return "Font"; + case 0x8A: return "Coded Font"; + case 0x90: return "Process Element"; + case 0x92: return "Object Container"; + case 0x9B: return "Presentation Text"; + case 0xA7: return "Index"; + case 0xA8: return "Document"; + case 0xAD: return "Page Group"; + case 0xAF: return "Page"; + case 0xBB: return "Graphics"; + case 0xC3: return "Data Resource"; + case 0xC4: return "Document Environment Group (DEG)"; + case 0xC6: return "Resource Group"; + case 0xC7: return "Object Environment Group (OEG)"; + case 0xC9: return "Active Environment Group (AEG)"; + case 0xCC: return "Medium Map"; + case 0xCD: return "Form Map"; + case 0xCE: return "Name Resource"; + case 0xD8: return "Page Overlay"; + case 0xD9: return "Resource Environment Group (REG)"; + case 0xDF: return "Overlay"; + case 0xEA: return "Data Supression"; + case 0xEB: return "Bar Code"; + case 0xEE: return "No Operation"; + case 0xFB: return "Image"; + default: return "Unknown:" + Integer.toHexString(getSfTypeCode()).toUpperCase(); + } + } + + /** + * Returns the structured field's length. + * @return the field length + */ + public short getSfLength() { + return introducer.length; + } + + /** + * Returns the structured field's identifier. + * @return the field identifier + */ + public int getSfTypeID() { + return ((getSfClassCode() & 0xFF) << 16) + | ((getSfTypeCode() & 0xFF) << 8) + | (getSfCategoryCode() & 0xFF); + } + + /** + * Returns the structured field's class code. + * @return the field class code + */ + public byte getSfClassCode() { + return introducer.classCode; + } + + /** + * Returns the structured field's type code. + * @return the type code + */ + public byte getSfTypeCode() { + return introducer.typeCode; + } + + /** + * Returns the structured field's category code. + * @return the sfCategoryCode + */ + public byte getSfCategoryCode() { + return introducer.categoryCode; + } + + /** + * Indicates whether an field introducer extension is present. + * @return true if an field introducer extension is present + */ + public boolean isSfiExtensionPresent() { + return introducer.extensionPresent && (this.extData != null); + } + + /** + * Indicates whether segmented data is present. + * @return true if the data is segmented + */ + public boolean isSfiSegmentedData() { + return introducer.segmentedData; + } + + /** + * Indicates whether the data is padded. + * @return true if the data is padded + */ + public boolean isSfiPaddingPresent() { + return introducer.paddingPresent; + } + + /** + * Returns the length of the extension if present. + * @return the length of the extension (or 0 if no extension is present) + */ + public short getExtLength() { + return (extData != null) ? (short)(extData.length + 1) : 0; + + } + + /** + * Returns the extension data if present. + * @return the extension data (or null if no extension is present) + */ + byte[] getExtData() { + if (this.extData == null) { + return null; + } + byte[] rtn = new byte[this.extData.length]; + System.arraycopy(this.extData, 0, rtn, 0, rtn.length); + return rtn; + } + + /** + * Returns the structured field's payload. + * @return the field's data + */ + public byte[] getData() { + if (this.data == null) { + return null; + } + byte[] rtn = new byte[this.data.length]; + System.arraycopy(this.data, 0, rtn, 0, rtn.length); + return rtn; + } + + //For unit testing + byte[] getIntroducerData() { + return introducer.getIntroducerData(); + } + + /** + * Returns the complete structured field as a byte array. + * @return the complete field data + */ + public byte[] getCompleteFieldAsBytes() { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(getSfLength()); + try { + writeTo(baos); + } catch (IOException ioe) { + //nop + } + return baos.toByteArray(); + + } + + /** + * Writes this structured field to the given {@link OutputStream}. + * @param out the output stream + * @throws IOException if an I/O error occurs + */ + public void writeTo(OutputStream out) throws IOException { + out.write(introducer.introducerData); + if (isSfiExtensionPresent()) { + out.write(this.extData.length + 1); + out.write(this.extData); + } + out.write(this.data); + } + + static final class Introducer { + + private final short length; + private final byte classCode; + private final byte typeCode; + private final byte categoryCode; + private final boolean extensionPresent; + private final boolean segmentedData; + private final boolean paddingPresent; + private final byte[] introducerData; + + Introducer(byte[] introducerData) throws IOException { + + this.introducerData = introducerData; + + // Parse the introducer; the 8 bytes have already been read from the stream just + // before, so we parse the introducer from the byte array + DataInputStream iis = new DataInputStream( + new ByteArrayInputStream(introducerData)); + + length = iis.readShort(); + + classCode = iis.readByte(); + typeCode = iis.readByte(); + categoryCode = iis.readByte(); + + //Flags + byte f = iis.readByte(); + + extensionPresent = (f & 0x01) != 0; + segmentedData = (f & 0x04) != 0; + paddingPresent = (f & 0x10) != 0; + + } + + + public short getLength() { + return length; + } + + public byte getClassCode() { + return classCode; + } + + public byte getTypeCode() { + return typeCode; + } + + public byte getCategoryCode() { + return categoryCode; + } + + public boolean isExtensionPresent() { + return extensionPresent; + } + + + public boolean isSegmentedData() { + return segmentedData; + } + + public boolean isPaddingPresent() { + return paddingPresent; + } + + public byte[] getIntroducerData() { + byte[] rtn = new byte[introducerData.length]; + System.arraycopy(introducerData, 0, rtn, 0, rtn.length); + return rtn; + } + } + } diff --git a/src/java/org/apache/fop/afp/util/AFPResourceUtil.java b/src/java/org/apache/fop/afp/util/AFPResourceUtil.java index ebb318046..979376b3e 100644 --- a/src/java/org/apache/fop/afp/util/AFPResourceUtil.java +++ b/src/java/org/apache/fop/afp/util/AFPResourceUtil.java @@ -29,8 +29,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPConstants; -import org.apache.fop.afp.modca.ResourceObject; import org.apache.fop.afp.modca.AbstractAFPObject.Category; +import org.apache.fop.afp.modca.ResourceObject; import org.apache.fop.afp.parser.MODCAParser; import org.apache.fop.afp.parser.UnparsedStructuredField; |