class PrivateType1CharStringReader implements Type1CharStringReader
    {
        @Override
        public Type1CharString getType1CharString(String name) throws IOException
        {
            return CFFType1Font.this.getType1CharString(name);
        }
    }

    @Override
    public GeneralPath getPath(String name) throws IOException
    {
        return getType1CharString(name).getPath();
    }

    @Override
    public float getWidth(String name) throws IOException
    {
        return getType1CharString(name).getWidth();
    }

    @Override
    public boolean hasGlyph(String name)
    {
        int sid = getCharset().getSID(name);
        int gid = getCharset().getGIDForSID(sid);
        return gid != 0;
    }

    /**
     * Returns the Type 1 charstring for the given PostScript glyph name.
     *
     * @param name PostScript glyph name
     * @return Type1 charstring of the given PostScript glyph name
     * 
     * @throws IOException if the charstring could not be read
     */
    public Type1CharString getType1CharString(String name) throws IOException
    {
        // lookup via charset
        int gid = nameToGID(name);

        // lookup in CharStrings INDEX
        return getType2CharString(gid, name);
    }

    /**
     * Returns the GID for the given PostScript glyph name.
     * 
     * @param name a PostScript glyph name.
     * @return GID
     */
    public int nameToGID(String name)
    {
        // some fonts have glyphs beyond their encoding, so we look up by charset SID
        int sid = getCharset().getSID(name);
        return getCharset().getGIDForSID(sid);
    }

    /**
     * Returns the Type 1 charstring for the given GID.
     *
     * @param gid GID
     * @throws IOException if the charstring could not be read
     */
    @Override
    public Type2CharString getType2CharString(int gid) throws IOException
    {
        String name = "GID+" + gid; // for debugging only
        return getType2CharString(gid, name);
    }

    // Returns the Type 2 charstring for the given GID, with name for debugging
    private Type2CharString getType2CharString(int gid, String name) throws IOException
    {
        Type2CharString type2 = charStringCache.get(gid);
        if (type2 == null)
        {
            byte[] bytes = null;
            if (gid < charStrings.length)
            {
                bytes = charStrings[gid];
            }
            if (bytes == null)
            {
                // .notdef
                bytes = charStrings[0];
            }
            List<Object> type2seq = getParser().parse(bytes, globalSubrIndex, getLocalSubrIndex(),
                    name);
            type2 = new Type2CharString(reader, getName(), name, gid, type2seq, getDefaultWidthX(),
                    getNominalWidthX());
            charStringCache.put(gid, type2);
        }
        return type2;
    }

    private Type2CharStringParser getParser()
    {
        if (charStringParser == null)
        {
            charStringParser = new Type2CharStringParser(getName());
        }
        return charStringParser;
    }

    /**
     * Returns the private dictionary.
     *
     * @return the dictionary
     */
    public Map<String, Object> getPrivateDict()
    {
        return privateDict;
    }

    /**
     * Adds the given key/value pair to the private dictionary.
     *
     * @param name the given key
     * @param value the given value
     */
    void addToPrivateDict(String name, Object value)
    {
        if (value != null)
        {
            privateDict.put(name, value);
        }
    }

    /**
     * Returns the CFFEncoding of the font.
     *
     * @return the encoding
     */
    @Override
    public CFFEncoding getEncoding()
    {
        return encoding;
    }

    /**
     * Sets the CFFEncoding of the font.
     *
     * @param encoding the given CFFEncoding
     */
    void setEncoding(CFFEncoding encoding)
    {
        this.encoding = encoding;
    }

    private byte[][] getLocalSubrIndex()
    {
        if (localSubrIndex == null)
        {
            localSubrIndex = (byte[][]) privateDict.get("Subrs");
        }
        return localSubrIndex;
    }

    // helper for looking up keys/values
    private Object getProperty(String name)
    {
        Object topDictValue = topDict.get(name);
        if (topDictValue != null)
        {
            return topDictValue;
        }
        return privateDict.get(name);
    }

    private int getDefaultWidthX()
    {
        if (defaultWidthX == Integer.MIN_VALUE)
        {
            Number num = (Number) getProperty("defaultWidthX");
            defaultWidthX = num != null ? num.intValue() : 1000;
        }
        return defaultWidthX;
    }

    private int getNominalWidthX()
    {<FILL_FUNCTION_BODY>

        if (nominalWidthX == Integer.MIN_VALUE)
        {
            Number num = (Number) getProperty("nominalWidthX");
            nominalWidthX = num != null ? num.intValue() : 0;
        }
        return nominalWidthX;
    
<methods>public non-sealed void <init>() ,public void addValueToTopDict(java.lang.String, java.lang.Object) ,public final List<byte[]> getCharStringBytes() ,public org.apache.fontbox.cff.CFFCharset getCharset() ,public byte[] getData() throws java.io.IOException,public org.apache.fontbox.util.BoundingBox getFontBBox() throws java.io.IOException,public List<java.lang.Number> getFontMatrix() ,public List<byte[]> getGlobalSubrIndex() ,public java.lang.String getName() ,public int getNumCharStrings() ,public Map<java.lang.String,java.lang.Object> getTopDict() ,public abstract org.apache.fontbox.cff.Type2CharString getType2CharString(int) throws java.io.IOException,public java.lang.String toString() <variables>protected byte[][] charStrings,private org.apache.fontbox.cff.CFFCharset charset,private java.lang.String fontName,protected byte[][] globalSubrIndex,private org.apache.fontbox.cff.CFFParser.ByteSource source,protected final Map<java.lang.String,java.lang.Object> topDict