private void ReadEncoding() { if (lexer.PeekToken().Kind == TokenKind.NAME) { string name = lexer.NextToken().Text; if (name.Equals("StandardEncoding", StringComparison.Ordinal)) { font.Encoding = StandardEncoding.Instance; } else { throw new IOException("Unknown encoding: " + name); } ReadMaybe(TokenKind.NAME, "readonly"); Read(TokenKind.NAME, "def"); } else { var intValue = Read(TokenKind.INTEGER).IntValue; ReadMaybe(TokenKind.NAME, "array"); // 0 1 255 {1 index exch /.notdef put } for // we have to check "readonly" and "def" too // as some fonts don't provide any dup-values, see PDFBOX-2134 while (!(lexer.PeekToken().Kind == TokenKind.NAME && (lexer.PeekToken().Text.Equals("dup", StringComparison.Ordinal) || lexer.PeekToken().Text.Equals("readonly", StringComparison.Ordinal) || lexer.PeekToken().Text.Equals("def", StringComparison.Ordinal)))) { lexer.NextToken(); } Dictionary <int, string> codeToName = new Dictionary <int, string>(); while (lexer.PeekToken().Kind == TokenKind.NAME && lexer.PeekToken().Text.Equals("dup", StringComparison.Ordinal)) { Read(TokenKind.NAME, "dup"); int code = Read(TokenKind.INTEGER).IntValue; string name = Read(TokenKind.LITERAL).Text; Read(TokenKind.NAME, "put"); codeToName.Add(code, name); } font.Encoding = new Encoding(codeToName); ReadMaybe(TokenKind.NAME, "readonly"); Read(TokenKind.NAME, "def"); } }
/** * 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); }