| /* |
| * 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; |
| } |
| |
| } |
| |