/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: UnparsedStructuredField.java 1135995 2011-06-15 11:04:33Z spepping $ */

package org.apache.fop.afp.parser;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;

Represents an unparsed (generic) AFP structured field.
/** * Represents an unparsed (generic) AFP structured field. */
public final class UnparsedStructuredField { private final Introducer introducer; private final byte[] extData; private final byte[] data;
Params:
  • Structured – field introducer
  • data – Structured field data
  • extData – Structured field extension 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.
Returns:the type code function name
/** * 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.
Returns:the category code function name
/** * 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.
Returns:the field length
/** * Returns the structured field's length. * @return the field length */
public short getSfLength() { return introducer.length; }
Returns the structured field's identifier.
Returns:the field identifier
/** * 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.
Returns:the field class code
/** * 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.
Returns:the type code
/** * Returns the structured field's type code. * @return the type code */
public byte getSfTypeCode() { return introducer.typeCode; }
Returns the structured field's category code.
Returns:the sfCategoryCode
/** * Returns the structured field's category code. * @return the sfCategoryCode */
public byte getSfCategoryCode() { return introducer.categoryCode; }
Indicates whether an field introducer extension is present.
Returns:true if an field introducer extension is present
/** * 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.
Returns:true if the data is segmented
/** * 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.
Returns:true if the data is padded
/** * 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.
Returns:the length of the extension (or 0 if no extension is present)
/** * 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.
Returns:the extension data (or null if no extension is present)
/** * Returns the extension data if present. * @return the extension data (or null if no extension is present) */
byte[] getExtData() { if (this.extData == null) { return new byte[0]; } byte[] rtn = new byte[this.extData.length]; System.arraycopy(this.extData, 0, rtn, 0, rtn.length); return rtn; }
Returns the structured field's payload.
Returns:the field's data
/** * Returns the structured field's payload. * @return the field's data */
public byte[] getData() { if (this.data == null) { return new byte[0]; } 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.
Returns:the complete field data
/** * 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 OutputStream.
Params:
  • out – the output stream
Throws:
/** * 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; } } }