001/*
002 * $Id: CFFFontSubset.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf;
045
046import java.io.IOException;
047import java.util.ArrayList;
048import java.util.HashMap;
049import java.util.HashSet;
050import java.util.Iterator;
051import java.util.LinkedList;
052
053/**
054 * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts.
055 * The Charstring is subsetted for both types. For CID fonts only the FDArray which are used are embedded.
056 * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2
057 * formatting although only tested on Type2 Format.
058 * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted.
059 * A font which was not of CID type is transformed into CID as a part of the subset process.
060 * The CID synthetic creation was written by Sivan Toledo (sivan@math.tau.ac.il)
061 * @author Oren Manor (manorore@post.tau.ac.il) and Ygal Blum (blumygal@post.tau.ac.il)
062 */
063public class CFFFontSubset extends CFFFont {
064
065        /**
066         *  The Strings in this array represent Type1/Type2 operator names
067         */
068        static final String SubrsFunctions[] = {
069                        "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto",
070                        "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13",
071                        "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask",
072                        "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto",
073                        "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto"
074                        };
075        /**
076         * The Strings in this array represent Type1/Type2 escape operator names
077         */
078        static final String SubrsEscapeFuncs[] = {
079                        "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6",
080                        "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg",
081                        "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse",
082                        "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31",
083                        "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST"
084        };
085
086        /**
087        *  Operator codes for unused  CharStrings and unused local and global Subrs
088        */
089        static final byte ENDCHAR_OP = 14;
090        static final byte RETURN_OP = 11;
091
092        /**
093         * A HashMap containing the glyphs used in the text after being converted
094         * to glyph number by the CMap
095         */
096        HashMap<Integer, int[]> GlyphsUsed;
097        /**
098         * The GlyphsUsed keys as an ArrayList
099         */
100        ArrayList<Integer> glyphsInList;
101        /**
102         * A HashSet for keeping the FDArrays being used by the font
103         */
104        HashSet<Integer> FDArrayUsed = new HashSet<Integer>();
105        /**
106         * A HashMaps array for keeping the subroutines used in each FontDict
107         */
108        HashMap<Integer, int[]>[] hSubrsUsed;
109        /**
110         * The SubroutinesUsed HashMaps as ArrayLists
111         */
112        ArrayList<Integer>[] lSubrsUsed;
113        /**
114         * A HashMap for keeping the Global subroutines used in the font
115         */
116        HashMap<Integer, int[]> hGSubrsUsed  = new HashMap<Integer, int[]>();
117        /**
118         * The Global SubroutinesUsed HashMaps as ArrayLists
119         */
120        ArrayList<Integer> lGSubrsUsed = new ArrayList<Integer>();
121        /**
122         * A HashMap for keeping the subroutines used in a non-cid font
123         */
124        HashMap<Integer, int[]> hSubrsUsedNonCID  = new HashMap<Integer, int[]>();
125        /**
126         * The SubroutinesUsed HashMap as ArrayList
127         */
128        ArrayList<Integer> lSubrsUsedNonCID = new ArrayList<Integer>();
129        /**
130         * An array of the new Indexes for the local Subr. One index for each FontDict
131         */
132        byte[][] NewLSubrsIndex;
133        /**
134         * The new subroutines index for a non-cid font
135         */
136        byte[] NewSubrsIndexNonCID;
137        /**
138         * The new global subroutines index of the font
139         */
140        byte[] NewGSubrsIndex;
141        /**
142         * The new CharString of the font
143         */
144        byte[] NewCharStringsIndex;
145
146        /**
147         * The bias for the global subroutines
148         */
149        int GBias = 0;
150
151        /**
152         * The linked list for generating the new font stream
153         */
154        LinkedList<Item> OutputList;
155
156        /**
157         * Number of arguments to the stem operators in a subroutine calculated recursively
158         */
159        int NumOfHints=0;
160
161
162        /**
163         * C'tor for CFFFontSubset
164         * @param rf - The font file
165         * @param GlyphsUsed - a HashMap that contains the glyph used in the subset
166         */
167    public CFFFontSubset(RandomAccessFileOrArray rf,HashMap<Integer, int[]> GlyphsUsed){
168                // Use CFFFont c'tor in order to parse the font file.
169        super(rf);
170                this.GlyphsUsed = GlyphsUsed;
171                //Put the glyphs into a list
172                glyphsInList = new ArrayList<Integer>(GlyphsUsed.keySet());
173
174
175                for (int i=0;i<fonts.length;++i)
176                {
177                        // Read the number of glyphs in the font
178                        seek(fonts[i].charstringsOffset);
179                fonts[i].nglyphs = getCard16();
180
181                // Jump to the count field of the String Index
182                seek(stringIndexOffset);
183                fonts[i].nstrings = getCard16()+standardStrings.length;
184
185                // For each font save the offset array of the charstring
186                        fonts[i].charstringsOffsets = getIndex(fonts[i].charstringsOffset);
187
188                        // Process the FDSelect if exist
189                        if (fonts[i].fdselectOffset>=0)
190                        {
191                                // Process the FDSelect
192                    readFDSelect(i);
193                    // Build the FDArrayUsed hashmap
194                BuildFDArrayUsed(i);
195                        }
196                        if (fonts[i].isCID)
197                                // Build the FD Array used Hash Map
198                                ReadFDArray(i);
199                        // compute the charset length
200                        fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs);
201                }
202        }
203
204    /**
205     * Calculates the length of the charset according to its format
206     * @param Offset The Charset Offset
207     * @param NumofGlyphs Number of glyphs in the font
208     * @return the length of the Charset
209     */
210    int CountCharset(int Offset,int NumofGlyphs){
211        int format;
212        int Length=0;
213        seek(Offset);
214        // Read the format
215        format = getCard8();
216        // Calc according to format
217        switch (format){
218                case 0:
219                        Length = 1+2*NumofGlyphs;
220                        break;
221                case 1:
222                        Length = 1+3*CountRange(NumofGlyphs,1);
223                        break;
224                case 2:
225                        Length = 1+4*CountRange(NumofGlyphs,2);
226                        break;
227                default:
228                        break;
229        }
230        return Length;
231    }
232
233    /**
234     * Function calculates the number of ranges in the Charset
235     * @param NumofGlyphs The number of glyphs in the font
236     * @param Type The format of the Charset
237     * @return The number of ranges in the Charset data structure
238     */
239    int CountRange(int NumofGlyphs,int Type){
240        int num=0;
241        char Sid;
242        int i=1,nLeft;
243        while (i<NumofGlyphs){
244                num++;
245                Sid = getCard16();
246                if (Type==1)
247                        nLeft = getCard8();
248                else
249                        nLeft = getCard16();
250                i += nLeft+1;
251        }
252        return num;
253    }
254
255
256        /**
257         * Read the FDSelect of the font and compute the array and its length
258         * @param Font The index of the font being processed
259         */
260        protected void readFDSelect(int Font)
261        {
262                // Restore the number of glyphs
263                int NumOfGlyphs = fonts[Font].nglyphs;
264                int[] FDSelect = new int[NumOfGlyphs];
265                // Go to the beginning of the FDSelect
266                seek(fonts[Font].fdselectOffset);
267                // Read the FDSelect's format
268                fonts[Font].FDSelectFormat = getCard8();
269
270                switch(fonts[Font].FDSelectFormat){
271                        // Format==0 means each glyph has an entry that indicated
272                        // its FD.
273                        case 0:
274                                for (int i=0;i<NumOfGlyphs;i++)
275                                {
276                                        FDSelect[i] = getCard8();
277                                }
278                                // The FDSelect's Length is one for each glyph + the format
279                                // for later use
280                                fonts[Font].FDSelectLength = fonts[Font].nglyphs+1;
281                                break;
282                        case 3:
283                                // Format==3 means the ranges version
284                                // The number of ranges
285                                int nRanges = getCard16();
286                                int l=0;
287                                // Read the first in the first range
288                                int first = getCard16();
289                                for (int i=0;i<nRanges;i++)
290                                {
291                                        // Read the FD index
292                                        int fd = getCard8();
293                                        // Read the first of the next range
294                                        int last = getCard16();
295                                        // Calc the steps and write to the array
296                                        int steps = last-first;
297                                        for (int k=0;k<steps;k++)
298                                        {
299                                                FDSelect[l] = fd;
300                                                l++;
301                                        }
302                                        // The last from this iteration is the first of the next
303                                        first = last;
304                                }
305                                // Store the length for later use
306                                fonts[Font].FDSelectLength = 1+2+nRanges*3+2;
307                                break;
308                        default:
309                                break;
310                }
311                // Save the FDSelect of the font
312                fonts[Font].FDSelect = FDSelect;
313        }
314
315        /**
316         * Function reads the FDSelect and builds the FDArrayUsed HashMap According to the glyphs used
317         * @param Font the Number of font being processed
318         */
319        protected void BuildFDArrayUsed(int Font)
320        {
321                int[] FDSelect = fonts[Font].FDSelect;
322                // For each glyph used
323                for (int i=0;i<glyphsInList.size();i++)
324                {
325                        // Pop the glyphs index
326                        int glyph = glyphsInList.get(i).intValue();
327                        // Pop the glyph's FD
328                        int FD = FDSelect[glyph];
329                        // Put the FD index into the FDArrayUsed HashMap
330                        FDArrayUsed.add(Integer.valueOf(FD));
331                }
332        }
333
334        /**
335         * Read the FDArray count, offsize and Offset array
336         * @param Font
337         */
338        protected void ReadFDArray(int Font)
339        {
340                seek(fonts[Font].fdarrayOffset);
341                fonts[Font].FDArrayCount = getCard16();
342                fonts[Font].FDArrayOffsize = getCard8();
343                // Since we will change values inside the FDArray objects
344                // We increase its offsize to prevent errors
345                if (fonts[Font].FDArrayOffsize < 4)
346                        fonts[Font].FDArrayOffsize++;
347                fonts[Font].FDArrayOffsets = getIndex(fonts[Font].fdarrayOffset);
348        }
349
350
351        /**
352         * The Process function extracts one font out of the CFF file and returns a
353         * subset version of the original.
354         * @param fontName - The name of the font to be taken out of the CFF
355         * @return The new font stream
356         * @throws IOException
357         */
358        public byte[] Process(String fontName)throws IOException{
359                try
360                {
361                        // Verify that the file is open
362                        buf.reOpen();
363                        // Find the Font that we will be dealing with
364                        int j;
365                for (j=0; j<fonts.length; j++)
366                    if (fontName.equals(fonts[j].name)) break;
367                if (j==fonts.length) return null;
368
369                        // Calc the bias for the global subrs
370                        if (gsubrIndexOffset >= 0)
371                                GBias = CalcBias(gsubrIndexOffset,j);
372
373                // Prepare the new CharStrings Index
374                        BuildNewCharString(j);
375                         // Prepare the new Global and Local Subrs Indices
376                        BuildNewLGSubrs(j);
377                        // Build the new file
378                        byte[] Ret = BuildNewFile(j);
379                        return Ret;
380                }
381                finally {
382            try {
383                buf.close();
384            }
385            catch (Exception e) {
386                // empty on purpose
387            }
388                }
389        }
390
391        /**
392         * Function calcs bias according to the CharString type and the count
393         * of the subrs
394         * @param Offset The offset to the relevant subrs index
395         * @param Font the font
396         * @return The calculated Bias
397         */
398        protected int CalcBias(int Offset,int Font)
399        {
400                seek(Offset);
401                int nSubrs = getCard16();
402                // If type==1 -> bias=0
403                if (fonts[Font].CharstringType == 1)
404                        return 0;
405                // else calc according to the count
406                else if (nSubrs < 1240)
407                        return 107;
408                else if (nSubrs < 33900)
409                        return 1131;
410                else
411                        return 32768;
412        }
413
414        /**
415         *Function uses BuildNewIndex to create the new index of the subset charstrings
416         * @param FontIndex the font
417         * @throws IOException
418         */
419        protected void BuildNewCharString(int FontIndex) throws IOException
420        {
421                NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed,ENDCHAR_OP);
422        }
423
424        /**
425         * Function builds the new local & global subsrs indices. IF CID then All of
426         * the FD Array lsubrs will be subsetted.
427         * @param Font the font
428         * @throws IOException
429         */
430    @SuppressWarnings("unchecked")
431    protected void BuildNewLGSubrs(int Font)throws IOException
432        {
433                // If the font is CID then the lsubrs are divided into FontDicts.
434                // for each FD array the lsubrs will be subsetted.
435                if(fonts[Font].isCID)
436                {
437                        // Init the hashmap-array and the arraylist-array to hold the subrs used
438                        // in each private dict.
439                        hSubrsUsed = new HashMap[fonts[Font].fdprivateOffsets.length];
440                        lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.length];
441                        // A [][] which will store the byte array for each new FD Array lsubs index
442                        NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.length][];
443                        // An array to hold the offset for each Lsubr index
444                        fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.length];
445                        // A [][] which will store the offset array for each lsubr index
446                        fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.length][];
447
448                        // Put the FDarrayUsed into a list
449                        ArrayList<Integer> FDInList = new ArrayList<Integer>(FDArrayUsed);
450                        // For each FD array which is used subset the lsubr
451                        for (int j=0;j<FDInList.size();j++)
452                        {
453                                // The FDArray index, Hash Map, Array List to work on
454                                int FD = FDInList.get(j).intValue();
455                                hSubrsUsed[FD] = new HashMap<Integer, int[]>();
456                                lSubrsUsed[FD] = new ArrayList<Integer>();
457                                //Reads the private dicts looking for the subr operator and
458                                // store both the offset for the index and its offset array
459                                BuildFDSubrsOffsets(Font,FD);
460                                // Verify that FDPrivate has a LSubrs index
461                                if(fonts[Font].PrivateSubrsOffset[FD]>=0)
462                                {
463                                        //Scans the Charstring data storing the used Local and Global subroutines
464                                        // by the glyphs. Scans the Subrs recursively.
465                                        BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]);
466                                        // Builds the New Local Subrs index
467                                        NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],RETURN_OP);
468                                }
469                        }
470                }
471                // If the font is not CID && the Private Subr exists then subset:
472                else if (fonts[Font].privateSubrs>=0)
473                {
474                        // Build the subrs offsets;
475                        fonts[Font].SubrsOffsets = getIndex(fonts[Font].privateSubrs);
476                        //Scans the Charstring data storing the used Local and Global subroutines
477                        // by the glyphs. Scans the Subrs recursively.
478                        BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID);
479                }
480                // For all fonts subset the Global Subroutines
481                // Scan the Global Subr Hashmap recursively on the Gsubrs
482                BuildGSubrsUsed(Font);
483                if (fonts[Font].privateSubrs>=0)
484                        // Builds the New Local Subrs index
485                        NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID,RETURN_OP);
486                //Builds the New Global Subrs index
487                NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed,RETURN_OP);
488        }
489
490        /**
491         * The function finds for the FD array processed the local subr offset and its
492         * offset array.
493         * @param Font the font
494         * @param FD The FDARRAY processed
495         */
496        protected void BuildFDSubrsOffsets(int Font,int FD)
497        {
498                // Initiate to -1 to indicate lsubr operator present
499                fonts[Font].PrivateSubrsOffset[FD] = -1;
500                // Goto beginning of objects
501        seek(fonts[Font].fdprivateOffsets[FD]);
502        // While in the same object:
503        while (getPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD])
504        {
505                getDictItem();
506                // If the dictItem is the "Subrs" then find and store offset,
507                if (key=="Subrs")
508                        fonts[Font].PrivateSubrsOffset[FD] = ((Integer)args[0]).intValue()+fonts[Font].fdprivateOffsets[FD];
509        }
510        //Read the lsubr index if the lsubr was found
511        if (fonts[Font].PrivateSubrsOffset[FD] >= 0)
512                fonts[Font].PrivateSubrsOffsetsArray[FD] = getIndex(fonts[Font].PrivateSubrsOffset[FD]);
513        }
514
515        /**
516         * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap.
517         * The HashMap (of the lsubr only) is then scanned recursively for Lsubr & Gsubrs
518         * calls.
519         * @param Font the font
520         * @param FD FD array processed. 0 indicates function was called by non CID font
521         * @param SubrOffset the offset to the subr index to calc the bias
522         * @param SubrsOffsets the offset array of the subr index
523         * @param hSubr HashMap of the subrs used
524         * @param lSubr ArrayList of the subrs used
525         */
526        protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,HashMap<Integer, int[]> hSubr,ArrayList<Integer> lSubr)
527        {
528
529                // Calc the Bias for the subr index
530                int LBias = CalcBias(SubrOffset,Font);
531
532                // For each glyph used find its GID, start & end pos
533                for (int i=0;i<glyphsInList.size();i++)
534                {
535                        int glyph = glyphsInList.get(i).intValue();
536                        int Start = fonts[Font].charstringsOffsets[glyph];
537                        int End = fonts[Font].charstringsOffsets[glyph+1];
538
539                        // IF CID:
540                        if (FD >= 0)
541                        {
542                                EmptyStack();
543                                NumOfHints=0;
544                                // Using FDSELECT find the FD Array the glyph belongs to.
545                                int GlyphFD = fonts[Font].FDSelect[glyph];
546                                // If the Glyph is part of the FD being processed
547                                if (GlyphFD == FD)
548                                        // Find the Subrs called by the glyph and insert to hash:
549                                        ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
550                        }
551                        else
552                                // If the font is not CID
553                                //Find the Subrs called by the glyph and insert to hash:
554                                ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
555                }
556                // For all Lsubrs used, check recursively for Lsubr & Gsubr used
557                for (int i=0;i<lSubr.size();i++)
558                {
559                        // Pop the subr value from the hash
560                        int Subr = lSubr.get(i).intValue();
561                        // Ensure the Lsubr call is valid
562                        if (Subr < SubrsOffsets.length-1 && Subr>=0)
563                        {
564                                // Read and process the subr
565                                int Start = SubrsOffsets[Subr];
566                                int End = SubrsOffsets[Subr+1];
567                                ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
568                        }
569                }
570        }
571
572        /**
573         * Function scans the Glsubr used ArrayList to find recursive calls
574         * to Gsubrs and adds to Hashmap & ArrayList
575         * @param Font the font
576         */
577        protected void BuildGSubrsUsed(int Font)
578        {
579                int LBias = 0;
580                int SizeOfNonCIDSubrsUsed = 0;
581                if (fonts[Font].privateSubrs>=0)
582                {
583                        LBias = CalcBias(fonts[Font].privateSubrs,Font);
584                        SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
585                }
586
587                // For each global subr used
588                for (int i=0;i<lGSubrsUsed.size();i++)
589                {
590                        //Pop the value + check valid
591                        int Subr = lGSubrsUsed.get(i).intValue();
592                        if (Subr < gsubrOffsets.length-1 && Subr>=0)
593                        {
594                                // Read the subr and process
595                                int Start = gsubrOffsets[Subr];
596                                int End = gsubrOffsets[Subr+1];
597
598                                if (fonts[Font].isCID)
599                                        ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null);
600                                else
601                                {
602                                        ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets);
603                                        if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.size())
604                                        {
605                                                for (int j=SizeOfNonCIDSubrsUsed;j<lSubrsUsedNonCID.size();j++)
606                                                {
607                                                        //Pop the value + check valid
608                                                        int LSubr = lSubrsUsedNonCID.get(j).intValue();
609                                                        if (LSubr < fonts[Font].SubrsOffsets.length-1 && LSubr>=0)
610                                                        {
611                                                                // Read the subr and process
612                                                                int LStart = fonts[Font].SubrsOffsets[LSubr];
613                                                                int LEnd = fonts[Font].SubrsOffsets[LSubr+1];
614                                                                ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets);
615                                                        }
616                                                }
617                                                SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
618                                        }
619                                }
620                        }
621                }
622        }
623
624        /**
625         * The function reads a subrs (glyph info) between begin and end.
626         * Adds calls to a Lsubr to the hSubr and lSubrs.
627         * Adds calls to a Gsubr to the hGSubr and lGSubrs.
628         * @param begin the start point of the subr
629         * @param end the end point of the subr
630         * @param GBias the bias of the Global Subrs
631         * @param LBias the bias of the Local Subrs
632         * @param hSubr the HashMap for the lSubrs
633         * @param lSubr the ArrayList for the lSubrs
634         */
635        protected void ReadASubr(int begin,int end,int GBias,int LBias,HashMap<Integer, int[]> hSubr,ArrayList<Integer> lSubr,int[] LSubrsOffsets)
636        {
637                // Clear the stack for the subrs
638                EmptyStack();
639                NumOfHints = 0;
640                // Goto beginning of the subr
641        seek(begin);
642        while (getPosition() < end)
643        {
644                // Read the next command
645                ReadCommand();
646                int pos = getPosition();
647                Object TopElement=null;
648                if (arg_count > 0)
649                        TopElement = args[arg_count-1];
650                int NumOfArgs = arg_count;
651                // Check the modification needed on the Argument Stack according to key;
652                HandelStack();
653                // a call to a Lsubr
654                if (key=="callsubr")
655                {
656                        // Verify that arguments are passed
657                        if (NumOfArgs > 0)
658                        {
659                        // Calc the index of the Subrs
660                        int Subr = ((Integer)TopElement).intValue() + LBias;
661                        // If the subr isn't in the HashMap -> Put in
662                                if (!hSubr.containsKey(Integer.valueOf (Subr)))
663                        {
664                                hSubr.put(Integer.valueOf(Subr),null);
665                                lSubr.add(Integer.valueOf(Subr));
666                        }
667                                CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
668                                seek(pos);
669                        }
670                }
671                // a call to a Gsubr
672                else if (key=="callgsubr")
673                {
674                        // Verify that arguments are passed
675                        if (NumOfArgs > 0)
676                        {
677                                // Calc the index of the Subrs
678                                int Subr = ((Integer)TopElement).intValue() + GBias;
679                                // If the subr isn't in the HashMap -> Put in
680                                if (!hGSubrsUsed.containsKey(Integer.valueOf (Subr)))
681                                {
682                                        hGSubrsUsed.put(Integer.valueOf(Subr),null);
683                                        lGSubrsUsed.add(Integer.valueOf(Subr));
684                                }
685                                CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
686                                seek(pos);
687                        }
688                }
689                // A call to "stem"
690                else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm")
691                        // Increment the NumOfHints by the number couples of of arguments
692                        NumOfHints += NumOfArgs/2;
693                // A call to "mask"
694                else if (key == "hintmask" || key == "cntrmask")
695                {
696                        // Compute the size of the mask
697                        int SizeOfMask = NumOfHints/8;
698                        if (NumOfHints%8 != 0 || SizeOfMask == 0)
699                                SizeOfMask++;
700                        // Continue the pointer in SizeOfMask steps
701                        for (int i=0;i<SizeOfMask;i++)
702                                getCard8();
703                }
704        }
705        }
706
707        /**
708         * Function Checks how the current operator effects the run time stack after being run
709         * An operator may increase or decrease the stack size
710         */
711        protected void HandelStack()
712        {
713        // Find out what the operator does to the stack
714        int StackHandel = StackOpp();
715        if (StackHandel < 2)
716        {
717                // The operators that enlarge the stack by one
718                if (StackHandel==1)
719                        PushStack();
720                // The operators that pop the stack
721                else
722                {
723                        // Abs value for the for loop
724                        StackHandel *= -1;
725                        for (int i=0;i<StackHandel;i++)
726                                PopStack();
727                }
728
729        }
730        // All other flush the stack
731        else
732                EmptyStack();
733        }
734
735        /**
736         * Function checks the key and return the change to the stack after the operator
737         * @return The change in the stack. 2-> flush the stack
738         */
739        protected int StackOpp()
740        {
741                if (key == "ifelse")
742                        return -3;
743                if (key == "roll" || key == "put")
744                        return -2;
745                if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" ||
746                        key == "div" || key == "mul" || key == "drop" || key == "and" ||
747                        key == "or" || key == "eq")
748                        return -1;
749                if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" ||
750                        key == "index" || key == "get" || key == "not" || key == "return")
751                        return 0;
752                if (key == "random" || key == "dup")
753                        return 1;
754                return 2;
755        }
756
757        /**
758         * Empty the Type2 Stack
759         *
760         */
761        protected void EmptyStack()
762        {
763                // Null the arguments
764        for (int i=0; i<arg_count; i++) args[i]=null;
765        arg_count = 0;
766        }
767
768        /**
769         * Pop one element from the stack
770         *
771         */
772        protected void PopStack()
773        {
774                if (arg_count>0)
775                {
776                        args[arg_count-1]=null;
777                        arg_count--;
778                }
779        }
780
781        /**
782         * Add an item to the stack
783         *
784         */
785        protected void PushStack()
786        {
787                arg_count++;
788        }
789
790        /**
791         * The function reads the next command after the file pointer is set
792         */
793        protected void ReadCommand()
794        {
795        key = null;
796        boolean gotKey = false;
797        // Until a key is found
798        while (!gotKey) {
799                // Read the first Char
800            char b0 = getCard8();
801            // decode according to the type1/type2 format
802            if (b0 == 28) // the two next bytes represent a short int;
803            {
804                int first = getCard8();
805                int second = getCard8();
806                args[arg_count] = Integer.valueOf(first<<8 | second);
807                arg_count++;
808                continue;
809            }
810            if (b0 >= 32 && b0 <= 246) // The byte read is the byte;
811            {
812                args[arg_count] = Integer.valueOf(b0 - 139);
813                arg_count++;
814                continue;
815            }
816            if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constitute a short int
817            {
818                int w = getCard8();
819                args[arg_count] = Integer.valueOf((b0-247)*256 + w + 108);
820                arg_count++;
821                continue;
822            }
823            if (b0 >= 251 && b0 <= 254)// Same as above except negative
824            {
825                int w = getCard8();
826                args[arg_count] = Integer.valueOf(-(b0-251)*256 - w - 108);
827                arg_count++;
828                continue;
829            }
830            if (b0 == 255)// The next for bytes represent a double.
831            {
832                int first = getCard8();
833                int second = getCard8();
834                int third = getCard8();
835                int fourth = getCard8();
836                args[arg_count] = Integer.valueOf(first<<24 | second<<16 | third<<8 | fourth);
837                arg_count++;
838                continue;
839            }
840            if (b0<=31 && b0 != 28) // An operator was found.. Set Key.
841            {
842                gotKey=true;
843                // 12 is an escape command therefore the next byte is a part
844                // of this command
845                if (b0 == 12)
846                {
847                        int b1 = getCard8();
848                        if (b1>SubrsEscapeFuncs.length-1)
849                                b1 = SubrsEscapeFuncs.length-1;
850                        key = SubrsEscapeFuncs[b1];
851                }
852                else
853                        key = SubrsFunctions[b0];
854                continue;
855            }
856        }
857        }
858
859        /**
860         * The function reads the subroutine and returns the number of the hint in it.
861         * If a call to another subroutine is found the function calls recursively.
862         * @param begin the start point of the subr
863         * @param end the end point of the subr
864         * @param LBias the bias of the Local Subrs
865         * @param GBias the bias of the Global Subrs
866         * @param LSubrsOffsets The Offsets array of the subroutines
867         * @return The number of hints in the subroutine read.
868         */
869        protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets)
870        {
871                // Goto beginning of the subr
872        seek(begin);
873        while (getPosition() < end)
874        {
875                // Read the next command
876                ReadCommand();
877                int pos = getPosition();
878                Object TopElement = null;
879                if (arg_count>0)
880                        TopElement = args[arg_count-1];
881                int NumOfArgs = arg_count;
882            //Check the modification needed on the Argument Stack according to key;
883                HandelStack();
884                // a call to a Lsubr
885                if (key=="callsubr")
886                {
887                        if (NumOfArgs>0)
888                        {
889                        int Subr = ((Integer)TopElement).intValue() + LBias;
890                        CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
891                        seek(pos);
892                        }
893                }
894                // a call to a Gsubr
895                else if (key=="callgsubr")
896                {
897                        if (NumOfArgs>0)
898                        {
899                        int Subr = ((Integer)TopElement).intValue() + GBias;
900                        CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
901                        seek(pos);
902                        }
903                }
904                // A call to "stem"
905                else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm")
906                        // Increment the NumOfHints by the number couples of of arguments
907                        NumOfHints += NumOfArgs/2;
908                // A call to "mask"
909                else if (key == "hintmask" || key == "cntrmask")
910                {
911                        // Compute the size of the mask
912                        int SizeOfMask = NumOfHints/8;
913                        if (NumOfHints%8 != 0 || SizeOfMask == 0)
914                                SizeOfMask++;
915                        // Continue the pointer in SizeOfMask steps
916                        for (int i=0;i<SizeOfMask;i++)
917                                getCard8();
918                }
919        }
920        return NumOfHints;
921        }
922
923
924        /**
925         * Function builds the new offset array, object array and assembles the index.
926         * used for creating the glyph and subrs subsetted index
927         * @param Offsets the offset array of the original index
928         * @param Used the hashmap of the used objects
929         * @param OperatorForUnusedEntries the operator inserted into the data stream for unused entries
930         * @return the new index subset version
931         * @throws IOException
932         */
933        protected byte[] BuildNewIndex(int[] Offsets,HashMap<Integer, int[]> Used,byte OperatorForUnusedEntries) throws IOException
934        {
935                int unusedCount = 0;
936                int Offset=0;
937                int[] NewOffsets = new int[Offsets.length];
938                // Build the Offsets Array for the Subset
939                for (int i=0;i<Offsets.length;++i)
940                {
941                        NewOffsets[i] = Offset;
942                        // If the object in the offset is also present in the used
943                        // HashMap then increment the offset var by its size
944                        if (Used.containsKey(Integer.valueOf(i))) {
945                                Offset += Offsets[i+1] - Offsets[i];
946                        } else {
947                                // Else the same offset is kept in i+1.
948                                unusedCount++;
949                        }
950                }
951                // Offset var determines the size of the object array
952                byte[] NewObjects = new byte[Offset+unusedCount];
953                // Build the new Object array
954                int unusedOffset = 0;
955                for (int i=0;i<Offsets.length-1;++i)
956                {
957                        int start = NewOffsets[i];
958                        int end = NewOffsets[i+1];
959                        NewOffsets[i] = start+unusedOffset;
960                        // If start != End then the Object is used
961                        // So, we will copy the object data from the font file
962                        if (start != end)
963                        {
964                                // All offsets are Global Offsets relative to the beginning of the font file.
965                                // Jump the file pointer to the start address to read from.
966                                buf.seek(Offsets[i]);
967                                // Read from the buffer and write into the array at start.
968                buf.readFully(NewObjects, start+unusedOffset, end-start);
969                        } else {
970                                NewObjects[start+unusedOffset] = OperatorForUnusedEntries;
971                                unusedOffset++;
972                        }
973                }
974                NewOffsets[Offsets.length-1] += unusedOffset;
975                // Use AssembleIndex to build the index from the offset & object arrays
976                return AssembleIndex(NewOffsets,NewObjects);
977        }
978
979        /**
980         * Function creates the new index, inserting the count,offsetsize,offset array
981         * and object array.
982         * @param NewOffsets the subsetted offset array
983         * @param NewObjects the subsetted object array
984         * @return the new index created
985         */
986        protected byte[] AssembleIndex(int[] NewOffsets,byte[] NewObjects)
987        {
988                // Calc the index' count field
989                char Count = (char)(NewOffsets.length-1);
990                // Calc the size of the object array
991                int Size = NewOffsets[NewOffsets.length-1];
992                // Calc the Offsize
993                byte Offsize;
994        if (Size <= 0xff) Offsize = 1;
995        else if (Size <= 0xffff) Offsize = 2;
996        else if (Size <= 0xffffff) Offsize = 3;
997        else Offsize = 4;
998        // The byte array for the new index. The size is calc by
999        // Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array
1000        byte[] NewIndex = new byte[2+1+Offsize*(Count+1)+NewObjects.length];
1001        // The counter for writing
1002        int Place = 0;
1003        // Write the count field
1004        NewIndex[Place++] = (byte) (Count >>> 8 & 0xff);
1005        NewIndex[Place++] = (byte) (Count >>> 0 & 0xff);
1006        // Write the offsize field
1007        NewIndex[Place++] = Offsize;
1008        // Write the offset array according to the offsize
1009        for (int newOffset : NewOffsets) {
1010                // The value to be written
1011                int Num = newOffset-NewOffsets[0]+1;
1012                // Write in bytes according to the offsize
1013                switch (Offsize) {
1014                case 4:
1015                        NewIndex[Place++] = (byte) (Num >>> 24 & 0xff);
1016                case 3:
1017                        NewIndex[Place++] = (byte) (Num >>> 16 & 0xff);
1018                case 2:
1019                        NewIndex[Place++] = (byte) (Num >>>  8 & 0xff);
1020                case 1:
1021                        NewIndex[Place++] = (byte) (Num >>>  0 & 0xff);
1022                }
1023        }
1024        // Write the new object array one by one
1025        for (byte newObject : NewObjects) {
1026                NewIndex[Place++] = newObject;
1027        }
1028        // Return the new index
1029        return NewIndex;
1030        }
1031
1032        /**
1033         * The function builds the new output stream according to the subset process
1034         * @param Font the font
1035         * @return the subsetted font stream
1036         */
1037        protected byte[] BuildNewFile(int Font)
1038    {
1039                // Prepare linked list for new font components
1040                OutputList = new LinkedList<Item>();
1041
1042        // copy the header of the font
1043        CopyHeader();
1044
1045        // create a name index
1046        BuildIndexHeader(1,1,1);
1047        OutputList.addLast(new UInt8Item((char)( 1+fonts[Font].name.length() )));
1048        OutputList.addLast(new StringItem(fonts[Font].name));
1049
1050        // create the topdict Index
1051        BuildIndexHeader(1,2,1);
1052        OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
1053        OutputList.addLast(topdictIndex1Ref);
1054        IndexBaseItem topdictBase = new IndexBaseItem();
1055        OutputList.addLast(topdictBase);
1056
1057        // Initialize the Dict Items for later use
1058        OffsetItem charsetRef     = new DictOffsetItem();
1059        OffsetItem charstringsRef = new DictOffsetItem();
1060        OffsetItem fdarrayRef     = new DictOffsetItem();
1061        OffsetItem fdselectRef    = new DictOffsetItem();
1062        OffsetItem privateRef     = new DictOffsetItem();
1063
1064        // If the font is not CID create the following keys
1065        if ( !fonts[Font].isCID ) {
1066            // create a ROS key
1067                OutputList.addLast(new DictNumberItem(fonts[Font].nstrings));
1068                OutputList.addLast(new DictNumberItem(fonts[Font].nstrings+1));
1069                OutputList.addLast(new DictNumberItem(0));
1070                OutputList.addLast(new UInt8Item((char)12));
1071                OutputList.addLast(new UInt8Item((char)30));
1072            // create a CIDCount key
1073                OutputList.addLast(new DictNumberItem(fonts[Font].nglyphs));
1074                OutputList.addLast(new UInt8Item((char)12));
1075            OutputList.addLast(new UInt8Item((char)34));
1076            // Sivan's comments
1077            // What about UIDBase (12,35)? Don't know what is it.
1078            // I don't think we need FontName; the font I looked at didn't have it.
1079        }
1080        // Go to the TopDict of the font being processed
1081        seek(topdictOffsets[Font]);
1082        // Run until the end of the TopDict
1083        while (getPosition() < topdictOffsets[Font+1]) {
1084            int p1 = getPosition();
1085            getDictItem();
1086            int p2 = getPosition();
1087            // The encoding key is disregarded since CID has no encoding
1088            if (key=="Encoding"
1089            // These keys will be added manually by the process.
1090            || key=="Private"
1091            || key=="FDSelect"
1092            || key=="FDArray"
1093            || key=="charset"
1094            || key=="CharStrings"
1095            ) {
1096            }else {
1097            //OtherWise copy key "as is" to the output list
1098                OutputList.add(new RangeItem(buf,p1,p2-p1));
1099            }
1100        }
1101        // Create the FDArray, FDSelect, Charset and CharStrings Keys
1102        CreateKeys(fdarrayRef,fdselectRef,charsetRef,charstringsRef);
1103
1104        // Mark the end of the top dict area
1105        OutputList.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase));
1106
1107        // Copy the string index
1108
1109        if (fonts[Font].isCID)
1110            OutputList.addLast(getEntireIndexRange(stringIndexOffset));
1111        // If the font is not CID we need to append new strings.
1112        // We need 3 more strings: Registry, Ordering, and a FontName for one FD.
1113        // The total length is at most "Adobe"+"Identity"+63 = 76
1114        else
1115                CreateNewStringIndex(Font);
1116
1117        // copy the new subsetted global subroutine index
1118        OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewGSubrsIndex),0,NewGSubrsIndex.length));
1119
1120        // deal with fdarray, fdselect, and the font descriptors
1121        // If the font is CID:
1122        if (fonts[Font].isCID) {
1123            // copy the FDArray, FDSelect, charset
1124
1125            // Copy FDSelect
1126                // Mark the beginning
1127            OutputList.addLast(new MarkerItem(fdselectRef));
1128            // If an FDSelect exists copy it
1129            if (fonts[Font].fdselectOffset>=0)
1130                        OutputList.addLast(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength));
1131            // Else create a new one
1132            else
1133                CreateFDSelect(fdselectRef,fonts[Font].nglyphs);
1134
1135                // Copy the Charset
1136            // Mark the beginning and copy entirely
1137            OutputList.addLast(new MarkerItem(charsetRef));
1138            OutputList.addLast(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength));
1139
1140            // Copy the FDArray
1141            // If an FDArray exists
1142            if (fonts[Font].fdarrayOffset>=0)
1143            {
1144                // Mark the beginning
1145                    OutputList.addLast(new MarkerItem(fdarrayRef));
1146                    // Build a new FDArray with its private dicts and their LSubrs
1147                    Reconstruct(Font);
1148            }
1149            else
1150                // Else create a new one
1151                CreateFDArray(fdarrayRef,privateRef,Font);
1152
1153        }
1154        // If the font is not CID
1155        else
1156        {
1157            // create FDSelect
1158                CreateFDSelect(fdselectRef,fonts[Font].nglyphs);
1159            // recreate a new charset
1160                CreateCharset(charsetRef,fonts[Font].nglyphs);
1161            // create a font dict index (fdarray)
1162                CreateFDArray(fdarrayRef,privateRef,Font);
1163        }
1164
1165        // if a private dict exists insert its subsetted version
1166        if (fonts[Font].privateOffset>=0)
1167        {
1168                // Mark the beginning of the private dict
1169                IndexBaseItem PrivateBase = new IndexBaseItem();
1170                OutputList.addLast(PrivateBase);
1171                OutputList.addLast(new MarkerItem(privateRef));
1172
1173                OffsetItem Subr = new DictOffsetItem();
1174                // Build and copy the new private dict
1175                CreateNonCIDPrivate(Font,Subr);
1176                // Copy the new LSubrs index
1177                CreateNonCIDSubrs(Font,PrivateBase,Subr);
1178        }
1179
1180        // copy the charstring index
1181        OutputList.addLast(new MarkerItem(charstringsRef));
1182
1183        // Add the subsetted charstring
1184        OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.length));
1185
1186        // now create the new CFF font
1187        int[] currentOffset = new int[1];
1188        currentOffset[0] = 0;
1189        // Count and save the offset for each item
1190        Iterator<Item> listIter = OutputList.iterator();
1191        while ( listIter.hasNext() ) {
1192            Item item = listIter.next();
1193            item.increment(currentOffset);
1194        }
1195        // Compute the Xref for each of the offset items
1196        listIter = OutputList.iterator();
1197        while ( listIter.hasNext() ) {
1198            Item item = listIter.next();
1199            item.xref();
1200        }
1201
1202        int size = currentOffset[0];
1203        byte[] b = new byte[size];
1204
1205        // Emit all the items into the new byte array
1206        listIter = OutputList.iterator();
1207        while ( listIter.hasNext() ) {
1208            Item item = listIter.next();
1209            item.emit(b);
1210        }
1211        // Return the new stream
1212        return b;
1213    }
1214
1215        /**
1216         * Function Copies the header from the original fileto the output list
1217         */
1218        protected void CopyHeader()
1219        {
1220                seek(0);
1221        int major = getCard8();
1222        int minor = getCard8();
1223        int hdrSize = getCard8();
1224        int offSize = getCard8();
1225        nextIndexOffset = hdrSize;
1226        OutputList.addLast(new RangeItem(buf,0,hdrSize));
1227        }
1228
1229        /**
1230         * Function Build the header of an index
1231         * @param Count the count field of the index
1232         * @param Offsize the offsize field of the index
1233         * @param First the first offset of the index
1234         */
1235        protected void BuildIndexHeader(int Count,int Offsize,int First)
1236        {
1237                // Add the count field
1238                OutputList.addLast(new UInt16Item((char)Count)); // count
1239                // Add the offsize field
1240                OutputList.addLast(new UInt8Item((char)Offsize)); // offSize
1241                // Add the first offset according to the offsize
1242        switch(Offsize){
1243                case 1:
1244                        OutputList.addLast(new UInt8Item((char)First)); // first offset
1245                        break;
1246                case 2:
1247                        OutputList.addLast(new UInt16Item((char)First)); // first offset
1248                        break;
1249                case 3:
1250                        OutputList.addLast(new UInt24Item((char)First)); // first offset
1251                        break;
1252                case 4:
1253                        OutputList.addLast(new UInt32Item((char)First)); // first offset
1254                        break;
1255                default:
1256                        break;
1257        }
1258        }
1259
1260        /**
1261         * Function adds the keys into the TopDict
1262         * @param fdarrayRef OffsetItem for the FDArray
1263         * @param fdselectRef OffsetItem for the FDSelect
1264         * @param charsetRef OffsetItem for the CharSet
1265         * @param charstringsRef OffsetItem for the CharString
1266         */
1267        protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef)
1268        {
1269            // create an FDArray key
1270        OutputList.addLast(fdarrayRef);
1271        OutputList.addLast(new UInt8Item((char)12));
1272        OutputList.addLast(new UInt8Item((char)36));
1273        // create an FDSelect key
1274        OutputList.addLast(fdselectRef);
1275        OutputList.addLast(new UInt8Item((char)12));
1276        OutputList.addLast(new UInt8Item((char)37));
1277        // create an charset key
1278        OutputList.addLast(charsetRef);
1279        OutputList.addLast(new UInt8Item((char)15));
1280        // create a CharStrings key
1281        OutputList.addLast(charstringsRef);
1282        OutputList.addLast(new UInt8Item((char)17));
1283        }
1284
1285        /**
1286         * Function takes the original string item and adds the new strings
1287         * to accommodate the CID rules
1288         * @param Font the font
1289         */
1290        protected void CreateNewStringIndex(int Font)
1291        {
1292        String fdFontName = fonts[Font].name+"-OneRange";
1293        if (fdFontName.length() > 127)
1294            fdFontName = fdFontName.substring(0,127);
1295        String extraStrings = "Adobe"+"Identity"+fdFontName;
1296
1297        int origStringsLen = stringOffsets[stringOffsets.length-1]
1298        - stringOffsets[0];
1299        int stringsBaseOffset = stringOffsets[0]-1;
1300
1301        byte stringsIndexOffSize;
1302        if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1;
1303        else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2;
1304        else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3;
1305        else stringsIndexOffSize = 4;
1306
1307        OutputList.addLast(new UInt16Item((char)(stringOffsets.length-1+3))); // count
1308        OutputList.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize
1309        for (int stringOffset : stringOffsets)
1310            OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
1311            stringOffset-stringsBaseOffset));
1312        int currentStringsOffset = stringOffsets[stringOffsets.length-1]
1313        - stringsBaseOffset;
1314        //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1315        currentStringsOffset += "Adobe".length();
1316        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1317        currentStringsOffset += "Identity".length();
1318        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1319        currentStringsOffset += fdFontName.length();
1320        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1321
1322        OutputList.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen));
1323        OutputList.addLast(new StringItem(extraStrings));
1324    }
1325
1326        /**
1327         * Function creates new FDSelect for non-CID fonts.
1328         * The FDSelect built uses a single range for all glyphs
1329         * @param fdselectRef OffsetItem for the FDSelect
1330         * @param nglyphs the number of glyphs in the font
1331         */
1332        protected void CreateFDSelect(OffsetItem fdselectRef,int nglyphs)
1333        {
1334                OutputList.addLast(new MarkerItem(fdselectRef));
1335            OutputList.addLast(new UInt8Item((char)3)); // format identifier
1336            OutputList.addLast(new UInt16Item((char)1)); // nRanges
1337
1338            OutputList.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph
1339            OutputList.addLast(new UInt8Item((char)0)); // Range[0].fd
1340
1341            OutputList.addLast(new UInt16Item((char)nglyphs)); // sentinel
1342        }
1343
1344        /**
1345         * Function creates new CharSet for non-CID fonts.
1346         * The CharSet built uses a single range for all glyphs
1347         * @param charsetRef OffsetItem for the CharSet
1348         * @param nglyphs the number of glyphs in the font
1349         */
1350        protected void CreateCharset(OffsetItem charsetRef,int nglyphs)
1351        {
1352                OutputList.addLast(new MarkerItem(charsetRef));
1353            OutputList.addLast(new UInt8Item((char)2)); // format identifier
1354            OutputList.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef)
1355            OutputList.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft
1356        }
1357
1358        /**
1359         * Function creates new FDArray for non-CID fonts.
1360         * The FDArray built has only the "Private" operator that points to the font's
1361         * original private dict
1362         * @param fdarrayRef OffsetItem for the FDArray
1363         * @param privateRef OffsetItem for the Private Dict
1364         * @param Font the font
1365         */
1366        protected void CreateFDArray(OffsetItem fdarrayRef,OffsetItem privateRef,int Font)
1367        {
1368                OutputList.addLast(new MarkerItem(fdarrayRef));
1369                // Build the header (count=offsize=first=1)
1370                BuildIndexHeader(1,1,1);
1371
1372                // Mark
1373            OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
1374            OutputList.addLast(privateIndex1Ref);
1375            IndexBaseItem privateBase = new IndexBaseItem();
1376            // Insert the private operands and operator
1377            OutputList.addLast(privateBase);
1378            // Calc the new size of the private after subsetting
1379            // Origianl size
1380            int NewSize = fonts[Font].privateLength;
1381            // Calc the original size of the Subr offset in the private
1382                int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].privateOffset,fonts[Font].privateLength);
1383                // Increase the ptivate's size
1384                if (OrgSubrsOffsetSize != 0)
1385                        NewSize += 5-OrgSubrsOffsetSize;
1386            OutputList.addLast(new DictNumberItem(NewSize));
1387            OutputList.addLast(privateRef);
1388            OutputList.addLast(new UInt8Item((char)18)); // Private
1389
1390            OutputList.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase));
1391        }
1392
1393        /**
1394         * Function reconstructs the FDArray, PrivateDict and LSubr for CID fonts
1395         * @param Font the font
1396         */
1397        void Reconstruct(int Font)
1398        {
1399                // Init for later use
1400                OffsetItem[] fdPrivate = new DictOffsetItem[fonts[Font].FDArrayOffsets.length-1];
1401                IndexBaseItem[] fdPrivateBase = new IndexBaseItem[fonts[Font].fdprivateOffsets.length];
1402                OffsetItem[] fdSubrs = new DictOffsetItem[fonts[Font].fdprivateOffsets.length];
1403                // Reconstruct each type
1404                ReconstructFDArray(Font,fdPrivate);
1405                ReconstructPrivateDict(Font,fdPrivate,fdPrivateBase,fdSubrs);
1406                ReconstructPrivateSubrs(Font,fdPrivateBase,fdSubrs);
1407        }
1408
1409        /**
1410         * Function subsets the FDArray and builds the new one with new offsets
1411         * @param Font The font
1412         * @param fdPrivate OffsetItem Array (one for each FDArray)
1413         */
1414        void ReconstructFDArray(int Font,OffsetItem[] fdPrivate)
1415        {
1416                // Build the header of the index
1417                BuildIndexHeader(fonts[Font].FDArrayCount,fonts[Font].FDArrayOffsize,1);
1418
1419                // For each offset create an Offset Item
1420                OffsetItem[] fdOffsets = new IndexOffsetItem[fonts[Font].FDArrayOffsets.length-1];
1421                for (int i=0;i<fonts[Font].FDArrayOffsets.length-1;i++)
1422                {
1423                        fdOffsets[i] = new IndexOffsetItem(fonts[Font].FDArrayOffsize);
1424                        OutputList.addLast(fdOffsets[i]);
1425                }
1426
1427                // Declare beginning of the object array
1428                IndexBaseItem fdArrayBase = new IndexBaseItem();
1429            OutputList.addLast(fdArrayBase);
1430
1431                // For each object check if that FD is used.
1432            // if is used build a new one by changing the private object
1433            // Else do nothing
1434            // At the end of each object mark its ending (Even if wasn't written)
1435                for (int k=0; k<fonts[Font].FDArrayOffsets.length-1; k++) {
1436//                      if (FDArrayUsed.contains(Integer.valueOf(k)))
1437//                      {
1438                                // Goto beginning of objects
1439                    seek(fonts[Font].FDArrayOffsets[k]);
1440                    while (getPosition() < fonts[Font].FDArrayOffsets[k+1])
1441                    {
1442                        int p1 = getPosition();
1443                        getDictItem();
1444                        int p2 = getPosition();
1445                        // If the dictItem is the "Private" then compute and copy length,
1446                        // use marker for offset and write operator number
1447                        if (key=="Private") {
1448                                // Save the original length of the private dict
1449                                int NewSize = ((Integer)args[0]).intValue();
1450                                // Save the size of the offset to the subrs in that private
1451                                int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].fdprivateOffsets[k],fonts[Font].fdprivateLengths[k]);
1452                                // Increase the private's length accordingly
1453                                if (OrgSubrsOffsetSize != 0)
1454                                        NewSize += 5-OrgSubrsOffsetSize;
1455                                // Insert the new size, OffsetItem and operator key number
1456                                OutputList.addLast(new DictNumberItem(NewSize));
1457                                fdPrivate[k] = new DictOffsetItem();
1458                                OutputList.addLast(fdPrivate[k]);
1459                            OutputList.addLast(new UInt8Item((char)18)); // Private
1460                            // Go back to place
1461                            seek(p2);
1462                        }
1463                        // Else copy the entire range
1464                        else  // other than private
1465                                OutputList.addLast(new RangeItem(buf,p1,p2-p1));
1466                    }
1467//                      }
1468            // Mark the ending of the object (even if wasn't written)
1469            OutputList.addLast(new IndexMarkerItem(fdOffsets[k],fdArrayBase));
1470        }
1471        }
1472        /**
1473         * Function Adds the new private dicts (only for the FDs used) to the list
1474         * @param Font the font
1475         * @param fdPrivate OffsetItem array one element for each private
1476         * @param fdPrivateBase IndexBaseItem array one element for each private
1477         * @param fdSubrs OffsetItem array one element for each private
1478         */
1479        void ReconstructPrivateDict(int Font,OffsetItem[] fdPrivate,IndexBaseItem[] fdPrivateBase,
1480                        OffsetItem[] fdSubrs)
1481        {
1482
1483                // For each fdarray private dict check if that FD is used.
1484            // if is used build a new one by changing the subrs offset
1485            // Else do nothing
1486                for (int i=0;i<fonts[Font].fdprivateOffsets.length;i++)
1487                {
1488//                      if (FDArrayUsed.contains(Integer.valueOf(i)))
1489//                      {
1490                                // Mark beginning
1491                        OutputList.addLast(new MarkerItem(fdPrivate[i]));
1492                        fdPrivateBase[i] = new IndexBaseItem();
1493                        OutputList.addLast(fdPrivateBase[i]);
1494                                // Goto beginning of objects
1495                    seek(fonts[Font].fdprivateOffsets[i]);
1496                    while (getPosition() < fonts[Font].fdprivateOffsets[i]+fonts[Font].fdprivateLengths[i])
1497                    {
1498                        int p1 = getPosition();
1499                        getDictItem();
1500                        int p2 = getPosition();
1501                        // If the dictItem is the "Subrs" then,
1502                        // use marker for offset and write operator number
1503                        if (key=="Subrs") {
1504                                fdSubrs[i] = new DictOffsetItem();
1505                                OutputList.addLast(fdSubrs[i]);
1506                            OutputList.addLast(new UInt8Item((char)19)); // Subrs
1507                        }
1508                        // Else copy the entire range
1509                        else
1510                                OutputList.addLast(new RangeItem(buf,p1,p2-p1));
1511                    }
1512//                      }
1513                }
1514        }
1515
1516        /**
1517         * Function Adds the new LSubrs dicts (only for the FDs used) to the list
1518         * @param Font  The index of the font
1519         * @param fdPrivateBase The IndexBaseItem array for the linked list
1520         * @param fdSubrs OffsetItem array for the linked list
1521         */
1522
1523        void ReconstructPrivateSubrs(int Font,IndexBaseItem[] fdPrivateBase,
1524                        OffsetItem[] fdSubrs)
1525        {
1526                // For each private dict
1527        for (int i=0;i<fonts[Font].fdprivateLengths.length;i++)
1528        {
1529                // If that private dict's Subrs are used insert the new LSubrs
1530                // computed earlier
1531                if (fdSubrs[i]!= null && fonts[Font].PrivateSubrsOffset[i] >= 0)
1532                {
1533                        OutputList.addLast(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i]));
1534                        OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].length));
1535                }
1536        }
1537    }
1538
1539        /**
1540         * Calculates how many byte it took to write the offset for the subrs in a specific
1541         * private dict.
1542         * @param Offset The Offset for the private dict
1543         * @param Size The size of the private dict
1544         * @return The size of the offset of the subrs in the private dict
1545         */
1546        int CalcSubrOffsetSize(int Offset,int Size)
1547        {
1548                // Set the size to 0
1549                int OffsetSize = 0;
1550                // Go to the beginning of the private dict
1551                seek(Offset);
1552                // Go until the end of the private dict
1553                while (getPosition() < Offset+Size)
1554        {
1555                int p1 = getPosition();
1556                getDictItem();
1557                int p2 = getPosition();
1558                // When reached to the subrs offset
1559                if (key=="Subrs") {
1560                        // The Offsize (minus the subrs key)
1561                        OffsetSize = p2-p1-1;
1562                }
1563                // All other keys are ignored
1564        }
1565                // return the size
1566                return OffsetSize;
1567        }
1568
1569        /**
1570         * Function computes the size of an index
1571         * @param indexOffset The offset for the computed index
1572         * @return The size of the index
1573         */
1574        protected int countEntireIndexRange(int indexOffset)
1575        {
1576                // Go to the beginning of the index
1577            seek(indexOffset);
1578            // Read the count field
1579            int count = getCard16();
1580            // If count==0 -> size=2
1581            if (count==0)
1582                return 2;
1583            else
1584            {
1585                // Read the offsize field
1586                int indexOffSize = getCard8();
1587                // Go to the last element of the offset array
1588                seek(indexOffset+2+1+count*indexOffSize);
1589                // The size of the object array is the value of the last element-1
1590                int size = getOffset(indexOffSize)-1;
1591                // Return the size of the entire index
1592                return 2+1+(count+1)*indexOffSize+size;
1593            }
1594        }
1595
1596        /**
1597         * The function creates a private dict for a font that was not CID
1598         * All the keys are copied as is except for the subrs key
1599         * @param Font the font
1600         * @param Subr The OffsetItem for the subrs of the private
1601         */
1602        void CreateNonCIDPrivate(int Font,OffsetItem Subr)
1603        {
1604                // Go to the beginning of the private dict and read until the end
1605                seek(fonts[Font].privateOffset);
1606        while (getPosition() < fonts[Font].privateOffset+fonts[Font].privateLength)
1607        {
1608                int p1 = getPosition();
1609                getDictItem();
1610                int p2 = getPosition();
1611                // If the dictItem is the "Subrs" then,
1612                // use marker for offset and write operator number
1613                if (key=="Subrs") {
1614                        OutputList.addLast(Subr);
1615                    OutputList.addLast(new UInt8Item((char)19)); // Subrs
1616                }
1617                // Else copy the entire range
1618                else
1619                        OutputList.addLast(new RangeItem(buf,p1,p2-p1));
1620        }
1621        }
1622
1623        /**
1624         * the function marks the beginning of the subrs index and adds the subsetted subrs
1625         * index to the output list.
1626         * @param Font the font
1627         * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs
1628         * @param Subrs OffsetItem for the subrs
1629         */
1630        void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs)
1631        {
1632                // Mark the beginning of the Subrs index
1633                OutputList.addLast(new SubrMarkerItem(Subrs,PrivateBase));
1634                // Put the subsetted new subrs index
1635        if (NewSubrsIndexNonCID != null) {
1636            OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.length));
1637        }
1638    }
1639}