001/*
002 * $Id: CFFFont.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 */
044
045/*
046 * Comments by the original author, Sivan Toledo:
047 * I created this class in order to add to iText the ability to utilize
048 * OpenType fonts with CFF glyphs (these usually have an .otf extension).
049 * The CFF font within the CFF table of the OT font might be either a CID
050 * or a Type1 font. (CFF fonts may also contain multiple fonts; I do not
051 * know if this is allowed in an OT table). The PDF spec, however, only
052 * allow a CID font with an Identity-H or Identity-V encoding. Otherwise,
053 * you are limited to an 8-bit encoding.
054 * Adobe fonts come in both flavors. That is, the OTFs sometimes have
055 * a CID CFF inside (for Japanese fonts), and sometimes a Type1 CFF
056 * (virtually all the others, Latin/Greek/Cyrillic). So to easily use
057 * all the glyphs in the latter, without creating multiple 8-bit encoding,
058 * I wrote this class, whose main purpose is to convert a Type1 font inside
059 * a CFF container (which might include other fonts) into a CID CFF font
060 * that can be directly embeded in the PDF.
061 *
062 * Limitations of the current version:
063 * 1. It does not extract a single CID font from a CFF that contains that
064 *    particular CID along with other fonts. The Adobe Japanese OTF's that
065 *    I have only have one font in the CFF table, so these can be
066 *    embeded in the PDF as is.
067 * 2. It does not yet subset fonts.
068 * 3. It may or may not work on CFF fonts that are not within OTF's.
069 *    I didn't try that. In any case, that would probably only be
070 *    useful for subsetting CID fonts, not for CFF Type1 fonts (I don't
071 *    think there are any available.
072 * I plan to extend the class to support these three features at some
073 * future time.
074 */
075
076package com.itextpdf.text.pdf;
077
078import java.util.Iterator;
079import java.util.LinkedList;
080
081import com.itextpdf.text.ExceptionConverter;
082
083public class CFFFont {
084
085    static final String operatorNames[] = {
086        "version", "Notice", "FullName", "FamilyName",
087        "Weight", "FontBBox", "BlueValues", "OtherBlues",
088        "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW",
089        "UNKNOWN_12", "UniqueID", "XUID", "charset",
090        "Encoding", "CharStrings", "Private", "Subrs",
091        "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23",
092        "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27",
093        "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31",
094        "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition",
095        "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix",
096        "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz",
097        "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15",
098        "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed",
099        "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend",
100        "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27",
101        "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion",
102        "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase",
103        "FDArray", "FDSelect", "FontName"
104    };
105
106    static final String standardStrings[] = {
107        // Automatically generated from Appendix A of the CFF specification; do
108        // not edit. Size should be 391.
109        ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar",
110        "percent", "ampersand", "quoteright", "parenleft", "parenright",
111        "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
112        "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
113        "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C",
114        "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
115        "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
116        "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c",
117        "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
118        "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
119        "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen",
120        "florin", "section", "currency", "quotesingle", "quotedblleft",
121        "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash",
122        "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet",
123        "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright",
124        "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex",
125        "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla",
126        "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash",
127        "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe",
128        "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth",
129        "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar",
130        "degree", "thorn", "threequarters", "twosuperior", "registered", "minus",
131        "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex",
132        "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute",
133        "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
134        "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve",
135        "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave",
136        "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis",
137        "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex",
138        "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave",
139        "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde",
140        "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute",
141        "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall",
142        "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall",
143        "parenleftsuperior", "parenrightsuperior", "twodotenleader",
144        "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle",
145        "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle",
146        "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior",
147        "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
148        "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior",
149        "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior",
150        "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
151        "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
152        "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall",
153        "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall",
154        "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
155        "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary",
156        "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle",
157        "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall",
158        "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
159        "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
160        "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths",
161        "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior",
162        "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
163        "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
164        "threeinferior", "fourinferior", "fiveinferior", "sixinferior",
165        "seveninferior", "eightinferior", "nineinferior", "centinferior",
166        "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
167        "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
168        "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall",
169        "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall",
170        "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall",
171        "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
172        "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall",
173        "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall",
174        "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black",
175        "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
176    };
177
178    //private String[] strings;
179    public String getString(char sid) {
180        if (sid < standardStrings.length) return standardStrings[sid];
181        if (sid >= standardStrings.length+stringOffsets.length-1) return null;
182        int j = sid - standardStrings.length;
183        //java.lang.System.err.println("going for "+j);
184        int p = getPosition();
185        seek(stringOffsets[j]);
186        StringBuffer s = new StringBuffer();
187        for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) {
188            s.append(getCard8());
189        }
190        seek(p);
191        return s.toString();
192    }
193
194    char getCard8() {
195        try {
196            byte i = buf.readByte();
197            return (char)(i & 0xff);
198        }
199        catch (Exception e) {
200            throw new ExceptionConverter(e);
201        }
202    }
203
204    char getCard16() {
205        try {
206            return buf.readChar();
207        }
208        catch (Exception e) {
209            throw new ExceptionConverter(e);
210        }
211    }
212
213    int getOffset(int offSize) {
214        int offset = 0;
215        for (int i=0; i<offSize; i++) {
216            offset *= 256;
217            offset += getCard8();
218        }
219        return offset;
220    }
221
222    void seek(int offset) {
223        try {
224            buf.seek(offset);
225        }
226        catch (Exception e) {
227            throw new ExceptionConverter(e);
228        }
229    }
230
231    short getShort() {
232        try {
233            return buf.readShort();
234        }
235        catch (Exception e) {
236            throw new ExceptionConverter(e);
237        }
238    }
239
240    int getInt() {
241        try {
242            return buf.readInt();
243        }
244        catch (Exception e) {
245            throw new ExceptionConverter(e);
246        }
247    }
248
249    int getPosition() {
250        try {
251            return buf.getFilePointer();
252        }
253        catch (Exception e) {
254            throw new ExceptionConverter(e);
255        }
256    }
257    int nextIndexOffset;
258    // read the offsets in the next index
259    // data structure, convert to global
260    // offsets, and return them.
261    // Sets the nextIndexOffset.
262    int[] getIndex(int nextIndexOffset) {
263        int count, indexOffSize;
264
265        seek(nextIndexOffset);
266        count = getCard16();
267        int[] offsets = new int[count+1];
268
269        if (count==0) {
270            offsets[0] = -1;
271            nextIndexOffset += 2; // TODO death store to local var .. should this be this.nextIndexOffset ?
272            return offsets;
273        }
274
275        indexOffSize = getCard8();
276
277        for (int j=0; j<=count; j++) {
278                //nextIndexOffset = ofset to relative segment
279            offsets[j] = nextIndexOffset
280                        //2-> count in the index header. 1->offset size in index header
281            + 2+1
282                        //offset array size * offset size
283            + (count+1)*indexOffSize
284                        //???zero <-> one base
285            - 1
286                        // read object offset relative to object array base
287            + getOffset(indexOffSize);
288        }
289        //nextIndexOffset = offsets[count];
290        return offsets;
291    }
292
293    protected String   key;
294    protected Object[] args      = new Object[48];
295    protected int      arg_count = 0;
296
297    protected void getDictItem() {
298        for (int i=0; i<arg_count; i++) args[i]=null;
299        arg_count = 0;
300        key = null;
301        boolean gotKey = false;
302
303        while (!gotKey) {
304            char b0 = getCard8();
305            if (b0 == 29) {
306                int item = getInt();
307                args[arg_count] = Integer.valueOf(item);
308                arg_count++;
309                //System.err.println(item+" ");
310                continue;
311            }
312            if (b0 == 28) {
313                short item = getShort();
314                args[arg_count] = Integer.valueOf(item);
315                arg_count++;
316                //System.err.println(item+" ");
317                continue;
318            }
319            if (b0 >= 32 && b0 <= 246) {
320                byte item = (byte) (b0-139);
321                args[arg_count] = Integer.valueOf(item);
322                arg_count++;
323                //System.err.println(item+" ");
324                continue;
325            }
326            if (b0 >= 247 && b0 <= 250) {
327                char b1 = getCard8();
328                short item = (short) ((b0-247)*256+b1+108);
329                args[arg_count] = Integer.valueOf(item);
330                arg_count++;
331                //System.err.println(item+" ");
332                continue;
333            }
334            if (b0 >= 251 && b0 <= 254) {
335                char b1 = getCard8();
336                short item = (short) (-(b0-251)*256-b1-108);
337                args[arg_count] = Integer.valueOf(item);
338                arg_count++;
339                //System.err.println(item+" ");
340                continue;
341            }
342            if (b0 == 30) {
343                StringBuilder item = new StringBuilder("");
344                boolean done = false;
345                char buffer = 0;
346                byte avail = 0;
347                int  nibble = 0;
348                while (!done) {
349                    // get a nibble
350                    if (avail==0) { buffer = getCard8(); avail=2; }
351                    if (avail==1) { nibble = buffer / 16; avail--; }
352                    if (avail==2) { nibble = buffer % 16; avail--; }
353                    switch (nibble) {
354                        case 0xa: item.append(".") ; break;
355                        case 0xb: item.append("E") ; break;
356                        case 0xc: item.append("E-"); break;
357                        case 0xe: item.append("-") ; break;
358                        case 0xf: done=true   ; break;
359                        default:
360                            if (nibble >= 0 && nibble <= 9)
361                                item.append(String.valueOf(nibble));
362                            else {
363                                item.append("<NIBBLE ERROR: ").append(nibble).append('>');
364                                done = true;
365                            }
366                            break;
367                    }
368                }
369                args[arg_count] = item.toString();
370                arg_count++;
371                //System.err.println(" real=["+item+"]");
372                continue;
373            }
374            if (b0 <= 21) {
375                gotKey=true;
376                if (b0 != 12) key = operatorNames[b0];
377                else key = operatorNames[32 + getCard8()];
378                //for (int i=0; i<arg_count; i++)
379                //  System.err.print(args[i].toString()+" ");
380                //System.err.println(key+" ;");
381                continue;
382            }
383        }
384    }
385
386    /** List items for the linked list that builds the new CID font.
387     */
388
389    protected static abstract class Item {
390        protected int myOffset = -1;
391        /** remember the current offset and increment by item's size in bytes. */
392        public void increment(int[] currentOffset) {
393            myOffset = currentOffset[0];
394        }
395        /** Emit the byte stream for this item. */
396        public void emit(byte[] buffer) {}
397        /** Fix up cross references to this item (applies only to markers). */
398        public void xref() {}
399    }
400
401    protected static abstract class OffsetItem extends Item {
402        public int value;
403        /** set the value of an offset item that was initially unknown.
404         * It will be fixed up latex by a call to xref on some marker.
405         */
406        public void set(int offset) { this.value = offset; }
407    }
408
409
410    /** A range item.
411     */
412
413    protected static final class RangeItem extends Item {
414        public int offset, length;
415        private RandomAccessFileOrArray buf;
416        public RangeItem(RandomAccessFileOrArray buf, int offset, int length) {
417            this.offset = offset;
418            this.length = length;
419            this.buf = buf;
420        }
421        @Override
422        public void increment(int[] currentOffset) {
423            super.increment(currentOffset);
424            currentOffset[0] += length;
425        }
426        @Override
427        public void emit(byte[] buffer) {
428            //System.err.println("range emit offset "+offset+" size="+length);
429            try {
430                buf.seek(offset);
431                for (int i=myOffset; i<myOffset+length; i++)
432                    buffer[i] = buf.readByte();
433            }
434            catch (Exception e) {
435                throw new ExceptionConverter(e);
436            }
437            //System.err.println("finished range emit");
438        }
439    }
440
441    /** An index-offset item for the list.
442     * The size denotes the required size in the CFF. A positive
443     * value means that we need a specific size in bytes (for offset arrays)
444     * and a negative value means that this is a dict item that uses a
445     * variable-size representation.
446     */
447    static protected final class IndexOffsetItem extends OffsetItem {
448        public final int size;
449        public IndexOffsetItem(int size, int value) {this.size=size; this.value=value;}
450        public IndexOffsetItem(int size) {this.size=size; }
451
452        @Override
453        public void increment(int[] currentOffset) {
454            super.increment(currentOffset);
455            currentOffset[0] += size;
456        }
457        @Override
458        public void emit(byte[] buffer) {
459            int i=0;
460            switch (size) {
461                case 4:
462                    buffer[myOffset+i] = (byte) (value >>> 24 & 0xff);
463                    i++;
464                case 3:
465                    buffer[myOffset+i] = (byte) (value >>> 16 & 0xff);
466                    i++;
467                case 2:
468                    buffer[myOffset+i] = (byte) (value >>>  8 & 0xff);
469                    i++;
470                case 1:
471                    buffer[myOffset+i] = (byte) (value >>>  0 & 0xff);
472                    i++;
473            }
474            /*
475            int mask = 0xff;
476            for (int i=size-1; i>=0; i--) {
477                buffer[myOffset+i] = (byte) (value & mask);
478                mask <<= 8;
479            }
480             */
481        }
482    }
483
484    static protected final class IndexBaseItem extends Item {
485        public IndexBaseItem() {}
486    }
487
488    static protected final class IndexMarkerItem extends Item {
489        private OffsetItem offItem;
490        private IndexBaseItem indexBase;
491        public IndexMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) {
492            this.offItem   = offItem;
493            this.indexBase = indexBase;
494        }
495        @Override
496        public void xref() {
497            //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset);
498            offItem.set(this.myOffset-indexBase.myOffset+1);
499        }
500    }
501    /**
502     * TODO To change the template for this generated type comment go to
503     * Window - Preferences - Java - Code Generation - Code and Comments
504     */
505    static protected final class SubrMarkerItem extends Item {
506        private OffsetItem offItem;
507        private IndexBaseItem indexBase;
508        public SubrMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) {
509            this.offItem   = offItem;
510            this.indexBase = indexBase;
511        }
512        @Override
513        public void xref() {
514            //System.err.println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset);
515            offItem.set(this.myOffset-indexBase.myOffset);
516        }
517    }
518
519
520    /** an unknown offset in a dictionary for the list.
521     * We will fix up the offset later; for now, assume it's large.
522     */
523    static protected final class DictOffsetItem extends OffsetItem {
524        public final int size;
525        public DictOffsetItem() {this.size=5; }
526
527        @Override
528        public void increment(int[] currentOffset) {
529            super.increment(currentOffset);
530            currentOffset[0] += size;
531        }
532        // this is incomplete!
533        @Override
534        public void emit(byte[] buffer) {
535            if (size==5) {
536                buffer[myOffset]   = 29;
537                buffer[myOffset+1] = (byte) (value >>> 24 & 0xff);
538                buffer[myOffset+2] = (byte) (value >>> 16 & 0xff);
539                buffer[myOffset+3] = (byte) (value >>>  8 & 0xff);
540                buffer[myOffset+4] = (byte) (value >>>  0 & 0xff);
541            }
542        }
543    }
544
545        /** Card24 item.
546     */
547
548    static protected final class UInt24Item extends Item {
549        public int value;
550        public UInt24Item(int value) {this.value=value;}
551
552        @Override
553        public void increment(int[] currentOffset) {
554            super.increment(currentOffset);
555            currentOffset[0] += 3;
556        }
557        // this is incomplete!
558        @Override
559        public void emit(byte[] buffer) {
560                buffer[myOffset+0] = (byte) (value >>> 16 & 0xff);
561            buffer[myOffset+1] = (byte) (value >>> 8 & 0xff);
562            buffer[myOffset+2] = (byte) (value >>> 0 & 0xff);
563        }
564    }
565
566    /** Card32 item.
567     */
568
569    static protected final class UInt32Item extends Item {
570        public int value;
571        public UInt32Item(int value) {this.value=value;}
572
573        @Override
574        public void increment(int[] currentOffset) {
575            super.increment(currentOffset);
576            currentOffset[0] += 4;
577        }
578        // this is incomplete!
579        @Override
580        public void emit(byte[] buffer) {
581                buffer[myOffset+0] = (byte) (value >>> 24 & 0xff);
582                buffer[myOffset+1] = (byte) (value >>> 16 & 0xff);
583            buffer[myOffset+2] = (byte) (value >>> 8 & 0xff);
584            buffer[myOffset+3] = (byte) (value >>> 0 & 0xff);
585        }
586    }
587
588    /** A SID or Card16 item.
589     */
590
591    static protected final class UInt16Item extends Item {
592        public char value;
593        public UInt16Item(char value) {this.value=value;}
594
595        @Override
596        public void increment(int[] currentOffset) {
597            super.increment(currentOffset);
598            currentOffset[0] += 2;
599        }
600        // this is incomplete!
601        @Override
602        public void emit(byte[] buffer) {
603            buffer[myOffset+0] = (byte) (value >>> 8 & 0xff);
604            buffer[myOffset+1] = (byte) (value >>> 0 & 0xff);
605        }
606    }
607
608    /** A Card8 item.
609     */
610
611    static protected final class UInt8Item extends Item {
612        public char value;
613        public UInt8Item(char value) {this.value=value;}
614
615        @Override
616        public void increment(int[] currentOffset) {
617            super.increment(currentOffset);
618            currentOffset[0] += 1;
619        }
620        // this is incomplete!
621        @Override
622        public void emit(byte[] buffer) {
623            buffer[myOffset+0] = (byte) (value >>> 0 & 0xff);
624        }
625    }
626
627    static protected final class StringItem extends Item {
628        public String s;
629        public StringItem(String s) {this.s=s;}
630
631        @Override
632        public void increment(int[] currentOffset) {
633            super.increment(currentOffset);
634            currentOffset[0] += s.length();
635        }
636        @Override
637        public void emit(byte[] buffer) {
638            for (int i=0; i<s.length(); i++)
639                buffer[myOffset+i] = (byte) (s.charAt(i) & 0xff);
640        }
641    }
642
643
644    /** A dictionary number on the list.
645     * This implementation is inefficient: it doesn't use the variable-length
646     * representation.
647     */
648
649    static protected final class DictNumberItem extends Item {
650        public final int value;
651        public int size = 5;
652        public DictNumberItem(int value) {this.value=value;}
653        @Override
654        public void increment(int[] currentOffset) {
655            super.increment(currentOffset);
656            currentOffset[0] += size;
657        }
658        // this is incomplete!
659        @Override
660        public void emit(byte[] buffer) {
661            if (size==5) {
662                buffer[myOffset]   = 29;
663                buffer[myOffset+1] = (byte) (value >>> 24 & 0xff);
664                buffer[myOffset+2] = (byte) (value >>> 16 & 0xff);
665                buffer[myOffset+3] = (byte) (value >>>  8 & 0xff);
666                buffer[myOffset+4] = (byte) (value >>>  0 & 0xff);
667            }
668        }
669    }
670
671    /** An offset-marker item for the list.
672     * It is used to mark an offset and to set the offset list item.
673     */
674
675    static protected final class MarkerItem extends Item {
676        OffsetItem p;
677        public MarkerItem(OffsetItem pointerToMarker) {p=pointerToMarker;}
678        @Override
679        public void xref() {
680            p.set(this.myOffset);
681        }
682    }
683
684    /** a utility that creates a range item for an entire index
685     *
686     * @param indexOffset where the index is
687     * @return a range item representing the entire index
688     */
689
690    protected RangeItem getEntireIndexRange(int indexOffset) {
691        seek(indexOffset);
692        int count = getCard16();
693        if (count==0) {
694            return new RangeItem(buf,indexOffset,2);
695        } else {
696            int indexOffSize = getCard8();
697            seek(indexOffset+2+1+count*indexOffSize);
698            int size = getOffset(indexOffSize)-1;
699            return new RangeItem(buf,indexOffset,
700            2+1+(count+1)*indexOffSize+size);
701        }
702    }
703
704
705    /** get a single CID font. The PDF architecture (1.4)
706     * supports 16-bit strings only with CID CFF fonts, not
707     * in Type-1 CFF fonts, so we convert the font to CID if
708     * it is in the Type-1 format.
709     * Two other tasks that we need to do are to select
710     * only a single font from the CFF package (this again is
711     * a PDF restriction) and to subset the CharStrings glyph
712     * description.
713     */
714
715
716    public byte[] getCID(String fontName)
717    //throws java.io.FileNotFoundException
718    {
719        int j;
720        for (j=0; j<fonts.length; j++)
721            if (fontName.equals(fonts[j].name)) break;
722        if (j==fonts.length) return null;
723
724        LinkedList<Item> l = new LinkedList<Item>();
725
726        // copy the header
727
728        seek(0);
729
730        int major = getCard8();
731        int minor = getCard8();
732        int hdrSize = getCard8();
733        int offSize = getCard8();
734        nextIndexOffset = hdrSize;
735
736        l.addLast(new RangeItem(buf,0,hdrSize));
737
738        int nglyphs=-1, nstrings=-1;
739        if ( ! fonts[j].isCID ) {
740            // count the glyphs
741            seek(fonts[j].charstringsOffset);
742            nglyphs = getCard16();
743            seek(stringIndexOffset);
744            nstrings = getCard16()+standardStrings.length;
745            //System.err.println("number of glyphs = "+nglyphs);
746        }
747
748        // create a name index
749
750        l.addLast(new UInt16Item((char)1)); // count
751        l.addLast(new UInt8Item((char)1)); // offSize
752        l.addLast(new UInt8Item((char)1)); // first offset
753        l.addLast(new UInt8Item((char)( 1+fonts[j].name.length() )));
754        l.addLast(new StringItem(fonts[j].name));
755
756        // create the topdict Index
757
758
759        l.addLast(new UInt16Item((char)1)); // count
760        l.addLast(new UInt8Item((char)2)); // offSize
761        l.addLast(new UInt16Item((char)1)); // first offset
762        OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
763        l.addLast(topdictIndex1Ref);
764        IndexBaseItem topdictBase = new IndexBaseItem();
765        l.addLast(topdictBase);
766
767        /*
768        int maxTopdictLen = (topdictOffsets[j+1]-topdictOffsets[j])
769                            + 9*2 // at most 9 new keys
770                            + 8*5 // 8 new integer arguments
771                            + 3*2;// 3 new SID arguments
772         */
773
774        //int    topdictNext = 0;
775        //byte[] topdict = new byte[maxTopdictLen];
776
777        OffsetItem charsetRef     = new DictOffsetItem();
778        OffsetItem charstringsRef = new DictOffsetItem();
779        OffsetItem fdarrayRef     = new DictOffsetItem();
780        OffsetItem fdselectRef    = new DictOffsetItem();
781
782        if ( !fonts[j].isCID ) {
783            // create a ROS key
784            l.addLast(new DictNumberItem(nstrings));
785            l.addLast(new DictNumberItem(nstrings+1));
786            l.addLast(new DictNumberItem(0));
787            l.addLast(new UInt8Item((char)12));
788            l.addLast(new UInt8Item((char)30));
789            // create a CIDCount key
790            l.addLast(new DictNumberItem(nglyphs));
791            l.addLast(new UInt8Item((char)12));
792            l.addLast(new UInt8Item((char)34));
793            // What about UIDBase (12,35)? Don't know what is it.
794            // I don't think we need FontName; the font I looked at didn't have it.
795        }
796
797        // create an FDArray key
798        l.addLast(fdarrayRef);
799        l.addLast(new UInt8Item((char)12));
800        l.addLast(new UInt8Item((char)36));
801        // create an FDSelect key
802        l.addLast(fdselectRef);
803        l.addLast(new UInt8Item((char)12));
804        l.addLast(new UInt8Item((char)37));
805        // create an charset key
806        l.addLast(charsetRef);
807        l.addLast(new UInt8Item((char)15));
808        // create a CharStrings key
809        l.addLast(charstringsRef);
810        l.addLast(new UInt8Item((char)17));
811
812        seek(topdictOffsets[j]);
813        while (getPosition() < topdictOffsets[j+1]) {
814            int p1 = getPosition();
815            getDictItem();
816            int p2 = getPosition();
817            if (key=="Encoding"
818            || key=="Private"
819            || key=="FDSelect"
820            || key=="FDArray"
821            || key=="charset"
822            || key=="CharStrings"
823            ) {
824                // just drop them
825            } else {
826                l.add(new RangeItem(buf,p1,p2-p1));
827            }
828        }
829
830        l.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase));
831
832        // Copy the string index and append new strings.
833        // We need 3 more strings: Registry, Ordering, and a FontName for one FD.
834        // The total length is at most "Adobe"+"Identity"+63 = 76
835
836        if (fonts[j].isCID) {
837            l.addLast(getEntireIndexRange(stringIndexOffset));
838        } else {
839            String fdFontName = fonts[j].name+"-OneRange";
840            if (fdFontName.length() > 127)
841                fdFontName = fdFontName.substring(0,127);
842            String extraStrings = "Adobe"+"Identity"+fdFontName;
843
844            int origStringsLen = stringOffsets[stringOffsets.length-1]
845            - stringOffsets[0];
846            int stringsBaseOffset = stringOffsets[0]-1;
847
848            byte stringsIndexOffSize;
849            if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1;
850            else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2;
851            else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3;
852            else stringsIndexOffSize = 4;
853
854            l.addLast(new UInt16Item((char)(stringOffsets.length-1+3))); // count
855            l.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize
856            for (int stringOffset : stringOffsets)
857                l.addLast(new IndexOffsetItem(stringsIndexOffSize,
858                stringOffset-stringsBaseOffset));
859            int currentStringsOffset = stringOffsets[stringOffsets.length-1]
860            - stringsBaseOffset;
861            //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
862            currentStringsOffset += "Adobe".length();
863            l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
864            currentStringsOffset += "Identity".length();
865            l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
866            currentStringsOffset += fdFontName.length();
867            l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
868
869            l.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen));
870            l.addLast(new StringItem(extraStrings));
871        }
872
873        // copy the global subroutine index
874
875        l.addLast(getEntireIndexRange(gsubrIndexOffset));
876
877        // deal with fdarray, fdselect, and the font descriptors
878
879        if (fonts[j].isCID) {
880            // copy the FDArray, FDSelect, charset
881        } else {
882            // create FDSelect
883            l.addLast(new MarkerItem(fdselectRef));
884            l.addLast(new UInt8Item((char)3)); // format identifier
885            l.addLast(new UInt16Item((char)1)); // nRanges
886
887            l.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph
888            l.addLast(new UInt8Item((char)0)); // Range[0].fd
889
890            l.addLast(new UInt16Item((char)nglyphs)); // sentinel
891
892            // recreate a new charset
893            // This format is suitable only for fonts without subsetting
894
895            l.addLast(new MarkerItem(charsetRef));
896            l.addLast(new UInt8Item((char)2)); // format identifier
897
898            l.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef)
899            l.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft
900            // now all are covered, the data structure is complete.
901
902            // create a font dict index (fdarray)
903
904            l.addLast(new MarkerItem(fdarrayRef));
905            l.addLast(new UInt16Item((char)1));
906            l.addLast(new UInt8Item((char)1)); // offSize
907            l.addLast(new UInt8Item((char)1)); // first offset
908
909            OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
910            l.addLast(privateIndex1Ref);
911            IndexBaseItem privateBase = new IndexBaseItem();
912            l.addLast(privateBase);
913
914            // looking at the PS that acrobat generates from a PDF with
915            // a CFF opentype font embedded with an identity-H encoding,
916            // it seems that it does not need a FontName.
917            //l.addLast(new DictNumberItem((standardStrings.length+(stringOffsets.length-1)+2)));
918            //l.addLast(new UInt8Item((char)12));
919            //l.addLast(new UInt8Item((char)38)); // FontName
920
921            l.addLast(new DictNumberItem(fonts[j].privateLength));
922            OffsetItem privateRef = new DictOffsetItem();
923            l.addLast(privateRef);
924            l.addLast(new UInt8Item((char)18)); // Private
925
926            l.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase));
927
928            // copy the private index & local subroutines
929
930            l.addLast(new MarkerItem(privateRef));
931            // copy the private dict and the local subroutines.
932            // the length of the private dict seems to NOT include
933            // the local subroutines.
934            l.addLast(new RangeItem(buf,fonts[j].privateOffset,fonts[j].privateLength));
935            if (fonts[j].privateSubrs >= 0) {
936                //System.err.println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength);
937                l.addLast(getEntireIndexRange(fonts[j].privateSubrs));
938            }
939        }
940
941        // copy the charstring index
942
943        l.addLast(new MarkerItem(charstringsRef));
944        l.addLast(getEntireIndexRange(fonts[j].charstringsOffset));
945
946        // now create the new CFF font
947
948        int[] currentOffset = new int[1];
949        currentOffset[0] = 0;
950
951        Iterator<Item> listIter = l.iterator();
952        while ( listIter.hasNext() ) {
953            Item item = listIter.next();
954            item.increment(currentOffset);
955        }
956
957        listIter = l.iterator();
958        while ( listIter.hasNext() ) {
959            Item item = listIter.next();
960            item.xref();
961        }
962
963        int size = currentOffset[0];
964        byte[] b = new byte[size];
965
966        listIter = l.iterator();
967        while ( listIter.hasNext() ) {
968            Item item = listIter.next();
969            item.emit(b);
970        }
971
972        return b;
973    }
974
975
976    public boolean isCID(String fontName) {
977        int j;
978        for (j=0; j<fonts.length; j++)
979            if (fontName.equals(fonts[j].name)) return fonts[j].isCID;
980        return false;
981    }
982
983    public boolean exists(String fontName) {
984        int j;
985        for (j=0; j<fonts.length; j++)
986            if (fontName.equals(fonts[j].name)) return true;
987        return false;
988    }
989
990
991    public String[] getNames() {
992        String[] names = new String[ fonts.length ];
993        for (int i=0; i<fonts.length; i++)
994            names[i] = fonts[i].name;
995        return names;
996    }
997    /**
998     * A random Access File or an array
999     */
1000    protected RandomAccessFileOrArray buf;
1001    private int offSize;
1002
1003    protected int nameIndexOffset;
1004    protected int topdictIndexOffset;
1005    protected int stringIndexOffset;
1006    protected int gsubrIndexOffset;
1007    protected int[] nameOffsets;
1008    protected int[] topdictOffsets;
1009    protected int[] stringOffsets;
1010    protected int[] gsubrOffsets;
1011
1012    /**
1013     * TODO Changed from private to protected by Ygal&Oren
1014     */
1015    protected final class Font {
1016        public String    name;
1017        public String    fullName;
1018        public boolean   isCID = false;
1019        public int       privateOffset     = -1; // only if not CID
1020        public int       privateLength     = -1; // only if not CID
1021        public int       privateSubrs      = -1;
1022        public int       charstringsOffset = -1;
1023        public int       encodingOffset    = -1;
1024        public int       charsetOffset     = -1;
1025        public int       fdarrayOffset     = -1; // only if CID
1026        public int       fdselectOffset    = -1; // only if CID
1027        public int[]     fdprivateOffsets;
1028        public int[]     fdprivateLengths;
1029        public int[]     fdprivateSubrs;
1030
1031        // Added by Oren & Ygal
1032        public int nglyphs;
1033        public int nstrings;
1034        public int CharsetLength;
1035        public int[]    charstringsOffsets;
1036        public int[]    charset;
1037        public int[]    FDSelect;
1038        public int FDSelectLength;
1039        public int FDSelectFormat;
1040        public int              CharstringType = 2;
1041        public int FDArrayCount;
1042        public int FDArrayOffsize;
1043        public int[] FDArrayOffsets;
1044        public int[] PrivateSubrsOffset;
1045        public int[][] PrivateSubrsOffsetsArray;
1046        public int[]       SubrsOffsets;
1047    }
1048    // Changed from private to protected by Ygal&Oren
1049    protected Font[] fonts;
1050
1051    public CFFFont(RandomAccessFileOrArray inputbuffer) {
1052
1053        //System.err.println("CFF: nStdString = "+standardStrings.length);
1054        buf = inputbuffer;
1055        seek(0);
1056
1057        int major, minor;
1058        major = getCard8();
1059        minor = getCard8();
1060
1061        //System.err.println("CFF Major-Minor = "+major+"-"+minor);
1062
1063        int hdrSize = getCard8();
1064
1065        offSize = getCard8();
1066
1067        //System.err.println("offSize = "+offSize);
1068
1069        //int count, indexOffSize, indexOffset, nextOffset;
1070
1071        nameIndexOffset    = hdrSize;
1072        nameOffsets        = getIndex(nameIndexOffset);
1073        topdictIndexOffset = nameOffsets[nameOffsets.length-1];
1074        topdictOffsets     = getIndex(topdictIndexOffset);
1075        stringIndexOffset  = topdictOffsets[topdictOffsets.length-1];
1076        stringOffsets      = getIndex(stringIndexOffset);
1077        gsubrIndexOffset   = stringOffsets[stringOffsets.length-1];
1078        gsubrOffsets       = getIndex(gsubrIndexOffset);
1079
1080        fonts = new Font[nameOffsets.length-1];
1081
1082        // now get the name index
1083
1084        /*
1085        names             = new String[nfonts];
1086        privateOffset     = new int[nfonts];
1087        charsetOffset     = new int[nfonts];
1088        encodingOffset    = new int[nfonts];
1089        charstringsOffset = new int[nfonts];
1090        fdarrayOffset     = new int[nfonts];
1091        fdselectOffset    = new int[nfonts];
1092         */
1093
1094        for (int j=0; j<nameOffsets.length-1; j++) {
1095            fonts[j] = new Font();
1096            seek(nameOffsets[j]);
1097            fonts[j].name = "";
1098            for (int k=nameOffsets[j]; k<nameOffsets[j+1]; k++) {
1099                fonts[j].name += getCard8();
1100            }
1101            //System.err.println("name["+j+"]=<"+fonts[j].name+">");
1102        }
1103
1104        // string index
1105
1106        //strings = new String[stringOffsets.length-1];
1107        /*
1108        System.err.println("std strings = "+standardStrings.length);
1109        System.err.println("fnt strings = "+(stringOffsets.length-1));
1110        for (char j=0; j<standardStrings.length+(stringOffsets.length-1); j++) {
1111            //seek(stringOffsets[j]);
1112            //strings[j] = "";
1113            //for (int k=stringOffsets[j]; k<stringOffsets[j+1]; k++) {
1114            //  strings[j] += (char)getCard8();
1115            //}
1116            System.err.println("j="+(int)j+" <? "+(standardStrings.length+(stringOffsets.length-1)));
1117            System.err.println("strings["+(int)j+"]=<"+getString(j)+">");
1118        }
1119         */
1120
1121        // top dict
1122
1123        for (int j=0; j<topdictOffsets.length-1; j++) {
1124            seek(topdictOffsets[j]);
1125            while (getPosition() < topdictOffsets[j+1]) {
1126                getDictItem();
1127                if (key=="FullName") {
1128                    //System.err.println("getting fullname sid = "+((Integer)args[0]).intValue());
1129                    fonts[j].fullName = getString((char)((Integer)args[0]).intValue());
1130                    //System.err.println("got it");
1131                } else if (key=="ROS")
1132                    fonts[j].isCID = true;
1133                else if (key=="Private") {
1134                    fonts[j].privateLength  = ((Integer)args[0]).intValue();
1135                    fonts[j].privateOffset  = ((Integer)args[1]).intValue();
1136                }
1137                else if (key=="charset"){
1138                    fonts[j].charsetOffset = ((Integer)args[0]).intValue();
1139
1140                }
1141//                else if (key=="Encoding"){
1142//                    int encOffset = ((Integer)args[0]).intValue();
1143//                    if (encOffset > 0) {
1144//                        fonts[j].encodingOffset = encOffset;
1145//                        ReadEncoding(fonts[j].encodingOffset);
1146//                    }
1147//                }
1148                else if (key=="CharStrings") {
1149                    fonts[j].charstringsOffset = ((Integer)args[0]).intValue();
1150                    //System.err.println("charstrings "+fonts[j].charstringsOffset);
1151                    // Added by Oren & Ygal
1152                    int p = getPosition();
1153                    fonts[j].charstringsOffsets = getIndex(fonts[j].charstringsOffset);
1154                    seek(p);
1155                } else if (key=="FDArray")
1156                    fonts[j].fdarrayOffset = ((Integer)args[0]).intValue();
1157                else if (key=="FDSelect")
1158                    fonts[j].fdselectOffset = ((Integer)args[0]).intValue();
1159                else if (key=="CharstringType")
1160                        fonts[j].CharstringType = ((Integer)args[0]).intValue();
1161            }
1162
1163            // private dict
1164            if (fonts[j].privateOffset >= 0) {
1165                //System.err.println("PRIVATE::");
1166                seek(fonts[j].privateOffset);
1167                while (getPosition() < fonts[j].privateOffset+fonts[j].privateLength) {
1168                    getDictItem();
1169                    if (key=="Subrs")
1170                        //Add the private offset to the lsubrs since the offset is
1171                        // relative to the beginning of the PrivateDict
1172                        fonts[j].privateSubrs = ((Integer)args[0]).intValue()+fonts[j].privateOffset;
1173                }
1174            }
1175
1176            // fdarray index
1177            if (fonts[j].fdarrayOffset >= 0) {
1178                int[] fdarrayOffsets = getIndex(fonts[j].fdarrayOffset);
1179
1180                fonts[j].fdprivateOffsets = new int[fdarrayOffsets.length-1];
1181                fonts[j].fdprivateLengths = new int[fdarrayOffsets.length-1];
1182
1183                //System.err.println("FD Font::");
1184
1185                for (int k=0; k<fdarrayOffsets.length-1; k++) {
1186                    seek(fdarrayOffsets[k]);
1187                    while (getPosition() < fdarrayOffsets[k+1]) {
1188                        getDictItem();
1189                        if (key=="Private") {
1190                            fonts[j].fdprivateLengths[k]  = ((Integer)args[0]).intValue();
1191                            fonts[j].fdprivateOffsets[k]  = ((Integer)args[1]).intValue();
1192                        }
1193                    }
1194                }
1195            }
1196        }
1197        //System.err.println("CFF: done");
1198    }
1199
1200    // ADDED BY Oren & Ygal
1201
1202    void ReadEncoding(int nextIndexOffset){
1203        int format;
1204        seek(nextIndexOffset);
1205        format = getCard8();
1206    }
1207}