public CrossReferenceTablePart Parse(ISeekableTokenScanner scanner, long offset, bool isLenientParsing) { var builder = new CrossReferenceTablePartBuilder { Offset = offset, XRefType = CrossReferenceType.Table }; if (scanner.CurrentPosition != offset) { scanner.Seek(offset); } scanner.MoveNext(); if (scanner.CurrentToken is OperatorToken operatorToken) { if (operatorToken.Data == "xref") { scanner.MoveNext(); } else { throw new PdfDocumentFormatException($"Unexpected operator in xref position: {operatorToken}."); } } if (scanner.CurrentToken is NumericToken firstObjectNumber) { if (!scanner.TryReadToken(out NumericToken objectCount)) { throw new PdfDocumentFormatException($"Unexpected token following xref and {firstObjectNumber}. We found: {scanner.CurrentToken}."); } var definition = new TableSubsectionDefinition(firstObjectNumber.Long, objectCount.Int); var tokenizer = new EndOfLineTokenizer(); scanner.RegisterCustomTokenizer((byte)'\r', tokenizer); scanner.RegisterCustomTokenizer((byte)'\n', tokenizer); var readingLine = false; var tokens = new List <IToken>(); var count = 0; while (scanner.MoveNext()) { if (scanner.CurrentToken is EndOfLineToken) { if (!readingLine) { continue; } readingLine = false; count = ProcessTokens(tokens, scanner, builder, isLenientParsing, count, ref definition); tokens.Clear(); continue; } if (scanner.CurrentToken is CommentToken) { continue; } var isLineOperator = scanner.CurrentToken is OperatorToken op && (op.Data == FreeEntry || op.Data == InUseEntry); if (!(scanner.CurrentToken is NumericToken) && !isLineOperator) { break; } readingLine = true; tokens.Add(scanner.CurrentToken); } if (tokens.Count > 0) { ProcessTokens(tokens, scanner, builder, isLenientParsing, count, ref definition); } scanner.DeregisterCustomTokenizer(tokenizer); } builder.Dictionary = ParseTrailer(scanner, isLenientParsing); return(builder.Build()); }