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

de.intarsys.pdf.font.StreamBasedCMap Maven / Gradle / Ivy

/*
 * Copyright (c) 2007, intarsys consulting GmbH
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * - Neither the name of intarsys nor the names of its contributors may be used
 *   to endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package de.intarsys.pdf.font;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import de.intarsys.pdf.content.CSContent;
import de.intarsys.pdf.content.CSOperation;
import de.intarsys.pdf.cos.COSArray;
import de.intarsys.pdf.cos.COSDictionary;
import de.intarsys.pdf.cos.COSInteger;
import de.intarsys.pdf.cos.COSName;
import de.intarsys.pdf.cos.COSNull;
import de.intarsys.pdf.cos.COSObject;
import de.intarsys.pdf.cos.COSString;

/**
 * A stream based mapping from character codes to CID's.
 * 

* The data in the stream defines the mapping from character codes to a font * number and a character selector. The data must follow the syntax defined in * Adobe Technical Note #5014, Adobe CMap and CIDFont Files Specification. */ abstract public class StreamBasedCMap extends CMap { /** * The meta class implementation */ public static class MetaClass extends CMap.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } } public static final COSName DK_CIDSystemInfo = COSName .constant("CIDSystemInfo"); public static final COSName DK_CMapName = COSName.constant("CMapName"); public static final COSName DK_UseCMap = COSName.constant("UseCMap"); public static final COSName DK_WMode = COSName.constant("WMode"); /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class .getDeclaringClass()); private Map definitions = new HashMap(); /** * The maps from bytes to CID's */ private List maps = new ArrayList(); /** * The notdef maps */ private List notdefs = new ArrayList(); /** * The codespace ranges */ private CMapRange[][] ranges = new CMapRange[4][0]; /** * @param object */ protected StreamBasedCMap(COSObject object) { super(object); } protected void addDefinition(COSName key, COSObject value) { definitions.put(key, value); } protected void addMap(CMapMap map) { maps.add(map); } protected void addNotdef(CMapMap notdef) { notdefs.add(notdef); } protected void addRange(CMapRange range) { int count = range.getByteCount(); CMapRange[] rangeArray = ranges[count]; CMapRange[] tempArray = new CMapRange[rangeArray.length + 1]; System.arraycopy(rangeArray, 0, tempArray, 0, rangeArray.length); tempArray[rangeArray.length] = range; ranges[count] = tempArray; } protected boolean checkPrefix(byte[] bytes, int count) { for (int k = 0; k < ranges.length; k++) { CMapRange[] rangeArray = ranges[k]; for (int i = 0; i < rangeArray.length; i++) { CMapRange range = rangeArray[i]; if (range.checkPrefix(bytes, count)) { return true; } } } return false; } protected boolean checkRange(byte[] bytes, int count) { if (count >= ranges.length) { return false; } CMapRange[] rangeArray = ranges[count]; for (int i = 0; i < rangeArray.length; i++) { CMapRange range = rangeArray[i]; if (range.checkRange(bytes, count)) { return true; } } return false; } protected void do_beginbfchar(CSOperation operation) { // no op, ignore size } protected void do_beginbfrange(CSOperation operation) { // no op, ignore size } protected void do_begincidchar(CSOperation operation) { // no op, ignore size } protected void do_begincidrange(CSOperation operation) { // no op, ignore size } /** * */ protected void do_begincmap(CSOperation operation) { // this is a no op } /** * */ protected void do_begincodespacerange(CSOperation operation) { // no op, ignore size } /** * */ protected void do_beginnotdefchar(CSOperation operation) { // no op, ignore size } /** * */ protected void do_beginnotdefrange(CSOperation operation) { // no op, ignore size } protected void do_def(CSOperation operation) { // define key / value association Iterator it = operation.getOperands(); COSObject operand = COSNull.NULL; if (it.hasNext()) { operand = (COSObject) it.next(); } COSDictionary dict = operand.asDictionary(); if (dict == null) { COSName key = operand.asName(); if (key == null) { return; } COSObject value = COSNull.NULL; if (it.hasNext()) { value = (COSObject) it.next(); } addDefinition(key, value); } else { Iterator> eit = dict.entryIterator(); while (eit.hasNext()) { Map.Entry entry = eit.next(); COSName key = entry.getKey(); COSObject value = entry.getValue(); addDefinition(key, value); } } } /** * */ protected void do_endbfchar(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSObject destination = (COSObject) it.next(); CMapCharMap map; if (destination instanceof COSString) { byte[] destBytes = ((COSString) destination).byteValue(); if (destBytes.length > 2) { // this is special to /ToUnicode maps map = new CMapBFCharStringMap(start.byteValue(), destBytes); } else { map = new CMapBFCharCodeMap(start.byteValue(), destBytes); } } else { map = new CMapBFCharNameMap(start.byteValue(), (COSName) destination); } addMap(map); } } /** * */ protected void do_endbfrange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSString end = (COSString) it.next(); COSObject destination = (COSObject) it.next(); CMapRangeMap map; if (destination instanceof COSString) { byte[] destBytes = ((COSString) destination).byteValue(); if (destBytes.length > 2) { // this is special to /ToUnicode maps map = new CMapBFRangeStringMap(start.byteValue(), end .byteValue(), ((COSString) destination).byteValue()); } else { map = new CMapBFRangeCodeMap(start.byteValue(), end .byteValue(), ((COSString) destination).byteValue()); } } else { COSArray array = destination.asArray(); if (array.get(0) instanceof COSString) { // this is special to /ToUnicode maps map = new CMapBFRangeStringArrayMap(start.byteValue(), end .byteValue(), (COSArray) destination); } else { map = new CMapBFRangeNameArrayMap(start.byteValue(), end .byteValue(), (COSArray) destination); } } addMap(map); } } /** * */ protected void do_endcidchar(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapCharMap map = new CMapCIDCharCodeMap(start.byteValue(), destination.intValue()); addMap(map); } } /** * */ protected void do_endcidrange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSString end = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapRangeMap map = new CMapCIDRangeCodeMap(start.byteValue(), end .byteValue(), destination.intValue()); addMap(map); } } /** * */ protected void do_endcmap(CSOperation operation) { // this is a no op } /** * */ protected void do_endcodespacerange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString startString = (COSString) it.next(); if (!it.hasNext()) { break; } COSString endString = (COSString) it.next(); CMapRange range = new CMapRange(startString.byteValue(), endString .byteValue()); addRange(range); } } /** * */ protected void do_endnotdefchar(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapCharMap map = new CMapCIDCharCodeMap(start.byteValue(), destination.intValue()); addNotdef(map); } } /** * */ protected void do_endnotdefrange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSString end = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapRangeMap map = new CMapNotDefRangeMap(start.byteValue(), end .byteValue(), destination.intValue()); addNotdef(map); } } /** * */ protected void do_usecmap(CSOperation operation) { // todo 2 cmap not yet supported } /** * */ protected void do_usefont(CSOperation operation) { // not needed and not yet supported } @Override public char[] getChars(int codepoint) { for (Iterator it = maps.iterator(); it.hasNext();) { CMapMap map = (CMapMap) it.next(); char[] result = map.toChars(codepoint); if (result != null) { return result; } } return null; } @Override public int getDecoded(int codepoint) { for (Iterator it = maps.iterator(); it.hasNext();) { CMapMap map = (CMapMap) it.next(); int result = map.toCID(codepoint); if (result != 0) { return result; } } return CharacterSelector.NotdefCID; } public COSObject getDefinition(COSName key) { COSObject result = definitions.get(key); if (result == null) { return COSNull.NULL; } return result; } @Override public int getEncoded(int character) { for (Iterator it = maps.iterator(); it.hasNext();) { CMapMap map = (CMapMap) it.next(); int result = map.toCodepoint(character); if (result != 0) { return result; } } return CharacterSelector.NotdefCID; } @Override public int getNextDecoded(InputStream is) throws IOException { return getDecoded(getNextEncoded(is)); } @Override public int getNextEncoded(InputStream is) throws IOException { is.mark(4); byte[] bytes = new byte[4]; int count = 0; while (count < 4) { int nextByte = is.read(); if (nextByte == -1) { return -1; } bytes[count++] = (byte) nextByte; if (checkRange(bytes, count)) { return toInt(bytes, 0, count); } } is.reset(); // invalid code, try to determine number of bytes to consume bytes = new byte[4]; count = 0; while (count < 4) { is.mark(1); int nextByte = is.read(); if (nextByte == -1) { return -1; } bytes[count++] = (byte) nextByte; if (!checkPrefix(bytes, count)) { // todo 1 this is not correct - must pad to next range size is.reset(); count--; return toInt(bytes, 0, count); } } return -1; } /* * (non-Javadoc) * * @see * de.intarsys.pdf.content.IContentStreamVisitor#visitFromContentStream( * de.intarsys.pdf.content.CSContent) */ protected void initializeFromContent(CSContent content) { int len = content.size(); for (int i = 0; i < len; i++) { CSOperation operation = content.getOperation(i); initializeFromOperation(operation); } } protected void initializeFromOperation(CSOperation operation) { if (operation.matchesOperator(CMapOperator.CMO_beginbfchar)) { do_beginbfchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_beginbfrange)) { do_beginbfrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincidchar)) { do_begincidchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincidrange)) { do_begincidrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincmap)) { do_begincmap(operation); } else if (operation .matchesOperator(CMapOperator.CMO_begincodespacerange)) { do_begincodespacerange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_beginnotdefchar)) { do_beginnotdefchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_beginnotdefrange)) { do_beginnotdefrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endbfchar)) { do_endbfchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endbfrange)) { do_endbfrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcidchar)) { do_endcidchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcidrange)) { do_endcidrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcmap)) { do_endcmap(operation); } else if (operation .matchesOperator(CMapOperator.CMO_endcodespacerange)) { do_endcodespacerange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endnotdefchar)) { do_endnotdefchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endnotdefrange)) { do_endnotdefrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_usecmap)) { do_usecmap(operation); } else if (operation.matchesOperator(CMapOperator.CMO_usefont)) { do_usefont(operation); } else if (operation.matchesOperator(CMapOperator.CMO_def)) { do_def(operation); } else { // unknown operator } } @Override public void putNextDecoded(OutputStream os, int character) throws IOException { // write cid value high byte first os.write((character >> 8) & 0xff); os.write(character & 0xff); } @Override public void putNextEncoded(OutputStream os, int codepoint) throws IOException { // write cid value high byte first os.write((codepoint >> 8) & 0xff); os.write(codepoint & 0xff); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy