public List <TokenXRefEntry> ParseXRef() { Tokenizer.IgnoreComments = true; TokenObject t = Tokenizer.GetToken(); TokenKeyword keyword = t as TokenKeyword; if ((keyword == null) || (keyword.Value != ParseKeyword.XRef)) { // Scan entire source creating XRef entries for each indirect object return(IndirectObjectsToXRef()); } else { List <TokenXRefEntry> entries = new List <TokenXRefEntry>(); ParseXRefSections(entries); return(entries); } }
public List <TokenXRefEntry> IndirectObjectsToXRef() { List <TokenXRefEntry> entries = new List <TokenXRefEntry>(); // Start scanning from beginning of the source Tokenizer.IgnoreComments = false; Tokenizer.Position = 0; long lastTrailer = -1; do { long t1Position = Tokenizer.Position; TokenObject t1 = Tokenizer.GetToken(); if (t1 is TokenInteger) { TokenInteger t2 = Tokenizer.GetToken() as TokenInteger; if (t2 != null) { TokenKeyword t3 = Tokenizer.GetToken() as TokenKeyword; if ((t3 != null) && (t3.Value == ParseKeyword.Obj)) { TokenInteger id = (TokenInteger)t1; entries.Add(new TokenXRefEntry(id.Value, t2.Value, t1Position, true)); } } } else if ((t1 is TokenKeyword) && ((TokenKeyword)t1).Value == ParseKeyword.Trailer) { lastTrailer = t1Position; } } while (Tokenizer.GotoNextLine()); // Leave with the position on the last 'trailer' as caller will then parse it if (lastTrailer >= 0) { Tokenizer.Position = lastTrailer; } return(entries); }
private TokenObject GetKeywordOrIdentifier() { long position = _position + _index; // Scan looking for the end of the keyword characters int key = _index; while ((key < _length) && _lookupKeyword[_line[key]]) { key++; } string text = Encoding.ASCII.GetString(_line, _index, key - _index); TokenKeyword token = TokenKeyword.GetToken(text); if (token != null) { _index = key; return(token); } if (AllowIdentifiers) { // Scan looking for the end of the identifier key = _index; while ((key < _length) && !_lookupDelimiterWhitespace[_line[key]]) { key++; } text = Encoding.ASCII.GetString(_line, _index, key - _index); _index = key; return(new TokenIdentifier(text)); } else { return(new TokenError(position, $"Cannot parse '{text}' as a keyword.")); } }
public ParseIndirectObject ParseIndirectObject() { Tokenizer.IgnoreComments = true; TokenObject t = Tokenizer.GetToken(); ThrowOnEmptyOrError(t); // Indirect object starts with an integer, the object identifier if (!(t is TokenInteger)) { Tokenizer.PushToken(t); return(null); } // Second is another integer, the generation number TokenObject u = Tokenizer.GetToken(); ThrowOnEmptyOrError(u); if (!(u is TokenInteger)) { Tokenizer.PushToken(t); Tokenizer.PushToken(u); return(null); } // This is the keyword 'obj' TokenObject v = Tokenizer.GetToken(); ThrowOnEmptyOrError(v); if (!(v is TokenKeyword) || ((v as TokenKeyword).Value != ParseKeyword.Obj)) { Tokenizer.PushToken(t); Tokenizer.PushToken(u); Tokenizer.PushToken(v); return(null); } // Get actual object that is the content ParseObjectBase obj = ParseObject(); if (obj == null) { throw new ApplicationException($"Indirect object has missing content."); } // Must be followed by either 'endobj' or 'stream' v = Tokenizer.GetToken(); ThrowOnEmptyOrError(v); TokenKeyword keyword = v as TokenKeyword; if (keyword == null) { // PH: FIXME: //throw new ApplicationException($"Indirect object has missing 'endobj or 'stream'."); return(new ParseIndirectObject(t as TokenInteger, u as TokenInteger, new ParseInteger(0))); } if (keyword.Value == ParseKeyword.EndObj) { return(new ParseIndirectObject(t as TokenInteger, u as TokenInteger, obj)); } else if (keyword.Value == ParseKeyword.Stream) { ParseDictionary dictionary = obj as ParseDictionary; if (dictionary == null) { throw new ApplicationException($"Stream must be preceded by a dictionary."); } if (!dictionary.ContainsName("Length")) { throw new ApplicationException($"Stream dictionary must contain a 'Length' entry."); } ParseObjectBase lengthObj = dictionary["Length"]; // Resolve any object reference ParseObjectReference reference = lengthObj as ParseObjectReference; if (reference != null) { lengthObj = OnResolveReference(reference); } ParseInteger length = lengthObj as ParseInteger; if (length == null) { throw new ApplicationException($"Stream dictionary has a 'Length' entry that is not an integer entry."); } if (length.Value < 0) { throw new ApplicationException($"Stream dictionary has a 'Length' less than 0."); } byte[] bytes = Tokenizer.GetBytes(length.Value); if (bytes == null) { throw new ApplicationException($"Cannot read in expected {length.Value} bytes from stream."); } // Stream contents must be followed by 'endstream' v = Tokenizer.GetToken(); ThrowOnEmptyOrError(v); keyword = v as TokenKeyword; if (keyword == null) { throw new ApplicationException($"Stream has missing 'endstream' after content."); } if (keyword.Value != ParseKeyword.EndStream) { throw new ApplicationException($"Stream has unexpected keyword {keyword.Value} instead of 'endstream'."); } // Stream contents must be followed by 'endobj' v = Tokenizer.GetToken(); ThrowOnEmptyOrError(v); keyword = v as TokenKeyword; if (keyword == null) { throw new ApplicationException($"Indirect object has missing 'endobj'."); } if (keyword.Value != ParseKeyword.EndObj) { throw new ApplicationException($"Indirect object has unexpected keyword {keyword.Value} instead of 'endobj'."); } return(new ParseIndirectObject(t as TokenInteger, u as TokenInteger, new ParseStream(dictionary, bytes))); } else { throw new ApplicationException($"Indirect object has unexpected keyword {keyword.Value}."); } }