iText 5 itextpdf.jar Source Code

itextpdf.jar is a component in iText 5 Java library to provide core functionalities. iText Java library allows you to generate and manage PDF documents.

The Source Code files are provided at iText GitHub site.

You can compile it to generate your JAR file, using pom.xml as the build configuration file.

The source code of itextpdf-5.5.14.jar is provided below:

✍: FYIcenter.com

com/itextpdf/text/pdf/CFFFontSubset.java

/*
 *
 * This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
 * Authors: Bruno Lowagie, Paulo Soares, et al.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
 * ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
 * OF THIRD PARTY RIGHTS
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
 * http://itextpdf.com/terms-of-use/
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License,
 * a covered work must retain the producer line in every PDF that is created
 * or manipulated using iText.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the iText software without
 * disclosing the source code of your own applications.
 * These activities include: offering paid services to customers as an ASP,
 * serving PDFs on the fly in a web application, shipping iText with a closed
 * source product.
 *
 * For more information, please contact iText Software Corp. at this
 * address: sales@itextpdf.com
 */
package com.itextpdf.text.pdf;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts.
 * The Charstring is subsetted for both types. For CID fonts only the FDArray which are used are embedded.
 * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2
 * formatting although only tested on Type2 Format.
 * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted.
 * A font which was not of CID type is transformed into CID as a part of the subset process.
 * The CID synthetic creation was written by Sivan Toledo (sivan@math.tau.ac.il)
 * @author Oren Manor (manorore@post.tau.ac.il) and Ygal Blum (blumygal@post.tau.ac.il)
 */
public class CFFFontSubset extends CFFFont {

	/**
	 *  The Strings in this array represent Type1/Type2 operator names
	 */
	static final String SubrsFunctions[] = {
			"RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto",
			"rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13",
			"endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask",
			"cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto",
			"hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto"
			};
	/**
	 * The Strings in this array represent Type1/Type2 escape operator names
	 */
	static final String SubrsEscapeFuncs[] = {
			"RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6",
			"RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg",
			"eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse",
			"random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31",
			"RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST"
	};

	/**
	*  Operator codes for unused  CharStrings and unused local and global Subrs
	*/
	static final byte ENDCHAR_OP = 14;
	static final byte RETURN_OP = 11;

	/**
	 * A HashMap containing the glyphs used in the text after being converted
	 * to glyph number by the CMap
	 */
	HashMap<Integer, int[]> GlyphsUsed;
	/**
	 * The GlyphsUsed keys as an ArrayList
	 */
	ArrayList<Integer> glyphsInList;
	/**
	 * A HashSet for keeping the FDArrays being used by the font
	 */
	HashSet<Integer> FDArrayUsed = new HashSet<Integer>();
	/**
	 * A HashMaps array for keeping the subroutines used in each FontDict
	 */
	HashMap<Integer, int[]>[] hSubrsUsed;
	/**
	 * The SubroutinesUsed HashMaps as ArrayLists
	 */
	ArrayList<Integer>[] lSubrsUsed;
	/**
	 * A HashMap for keeping the Global subroutines used in the font
	 */
	HashMap<Integer, int[]> hGSubrsUsed  = new HashMap<Integer, int[]>();
	/**
	 * The Global SubroutinesUsed HashMaps as ArrayLists
	 */
	ArrayList<Integer> lGSubrsUsed = new ArrayList<Integer>();
	/**
	 * A HashMap for keeping the subroutines used in a non-cid font
	 */
	HashMap<Integer, int[]> hSubrsUsedNonCID  = new HashMap<Integer, int[]>();
	/**
	 * The SubroutinesUsed HashMap as ArrayList
	 */
	ArrayList<Integer> lSubrsUsedNonCID = new ArrayList<Integer>();
	/**
	 * An array of the new Indexes for the local Subr. One index for each FontDict
	 */
	byte[][] NewLSubrsIndex;
	/**
	 * The new subroutines index for a non-cid font
	 */
	byte[] NewSubrsIndexNonCID;
	/**
	 * The new global subroutines index of the font
	 */
	byte[] NewGSubrsIndex;
	/**
	 * The new CharString of the font
	 */
	byte[] NewCharStringsIndex;

	/**
	 * The bias for the global subroutines
	 */
	int GBias = 0;

	/**
	 * The linked list for generating the new font stream
	 */
	LinkedList<Item> OutputList;

	/**
	 * Number of arguments to the stem operators in a subroutine calculated recursively
	 */
	int NumOfHints=0;


	/**
	 * C'tor for CFFFontSubset
	 * @param rf - The font file
	 * @param GlyphsUsed - a HashMap that contains the glyph used in the subset
	 */
    public CFFFontSubset(RandomAccessFileOrArray rf,HashMap<Integer, int[]> GlyphsUsed){
		// Use CFFFont c'tor in order to parse the font file.
    	super(rf);
		this.GlyphsUsed = GlyphsUsed;
		//Put the glyphs into a list
		glyphsInList = new ArrayList<Integer>(GlyphsUsed.keySet());


		for (int i=0;i<fonts.length;++i)
		{
			// Read the number of glyphs in the font
			seek(fonts[i].charstringsOffset);
	        fonts[i].nglyphs = getCard16();

	    	// Jump to the count field of the String Index
	        seek(stringIndexOffset);
	        fonts[i].nstrings = getCard16()+standardStrings.length;

	        // For each font save the offset array of the charstring
			fonts[i].charstringsOffsets = getIndex(fonts[i].charstringsOffset);

			// Process the FDSelect if exist
			if (fonts[i].fdselectOffset>=0)
			{
				// Process the FDSelect
	            readFDSelect(i);
	            // Build the FDArrayUsed hashmap
            	BuildFDArrayUsed(i);
			}
			if (fonts[i].isCID)
				// Build the FD Array used Hash Map
				ReadFDArray(i);
			// compute the charset length
			fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs);
		}
	}

    /**
     * Calculates the length of the charset according to its format
     * @param Offset The Charset Offset
     * @param NumofGlyphs Number of glyphs in the font
     * @return the length of the Charset
     */
    int CountCharset(int Offset,int NumofGlyphs){
    	int format;
    	int Length=0;
    	seek(Offset);
    	// Read the format
    	format = getCard8();
    	// Calc according to format
    	switch (format){
    		case 0:
    			Length = 1+2*NumofGlyphs;
    			break;
    		case 1:
    			Length = 1+3*CountRange(NumofGlyphs,1);
    			break;
    		case 2:
    			Length = 1+4*CountRange(NumofGlyphs,2);
    			break;
    		default:
    			break;
    	}
    	return Length;
    }

    /**
     * Function calculates the number of ranges in the Charset
     * @param NumofGlyphs The number of glyphs in the font
     * @param Type The format of the Charset
     * @return The number of ranges in the Charset data structure
     */
    int CountRange(int NumofGlyphs,int Type){
    	int num=0;
    	char Sid;
    	int i=1,nLeft;
    	while (i<NumofGlyphs){
    		num++;
    		Sid = getCard16();
    		if (Type==1)
    			nLeft = getCard8();
    		else
    			nLeft = getCard16();
    		i += nLeft+1;
    	}
    	return num;
    }


	/**
	 * Read the FDSelect of the font and compute the array and its length
	 * @param Font The index of the font being processed
	 */
	protected void readFDSelect(int Font)
	{
		// Restore the number of glyphs
		int NumOfGlyphs = fonts[Font].nglyphs;
		int[] FDSelect = new int[NumOfGlyphs];
		// Go to the beginning of the FDSelect
		seek(fonts[Font].fdselectOffset);
		// Read the FDSelect's format
		fonts[Font].FDSelectFormat = getCard8();

		switch(fonts[Font].FDSelectFormat){
			// Format==0 means each glyph has an entry that indicated
			// its FD.
			case 0:
				for (int i=0;i<NumOfGlyphs;i++)
				{
					FDSelect[i] = getCard8();
				}
				// The FDSelect's Length is one for each glyph + the format
				// for later use
				fonts[Font].FDSelectLength = fonts[Font].nglyphs+1;
				break;
			case 3:
				// Format==3 means the ranges version
				// The number of ranges
				int nRanges = getCard16();
				int l=0;
				// Read the first in the first range
				int first = getCard16();
				for (int i=0;i<nRanges;i++)
				{
					// Read the FD index
					int fd = getCard8();
					// Read the first of the next range
					int last = getCard16();
					// Calc the steps and write to the array
					int steps = last-first;
					for (int k=0;k<steps;k++)
					{
						FDSelect[l] = fd;
						l++;
					}
					// The last from this iteration is the first of the next
					first = last;
				}
				// Store the length for later use
				fonts[Font].FDSelectLength = 1+2+nRanges*3+2;
				break;
			default:
				break;
		}
		// Save the FDSelect of the font
		fonts[Font].FDSelect = FDSelect;
	}

	/**
	 * Function reads the FDSelect and builds the FDArrayUsed HashMap According to the glyphs used
	 * @param Font the Number of font being processed
	 */
	protected void BuildFDArrayUsed(int Font)
	{
		int[] FDSelect = fonts[Font].FDSelect;
		// For each glyph used
		for (int i=0;i<glyphsInList.size();i++)
		{
			// Pop the glyphs index
			int glyph = glyphsInList.get(i).intValue();
			// Pop the glyph's FD
			int FD = FDSelect[glyph];
			// Put the FD index into the FDArrayUsed HashMap
			FDArrayUsed.add(Integer.valueOf(FD));
		}
	}

	/**
	 * Read the FDArray count, offsize and Offset array
	 * @param Font
	 */
	protected void ReadFDArray(int Font)
	{
		seek(fonts[Font].fdarrayOffset);
		fonts[Font].FDArrayCount = getCard16();
		fonts[Font].FDArrayOffsize = getCard8();
		// Since we will change values inside the FDArray objects
		// We increase its offsize to prevent errors
		if (fonts[Font].FDArrayOffsize < 4)
			fonts[Font].FDArrayOffsize++;
		fonts[Font].FDArrayOffsets = getIndex(fonts[Font].fdarrayOffset);
	}


	/**
	 * The Process function extracts one font out of the CFF file and returns a
	 * subset version of the original.
	 * @param fontName - The name of the font to be taken out of the CFF
	 * @return The new font stream
	 * @throws IOException
	 */
	public byte[] Process(String fontName)throws IOException{
		try
		{
			// Verify that the file is open
			buf.reOpen();
			// Find the Font that we will be dealing with
			int j;
	        for (j=0; j<fonts.length; j++)
	            if (fontName.equals(fonts[j].name)) break;
	        if (j==fonts.length) return null;

			// Calc the bias for the global subrs
			if (gsubrIndexOffset >= 0)
				GBias = CalcBias(gsubrIndexOffset,j);

	        // Prepare the new CharStrings Index
			BuildNewCharString(j);
			 // Prepare the new Global and Local Subrs Indices
			BuildNewLGSubrs(j);
			// Build the new file
			byte[] Ret = BuildNewFile(j);
			return Ret;
		}
		finally {
            try {
                buf.close();
            }
            catch (Exception e) {
                // empty on purpose
            }
		}
	}

	/**
	 * Function calcs bias according to the CharString type and the count
	 * of the subrs
	 * @param Offset The offset to the relevant subrs index
	 * @param Font the font
	 * @return The calculated Bias
	 */
	protected int CalcBias(int Offset,int Font)
	{
		seek(Offset);
		int nSubrs = getCard16();
		// If type==1 -> bias=0
		if (fonts[Font].CharstringType == 1)
			return 0;
		// else calc according to the count
		else if (nSubrs < 1240)
			return 107;
		else if (nSubrs < 33900)
			return 1131;
		else
			return 32768;
	}

	/**
	 *Function uses BuildNewIndex to create the new index of the subset charstrings
	 * @param FontIndex the font
	 * @throws IOException
	 */
	protected void BuildNewCharString(int FontIndex) throws IOException
	{
		NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed,ENDCHAR_OP);
	}

	/**
	 * Function builds the new local & global subsrs indices. IF CID then All of
	 * the FD Array lsubrs will be subsetted.
	 * @param Font the font
	 * @throws IOException
	 */
    @SuppressWarnings("unchecked")
    protected void BuildNewLGSubrs(int Font)throws IOException
	{
		// If the font is CID then the lsubrs are divided into FontDicts.
		// for each FD array the lsubrs will be subsetted.
		if(fonts[Font].isCID)
		{
			// Init the hashmap-array and the arraylist-array to hold the subrs used
			// in each private dict.
			hSubrsUsed = new HashMap[fonts[Font].fdprivateOffsets.length];
			lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.length];
			// A [][] which will store the byte array for each new FD Array lsubs index
			NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.length][];
			// An array to hold the offset for each Lsubr index
			fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.length];
			// A [][] which will store the offset array for each lsubr index
			fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.length][];

			// Put the FDarrayUsed into a list
			ArrayList<Integer> FDInList = new ArrayList<Integer>(FDArrayUsed);
			// For each FD array which is used subset the lsubr
			for (int j=0;j<FDInList.size();j++)
			{
				// The FDArray index, Hash Map, Array List to work on
				int FD = FDInList.get(j).intValue();
				hSubrsUsed[FD] = new HashMap<Integer, int[]>();
				lSubrsUsed[FD] = new ArrayList<Integer>();
				//Reads the private dicts looking for the subr operator and
				// store both the offset for the index and its offset array
				BuildFDSubrsOffsets(Font,FD);
				// Verify that FDPrivate has a LSubrs index
				if(fonts[Font].PrivateSubrsOffset[FD]>=0)
				{
					//Scans the Charstring data storing the used Local and Global subroutines
					// by the glyphs. Scans the Subrs recursively.
					BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]);
					// Builds the New Local Subrs index
					NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],RETURN_OP);
				}
			}
		}
		// If the font is not CID && the Private Subr exists then subset:
		else if (fonts[Font].privateSubrs>=0)
		{
			// Build the subrs offsets;
			fonts[Font].SubrsOffsets = getIndex(fonts[Font].privateSubrs);
			//Scans the Charstring data storing the used Local and Global subroutines
			// by the glyphs. Scans the Subrs recursively.
			BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID);
		}
		// For all fonts subset the Global Subroutines
		// Scan the Global Subr Hashmap recursively on the Gsubrs
		BuildGSubrsUsed(Font);
		if (fonts[Font].privateSubrs>=0)
			// Builds the New Local Subrs index
			NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID,RETURN_OP);
		//Builds the New Global Subrs index
		NewGSubrsIndex = BuildNewIndexAndCopyAllGSubrs(gsubrOffsets, RETURN_OP);
	}

	/**
	 * The function finds for the FD array processed the local subr offset and its
	 * offset array.
	 * @param Font the font
	 * @param FD The FDARRAY processed
	 */
	protected void BuildFDSubrsOffsets(int Font,int FD)
	{
		// Initiate to -1 to indicate lsubr operator present
		fonts[Font].PrivateSubrsOffset[FD] = -1;
		// Goto beginning of objects
        seek(fonts[Font].fdprivateOffsets[FD]);
        // While in the same object:
        while (getPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD])
        {
        	getDictItem();
        	// If the dictItem is the "Subrs" then find and store offset,
        	if (key=="Subrs")
        		fonts[Font].PrivateSubrsOffset[FD] = ((Integer)args[0]).intValue()+fonts[Font].fdprivateOffsets[FD];
        }
        //Read the lsubr index if the lsubr was found
        if (fonts[Font].PrivateSubrsOffset[FD] >= 0)
        	fonts[Font].PrivateSubrsOffsetsArray[FD] = getIndex(fonts[Font].PrivateSubrsOffset[FD]);
	}

	/**
	 * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap.
	 * The HashMap (of the lsubr only) is then scanned recursively for Lsubr & Gsubrs
	 * calls.
	 * @param Font the font
	 * @param FD FD array processed. 0 indicates function was called by non CID font
	 * @param SubrOffset the offset to the subr index to calc the bias
	 * @param SubrsOffsets the offset array of the subr index
	 * @param hSubr HashMap of the subrs used
	 * @param lSubr ArrayList of the subrs used
	 */
	protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,HashMap<Integer, int[]> hSubr,ArrayList<Integer> lSubr)
	{

		// Calc the Bias for the subr index
		int LBias = CalcBias(SubrOffset,Font);

		// For each glyph used find its GID, start & end pos
		for (int i=0;i<glyphsInList.size();i++)
		{
			int glyph = glyphsInList.get(i).intValue();
			int Start = fonts[Font].charstringsOffsets[glyph];
			int End = fonts[Font].charstringsOffsets[glyph+1];

			// IF CID:
			if (FD >= 0)
			{
				EmptyStack();
				NumOfHints=0;
				// Using FDSELECT find the FD Array the glyph belongs to.
				int GlyphFD = fonts[Font].FDSelect[glyph];
				// If the Glyph is part of the FD being processed
				if (GlyphFD == FD)
					// Find the Subrs called by the glyph and insert to hash:
					ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
			}
			else
				// If the font is not CID
				//Find the Subrs called by the glyph and insert to hash:
				ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
		}
		// For all Lsubrs used, check recursively for Lsubr & Gsubr used
		for (int i=0;i<lSubr.size();i++)
		{
			// Pop the subr value from the hash
			int Subr = lSubr.get(i).intValue();
			// Ensure the Lsubr call is valid
			if (Subr < SubrsOffsets.length-1 && Subr>=0)
			{
				// Read and process the subr
				int Start = SubrsOffsets[Subr];
				int End = SubrsOffsets[Subr+1];
				ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
			}
		}
	}

	/**
	 * Function scans the Glsubr used ArrayList to find recursive calls
	 * to Gsubrs and adds to Hashmap & ArrayList
	 * @param Font the font
	 */
	protected void BuildGSubrsUsed(int Font)
	{
		int LBias = 0;
		int SizeOfNonCIDSubrsUsed = 0;
		if (fonts[Font].privateSubrs>=0)
		{
			LBias = CalcBias(fonts[Font].privateSubrs,Font);
			SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
		}

		// For each global subr used
		for (int i=0;i<lGSubrsUsed.size();i++)
		{
			//Pop the value + check valid
			int Subr = lGSubrsUsed.get(i).intValue();
			if (Subr < gsubrOffsets.length-1 && Subr>=0)
			{
				// Read the subr and process
				int Start = gsubrOffsets[Subr];
				int End = gsubrOffsets[Subr+1];

				if (fonts[Font].isCID)
					ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null);
				else
				{
					ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets);
					if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.size())
					{
						for (int j=SizeOfNonCIDSubrsUsed;j<lSubrsUsedNonCID.size();j++)
						{
							//Pop the value + check valid
							int LSubr = lSubrsUsedNonCID.get(j).intValue();
							if (LSubr < fonts[Font].SubrsOffsets.length-1 && LSubr>=0)
							{
								// Read the subr and process
								int LStart = fonts[Font].SubrsOffsets[LSubr];
								int LEnd = fonts[Font].SubrsOffsets[LSubr+1];
								ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets);
							}
						}
						SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
					}
				}
			}
		}
	}

	/**
	 * The function reads a subrs (glyph info) between begin and end.
	 * Adds calls to a Lsubr to the hSubr and lSubrs.
	 * Adds calls to a Gsubr to the hGSubr and lGSubrs.
	 * @param begin the start point of the subr
	 * @param end the end point of the subr
	 * @param GBias the bias of the Global Subrs
	 * @param LBias the bias of the Local Subrs
	 * @param hSubr the HashMap for the lSubrs
	 * @param lSubr the ArrayList for the lSubrs
	 */
	protected void ReadASubr(int begin,int end,int GBias,int LBias,HashMap<Integer, int[]> hSubr,ArrayList<Integer> lSubr,int[] LSubrsOffsets)
	{
		// Clear the stack for the subrs
		EmptyStack();
		NumOfHints = 0;
		// Goto beginning of the subr
        seek(begin);
        while (getPosition() < end)
        {
        	// Read the next command
        	ReadCommand();
        	int pos = getPosition();
        	Object TopElement=null;
        	if (arg_count > 0)
        		TopElement = args[arg_count-1];
        	int NumOfArgs = arg_count;
        	// Check the modification needed on the Argument Stack according to key;
        	HandelStack();
        	// a call to a Lsubr
        	if (key=="callsubr")
        	{
        		// Verify that arguments are passed
        		if (NumOfArgs > 0)
        		{
            		// Calc the index of the Subrs
            		int Subr = ((Integer)TopElement).intValue() + LBias;
            		// If the subr isn't in the HashMap -> Put in
        			if (!hSubr.containsKey(Integer.valueOf (Subr)))
            		{
            			hSubr.put(Integer.valueOf(Subr),null);
            			lSubr.add(Integer.valueOf(Subr));
            		}
        			CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
        			seek(pos);
        		}
        	}
        	// a call to a Gsubr
        	else if (key=="callgsubr")
        	{
        		// Verify that arguments are passed
        		if (NumOfArgs > 0)
        		{
	        		// Calc the index of the Subrs
	        		int Subr = ((Integer)TopElement).intValue() + GBias;
	        		// If the subr isn't in the HashMap -> Put in
	        		if (!hGSubrsUsed.containsKey(Integer.valueOf (Subr)))
	        		{
	        			hGSubrsUsed.put(Integer.valueOf(Subr),null);
	        			lGSubrsUsed.add(Integer.valueOf(Subr));
	        		}
	        		CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
	        		seek(pos);
        		}
        	}
        	// A call to "stem"
        	else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") {
				// Increment the NumOfHints by the number couples of of arguments
				NumOfHints += NumOfArgs / 2;
			}
        	// A call to "mask"
        	else if (key == "hintmask" || key == "cntrmask")
        	{
				// if stack is not empty the reason is vstem implicit definition
				// See Adobe Technical Note #5177, page 25, hintmask usage example.
				NumOfHints += NumOfArgs/2;
        		// Compute the size of the mask
        		int SizeOfMask = NumOfHints/8;
        		if (NumOfHints%8 != 0 || SizeOfMask == 0)
        			SizeOfMask++;
        		// Continue the pointer in SizeOfMask steps
        		for (int i=0;i<SizeOfMask;i++)
        			getCard8();
        	}
        }
	}

	/**
	 * Function Checks how the current operator effects the run time stack after being run
	 * An operator may increase or decrease the stack size
	 */
	protected void HandelStack()
	{
    	// Find out what the operator does to the stack
    	int StackHandel = StackOpp();
    	if (StackHandel < 2)
    	{
    		// The operators that enlarge the stack by one
    		if (StackHandel==1)
    			PushStack();
    		// The operators that pop the stack
    		else
    		{
    			// Abs value for the for loop
    			StackHandel *= -1;
    			for (int i=0;i<StackHandel;i++)
    				PopStack();
    		}

    	}
    	// All other flush the stack
    	else
    		EmptyStack();
	}

	/**
	 * Function checks the key and return the change to the stack after the operator
	 * @return The change in the stack. 2-> flush the stack
	 */
	protected int StackOpp()
	{
		if (key == "ifelse")
			return -3;
		if (key == "roll" || key == "put")
			return -2;
		if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" ||
			key == "div" || key == "mul" || key == "drop" || key == "and" ||
			key == "or" || key == "eq")
			return -1;
		if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" ||
			key == "index" || key == "get" || key == "not" || key == "return")
			return 0;
		if (key == "random" || key == "dup")
			return 1;
		return 2;
	}

	/**
	 * Empty the Type2 Stack
	 *
	 */
	protected void EmptyStack()
	{
		// Null the arguments
    	for (int i=0; i<arg_count; i++) args[i]=null;
        arg_count = 0;
	}

	/**
	 * Pop one element from the stack
	 *
	 */
	protected void PopStack()
	{
		if (arg_count>0)
		{
			args[arg_count-1]=null;
			arg_count--;
		}
	}

	/**
	 * Add an item to the stack
	 *
	 */
	protected void PushStack()
	{
		arg_count++;
	}

	/**
	 * The function reads the next command after the file pointer is set
	 */
	protected void ReadCommand()
	{
        key = null;
        boolean gotKey = false;
        // Until a key is found
        while (!gotKey) {
        	// Read the first Char
            char b0 = getCard8();
            // decode according to the type1/type2 format
            if (b0 == 28) // the two next bytes represent a short int;
            {
            	int first = getCard8();
            	int second = getCard8();
            	args[arg_count] = Integer.valueOf(first<<8 | second);
            	arg_count++;
            	continue;
            }
            if (b0 >= 32 && b0 <= 246) // The byte read is the byte;
            {
            	args[arg_count] = Integer.valueOf(b0 - 139);
            	arg_count++;
            	continue;
            }
            if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constitute a short int
            {
            	int w = getCard8();
            	args[arg_count] = Integer.valueOf((b0-247)*256 + w + 108);
            	arg_count++;
            	continue;
            }
            if (b0 >= 251 && b0 <= 254)// Same as above except negative
            {
            	int w = getCard8();
            	args[arg_count] = Integer.valueOf(-(b0-251)*256 - w - 108);
            	arg_count++;
            	continue;
            }
            if (b0 == 255)// The next for bytes represent a double.
            {
            	int first = getCard8();
            	int second = getCard8();
            	int third = getCard8();
            	int fourth = getCard8();
            	args[arg_count] = Integer.valueOf(first<<24 | second<<16 | third<<8 | fourth);
            	arg_count++;
            	continue;
            }
            if (b0<=31 && b0 != 28) // An operator was found.. Set Key.
            {
            	gotKey=true;
            	// 12 is an escape command therefore the next byte is a part
            	// of this command
            	if (b0 == 12)
            	{
            		int b1 = getCard8();
            		if (b1>SubrsEscapeFuncs.length-1)
            			b1 = SubrsEscapeFuncs.length-1;
            		key = SubrsEscapeFuncs[b1];
            	}
            	else
            		key = SubrsFunctions[b0];
                continue;
            }
        }
	}

	/**
	 * The function reads the subroutine and returns the number of the hint in it.
	 * If a call to another subroutine is found the function calls recursively.
	 * @param begin the start point of the subr
	 * @param end the end point of the subr
	 * @param LBias the bias of the Local Subrs
	 * @param GBias the bias of the Global Subrs
	 * @param LSubrsOffsets The Offsets array of the subroutines
	 * @return The number of hints in the subroutine read.
	 */
	protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets)
	{
		// Goto beginning of the subr
        seek(begin);
        while (getPosition() < end)
        {
        	// Read the next command
        	ReadCommand();
        	int pos = getPosition();
        	Object TopElement = null;
        	if (arg_count>0)
        		TopElement = args[arg_count-1];
        	int NumOfArgs = arg_count;
            //Check the modification needed on the Argument Stack according to key;
        	HandelStack();
        	// a call to a Lsubr
        	if (key=="callsubr")
        	{
        		if (NumOfArgs>0)
        		{
            		int Subr = ((Integer)TopElement).intValue() + LBias;
            		CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
            		seek(pos);
        		}
        	}
        	// a call to a Gsubr
        	else if (key=="callgsubr")
        	{
        		if (NumOfArgs>0)
        		{
            		int Subr = ((Integer)TopElement).intValue() + GBias;
            		CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
            		seek(pos);
        		}
        	}
        	// A call to "stem"
        	else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm")
        		// Increment the NumOfHints by the number couples of of arguments
        		NumOfHints += NumOfArgs/2;
        	// A call to "mask"
        	else if (key == "hintmask" || key == "cntrmask")
        	{
        		// Compute the size of the mask
        		int SizeOfMask = NumOfHints/8;
        		if (NumOfHints%8 != 0 || SizeOfMask == 0)
        			SizeOfMask++;
        		// Continue the pointer in SizeOfMask steps
        		for (int i=0;i<SizeOfMask;i++)
        			getCard8();
        	}
        }
        return NumOfHints;
	}


	/**
	 * Function builds the new offset array, object array and assembles the index.
	 * used for creating the glyph and subrs subsetted index
	 * @param Offsets the offset array of the original index
	 * @param Used the hashmap of the used objects
	 * @param OperatorForUnusedEntries the operator inserted into the data stream for unused entries
	 * @return the new index subset version
	 * @throws IOException
	 */
	protected byte[] BuildNewIndex(int[] Offsets,HashMap<Integer, int[]> Used,byte OperatorForUnusedEntries) throws IOException
	{
		int unusedCount = 0;
		int Offset=0;
		int[] NewOffsets = new int[Offsets.length];
		// Build the Offsets Array for the Subset
		for (int i=0;i<Offsets.length;++i)
		{
			NewOffsets[i] = Offset;
			// If the object in the offset is also present in the used
			// HashMap then increment the offset var by its size
			if (Used.containsKey(Integer.valueOf(i))) {
				Offset += Offsets[i+1] - Offsets[i];
			} else {
				// Else the same offset is kept in i+1.
				unusedCount++;
			}
		}
		// Offset var determines the size of the object array
		byte[] NewObjects = new byte[Offset+unusedCount];
		// Build the new Object array
		int unusedOffset = 0;
		for (int i=0;i<Offsets.length-1;++i)
		{
			int start = NewOffsets[i];
			int end = NewOffsets[i+1];
			NewOffsets[i] = start+unusedOffset;
			// If start != End then the Object is used
			// So, we will copy the object data from the font file
			if (start != end)
			{
				// All offsets are Global Offsets relative to the beginning of the font file.
				// Jump the file pointer to the start address to read from.
				buf.seek(Offsets[i]);
				// Read from the buffer and write into the array at start.
                buf.readFully(NewObjects, start+unusedOffset, end-start);
			} else {
				NewObjects[start+unusedOffset] = OperatorForUnusedEntries;
				unusedOffset++;
			}
		}
		NewOffsets[Offsets.length-1] += unusedOffset;
		// Use AssembleIndex to build the index from the offset & object arrays
		return AssembleIndex(NewOffsets,NewObjects);
	}

	/**
	 * Function builds the new offset array, object array and assembles the index.
	 * used for creating the glyph and subrs subsetted index
	 *
	 * @param Offsets                  the offset array of the original index
	 * @param OperatorForUnusedEntries the operator inserted into the data stream for unused entries
	 * @return the new index subset version
	 * @throws java.io.IOException
	 */
	protected byte[] BuildNewIndexAndCopyAllGSubrs(int[] Offsets, byte OperatorForUnusedEntries) throws java.io.IOException {
		int unusedCount = 0;
		int Offset = 0;
		int[] NewOffsets = new int[Offsets.length];
		// Build the Offsets Array for the Subset
		for (int i = 0; i < Offsets.length - 1; ++i) {
			NewOffsets[i] = Offset;
			Offset += Offsets[i + 1] - Offsets[i];
		}
		// Else the same offset is kept in i+1.
		NewOffsets[Offsets.length - 1] = Offset;
		unusedCount++;

		// Offset var determines the size of the object array
		byte[] NewObjects = new byte[Offset + unusedCount];
		// Build the new Object array
		int unusedOffset = 0;
		for (int i = 0; i < Offsets.length - 1; ++i) {
			int start = NewOffsets[i];
			int end = NewOffsets[i + 1];
			NewOffsets[i] = start + unusedOffset;
			// If start != End then the Object is used
			// So, we will copy the object data from the font file
			if (start != end) {
				// All offsets are Global Offsets relative to the beginning of the font file.
				// Jump the file pointer to the start address to read from.
				buf.seek(Offsets[i]);
				// Read from the buffer and write into the array at start.
				buf.readFully(NewObjects, start + unusedOffset, end - start);
			} else {
				NewObjects[start + unusedOffset] = OperatorForUnusedEntries;
				unusedOffset++;
			}
		}
		NewOffsets[Offsets.length - 1] += unusedOffset;
		// Use AssembleIndex to build the index from the offset & object arrays
		return AssembleIndex(NewOffsets, NewObjects);
	}

	/**
	 * Function creates the new index, inserting the count,offsetsize,offset array
	 * and object array.
	 * @param NewOffsets the subsetted offset array
	 * @param NewObjects the subsetted object array
	 * @return the new index created
	 */
	protected byte[] AssembleIndex(int[] NewOffsets,byte[] NewObjects)
	{
		// Calc the index' count field
		char Count = (char)(NewOffsets.length-1);
		// Calc the size of the object array
		int Size = NewOffsets[NewOffsets.length-1];
		// Calc the Offsize
		byte Offsize;
        if (Size < 0xff) Offsize = 1;
        else if (Size < 0xffff) Offsize = 2;
        else if (Size < 0xffffff) Offsize = 3;
        else Offsize = 4;
        // The byte array for the new index. The size is calc by
        // Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array
        byte[] NewIndex = new byte[2+1+Offsize*(Count+1)+NewObjects.length];
        // The counter for writing
        int Place = 0;
        // Write the count field
        NewIndex[Place++] = (byte) (Count >>> 8 & 0xff);
        NewIndex[Place++] = (byte) (Count >>> 0 & 0xff);
        // Write the offsize field
        NewIndex[Place++] = Offsize;
        // Write the offset array according to the offsize
        for (int newOffset : NewOffsets) {
        	// The value to be written
        	int Num = newOffset-NewOffsets[0]+1;
        	// Write in bytes according to the offsize
        	switch (Offsize) {
                case 4:
                	NewIndex[Place++] = (byte) (Num >>> 24 & 0xff);
                case 3:
                	NewIndex[Place++] = (byte) (Num >>> 16 & 0xff);
                case 2:
                	NewIndex[Place++] = (byte) (Num >>>  8 & 0xff);
                case 1:
                	NewIndex[Place++] = (byte) (Num >>>  0 & 0xff);
        	}
        }
        // Write the new object array one by one
        for (byte newObject : NewObjects) {
        	NewIndex[Place++] = newObject;
        }
        // Return the new index
        return NewIndex;
	}

	/**
	 * The function builds the new output stream according to the subset process
	 * @param Font the font
	 * @return the subsetted font stream
	 */
	protected byte[] BuildNewFile(int Font)
    {
		// Prepare linked list for new font components
		OutputList = new LinkedList<Item>();

        // copy the header of the font
        CopyHeader();

        // create a name index
        BuildIndexHeader(1,1,1);
        OutputList.addLast(new UInt8Item((char)( 1+fonts[Font].name.length() )));
        OutputList.addLast(new StringItem(fonts[Font].name));

        // create the topdict Index
        BuildIndexHeader(1,2,1);
        OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
        OutputList.addLast(topdictIndex1Ref);
        IndexBaseItem topdictBase = new IndexBaseItem();
        OutputList.addLast(topdictBase);

        // Initialize the Dict Items for later use
        OffsetItem charsetRef     = new DictOffsetItem();
        OffsetItem charstringsRef = new DictOffsetItem();
        OffsetItem fdarrayRef     = new DictOffsetItem();
        OffsetItem fdselectRef    = new DictOffsetItem();
        OffsetItem privateRef     = new DictOffsetItem();

        // If the font is not CID create the following keys
        if ( !fonts[Font].isCID ) {
            // create a ROS key
        	OutputList.addLast(new DictNumberItem(fonts[Font].nstrings));
        	OutputList.addLast(new DictNumberItem(fonts[Font].nstrings+1));
        	OutputList.addLast(new DictNumberItem(0));
        	OutputList.addLast(new UInt8Item((char)12));
        	OutputList.addLast(new UInt8Item((char)30));
            // create a CIDCount key
        	OutputList.addLast(new DictNumberItem(fonts[Font].nglyphs));
        	OutputList.addLast(new UInt8Item((char)12));
            OutputList.addLast(new UInt8Item((char)34));
            // Sivan's comments
            // What about UIDBase (12,35)? Don't know what is it.
            // I don't think we need FontName; the font I looked at didn't have it.
        }
        // Go to the TopDict of the font being processed
        seek(topdictOffsets[Font]);
        // Run until the end of the TopDict
        while (getPosition() < topdictOffsets[Font+1]) {
            int p1 = getPosition();
            getDictItem();
            int p2 = getPosition();
            // The encoding key is disregarded since CID has no encoding
            if (key=="Encoding"
            // These keys will be added manually by the process.
            || key=="Private"
            || key=="FDSelect"
            || key=="FDArray"
            || key=="charset"
            || key=="CharStrings"
            ) {
            }else {
            //OtherWise copy key "as is" to the output list
                OutputList.add(new RangeItem(buf,p1,p2-p1));
            }
        }
        // Create the FDArray, FDSelect, Charset and CharStrings Keys
        CreateKeys(fdarrayRef,fdselectRef,charsetRef,charstringsRef);

        // Mark the end of the top dict area
        OutputList.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase));

        // Copy the string index

        if (fonts[Font].isCID)
            OutputList.addLast(getEntireIndexRange(stringIndexOffset));
        // If the font is not CID we need to append new strings.
        // We need 3 more strings: Registry, Ordering, and a FontName for one FD.
        // The total length is at most "Adobe"+"Identity"+63 = 76
        else
        	CreateNewStringIndex(Font);

        // copy the new subsetted global subroutine index
        OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewGSubrsIndex),0,NewGSubrsIndex.length));

        // deal with fdarray, fdselect, and the font descriptors
        // If the font is CID:
        if (fonts[Font].isCID) {
            // copy the FDArray, FDSelect, charset

            // Copy FDSelect
        	// Mark the beginning
            OutputList.addLast(new MarkerItem(fdselectRef));
            // If an FDSelect exists copy it
            if (fonts[Font].fdselectOffset>=0)
        		OutputList.addLast(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength));
            // Else create a new one
            else
            	CreateFDSelect(fdselectRef,fonts[Font].nglyphs);

          	// Copy the Charset
            // Mark the beginning and copy entirely
            OutputList.addLast(new MarkerItem(charsetRef));
            OutputList.addLast(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength));

            // Copy the FDArray
            // If an FDArray exists
            if (fonts[Font].fdarrayOffset>=0)
            {
                // Mark the beginning
	            OutputList.addLast(new MarkerItem(fdarrayRef));
	            // Build a new FDArray with its private dicts and their LSubrs
	            Reconstruct(Font);
            }
            else
            	// Else create a new one
            	CreateFDArray(fdarrayRef,privateRef,Font);

        }
        // If the font is not CID
        else
        {
            // create FDSelect
        	CreateFDSelect(fdselectRef,fonts[Font].nglyphs);
            // recreate a new charset
        	CreateCharset(charsetRef,fonts[Font].nglyphs);
            // create a font dict index (fdarray)
        	CreateFDArray(fdarrayRef,privateRef,Font);
        }

        // if a private dict exists insert its subsetted version
        if (fonts[Font].privateOffset>=0)
        {
        	// Mark the beginning of the private dict
        	IndexBaseItem PrivateBase = new IndexBaseItem();
	        OutputList.addLast(PrivateBase);
        	OutputList.addLast(new MarkerItem(privateRef));

        	OffsetItem Subr = new DictOffsetItem();
        	// Build and copy the new private dict
        	CreateNonCIDPrivate(Font,Subr);
        	// Copy the new LSubrs index
        	CreateNonCIDSubrs(Font,PrivateBase,Subr);
        }

        // copy the charstring index
        OutputList.addLast(new MarkerItem(charstringsRef));

        // Add the subsetted charstring
        OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.length));

        // now create the new CFF font
        int[] currentOffset = new int[1];
        currentOffset[0] = 0;
        // Count and save the offset for each item
        Iterator<Item> listIter = OutputList.iterator();
        while ( listIter.hasNext() ) {
            Item item = listIter.next();
            item.increment(currentOffset);
        }
        // Compute the Xref for each of the offset items
        listIter = OutputList.iterator();
        while ( listIter.hasNext() ) {
            Item item = listIter.next();
            item.xref();
        }

        int size = currentOffset[0];
        byte[] b = new byte[size];

        // Emit all the items into the new byte array
        listIter = OutputList.iterator();
        while ( listIter.hasNext() ) {
            Item item = listIter.next();
            item.emit(b);
        }
        // Return the new stream
        return b;
    }

	/**
	 * Function Copies the header from the original fileto the output list
	 */
	protected void CopyHeader()
	{
		seek(0);
        int major = getCard8();
        int minor = getCard8();
        int hdrSize = getCard8();
        int offSize = getCard8();
        nextIndexOffset = hdrSize;
        OutputList.addLast(new RangeItem(buf,0,hdrSize));
	}

	/**
	 * Function Build the header of an index
	 * @param Count the count field of the index
	 * @param Offsize the offsize field of the index
	 * @param First the first offset of the index
	 */
	protected void BuildIndexHeader(int Count,int Offsize,int First)
	{
		// Add the count field
		OutputList.addLast(new UInt16Item((char)Count)); // count
		// Add the offsize field
		OutputList.addLast(new UInt8Item((char)Offsize)); // offSize
		// Add the first offset according to the offsize
        switch(Offsize){
        	case 1:
        		OutputList.addLast(new UInt8Item((char)First)); // first offset
        		break;
        	case 2:
        		OutputList.addLast(new UInt16Item((char)First)); // first offset
        		break;
        	case 3:
        		OutputList.addLast(new UInt24Item((char)First)); // first offset
        		break;
        	case 4:
        		OutputList.addLast(new UInt32Item((char)First)); // first offset
        		break;
    		default:
    			break;
        }
	}

	/**
	 * Function adds the keys into the TopDict
	 * @param fdarrayRef OffsetItem for the FDArray
	 * @param fdselectRef OffsetItem for the FDSelect
	 * @param charsetRef OffsetItem for the CharSet
	 * @param charstringsRef OffsetItem for the CharString
	 */
	protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef)
	{
	    // create an FDArray key
        OutputList.addLast(fdarrayRef);
        OutputList.addLast(new UInt8Item((char)12));
        OutputList.addLast(new UInt8Item((char)36));
        // create an FDSelect key
        OutputList.addLast(fdselectRef);
        OutputList.addLast(new UInt8Item((char)12));
        OutputList.addLast(new UInt8Item((char)37));
        // create an charset key
        OutputList.addLast(charsetRef);
        OutputList.addLast(new UInt8Item((char)15));
        // create a CharStrings key
        OutputList.addLast(charstringsRef);
        OutputList.addLast(new UInt8Item((char)17));
	}

	/**
	 * Function takes the original string item and adds the new strings
	 * to accommodate the CID rules
	 * @param Font the font
	 */
	protected void CreateNewStringIndex(int Font)
	{
        String fdFontName = fonts[Font].name+"-OneRange";
        if (fdFontName.length() > 127)
            fdFontName = fdFontName.substring(0,127);
        String extraStrings = "Adobe"+"Identity"+fdFontName;

        int origStringsLen = stringOffsets[stringOffsets.length-1]
        - stringOffsets[0];
        int stringsBaseOffset = stringOffsets[0]-1;

        byte stringsIndexOffSize;
        if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1;
        else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2;
        else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3;
        else stringsIndexOffSize = 4;

        OutputList.addLast(new UInt16Item((char)(stringOffsets.length-1+3))); // count
        OutputList.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize
        for (int stringOffset : stringOffsets)
            OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
            stringOffset-stringsBaseOffset));
        int currentStringsOffset = stringOffsets[stringOffsets.length-1]
        - stringsBaseOffset;
        //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
        currentStringsOffset += "Adobe".length();
        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
        currentStringsOffset += "Identity".length();
        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
        currentStringsOffset += fdFontName.length();
        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));

        OutputList.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen));
        OutputList.addLast(new StringItem(extraStrings));
    }

	/**
	 * Function creates new FDSelect for non-CID fonts.
	 * The FDSelect built uses a single range for all glyphs
	 * @param fdselectRef OffsetItem for the FDSelect
	 * @param nglyphs the number of glyphs in the font
	 */
	protected void CreateFDSelect(OffsetItem fdselectRef,int nglyphs)
	{
		OutputList.addLast(new MarkerItem(fdselectRef));
	    OutputList.addLast(new UInt8Item((char)3)); // format identifier
	    OutputList.addLast(new UInt16Item((char)1)); // nRanges

	    OutputList.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph
	    OutputList.addLast(new UInt8Item((char)0)); // Range[0].fd

	    OutputList.addLast(new UInt16Item((char)nglyphs)); // sentinel
	}

	/**
	 * Function creates new CharSet for non-CID fonts.
	 * The CharSet built uses a single range for all glyphs
	 * @param charsetRef OffsetItem for the CharSet
	 * @param nglyphs the number of glyphs in the font
	 */
	protected void CreateCharset(OffsetItem charsetRef,int nglyphs)
	{
		OutputList.addLast(new MarkerItem(charsetRef));
	    OutputList.addLast(new UInt8Item((char)2)); // format identifier
	    OutputList.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef)
	    OutputList.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft
	}

	/**
	 * Function creates new FDArray for non-CID fonts.
	 * The FDArray built has only the "Private" operator that points to the font's
	 * original private dict
	 * @param fdarrayRef OffsetItem for the FDArray
	 * @param privateRef OffsetItem for the Private Dict
	 * @param Font the font
	 */
	protected void CreateFDArray(OffsetItem fdarrayRef,OffsetItem privateRef,int Font)
	{
		OutputList.addLast(new MarkerItem(fdarrayRef));
		// Build the header (count=offsize=first=1)
		BuildIndexHeader(1,1,1);

		// Mark
	    OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
	    OutputList.addLast(privateIndex1Ref);
	    IndexBaseItem privateBase = new IndexBaseItem();
	    // Insert the private operands and operator
	    OutputList.addLast(privateBase);
	    // Calc the new size of the private after subsetting
	    // Origianl size
	    int NewSize = fonts[Font].privateLength;
	    // Calc the original size of the Subr offset in the private
		int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].privateOffset,fonts[Font].privateLength);
		// Increase the ptivate's size
		if (OrgSubrsOffsetSize != 0)
			NewSize += 5-OrgSubrsOffsetSize;
	    OutputList.addLast(new DictNumberItem(NewSize));
	    OutputList.addLast(privateRef);
	    OutputList.addLast(new UInt8Item((char)18)); // Private

	    OutputList.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase));
	}

	/**
	 * Function reconstructs the FDArray, PrivateDict and LSubr for CID fonts
	 * @param Font the font
	 */
	void Reconstruct(int Font)
	{
		// Init for later use
		OffsetItem[] fdPrivate = new DictOffsetItem[fonts[Font].FDArrayOffsets.length-1];
		IndexBaseItem[] fdPrivateBase = new IndexBaseItem[fonts[Font].fdprivateOffsets.length];
		OffsetItem[] fdSubrs = new DictOffsetItem[fonts[Font].fdprivateOffsets.length];
		// Reconstruct each type
		ReconstructFDArray(Font,fdPrivate);
		ReconstructPrivateDict(Font,fdPrivate,fdPrivateBase,fdSubrs);
		ReconstructPrivateSubrs(Font,fdPrivateBase,fdSubrs);
	}

	/**
	 * Function subsets the FDArray and builds the new one with new offsets
	 * @param Font The font
	 * @param fdPrivate OffsetItem Array (one for each FDArray)
	 */
	void ReconstructFDArray(int Font,OffsetItem[] fdPrivate)
	{
		// Build the header of the index
		BuildIndexHeader(fonts[Font].FDArrayCount,fonts[Font].FDArrayOffsize,1);

		// For each offset create an Offset Item
		OffsetItem[] fdOffsets = new IndexOffsetItem[fonts[Font].FDArrayOffsets.length-1];
		for (int i=0;i<fonts[Font].FDArrayOffsets.length-1;i++)
		{
			fdOffsets[i] = new IndexOffsetItem(fonts[Font].FDArrayOffsize);
			OutputList.addLast(fdOffsets[i]);
		}

		// Declare beginning of the object array
		IndexBaseItem fdArrayBase = new IndexBaseItem();
	    OutputList.addLast(fdArrayBase);

		// For each object check if that FD is used.
	    // if is used build a new one by changing the private object
	    // Else do nothing
	    // At the end of each object mark its ending (Even if wasn't written)
		for (int k=0; k<fonts[Font].FDArrayOffsets.length-1; k++) {
//			if (FDArrayUsed.contains(Integer.valueOf(k)))
//			{
				// Goto beginning of objects
	            seek(fonts[Font].FDArrayOffsets[k]);
	            while (getPosition() < fonts[Font].FDArrayOffsets[k+1])
	            {
	            	int p1 = getPosition();
	            	getDictItem();
	            	int p2 = getPosition();
	            	// If the dictItem is the "Private" then compute and copy length,
	            	// use marker for offset and write operator number
	            	if (key=="Private") {
	            		// Save the original length of the private dict
	            		int NewSize = ((Integer)args[0]).intValue();
	            		// Save the size of the offset to the subrs in that private
	            		int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].fdprivateOffsets[k],fonts[Font].fdprivateLengths[k]);
	            		// Increase the private's length accordingly
	            		if (OrgSubrsOffsetSize != 0)
	            			NewSize += 5-OrgSubrsOffsetSize;
	            		// Insert the new size, OffsetItem and operator key number
	            		OutputList.addLast(new DictNumberItem(NewSize));
	            		fdPrivate[k] = new DictOffsetItem();
	            		OutputList.addLast(fdPrivate[k]);
	            	    OutputList.addLast(new UInt8Item((char)18)); // Private
	            	    // Go back to place
	            	    seek(p2);
	            	}
	            	// Else copy the entire range
	            	else  // other than private
	            		OutputList.addLast(new RangeItem(buf,p1,p2-p1));
	            }
//			}
            // Mark the ending of the object (even if wasn't written)
            OutputList.addLast(new IndexMarkerItem(fdOffsets[k],fdArrayBase));
        }
	}
	/**
	 * Function Adds the new private dicts (only for the FDs used) to the list
	 * @param Font the font
	 * @param fdPrivate OffsetItem array one element for each private
	 * @param fdPrivateBase IndexBaseItem array one element for each private
	 * @param fdSubrs OffsetItem array one element for each private
	 */
	void ReconstructPrivateDict(int Font,OffsetItem[] fdPrivate,IndexBaseItem[] fdPrivateBase,
			OffsetItem[] fdSubrs)
	{

		// For each fdarray private dict check if that FD is used.
	    // if is used build a new one by changing the subrs offset
	    // Else do nothing
		for (int i=0;i<fonts[Font].fdprivateOffsets.length;i++)
		{
//			if (FDArrayUsed.contains(Integer.valueOf(i)))
//			{
				// Mark beginning
		        OutputList.addLast(new MarkerItem(fdPrivate[i]));
		        fdPrivateBase[i] = new IndexBaseItem();
		        OutputList.addLast(fdPrivateBase[i]);
				// Goto beginning of objects
	            seek(fonts[Font].fdprivateOffsets[i]);
	            while (getPosition() < fonts[Font].fdprivateOffsets[i]+fonts[Font].fdprivateLengths[i])
	            {
	            	int p1 = getPosition();
	            	getDictItem();
	            	int p2 = getPosition();
	            	// If the dictItem is the "Subrs" then,
	            	// use marker for offset and write operator number
	            	if (key=="Subrs") {
	            		fdSubrs[i] = new DictOffsetItem();
	            		OutputList.addLast(fdSubrs[i]);
	            	    OutputList.addLast(new UInt8Item((char)19)); // Subrs
	            	}
	            	// Else copy the entire range
	            	else
	            		OutputList.addLast(new RangeItem(buf,p1,p2-p1));
	            }
//			}
		}
	}

	/**
	 * Function Adds the new LSubrs dicts (only for the FDs used) to the list
	 * @param Font  The index of the font
	 * @param fdPrivateBase The IndexBaseItem array for the linked list
	 * @param fdSubrs OffsetItem array for the linked list
	 */

	void ReconstructPrivateSubrs(int Font,IndexBaseItem[] fdPrivateBase,
			OffsetItem[] fdSubrs)
	{
		// For each private dict
        for (int i=0;i<fonts[Font].fdprivateLengths.length;i++)
        {
        	// If that private dict's Subrs are used insert the new LSubrs
        	// computed earlier
        	if (fdSubrs[i]!= null && fonts[Font].PrivateSubrsOffset[i] >= 0)
        	{
        		OutputList.addLast(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i]));
        		if(NewLSubrsIndex[i]!=null)
        			OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].length));
        	}
        }
    }

	/**
	 * Calculates how many byte it took to write the offset for the subrs in a specific
	 * private dict.
	 * @param Offset The Offset for the private dict
	 * @param Size The size of the private dict
	 * @return The size of the offset of the subrs in the private dict
	 */
	int CalcSubrOffsetSize(int Offset,int Size)
	{
		// Set the size to 0
		int OffsetSize = 0;
		// Go to the beginning of the private dict
		seek(Offset);
		// Go until the end of the private dict
		while (getPosition() < Offset+Size)
        {
        	int p1 = getPosition();
        	getDictItem();
        	int p2 = getPosition();
        	// When reached to the subrs offset
        	if (key=="Subrs") {
        		// The Offsize (minus the subrs key)
        		OffsetSize = p2-p1-1;
        	}
        	// All other keys are ignored
        }
		// return the size
		return OffsetSize;
	}

	/**
	 * Function computes the size of an index
	 * @param indexOffset The offset for the computed index
	 * @return The size of the index
	 */
	protected int countEntireIndexRange(int indexOffset)
	{
		// Go to the beginning of the index
	    seek(indexOffset);
	    // Read the count field
	    int count = getCard16();
	    // If count==0 -> size=2
	    if (count==0)
	        return 2;
	    else
	    {
	    	// Read the offsize field
	        int indexOffSize = getCard8();
	        // Go to the last element of the offset array
	        seek(indexOffset+2+1+count*indexOffSize);
	        // The size of the object array is the value of the last element-1
	        int size = getOffset(indexOffSize)-1;
	        // Return the size of the entire index
	        return 2+1+(count+1)*indexOffSize+size;
	    }
	}

	/**
	 * The function creates a private dict for a font that was not CID
	 * All the keys are copied as is except for the subrs key
	 * @param Font the font
	 * @param Subr The OffsetItem for the subrs of the private
	 */
	void CreateNonCIDPrivate(int Font,OffsetItem Subr)
	{
		// Go to the beginning of the private dict and read until the end
		seek(fonts[Font].privateOffset);
        while (getPosition() < fonts[Font].privateOffset+fonts[Font].privateLength)
        {
        	int p1 = getPosition();
        	getDictItem();
        	int p2 = getPosition();
        	// If the dictItem is the "Subrs" then,
        	// use marker for offset and write operator number
        	if (key=="Subrs") {
        		OutputList.addLast(Subr);
        	    OutputList.addLast(new UInt8Item((char)19)); // Subrs
        	}
        	// Else copy the entire range
        	else
        		OutputList.addLast(new RangeItem(buf,p1,p2-p1));
        }
	}

	/**
	 * the function marks the beginning of the subrs index and adds the subsetted subrs
	 * index to the output list.
	 * @param Font the font
	 * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs
	 * @param Subrs OffsetItem for the subrs
	 */
	void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs)
	{
		// Mark the beginning of the Subrs index
		OutputList.addLast(new SubrMarkerItem(Subrs,PrivateBase));
		// Put the subsetted new subrs index
        if (NewSubrsIndexNonCID != null) {
            OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.length));
        }
    }
}

com/itextpdf/text/pdf/CFFFontSubset.java

 

⇒ iText-2.1.6.jar - iText, a JAVA-PDF library

⇐ iText layout.jar Source Code

⇑ Download and Install iText Java Library

⇑⇑ iText for PDF Generation

2021-07-03, 48033👍, 0💬