/// <summary> /// Attempt to parse the given data stream, returning an indicator of parse progress /// </summary> /// <param name="StartingToken">The token immediately preceeding the starting index in Data stream</param> /// <param name="Data">Raw byte stream to parse</param> /// <param name="StartingIndex">0-based starting index into Data where StartingToken appears</param> /// <param name="EndingIndex">Index into data stream where parsing ended (either successfully or unsuccessfully)</param> /// <returns>Object parsed from data stream, or NULL if unable to parse. If NULL and EndingIndex is equal to Data.Length, parsing may be successful with more data</returns> public static IPDFObject TryParse(string StartingToken, byte[] Data, int StartingIndex, out int EndingIndex) { int StartIndex; int Number; EndingIndex = StartingIndex; if (int.TryParse(StartingToken, out Number)) { string Declaration = PDFObjectParser.GetTokenString(Data, StartingIndex + StartingToken.Length, out StartIndex, out EndingIndex, 2); if (!String.IsNullOrEmpty(Declaration)) { Match objMatch = Regex.Match(Declaration, @"([+-]?\d+) R"); if (objMatch.Success) { int Generation = int.Parse(objMatch.Groups[1].Value); if (Declaration.Length != objMatch.Length) { EndingIndex = EndingIndex - (Declaration.Length - objMatch.Length) - 1; } return(new PDFIndirectObject(Number, Generation)); } } } return(null); }
public static PDFStream MakeStream(PDFDictionary StreamDictionary, byte[] Data, int StartingIndex, out int EndingIndex) { int TokEnd; int StreamLength = 0; if (StreamDictionary.ContainsKey("Length")) { StreamLength = (int)(Decimal.Parse(StreamDictionary["Length"].Description)); } else { StreamLength = PDF.FirstOccurance(Data, Encoding.UTF8.GetBytes("endstream"), StartingIndex); } EndingIndex = StartingIndex; if ("stream".Equals(PDFObjectParser.GetTokenString(Data, EndingIndex, out _, out TokEnd))) { if ((StreamLength > 0) && (Data.Length >= TokEnd + 1 + StreamLength)) { byte[] StreamBytes = new byte[StreamLength]; Array.Copy(Data, TokEnd + 1, StreamBytes, 0, StreamLength); EndingIndex = TokEnd + 1 + StreamLength; if (!"endstream".Equals(PDFObjectParser.GetTokenString(Data, EndingIndex, out _, out EndingIndex))) { } // Error - missing "endstream" return(new PDFStream(StreamDictionary, StreamBytes)); } } // Unable to make a stream from this data return(null); }
/// <summary> /// Read the trailer from a PDF data file /// </summary> /// <param name="Data">Data to read</param> /// <param name="StartIndex">Starting index of where to look for trailer, or -1 to look from end of file (default: -1)</param> /// <returns>TRUE if a trailer was successfully read, FALSE otherwise</returns> public static PDFTrailer ReadTrailer(byte[] Data, int StartIndex = -1) { int EndIndex = StartIndex; if (EndIndex < 0) { EndIndex = PDF.FindEOF(Data, Data.Length - 1); } if (EndIndex < 0) { return(null); } int EndOfLineIndex; byte[] LineData = PDF.ExtractPreviousPDFLine(Data, EndIndex, out EndIndex, out EndOfLineIndex); while (LineData != null) { if ("trailer".Equals(Encoding.UTF8.GetString(LineData).Trim())) { int TokenStartIndex = 0; string Token = PDFObjectParser.GetTokenString(Data, EndOfLineIndex, out TokenStartIndex, out EndIndex); PDFDictionary TrailerDictionary = (PDFDictionary)PDFDictionary.TryParse(Token, Data, TokenStartIndex, out EndIndex); if (TrailerDictionary != null) { LineData = PDF.ExtractPDFLine(Data, EndIndex, out EndIndex); if ("startxref".Equals(Encoding.UTF8.GetString(LineData).Trim())) { Token = PDFObjectParser.GetTokenString(Data, EndIndex, out TokenStartIndex, out _); PDFNumber Offset = (PDFNumber)PDFNumber.TryParse(Token, Data, TokenStartIndex, out EndIndex); PDFCrossReference CrossRef = PDFCrossReference.ReadCrossReference(Data, Offset, out _); return(new PDFTrailer(TrailerDictionary, CrossRef)); } else { return(null); } } else { return(null); } } else { LineData = PDF.ExtractPreviousPDFLine(Data, EndIndex, out EndIndex, out EndOfLineIndex); } } return(null); }
/// <summary> /// Attempt to parse the given data stream, returning an indicator of parse progress /// </summary> /// <param name="StartingToken">The token immediately preceeding the starting index in Data stream</param> /// <param name="Data">Raw byte stream to parse</param> /// <param name="StartingIndex">0-based starting index into Data where StartingToken appears</param> /// <param name="EndingIndex">Index into data stream where parsing ended (either successfully or unsuccessfully)</param> /// <returns>Object parsed from data stream, or NULL if unable to parse. If NULL and EndingIndex is equal to Data.Length, parsing may be successful with more data</returns> public static IPDFObject TryParse(string StartingToken, byte[] Data, int StartingIndex, out int EndingIndex) { Dictionary <string, IPDFObject> KeyValuePairs = new Dictionary <string, IPDFObject>(); EndingIndex = StartingIndex; if (StartingToken.Equals("<<")) { EndingIndex += StartingToken.Length; while (EndingIndex < Data.Length) { int TokEnd; if (">>".Equals(PDFObjectParser.GetTokenString(Data, EndingIndex, out _, out TokEnd))) { EndingIndex = TokEnd; if ("stream".Equals(PDFObjectParser.GetTokenString(Data, EndingIndex, out _, out TokEnd))) { return(PDFStream.MakeStream(new PDFDictionary(KeyValuePairs), Data, EndingIndex, out EndingIndex)); } else { return(new PDFDictionary(KeyValuePairs)); } } IPDFObject Key = PDFObjectParser.Parse(Data, out EndingIndex, EndingIndex); if (Key == null) { return(null); // No key found } if (Key.Type != PDFObjectType.Name) { return(null); // Invalid key type found } IPDFObject Value = PDFObjectParser.Parse(Data, out EndingIndex, EndingIndex); if (Value == null) { return(null); // No value found } KeyValuePairs.Add(Key.Description, Value); } } // Didn't find a dictionary delimiter return(null); }
/// <summary> /// Attempt to parse the given data stream, returning an indicator of parse progress /// </summary> /// <param name="StartingToken">The token immediately preceeding the starting index in Data stream</param> /// <param name="Data">Raw byte stream to parse</param> /// <param name="StartingIndex">0-based starting index into Data where StartingToken appears</param> /// <param name="EndingIndex">Index into data stream where parsing ended (either successfully or unsuccessfully)</param> /// <returns>Object parsed from data stream, or NULL if unable to parse. If NULL and EndingIndex is equal to Data.Length, parsing may be successful with more data</returns> public static IPDFObject TryParse(string StartingToken, byte[] Data, int StartingIndex, out int EndingIndex) { int Number; EndingIndex = StartingIndex; if (int.TryParse(StartingToken, out Number)) { string Declaration = PDFObjectParser.GetTokenString(Data, StartingIndex + StartingToken.Length, out _, out EndingIndex, 2); if (!String.IsNullOrEmpty(Declaration)) { Match objMatch = Regex.Match(Declaration, @"([+-]?\d+) obj"); if (objMatch.Success) { if (Declaration.Length != objMatch.Length) { EndingIndex = EndingIndex - (Declaration.Length - objMatch.Length) - 1; } int Generation = int.Parse(objMatch.Groups[1].Value); // Parse the indirect object content (should be a single object) IPDFObject PDFObject = PDFObjectParser.Parse(Data, out EndingIndex, EndingIndex); if (PDFObject != null) { int ObjectEndIndex = PDF.FirstOccurance(Data, Encoding.UTF8.GetBytes("endobj"), EndingIndex); if (ObjectEndIndex > 0) { // Format error - tokens after object definition but before "endobj" } EndingIndex = ObjectEndIndex + "endobj".Length; return(new PDFObjectDefinition(Number, Generation, PDFObject)); } } } } return(null); }