You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2015/03/16 21:26:03 UTC

svn commit: r1667121 - in /pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff: CharStringCommand.java Type1CharString.java Type1CharStringParser.java Type2CharString.java Type2CharStringParser.java

Author: tilman
Date: Mon Mar 16 20:26:02 2015
New Revision: 1667121

URL: http://svn.apache.org/r1667121
Log:
PDFBOX-2576: misc code cleanup, as suggested by Martin Schröder:
- move code out of unneded else
- add @Override where needed
- document an unused parameter
- make methods static

Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java?rev=1667121&r1=1667120&r2=1667121&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringCommand.java Mon Mar 16 20:26:02 2015
@@ -1,320 +1,317 @@
-/*
- * 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 Ruusmann
- */
-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}
-     */
-    @Override
-    public String toString()
-    {
-        String str = TYPE2_VOCABULARY.get(getKey());
-        if (str == null)
-        {
-            str = TYPE1_VOCABULARY.get(getKey());
-        }
-        if (str == null)
-        {
-            return getKey().toString() + '|';
-        }
-        else
-        {
-            return str + '|';
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode()
-    {
-        return getKey().hashCode();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    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}
-         */
-        @Override
-        public String toString()
-        {
-            return Arrays.toString(getValue());
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int hashCode()
-        {
-            if (keyValues[0] == 12 && keyValues.length > 1)
-            {
-                return keyValues[0] ^ keyValues[1];
-            }
-            return keyValues[0];
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        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);
-    }
-}
+/*
+ * 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 Ruusmann
+ */
+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}
+     */
+    @Override
+    public String toString()
+    {
+        String str = TYPE2_VOCABULARY.get(getKey());
+        if (str == null)
+        {
+            str = TYPE1_VOCABULARY.get(getKey());
+        }
+        if (str == null)
+        {
+            return getKey().toString() + '|';
+        }
+        return str + '|';
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        return getKey().hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    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}
+         */
+        @Override
+        public String toString()
+        {
+            return Arrays.toString(getValue());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int hashCode()
+        {
+            if (keyValues[0] == 12 && keyValues.length > 1)
+            {
+                return keyValues[0] ^ keyValues[1];
+            }
+            return keyValues[0];
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        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);
+    }
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java?rev=1667121&r1=1667120&r2=1667121&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java Mon Mar 16 20:26:02 2015
@@ -16,11 +16,6 @@
  */
 package org.apache.fontbox.cff;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.fontbox.encoding.StandardEncoding;
-import org.apache.fontbox.type1.Type1CharStringReader;
-
 import java.awt.Point;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
@@ -30,6 +25,11 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.encoding.StandardEncoding;
+import org.apache.fontbox.type1.Type1CharStringReader;
+
 /**
  * This class represents and renders a Type 1 CharString.
  *
@@ -138,6 +138,7 @@ public class Type1CharString
         leftSideBearing = new Point2D.Float(0, 0);
         width = 0;
         CharStringHandler handler = new CharStringHandler() {
+            @Override
             public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
             {
                 return Type1CharString.this.handleCommand(numbers, command);
@@ -411,6 +412,7 @@ public class Type1CharString
      * Standard Encoding Accented Character
      *
      * Makes an accented character from two other characters.
+     * @param asb 
      */
     private void seac(Number asb, Number adx, Number ady, Number bchar, Number achar)
     {
@@ -452,4 +454,4 @@ public class Type1CharString
     {
         return type1Sequence.toString().replace("|","\n").replace(",", " ");
     }
-}
\ No newline at end of file
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java?rev=1667121&r1=1667120&r2=1667121&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java Mon Mar 16 20:26:02 2015
@@ -1,235 +1,229 @@
-/*
- * 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 org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Stack;
-
-/**
- * This class represents a converter for a mapping into a Type 1 sequence.
- *
- * @see "Adobe Type 1 Font Format, Adobe Systems (1999)"
- *
- * @author Villu Ruusmann
- * @author John Hewson
- */
-public class Type1CharStringParser
-{
-    private static final Log LOG = LogFactory.getLog(Type1CharStringParser.class);
-
-    // 1-byte commands
-    static final int RETURN = 11;
-    static final int CALLSUBR = 10;
-
-    // 2-byte commands
-    static final int TWO_BYTE = 12;
-    static final int CALLOTHERSUBR = 16;
-    static final int POP = 17;
-
-    private final String fontName, glyphName;
-
-    /**
-     * Constructs a new Type1CharStringParser object.
-     *
-     * @param fontName font name
-     * @param glyphName glyph name
-     */
-    public Type1CharStringParser(String fontName, String glyphName)
-    {
-        this.fontName = fontName;
-        this.glyphName = glyphName;
-    }
-
-    /**
-     * The given byte array will be parsed and converted to a Type1 sequence.
-     *
-     * @param bytes the given mapping as byte array
-     * @param subrs list of local subroutines
-     * @return the Type1 sequence
-     * @throws IOException if an error occurs during reading
-     */
-    public List<Object> parse(byte[] bytes, List<byte[]> subrs) throws IOException
-    {
-        return parse(bytes, subrs, new ArrayList<Object>());
-    }
-
-    private List<Object> parse(byte[] bytes, List<byte[]> subrs, List<Object> sequence) throws IOException
-    {
-        DataInput input = new DataInput(bytes);
-        while (input.hasRemaining())
-        {
-            int b0 = input.readUnsignedByte();
-            if (b0 == CALLSUBR)
-            {
-                // callsubr command
-                Integer operand=(Integer)sequence.remove(sequence.size()-1);
-
-                if (operand < subrs.size())
-                {
-                    byte[] subrBytes = subrs.get(operand);
-                    parse(subrBytes, subrs, sequence);
-                    Object lastItem = sequence.get(sequence.size()-1);
-                    if (lastItem instanceof CharStringCommand &&
-                          ((CharStringCommand)lastItem).getKey().getValue()[0] == RETURN)
-                    {
-                        sequence.remove(sequence.size()-1); // remove "return" command
-                    }
-                }
-            }
-            else if (b0 == TWO_BYTE && input.peekUnsignedByte(0) == CALLOTHERSUBR)
-            {
-                // callothersubr command (needed in order to expand Subrs)
-                input.readByte();
-
-                Integer othersubrNum = (Integer)sequence.remove(sequence.size()-1);
-                Integer numArgs = (Integer)sequence.remove(sequence.size()-1);
-
-                // othersubrs 0-3 have their own semantics
-                Stack<Integer> results = new Stack<Integer>();
-                if (othersubrNum == 0)
-                {
-                    results.push(removeInteger(sequence));
-                    results.push(removeInteger(sequence));
-                    sequence.remove(sequence.size() - 1);
-                    // end flex
-                    sequence.add(0);
-                    sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
-                }
-                else if (othersubrNum == 1)
-                {
-                    // begin flex
-                    sequence.add(1);
-                    sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
-                }
-                else if (othersubrNum == 3)
-                {
-                    // allows hint replacement
-                    results.push(removeInteger(sequence));
-                }
-                else
-                {
-                    // all remaining othersubrs use this fallback mechanism
-                    for (int i = 0; i < numArgs; i++)
-                    {
-                        Integer arg = removeInteger(sequence);
-                        results.push(arg);
-                    }
-                }
-
-                // pop must follow immediately
-                while (input.peekUnsignedByte(0) == TWO_BYTE && input.peekUnsignedByte(1) == POP)
-                {
-                    input.readByte(); // B0_POP
-                    input.readByte(); // B1_POP
-                    Integer val = results.pop();
-                    sequence.add(val);
-                }
-
-                if (results.size() > 0)
-                {
-                    LOG.warn("Value left on the PostScript stack in glyph " + glyphName + " of font " + fontName);
-                }
-            }
-            else if (b0 >= 0 && b0 <= 31)
-            {
-                sequence.add(readCommand(input, b0));
-            } 
-            else if (b0 >= 32 && b0 <= 255)
-            {
-                sequence.add(readNumber(input, b0));
-            } 
-            else
-            {
-                throw new IllegalArgumentException();
-            }
-        }
-        return sequence;
-    }
-
-    // this method is a workaround for the fact that Type1CharStringParser assumes that subrs and
-    // othersubrs can be unrolled without executing the 'div' operator, which isn't true
-    private Integer removeInteger(List<Object> sequence) throws IOException
-    {
-        Object item = sequence.remove(sequence.size() - 1);
-        if (item instanceof Integer)
-        {
-            return (Integer)item;
-        }
-        else
-        {
-            CharStringCommand command = (CharStringCommand)item;
-
-            // div
-            if (command.getKey().getValue()[0] == 12 && command.getKey().getValue()[0] == 12)
-            {
-                int a = (Integer)sequence.remove(sequence.size() - 1);
-                int b = (Integer)sequence.remove(sequence.size() - 1);
-                return b / a;
-            }
-            else
-            {
-                throw new IOException("Unexpected char string command: " + command.getKey());
-            }
-        }
-    }
-
-    private CharStringCommand readCommand(DataInput input, int b0) throws IOException
-    {
-        if (b0 == 12)
-        {
-            int b1 = input.readUnsignedByte();
-            return new CharStringCommand(b0, b1);
-        }
-        return new CharStringCommand(b0);
-    }
-
-    private Integer readNumber(DataInput input, int b0) throws IOException
-    {
-        if (b0 >= 32 && b0 <= 246)
-        {
-            return b0 - 139;
-        } 
-        else if (b0 >= 247 && b0 <= 250)
-        {
-            int b1 = input.readUnsignedByte();
-            return (b0 - 247) * 256 + b1 + 108;
-        } 
-        else if (b0 >= 251 && b0 <= 254)
-        {
-            int b1 = input.readUnsignedByte();
-            return -(b0 - 251) * 256 - b1 - 108;
-        } 
-        else if (b0 == 255)
-        {
-            int b1 = input.readUnsignedByte();
-            int b2 = input.readUnsignedByte();
-            int b3 = input.readUnsignedByte();
-            int b4 = input.readUnsignedByte();
-
-            return b1 << 24 | b2 << 16 | b3 << 8 | b4;
-        } 
-        else
-        {
-            throw new IllegalArgumentException();
-        }
-    }
-}
+/*
+ * 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.List;
+import java.util.Stack;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class represents a converter for a mapping into a Type 1 sequence.
+ *
+ * @see "Adobe Type 1 Font Format, Adobe Systems (1999)"
+ *
+ * @author Villu Ruusmann
+ * @author John Hewson
+ */
+public class Type1CharStringParser
+{
+    private static final Log LOG = LogFactory.getLog(Type1CharStringParser.class);
+
+    // 1-byte commands
+    static final int RETURN = 11;
+    static final int CALLSUBR = 10;
+
+    // 2-byte commands
+    static final int TWO_BYTE = 12;
+    static final int CALLOTHERSUBR = 16;
+    static final int POP = 17;
+
+    private final String fontName, glyphName;
+
+    /**
+     * Constructs a new Type1CharStringParser object.
+     *
+     * @param fontName font name
+     * @param glyphName glyph name
+     */
+    public Type1CharStringParser(String fontName, String glyphName)
+    {
+        this.fontName = fontName;
+        this.glyphName = glyphName;
+    }
+
+    /**
+     * The given byte array will be parsed and converted to a Type1 sequence.
+     *
+     * @param bytes the given mapping as byte array
+     * @param subrs list of local subroutines
+     * @return the Type1 sequence
+     * @throws IOException if an error occurs during reading
+     */
+    public List<Object> parse(byte[] bytes, List<byte[]> subrs) throws IOException
+    {
+        return parse(bytes, subrs, new ArrayList<Object>());
+    }
+
+    private List<Object> parse(byte[] bytes, List<byte[]> subrs, List<Object> sequence) throws IOException
+    {
+        DataInput input = new DataInput(bytes);
+        while (input.hasRemaining())
+        {
+            int b0 = input.readUnsignedByte();
+            if (b0 == CALLSUBR)
+            {
+                // callsubr command
+                Integer operand=(Integer)sequence.remove(sequence.size()-1);
+
+                if (operand < subrs.size())
+                {
+                    byte[] subrBytes = subrs.get(operand);
+                    parse(subrBytes, subrs, sequence);
+                    Object lastItem = sequence.get(sequence.size()-1);
+                    if (lastItem instanceof CharStringCommand &&
+                          ((CharStringCommand)lastItem).getKey().getValue()[0] == RETURN)
+                    {
+                        sequence.remove(sequence.size()-1); // remove "return" command
+                    }
+                }
+            }
+            else if (b0 == TWO_BYTE && input.peekUnsignedByte(0) == CALLOTHERSUBR)
+            {
+                // callothersubr command (needed in order to expand Subrs)
+                input.readByte();
+
+                Integer othersubrNum = (Integer)sequence.remove(sequence.size()-1);
+                Integer numArgs = (Integer)sequence.remove(sequence.size()-1);
+
+                // othersubrs 0-3 have their own semantics
+                Stack<Integer> results = new Stack<Integer>();
+                if (othersubrNum == 0)
+                {
+                    results.push(removeInteger(sequence));
+                    results.push(removeInteger(sequence));
+                    sequence.remove(sequence.size() - 1);
+                    // end flex
+                    sequence.add(0);
+                    sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
+                }
+                else if (othersubrNum == 1)
+                {
+                    // begin flex
+                    sequence.add(1);
+                    sequence.add(new CharStringCommand(TWO_BYTE, CALLOTHERSUBR));
+                }
+                else if (othersubrNum == 3)
+                {
+                    // allows hint replacement
+                    results.push(removeInteger(sequence));
+                }
+                else
+                {
+                    // all remaining othersubrs use this fallback mechanism
+                    for (int i = 0; i < numArgs; i++)
+                    {
+                        Integer arg = removeInteger(sequence);
+                        results.push(arg);
+                    }
+                }
+
+                // pop must follow immediately
+                while (input.peekUnsignedByte(0) == TWO_BYTE && input.peekUnsignedByte(1) == POP)
+                {
+                    input.readByte(); // B0_POP
+                    input.readByte(); // B1_POP
+                    Integer val = results.pop();
+                    sequence.add(val);
+                }
+
+                if (results.size() > 0)
+                {
+                    LOG.warn("Value left on the PostScript stack in glyph " + glyphName + " of font " + fontName);
+                }
+            }
+            else if (b0 >= 0 && b0 <= 31)
+            {
+                sequence.add(readCommand(input, b0));
+            } 
+            else if (b0 >= 32 && b0 <= 255)
+            {
+                sequence.add(readNumber(input, b0));
+            } 
+            else
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+        return sequence;
+    }
+
+    // this method is a workaround for the fact that Type1CharStringParser assumes that subrs and
+    // othersubrs can be unrolled without executing the 'div' operator, which isn't true
+    private static Integer removeInteger(List<Object> sequence) throws IOException
+    {
+        Object item = sequence.remove(sequence.size() - 1);
+        if (item instanceof Integer)
+        {
+            return (Integer)item;
+        }
+        CharStringCommand command = (CharStringCommand) item;
+
+        // div
+        if (command.getKey().getValue()[0] == 12 && command.getKey().getValue()[0] == 12)
+        {
+            int a = (Integer) sequence.remove(sequence.size() - 1);
+            int b = (Integer) sequence.remove(sequence.size() - 1);
+            return b / a;
+        }
+        throw new IOException("Unexpected char string command: " + command.getKey());
+    }
+
+    private static CharStringCommand readCommand(DataInput input, int b0) throws IOException
+    {
+        if (b0 == 12)
+        {
+            int b1 = input.readUnsignedByte();
+            return new CharStringCommand(b0, b1);
+        }
+        return new CharStringCommand(b0);
+    }
+
+    private static Integer readNumber(DataInput input, int b0) throws IOException
+    {
+        if (b0 >= 32 && b0 <= 246)
+        {
+            return b0 - 139;
+        } 
+        else if (b0 >= 247 && b0 <= 250)
+        {
+            int b1 = input.readUnsignedByte();
+            return (b0 - 247) * 256 + b1 + 108;
+        } 
+        else if (b0 >= 251 && b0 <= 254)
+        {
+            int b1 = input.readUnsignedByte();
+            return -(b0 - 251) * 256 - b1 - 108;
+        } 
+        else if (b0 == 255)
+        {
+            int b1 = input.readUnsignedByte();
+            int b2 = input.readUnsignedByte();
+            int b3 = input.readUnsignedByte();
+            int b4 = input.readUnsignedByte();
+
+            return b1 << 24 | b2 << 16 | b3 << 8 | b4;
+        } 
+        else
+        {
+            throw new IllegalArgumentException();
+        }
+    }
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java?rev=1667121&r1=1667120&r2=1667121&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java Mon Mar 16 20:26:02 2015
@@ -16,13 +16,13 @@
  */
 package org.apache.fontbox.cff;
 
-import org.apache.fontbox.type1.Type1CharStringReader;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.fontbox.type1.Type1CharStringReader;
+
 /**
  * Represents a Type 2 CharString by converting it into an equivalent Type 1 CharString.
  * 
@@ -83,6 +83,7 @@ public class Type2CharString extends Typ
         type1Sequence = new ArrayList<Object>();
         pathCount = 0;
         CharStringHandler handler = new CharStringHandler() {
+            @Override
             public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command)
             {
                 return Type2CharString.this.handleCommand(numbers, command);
@@ -269,6 +270,10 @@ public class Type2CharString extends Typ
         return numbers;
     }
 
+    /**
+     * @param numbers  
+     * @param horizontal 
+     */
     private void expandStemHints(List<Integer> numbers, boolean horizontal)
     {
         // TODO
@@ -379,4 +384,4 @@ public class Type2CharString extends Typ
         }
         return result;
     }
-}
\ No newline at end of file
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java?rev=1667121&r1=1667120&r2=1667121&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java Mon Mar 16 20:26:02 2015
@@ -1,287 +1,287 @@
-/*
- * 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.List;
-
-/**
- * This class represents a converter for a mapping into a Type2-sequence.
- * @author Villu Ruusmann
- */
-public class Type2CharStringParser
-{
-    private int hstemCount = 0;
-    private int vstemCount = 0;
-    private List<Object> sequence = null;
-    private final String fontName, glyphName;
-
-    /**
-     * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
-     *
-     * @param fontName font name
-     * @param glyphName glyph name
-     */
-    public Type2CharStringParser(String fontName, String glyphName)
-    {
-        this.fontName = fontName;
-        this.glyphName = glyphName;
-    }
-
-    /**
-     * Constructs a new Type1CharStringParser object for a CID-Keyed font.
-     *
-     * @param fontName font name
-     * @param cid CID
-     */
-    public Type2CharStringParser(String fontName, int cid)
-    {
-        this.fontName = fontName;
-        this.glyphName = String.format("%04x", cid); // for debugging only
-    }
-
-    /**
-     * The given byte array will be parsed and converted to a Type2 sequence.
-     * @param bytes the given mapping as byte array
-     * @param globalSubrIndex index containing all global subroutines
-     * @param localSubrIndex index containing all local subroutines
-     * 
-     * @return the Type2 sequence
-     * @throws IOException if an error occurs during reading
-     */
-    public List<Object> parse(byte[] bytes, IndexData globalSubrIndex, IndexData localSubrIndex) throws IOException
-    {
-        return parse(bytes, globalSubrIndex, localSubrIndex, true);
-    }
-    
-    private List<Object> parse(byte[] bytes, IndexData globalSubrIndex, IndexData localSubrIndex, boolean init) throws IOException
-    {
-        if (init) 
-        {
-            hstemCount = 0;
-            vstemCount = 0;
-            sequence = new ArrayList<Object>();
-        }
-        DataInput input = new DataInput(bytes);
-        boolean localSubroutineIndexProvided = localSubrIndex != null && localSubrIndex.getCount() > 0;
-        boolean globalSubroutineIndexProvided = globalSubrIndex != null && globalSubrIndex.getCount() > 0;
-
-        while (input.hasRemaining())
-        {
-            int b0 = input.readUnsignedByte();
-            if (b0 == 10 && localSubroutineIndexProvided) 
-            { // process subr command
-                Integer operand=(Integer)sequence.remove(sequence.size()-1);
-                //get subrbias
-                int bias = 0;
-                int nSubrs = localSubrIndex.getCount();
-                
-                if (nSubrs < 1240)
-                {
-                    bias = 107;
-                }
-                else if (nSubrs < 33900) 
-                {
-                    bias = 1131;
-                }
-                else 
-                {
-                    bias = 32768;
-                }
-                int subrNumber = bias+operand;
-                if (subrNumber < localSubrIndex.getCount())
-                {
-                    byte[] subrBytes = localSubrIndex.getBytes(subrNumber);
-                    parse(subrBytes, globalSubrIndex, localSubrIndex, false);
-                    Object lastItem=sequence.get(sequence.size()-1);
-                    if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0] == 11)
-                    {
-                        sequence.remove(sequence.size()-1); // remove "return" command
-                    }
-                }
-
-            } 
-            else if (b0 == 29 && globalSubroutineIndexProvided) 
-            { // process globalsubr command
-                Integer operand=(Integer)sequence.remove(sequence.size()-1);
-                //get subrbias
-                int bias = 0;
-                int nSubrs = globalSubrIndex.getCount();
-                
-                if (nSubrs < 1240)
-                {
-                    bias = 107;
-                }
-                else if (nSubrs < 33900) 
-                {
-                    bias = 1131;
-                }
-                else 
-                {
-                    bias = 32768;
-                }
-                
-                int subrNumber = bias+operand;
-                if (subrNumber < globalSubrIndex.getCount())
-                {
-                    byte[] subrBytes = globalSubrIndex.getBytes(subrNumber);
-                    parse(subrBytes, globalSubrIndex, localSubrIndex, false);
-                    Object lastItem=sequence.get(sequence.size()-1);
-                    if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0]==11) 
-                    {
-                        sequence.remove(sequence.size()-1); // remove "return" command
-                    }
-                }
-
-            } 
-            else if (b0 >= 0 && b0 <= 27)
-            {
-                sequence.add(readCommand(b0, input));
-            } 
-            else if (b0 == 28)
-            {
-                sequence.add(readNumber(b0, input));
-            } 
-            else if (b0 >= 29 && b0 <= 31)
-            {
-                sequence.add(readCommand(b0, input));
-            } 
-            else if (b0 >= 32 && b0 <= 255)
-            {
-                sequence.add(readNumber(b0, input));
-            }
-            else
-            {
-                throw new IllegalArgumentException();
-            }
-        }
-        return sequence;
-    }
-
-    private CharStringCommand readCommand(int b0, DataInput input) throws IOException
-    {
-
-        if (b0 == 1 || b0 == 18)
-        {
-            hstemCount += peekNumbers().size() / 2;
-        } 
-        else if (b0 == 3 || b0 == 19 || b0 == 20 || b0 == 23)
-        {
-            vstemCount += peekNumbers().size() / 2;
-        } // End if
-
-        if (b0 == 12)
-        {
-            int b1 = input.readUnsignedByte();
-
-            return new CharStringCommand(b0, b1);
-        } 
-        else if (b0 == 19 || b0 == 20)
-        {
-            int[] value = new int[1 + getMaskLength()];
-            value[0] = b0;
-
-            for (int i = 1; i < value.length; i++)
-            {
-                value[i] = input.readUnsignedByte();
-            }
-
-            return new CharStringCommand(value);
-        }
-
-        return new CharStringCommand(b0);
-    }
-
-    private Integer readNumber(int b0, DataInput input) throws IOException
-    {
-
-        if (b0 == 28)
-        {
-            int b1 = input.readUnsignedByte();
-            int b2 = input.readUnsignedByte();
-
-            return (int) (short) (b1 << 8 | b2);
-        } 
-        else if (b0 >= 32 && b0 <= 246)
-        {
-            return b0 - 139;
-        } 
-        else if (b0 >= 247 && b0 <= 250)
-        {
-            int b1 = input.readUnsignedByte();
-
-            return (b0 - 247) * 256 + b1 + 108;
-        } 
-        else if (b0 >= 251 && b0 <= 254)
-        {
-            int b1 = input.readUnsignedByte();
-
-            return -(b0 - 251) * 256 - b1 - 108;
-        } 
-        else if (b0 == 255)
-        {
-            int b1 = input.readUnsignedByte();
-            int b2 = input.readUnsignedByte();
-            // The lower bytes are representing the digits after 
-            // the decimal point and aren't needed in this context
-            input.readUnsignedByte();
-            input.readUnsignedByte();
-            return (int) (short)(b1 << 8 | b2);
-        } 
-        else
-        {
-            throw new IllegalArgumentException();
-        }
-    }
-
-    private int getMaskLength()
-    {
-        int length = 1;
-
-        int hintCount = hstemCount + vstemCount;
-        while ((hintCount -= 8) > 0)
-        {
-            length++;
-        }
-
-        return length;
-    }
-
-    private List<Number> peekNumbers()
-    {
-        List<Number> numbers = new ArrayList<Number>();
-
-        for (int i = sequence.size() - 1; i > -1; i--)
-        {
-            Object object = sequence.get(i);
-
-            if (object instanceof Number)
-            {
-                Number number = (Number) object;
-
-                numbers.add(0, number);
-
-                continue;
-            }
-
-            return numbers;
-        }
-
-        return numbers;
-    }
-}
+/*
+ * 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.List;
+
+/**
+ * This class represents a converter for a mapping into a Type2-sequence.
+ * @author Villu Ruusmann
+ */
+public class Type2CharStringParser
+{
+    private int hstemCount = 0;
+    private int vstemCount = 0;
+    private List<Object> sequence = null;
+    private final String fontName, glyphName;
+
+    /**
+     * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
+     *
+     * @param fontName font name
+     * @param glyphName glyph name
+     */
+    public Type2CharStringParser(String fontName, String glyphName)
+    {
+        this.fontName = fontName;
+        this.glyphName = glyphName;
+    }
+
+    /**
+     * Constructs a new Type1CharStringParser object for a CID-Keyed font.
+     *
+     * @param fontName font name
+     * @param cid CID
+     */
+    public Type2CharStringParser(String fontName, int cid)
+    {
+        this.fontName = fontName;
+        this.glyphName = String.format("%04x", cid); // for debugging only
+    }
+
+    /**
+     * The given byte array will be parsed and converted to a Type2 sequence.
+     * @param bytes the given mapping as byte array
+     * @param globalSubrIndex index containing all global subroutines
+     * @param localSubrIndex index containing all local subroutines
+     * 
+     * @return the Type2 sequence
+     * @throws IOException if an error occurs during reading
+     */
+    public List<Object> parse(byte[] bytes, IndexData globalSubrIndex, IndexData localSubrIndex) throws IOException
+    {
+        return parse(bytes, globalSubrIndex, localSubrIndex, true);
+    }
+    
+    private List<Object> parse(byte[] bytes, IndexData globalSubrIndex, IndexData localSubrIndex, boolean init) throws IOException
+    {
+        if (init) 
+        {
+            hstemCount = 0;
+            vstemCount = 0;
+            sequence = new ArrayList<Object>();
+        }
+        DataInput input = new DataInput(bytes);
+        boolean localSubroutineIndexProvided = localSubrIndex != null && localSubrIndex.getCount() > 0;
+        boolean globalSubroutineIndexProvided = globalSubrIndex != null && globalSubrIndex.getCount() > 0;
+
+        while (input.hasRemaining())
+        {
+            int b0 = input.readUnsignedByte();
+            if (b0 == 10 && localSubroutineIndexProvided) 
+            { // process subr command
+                Integer operand=(Integer)sequence.remove(sequence.size()-1);
+                //get subrbias
+                int bias = 0;
+                int nSubrs = localSubrIndex.getCount();
+                
+                if (nSubrs < 1240)
+                {
+                    bias = 107;
+                }
+                else if (nSubrs < 33900) 
+                {
+                    bias = 1131;
+                }
+                else 
+                {
+                    bias = 32768;
+                }
+                int subrNumber = bias+operand;
+                if (subrNumber < localSubrIndex.getCount())
+                {
+                    byte[] subrBytes = localSubrIndex.getBytes(subrNumber);
+                    parse(subrBytes, globalSubrIndex, localSubrIndex, false);
+                    Object lastItem=sequence.get(sequence.size()-1);
+                    if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0] == 11)
+                    {
+                        sequence.remove(sequence.size()-1); // remove "return" command
+                    }
+                }
+
+            } 
+            else if (b0 == 29 && globalSubroutineIndexProvided) 
+            { // process globalsubr command
+                Integer operand=(Integer)sequence.remove(sequence.size()-1);
+                //get subrbias
+                int bias = 0;
+                int nSubrs = globalSubrIndex.getCount();
+                
+                if (nSubrs < 1240)
+                {
+                    bias = 107;
+                }
+                else if (nSubrs < 33900) 
+                {
+                    bias = 1131;
+                }
+                else 
+                {
+                    bias = 32768;
+                }
+                
+                int subrNumber = bias+operand;
+                if (subrNumber < globalSubrIndex.getCount())
+                {
+                    byte[] subrBytes = globalSubrIndex.getBytes(subrNumber);
+                    parse(subrBytes, globalSubrIndex, localSubrIndex, false);
+                    Object lastItem=sequence.get(sequence.size()-1);
+                    if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0]==11) 
+                    {
+                        sequence.remove(sequence.size()-1); // remove "return" command
+                    }
+                }
+
+            } 
+            else if (b0 >= 0 && b0 <= 27)
+            {
+                sequence.add(readCommand(b0, input));
+            } 
+            else if (b0 == 28)
+            {
+                sequence.add(readNumber(b0, input));
+            } 
+            else if (b0 >= 29 && b0 <= 31)
+            {
+                sequence.add(readCommand(b0, input));
+            } 
+            else if (b0 >= 32 && b0 <= 255)
+            {
+                sequence.add(readNumber(b0, input));
+            }
+            else
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+        return sequence;
+    }
+
+    private CharStringCommand readCommand(int b0, DataInput input) throws IOException
+    {
+
+        if (b0 == 1 || b0 == 18)
+        {
+            hstemCount += peekNumbers().size() / 2;
+        } 
+        else if (b0 == 3 || b0 == 19 || b0 == 20 || b0 == 23)
+        {
+            vstemCount += peekNumbers().size() / 2;
+        } // End if
+
+        if (b0 == 12)
+        {
+            int b1 = input.readUnsignedByte();
+
+            return new CharStringCommand(b0, b1);
+        } 
+        else if (b0 == 19 || b0 == 20)
+        {
+            int[] value = new int[1 + getMaskLength()];
+            value[0] = b0;
+
+            for (int i = 1; i < value.length; i++)
+            {
+                value[i] = input.readUnsignedByte();
+            }
+
+            return new CharStringCommand(value);
+        }
+
+        return new CharStringCommand(b0);
+    }
+
+    private static Integer readNumber(int b0, DataInput input) throws IOException
+    {
+
+        if (b0 == 28)
+        {
+            int b1 = input.readUnsignedByte();
+            int b2 = input.readUnsignedByte();
+
+            return (int) (short) (b1 << 8 | b2);
+        } 
+        else if (b0 >= 32 && b0 <= 246)
+        {
+            return b0 - 139;
+        } 
+        else if (b0 >= 247 && b0 <= 250)
+        {
+            int b1 = input.readUnsignedByte();
+
+            return (b0 - 247) * 256 + b1 + 108;
+        } 
+        else if (b0 >= 251 && b0 <= 254)
+        {
+            int b1 = input.readUnsignedByte();
+
+            return -(b0 - 251) * 256 - b1 - 108;
+        } 
+        else if (b0 == 255)
+        {
+            int b1 = input.readUnsignedByte();
+            int b2 = input.readUnsignedByte();
+            // The lower bytes are representing the digits after 
+            // the decimal point and aren't needed in this context
+            input.readUnsignedByte();
+            input.readUnsignedByte();
+            return (int) (short)(b1 << 8 | b2);
+        } 
+        else
+        {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private int getMaskLength()
+    {
+        int length = 1;
+
+        int hintCount = hstemCount + vstemCount;
+        while ((hintCount -= 8) > 0)
+        {
+            length++;
+        }
+
+        return length;
+    }
+
+    private List<Number> peekNumbers()
+    {
+        List<Number> numbers = new ArrayList<Number>();
+
+        for (int i = sequence.size() - 1; i > -1; i--)
+        {
+            Object object = sequence.get(i);
+
+            if (object instanceof Number)
+            {
+                Number number = (Number) object;
+
+                numbers.add(0, number);
+
+                continue;
+            }
+
+            return numbers;
+        }
+
+        return numbers;
+    }
+}