123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- /*
- * 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.fonts.cff;
-
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
-
- import org.apache.fontbox.cff.CFFDataInput;
- import org.apache.fontbox.cff.CFFOperator;
-
- import org.apache.fop.fonts.truetype.FontFileReader;
- import org.apache.fop.fonts.truetype.OTFFile;
-
- /**
- * A class to read the CFF data from an OTF CFF font file.
- */
- public class CFFDataReader {
- private CFFDataInput cffData;
-
- private byte[] header;
- private CFFIndexData nameIndex;
- private CFFIndexData topDICTIndex;
- private CFFIndexData stringIndex;
- private CFFIndexData charStringIndex;
- private CFFIndexData globalIndexSubr;
- private CFFIndexData localIndexSubr;
- private CustomEncoding encoding;
- private FDSelect fdSelect;
- private List<FontDict> fdFonts;
-
- private static final int DOUBLE_BYTE_OPERATOR = 12;
- private static final int NUM_STANDARD_STRINGS = 391;
-
- /** Commonly used parsed dictionaries */
- private LinkedHashMap<String, DICTEntry> topDict;
-
- public CFFDataReader() {
-
- }
-
- /**
- * Constructor for the CFF data reader which accepts the CFF byte data
- * as an argument.
- * @param cffDataArray A byte array which holds the CFF data
- */
- public CFFDataReader(byte[] cffDataArray) throws IOException {
- cffData = new CFFDataInput(cffDataArray);
- readCFFData();
- }
-
- /**
- * Constructor for the CFF data reader which accepts a FontFileReader object
- * which points to the original font file as an argument.
- * @param fontFile The font file as represented by a FontFileReader object
- */
- public CFFDataReader(FontFileReader fontFile) throws IOException {
- cffData = new CFFDataInput(OTFFile.getCFFData(fontFile));
- readCFFData();
- }
-
- private void readCFFData() throws IOException {
- header = readHeader();
- nameIndex = readIndex();
- topDICTIndex = readIndex();
- topDict = parseDictData(topDICTIndex.getData());
- stringIndex = readIndex();
- globalIndexSubr = readIndex();
- charStringIndex = readCharStringIndex();
- encoding = readEncoding();
- fdSelect = readFDSelect();
- localIndexSubr = readLocalIndexSubrs();
- fdFonts = parseCIDData();
- }
-
- public Map<String, DICTEntry> getPrivateDict(DICTEntry privateEntry) throws IOException {
- return parseDictData(getPrivateDictBytes(privateEntry));
- }
-
- public byte[] getPrivateDictBytes(DICTEntry privateEntry) throws IOException {
- int privateLength = privateEntry.getOperands().get(0).intValue();
- int privateOffset = privateEntry.getOperands().get(1).intValue();
- return getCFFOffsetBytes(privateOffset, privateLength);
- }
-
- /**
- * Retrieves a number of bytes from the CFF data stream
- * @param offset The offset of the bytes to retrieve
- * @param length The number of bytes to retrieve
- * @return Returns a byte array of requested bytes
- * @throws IOException Throws an IO Exception if an error occurs
- */
- private byte[] getCFFOffsetBytes(int offset, int length) throws IOException {
- cffData.setPosition(offset);
- return cffData.readBytes(length);
- }
-
- /**
- * Parses the dictionary data and returns a map of objects for each entry
- * @param dictData The data for the dictionary data
- * @return Returns a map of type DICTEntry identified by the operand name
- * @throws IOException Throws an IO Exception if an error occurs
- */
- public LinkedHashMap<String, DICTEntry> parseDictData(byte[] dictData) throws IOException {
- LinkedHashMap<String, DICTEntry> dictEntries = new LinkedHashMap<String, DICTEntry>();
- List<Number> operands = new ArrayList<Number>();
- List<Integer> operandLengths = new ArrayList<Integer>();
- int lastOperandLength = 0;
- for (int i = 0; i < dictData.length; i++) {
- int readByte = dictData[i] & 0xFF;
- if (readByte < 28) {
- int[] operator = new int[(readByte == DOUBLE_BYTE_OPERATOR) ? 2 : 1];
- if (readByte == DOUBLE_BYTE_OPERATOR) {
- operator[0] = dictData[i];
- operator[1] = dictData[i + 1];
- i++;
- } else {
- operator[0] = dictData[i];
- }
- String operatorName = "";
- CFFOperator tempOp = null;
- if (operator.length > 1) {
- tempOp = CFFOperator.getOperator(new CFFOperator.Key(operator[0], operator[1]));
- } else {
- tempOp = CFFOperator.getOperator(new CFFOperator.Key(operator[0]));
- }
- if (tempOp != null) {
- operatorName = tempOp.getName();
- }
- DICTEntry newEntry = new DICTEntry();
- newEntry.setOperator(operator);
- newEntry.setOperands(new ArrayList<Number>(operands));
- newEntry.setOperatorName(operatorName);
- newEntry.setOffset(i - lastOperandLength);
- newEntry.setOperandLength(lastOperandLength);
- newEntry.setOperandLengths(new ArrayList<Integer>(operandLengths));
- byte[] byteData = new byte[lastOperandLength + operator.length];
- System.arraycopy(dictData, i - operator.length - (lastOperandLength - 1),
- byteData, 0, operator.length + lastOperandLength);
- newEntry.setByteData(byteData);
- dictEntries.put(operatorName, newEntry);
- operands.clear();
- operandLengths.clear();
- lastOperandLength = 0;
- } else {
- if (readByte >= 32 && readByte <= 246) {
- operands.add(readByte - 139);
- lastOperandLength += 1;
- operandLengths.add(1);
- } else if (readByte >= 247 && readByte <= 250) {
- operands.add((readByte - 247) * 256 + (dictData[i + 1] & 0xFF) + 108);
- lastOperandLength += 2;
- operandLengths.add(2);
- i++;
- } else if (readByte >= 251 && readByte <= 254) {
- operands.add(-(readByte - 251) * 256 - (dictData[i + 1] & 0xFF) - 108);
- lastOperandLength += 2;
- operandLengths.add(2);
- i++;
- } else if (readByte == 28) {
- operands.add((dictData[i + 1] & 0xFF) << 8 | (dictData[i + 2] & 0xFF));
- lastOperandLength += 3;
- operandLengths.add(3);
- i += 2;
- } else if (readByte == 29) {
- operands.add((dictData[i + 1] & 0xFF) << 24 | (dictData[i + 2] & 0xFF) << 16
- | (dictData[i + 3] & 0xFF) << 8 | (dictData[i + 4] & 0xFF));
- lastOperandLength += 5;
- operandLengths.add(5);
- i += 4;
- } else if (readByte == 30) {
- boolean terminatorFound = false;
- StringBuilder realNumber = new StringBuilder();
- int byteCount = 1;
- do {
- byte nibblesByte = dictData[++i];
- byteCount++;
- terminatorFound = readNibble(realNumber, (nibblesByte >> 4) & 0x0F);
- if (!terminatorFound) {
- terminatorFound = readNibble(realNumber, nibblesByte & 0x0F);
- }
- } while (!terminatorFound);
- operands.add(Double.valueOf(realNumber.toString()));
- lastOperandLength += byteCount;
- operandLengths.add(byteCount);
- }
- }
- }
- return dictEntries;
- }
-
- private boolean readNibble(StringBuilder realNumber, int nibble) {
- if (nibble <= 0x9) {
- realNumber.append(nibble);
- } else {
- switch (nibble) {
- case 0xa: realNumber.append("."); break;
- case 0xb: realNumber.append("E"); break;
- case 0xc: realNumber.append("E-"); break;
- case 0xd: break;
- case 0xe: realNumber.append("-"); break;
- case 0xf: return true;
- default: throw new AssertionError("Unexpected nibble value");
- }
- }
- return false;
- }
-
- /**
- * A class containing data for a dictionary entry
- */
- public static class DICTEntry {
- private int[] operator;
- private List<Number> operands;
- private List<Integer> operandLengths;
- private String operatorName;
- private int offset;
- private int operandLength;
- private byte[] data = new byte[0];
-
- public void setOperator(int[] operator) {
- this.operator = operator;
- }
-
- public int[] getOperator() {
- return this.operator;
- }
-
- public void setOperands(List<Number> operands) {
- this.operands = operands;
- }
-
- public List<Number> getOperands() {
- return this.operands;
- }
-
- public void setOperatorName(String operatorName) {
- this.operatorName = operatorName;
- }
-
- public String getOperatorName() {
- return this.operatorName;
- }
-
- public void setOffset(int offset) {
- this.offset = offset;
- }
-
- public int getOffset() {
- return this.offset;
- }
-
- public void setOperandLength(int operandLength) {
- this.operandLength = operandLength;
- }
-
- public int getOperandLength() {
- return this.operandLength;
- }
-
- public void setByteData(byte[] data) {
- this.data = data.clone();
- }
-
- public byte[] getByteData() {
- return data.clone();
- }
-
- public void setOperandLengths(List<Integer> operandLengths) {
- this.operandLengths = operandLengths;
- }
-
- public List<Integer> getOperandLengths() {
- return operandLengths;
- }
- }
-
- private byte[] readHeader() throws IOException {
- //Read known header
- byte[] fixedHeader = cffData.readBytes(4);
- int hdrSize = (fixedHeader[2] & 0xFF);
- byte[] extra = cffData.readBytes(hdrSize - 4);
- byte[] header = new byte[hdrSize];
- for (int i = 0; i < fixedHeader.length; i++) {
- header[i] = fixedHeader[i];
- }
- for (int i = 4; i < extra.length; i++) {
- header[i] = extra[i - 4];
- }
- return header;
- }
-
- /**
- * Reads a CFF index object are the specified offset position
- * @param offset The position of the index object to read
- * @return Returns an object representing the index
- * @throws IOException Throws an IO Exception if an error occurs
- */
- public CFFIndexData readIndex(int offset) throws IOException {
- cffData.setPosition(offset);
- return readIndex();
- }
-
- private CFFIndexData readIndex() throws IOException {
- return readIndex(cffData);
- }
-
- /**
- * Reads an index from the current position of the CFFDataInput object
- * @param input The object holding the CFF byte data
- * @return Returns an object representing the index
- * @throws IOException Throws an IO Exception if an error occurs
- */
- public CFFIndexData readIndex(CFFDataInput input) throws IOException {
- CFFIndexData nameIndex = new CFFIndexData();
- if (input != null) {
- int origPos = input.getPosition();
- nameIndex.parseIndexHeader(input);
- int tableSize = input.getPosition() - origPos;
- nameIndex.setByteData(input.getPosition() - tableSize, tableSize);
- }
- return nameIndex;
- }
-
- /**
- * Retrieves the SID for the given GID object
- * @param charsetOffset The offset of the charset data
- * @param GID The GID for which to retrieve the SID
- * @return Returns the SID as an integer
- */
- public int getSIDFromGID(int charsetOffset, int gid) throws IOException {
- if (gid == 0) {
- return 0;
- }
- cffData.setPosition(charsetOffset);
- int charsetFormat = cffData.readCard8();
- switch (charsetFormat) {
- case 0: //Adjust for .notdef character
- cffData.setPosition(cffData.getPosition() + (--gid * 2));
- return cffData.readSID();
- case 1: return getSIDFromGIDFormat(gid, 1);
- case 2: return getSIDFromGIDFormat(gid, 2);
- default: return 0;
- }
- }
-
- private int getSIDFromGIDFormat(int gid, int format) throws IOException {
- int glyphCount = 0;
- while (true) {
- int oldGlyphCount = glyphCount;
- int start = cffData.readSID();
- glyphCount += ((format == 1) ? cffData.readCard8() : cffData.readCard16()) + 1;
- if (gid <= glyphCount) {
- return start + (gid - oldGlyphCount) - 1;
- }
- }
- }
-
- public byte[] getHeader() {
- return header.clone();
- }
-
- public CFFIndexData getNameIndex() {
- return nameIndex;
- }
-
- public CFFIndexData getTopDictIndex() {
- return topDICTIndex;
- }
-
- public LinkedHashMap<String, DICTEntry> getTopDictEntries() {
- return topDict;
- }
-
- public CFFIndexData getStringIndex() {
- return stringIndex;
- }
-
- public CFFIndexData getGlobalIndexSubr() {
- return globalIndexSubr;
- }
-
- public CFFIndexData getLocalIndexSubr() {
- return localIndexSubr;
- }
-
- public CFFIndexData getCharStringIndex() {
- return charStringIndex;
- }
-
- public CFFDataInput getCFFData() {
- return cffData;
- }
-
- public CustomEncoding getEncoding() {
- return encoding;
- }
-
- public FDSelect getFDSelect() {
- return fdSelect;
- }
-
- public List<FontDict> getFDFonts() {
- return fdFonts;
- }
-
- public CFFDataInput getLocalSubrsForGlyph(int glyph) throws IOException {
- //Subsets are currently written using a Format0 FDSelect
- FDSelect fontDictionary = getFDSelect();
- if (fontDictionary instanceof Format0FDSelect) {
- Format0FDSelect fdSelect = (Format0FDSelect)fontDictionary;
- int found = fdSelect.getFDIndexes()[glyph];
- FontDict font = getFDFonts().get(found);
- byte[] localSubrData = font.getLocalSubrData().getByteData();
- if (localSubrData != null) {
- return new CFFDataInput(localSubrData);
- } else {
- return null;
- }
- } else if (fontDictionary instanceof Format3FDSelect) {
- Format3FDSelect fdSelect = (Format3FDSelect)fontDictionary;
- int index = 0;
- for (int first : fdSelect.getRanges().keySet()) {
- if (first > glyph) {
- break;
- }
- index++;
- }
- FontDict font = getFDFonts().get(index);
- byte[] localSubrsData = font.getLocalSubrData().getByteData();
- if (localSubrsData != null) {
- return new CFFDataInput(localSubrsData);
- } else {
- return null;
- }
- }
- return null;
- }
-
- /**
- * Parses the char string index from the CFF byte data
- * @param offset The offset to the char string index
- * @return Returns the char string index object
- * @throws IOException Throws an IO Exception if an error occurs
- */
- public CFFIndexData readCharStringIndex() throws IOException {
- int offset = topDict.get("CharStrings").getOperands().get(0).intValue();
- cffData.setPosition(offset);
- return readIndex();
- }
-
- private CustomEncoding readEncoding() throws IOException {
- CustomEncoding foundEncoding = null;
- if (topDict.get("Encoding") != null) {
- int offset = topDict.get("Encoding").getOperands().get(0).intValue();
- if (offset != 0 && offset != 1) {
- //No need to set the offset as we are reading the data sequentially.
- int format = cffData.readCard8();
- int numEntries = cffData.readCard8();
- switch (format) {
- case 0:
- foundEncoding = readFormat0Encoding(format, numEntries);
- break;
- case 1:
- foundEncoding = readFormat1Encoding(format, numEntries);
- break;
- default: break;
- }
- }
- }
- return foundEncoding;
- }
-
- private Format0Encoding readFormat0Encoding(int format, int numEntries)
- throws IOException {
- Format0Encoding newEncoding = new Format0Encoding();
- newEncoding.setFormat(format);
- newEncoding.setNumEntries(numEntries);
- int[] codes = new int[numEntries];
- for (int i = 0; i < numEntries; i++) {
- codes[i] = cffData.readCard8();
- }
- newEncoding.setCodes(codes);
- return newEncoding;
- }
-
- private Format1Encoding readFormat1Encoding(int format, int numEntries)
- throws IOException {
- Format1Encoding newEncoding = new Format1Encoding();
- newEncoding.setFormat(format);
- newEncoding.setNumEntries(numEntries);
- LinkedHashMap<Integer, Integer> ranges = new LinkedHashMap<Integer, Integer>();
- for (int i = 0; i < numEntries; i++) {
- int first = cffData.readCard8();
- int left = cffData.readCard8();
- ranges.put(first, left);
- }
- newEncoding.setRanges(ranges);
- return newEncoding;
- }
-
- private FDSelect readFDSelect() throws IOException {
- FDSelect fdSelect = null;
- DICTEntry fdSelectEntry = topDict.get("FDSelect");
- if (fdSelectEntry != null) {
- int fdOffset = fdSelectEntry.getOperands().get(0).intValue();
- cffData.setPosition(fdOffset);
- int format = cffData.readCard8();
- switch (format) {
- case 0:
- fdSelect = readFormat0FDSelect();
- break;
- case 3:
- fdSelect = readFormat3FDSelect();
- break;
- default:
- }
- }
- return fdSelect;
- }
-
- private Format0FDSelect readFormat0FDSelect() throws IOException {
- Format0FDSelect newFDs = new Format0FDSelect();
- newFDs.setFormat(0);
- int glyphCount = charStringIndex.getNumObjects();
- int[] fds = new int[glyphCount];
- for (int i = 0; i < glyphCount; i++) {
- fds[i] = cffData.readCard8();
- }
- newFDs.setFDIndexes(fds);
- return newFDs;
- }
-
- private Format3FDSelect readFormat3FDSelect() throws IOException {
- Format3FDSelect newFDs = new Format3FDSelect();
- newFDs.setFormat(3);
- int rangeCount = cffData.readCard16();
- newFDs.setRangeCount(rangeCount);
- LinkedHashMap<Integer, Integer> ranges = new LinkedHashMap<Integer, Integer>();
- for (int i = 0; i < rangeCount; i++) {
- int first = cffData.readCard16();
- int fd = cffData.readCard8();
- ranges.put(first, fd);
- }
- newFDs.setRanges(ranges);
- newFDs.setSentinelGID(cffData.readCard16());
- return newFDs;
- }
-
- private List<FontDict> parseCIDData() throws IOException {
- ArrayList<FontDict> fdFonts = new ArrayList<FontDict>();
- if (topDict.get("ROS") != null) {
- DICTEntry fdArray = topDict.get("FDArray");
- if (fdArray != null) {
- int fdIndex = fdArray.getOperands().get(0).intValue();
- CFFIndexData fontDicts = readIndex(fdIndex);
- for (int i = 0; i < fontDicts.getNumObjects(); i++) {
- FontDict newFontDict = new FontDict();
-
- byte[] fdData = fontDicts.getValue(i);
- LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData);
- newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i));
- DICTEntry fontFDEntry = fdEntries.get("FontName");
- newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue()));
- DICTEntry privateFDEntry = fdEntries.get("Private");
- if (privateFDEntry != null) {
- newFontDict = setFDData(privateFDEntry, newFontDict);
- }
-
- fdFonts.add(newFontDict);
- }
- }
- }
- return fdFonts;
- }
-
- private FontDict setFDData(DICTEntry privateFDEntry, FontDict newFontDict) throws IOException {
- int privateFDLength = privateFDEntry.getOperands().get(0).intValue();
- int privateFDOffset = privateFDEntry.getOperands().get(1).intValue();
- cffData.setPosition(privateFDOffset);
- byte[] privateDict = cffData.readBytes(privateFDLength);
- newFontDict.setPrivateDictData(privateFDOffset, privateFDLength);
- LinkedHashMap<String, DICTEntry> privateEntries = parseDictData(privateDict);
- DICTEntry subroutines = privateEntries.get("Subrs");
- if (subroutines != null) {
- CFFIndexData localSubrs = readIndex(privateFDOffset
- + subroutines.getOperands().get(0).intValue());
- newFontDict.setLocalSubrData(localSubrs);
- } else {
- newFontDict.setLocalSubrData(new CFFIndexData());
- }
- return newFontDict;
- }
-
- private String getString(int sid) throws IOException {
- return new String(stringIndex.getValue(sid - NUM_STANDARD_STRINGS));
- }
-
- private CFFIndexData readLocalIndexSubrs() throws IOException {
- CFFIndexData localSubrs = null;
- DICTEntry privateEntry = topDict.get("Private");
- if (privateEntry != null) {
- int length = privateEntry.getOperands().get(0).intValue();
- int offset = privateEntry.getOperands().get(1).intValue();
- cffData.setPosition(offset);
- byte[] privateData = cffData.readBytes(length);
- LinkedHashMap<String, DICTEntry> privateDict = parseDictData(privateData);
- DICTEntry localSubrsEntry = privateDict.get("Subrs");
- if (localSubrsEntry != null) {
- int localOffset = offset + localSubrsEntry.getOperands().get(0).intValue();
- cffData.setPosition(localOffset);
- localSubrs = readIndex();
- }
- }
- return localSubrs;
- }
-
- /**
- * Parent class which provides the ability to retrieve byte data from
- * a sub-table.
- */
- public class CFFSubTable {
- private DataLocation dataLocation = new DataLocation();
-
- public void setByteData(int position, int length) {
- dataLocation = new DataLocation(position, length);
- }
-
- public byte[] getByteData() throws IOException {
- int oldPos = cffData.getPosition();
- try {
- cffData.setPosition(dataLocation.getDataPosition());
- return cffData.readBytes(dataLocation.getDataLength());
- } finally {
- cffData.setPosition(oldPos);
- }
- }
- }
-
- /**
- * An object used to hold index data from the CFF data
- */
- public class CFFIndexData extends CFFSubTable {
- private int numObjects;
- private int offSize;
- private int[] offsets = new int[0];
- private DataLocation dataLocation = new DataLocation();
-
- public void setNumObjects(int numObjects) {
- this.numObjects = numObjects;
- }
-
- public int getNumObjects() {
- return this.numObjects;
- }
-
- public void setOffSize(int offSize) {
- this.offSize = offSize;
- }
-
- public int getOffSize() {
- return this.offSize;
- }
-
- public void setOffsets(int[] offsets) {
- this.offsets = offsets.clone();
- }
-
- public int[] getOffsets() {
- return offsets.clone();
- }
-
- public void setData(int position, int length) {
- dataLocation = new DataLocation(position, length);
- }
-
- public byte[] getData() throws IOException {
- int origPos = cffData.getPosition();
- try {
- cffData.setPosition(dataLocation.getDataPosition());
- return cffData.readBytes(dataLocation.getDataLength());
- } finally {
- cffData.setPosition(origPos);
- }
- }
-
- /**
- * Parses index data from an index object found within the CFF byte data
- * @param cffData A byte array containing the CFF data
- * @throws IOException Throws an IO Exception if an error occurs
- */
- public void parseIndexHeader(CFFDataInput cffData) throws IOException {
- setNumObjects(cffData.readCard16());
- setOffSize(cffData.readOffSize());
- int[] offsets = new int[getNumObjects() + 1];
- byte[] bytes;
- //Fills the offsets array
- for (int i = 0; i <= getNumObjects(); i++) {
- switch (getOffSize()) {
- case 1:
- offsets[i] = cffData.readCard8();
- break;
- case 2:
- offsets[i] = cffData.readCard16();
- break;
- case 3:
- bytes = cffData.readBytes(3);
- offsets[i] = ((bytes[0] & 0xFF) << 16) + ((bytes[1] & 0xFF) << 8) + (bytes[2] & 0xFF);
- break;
- case 4:
- bytes = cffData.readBytes(4);
- offsets[i] = ((bytes[0] & 0xFF) << 24) + ((bytes[1] & 0xFF) << 16)
- + ((bytes[2] & 0xFF) << 8) + (bytes[3] & 0xFF);
- break;
- default: continue;
- }
- }
- setOffsets(offsets);
- int position = cffData.getPosition();
- int dataSize = offsets[offsets.length - 1] - offsets[0];
-
- cffData.setPosition(cffData.getPosition() + dataSize);
- setData(position, dataSize);
- }
-
- /**
- * Retrieves data from the index data
- * @param index The index position of the data to retrieve
- * @return Returns the byte data for the given index
- * @throws IOException Throws an IO Exception if an error occurs
- */
- public byte[] getValue(int index) throws IOException {
- int oldPos = cffData.getPosition();
- try {
- cffData.setPosition(dataLocation.getDataPosition() + (offsets[index] - 1));
- return cffData.readBytes(offsets[index + 1] - offsets[index]);
- } finally {
- cffData.setPosition(oldPos);
- }
- }
-
- public int getValuePosition(int index) {
- return dataLocation.getDataPosition() + (offsets[index] - 1);
- }
-
- public int getValueLength(int index) {
- return offsets[index + 1] - offsets[index];
- }
- }
-
- public abstract class CustomEncoding {
- private int format;
- private int numEntries;
-
- public void setFormat(int format) {
- this.format = format;
- }
-
- public int getFormat() {
- return format;
- }
-
- public void setNumEntries(int numEntries) {
- this.numEntries = numEntries;
- }
-
- public int getNumEntries() {
- return numEntries;
- }
- }
-
- public class Format0Encoding extends CustomEncoding {
- private int[] codes = new int[0];
-
- public void setCodes(int[] codes) {
- this.codes = codes.clone();
- }
-
- public int[] getCodes() {
- return codes.clone();
- }
- }
-
- public class Format1Encoding extends CustomEncoding {
- private LinkedHashMap<Integer, Integer> ranges;
-
- public void setRanges(LinkedHashMap<Integer, Integer> ranges) {
- this.ranges = ranges;
- }
-
- public LinkedHashMap<Integer, Integer> getRanges() {
- return ranges;
- }
- }
-
- public class FDSelect {
- private int format;
-
- public void setFormat(int format) {
- this.format = format;
- }
-
- public int getFormat() {
- return format;
- }
- }
-
- public class Format0FDSelect extends FDSelect {
- private int[] fds = new int[0];
-
- public void setFDIndexes(int[] fds) {
- this.fds = fds.clone();
- }
-
- public int[] getFDIndexes() {
- return fds.clone();
- }
- }
-
- public class Format3FDSelect extends FDSelect {
- private int rangeCount;
- private LinkedHashMap<Integer, Integer> ranges;
- private int sentinelGID;
-
- public void setRangeCount(int rangeCount) {
- this.rangeCount = rangeCount;
- }
-
- public int getRangeCount() {
- return rangeCount;
- }
-
- public void setRanges(LinkedHashMap<Integer, Integer> ranges) {
- this.ranges = ranges;
- }
-
- public LinkedHashMap<Integer, Integer> getRanges() {
- return ranges;
- }
-
- public void setSentinelGID(int sentinelGID) {
- this.sentinelGID = sentinelGID;
- }
-
- public int getSentinelGID() {
- return sentinelGID;
- }
- }
-
- public class FontDict extends CFFSubTable {
- private String fontName;
- private DataLocation dataLocation = new DataLocation();
- private CFFIndexData localSubrData;
-
- public void setFontName(String groupName) {
- this.fontName = groupName;
- }
-
- public String getFontName() {
- return fontName;
- }
-
- public void setPrivateDictData(int position, int length) {
- dataLocation = new DataLocation(position, length);
- }
-
- public byte[] getPrivateDictData() throws IOException {
- int origPos = cffData.getPosition();
- try {
- cffData.setPosition(dataLocation.getDataPosition());
- return cffData.readBytes(dataLocation.getDataLength());
- } finally {
- cffData.setPosition(origPos);
- }
- }
-
- public void setLocalSubrData(CFFIndexData localSubrData) {
- this.localSubrData = localSubrData;
- }
-
- public CFFIndexData getLocalSubrData() {
- return localSubrData;
- }
- }
-
- private static class DataLocation {
- private int dataPosition;
- private int dataLength;
-
- public DataLocation() {
- dataPosition = 0;
- dataLength = 0;
- }
-
- public DataLocation(int position, int length) {
- this.dataPosition = position;
- this.dataLength = length;
- }
-
- public int getDataPosition() {
- return dataPosition;
- }
-
- public int getDataLength() {
- return dataLength;
- }
- }
- }
|