pdfbox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From le...@apache.org
Subject svn commit: r907461 [1/3] - in /pdfbox/fontbox/trunk/src: main/java/org/apache/fontbox/cff/ main/java/org/apache/fontbox/cff/charset/ main/java/org/apache/fontbox/cff/encoding/ test/java/org/apache/fontbox/cff/
Date Sun, 07 Feb 2010 18:09:21 GMT
Author: lehmi
Date: Sun Feb  7 18:09:19 2010
New Revision: 907461

URL: http://svn.apache.org/viewvc?rev=907461&view=rev
Log:
PDFBOX-542: added support for Adobe CFF/Type2 fonts to FontBox. Patch by Villu Ruusmann (villu dot ruusmann at gmail dot com)

Added:
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/AFMFormatter.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFDataInput.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFFont.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFOperator.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFParser.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFStandardString.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringCommand.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringHandler.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/DataInput.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/DataOutput.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/Type1CharStringFormatter.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/Type1FontFormatter.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/Type1FontUtil.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/charset/
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/charset/CFFCharset.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/charset/CFFExpertCharset.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/charset/CFFExpertSubsetCharset.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/charset/CFFISOAdobeCharset.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/charset/package.html
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/encoding/
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/encoding/CFFEncoding.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/encoding/CFFExpertEncoding.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/encoding/CFFStandardEncoding.java
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/encoding/package.html
    pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/package.html
    pdfbox/fontbox/trunk/src/test/java/org/apache/fontbox/cff/
    pdfbox/fontbox/trunk/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
    pdfbox/fontbox/trunk/src/test/java/org/apache/fontbox/cff/Type1FontUtilTest.java

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/AFMFormatter.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/AFMFormatter.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/AFMFormatter.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/AFMFormatter.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.fontbox.cff.encoding.CFFEncoding;
+
+/**
+ * This class creates all needed AFM font metric data from a CFFFont ready to be read from a AFMPaser.
+ * 
+ * @author Villu Russmann
+ * @version $Revision$
+ */
+public class AFMFormatter
+{
+
+    private AFMFormatter()
+    {
+    }
+
+    /**
+     * Create font metric data for the given CFFFont.
+     * @param font the CFFFont
+     * @return the created font metric data
+     * @throws IOException if an error occurs during reading
+     */
+    public static byte[] format(CFFFont font) throws IOException
+    {
+        DataOutput output = new DataOutput();
+        printFont(font, output);
+        return output.getBytes();
+    }
+
+    private static void printFont(CFFFont font, DataOutput output)
+            throws IOException
+    {
+        printFontMetrics(font, output);
+    }
+
+    @SuppressWarnings(value = { "unchecked" })
+    private static void printFontMetrics(CFFFont font, DataOutput output)
+            throws IOException
+    {
+        output.println("StartFontMetrics 2.0");
+        output.println("FontName " + font.getName());
+        output.println("FullName " + font.getProperty("FullName"));
+        output.println("FamilyName " + font.getProperty("FamilyName"));
+        output.println("Weight " + font.getProperty("Weight"));
+        CFFEncoding encoding = font.getEncoding();
+        if (encoding.isFontSpecific())
+        {
+            output.println("EncodingScheme FontSpecific");
+        }
+        List<Number> fontBBox = (List<Number>) font.getProperty("FontBBox");
+        output.println("FontBBox " + fontBBox.get(0) + " " + fontBBox.get(1)
+                + " " + fontBBox.get(2) + " " + fontBBox.get(3));
+        printDirectionMetrics(font, output);
+        printCharMetrics(font, output);
+        output.println("EndFontMetrics");
+    }
+
+    private static void printDirectionMetrics(CFFFont font, DataOutput output)
+            throws IOException
+    {
+        output.println("UnderlinePosition "
+                + font.getProperty("UnderlinePosition"));
+        output.println("UnderlineThickness "
+                + font.getProperty("UnderlineThickness"));
+        output.println("ItalicAngle " + font.getProperty("ItalicAngle"));
+        output.println("IsFixedPitch " + font.getProperty("isFixedPitch"));
+    }
+
+    private static void printCharMetrics(CFFFont font, DataOutput output)
+            throws IOException
+    {
+        List<CharMetric> metrics;
+        try
+        {
+            metrics = renderFont(font);
+        } 
+        catch (IOException ioe)
+        {
+            return;
+        }
+        output.println("StartCharMetrics " + metrics.size());
+        Collections.sort(metrics);
+        for (CharMetric metric : metrics)
+        {
+            output.print("C " + metric.code + " ;");
+            output.print(" ");
+            output.print("WX " + metric.width + " ;");
+            output.print(" ");
+            output.print("N " + metric.name + " ;");
+            output.print(" ");
+            output.print("B " + (int) metric.bounds.getX() + " "
+                    + (int) metric.bounds.getY() + " "
+                    + (int) metric.bounds.getMaxX() + " "
+                    + (int) metric.bounds.getMaxY() + " ;");
+            output.println();
+        }
+        output.println("EndCharMetrics");
+    }
+
+    private static List<CharMetric> renderFont(CFFFont font) throws IOException
+    {
+        List<CharMetric> metrics = new ArrayList<CharMetric>();
+        CharStringRenderer renderer = font.createRenderer();
+        Collection<CFFFont.Mapping> mappings = font.getMappings();
+        for (CFFFont.Mapping mapping : mappings)
+        {
+            CharMetric metric = new CharMetric();
+            metric.code = mapping.getCode();
+            metric.name = mapping.getName();
+            renderer.render(mapping.toType1Sequence());
+            metric.width = renderer.getWidth();
+            metric.bounds = renderer.getBounds();
+            metrics.add(metric);
+        }
+        return metrics;
+    }
+
+    /**
+     * This class represents the metric of one single character. 
+     *
+     */
+    private static class CharMetric implements Comparable<CharMetric>
+    {
+        private int code;
+        private String name;
+        private int width;
+        private Rectangle2D bounds;
+
+        public int compareTo(CharMetric that)
+        {
+            return code - that.code;
+        }
+    }
+}
\ No newline at end of file

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFDataInput.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFDataInput.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFDataInput.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFDataInput.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+import java.io.IOException;
+
+/**
+ * This is specialized DataInput. It's used to parse a CFFFont.
+ * 
+ * @author Villu Russmann
+ * @version $Revision$
+ */
+public class CFFDataInput extends DataInput
+{
+
+    /**
+     * Constructor.
+     * @param buffer the buffer to be read 
+     */
+    public CFFDataInput(byte[] buffer)
+    {
+        super(buffer);
+    }
+
+    /**
+     * Read one single Card8 value from the buffer. 
+     * @return the card8 value
+     * @throws IOException if an error occurs during reading
+     */
+    public int readCard8() throws IOException
+    {
+        return readUnsignedByte();
+    }
+
+    /**
+     * Read one single Card16 value from the buffer.
+     * @return the card16 value
+     * @throws IOException if an error occurs during reading
+     */
+    public int readCard16() throws IOException
+    {
+        return readUnsignedShort();
+    }
+
+    /**
+     * Read the offset from the buffer.
+     * @param offSize the given offsize
+     * @return the offset
+     * @throws IOException if an error occurs during reading
+     */
+    public int readOffset(int offSize) throws IOException
+    {
+        int value = 0;
+        for (int i = 0; i < offSize; i++)
+        {
+            value = value << 8 | readUnsignedByte();
+        }
+        return value;
+    }
+
+    /**
+     * Read the offsize from the buffer.
+     * @return the offsize
+     * @throws IOException if an error occurs during reading
+     */
+    public int readOffSize() throws IOException
+    {
+        return readUnsignedByte();
+    }
+
+    /**
+     * Read a SID from the buffer.
+     * @return the SID
+     * @throws IOException if an error occurs during reading
+     */
+    public int readSID() throws IOException
+    {
+        return readUnsignedShort();
+    }
+}
\ No newline at end of file

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFFont.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFFont.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFFont.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFFont.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.fontbox.cff.charset.CFFCharset;
+import org.apache.fontbox.cff.encoding.CFFEncoding;
+
+/**
+ * This class represents a CFF/Type2 Font.
+ * 
+ * @author Villu Russmann
+ * @version $Revision$
+ */
+public class CFFFont
+{
+
+    private String fontname = null;
+    private Map<String, Object> topDict = new LinkedHashMap<String, Object>();
+    private Map<String, Object> privateDict = new LinkedHashMap<String, Object>();
+    private CFFEncoding fontEncoding = null;
+    private CFFCharset fontCharset = null;
+    private Map<String, byte[]> charStringsDict = new LinkedHashMap<String, byte[]>();
+
+    /**
+     * The name of the font.
+     * @return the name of the font
+     */
+    public String getName()
+    {
+        return fontname;
+    }
+
+    /**
+     * Sets the name of the font.
+     * @param name the name of the font
+     */
+    public void setName(String name)
+    {
+        fontname = name;
+    }
+
+    /**
+     * Returns the value for the given name from the dictionary.
+     * @param name the name of the value
+     * @return the value of the name if available
+     */
+    public Object getProperty(String name)
+    {
+        Object topDictValue = topDict.get(name);
+        if (topDictValue != null)
+        {
+            return topDictValue;
+        }
+        Object privateDictValue = privateDict.get(name);
+        if (privateDictValue != null)
+        {
+            return privateDictValue;
+        }
+        return null;
+    }
+
+    /**
+     * Adds the given key/value pair to the top dictionary. 
+     * @param name the given key
+     * @param value the given value
+     */
+    public void addValueToTopDict(String name, Object value)
+    {
+        if (value != null)
+        {
+            topDict.put(name, value);
+        }
+    }
+    /** 
+     * Returns the top dictionary.
+     * @return the dictionary
+     */
+    public Map<String, Object> getTopDict()
+    {
+        return topDict;
+    }
+
+    /**
+     * Adds the given key/value pair to the private dictionary. 
+     * @param name the given key
+     * @param value the given value
+     */
+    public void addValueToPrivateDict(String name, Object value)
+    {
+        if (value != null)
+        {
+            privateDict.put(name, value);
+        }
+    }
+    /** 
+     * Returns the private dictionary.
+     * @return the dictionary
+     */
+    public Map<String, Object> getPrivateDict()
+    {
+        return privateDict;
+    }
+
+    /**
+     * Get the mapping (code/SID/charname/bytes) for this font.
+     * @return mappings for codes < 256 and for codes > = 256
+     */
+    public Collection<Mapping> getMappings()
+    {
+        List<Mapping> mappings = new ArrayList<Mapping>();
+        Set<String> mappedNames = new HashSet<String>();
+        Iterator<Integer> codes = fontEncoding.getCodes();
+        while (codes.hasNext())
+        {
+            int code = codes.next();
+            int sid = fontEncoding.getSID(code);
+            String charName = fontCharset.getName(sid);
+            // Predefined encoding
+            if (charName == null)
+            {
+                continue;
+            }
+            byte[] bytes = charStringsDict.get(charName);
+            if (bytes == null)
+            {
+                continue;
+            }
+            Mapping mapping = new Mapping();
+            mapping.setCode(code);
+            mapping.setSID(sid);
+            mapping.setName(charName);
+            mapping.setBytes(bytes);
+            mappings.add(mapping);
+            mappedNames.add(charName);
+        }
+        // XXX
+        int code = 256;
+        for (CFFCharset.Entry entry : fontCharset.getEntries())
+        {
+            String name = entry.getName();
+            if (mappedNames.contains(name))
+            {
+                continue;
+            }
+            byte[] bytes = this.charStringsDict.get(name);
+            if (bytes == null)
+            {
+                continue;
+            }
+            Mapping mapping = new Mapping();
+            mapping.setCode(code++);
+            mapping.setSID(entry.getSID());
+            mapping.setName(name);
+            mapping.setBytes(bytes);
+
+            mappings.add(mapping);
+
+            mappedNames.add(name);
+        }
+        return mappings;
+    }
+
+    /**
+     * Returns the CFFEncoding of the font.
+     * @return the encoding
+     */
+    public CFFEncoding getEncoding()
+    {
+        return fontEncoding;
+    }
+
+    /**
+     * Sets the CFFEncoding of the font.
+     * @param encoding the given CFFEncoding
+     */
+    public void setEncoding(CFFEncoding encoding)
+    {
+        fontEncoding = encoding;
+    }
+
+    /**
+     * Returns the CFFCharset of the font.
+     * @return the charset
+     */
+    public CFFCharset getCharset()
+    {
+        return fontCharset;
+    }
+
+    /**
+     * Sets the CFFCharset of the font.
+     * @param charset the given CFFCharset
+     */
+    public void setCharset(CFFCharset charset)
+    {
+        fontCharset = charset;
+    }
+
+    /** 
+     * Returns the character strings dictionary.
+     * @return the dictionary
+     */
+    public Map<String, byte[]> getCharStringsDict()
+    {
+        return charStringsDict;
+    }
+
+    /**
+     * Creates a CharStringConverter for this font.
+     * @return the new CharStringConverter
+     */
+    public CharStringConverter createConverter()
+    {
+        Number defaultWidthX = (Number) getProperty("defaultWidthX");
+        Number nominalWidthX = (Number) getProperty("nominalWidthX");
+        return new CharStringConverter(defaultWidthX.intValue(), nominalWidthX
+                .intValue());
+    }
+
+    /**
+     * Creates a CharStringRenderer for this font.
+     * @return the new CharStringRenderer
+     */
+    public CharStringRenderer createRenderer()
+    {
+        return new CharStringRenderer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return getClass().getName() + "[name=" + fontname + ", topDict=" + topDict
+                + ", privateDict=" + privateDict + ", encoding=" + fontEncoding
+                + ", charset=" + fontCharset + ", charStringsDict="
+                + charStringsDict + "]";
+    }
+
+    /**
+     * This class is used for the font mapping.
+     *
+     */
+    public class Mapping
+    {
+        private int mappedCode;
+        private int mappedSID;
+        private String mappedName;
+        private byte[] mappedBytes;
+
+        /**
+         * Converts the mapping into a Type1-sequence.
+         * @return the Type1-sequence
+         * @throws IOException if an error occurs during reading
+         */
+        public List<Object> toType1Sequence() throws IOException
+        {
+            CharStringConverter converter = createConverter();
+            return converter.convert(toType2Sequence());
+        }
+
+        /**
+         * Converts the mapping into a Type2-sequence.
+         * @return the Type2-sequence
+         * @throws IOException if an error occurs during reading
+         */
+        public List<Object> toType2Sequence() throws IOException
+        {
+            Type2CharStringParser parser = new Type2CharStringParser();
+            return parser.parse(getBytes());
+        }
+
+        /**
+         * Gets the value for the code.
+         * @return the code
+         */
+        public int getCode()
+        {
+            return mappedCode;
+        }
+
+        private void setCode(int code)
+        {
+            mappedCode = code;
+        }
+
+        /**
+         * Gets the value for the SID.
+         * @return the SID
+         */
+        public int getSID()
+        {
+            return mappedSID;
+        }
+
+        private void setSID(int sid)
+        {
+            this.mappedSID = sid;
+        }
+
+        /**
+         * Gets the value for the name.
+         * @return the name
+         */
+        public String getName()
+        {
+            return mappedName;
+        }
+
+        private void setName(String name)
+        {
+            this.mappedName = name;
+        }
+
+        /**
+         * Gets the value for the bytes.
+         * @return the bytes
+         */
+        public byte[] getBytes()
+        {
+            return mappedBytes;
+        }
+
+        private void setBytes(byte[] bytes)
+        {
+            this.mappedBytes = bytes;
+        }
+    }
+}
\ No newline at end of file

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFOperator.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFOperator.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFOperator.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFOperator.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * This class represents a CFF operator.
+ * @author Villu Russmann
+ * @version $Revision: 1.0 $
+ */
+public class CFFOperator
+{
+
+    private Key operatorKey = null;
+    private String operatorName = null;
+
+    private CFFOperator(Key key, String name)
+    {
+        setKey(key);
+        setName(name);
+    }
+
+    /**
+     * The key of the operator.
+     * @return the key
+     */
+    public Key getKey()
+    {
+        return operatorKey;
+    }
+
+    private void setKey(Key key)
+    {
+        operatorKey = key;
+    }
+
+    /**
+     * The name of the operator.
+     * @return the name
+     */
+    public String getName()
+    {
+        return operatorName;
+    }
+
+    private void setName(String name)
+    {
+        operatorName = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode()
+    {
+        return getKey().hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object object)
+    {
+        if (object instanceof CFFOperator)
+        {
+            CFFOperator that = (CFFOperator) object;
+            return getKey().equals(that.getKey());
+        }
+        return false;
+    }
+
+    private static void register(Key key, String name)
+    {
+        CFFOperator operator = new CFFOperator(key, name);
+        keyMap.put(key, operator);
+        nameMap.put(name, operator);
+    }
+
+    /**
+     * Returns the operator corresponding to the given key.
+     * @param key the given key
+     * @return the corresponding operator
+     */
+    public static CFFOperator getOperator(Key key)
+    {
+        return keyMap.get(key);
+    }
+
+    /**
+     * Returns the operator corresponding to the given name.
+     * @param key the given name
+     * @return the corresponding operator
+     */
+    public static CFFOperator getOperator(String name)
+    {
+        return nameMap.get(name);
+    }
+
+    /**
+     * This class is a holder for a key value. It consists of one or two bytes.  
+     * @author Villu Russmann
+     */
+    public static class Key
+    {
+        private int[] value = null;
+
+        /**
+         * Constructor.
+         * @param b0 the one byte value
+         */
+        public Key(int b0)
+        {
+            this(new int[] { b0 });
+        }
+
+        /**
+         * Constructor.
+         * @param b0 the first byte of a two byte value
+         * @param b1 the second byte of a two byte value
+         */
+        public Key(int b0, int b1)
+        {
+            this(new int[] { b0, b1 });
+        }
+
+        private Key(int[] value)
+        {
+            setValue(value);
+        }
+
+        /**
+         * Returns the value of the key.
+         * @return the value
+         */
+        public int[] getValue()
+        {
+            return value;
+        }
+
+        private void setValue(int[] value)
+        {
+            this.value = value;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String toString()
+        {
+            return Arrays.toString(getValue());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public int hashCode()
+        {
+            return Arrays.hashCode(getValue());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean equals(Object object)
+        {
+            if (object instanceof Key)
+            {
+                Key that = (Key) object;
+                return Arrays.equals(getValue(), that.getValue());
+            }
+            return false;
+        }
+    }
+
+    private static Map<CFFOperator.Key, CFFOperator> keyMap = new LinkedHashMap<CFFOperator.Key, CFFOperator>();
+    private static Map<String, CFFOperator> nameMap = new LinkedHashMap<String, CFFOperator>();
+
+    static
+    {
+        // Top DICT
+        register(new Key(0), "version");
+        register(new Key(1), "Notice");
+        register(new Key(12, 0), "Copyright");
+        register(new Key(2), "FullName");
+        register(new Key(3), "FamilyName");
+        register(new Key(4), "Weight");
+        register(new Key(12, 1), "isFixedPitch");
+        register(new Key(12, 2), "ItalicAngle");
+        register(new Key(12, 3), "UnderlinePosition");
+        register(new Key(12, 4), "UnderlineThickness");
+        register(new Key(12, 5), "PaintType");
+        register(new Key(12, 6), "CharstringType");
+        register(new Key(12, 7), "FontMatrix");
+        register(new Key(13), "UniqueID");
+        register(new Key(5), "FontBBox");
+        register(new Key(12, 8), "StrokeWidth");
+        register(new Key(14), "XUID");
+        register(new Key(15), "charset");
+        register(new Key(16), "Encoding");
+        register(new Key(17), "CharStrings");
+        register(new Key(18), "Private");
+        register(new Key(12, 20), "SyntheticBase");
+        register(new Key(12, 21), "PostScript");
+        register(new Key(12, 22), "BaseFontName");
+        register(new Key(12, 23), "BaseFontBlend");
+        register(new Key(12, 30), "ROS");
+        register(new Key(12, 31), "CIDFontVersion");
+        register(new Key(12, 32), "CIDFontRevision");
+        register(new Key(12, 33), "CIDFontType");
+        register(new Key(12, 34), "CIDCount");
+        register(new Key(12, 35), "UIDBase");
+        register(new Key(12, 36), "FDArray");
+        register(new Key(12, 37), "FDSelect");
+        register(new Key(12, 38), "FontName");
+
+        // Private DICT
+        register(new Key(6), "BlueValues");
+        register(new Key(7), "OtherBlues");
+        register(new Key(8), "FamilyBlues");
+        register(new Key(9), "FamilyOtherBlues");
+        register(new Key(12, 9), "BlueScale");
+        register(new Key(12, 10), "BlueShift");
+        register(new Key(12, 11), "BlueFuzz");
+        register(new Key(10), "StdHW");
+        register(new Key(11), "StdVW");
+        register(new Key(12, 12), "StemSnapH");
+        register(new Key(12, 13), "StemSnapV");
+        register(new Key(12, 14), "ForceBold");
+        register(new Key(12, 15), "LanguageGroup");
+        register(new Key(12, 16), "ExpansionFactor");
+        register(new Key(12, 17), "initialRandomSeed");
+        register(new Key(19), "Subrs");
+        register(new Key(20), "defaultWidthX");
+        register(new Key(21), "nominalWidthX");
+    }
+}
\ No newline at end of file

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFParser.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFParser.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFParser.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,847 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.fontbox.cff.charset.CFFCharset;
+import org.apache.fontbox.cff.charset.CFFExpertCharset;
+import org.apache.fontbox.cff.charset.CFFExpertSubsetCharset;
+import org.apache.fontbox.cff.charset.CFFISOAdobeCharset;
+import org.apache.fontbox.cff.encoding.CFFEncoding;
+import org.apache.fontbox.cff.encoding.CFFExpertEncoding;
+import org.apache.fontbox.cff.encoding.CFFStandardEncoding;
+
+/**
+ * This class represents a parser for a CFF font. 
+ * @author Villu Russmann
+ * @version $Revision: 1.0 $
+ */
+public class CFFParser
+{
+
+    private CFFDataInput input = null;
+    private Header header = null;
+    private IndexData nameIndex = null;
+    private IndexData topDictIndex = null;
+    private IndexData stringIndex = null;
+    private IndexData globalSubrIndex = null;
+
+    /**
+     * Parsing CFF Font using a byte array as input.
+     * @param bytes the given byte array
+     * @return the parsed CFF fonts
+     * @throws IOException If there is an error reading from the stream
+     */
+    public List<CFFFont> parse(byte[] bytes) throws IOException
+    {
+        input = new CFFDataInput(bytes);
+        header = readHeader(input);
+        nameIndex = readIndexData(input);
+        topDictIndex = readIndexData(input);
+        stringIndex = readIndexData(input);
+        globalSubrIndex = readIndexData(input);
+
+        List<CFFFont> fonts = new ArrayList<CFFFont>();
+        for (int i = 0; i < nameIndex.count; i++)
+        {
+            CFFFont font = parseFont(i);
+            fonts.add(font);
+        }
+        return fonts;
+    }
+
+    private static Header readHeader(CFFDataInput input) throws IOException
+    {
+        Header header = new Header();
+        header.major = input.readCard8();
+        header.minor = input.readCard8();
+        header.hdrSize = input.readCard8();
+        header.offSize = input.readOffSize();
+        return header;
+    }
+
+    private static IndexData readIndexData(CFFDataInput input)
+            throws IOException
+    {
+        IndexData index = new IndexData();
+        index.count = input.readCard16();
+        if (index.count == 0)
+        {
+            return index;
+        }
+        index.offSize = input.readOffSize();
+        index.offset = new int[index.count + 1];
+        for (int i = 0; i < index.offset.length; i++)
+        {
+            index.offset[i] = input.readOffset(index.offSize);
+        }
+        index.data = new int[index.offset[index.offset.length - 1]
+                - index.offset[0]];
+        for (int i = 0; i < index.data.length; i++)
+        {
+            index.data[i] = input.readCard8();
+        }
+        return index;
+    }
+
+    private static DictData readDictData(CFFDataInput input) throws IOException
+    {
+        DictData dict = new DictData();
+        dict.entries = new ArrayList<DictData.Entry>();
+        while (input.hasRemaining())
+        {
+            DictData.Entry entry = readEntry(input);
+            dict.entries.add(entry);
+        }
+        return dict;
+    }
+
+    private static DictData.Entry readEntry(CFFDataInput input)
+            throws IOException
+    {
+        DictData.Entry entry = new DictData.Entry();
+        while (true)
+        {
+            int b0 = input.readUnsignedByte();
+
+            if (b0 >= 0 && b0 <= 21)
+            {
+                entry.operator = readOperator(input, b0);
+                break;
+            } 
+            else if (b0 == 28 || b0 == 29)
+            {
+                entry.operands.add(readIntegerNumber(input, b0));
+            } 
+            else if (b0 == 30)
+            {
+                entry.operands.add(readRealNumber(input, b0));
+            } 
+            else if (b0 >= 32 && b0 <= 254)
+            {
+                entry.operands.add(readIntegerNumber(input, b0));
+            } 
+            else
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+        return entry;
+    }
+
+    private static CFFOperator readOperator(CFFDataInput input, int b0)
+            throws IOException
+    {
+        CFFOperator.Key key = readOperatorKey(input, b0);
+        return CFFOperator.getOperator(key);
+    }
+
+    private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0)
+            throws IOException
+    {
+        if (b0 == 12)
+        {
+            int b1 = input.readUnsignedByte();
+            return new CFFOperator.Key(b0, b1);
+        }
+        return new CFFOperator.Key(b0);
+    }
+
+    private static Integer readIntegerNumber(CFFDataInput input, int b0)
+            throws IOException
+    {
+        if (b0 == 28)
+        {
+            int b1 = input.readUnsignedByte();
+            int b2 = input.readUnsignedByte();
+            return Integer.valueOf((short) (b1 << 8 | b2));
+        } 
+        else if (b0 == 29)
+        {
+            int b1 = input.readUnsignedByte();
+            int b2 = input.readUnsignedByte();
+            int b3 = input.readUnsignedByte();
+            int b4 = input.readUnsignedByte();
+            return Integer.valueOf(b1 << 24 | b2 << 16 | b3 << 8 | b4);
+        } 
+        else if (b0 >= 32 && b0 <= 246)
+        {
+            return Integer.valueOf(b0 - 139);
+        } 
+        else if (b0 >= 247 && b0 <= 250)
+        {
+            int b1 = input.readUnsignedByte();
+            return Integer.valueOf((b0 - 247) * 256 + b1 + 108);
+        } 
+        else if (b0 >= 251 && b0 <= 254)
+        {
+            int b1 = input.readUnsignedByte();
+            return Integer.valueOf(-(b0 - 251) * 256 - b1 - 108);
+        } 
+        else
+        {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private static Double readRealNumber(CFFDataInput input, int b0)
+            throws IOException
+    {
+        StringBuffer sb = new StringBuffer();
+        boolean done = false;
+        while (!done)
+        {
+            int b = input.readUnsignedByte();
+            int[] nibbles = { b / 16, b % 16 };
+            for (int nibble : nibbles)
+            {
+                switch (nibble)
+                {
+                case 0x0:
+                case 0x1:
+                case 0x2:
+                case 0x3:
+                case 0x4:
+                case 0x5:
+                case 0x6:
+                case 0x7:
+                case 0x8:
+                case 0x9:
+                    sb.append(nibble);
+                    break;
+                case 0xa:
+                    sb.append(".");
+                    break;
+                case 0xb:
+                    sb.append("E");
+                    break;
+                case 0xc:
+                    sb.append("E-");
+                    break;
+                case 0xd:
+                    break;
+                case 0xe:
+                    sb.append("-");
+                    break;
+                case 0xf:
+                    done = true;
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+                }
+            }
+        }
+        return Double.valueOf(sb.toString());
+    }
+
+    private CFFFont parseFont(int index) throws IOException
+    {
+        CFFFont font = new CFFFont();
+        DataInput nameInput = new DataInput(nameIndex.getBytes(index));
+        String name = nameInput.getString();
+        font.setName(name);
+        CFFDataInput topDictInput = new CFFDataInput(topDictIndex
+                .getBytes(index));
+        DictData topDict = readDictData(topDictInput);
+        DictData.Entry syntheticBaseEntry = topDict.getEntry("SyntheticBase");
+        if (syntheticBaseEntry != null)
+        {
+            throw new IOException("Synthetic Fonts are not supported");
+        }
+        DictData.Entry rosEntry = topDict.getEntry("ROS");
+        if (rosEntry != null)
+        {
+            throw new IOException("CID-keyed Fonts are not supported");
+        }
+        font.addValueToTopDict("version", getString(topDict,"version"));
+        font.addValueToTopDict("Notice", getString(topDict,"Notice"));
+        font.addValueToTopDict("Copyright", getString(topDict,"Copyright"));
+        font.addValueToTopDict("FullName", getString(topDict,"FullName"));
+        font.addValueToTopDict("FamilyName", getString(topDict,"FamilyName"));
+        font.addValueToTopDict("Weight", getString(topDict,"Weight"));
+        font.addValueToTopDict("isFixedPitch", getBoolean(topDict, "isFixedPitch", false));
+        font.addValueToTopDict("ItalicAngle", getNumber(topDict, "ItalicAngle", 0));
+        font.addValueToTopDict("UnderlinePosition", getNumber(topDict, "UnderlinePosition", -100));
+        font.addValueToTopDict("UnderlineThickness", getNumber(topDict, "UnderlineThickness", 50));
+        font.addValueToTopDict("PaintType", getNumber(topDict, "PaintType", 0));
+        font.addValueToTopDict("CharstringType", getNumber(topDict, "CharstringType", 2));
+        font.addValueToTopDict("FontMatrix", getArray(topDict, "FontMatrix", Arrays
+                .<Number> asList(Double.valueOf(0.001), Double.valueOf(0),
+                        Double.valueOf(0), Double.valueOf(0.001), Double
+                                .valueOf(0), Double.valueOf(0))));
+        font.addValueToTopDict("UniqueID", getNumber(topDict, "UniqueID", null));
+        font.addValueToTopDict("FontBBox", getArray(topDict, "FontBBox", Arrays
+                .<Number> asList(Integer.valueOf(0), Integer.valueOf(0),
+                        Integer.valueOf(0), Integer.valueOf(0))));
+        font.addValueToTopDict("StrokeWidth", getNumber(topDict, "StrokeWidth", 0));
+        font.addValueToTopDict("XUID", getArray(topDict, "XUID", null));
+        DictData.Entry charStringsEntry = topDict.getEntry("CharStrings");
+        int charStringsOffset = charStringsEntry.getNumber(0).intValue();
+        input.setPosition(charStringsOffset);
+        IndexData charStringsIndex = readIndexData(input);
+        DictData.Entry charsetEntry = topDict.getEntry("charset");
+        CFFCharset charset;
+        int charsetId = charsetEntry != null ? charsetEntry.getNumber(0)
+                .intValue() : 0;
+        if (charsetId == 0)
+        {
+            charset = CFFISOAdobeCharset.getInstance();
+        } 
+        else if (charsetId == 1)
+        {
+            charset = CFFExpertCharset.getInstance();
+        } 
+        else if (charsetId == 2)
+        {
+            charset = CFFExpertSubsetCharset.getInstance();
+        } 
+        else
+        {
+            input.setPosition(charsetId);
+            charset = readCharset(input, charStringsIndex.count);
+        }
+        font.setCharset(charset);
+        font.getCharStringsDict().put(".notdef", charStringsIndex.getBytes(0));
+        int[] gids = new int[charStringsIndex.count];
+        List<CFFCharset.Entry> glyphEntries = charset.getEntries();
+        for (int i = 0; i < glyphEntries.size(); i++)
+        {
+            CFFCharset.Entry glyphEntry = glyphEntries.get(i);
+            gids[i] = glyphEntry.getSID();
+            font.getCharStringsDict().put(glyphEntry.getName(), charStringsIndex.getBytes(i + 1));
+        }
+        DictData.Entry encodingEntry = topDict.getEntry("Encoding");
+        CFFEncoding encoding;
+        int encodingId = encodingEntry != null ? encodingEntry.getNumber(0)
+                .intValue() : 0;
+        if (encodingId == 0)
+        {
+            encoding = CFFStandardEncoding.getInstance();
+        } 
+        else if (encodingId == 1)
+        {
+            encoding = CFFExpertEncoding.getInstance();
+        } 
+        else
+        {
+            input.setPosition(encodingId);
+            encoding = readEncoding(input, gids);
+        }
+        font.setEncoding(encoding);
+        DictData.Entry privateEntry = topDict.getEntry("Private");
+        int privateOffset = privateEntry.getNumber(1).intValue();
+        input.setPosition(privateOffset);
+        int privateSize = privateEntry.getNumber(0).intValue();
+        CFFDataInput privateDictData = new CFFDataInput(input.readBytes(privateSize));
+        DictData privateDict = readDictData(privateDictData);
+        font.addValueToPrivateDict("BlueValues", getDelta(privateDict, "BlueValues", null));
+        font.addValueToPrivateDict("OtherBlues", getDelta(privateDict, "OtherBlues", null));
+        font.addValueToPrivateDict("FamilyBlues", getDelta(privateDict, "FamilyBlues", null));
+        font.addValueToPrivateDict("FamilyOtherBlues", getDelta(privateDict, "FamilyOtherBlues", null));
+        font.addValueToPrivateDict("BlueScale", getNumber(privateDict, "BlueScale", Double.valueOf(0.039625)));
+        font.addValueToPrivateDict("BlueShift", getNumber(privateDict, "BlueShift", Integer.valueOf(7)));
+        font.addValueToPrivateDict("BlueFuzz", getNumber(privateDict, "BlueFuzz", Integer.valueOf(1)));
+        font.addValueToPrivateDict("StdHW", getNumber(privateDict, "StdHW", null));
+        font.addValueToPrivateDict("StdVW", getNumber(privateDict, "StdVW", null));
+        font.addValueToPrivateDict("StemSnapH", getDelta(privateDict, "StemSnapH", null));
+        font.addValueToPrivateDict("StemSnapV", getDelta(privateDict, "StemSnapV", null));
+        font.addValueToPrivateDict("ForceBold", getBoolean(privateDict, "ForceBold", false));
+        font.addValueToPrivateDict("LanguageGroup", getNumber(privateDict, "LanguageGroup", Integer.valueOf(0)));
+        font.addValueToPrivateDict("ExpansionFactor", getNumber(privateDict, "ExpansionFactor", Double.valueOf(0.06)));
+        font.addValueToPrivateDict("initialRandomSeed", getNumber(privateDict, "initialRandomSeed", Integer.valueOf(0)));
+        font.addValueToPrivateDict("defaultWidthX", getNumber(privateDict, "defaultWidthX", Integer.valueOf(0)));
+        font.addValueToPrivateDict("nominalWidthX", getNumber(privateDict, "nominalWidthX", Integer.valueOf(0)));
+        return font;
+    }
+
+    private String readString(int index) throws IOException
+    {
+        if (index >= 0 && index <= 390)
+        {
+            return CFFStandardString.getName(index);
+        }
+        DataInput dataInput = new DataInput(stringIndex.getBytes(index - 391));
+        return dataInput.getString();
+    }
+
+    private String getString(DictData dict, String name) throws IOException
+    {
+        DictData.Entry entry = dict.getEntry(name);
+        return (entry != null ? readString(entry.getNumber(0).intValue()) : null);
+    }
+
+    private Boolean getBoolean(DictData dict, String name, boolean defaultValue) throws IOException
+    {
+        DictData.Entry entry = dict.getEntry(name);
+        return entry != null ? entry.getBoolean(0) : defaultValue;
+    }
+
+    private Number getNumber(DictData dict, String name, Number defaultValue) throws IOException
+    {
+        DictData.Entry entry = dict.getEntry(name);
+        return entry != null ? entry.getNumber(0) : defaultValue;
+    }
+
+    // TODO Where is the difference to getDelta??
+    private List<Number> getArray(DictData dict, String name, List<Number> defaultValue) throws IOException
+    {
+        DictData.Entry entry = dict.getEntry(name);
+        return entry != null ? entry.getArray() : defaultValue;
+    }
+
+    // TODO Where is the difference to getArray??
+    private List<Number> getDelta(DictData dict, String name, List<Number> defaultValue) throws IOException
+    {
+        DictData.Entry entry = dict.getEntry(name);
+        return entry != null ? entry.getArray() : defaultValue;
+    }
+
+    private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids)
+            throws IOException
+    {
+        int format = dataInput.readCard8();
+        int baseFormat = format & 0x7f;
+
+        if (baseFormat == 0)
+        {
+            return readFormat0Encoding(dataInput, format, gids);
+        } 
+        else if (baseFormat == 1)
+        {
+            return readFormat1Encoding(dataInput, format, gids);
+        } 
+        else
+        {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format,
+            int[] gids) throws IOException
+    {
+        Format0Encoding encoding = new Format0Encoding();
+        encoding.format = format;
+        encoding.nCodes = dataInput.readCard8();
+        encoding.code = new int[encoding.nCodes];
+        for (int i = 0; i < encoding.code.length; i++)
+        {
+            encoding.code[i] = dataInput.readCard8();
+            encoding.register(encoding.code[i], gids[i]);
+        }
+        if ((format & 0x80) != 0)
+        {
+            readSupplement(dataInput, encoding);
+        }
+        return encoding;
+    }
+
+    private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format,
+            int[] gids) throws IOException
+    {
+        Format1Encoding encoding = new Format1Encoding();
+        encoding.format = format;
+        encoding.nRanges = dataInput.readCard8();
+        int count = 0;
+        encoding.range = new Format1Encoding.Range1[encoding.nRanges];
+        for (int i = 0; i < encoding.range.length; i++)
+        {
+            Format1Encoding.Range1 range = new Format1Encoding.Range1();
+            range.first = dataInput.readCard8();
+            range.nLeft = dataInput.readCard8();
+            encoding.range[i] = range;
+            for (int j = 0; j < 1 + range.nLeft; j++)
+            {
+                encoding.register(range.first + j, gids[count + j]);
+            }
+            count += 1 + range.nLeft;
+        }
+        if ((format & 0x80) != 0)
+        {
+            readSupplement(dataInput, encoding);
+        }
+        return encoding;
+    }
+
+    private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding)
+            throws IOException
+    {
+        encoding.nSups = dataInput.readCard8();
+        encoding.supplement = new EmbeddedEncoding.Supplement[encoding.nSups];
+        for (int i = 0; i < encoding.supplement.length; i++)
+        {
+            EmbeddedEncoding.Supplement supplement = new EmbeddedEncoding.Supplement();
+            supplement.code = dataInput.readCard8();
+            supplement.glyph = dataInput.readSID();
+            encoding.supplement[i] = supplement;
+        }
+    }
+
+    private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs)
+            throws IOException
+    {
+        int format = dataInput.readCard8();
+        if (format == 0)
+        {
+            return readFormat0Charset(dataInput, format, nGlyphs);
+        } 
+        else if (format == 1)
+        {
+            return readFormat1Charset(dataInput, format, nGlyphs);
+        } 
+        else
+        {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format,
+            int nGlyphs) throws IOException
+    {
+        Format0Charset charset = new Format0Charset();
+        charset.format = format;
+        charset.glyph = new int[nGlyphs - 1];
+        for (int i = 0; i < charset.glyph.length; i++)
+        {
+            charset.glyph[i] = dataInput.readSID();
+            charset.register(charset.glyph[i], readString(charset.glyph[i]));
+        }
+        return charset;
+    }
+
+    private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format,
+            int nGlyphs) throws IOException
+    {
+        Format1Charset charset = new Format1Charset();
+        charset.format = format;
+        charset.range = new Format1Charset.Range1[0];
+        for (int i = 0; i < nGlyphs - 1;)
+        {
+            Format1Charset.Range1[] newRange = new Format1Charset.Range1[charset.range.length + 1];
+            System.arraycopy(charset.range, 0, newRange, 0,
+                    charset.range.length);
+            charset.range = newRange;
+            Format1Charset.Range1 range = new Format1Charset.Range1();
+            range.first = dataInput.readSID();
+            range.nLeft = dataInput.readCard8();
+            charset.range[charset.range.length - 1] = range;
+            for (int j = 0; j < 1 + range.nLeft; j++)
+            {
+                charset.register(range.first + j, readString(range.first + j));
+            }
+            i += 1 + range.nLeft;
+        }
+        return charset;
+    }
+
+    /**
+     * Inner class holding the header of a CFF font. 
+     */
+    private static class Header
+    {
+        private int major;
+        private int minor;
+        private int hdrSize;
+        private int offSize;
+
+        @Override
+        public String toString()
+        {
+            return getClass().getName() + "[major=" + major + ", minor="
+                    + minor + ", hdrSize=" + hdrSize + ", offSize=" + offSize
+                    + "]";
+        }
+    }
+
+    /**
+     * Inner class holding the IndexData of a CFF font. 
+     */
+    private static class IndexData
+    {
+        private int count;
+        private int offSize;
+        private int[] offset;
+        private int[] data;
+
+        public byte[] getBytes(int index)
+        {
+            int length = offset[index + 1] - offset[index];
+            byte[] bytes = new byte[length];
+            for (int i = 0; i < length; i++)
+            {
+                bytes[i] = (byte) data[offset[index] - 1 + i];
+            }
+            return bytes;
+        }
+
+        @Override
+        public String toString()
+        {
+            return getClass().getName() + "[count=" + count + ", offSize="
+                    + offSize + ", offset=" + Arrays.toString(offset)
+                    + ", data=" + Arrays.toString(data) + "]";
+        }
+    }
+
+    /**
+     * Inner class holding the DictData of a CFF font. 
+     */
+    private static class DictData
+    {
+
+        private List<Entry> entries = null;
+
+        public Entry getEntry(CFFOperator.Key key)
+        {
+            return getEntry(CFFOperator.getOperator(key));
+        }
+
+        public Entry getEntry(String name)
+        {
+            return getEntry(CFFOperator.getOperator(name));
+        }
+
+        private Entry getEntry(CFFOperator operator)
+        {
+            for (Entry entry : entries)
+            {
+                if (entry.operator.equals(operator))
+                {
+                    return entry;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc} 
+         */
+        public String toString()
+        {
+            return getClass().getName() + "[entries=" + entries + "]";
+        }
+
+        /**
+         * Inner class holding an operand of a CFF font. 
+         */
+        private static class Entry
+        {
+            private List<Number> operands = new ArrayList<Number>();
+            private CFFOperator operator = null;
+
+            public Number getNumber(int index)
+            {
+                return operands.get(index);
+            }
+
+            public Boolean getBoolean(int index)
+            {
+                Number operand = operands.get(index);
+                if (operand instanceof Integer)
+                {
+                    switch (operand.intValue())
+                    {
+                    case 0:
+                        return Boolean.FALSE;
+                    case 1:
+                        return Boolean.TRUE;
+                    default:
+                        break;
+                    }
+                }
+                throw new IllegalArgumentException();
+            }
+
+            // TODO unused??
+            public Integer getSID(int index)
+            {
+                Number operand = operands.get(index);
+                if (operand instanceof Integer)
+                {
+                    return (Integer) operand;
+                }
+                throw new IllegalArgumentException();
+            }
+
+            // TODO Where is the difference to getDelta??
+            public List<Number> getArray()
+            {
+                return operands;
+            }
+
+            // TODO Where is the difference to getArray??
+            public List<Number> getDelta()
+            {
+                return operands;
+            }
+
+            @Override
+            public String toString()
+            {
+                return getClass().getName() + "[operands=" + operands
+                        + ", operator=" + operator + "]";
+            }
+        }
+    }
+
+    /**
+     * Inner class representing an embedded CFF encoding. 
+     */
+    private abstract static class EmbeddedEncoding extends CFFEncoding
+    {
+
+        private int nSups;
+        private Supplement[] supplement;
+
+        @Override
+        public boolean isFontSpecific()
+        {
+            return true;
+        }
+
+        /**
+         * Inner class representing a supplement for an encoding. 
+         */
+        private static class Supplement
+        {
+            private int code;
+            private int glyph;
+
+            @Override
+            public String toString()
+            {
+                return getClass().getName() + "[code=" + code + ", glyph="
+                        + glyph + "]";
+            }
+        }
+    }
+
+    /**
+     * Inner class representing a Format0 encoding. 
+     */
+    private static class Format0Encoding extends EmbeddedEncoding
+    {
+        private int format;
+        private int nCodes;
+        private int[] code;
+
+        @Override
+        public String toString()
+        {
+            return getClass().getName() + "[format=" + format + ", nCodes="
+                    + nCodes + ", code=" + Arrays.toString(code)
+                    + ", supplement=" + Arrays.toString(super.supplement) + "]";
+        }
+    }
+
+    /**
+     * Inner class representing a Format1 encoding. 
+     */
+    private static class Format1Encoding extends EmbeddedEncoding
+    {
+        private int format;
+        private int nRanges;
+        private Range1[] range;
+
+        @Override
+        public String toString()
+        {
+            return getClass().getName() + "[format=" + format + ", nRanges="
+                    + nRanges + ", range=" + Arrays.toString(range)
+                    + ", supplement=" + Arrays.toString(super.supplement) + "]";
+        }
+
+        /**
+         * Inner class representing a range of an encoding. 
+         */
+        private static class Range1
+        {
+            private int first;
+            private int nLeft;
+
+            @Override
+            public String toString()
+            {
+                return getClass().getName() + "[first=" + first + ", nLeft="
+                        + nLeft + "]";
+            }
+        }
+    }
+
+    /**
+     * Inner class representing an embedded CFF charset. 
+     */
+    private abstract static class EmbeddedCharset extends CFFCharset
+    {
+        @Override
+        public boolean isFontSpecific()
+        {
+            return true;
+        }
+    }
+
+    /**
+     * Inner class representing a Format0 charset. 
+     */
+    private static class Format0Charset extends EmbeddedCharset
+    {
+        private int format;
+        private int[] glyph;
+
+        @Override
+        public String toString()
+        {
+            return getClass().getName() + "[format=" + format + ", glyph="
+                    + Arrays.toString(glyph) + "]";
+        }
+    }
+
+    /**
+     * Inner class representing a Format1 charset. 
+     */
+    private static class Format1Charset extends EmbeddedCharset
+    {
+        private int format;
+        private Range1[] range;
+
+        @Override
+        public String toString()
+        {
+            return getClass().getName() + "[format=" + format + ", range="
+                    + Arrays.toString(range) + "]";
+        }
+
+        /**
+         * Inner class representing a range of a charset. 
+         */
+        private static class Range1
+        {
+            private int first;
+            private int nLeft;
+
+            @Override
+            public String toString()
+            {
+                return getClass().getName() + "[first=" + first + ", nLeft="
+                        + nLeft + "]";
+            }
+        }
+    }
+}
\ No newline at end of file

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFStandardString.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFStandardString.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFStandardString.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CFFStandardString.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,435 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+/**
+ * This class represents a standard SID to String mapping.
+ * @author Villu Russmann
+ * @version $Revision: 1.0 $
+ */
+public class CFFStandardString 
+{
+
+    private CFFStandardString()
+    {
+    }
+
+    /**
+     * This will return the string mapped to the given SID. 
+     * @param sid the given SID
+     * @return the mapped string
+     */
+    public static String getName(int sid)
+    {
+        return SID2STR[sid];
+    }
+
+    private static final String[] SID2STR = 
+    {
+        ".notdef",
+        "space",
+        "exclam",
+        "quotedbl",
+        "numbersign",
+        "dollar",
+        "percent",
+        "ampersand",
+        "quoteright",
+        "parenleft",
+        "parenright",
+        "asterisk",
+        "plus",
+        "comma",
+        "hyphen",
+        "period",
+        "slash",
+        "zero",
+        "one",
+        "two",
+        "three",
+        "four",
+        "five",
+        "six",
+        "seven",
+        "eight",
+        "nine",
+        "colon",
+        "semicolon",
+        "less",
+        "equal",
+        "greater",
+        "question",
+        "at",
+        "A",
+        "B",
+        "C",
+        "D",
+        "E",
+        "F",
+        "G",
+        "H",
+        "I",
+        "J",
+        "K",
+        "L",
+        "M",
+        "N",
+        "O",
+        "P",
+        "Q",
+        "R",
+        "S",
+        "T",
+        "U",
+        "V",
+        "W",
+        "X",
+        "Y",
+        "Z",
+        "bracketleft",
+        "backslash",
+        "bracketright",
+        "asciicircum",
+        "underscore",
+        "quoteleft",
+        "a",
+        "b",
+        "c",
+        "d",
+        "e",
+        "f",
+        "g",
+        "h",
+        "i",
+        "j",
+        "k",
+        "l",
+        "m",
+        "n",
+        "o",
+        "p",
+        "q",
+        "r",
+        "s",
+        "t",
+        "u",
+        "v",
+        "w",
+        "x",
+        "y",
+        "z",
+        "braceleft",
+        "bar",
+        "braceright",
+        "asciitilde",
+        "exclamdown",
+        "cent",
+        "sterling",
+        "fraction",
+        "yen",
+        "florin",
+        "section",
+        "currency",
+        "quotesingle",
+        "quotedblleft",
+        "guillemotleft",
+        "guilsinglleft",
+        "guilsinglright",
+        "fi",
+        "fl",
+        "endash",
+        "dagger",
+        "daggerdbl",
+        "periodcentered",
+        "paragraph",
+        "bullet",
+        "quotesinglbase",
+        "quotedblbase",
+        "quotedblright",
+        "guillemotright",
+        "ellipsis",
+        "perthousand",
+        "questiondown",
+        "grave",
+        "acute",
+        "circumflex",
+        "tilde",
+        "macron",
+        "breve",
+        "dotaccent",
+        "dieresis",
+        "ring",
+        "cedilla",
+        "hungarumlaut",
+        "ogonek",
+        "caron",
+        "emdash",
+        "AE",
+        "ordfeminine",
+        "Lslash",
+        "Oslash",
+        "OE",
+        "ordmasculine",
+        "ae",
+        "dotlessi",
+        "lslash",
+        "oslash",
+        "oe",
+        "germandbls",
+        "onesuperior",
+        "logicalnot",
+        "mu",
+        "trademark",
+        "Eth",
+        "onehalf",
+        "plusminus",
+        "Thorn",
+        "onequarter",
+        "divide",
+        "brokenbar",
+        "degree",
+        "thorn",
+        "threequarters",
+        "twosuperior",
+        "registered",
+        "minus",
+        "eth",
+        "multiply",
+        "threesuperior",
+        "copyright",
+        "Aacute",
+        "Acircumflex",
+        "Adieresis",
+        "Agrave",
+        "Aring",
+        "Atilde",
+        "Ccedilla",
+        "Eacute",
+        "Ecircumflex",
+        "Edieresis",
+        "Egrave",
+        "Iacute",
+        "Icircumflex",
+        "Idieresis",
+        "Igrave",
+        "Ntilde",
+        "Oacute",
+        "Ocircumflex",
+        "Odieresis",
+        "Ograve",
+        "Otilde",
+        "Scaron",
+        "Uacute",
+        "Ucircumflex",
+        "Udieresis",
+        "Ugrave",
+        "Yacute",
+        "Ydieresis",
+        "Zcaron",
+        "aacute",
+        "acircumflex",
+        "adieresis",
+        "agrave",
+        "aring",
+        "atilde",
+        "ccedilla",
+        "eacute",
+        "ecircumflex",
+        "edieresis",
+        "egrave",
+        "iacute",
+        "icircumflex",
+        "idieresis",
+        "igrave",
+        "ntilde",
+        "oacute",
+        "ocircumflex",
+        "odieresis",
+        "ograve",
+        "otilde",
+        "scaron",
+        "uacute",
+        "ucircumflex",
+        "udieresis",
+        "ugrave",
+        "yacute",
+        "ydieresis",
+        "zcaron",
+        "exclamsmall",
+        "Hungarumlautsmall",
+        "dollaroldstyle",
+        "dollarsuperior",
+        "ampersandsmall",
+        "Acutesmall",
+        "parenleftsuperior",
+        "parenrightsuperior",
+        "twodotenleader",
+        "onedotenleader",
+        "zerooldstyle",
+        "oneoldstyle",
+        "twooldstyle",
+        "threeoldstyle",
+        "fouroldstyle",
+        "fiveoldstyle",
+        "sixoldstyle",
+        "sevenoldstyle",
+        "eightoldstyle",
+        "nineoldstyle",
+        "commasuperior",
+        "threequartersemdash",
+        "periodsuperior",
+        "questionsmall",
+        "asuperior",
+        "bsuperior",
+        "centsuperior",
+        "dsuperior",
+        "esuperior",
+        "isuperior",
+        "lsuperior",
+        "msuperior",
+        "nsuperior",
+        "osuperior",
+        "rsuperior",
+        "ssuperior",
+        "tsuperior",
+        "ff",
+        "ffi",
+        "ffl",
+        "parenleftinferior",
+        "parenrightinferior",
+        "Circumflexsmall",
+        "hyphensuperior",
+        "Gravesmall",
+        "Asmall",
+        "Bsmall",
+        "Csmall",
+        "Dsmall",
+        "Esmall",
+        "Fsmall",
+        "Gsmall",
+        "Hsmall",
+        "Ismall",
+        "Jsmall",
+        "Ksmall",
+        "Lsmall",
+        "Msmall",
+        "Nsmall",
+        "Osmall",
+        "Psmall",
+        "Qsmall",
+        "Rsmall",
+        "Ssmall",
+        "Tsmall",
+        "Usmall",
+        "Vsmall",
+        "Wsmall",
+        "Xsmall",
+        "Ysmall",
+        "Zsmall",
+        "colonmonetary",
+        "onefitted",
+        "rupiah",
+        "Tildesmall",
+        "exclamdownsmall",
+        "centoldstyle",
+        "Lslashsmall",
+        "Scaronsmall",
+        "Zcaronsmall",
+        "Dieresissmall",
+        "Brevesmall",
+        "Caronsmall",
+        "Dotaccentsmall",
+        "Macronsmall",
+        "figuredash",
+        "hypheninferior",
+        "Ogoneksmall",
+        "Ringsmall",
+        "Cedillasmall",
+        "questiondownsmall",
+        "oneeighth",
+        "threeeighths",
+        "fiveeighths",
+        "seveneighths",
+        "onethird",
+        "twothirds",
+        "zerosuperior",
+        "foursuperior",
+        "fivesuperior",
+        "sixsuperior",
+        "sevensuperior",
+        "eightsuperior",
+        "ninesuperior",
+        "zeroinferior",
+        "oneinferior",
+        "twoinferior",
+        "threeinferior",
+        "fourinferior",
+        "fiveinferior",
+        "sixinferior",
+        "seveninferior",
+        "eightinferior",
+        "nineinferior",
+        "centinferior",
+        "dollarinferior",
+        "periodinferior",
+        "commainferior",
+        "Agravesmall",
+        "Aacutesmall",
+        "Acircumflexsmall",
+        "Atildesmall",
+        "Adieresissmall",
+        "Aringsmall",
+        "AEsmall",
+        "Ccedillasmall",
+        "Egravesmall",
+        "Eacutesmall",
+        "Ecircumflexsmall",
+        "Edieresissmall",
+        "Igravesmall",
+        "Iacutesmall",
+        "Icircumflexsmall",
+        "Idieresissmall",
+        "Ethsmall",
+        "Ntildesmall",
+        "Ogravesmall",
+        "Oacutesmall",
+        "Ocircumflexsmall",
+        "Otildesmall",
+        "Odieresissmall",
+        "OEsmall",
+        "Oslashsmall",
+        "Ugravesmall",
+        "Uacutesmall",
+        "Ucircumflexsmall",
+        "Udieresissmall",
+        "Yacutesmall",
+        "Thornsmall",
+        "Ydieresissmall",
+        "001.000",
+        "001.001",
+        "001.002",
+        "001.003",
+        "Black",
+        "Bold",
+        "Book",
+        "Light",
+        "Medium",
+        "Regular",
+        "Roman",
+        "Semibold",
+    };
+}
\ No newline at end of file

Added: pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringCommand.java
URL: http://svn.apache.org/viewvc/pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringCommand.java?rev=907461&view=auto
==============================================================================
--- pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringCommand.java (added)
+++ pdfbox/fontbox/trunk/src/main/java/org/apache/fontbox/cff/CharStringCommand.java Sun Feb  7 18:09:19 2010
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.fontbox.cff;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * This class represents a CharStringCommand.
+ * 
+ * @author Villu Russmann
+ * @version $Revision$
+ */
+public class CharStringCommand
+{
+
+    private Key commandKey = null;
+
+    /**
+     * Constructor with one value.
+     * 
+     * @param b0 value
+     */
+    public CharStringCommand(int b0)
+    {
+        setKey(new Key(b0));
+    }
+
+    /**
+     * Constructor with two values.
+     * 
+     * @param b0 value1
+     * @param b1 value2
+     */
+    public CharStringCommand(int b0, int b1)
+    {
+        setKey(new Key(b0, b1));
+    }
+
+    /**
+     * Constructor with an array as values.
+     * 
+     * @param values array of values
+     */
+    public CharStringCommand(int[] values)
+    {
+        setKey(new Key(values));
+    }
+
+    /**
+     * The key of the CharStringCommand.
+     * @return the key
+     */
+    public Key getKey()
+    {
+        return commandKey;
+    }
+
+    private void setKey(Key key)
+    {
+        commandKey = key;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return getKey().toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode()
+    {
+        return getKey().hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object object)
+    {
+        if (object instanceof CharStringCommand)
+        {
+            CharStringCommand that = (CharStringCommand) object;
+            return getKey().equals(that.getKey());
+        }
+        return false;
+    }
+
+    /**
+     * A static class to hold one or more int values as key. 
+     */
+    public static class Key
+    {
+
+        private int[] keyValues = null;
+
+        /**
+         * Constructor with one value.
+         * 
+         * @param b0 value
+         */
+        public Key(int b0)
+        {
+            setValue(new int[] { b0 });
+        }
+
+        /**
+         * Constructor with two values.
+         * 
+         * @param b0 value1
+         * @param b1 value2
+         */
+        public Key(int b0, int b1)
+        {
+            setValue(new int[] { b0, b1 });
+        }
+
+        /**
+         * Constructor with an array as values.
+         * 
+         * @param values array of values
+         */
+        public Key(int[] values)
+        {
+            setValue(values);
+        }
+
+        /**
+         * Array the with the values.
+         * 
+         * @return array with the values
+         */
+        public int[] getValue()
+        {
+            return keyValues;
+        }
+
+        private void setValue(int[] value)
+        {
+            keyValues = value;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String toString()
+        {
+            return Arrays.toString(getValue());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public int hashCode()
+        {
+            if (keyValues[0] == 12)
+            {
+                if (keyValues.length > 1)
+                {
+                    return keyValues[0] ^ keyValues[1];
+                }
+            }
+            return keyValues[0];
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean equals(Object object)
+        {
+            if (object instanceof Key)
+            {
+                Key that = (Key) object;
+                if (keyValues[0] == 12 && that.keyValues[0] == 12)
+                {
+                    if (keyValues.length > 1 && that.keyValues.length > 1)
+                    {
+                        return keyValues[1] == that.keyValues[1];
+                    }
+
+                    return keyValues.length == that.keyValues.length;
+                }
+                return keyValues[0] == that.keyValues[0];
+            }
+            return false;
+        }
+    }
+
+    /**
+     * A map with the Type1 vocabulary.
+     */
+    public static final Map<Key, String> TYPE1_VOCABULARY;
+
+    static
+    {
+        Map<Key, String> map = new LinkedHashMap<Key, String>();
+        map.put(new Key(1), "hstem");
+        map.put(new Key(3), "vstem");
+        map.put(new Key(4), "vmoveto");
+        map.put(new Key(5), "rlineto");
+        map.put(new Key(6), "hlineto");
+        map.put(new Key(7), "vlineto");
+        map.put(new Key(8), "rrcurveto");
+        map.put(new Key(9), "closepath");
+        map.put(new Key(10), "callsubr");
+        map.put(new Key(11), "return");
+        map.put(new Key(12), "escape");
+        map.put(new Key(12, 0), "dotsection");
+        map.put(new Key(12, 1), "vstem3");
+        map.put(new Key(12, 2), "hstem3");
+        map.put(new Key(12, 6), "seac");
+        map.put(new Key(12, 7), "sbw");
+        map.put(new Key(12, 12), "div");
+        map.put(new Key(12, 16), "callothersubr");
+        map.put(new Key(12, 17), "pop");
+        map.put(new Key(12, 33), "setcurrentpoint");
+        map.put(new Key(13), "hsbw");
+        map.put(new Key(14), "endchar");
+        map.put(new Key(21), "rmoveto");
+        map.put(new Key(22), "hmoveto");
+        map.put(new Key(30), "vhcurveto");
+        map.put(new Key(31), "hvcurveto");
+
+        TYPE1_VOCABULARY = Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * A map with the Type2 vocabulary.
+     */
+    public static final Map<Key, String> TYPE2_VOCABULARY;
+
+    static
+    {
+        Map<Key, String> map = new LinkedHashMap<Key, String>();
+        map.put(new Key(1), "hstem");
+        map.put(new Key(3), "vstem");
+        map.put(new Key(4), "vmoveto");
+        map.put(new Key(5), "rlineto");
+        map.put(new Key(6), "hlineto");
+        map.put(new Key(7), "vlineto");
+        map.put(new Key(8), "rrcurveto");
+        map.put(new Key(10), "callsubr");
+        map.put(new Key(11), "return");
+        map.put(new Key(12), "escape");
+        map.put(new Key(12, 3), "and");
+        map.put(new Key(12, 4), "or");
+        map.put(new Key(12, 5), "not");
+        map.put(new Key(12, 9), "abs");
+        map.put(new Key(12, 10), "add");
+        map.put(new Key(12, 11), "sub");
+        map.put(new Key(12, 12), "div");
+        map.put(new Key(12, 14), "neg");
+        map.put(new Key(12, 15), "eq");
+        map.put(new Key(12, 18), "drop");
+        map.put(new Key(12, 20), "put");
+        map.put(new Key(12, 21), "get");
+        map.put(new Key(12, 22), "ifelse");
+        map.put(new Key(12, 23), "random");
+        map.put(new Key(12, 24), "mul");
+        map.put(new Key(12, 26), "sqrt");
+        map.put(new Key(12, 27), "dup");
+        map.put(new Key(12, 28), "exch");
+        map.put(new Key(12, 29), "index");
+        map.put(new Key(12, 30), "roll");
+        map.put(new Key(12, 34), "hflex");
+        map.put(new Key(12, 35), "flex");
+        map.put(new Key(12, 36), "hflex1");
+        map.put(new Key(12, 37), "flex1");
+        map.put(new Key(14), "endchar");
+        map.put(new Key(18), "hstemhm");
+        map.put(new Key(19), "hintmask");
+        map.put(new Key(20), "cntrmask");
+        map.put(new Key(21), "rmoveto");
+        map.put(new Key(22), "hmoveto");
+        map.put(new Key(23), "vstemhm");
+        map.put(new Key(24), "rcurveline");
+        map.put(new Key(25), "rlinecurve");
+        map.put(new Key(26), "vvcurveto");
+        map.put(new Key(27), "hhcurveto");
+        map.put(new Key(28), "shortint");
+        map.put(new Key(29), "callgsubr");
+        map.put(new Key(30), "vhcurveto");
+        map.put(new Key(31), "hvcurveto");
+
+        TYPE2_VOCABULARY = Collections.unmodifiableMap(map);
+    }
+}
\ No newline at end of file



Mime
View raw message