All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.fop.afp.util.AFPResourceUtil Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*
 * 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: AFPResourceUtil.java 1679676 2015-05-16 02:10:42Z adelmelle $ */

package org.apache.fop.afp.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.AFPConstants;
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;

/**
 * TODO better docs
 * Utility for AFP resource handling
 *
 *
 * A utility class to read structured fields from a MO:DCA document. Each
 * component of a mixed object document is explicitly defined and delimited
 * in the data. This is accomplished through the use of MO:DCA data structures,
 * called structured fields. Structured fields are used to envelop document
 * components and to provide commands and information to applications using
 * the data. Structured fields may contain one or more parameters. Each
 * parameter provides one value from a set of values defined by the architecture.
 * 
* MO:DCA structured fields consist of two parts: an introducer that identifies * the length and type of the structured field, and data that provides the * structured field's effect. The data is contained in a set of parameters, * which can consist of other data structures and data elements. The maximum * length of a structured field is 32767 bytes. */ public final class AFPResourceUtil { private static final byte TYPE_CODE_BEGIN = (byte) (0xA8 & 0xFF); private static final byte TYPE_CODE_END = (byte) (0xA9 & 0xFF); private static final byte END_FIELD_ANY_NAME = (byte) (0xFF & 0xFF); private static final Log LOG = LogFactory.getLog(AFPResourceUtil.class); private AFPResourceUtil() { //nop } /** * Get the next structured field as identified by the identifier * parameter (this must be a valid MO:DCA structured field). * @param identifier the three byte identifier * @param inputStream the inputStream * @throws IOException if an I/O exception occurred * @return the next structured field or null when there are no more */ public static byte[] getNext(byte[] identifier, InputStream inputStream) throws IOException { MODCAParser parser = new MODCAParser(inputStream); while (true) { UnparsedStructuredField field = parser.readNextStructuredField(); if (field == null) { return null; } if (field.getSfClassCode() == identifier[0] && field.getSfTypeCode() == identifier[1] && field.getSfCategoryCode() == identifier[2]) { return field.getCompleteFieldAsBytes(); } } } private static String getResourceName(UnparsedStructuredField field) throws UnsupportedEncodingException { //The first 8 bytes of the field data represent the resource name byte[] nameBytes = new byte[8]; byte[] fieldData = field.getData(); if (fieldData.length < 8) { throw new IllegalArgumentException("Field data does not contain a resource name"); } System.arraycopy(fieldData, 0, nameBytes, 0, 8); return new String(nameBytes, AFPConstants.EBCIDIC_ENCODING); } /** * Copy a complete resource file to a given {@link OutputStream}. * @param in external resource input * @param out output destination * @throws IOException if an I/O error occurs */ public static void copyResourceFile(final InputStream in, OutputStream out) throws IOException { MODCAParser parser = new MODCAParser(in); while (true) { UnparsedStructuredField field = parser.readNextStructuredField(); if (field == null) { break; } out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); field.writeTo(out); } } /** * Copy a named resource to a given {@link OutputStream}. The MO:DCA fields read from the * {@link InputStream} are scanned for the resource with the given name. * @param name name of structured field * @param in external resource input * @param out output destination * @throws IOException if an I/O error occurs */ public static void copyNamedResource(String name, final InputStream in, final OutputStream out) throws IOException { final MODCAParser parser = new MODCAParser(in); Collection resourceNames = new java.util.HashSet(); //Find matching "Begin" field final UnparsedStructuredField fieldBegin; while (true) { final UnparsedStructuredField field = parser.readNextStructuredField(); if (field == null) { throw new IOException("Requested resource '" + name + "' not found. Encountered resource names: " + resourceNames); } if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin continue; //Not a "Begin" field } final String resourceName = getResourceName(field); resourceNames.add(resourceName); if (resourceName.equals(name)) { if (LOG.isDebugEnabled()) { LOG.debug("Start of requested structured field found:\n" + field); } fieldBegin = field; break; //Name doesn't match } } //Decide whether the resource file has to be wrapped in a resource object boolean wrapInResource; if (fieldBegin.getSfCategoryCode() == Category.PAGE_SEGMENT) { //A naked page segment must be wrapped in a resource object wrapInResource = true; } else if (fieldBegin.getSfCategoryCode() == Category.NAME_RESOURCE) { //A resource object can be copied directly wrapInResource = false; } else { throw new IOException("Cannot handle resource: " + fieldBegin); } //Copy structured fields (wrapped or as is) if (wrapInResource) { ResourceObject resourceObject = new ResourceObject(name) { protected void writeContent(OutputStream os) throws IOException { copyNamedStructuredFields(name, fieldBegin, parser, out); } }; resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT); resourceObject.writeToStream(out); } else { copyNamedStructuredFields(name, fieldBegin, parser, out); } } private static void copyNamedStructuredFields(final String name, UnparsedStructuredField fieldBegin, MODCAParser parser, OutputStream out) throws IOException { UnparsedStructuredField field = fieldBegin; while (true) { if (field == null) { throw new IOException("Ending structured field not found for resource " + name); } out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); field.writeTo(out); if (isEndOfStructuredField(field, fieldBegin, name)) { break; } field = parser.readNextStructuredField(); } } private static boolean isEndOfStructuredField(UnparsedStructuredField field, UnparsedStructuredField fieldBegin, String name) throws UnsupportedEncodingException { return fieldMatchesEndTagType(field) && fieldMatchesBeginCategoryCode(field, fieldBegin) && fieldHasValidName(field, name); } private static boolean fieldMatchesEndTagType(UnparsedStructuredField field) { return field.getSfTypeCode() == TYPE_CODE_END; } private static boolean fieldMatchesBeginCategoryCode(UnparsedStructuredField field, UnparsedStructuredField fieldBegin) { return fieldBegin.getSfCategoryCode() == field.getSfCategoryCode(); } /** * The AFP specification states that it is valid for the end structured field to have: * - No tag name specified, which will cause it to match any existing tag type match. * - The name has FFFF as its first two bytes * - The given name matches the previous structured field name */ private static boolean fieldHasValidName(UnparsedStructuredField field, String name) throws UnsupportedEncodingException { if (field.getData().length > 0) { if (field.getData()[0] == field.getData()[1] && field.getData()[0] == END_FIELD_ANY_NAME) { return true; } else { return name.equals(getResourceName(field)); } } return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy