Beispiel #1
0
        /**
         * Parses the ASCII portion of a Type 1 font.
         */
        private void ParseASCII(byte[] bytes)
        {
            if (bytes.Length == 0)
            {
                throw new ArgumentException("byte[] is empty");
            }

            // %!FontType1-1.0
            // %!PS-AdobeFont-1.0
            if (bytes.Length < 2 || (bytes[0] != '%' && bytes[1] != '!'))
            {
                throw new IOException("Invalid start of ASCII segment");
            }

            lexer = new Type1Lexer(bytes);

            // (corrupt?) synthetic font
            if (lexer.PeekToken().Text.Equals("FontDirectory", StringComparison.Ordinal))
            {
                Read(TokenKind.NAME, "FontDirectory");
                Read(TokenKind.LITERAL); // font name
                Read(TokenKind.NAME, "known");
                Read(TokenKind.START_PROC);
                ReadProc();
                Read(TokenKind.START_PROC);
                ReadProc();
                Read(TokenKind.NAME, "ifelse");
            }

            // font dict
            int Length = Read(TokenKind.INTEGER).IntValue;

            Read(TokenKind.NAME, "dict");
            // found in some TeX fonts
            ReadMaybe(TokenKind.NAME, "dup");
            // if present, the "currentdict" is not required
            Read(TokenKind.NAME, "begin");

            for (int i = 0; i < Length; i++)
            {
                // premature end
                Token token = lexer.PeekToken();
                if (token == null)
                {
                    break;
                }
                if (token.Kind == TokenKind.NAME &&
                    ("currentdict".Equals(token.Text, StringComparison.Ordinal) ||
                     "end".Equals(token.Text, StringComparison.Ordinal)))
                {
                    break;
                }

                // key/value
                string key = Read(TokenKind.LITERAL).Text;
                switch (key)
                {
                case "FontInfo":
                case "Fontinfo":
                    ReadFontInfo(ReadSimpleDict());
                    break;

                case "Metrics":
                    ReadSimpleDict();
                    break;

                case "Encoding":
                    ReadEncoding();
                    break;

                default:
                    ReadSimpleValue(key);
                    break;
                }
            }

            ReadMaybe(TokenKind.NAME, "currentdict");
            Read(TokenKind.NAME, "end");

            Read(TokenKind.NAME, "currentfile");
            Read(TokenKind.NAME, "eexec");
        }
Beispiel #2
0
        /**
         * Parses the binary portion of a Type 1 font.
         */
        private void ParseBinary(byte[] bytes)
        {
            byte[] decrypted;
            // Sometimes, fonts use the hex format, so this needs to be converted before decryption
            if (IsBinary(bytes))
            {
                decrypted = Decrypt(bytes, EEXEC_KEY, 4);
            }
            else
            {
                decrypted = Decrypt(hexToBinary(bytes), EEXEC_KEY, 4);
            }
            lexer = new Type1Lexer(decrypted);

            // find /Private dict
            Token peekToken = lexer.PeekToken();

            while (peekToken != null && !peekToken.Text.Equals("Private", StringComparison.Ordinal))
            {
                // for a more thorough validation, the presence of "begin" before Private
                // determines how code before and following charstrings should look
                // it is not currently checked anyway
                lexer.NextToken();
                peekToken = lexer.PeekToken();
            }
            if (peekToken == null)
            {
                throw new IOException("/Private token not found");
            }

            // Private dict
            Read(TokenKind.LITERAL, "Private");
            int Length = Read(TokenKind.INTEGER).IntValue;

            Read(TokenKind.NAME, "dict");
            // actually could also be "/Private 10 dict def Private begin"
            // instead of the "dup"
            ReadMaybe(TokenKind.NAME, "dup");
            Read(TokenKind.NAME, "begin");

            int lenIV = 4; // number of random bytes at start of charstring

            for (int i = 0; i < Length; i++)
            {
                // premature end
                if (lexer.PeekToken() == null || lexer.PeekToken().Kind != TokenKind.LITERAL)
                {
                    break;
                }

                // key/value
                string key = Read(TokenKind.LITERAL).Text;

                switch (key)
                {
                case "Subrs":
                    ReadSubrs(lenIV);
                    break;

                case "OtherSubrs":
                    ReadOtherSubrs();
                    break;

                case "lenIV":
                    lenIV = ReadDictValue()[0].IntValue;
                    break;

                case "ND":
                    Read(TokenKind.START_PROC);
                    // the access restrictions are not mandatory
                    ReadMaybe(TokenKind.NAME, "noaccess");
                    Read(TokenKind.NAME, "def");
                    Read(TokenKind.END_PROC);
                    ReadMaybe(TokenKind.NAME, "executeonly");
                    Read(TokenKind.NAME, "def");
                    break;

                case "NP":
                    Read(TokenKind.START_PROC);
                    ReadMaybe(TokenKind.NAME, "noaccess");
                    Read(TokenKind.NAME);
                    Read(TokenKind.END_PROC);
                    ReadMaybe(TokenKind.NAME, "executeonly");
                    Read(TokenKind.NAME, "def");
                    break;

                case "RD":
                    // /RD {string currentfile exch readstring pop} bind executeonly def
                    Read(TokenKind.START_PROC);
                    ReadProc();
                    ReadMaybe(TokenKind.NAME, "bind");
                    ReadMaybe(TokenKind.NAME, "executeonly");
                    Read(TokenKind.NAME, "def");
                    break;

                default:
                    ReadPrivate(key, ReadDictValue());
                    break;
                }
            }

            // some fonts have "2 index" here, others have "end noaccess put"
            // sometimes followed by "put". Either way, we just skip until
            // the /CharStrings dict is found
            while (!(lexer.PeekToken().Kind == TokenKind.LITERAL &&
                     lexer.PeekToken().Text.Equals("CharStrings", StringComparison.Ordinal)))
            {
                lexer.NextToken();
            }

            // CharStrings dict
            Read(TokenKind.LITERAL, "CharStrings");
            ReadCharStrings(lenIV);
        }