blob: 2c612092edec5922834c580431dbe255643b5fac [file] [log] [blame]
/*
* 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$ */
package org.apache.fop.afp.modca;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.afp.Streamable;
import org.apache.fop.afp.util.BinaryUtils;
/**
* This is the base class for all data stream objects. Page objects are
* responsible for building and generating the binary datastream in an
* AFP format.
*/
public abstract class AbstractAFPObject implements Streamable {
/** Static logging instance */
protected static final Log LOG = LogFactory.getLog(AbstractAFPObject.class);
/** the structured field class id */
protected static final byte SF_CLASS = (byte)0xD3;
private static final byte[] SF_HEADER = new byte[] {
0x5A, // Structured field identifier
0x00, // Length byte 1
0x10, // Length byte 2
SF_CLASS, // Structured field id byte 1
(byte) 0x00, // Structured field id byte 2
(byte) 0x00, // Structured field id byte 3
0x00, // Flags
0x00, // Reserved
0x00, // Reserved
};
/** Length of bytes of a Structured Field Header */
protected static final int SF_HEADER_LENGTH = SF_HEADER.length;
/**
* Copies the template structured field data array to the given byte array
*
* @param data the structured field data byte array
* @param type the type code
* @param category the category code
*/
protected void copySF(byte[] data, byte type, byte category) {
copySF(data, SF_CLASS, type, category);
}
/**
* Copies the template structured field data array to the given byte array
*
* @param data the structured field data byte array
* @param clazz the class code
* @param type the type code
* @param category the category code
*/
protected static void copySF(byte[] data, byte clazz, byte type, byte category) {
System.arraycopy(SF_HEADER, 0, data, 0, SF_HEADER_LENGTH);
data[3] = clazz;
data[4] = type;
data[5] = category;
}
/**
* Writes a collection of Streamable to the AFP Datastream.
*
* @param objects a list of AFPObjects
* @param <S> Streamable view of an AFPObject
* @param os The stream to write to
* @throws java.io.IOException an I/O exception of some sort has occurred.
*/
protected <S extends Streamable> void writeObjects(Collection<S> objects, OutputStream os)
throws IOException {
if (objects != null) {
Iterator<S> it = objects.iterator();
while (it.hasNext()) {
Streamable s = it.next();
s.writeToStream(os);
it.remove(); // once written, immediately remove the object
}
}
}
/**
* Writes data chunks to a given outputstream
*
* @param data the data byte array
* @param dataHeader the header data
* @param lengthOffset offset of length field in data chunk
* @param maxChunkLength the maximum chunk length
* @param os the outputstream to write to
* @throws IOException thrown if an I/O exception of some sort has occurred.
*/
protected static void writeChunksToStream(byte[] data, byte[] dataHeader,
int lengthOffset, int maxChunkLength, OutputStream os) throws IOException {
int dataLength = data.length;
int numFullChunks = dataLength / maxChunkLength;
int lastChunkLength = dataLength % maxChunkLength;
int headerLen = dataHeader.length - lengthOffset;
// length field is just before data so do not include in data length
if (headerLen == 2) {
headerLen = 0;
}
byte[] len;
int off = 0;
if (numFullChunks > 0) {
// write out full data chunks
len = BinaryUtils.convert(headerLen + maxChunkLength, 2);
dataHeader[lengthOffset] = len[0]; // Length byte 1
dataHeader[lengthOffset + 1] = len[1]; // Length byte 2
for (int i = 0; i < numFullChunks; i++, off += maxChunkLength) {
os.write(dataHeader);
os.write(data, off, maxChunkLength);
}
}
if (lastChunkLength > 0) {
// write last data chunk
len = BinaryUtils.convert(headerLen + lastChunkLength, 2);
dataHeader[lengthOffset] = len[0]; // Length byte 1
dataHeader[lengthOffset + 1] = len[1]; // Length byte 2
os.write(dataHeader);
os.write(data, off, lastChunkLength);
}
}
/**
* Truncates the string as necessary
*
* @param str a character string
* @param maxLength the maximum length allowed for the string
* @return a possibly truncated string
*/
protected static String truncate(String str, int maxLength) {
if (str.length() > maxLength) {
str = str.substring(0, maxLength);
LOG.warn("truncated character string '"
+ str + "', longer than " + maxLength + " chars");
}
return str;
}
/** structured field type codes */
public interface Type {
/** Attribute */
byte ATTRIBUTE = (byte)0xA0;
/** Copy Count */
byte COPY_COUNT = (byte)0xA2;
/** Descriptor */
byte DESCRIPTOR = (byte)0xA6;
/** Control */
byte CONTROL = (byte)0xA7;
/** Begin */
byte BEGIN = (byte)0xA8;
/** End */
byte END = (byte)0xA9;
/** Map */
byte MAP = (byte)0xAB;
/** Position */
byte POSITION = (byte)0xAC;
/** Process */
byte PROCESS = (byte)0xAD;
/** Include */
byte INCLUDE = (byte)0xAF;
/** Table */
byte TABLE = (byte)0xB0;
/** Migration */
byte MIGRATION = (byte)0xB1;
/** Variable */
byte VARIABLE = (byte)0xB2;
/** Link */
byte LINK = (byte)0xB4;
/** Data */
byte DATA = (byte)0xEE;
}
/** structured field category codes */
public interface Category {
/** Page Segment */
byte PAGE_SEGMENT = (byte)0x5F;
/** Object Area */
byte OBJECT_AREA = (byte)0x6B;
/** Color Attribute Table */
byte COLOR_ATTRIBUTE_TABLE = (byte)0x77;
/** IM Image */
byte IM_IMAGE = (byte)0x7B;
/** Medium */
byte MEDIUM = (byte)0x88;
/** Coded Font */
byte CODED_FONT = (byte)0x8A;
/** Process Element */
byte PROCESS_ELEMENT = (byte)0x90;
/** Object Container */
byte OBJECT_CONTAINER = (byte)0x92;
/** Presentation Text */
byte PRESENTATION_TEXT = (byte)0x9B;
/** Index */
byte INDEX = (byte)0xA7;
/** Document */
byte DOCUMENT = (byte)0xA8;
/** Page Group */
byte PAGE_GROUP = (byte)0xAD;
/** Page */
byte PAGE = (byte)0xAF;
/** Graphics */
byte GRAPHICS = (byte)0xBB;
/** Data Resource */
byte DATA_RESOURCE = (byte)0xC3;
/** Document Environment Group (DEG) */
byte DOCUMENT_ENVIRONMENT_GROUP = (byte)0xC4;
/** Resource Group */
byte RESOURCE_GROUP = (byte)0xC6;
/** Object Environment Group (OEG) */
byte OBJECT_ENVIRONMENT_GROUP = (byte)0xC7;
/** Active Environment Group (AEG) */
byte ACTIVE_ENVIRONMENT_GROUP = (byte)0xC9;
/** Medium Map */
byte MEDIUM_MAP = (byte)0xCC;
/** Form Map */
byte FORM_MAP = (byte)0xCD;
/** Name Resource */
byte NAME_RESOURCE = (byte)0xCE;
/** Page Overlay */
byte PAGE_OVERLAY = (byte)0xD8;
/** Resource Environment Group (REG) */
byte RESOURCE_ENVIROMENT_GROUP = (byte)0xD9;
/** Overlay */
byte OVERLAY = (byte)0xDF;
/** Data Suppression */
byte DATA_SUPRESSION = (byte)0xEA;
/** Bar Code */
byte BARCODE = (byte)0xEB;
/** No Operation */
byte NO_OPERATION = (byte)0xEE;
/** Image */
byte IMAGE = (byte)0xFB;
}
}