vendor: import KillerPDF 1.7.5 source (GPL-3.0) as the base for MMD PDF
This commit is contained in:
+189
@@ -0,0 +1,189 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Character table by name.
|
||||
/// </summary>
|
||||
public sealed class Chars
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
/// <summary>
|
||||
/// The EOF marker.
|
||||
/// </summary>
|
||||
public const char EOF = (char)65535; //unchecked((char)(-1));
|
||||
/// <summary>
|
||||
/// The null byte.
|
||||
/// </summary>
|
||||
public const char NUL = '\0'; // EOF
|
||||
/// <summary>
|
||||
/// The carriage return character (ignored by lexer).
|
||||
/// </summary>
|
||||
public const char CR = '\x0D'; // ignored by lexer
|
||||
/// <summary>
|
||||
/// The line feed character.
|
||||
/// </summary>
|
||||
public const char LF = '\x0A'; // Line feed
|
||||
/// <summary>
|
||||
/// The bell character.
|
||||
/// </summary>
|
||||
public const char BEL = '\a'; // Bell
|
||||
/// <summary>
|
||||
/// The backspace character.
|
||||
/// </summary>
|
||||
public const char BS = '\b'; // Backspace
|
||||
/// <summary>
|
||||
/// The form feed character.
|
||||
/// </summary>
|
||||
public const char FF = '\f'; // Form feed
|
||||
/// <summary>
|
||||
/// The horizontal tab character.
|
||||
/// </summary>
|
||||
public const char HT = '\t'; // Horizontal tab
|
||||
/// <summary>
|
||||
/// The vertical tab character.
|
||||
/// </summary>
|
||||
public const char VT = '\v'; // Vertical tab
|
||||
/// <summary>
|
||||
/// The non-breakable space character (aka no-break space or non-breaking space).
|
||||
/// </summary>
|
||||
public const char NonBreakableSpace = (char)160; // char(160)
|
||||
|
||||
// The following names come from "PDF Reference Third Edition"
|
||||
// Appendix D.1, Latin Character Set and Encoding
|
||||
/// <summary>
|
||||
/// The space character.
|
||||
/// </summary>
|
||||
public const char SP = ' ';
|
||||
/// <summary>
|
||||
/// The double quote character.
|
||||
/// </summary>
|
||||
public const char QuoteDbl = '"';
|
||||
/// <summary>
|
||||
/// The single quote character.
|
||||
/// </summary>
|
||||
public const char QuoteSingle = '\'';
|
||||
/// <summary>
|
||||
/// The left parenthesis.
|
||||
/// </summary>
|
||||
public const char ParenLeft = '(';
|
||||
/// <summary>
|
||||
/// The right parenthesis.
|
||||
/// </summary>
|
||||
public const char ParenRight = ')';
|
||||
/// <summary>
|
||||
/// The left brace.
|
||||
/// </summary>
|
||||
public const char BraceLeft = '{';
|
||||
/// <summary>
|
||||
/// The right brace.
|
||||
/// </summary>
|
||||
public const char BraceRight = '}';
|
||||
/// <summary>
|
||||
/// The left bracket.
|
||||
/// </summary>
|
||||
public const char BracketLeft = '[';
|
||||
/// <summary>
|
||||
/// The right bracket.
|
||||
/// </summary>
|
||||
public const char BracketRight = ']';
|
||||
/// <summary>
|
||||
/// The less-than sign.
|
||||
/// </summary>
|
||||
public const char Less = '<';
|
||||
/// <summary>
|
||||
/// The greater-than sign.
|
||||
/// </summary>
|
||||
public const char Greater = '>';
|
||||
/// <summary>
|
||||
/// The equal sign.
|
||||
/// </summary>
|
||||
public const char Equal = '=';
|
||||
/// <summary>
|
||||
/// The period.
|
||||
/// </summary>
|
||||
public const char Period = '.';
|
||||
/// <summary>
|
||||
/// The semicolon.
|
||||
/// </summary>
|
||||
public const char Semicolon = ';';
|
||||
/// <summary>
|
||||
/// The colon.
|
||||
/// </summary>
|
||||
public const char Colon = ':';
|
||||
/// <summary>
|
||||
/// The slash.
|
||||
/// </summary>
|
||||
public const char Slash = '/';
|
||||
/// <summary>
|
||||
/// The bar character.
|
||||
/// </summary>
|
||||
public const char Bar = '|';
|
||||
/// <summary>
|
||||
/// The back slash.
|
||||
/// </summary>
|
||||
public const char BackSlash = '\\';
|
||||
/// <summary>
|
||||
/// The percent sign.
|
||||
/// </summary>
|
||||
public const char Percent = '%';
|
||||
/// <summary>
|
||||
/// The dollar sign.
|
||||
/// </summary>
|
||||
public const char Dollar = '$';
|
||||
/// <summary>
|
||||
/// The at sign.
|
||||
/// </summary>
|
||||
public const char At = '@';
|
||||
/// <summary>
|
||||
/// The number sign.
|
||||
/// </summary>
|
||||
public const char NumberSign = '#';
|
||||
/// <summary>
|
||||
/// The question mark.
|
||||
/// </summary>
|
||||
public const char Question = '?';
|
||||
/// <summary>
|
||||
/// The hyphen.
|
||||
/// </summary>
|
||||
public const char Hyphen = '-'; // char(45)
|
||||
/// <summary>
|
||||
/// The soft hyphen.
|
||||
/// </summary>
|
||||
public const char SoftHyphen = ''; // char(173)
|
||||
/// <summary>
|
||||
/// The currency sign.
|
||||
/// </summary>
|
||||
public const char Currency = '¤';
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
}
|
||||
+925
@@ -0,0 +1,925 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using PdfSharpCore.Internal;
|
||||
using PdfSharpCore.Pdf.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Lexical analyzer for PDF files. Technically a PDF file is a stream of bytes. Some chunks
|
||||
/// of bytes represent strings in several encodings. The actual encoding depends on the
|
||||
/// context where the string is used. Therefore the bytes are 'raw encoded' into characters,
|
||||
/// i.e. a character or token read by the lexer has always character values in the range from
|
||||
/// 0 to 255.
|
||||
/// </summary>
|
||||
public class Lexer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Lexer class.
|
||||
/// </summary>
|
||||
public Lexer(Stream pdfInputStream)
|
||||
{
|
||||
_pdfSteam = pdfInputStream;
|
||||
_pdfLength = _pdfSteam.Length;
|
||||
_idxChar = 0;
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the PDF stream.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get { return _idxChar; }
|
||||
set
|
||||
{
|
||||
_idxChar = value;
|
||||
_pdfSteam.Position = value;
|
||||
// ReadByte return -1 (eof) at the end of the stream.
|
||||
_currChar = (char)_pdfSteam.ReadByte();
|
||||
_nextChar = (char)_pdfSteam.ReadByte();
|
||||
_token = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next token and returns its type. If the token starts with a digit, the parameter
|
||||
/// testReference specifies how to treat it. If it is false, the lexer scans for a single integer.
|
||||
/// If it is true, the lexer checks if the digit is the prefix of a reference. If it is a reference,
|
||||
/// the token is set to the object ID followed by the generation number separated by a blank
|
||||
/// (the 'R' is omitted from the token).
|
||||
/// </summary>
|
||||
// /// <param name="testReference">Indicates whether to test the next token if it is a reference.</param>
|
||||
public Symbol ScanNextToken()
|
||||
{
|
||||
Again:
|
||||
_token = new StringBuilder();
|
||||
|
||||
char ch = MoveToNonWhiteSpace();
|
||||
switch (ch)
|
||||
{
|
||||
case '%':
|
||||
// Eat comments, the parser doesn't handle them
|
||||
//return symbol = ScanComment();
|
||||
ScanComment();
|
||||
goto Again;
|
||||
|
||||
case '/':
|
||||
return _symbol = ScanName();
|
||||
|
||||
//case 'R':
|
||||
// if (Lexer.IsWhiteSpace(nextChar))
|
||||
// {
|
||||
// ScanNextChar();
|
||||
// return Symbol.R;
|
||||
// }
|
||||
// break;
|
||||
|
||||
case '+': //TODO is it so easy?
|
||||
case '-':
|
||||
return _symbol = ScanNumber();
|
||||
|
||||
case '(':
|
||||
return _symbol = ScanLiteralString();
|
||||
|
||||
case '[':
|
||||
ScanNextChar(true);
|
||||
return _symbol = Symbol.BeginArray;
|
||||
|
||||
case ']':
|
||||
ScanNextChar(true);
|
||||
return _symbol = Symbol.EndArray;
|
||||
|
||||
case '<':
|
||||
if (_nextChar == '<')
|
||||
{
|
||||
ScanNextChar(true);
|
||||
ScanNextChar(true);
|
||||
return _symbol = Symbol.BeginDictionary;
|
||||
}
|
||||
return _symbol = ScanHexadecimalString();
|
||||
|
||||
case '>':
|
||||
if (_nextChar == '>')
|
||||
{
|
||||
ScanNextChar(true);
|
||||
ScanNextChar(true);
|
||||
return _symbol = Symbol.EndDictionary;
|
||||
}
|
||||
ParserDiagnostics.HandleUnexpectedCharacter(_nextChar);
|
||||
break;
|
||||
|
||||
case '.':
|
||||
return _symbol = ScanNumber();
|
||||
}
|
||||
if (char.IsDigit(ch))
|
||||
#if true_
|
||||
return ScanNumberOrReference();
|
||||
#else
|
||||
if (PeekReference())
|
||||
return _symbol = ScanNumber();
|
||||
else
|
||||
return _symbol = ScanNumber();
|
||||
#endif
|
||||
|
||||
if (char.IsLetter(ch))
|
||||
return _symbol = ScanKeyword();
|
||||
|
||||
if (ch == Chars.EOF)
|
||||
return _symbol = Symbol.Eof;
|
||||
|
||||
// #???
|
||||
|
||||
ParserDiagnostics.HandleUnexpectedCharacter(ch);
|
||||
return _symbol = Symbol.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the raw content of a stream.
|
||||
/// </summary>
|
||||
public byte[] ReadStream(int length)
|
||||
{
|
||||
var pos = MoveToStartOfStream();
|
||||
_pdfSteam.Position = pos;
|
||||
byte[] bytes = new byte[length];
|
||||
int read = _pdfSteam.Read(bytes, 0, length);
|
||||
Debug.Assert(read == length);
|
||||
|
||||
// Synchronize idxChar etc.
|
||||
Position = pos + length;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
internal long MoveToStartOfStream()
|
||||
{
|
||||
long pos;
|
||||
|
||||
// Skip illegal blanks behind «stream».
|
||||
while (_currChar == Chars.SP)
|
||||
ScanNextChar(true);
|
||||
|
||||
// Skip new line behind «stream».
|
||||
if (_currChar == Chars.CR)
|
||||
{
|
||||
if (_nextChar == Chars.LF)
|
||||
pos = _idxChar + 2;
|
||||
else
|
||||
pos = _idxChar + 1;
|
||||
}
|
||||
else
|
||||
pos = _idxChar + 1;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans the input stream for the specified marker.<br></br>
|
||||
/// Returns the bytes from the current position up to the start of the marker or the end of the stream.<br></br>
|
||||
/// The position of the input-stream is the byte right after the marker (if found) or the end of the stream.
|
||||
/// </summary>
|
||||
/// <param name="marker">The marker to scan for</param>
|
||||
/// <param name="markerFound">Receives a boolean that indicates whether the marker was found</param>
|
||||
/// <returns></returns>
|
||||
internal byte[] ScanUntilMarker(byte[] marker, out bool markerFound)
|
||||
{
|
||||
markerFound = false;
|
||||
var result = new List<byte>();
|
||||
while (true)
|
||||
{
|
||||
var markerIndex = 0;
|
||||
while (_currChar != Chars.EOF && _currChar != marker[markerIndex])
|
||||
{
|
||||
result.Add((byte)_currChar);
|
||||
ScanNextChar(false);
|
||||
}
|
||||
while (_currChar != Chars.EOF && markerIndex < marker.Length && _currChar == marker[markerIndex])
|
||||
{
|
||||
markerIndex++;
|
||||
ScanNextChar(false);
|
||||
}
|
||||
if (_currChar == Chars.EOF || markerIndex == marker.Length)
|
||||
{
|
||||
if (markerIndex == marker.Length)
|
||||
markerFound = true;
|
||||
break;
|
||||
}
|
||||
// only part of the marker was found, add to result and continue
|
||||
result.AddRange(marker.Take(markerIndex));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string in raw encoding.
|
||||
/// </summary>
|
||||
public string ReadRawString(long position, int length)
|
||||
{
|
||||
_pdfSteam.Position = position;
|
||||
byte[] bytes = new byte[length];
|
||||
_pdfSteam.Read(bytes, 0, length);
|
||||
return PdfEncoders.RawEncoding.GetString(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans a comment line.
|
||||
/// </summary>
|
||||
public Symbol ScanComment()
|
||||
{
|
||||
Debug.Assert(_currChar == Chars.Percent);
|
||||
|
||||
_token = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
char ch = AppendAndScanNextChar();
|
||||
if (ch == Chars.LF || ch == Chars.EOF)
|
||||
break;
|
||||
}
|
||||
// TODO: not correct
|
||||
if (_token.ToString().StartsWith("%%EOF"))
|
||||
return Symbol.Eof;
|
||||
return _symbol = Symbol.Comment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans a name.
|
||||
/// </summary>
|
||||
public Symbol ScanName()
|
||||
{
|
||||
Debug.Assert(_currChar == Chars.Slash);
|
||||
|
||||
_token = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
char ch = AppendAndScanNextChar();
|
||||
if (IsWhiteSpace(ch) || IsDelimiter(ch) || ch == Chars.EOF)
|
||||
return _symbol = Symbol.Name;
|
||||
|
||||
if (ch == '#')
|
||||
{
|
||||
ScanNextChar(true);
|
||||
char[] hex = new char[2];
|
||||
hex[0] = _currChar;
|
||||
hex[1] = _nextChar;
|
||||
ScanNextChar(true);
|
||||
// TODO Check syntax
|
||||
ch = (char)(ushort)int.Parse(new string(hex), NumberStyles.AllowHexSpecifier);
|
||||
_currChar = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans a number.
|
||||
/// </summary>
|
||||
public Symbol ScanNumber()
|
||||
{
|
||||
// I found a PDF file created with Acrobat 7 with this entry
|
||||
// /Checksum 2996984786
|
||||
// What is this? It is neither an integer nor a real.
|
||||
// I introduced an UInteger...
|
||||
bool period = false;
|
||||
//bool sign;
|
||||
|
||||
_token = new StringBuilder();
|
||||
char ch = _currChar;
|
||||
if (ch == '+' || ch == '-')
|
||||
{
|
||||
//sign = true;
|
||||
_token.Append(ch);
|
||||
ch = ScanNextChar(true);
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (char.IsDigit(ch))
|
||||
{
|
||||
_token.Append(ch);
|
||||
}
|
||||
else if (ch == '.')
|
||||
{
|
||||
if (period)
|
||||
ParserDiagnostics.ThrowParserException("More than one period in number.");
|
||||
|
||||
period = true;
|
||||
_token.Append(ch);
|
||||
}
|
||||
else
|
||||
break;
|
||||
ch = ScanNextChar(true);
|
||||
}
|
||||
|
||||
if (period)
|
||||
return Symbol.Real;
|
||||
long l = Int64.Parse(_token.ToString(), CultureInfo.InvariantCulture);
|
||||
if (l >= Int32.MinValue && l <= Int32.MaxValue)
|
||||
return Symbol.Integer;
|
||||
if (l >= Int64.MinValue && l <= Int64.MaxValue)
|
||||
return Symbol.Long;
|
||||
|
||||
// Got an AutoCAD PDF file that contains this: /C 264584027963392
|
||||
// Best we can do is to convert it to real value.
|
||||
return Symbol.Real;
|
||||
}
|
||||
|
||||
public Symbol ScanNumberOrReference()
|
||||
{
|
||||
Symbol result = ScanNumber();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans a keyword.
|
||||
/// </summary>
|
||||
public Symbol ScanKeyword()
|
||||
{
|
||||
_token = new StringBuilder();
|
||||
char ch = _currChar;
|
||||
// Scan token
|
||||
while (true)
|
||||
{
|
||||
if (char.IsLetter(ch))
|
||||
_token.Append(ch);
|
||||
else
|
||||
break;
|
||||
ch = ScanNextChar(false);
|
||||
}
|
||||
|
||||
// Check known tokens.
|
||||
switch (_token.ToString())
|
||||
{
|
||||
case "obj":
|
||||
return _symbol = Symbol.Obj;
|
||||
|
||||
case "endobj":
|
||||
return _symbol = Symbol.EndObj;
|
||||
|
||||
case "null":
|
||||
return _symbol = Symbol.Null;
|
||||
|
||||
case "true":
|
||||
case "false":
|
||||
return _symbol = Symbol.Boolean;
|
||||
|
||||
case "R":
|
||||
return _symbol = Symbol.R;
|
||||
|
||||
case "stream":
|
||||
return _symbol = Symbol.BeginStream;
|
||||
|
||||
case "endstream":
|
||||
return _symbol = Symbol.EndStream;
|
||||
|
||||
case "xref":
|
||||
return _symbol = Symbol.XRef;
|
||||
|
||||
case "trailer":
|
||||
return _symbol = Symbol.Trailer;
|
||||
|
||||
case "startxref":
|
||||
return _symbol = Symbol.StartXRef;
|
||||
}
|
||||
|
||||
// Anything else is treated as a keyword. Samples are f or n in iref.
|
||||
return _symbol = Symbol.Keyword;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans a literal string, contained between "(" and ")".
|
||||
/// </summary>
|
||||
public Symbol ScanLiteralString()
|
||||
{
|
||||
// Reference: 3.2.3 String Objects / Page 53
|
||||
// Reference: TABLE 3.32 String Types / Page 157
|
||||
|
||||
Debug.Assert(_currChar == Chars.ParenLeft);
|
||||
_token = new StringBuilder();
|
||||
int parenLevel = 0;
|
||||
char ch = ScanNextChar(false);
|
||||
|
||||
// Phase 1: deal with escape characters.
|
||||
while (ch != Chars.EOF)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '(':
|
||||
parenLevel++;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
if (parenLevel == 0)
|
||||
{
|
||||
ScanNextChar(false);
|
||||
// Is goto evil? We could move Phase 2 code here or create a subroutine for Phase 1.
|
||||
goto Phase2;
|
||||
}
|
||||
parenLevel--;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
{
|
||||
ch = ScanNextChar(false);
|
||||
switch (ch)
|
||||
{
|
||||
case 'n':
|
||||
ch = Chars.LF;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
ch = Chars.CR;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
ch = Chars.HT;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
ch = Chars.BS;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
ch = Chars.FF;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
ch = Chars.ParenLeft;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
ch = Chars.ParenRight;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
ch = Chars.BackSlash;
|
||||
break;
|
||||
|
||||
// AutoCAD PDFs my contain such strings: (\ )
|
||||
case ' ':
|
||||
ch = ' ';
|
||||
break;
|
||||
|
||||
case Chars.CR:
|
||||
case Chars.LF:
|
||||
ch = ScanNextChar(false);
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (char.IsDigit(ch)) // First octal character.
|
||||
{
|
||||
// Octal character code.
|
||||
if (ch >= '8')
|
||||
break; // Since the first possible octal character is not valid,
|
||||
// the backslash is ignored.
|
||||
|
||||
int n = ch - '0';
|
||||
if (char.IsDigit(_nextChar)) // Second octal character.
|
||||
{
|
||||
ch = ScanNextChar(false);
|
||||
if (ch >= '8')
|
||||
ParserDiagnostics.HandleUnexpectedCharacter(ch);
|
||||
|
||||
n = n * 8 + ch - '0';
|
||||
if (char.IsDigit(_nextChar)) // Third octal character.
|
||||
{
|
||||
ch = ScanNextChar(false);
|
||||
if (ch >= '8')
|
||||
ParserDiagnostics.HandleUnexpectedCharacter(ch);
|
||||
|
||||
n = n * 8 + ch - '0';
|
||||
}
|
||||
}
|
||||
ch = (char)n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_token.Append(ch);
|
||||
ch = ScanNextChar(false);
|
||||
}
|
||||
|
||||
// Phase 2: deal with UTF-16BE if necessary.
|
||||
// UTF-16BE Unicode strings start with U+FEFF ("þÿ"). There can be empty strings with UTF-16BE prefix.
|
||||
Phase2:
|
||||
if (_token.Length >= 2 && _token[0] == '\xFE' && _token[1] == '\xFF')
|
||||
{
|
||||
// Combine two ANSI characters to get one Unicode character.
|
||||
StringBuilder temp = _token;
|
||||
int length = temp.Length;
|
||||
if ((length & 1) == 1)
|
||||
{
|
||||
// TODO What does the PDF Reference say about this case? Assume (char)0 or treat the file as corrupted?
|
||||
temp.Append(0);
|
||||
++length;
|
||||
DebugBreak.Break();
|
||||
}
|
||||
_token = new StringBuilder();
|
||||
for (int i = 2; i < length; i += 2)
|
||||
{
|
||||
_token.Append((char)(256 * temp[i] + temp[i + 1]));
|
||||
}
|
||||
return _symbol = Symbol.UnicodeString;
|
||||
}
|
||||
// Adobe Reader also supports UTF-16LE.
|
||||
if (_token.Length >= 2 && _token[0] == '\xFF' && _token[1] == '\xFE')
|
||||
{
|
||||
// Combine two ANSI characters to get one Unicode character.
|
||||
StringBuilder temp = _token;
|
||||
int length = temp.Length;
|
||||
if ((length & 1) == 1)
|
||||
{
|
||||
// TODO What does the PDF Reference say about this case? Assume (char)0 or treat the file as corrupted?
|
||||
temp.Append(0);
|
||||
++length;
|
||||
DebugBreak.Break();
|
||||
}
|
||||
_token = new StringBuilder();
|
||||
for (int i = 2; i < length; i += 2)
|
||||
{
|
||||
_token.Append((char)(256 * temp[i + 1] + temp[i]));
|
||||
}
|
||||
return _symbol = Symbol.UnicodeString;
|
||||
}
|
||||
return _symbol = Symbol.String;
|
||||
}
|
||||
|
||||
public Symbol ScanHexadecimalString()
|
||||
{
|
||||
Debug.Assert(_currChar == Chars.Less);
|
||||
|
||||
_token = new StringBuilder();
|
||||
char[] hex = new char[2];
|
||||
ScanNextChar(true);
|
||||
while (true)
|
||||
{
|
||||
MoveToNonWhiteSpace();
|
||||
if (_currChar == '>')
|
||||
{
|
||||
ScanNextChar(true);
|
||||
break;
|
||||
}
|
||||
if (IsHexChar(_currChar))
|
||||
{
|
||||
hex[0] = _currChar;
|
||||
hex[1] = IsHexChar(_nextChar) ? _nextChar : ' ';
|
||||
int ch = int.Parse(new string(hex), NumberStyles.HexNumber);
|
||||
_token.Append(Convert.ToChar(ch));
|
||||
ScanNextChar(true);
|
||||
if (_currChar != '>')
|
||||
ScanNextChar(true);
|
||||
}
|
||||
else
|
||||
// prevent endless loop in case _currChar is neither '>' nor a hex-char nor whitespace
|
||||
ScanNextChar(true);
|
||||
}
|
||||
string chars = _token.ToString();
|
||||
int count = chars.Length;
|
||||
if (count > 2 && chars[0] == (char)0xFE && chars[1] == (char)0xFF)
|
||||
{
|
||||
Debug.Assert(count % 2 == 0);
|
||||
_token.Length = 0;
|
||||
for (int idx = 2; idx < count; idx += 2)
|
||||
_token.Append((char)(chars[idx] * 256 + chars[idx + 1]));
|
||||
return _symbol = Symbol.UnicodeHexString;
|
||||
}
|
||||
return _symbol = Symbol.HexString;
|
||||
}
|
||||
|
||||
internal static bool IsHexChar(char c)
|
||||
{
|
||||
return char.IsDigit(c) ||
|
||||
(c >= 'A' && c <= 'F') ||
|
||||
(c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move current position one character further in PDF stream.
|
||||
/// </summary>
|
||||
internal char ScanNextChar(bool handleCRLF)
|
||||
{
|
||||
if (_pdfLength <= _idxChar)
|
||||
{
|
||||
_currChar = Chars.EOF;
|
||||
_nextChar = Chars.EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currChar = _nextChar;
|
||||
_nextChar = (char)_pdfSteam.ReadByte();
|
||||
_idxChar++;
|
||||
if (handleCRLF && _currChar == Chars.CR)
|
||||
{
|
||||
if (_nextChar == Chars.LF)
|
||||
{
|
||||
// Treat CR LF as LF.
|
||||
_currChar = _nextChar;
|
||||
_nextChar = (char)_pdfSteam.ReadByte();
|
||||
_idxChar++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Treat single CR as LF.
|
||||
_currChar = Chars.LF;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _currChar;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Resets the current token to the empty string.
|
||||
///// </summary>
|
||||
//void ClearToken()
|
||||
//{
|
||||
// _token.Length = 0;
|
||||
//}
|
||||
|
||||
bool PeekReference()
|
||||
{
|
||||
// A Reference has the form "nnn mmm R". The implementation of the the parser used a
|
||||
// reduce/shift algorithm in the first place. But this case is the only one we need to
|
||||
// look ahead 3 tokens.
|
||||
var positon = Position;
|
||||
|
||||
// Skip digits.
|
||||
while (char.IsDigit(_currChar))
|
||||
ScanNextChar(true);
|
||||
|
||||
// Space expected.
|
||||
if (_currChar != Chars.SP)
|
||||
goto False;
|
||||
|
||||
// Skip spaces.
|
||||
while (_currChar == Chars.SP)
|
||||
ScanNextChar(true);
|
||||
|
||||
// Digit expected.
|
||||
if (!char.IsDigit(_currChar))
|
||||
goto False;
|
||||
|
||||
// Skip digits.
|
||||
while (char.IsDigit(_currChar))
|
||||
ScanNextChar(true);
|
||||
|
||||
// Space expected.
|
||||
if (_currChar != Chars.SP)
|
||||
goto False;
|
||||
|
||||
// Skip spaces.
|
||||
while (_currChar == Chars.SP)
|
||||
ScanNextChar(true);
|
||||
|
||||
// "R" expected.
|
||||
// We can ignore _nextChar because there is no other valid token that starts with an 'R'.
|
||||
if (_currChar != 'R')
|
||||
goto False;
|
||||
|
||||
Position = positon;
|
||||
return true;
|
||||
|
||||
False:
|
||||
Position = positon;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends current character to the token and reads next one.
|
||||
/// </summary>
|
||||
internal char AppendAndScanNextChar()
|
||||
{
|
||||
if (_currChar == Chars.EOF)
|
||||
ParserDiagnostics.ThrowParserException("Undetected EOF reached.");
|
||||
|
||||
_token.Append(_currChar);
|
||||
return ScanNextChar(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the current character is not a white space, the function immediately returns it.
|
||||
/// Otherwise the PDF cursor is moved forward to the first non-white space or EOF.
|
||||
/// White spaces are NUL, HT, LF, FF, CR, and SP.
|
||||
/// </summary>
|
||||
public char MoveToNonWhiteSpace()
|
||||
{
|
||||
while (_currChar != Chars.EOF)
|
||||
{
|
||||
switch (_currChar)
|
||||
{
|
||||
case Chars.NUL:
|
||||
case Chars.HT:
|
||||
case Chars.LF:
|
||||
case Chars.FF:
|
||||
case Chars.CR:
|
||||
case Chars.SP:
|
||||
ScanNextChar(true);
|
||||
break;
|
||||
|
||||
case (char)11:
|
||||
case (char)173:
|
||||
ScanNextChar(true);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return _currChar;
|
||||
}
|
||||
}
|
||||
return _currChar;
|
||||
}
|
||||
// #if DEBUG
|
||||
// public string SurroundingsOfCurrentPosition(bool hex)
|
||||
// {
|
||||
// const int range = 20;
|
||||
// int start = Math.Max(Position - range, 0);
|
||||
// int length = Math.Min(2 * range, PdfLength - start);
|
||||
// long posOld = _pdfSteam.Position;
|
||||
// _pdfSteam.Position = start;
|
||||
// byte[] bytes = new byte[length];
|
||||
// _pdfSteam.Read(bytes, 0, length);
|
||||
// _pdfSteam.Position = posOld;
|
||||
// string result = "";
|
||||
// if (hex)
|
||||
// {
|
||||
// for (int idx = 0; idx < length; idx++)
|
||||
// result += ((int)bytes[idx]).ToString("x2");
|
||||
// //result += string.Format("{0:", (int) bytes[idx]);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// for (int idx = 0; idx < length; idx++)
|
||||
// result += (char)bytes[idx];
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
// #endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current symbol.
|
||||
/// </summary>
|
||||
public Symbol Symbol
|
||||
{
|
||||
get { return _symbol; }
|
||||
set { _symbol = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current token.
|
||||
/// </summary>
|
||||
public string Token
|
||||
{
|
||||
get { return _token.ToString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets current token as boolean literal.
|
||||
/// </summary>
|
||||
public bool TokenToBoolean
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_token.ToString() == "true" || _token.ToString() == "false");
|
||||
return _token.ToString()[0] == 't';
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets current token as integer literal.
|
||||
/// </summary>
|
||||
public int TokenToInteger
|
||||
{
|
||||
get
|
||||
{
|
||||
//Debug.As sert(_token.ToString().IndexOf('.') == -1);
|
||||
return int.Parse(_token.ToString(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets current token as unsigned integer literal.
|
||||
/// </summary>
|
||||
public uint TokenToUInteger
|
||||
{
|
||||
get
|
||||
{
|
||||
//Debug.As sert(_token.ToString().IndexOf('.') == -1);
|
||||
return uint.Parse(_token.ToString(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
public long TokenToLong => long.Parse(_token.ToString(), CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>
|
||||
/// Interprets current token as real or integer literal.
|
||||
/// </summary>
|
||||
public double TokenToReal
|
||||
{
|
||||
get { return double.Parse(_token.ToString(), CultureInfo.InvariantCulture); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets current token as object ID.
|
||||
/// </summary>
|
||||
public PdfObjectID TokenToObjectID
|
||||
{
|
||||
get
|
||||
{
|
||||
string[] numbers = Token.Split('|');
|
||||
int objectNumber = Int32.Parse(numbers[0]);
|
||||
int generationNumber = Int32.Parse(numbers[1]);
|
||||
return new PdfObjectID(objectNumber, generationNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the specified character is a PDF white-space character.
|
||||
/// </summary>
|
||||
internal static bool IsWhiteSpace(char ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Chars.NUL: // 0 Null
|
||||
case Chars.HT: // 9 Horizontal Tab
|
||||
case Chars.LF: // 10 Line Feed
|
||||
case Chars.FF: // 12 Form Feed
|
||||
case Chars.CR: // 13 Carriage Return
|
||||
case Chars.SP: // 32 Space
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the specified character is a PDF delimiter character.
|
||||
/// </summary>
|
||||
internal static bool IsDelimiter(char ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '(':
|
||||
case ')':
|
||||
case '<':
|
||||
case '>':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '/':
|
||||
case '%':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the PDF output.
|
||||
/// </summary>
|
||||
public long PdfLength
|
||||
{
|
||||
get { return _pdfLength; }
|
||||
}
|
||||
|
||||
readonly long _pdfLength;
|
||||
long _idxChar;
|
||||
char _currChar;
|
||||
char _nextChar;
|
||||
StringBuilder _token;
|
||||
Symbol _symbol = Symbol.None;
|
||||
|
||||
readonly Stream _pdfSteam;
|
||||
}
|
||||
}
|
||||
+1838
File diff suppressed because it is too large
Load Diff
+632
@@ -0,0 +1,632 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using PdfSharpCore.Exceptions;
|
||||
using PdfSharpCore.Pdf.Advanced;
|
||||
using PdfSharpCore.Pdf.Security;
|
||||
using PdfSharpCore.Pdf.Internal;
|
||||
using PdfSharpCore.Internal;
|
||||
using PdfSharpCore.Pdf.IO.enums;
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates the arguments of the PdfPasswordProvider delegate.
|
||||
/// </summary>
|
||||
public class PdfPasswordProviderArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the password to open the document with.
|
||||
/// </summary>
|
||||
public string Password;
|
||||
|
||||
/// <summary>
|
||||
/// When set to true the PdfReader.Open function returns null indicating that no PdfDocument was created.
|
||||
/// </summary>
|
||||
public bool Abort;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegated used by the PdfReader.Open function to retrieve a password if the document is protected.
|
||||
/// </summary>
|
||||
public delegate void PdfPasswordProvider(PdfPasswordProviderArgs args);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the functionality for reading PDF documents.
|
||||
/// </summary>
|
||||
public static class PdfReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the file specified by its path is a PDF file by inspecting the first eight
|
||||
/// bytes of the data. If the file header has the form «%PDF-x.y» the function returns the version
|
||||
/// number as integer (e.g. 14 for PDF 1.4). If the file header is invalid or inaccessible
|
||||
/// for any reason, 0 is returned. The function never throws an exception.
|
||||
/// </summary>
|
||||
public static int TestPdfFile(string path)
|
||||
{
|
||||
FileStream stream = null;
|
||||
try
|
||||
{
|
||||
int pageNumber;
|
||||
string realPath = Drawing.XPdfForm.ExtractPageNumber(path, out pageNumber);
|
||||
if (File.Exists(realPath)) // prevent unwanted exceptions during debugging
|
||||
{
|
||||
stream = new FileStream(realPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
byte[] bytes = new byte[1024];
|
||||
stream.Read(bytes, 0, 1024);
|
||||
return GetPdfFileVersion(bytes);
|
||||
}
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified stream is a PDF file by inspecting the first eight
|
||||
/// bytes of the data. If the data begins with «%PDF-x.y» the function returns the version
|
||||
/// number as integer (e.g. 14 for PDF 1.4). If the data is invalid or inaccessible
|
||||
/// for any reason, 0 is returned. The function never throws an exception.
|
||||
/// </summary>
|
||||
public static int TestPdfFile(Stream stream)
|
||||
{
|
||||
long pos = -1;
|
||||
try
|
||||
{
|
||||
pos = stream.Position;
|
||||
byte[] bytes = new byte[1024];
|
||||
stream.Read(bytes, 0, 1024);
|
||||
return GetPdfFileVersion(bytes);
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pos != -1)
|
||||
stream.Position = pos;
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch { }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified data is a PDF file by inspecting the first eight
|
||||
/// bytes of the data. If the data begins with «%PDF-x.y» the function returns the version
|
||||
/// number as integer (e.g. 14 for PDF 1.4). If the data is invalid or inaccessible
|
||||
/// for any reason, 0 is returned. The function never throws an exception.
|
||||
/// </summary>
|
||||
public static int TestPdfFile(byte[] data)
|
||||
{
|
||||
return GetPdfFileVersion(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements scanning the PDF file version.
|
||||
/// </summary>
|
||||
///
|
||||
internal static int GetPdfFileVersion(byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Acrobat accepts headers like «%!PS-Adobe-N.n PDF-M.m»...
|
||||
string header = PdfEncoders.RawEncoding.GetString(bytes, 0, bytes.Length); // Encoding.ASCII.GetString(bytes);
|
||||
if (header[0] == '%' || header.IndexOf("%PDF", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
int ich = header.IndexOf("PDF-", StringComparison.Ordinal);
|
||||
if (ich > 0 && header[ich + 5] == '.')
|
||||
{
|
||||
char major = header[ich + 4];
|
||||
char minor = header[ich + 6];
|
||||
if (major >= '1' && major < '2' && minor >= '0' && minor <= '9')
|
||||
return (major - '0') * 10 + (minor - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch
|
||||
{ }
|
||||
|
||||
// If it doesn't work with the specified encoding ...
|
||||
try
|
||||
{
|
||||
// The file might be incorrectly encoded as ASCII
|
||||
string header = System.Text.Encoding.ASCII.GetString(bytes);
|
||||
if (header[0] == '%' || header.IndexOf("%PDF", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
int ich = header.IndexOf("PDF-", StringComparison.Ordinal);
|
||||
if (ich > 0 && header[ich + 5] == '.')
|
||||
{
|
||||
char major = header[ich + 4];
|
||||
char minor = header[ich + 6];
|
||||
if (major >= '1' && major < '2' && minor >= '0' && minor <= '9')
|
||||
return (major - '0') * 10 + (minor - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch { }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, PdfDocumentOpenMode openmode)
|
||||
{
|
||||
return Open(path, null, openmode, null, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, PdfDocumentOpenMode openmode, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(path, null, openmode, null, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, PdfDocumentOpenMode openmode, PdfPasswordProvider provider)
|
||||
{
|
||||
return Open(path, null, openmode, provider, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, PdfDocumentOpenMode openmode, PdfPasswordProvider provider, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(path, null, openmode, provider, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, string password, PdfDocumentOpenMode openmode)
|
||||
{
|
||||
return Open(path, password, openmode, null, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, string password, PdfDocumentOpenMode openmode, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(path, password, openmode, null, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider provider)
|
||||
{
|
||||
return Open(path, password, openmode, provider, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider provider, PdfReadAccuracy accuracy)
|
||||
{
|
||||
PdfDocument document;
|
||||
Stream stream = null;
|
||||
try
|
||||
{
|
||||
stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
document = Open(stream, password, openmode, provider, accuracy);
|
||||
if (document != null)
|
||||
{
|
||||
document._fullPath = Path.GetFullPath(path);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stream != null)
|
||||
stream.Dispose();
|
||||
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path)
|
||||
{
|
||||
return Open(path, null, PdfDocumentOpenMode.Modify, null, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(path, null, PdfDocumentOpenMode.Modify, null, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, string password)
|
||||
{
|
||||
return Open(path, password, PdfDocumentOpenMode.Modify, null, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(string path, string password, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(path, password, PdfDocumentOpenMode.Modify, null, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, PdfDocumentOpenMode openmode)
|
||||
{
|
||||
return Open(stream, null, openmode, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, PdfDocumentOpenMode openmode, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(stream, null, openmode, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider)
|
||||
{
|
||||
return Open(stream, null, openmode, passwordProvider, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(stream, null, openmode, passwordProvider, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode)
|
||||
{
|
||||
return Open(stream, password, openmode, null, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(stream, password, openmode, null, accuracy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider)
|
||||
{
|
||||
return Open(stream, password, openmode, passwordProvider, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider, PdfReadAccuracy accuracy)
|
||||
{
|
||||
PdfDocument document;
|
||||
try
|
||||
{
|
||||
Lexer lexer = new Lexer(stream);
|
||||
document = new PdfDocument(lexer);
|
||||
document._state |= DocumentState.Imported;
|
||||
document._openMode = openmode;
|
||||
document._fileSize = stream.Length;
|
||||
|
||||
// Get file version.
|
||||
byte[] header = new byte[1024];
|
||||
stream.Position = 0;
|
||||
stream.Read(header, 0, 1024);
|
||||
document._version = GetPdfFileVersion(header);
|
||||
if (document._version == 0)
|
||||
throw new InvalidOperationException(PSSR.InvalidPdf);
|
||||
|
||||
document._irefTable.IsUnderConstruction = true;
|
||||
Parser parser = new Parser(document);
|
||||
|
||||
// Read all trailers or cross-reference streams, but no objects.
|
||||
document._trailer = parser.ReadTrailer(accuracy);
|
||||
|
||||
if (document._trailer == null)
|
||||
ParserDiagnostics.ThrowParserException("Invalid PDF file: no trailer found.");
|
||||
|
||||
Debug.Assert(document._irefTable.IsUnderConstruction);
|
||||
document._irefTable.IsUnderConstruction = false;
|
||||
|
||||
// Is document encrypted?
|
||||
PdfReference xrefEncrypt = document._trailer.Elements[PdfTrailer.Keys.Encrypt] as PdfReference;
|
||||
if (xrefEncrypt != null)
|
||||
{
|
||||
//xrefEncrypt.Value = parser.ReadObject(null, xrefEncrypt.ObjectID, false);
|
||||
PdfObject encrypt = parser.ReadObject(null, xrefEncrypt.ObjectID, false, false);
|
||||
|
||||
encrypt.Reference = xrefEncrypt;
|
||||
xrefEncrypt.Value = encrypt;
|
||||
PdfStandardSecurityHandler securityHandler = document.SecurityHandler;
|
||||
TryAgain:
|
||||
PasswordValidity validity = securityHandler.ValidatePassword(password);
|
||||
if (validity == PasswordValidity.Invalid)
|
||||
{
|
||||
if (passwordProvider != null)
|
||||
{
|
||||
PdfPasswordProviderArgs args = new PdfPasswordProviderArgs();
|
||||
passwordProvider(args);
|
||||
if (args.Abort)
|
||||
return null;
|
||||
password = args.Password;
|
||||
goto TryAgain;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (password == null)
|
||||
throw new PdfReaderException(PSSR.PasswordRequired);
|
||||
else
|
||||
throw new PdfReaderException(PSSR.InvalidPassword);
|
||||
}
|
||||
}
|
||||
else if (validity == PasswordValidity.UserPassword && openmode == PdfDocumentOpenMode.Modify)
|
||||
{
|
||||
if (passwordProvider != null)
|
||||
{
|
||||
PdfPasswordProviderArgs args = new PdfPasswordProviderArgs();
|
||||
passwordProvider(args);
|
||||
if (args.Abort)
|
||||
return null;
|
||||
password = args.Password;
|
||||
goto TryAgain;
|
||||
}
|
||||
else
|
||||
throw new PdfReaderException(PSSR.OwnerPasswordRequired);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (password != null)
|
||||
{
|
||||
// Password specified but document is not encrypted.
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
PdfReference[] irefs2 = document._irefTable.AllReferences;
|
||||
int count2 = irefs2.Length;
|
||||
|
||||
// 3rd: Create iRefs for all compressed objects.
|
||||
Dictionary<int, object> objectStreams = new Dictionary<int, object>();
|
||||
for (int idx = 0; idx < count2; idx++)
|
||||
{
|
||||
PdfReference iref = irefs2[idx];
|
||||
PdfCrossReferenceStream xrefStream = iref.Value as PdfCrossReferenceStream;
|
||||
if (xrefStream != null)
|
||||
{
|
||||
for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++)
|
||||
{
|
||||
PdfCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2];
|
||||
// Is type xref to compressed object?
|
||||
if (item.Type == 2)
|
||||
{
|
||||
//PdfReference irefNew = parser.ReadCompressedObject(new PdfObjectID((int)item.Field2), (int)item.Field3);
|
||||
//document._irefTable.Add(irefNew);
|
||||
int objectNumber = (int)item.Field2;
|
||||
if (!objectStreams.ContainsKey(objectNumber))
|
||||
{
|
||||
objectStreams.Add(objectNumber, null);
|
||||
PdfObjectID objectID = new PdfObjectID((int)item.Field2);
|
||||
parser.ReadIRefsFromCompressedObject(objectID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4th: Read compressed objects.
|
||||
for (int idx = 0; idx < count2; idx++)
|
||||
{
|
||||
PdfReference iref = irefs2[idx];
|
||||
PdfCrossReferenceStream xrefStream = iref.Value as PdfCrossReferenceStream;
|
||||
if (xrefStream != null)
|
||||
{
|
||||
for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++)
|
||||
{
|
||||
PdfCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2];
|
||||
// Is type xref to compressed object?
|
||||
if (item.Type == 2)
|
||||
{
|
||||
PdfReference irefNew = parser.ReadCompressedObject(new PdfObjectID((int)item.Field2),
|
||||
(int)item.Field3);
|
||||
Debug.Assert(document._irefTable.Contains(iref.ObjectID));
|
||||
//document._irefTable.Add(irefNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PdfReference[] irefs = document._irefTable.AllReferences;
|
||||
int count = irefs.Length;
|
||||
|
||||
// Read all indirect objects.
|
||||
for (int idx = 0; idx < count; idx++)
|
||||
{
|
||||
PdfReference iref = irefs[idx];
|
||||
if (iref.Value == null)
|
||||
{
|
||||
#if DEBUG_
|
||||
if (iref.ObjectNumber == 1074)
|
||||
iref.GetType();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
Debug.Assert(document._irefTable.Contains(iref.ObjectID));
|
||||
PdfObject pdfObject = parser.ReadObject(null, iref.ObjectID, false, false);
|
||||
Debug.Assert(pdfObject.Reference == iref);
|
||||
pdfObject.Reference = iref;
|
||||
Debug.Assert(pdfObject.Reference.Value != null, "Something went wrong.");
|
||||
}
|
||||
catch (PositionNotFoundException ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
|
||||
if (accuracy == PdfReadAccuracy.Strict)
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
// 4STLA rethrow exception to notify caller.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(document._irefTable.Contains(iref.ObjectID));
|
||||
//iref.GetType();
|
||||
}
|
||||
// Set maximum object number.
|
||||
document._irefTable._maxObjectNumber = Math.Max(document._irefTable._maxObjectNumber,
|
||||
iref.ObjectNumber);
|
||||
}
|
||||
|
||||
// Encrypt all objects.
|
||||
if (xrefEncrypt != null)
|
||||
{
|
||||
document.SecurityHandler.EncryptDocument();
|
||||
}
|
||||
|
||||
// Fix references of trailer values and then objects and irefs are consistent.
|
||||
document._trailer.Finish();
|
||||
|
||||
#if DEBUG_
|
||||
// Some tests...
|
||||
PdfReference[] reachables = document.xrefTable.TransitiveClosure(document.trailer);
|
||||
reachables.GetType();
|
||||
reachables = document.xrefTable.AllXRefs;
|
||||
document.xrefTable.CheckConsistence();
|
||||
#endif
|
||||
|
||||
if (openmode == PdfDocumentOpenMode.Modify)
|
||||
{
|
||||
// Create new or change existing document IDs.
|
||||
if (document.Internals.SecondDocumentID == "")
|
||||
document._trailer.CreateNewDocumentIDs();
|
||||
else
|
||||
{
|
||||
byte[] agTemp = Guid.NewGuid().ToByteArray();
|
||||
document.Internals.SecondDocumentID = PdfEncoders.RawEncoding.GetString(agTemp, 0, agTemp.Length);
|
||||
}
|
||||
|
||||
// KillerPDF patch: do NOT stamp /ModDate just because the file was OPENED in
|
||||
// Modify mode. PDF/A (ISO 19005-1, 6.7.3 t8) requires /ModDate to stay
|
||||
// equivalent to the XMP xmp:ModifyDate, and rewriting it here desynced every
|
||||
// opened file before a single edit was made.
|
||||
// document.Info.ModificationDate = DateTime.Now;
|
||||
|
||||
// Remove all unreachable objects
|
||||
int removed = document._irefTable.Compact();
|
||||
if (removed != 0)
|
||||
Debug.WriteLine("Number of deleted unreachable objects: " + removed);
|
||||
|
||||
// Force flattening of page tree
|
||||
PdfPages pages = document.Pages;
|
||||
Debug.Assert(pages != null);
|
||||
|
||||
//bool b = document.irefTable.Contains(new PdfObjectID(1108));
|
||||
//b.GetType();
|
||||
|
||||
document._irefTable.CheckConsistence();
|
||||
document._irefTable.Renumber();
|
||||
document._irefTable.CheckConsistence();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
throw;
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream)
|
||||
{
|
||||
return Open(stream, PdfDocumentOpenMode.Modify, PdfReadAccuracy.Strict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing PDF document.
|
||||
/// </summary>
|
||||
public static PdfDocument Open(Stream stream, PdfReadAccuracy accuracy)
|
||||
{
|
||||
return Open(stream, PdfDocumentOpenMode.Modify, accuracy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception thrown by PdfReader.
|
||||
/// </summary>
|
||||
public class PdfReaderException : PdfSharpException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PdfReaderException"/> class.
|
||||
/// </summary>
|
||||
public PdfReaderException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PdfReaderException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
public PdfReaderException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PdfReaderException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <param name="innerException">The inner exception.</param>
|
||||
public PdfReaderException(string message, Exception innerException)
|
||||
:
|
||||
base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
+656
@@ -0,0 +1,656 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using PdfSharpCore.Pdf.Advanced;
|
||||
using PdfSharpCore.Pdf.Security;
|
||||
using PdfSharpCore.Pdf.Internal;
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a writer for generation of PDF streams.
|
||||
/// </summary>
|
||||
internal class PdfWriter
|
||||
{
|
||||
public PdfWriter(Stream pdfStream, PdfStandardSecurityHandler securityHandler)
|
||||
{
|
||||
_stream = pdfStream;
|
||||
_securityHandler = securityHandler;
|
||||
//System.Xml.XmlTextWriter
|
||||
// KillerPDF patch: never default to Verbose layout in DEBUG builds. Verbose sprinkles
|
||||
// comments and loose token spacing through the output, which violates PDF/A object
|
||||
// syntax rules (ISO 19005-1, 6.1.8) - a Debug-built KillerPDF must write the same
|
||||
// conformant bytes a Release build writes.
|
||||
}
|
||||
|
||||
public void Close(bool closeUnderlyingStream)
|
||||
{
|
||||
if (_stream != null && closeUnderlyingStream)
|
||||
_stream.Dispose();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Close(true);
|
||||
}
|
||||
|
||||
public long Position
|
||||
{
|
||||
get { return _stream.Position; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the kind of layout.
|
||||
/// </summary>
|
||||
public PdfWriterLayout Layout
|
||||
{
|
||||
get { return _layout; }
|
||||
set { _layout = value; }
|
||||
}
|
||||
PdfWriterLayout _layout;
|
||||
|
||||
public PdfWriterOptions Options
|
||||
{
|
||||
get { return _options; }
|
||||
set { _options = value; }
|
||||
}
|
||||
PdfWriterOptions _options;
|
||||
|
||||
// -----------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(bool value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
// KillerPDF patch: bool.TrueString/FalseString are "True"/"False", which are NOT
|
||||
// valid PDF boolean keywords (ISO 32000 7.3.2 requires lowercase). This corrupted
|
||||
// indirect boolean objects (e.g. "42 0 obj True endobj") on resave.
|
||||
WriteRaw(value ? "true" : "false");
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfBoolean value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.Value ? "true" : "false");
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(int value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.ToString(CultureInfo.InvariantCulture));
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(long value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.ToString(CultureInfo.InvariantCulture));
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(uint value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.ToString(CultureInfo.InvariantCulture));
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfInteger value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
_lastCat = CharCat.Character;
|
||||
WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfLong value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
_lastCat = CharCat.Character;
|
||||
WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfUInteger value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
_lastCat = CharCat.Character;
|
||||
WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(double value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.ToString(Config.SignificantFigures7, CultureInfo.InvariantCulture));
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfReal value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.Value.ToString(Config.SignificantFigures7, CultureInfo.InvariantCulture));
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfString value)
|
||||
{
|
||||
WriteSeparator(CharCat.Delimiter);
|
||||
PdfStringEncoding encoding = (PdfStringEncoding)(value.Flags & PdfStringFlags.EncodingMask);
|
||||
string pdf = (value.Flags & PdfStringFlags.HexLiteral) == 0 ?
|
||||
PdfEncoders.ToStringLiteral(value.EncryptionValue, encoding == PdfStringEncoding.Unicode, SecurityHandler) :
|
||||
PdfEncoders.ToHexStringLiteral(value.EncryptionValue, encoding == PdfStringEncoding.Unicode, SecurityHandler);
|
||||
WriteRaw(pdf);
|
||||
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value to the PDF stream.
|
||||
/// </summary>
|
||||
public void Write(PdfName value)
|
||||
{
|
||||
WriteSeparator(CharCat.Delimiter, '/');
|
||||
string name = value.Value;
|
||||
|
||||
StringBuilder pdf = new StringBuilder("/");
|
||||
for (int idx = 1; idx < name.Length; idx++)
|
||||
{
|
||||
char ch = name[idx];
|
||||
Debug.Assert(ch < 256);
|
||||
if (ch > ' ')
|
||||
switch (ch)
|
||||
{
|
||||
// TODO: is this all?
|
||||
case '%':
|
||||
case '/':
|
||||
case '<':
|
||||
case '>':
|
||||
case '(':
|
||||
case ')':
|
||||
case '#':
|
||||
break;
|
||||
|
||||
default:
|
||||
pdf.Append(name[idx]);
|
||||
continue;
|
||||
}
|
||||
pdf.AppendFormat("#{0:X2}", (int)name[idx]);
|
||||
}
|
||||
WriteRaw(pdf.ToString());
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
public void Write(PdfLiteral value)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(value.Value);
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
public void Write(PdfRectangle rect)
|
||||
{
|
||||
const string format = Config.SignificantFigures3;
|
||||
WriteSeparator(CharCat.Delimiter, '/');
|
||||
WriteRaw(PdfEncoders.Format("[{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}]", rect.X1, rect.Y1, rect.X2, rect.Y2));
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
|
||||
public void Write(PdfReference iref)
|
||||
{
|
||||
WriteSeparator(CharCat.Character);
|
||||
WriteRaw(iref.ToString());
|
||||
_lastCat = CharCat.Character;
|
||||
}
|
||||
|
||||
public void WriteDocString(string text, bool unicode)
|
||||
{
|
||||
WriteSeparator(CharCat.Delimiter);
|
||||
//WriteRaw(PdfEncoders.DocEncode(text, unicode));
|
||||
byte[] bytes;
|
||||
if (!unicode)
|
||||
bytes = PdfEncoders.DocEncoding.GetBytes(text);
|
||||
else
|
||||
bytes = PdfEncoders.UnicodeEncoding.GetBytes(text);
|
||||
bytes = PdfEncoders.FormatStringLiteral(bytes, unicode, true, false, _securityHandler);
|
||||
Write(bytes);
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
|
||||
public void WriteDocString(string text)
|
||||
{
|
||||
WriteSeparator(CharCat.Delimiter);
|
||||
//WriteRaw(PdfEncoders.DocEncode(text, false));
|
||||
byte[] bytes = PdfEncoders.DocEncoding.GetBytes(text);
|
||||
bytes = PdfEncoders.FormatStringLiteral(bytes, false, false, false, _securityHandler);
|
||||
Write(bytes);
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
|
||||
public void WriteDocStringHex(string text)
|
||||
{
|
||||
WriteSeparator(CharCat.Delimiter);
|
||||
//WriteRaw(PdfEncoders.DocEncodeHex(text));
|
||||
byte[] bytes = PdfEncoders.DocEncoding.GetBytes(text);
|
||||
bytes = PdfEncoders.FormatStringLiteral(bytes, false, false, true, _securityHandler);
|
||||
_stream.Write(bytes, 0, bytes.Length);
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins a direct or indirect dictionary or array.
|
||||
/// </summary>
|
||||
public void WriteBeginObject(PdfObject obj)
|
||||
{
|
||||
bool indirect = obj.IsIndirect;
|
||||
if (indirect)
|
||||
{
|
||||
WriteObjectAddress(obj);
|
||||
if (_securityHandler != null)
|
||||
_securityHandler.SetHashKey(obj.ObjectID);
|
||||
}
|
||||
_stack.Add(new StackItem(obj));
|
||||
if (indirect)
|
||||
{
|
||||
if (obj is PdfArray)
|
||||
WriteRaw("[\n");
|
||||
else if (obj is PdfDictionary)
|
||||
WriteRaw("<<\n");
|
||||
_lastCat = CharCat.NewLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj is PdfArray)
|
||||
{
|
||||
WriteSeparator(CharCat.Delimiter);
|
||||
WriteRaw('[');
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
else if (obj is PdfDictionary)
|
||||
{
|
||||
NewLine();
|
||||
WriteSeparator(CharCat.Delimiter);
|
||||
WriteRaw("<<\n");
|
||||
_lastCat = CharCat.NewLine;
|
||||
}
|
||||
}
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
IncreaseIndent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends a direct or indirect dictionary or array.
|
||||
/// </summary>
|
||||
public void WriteEndObject()
|
||||
{
|
||||
int count = _stack.Count;
|
||||
Debug.Assert(count > 0, "PdfWriter stack underflow.");
|
||||
|
||||
StackItem stackItem = _stack[count - 1];
|
||||
_stack.RemoveAt(count - 1);
|
||||
|
||||
PdfObject value = stackItem.Object;
|
||||
bool indirect = value.IsIndirect;
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
DecreaseIndent();
|
||||
if (value is PdfArray)
|
||||
{
|
||||
if (indirect)
|
||||
{
|
||||
WriteRaw("\n]\n");
|
||||
_lastCat = CharCat.NewLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRaw("]");
|
||||
_lastCat = CharCat.Delimiter;
|
||||
}
|
||||
}
|
||||
else if (value is PdfDictionary)
|
||||
{
|
||||
if (indirect)
|
||||
{
|
||||
if (!stackItem.HasStream)
|
||||
WriteRaw(_lastCat == CharCat.NewLine ? ">>\n" : " >>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(!stackItem.HasStream, "Direct object with stream??");
|
||||
WriteSeparator(CharCat.NewLine);
|
||||
WriteRaw(">>\n");
|
||||
_lastCat = CharCat.NewLine;
|
||||
}
|
||||
}
|
||||
if (indirect)
|
||||
{
|
||||
NewLine();
|
||||
WriteRaw("endobj\n");
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
WriteRaw("%--------------------------------------------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the stream of the specified dictionary.
|
||||
/// </summary>
|
||||
public void WriteStream(PdfDictionary value, bool omitStream)
|
||||
{
|
||||
StackItem stackItem = _stack[_stack.Count - 1];
|
||||
Debug.Assert(stackItem.Object is PdfDictionary);
|
||||
Debug.Assert(stackItem.Object.IsIndirect);
|
||||
stackItem.HasStream = true;
|
||||
|
||||
WriteRaw(_lastCat == CharCat.NewLine ? ">>\nstream\n" : " >>\nstream\n");
|
||||
|
||||
if (omitStream)
|
||||
{
|
||||
WriteRaw(" �...stream content omitted...�\n"); // useful for debugging only
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] bytes = value.Stream.Value;
|
||||
if (bytes.Length != 0)
|
||||
{
|
||||
if (_securityHandler != null)
|
||||
{
|
||||
bytes = (byte[])bytes.Clone();
|
||||
bytes = _securityHandler.EncryptBytes(bytes);
|
||||
}
|
||||
Write(bytes);
|
||||
}
|
||||
// KillerPDF patch: ALWAYS write an explicit LF between the stream data and
|
||||
// 'endstream' - INCLUDING for zero-length streams. The old conditional skipped
|
||||
// it when the data ended in a newline byte (that byte then doubled as the EOL
|
||||
// marker), and empty streams got no EOL at all ("stream\nendstream"), so /Length
|
||||
// no longer matched ISO 19005's byte count (6.1.7: the bytes between the LF
|
||||
// after 'stream' and the EOL before 'endstream'). The spec-blessed form is
|
||||
// stream + LF + data + EOL + endstream, with both markers excluded from /Length;
|
||||
// a compliant empty stream is "stream\n\nendstream".
|
||||
WriteRaw('\n');
|
||||
}
|
||||
WriteRaw("endstream\n");
|
||||
}
|
||||
|
||||
public void WriteRaw(string rawString)
|
||||
{
|
||||
if (String.IsNullOrEmpty(rawString))
|
||||
return;
|
||||
|
||||
byte[] bytes = PdfEncoders.RawEncoding.GetBytes(rawString);
|
||||
_stream.Write(bytes, 0, bytes.Length);
|
||||
_lastCat = GetCategory((char)bytes[bytes.Length - 1]);
|
||||
}
|
||||
|
||||
public void WriteRaw(char ch)
|
||||
{
|
||||
Debug.Assert(ch < 256, "Raw character greater than 255 detected.");
|
||||
|
||||
_stream.WriteByte((byte)ch);
|
||||
_lastCat = GetCategory(ch);
|
||||
}
|
||||
|
||||
public void Write(byte[] bytes)
|
||||
{
|
||||
if (bytes == null || bytes.Length == 0)
|
||||
return;
|
||||
|
||||
_stream.Write(bytes, 0, bytes.Length);
|
||||
_lastCat = GetCategory((char)bytes[bytes.Length - 1]);
|
||||
}
|
||||
|
||||
void WriteObjectAddress(PdfObject value)
|
||||
{
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
WriteRaw(String.Format("{0} {1} obj % {2}\n",
|
||||
value.ObjectID.ObjectNumber, value.ObjectID.GenerationNumber,
|
||||
value.GetType().FullName));
|
||||
else
|
||||
WriteRaw(String.Format("{0} {1} obj\n", value.ObjectID.ObjectNumber, value.ObjectID.GenerationNumber));
|
||||
}
|
||||
|
||||
public void WriteFileHeader(PdfDocument document)
|
||||
{
|
||||
StringBuilder header = new StringBuilder("%PDF-");
|
||||
int version = document._version;
|
||||
header.Append((version / 10).ToString(CultureInfo.InvariantCulture) + "." +
|
||||
(version % 10).ToString(CultureInfo.InvariantCulture) + "\n%\xD3\xF4\xCC\xE1\n");
|
||||
WriteRaw(header.ToString());
|
||||
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
{
|
||||
WriteRaw(String.Format("% PDFsharp Version {0} (verbose mode)\n", VersionInfo.Version));
|
||||
// Keep some space for later fix-up.
|
||||
_commentPosition = (int)_stream.Position + 2;
|
||||
WriteRaw("% \n");
|
||||
WriteRaw("% \n");
|
||||
WriteRaw("% \n");
|
||||
WriteRaw("% \n");
|
||||
WriteRaw("% \n");
|
||||
WriteRaw("%--------------------------------------------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteEof(PdfDocument document, long startxref)
|
||||
{
|
||||
WriteRaw("startxref\n");
|
||||
WriteRaw(startxref.ToString(CultureInfo.InvariantCulture));
|
||||
WriteRaw("\n%%EOF\n");
|
||||
var fileSize = _stream.Position;
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
{
|
||||
TimeSpan duration = DateTime.Now - document._creation;
|
||||
|
||||
_stream.Position = _commentPosition;
|
||||
// Without InvariantCulture parameter the following line fails if the current culture is e.g.
|
||||
// a Far East culture, because the date string contains non-ASCII characters.
|
||||
// So never never never never use ToString without a culture info.
|
||||
WriteRaw("Creation date: " + document._creation.ToString("G", CultureInfo.InvariantCulture));
|
||||
_stream.Position = _commentPosition + 50;
|
||||
WriteRaw("Creation time: " + duration.TotalSeconds.ToString("0.000", CultureInfo.InvariantCulture) + " seconds");
|
||||
_stream.Position = _commentPosition + 100;
|
||||
WriteRaw("File size: " + fileSize.ToString(CultureInfo.InvariantCulture) + " bytes");
|
||||
_stream.Position = _commentPosition + 150;
|
||||
WriteRaw("Pages: " + document.Pages.Count.ToString(CultureInfo.InvariantCulture));
|
||||
_stream.Position = _commentPosition + 200;
|
||||
WriteRaw("Objects: " + document._irefTable.ObjectTable.Count.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indentation for a new indentation level.
|
||||
/// </summary>
|
||||
internal int Indent
|
||||
{
|
||||
get { return _indent; }
|
||||
set { _indent = value; }
|
||||
}
|
||||
int _indent = 2;
|
||||
int _writeIndent;
|
||||
|
||||
/// <summary>
|
||||
/// Increases indent level.
|
||||
/// </summary>
|
||||
void IncreaseIndent()
|
||||
{
|
||||
_writeIndent += _indent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decreases indent level.
|
||||
/// </summary>
|
||||
void DecreaseIndent()
|
||||
{
|
||||
_writeIndent -= _indent;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Returns an indent string of blanks.
|
||||
///// </summary>
|
||||
//static string Ind(int _indent)
|
||||
//{
|
||||
// return new String(' ', _indent);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indent string of current indent.
|
||||
/// </summary>
|
||||
string IndentBlanks
|
||||
{
|
||||
get { return new string(' ', _writeIndent); }
|
||||
}
|
||||
|
||||
void WriteIndent()
|
||||
{
|
||||
WriteRaw(IndentBlanks);
|
||||
}
|
||||
|
||||
void WriteSeparator(CharCat cat, char ch)
|
||||
{
|
||||
switch (_lastCat)
|
||||
{
|
||||
case CharCat.NewLine:
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
WriteIndent();
|
||||
break;
|
||||
|
||||
case CharCat.Delimiter:
|
||||
break;
|
||||
|
||||
case CharCat.Character:
|
||||
if (_layout == PdfWriterLayout.Verbose)
|
||||
{
|
||||
//if (cat == CharCat.Character || ch == '/')
|
||||
_stream.WriteByte((byte)' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (cat == CharCat.Character)
|
||||
_stream.WriteByte((byte)' ');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSeparator(CharCat cat)
|
||||
{
|
||||
WriteSeparator(cat, '\0');
|
||||
}
|
||||
|
||||
public void NewLine()
|
||||
{
|
||||
if (_lastCat != CharCat.NewLine)
|
||||
WriteRaw('\n');
|
||||
}
|
||||
|
||||
CharCat GetCategory(char ch)
|
||||
{
|
||||
if (Lexer.IsDelimiter(ch))
|
||||
return CharCat.Delimiter;
|
||||
if (ch == Chars.LF)
|
||||
return CharCat.NewLine;
|
||||
return CharCat.Character;
|
||||
}
|
||||
|
||||
enum CharCat
|
||||
{
|
||||
NewLine,
|
||||
Character,
|
||||
Delimiter,
|
||||
};
|
||||
CharCat _lastCat;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying stream.
|
||||
/// </summary>
|
||||
internal Stream Stream
|
||||
{
|
||||
get { return _stream; }
|
||||
}
|
||||
Stream _stream;
|
||||
|
||||
internal PdfStandardSecurityHandler SecurityHandler
|
||||
{
|
||||
get { return _securityHandler; }
|
||||
set { _securityHandler = value; }
|
||||
}
|
||||
PdfStandardSecurityHandler _securityHandler;
|
||||
|
||||
class StackItem
|
||||
{
|
||||
public StackItem(PdfObject value)
|
||||
{
|
||||
Object = value;
|
||||
}
|
||||
|
||||
public readonly PdfObject Object;
|
||||
public bool HasStream;
|
||||
}
|
||||
|
||||
readonly List<StackItem> _stack = new List<StackItem>();
|
||||
int _commentPosition;
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the stack for the shift-reduce parser. It seems that it is only needed for
|
||||
/// reduction of indirect references.
|
||||
/// </summary>
|
||||
internal class ShiftStack
|
||||
{
|
||||
// TODO: make Lexer.PeekChars(20) and scan for 'R' to detect indirect references
|
||||
|
||||
public ShiftStack()
|
||||
{
|
||||
_items = new List<PdfItem>();
|
||||
}
|
||||
|
||||
public PdfItem[] ToArray(int start, int length)
|
||||
{
|
||||
PdfItem[] items = new PdfItem[length];
|
||||
for (int i = 0, j = start; i < length; i++, j++)
|
||||
items[i] = _items[j];
|
||||
return items;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stack pointer index.
|
||||
/// </summary>
|
||||
// ReSharper disable InconsistentNaming
|
||||
public int SP
|
||||
// ReSharper restore InconsistentNaming
|
||||
{
|
||||
get { return _sp; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value at the specified index. Valid index is in range 0 up to sp-1.
|
||||
/// </summary>
|
||||
public PdfItem this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index >= _sp)
|
||||
throw new ArgumentOutOfRangeException("index", index, "Value greater than stack index.");
|
||||
return _items[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an item relative to the current stack pointer. The index must be a negative value (-1, -2, etc.).
|
||||
/// </summary>
|
||||
public PdfItem GetItem(int relativeIndex)
|
||||
{
|
||||
if (relativeIndex >= 0 || -relativeIndex > _sp)
|
||||
throw new ArgumentOutOfRangeException("relativeIndex", relativeIndex, "Value out of stack range.");
|
||||
return _items[_sp + relativeIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an item relative to the current stack pointer. The index must be a negative value (-1, -2, etc.).
|
||||
/// </summary>
|
||||
public int GetInteger(int relativeIndex)
|
||||
{
|
||||
if (relativeIndex >= 0 || -relativeIndex > _sp)
|
||||
throw new ArgumentOutOfRangeException("relativeIndex", relativeIndex, "Value out of stack range.");
|
||||
return ((PdfInteger)_items[_sp + relativeIndex]).Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes the specified item onto the stack.
|
||||
/// </summary>
|
||||
public void Shift(PdfItem item)
|
||||
{
|
||||
Debug.Assert(item != null);
|
||||
_items.Add(item);
|
||||
_sp++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the last 'count' items with the specified item.
|
||||
/// </summary>
|
||||
public void Reduce(int count)
|
||||
{
|
||||
if (count > _sp)
|
||||
throw new ArgumentException("count causes stack underflow.");
|
||||
_items.RemoveRange(_sp - count, count);
|
||||
_sp -= count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the last 'count' items with the specified item.
|
||||
/// </summary>
|
||||
public void Reduce(PdfItem item, int count)
|
||||
{
|
||||
Debug.Assert(item != null);
|
||||
Reduce(count);
|
||||
_items.Add(item);
|
||||
_sp++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The stack pointer index. Points to the next free item.
|
||||
/// </summary>
|
||||
int _sp;
|
||||
|
||||
/// <summary>
|
||||
/// An array representing the stack.
|
||||
/// </summary>
|
||||
readonly List<PdfItem> _items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the type of the password.
|
||||
/// </summary>
|
||||
public enum PasswordValidity
|
||||
{
|
||||
/// <summary>
|
||||
/// Password is neither user nor owner password.
|
||||
/// </summary>
|
||||
Invalid,
|
||||
|
||||
/// <summary>
|
||||
/// Password is user password.
|
||||
/// </summary>
|
||||
UserPassword,
|
||||
|
||||
/// <summary>
|
||||
/// Password is owner password.
|
||||
/// </summary>
|
||||
OwnerPassword,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines how a PDF document is opened.
|
||||
/// </summary>
|
||||
public enum PdfDocumentOpenMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The PDF stream is completely read into memory and can be modified. Pages can be deleted or
|
||||
/// inserted, but it is not possible to extract pages. This mode is useful for modifying an
|
||||
/// existing PDF document.
|
||||
/// </summary>
|
||||
Modify,
|
||||
|
||||
/// <summary>
|
||||
/// The PDF stream is opened for importing pages from it. A document opened in this mode cannot
|
||||
/// be modified.
|
||||
/// </summary>
|
||||
Import,
|
||||
|
||||
/// <summary>
|
||||
/// The PDF stream is completely read into memory, but cannot be modified. This mode preserves the
|
||||
/// original internal structure of the document and is useful for analyzing existing PDF files.
|
||||
/// </summary>
|
||||
ReadOnly,
|
||||
|
||||
/// <summary>
|
||||
/// The PDF stream is partially read for information purposes only. The only valid operation is to
|
||||
/// call the Info property at the imported document. This option is very fast and needs less memory
|
||||
/// and is e.g. useful for browsing information about a collection of PDF documents in a user interface.
|
||||
/// </summary>
|
||||
InformationOnly, // TODO: not yet implemented
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace PdfSharpCore.Pdf.IO.enums
|
||||
{
|
||||
public enum PdfReadAccuracy
|
||||
{
|
||||
Strict,
|
||||
Moderate
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines how the PDF output stream is formatted. Even all formats create valid PDF files,
|
||||
/// only Compact or Standard should be used for production purposes.
|
||||
/// </summary>
|
||||
public enum PdfWriterLayout
|
||||
{
|
||||
/// <summary>
|
||||
/// The PDF stream contains no unnecessary characters. This is default in release build.
|
||||
/// </summary>
|
||||
Compact,
|
||||
|
||||
/// <summary>
|
||||
/// The PDF stream contains some superfluous line feeds, but is more readable.
|
||||
/// </summary>
|
||||
Standard,
|
||||
|
||||
/// <summary>
|
||||
/// The PDF stream is indented to reflect the nesting levels of the objects. This is useful
|
||||
/// for analyzing PDF files, but increases the size of the file significantly.
|
||||
/// </summary>
|
||||
Indented,
|
||||
|
||||
/// <summary>
|
||||
/// The PDF stream is indented to reflect the nesting levels of the objects and contains additional
|
||||
/// information about the PDFsharp objects. Furthermore content streams are not deflated. This
|
||||
/// is useful for debugging purposes only and increases the size of the file significantly.
|
||||
/// </summary>
|
||||
Verbose,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// INTERNAL USE ONLY.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum PdfWriterOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// If only this flag is specified the result is a regular valid PDF stream.
|
||||
/// </summary>
|
||||
Regular = 0x000000,
|
||||
|
||||
/// <summary>
|
||||
/// Omit writing stream data. For debugging purposes only.
|
||||
/// With this option the result is not valid PDF.
|
||||
/// </summary>
|
||||
OmitStream = 0x000001,
|
||||
|
||||
/// <summary>
|
||||
/// Omit inflate filter. For debugging purposes only.
|
||||
/// </summary>
|
||||
OmitInflation = 0x000002,
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
namespace PdfSharpCore.Pdf.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Terminal symbols recognized by lexer.
|
||||
/// </summary>
|
||||
public enum Symbol
|
||||
{
|
||||
#pragma warning disable 1591
|
||||
None,
|
||||
Comment, Null, Integer, UInteger, Real, Boolean, String, HexString, UnicodeString, UnicodeHexString,
|
||||
Name, Keyword,
|
||||
BeginStream, EndStream,
|
||||
BeginArray, EndArray,
|
||||
BeginDictionary, EndDictionary,
|
||||
Obj, EndObj, R, XRef, Trailer, StartXRef, Eof, Long
|
||||
#pragma warning restore 1591
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user