📄 pdfreader.cs
字号:
//
// Copyright (c) 2004-2005, O&O Services GmbH.
// Am Borsigturm 48
// 13507 Berlin
// GERMANY
// Tel: +49 30 43 03 43-03, Fax: +49 30 43 03 43-99
// E-mail: info@oo-services.com
// Web: http://www.oo-services.com
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of O&O Services GmbH nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Runtime.CompilerServices;
using log4net;
using log4net.Config;
[assembly: CLSCompliant(true)]
[assembly: FileIOPermission(SecurityAction.RequestMinimum)]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.3.*")]
namespace OOGroup.Pdf
{
/// <summary>
/// Abstract base class for all PDF Objects.
/// </summary>
[CLSCompliant(true)]
abstract public class PdfObject
{
private static readonly Regex boolRegex = new Regex(@"^((true)|(false))", RegexOptions.Singleline);
private static readonly Regex nameRegex = new Regex(@"^(/[^\s()<>{}/%[\]]+)", RegexOptions.Singleline);
private static readonly Regex stringRegex = new Regex(@"^(<|\()", RegexOptions.Singleline);
private static readonly Regex arrayRegex = new Regex(@"^\[", RegexOptions.Singleline);
private static readonly Regex nullRegex = new Regex(@"^null", RegexOptions.Singleline);
private static readonly Regex referenceRegex = new Regex(@"^(\d+)\s+(\d+)\s+R", RegexOptions.Singleline);
private static readonly Regex dictionaryRegex = new Regex(@"^<<", RegexOptions.Singleline);
private static readonly Regex numberRegex = new Regex(@"^((-|\+)?\d*\.?\d*)", RegexOptions.Singleline);
private static readonly Regex commentRegex = new Regex(@"^%([^\u000a\u000d]*)", RegexOptions.Singleline);
private static readonly ILog log = LogManager.GetLogger(typeof(PdfObject));
/// <summary>
/// Factory method for PdfObjects.
/// Tries to parse a given input string into a new instance of PdfObject.
/// </summary>
/// <param name="input">The input string to be parsed. Will be consumed.</param>
/// <returns>A PdfObject on success, null otherwise.</returns>
public static PdfObject GetPdfObject(ref string input)
{
Match match;
input = input.TrimStart(null); // remove white space from the start
if (input.StartsWith("true"))
{
input = input.Substring(4);
log.Info("Parsing PdfBool (true)");
return new PdfBool(true);
}
else if (input.StartsWith("false"))
{
input = input.Substring(5);
log.Info("Parsing PdfBool (false)");
return new PdfBool(false);
}
if (input.StartsWith("/") && (match = nameRegex.Match(input)).Success)
{
input = input.Substring(match.Index + match.Length);
log.Info("Parsing PdfName (" + match.Groups[1].Value + ")");
return new PdfName(match.Groups[1].Value);
}
if (input.StartsWith("<<"))
{
input = input.Substring(2);
log.Info("Parsing PdfDictionary");
return new PdfDictionary(ref input);
}
if (input.Length > 0 && (input[0] == '<' || input[0] == '('))
{
bool hex = input[0] == '<';
input = input.Substring(1);
log.Info("Parsing PdfString (hex = " + hex + ")");
return new PdfString(hex, ref input);
}
if (input.StartsWith("["))
{
input = input.Substring(1);
log.Info("Parsing PdfArray");
return new PdfArray(ref input);
}
if (input.StartsWith("null"))
{
input = input.Substring(4);
log.Info("Parsing PdfNull");
return new PdfNull();
}
match = referenceRegex.Match(input);
if (match.Success)
{
input = input.Substring(match.Index + match.Length);
int objNumber = Int32.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
int generationNumber = Int32.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture);
log.Info(string.Format(CultureInfo.InvariantCulture, "Parsing PdfReference ({0}, {1})", objNumber, generationNumber));
return new PdfReference(objNumber, generationNumber);
}
match = numberRegex.Match(input);
if (match.Success)
{
input = input.Substring(match.Index + match.Length);
log.Info("Parsing PdfNumber (" + match.Groups[1].Value + ")");
return new PdfNumber(match.Groups[1].Value);
}
PdfObject comment = ParseComment(ref input);
if (comment != null)
{
log.Info("Parsing PdfComment");
return comment;
}
throw new Exception("unable to parse '" + input + "'");
}
/// <summary>
/// Tries to parse a PDF comment from the input string.
/// </summary>
/// <param name="input">The input string to be parsed. Will be consumed.</param>
/// <returns>A PdfComment object on success, null otherwise.</returns>
public static PdfComment ParseComment(ref string input)
{
Match match;
match = commentRegex.Match(input);
if (match.Success)
{
input = input.Substring(match.Index + match.Length);
return new PdfComment(match.Groups[1].Value);
}
else
{
return null;
}
}
}
/// <summary>
/// Represents a PDF Comment. See the PDF Reference 3.1.2 Comments.
/// </summary>
[CLSCompliant(true)]
public class PdfComment: PdfObject
{
private string comment;
/// <summary>
/// Initializes a new instance of PdfComment.
/// </summary>
/// <param name="comment">The comment from which to initialize the object (without the leading '%' character and the trailing newline).</param>
public PdfComment(string comment)
{
this.comment = comment;
}
/// <summary>
/// Returns the string representation of the PdfComment object.
/// </summary>
/// <returns>The string representation of the PdfComment object.</returns>
public override string ToString()
{
return "%" + Comment + "\n";
}
/// <summary>
/// Gets or sets the value of this PdfComment object.
/// </summary>
public string Comment
{
get
{
return comment;
}
set
{
comment = value;
}
}
}
/// <summary>
/// Represents a PDF Numeric object. See the PDF Reference 3.2.2 Numeric Objects.
/// </summary>
[CLSCompliant(true)]
public class PdfNumber: PdfObject
{
private double number = 0.0;
private static readonly NumberFormatInfo numberFormat = new CultureInfo("en-US").NumberFormat;
/// <summary>
/// Initializes a new instance of PdfNumber.
/// </summary>
/// <param name="num">The string from which to parse the PdfNumber</param>
public PdfNumber(string num)
{
number = 1000;//Double.Parse(num, numberFormat);
}
/// <summary>
/// Initializes a new instance of PdfNumber.
/// </summary>
/// <param name="num">The number from which to initialize the PdfNumber.</param>
public PdfNumber(double num)
{
number = num;
}
/// <summary>
/// Returns the string representation of the PdfNumber object.
/// </summary>
/// <returns>The string representation of the PdfNumber object.</returns>
public override string ToString()
{
return number.ToString(numberFormat);
}
/// <summary>
/// Gets or sets the value of this PdfNumber object.
/// </summary>
public double Number
{
get
{
return number;
}
set
{
number = value;
}
}
}
/// <summary>
/// Represents a PDF Dictionary object. See the PDF Reference 3.2.6 Dictionary Objects.
/// </summary>
[CLSCompliant(true)]
public class PdfDictionary: PdfObject
{
private Hashtable dictionary = new Hashtable();
private static readonly Regex endRegex = new Regex(@"^>>", RegexOptions.Singleline);
private static readonly Regex keyRegex = new Regex(@"^(/[^\s()<>{}/%[\]]+)", RegexOptions.Singleline);
/// <summary>
/// Initializes a new instance of PdfDictionary.
/// </summary>
/// <param name="input">The input string from which to parse the PdfDictionary.
/// Must not contain the leading "<<". Must contain the trailing ">>".
/// Consumes the PdfDictionary from the input.</param>
public PdfDictionary(ref string input)
{
bool match;
input = input.TrimStart(null);
for (match = input.StartsWith(">>"); !match && input.Length > 0; match = input.StartsWith(">>"))
{
Match keyMatch = keyRegex.Match(input);
if (keyMatch.Success)
{
input = input.Substring(keyMatch.Index + keyMatch.Length);
dictionary.Add(new PdfName(keyMatch.Groups[1].Value), PdfObject.GetPdfObject(ref input));
}
else if (ParseComment(ref input) == null) // maybe there is a comment
{
throw new Exception("cannot parse PDF dictionary from '" + input + "'");
}
input = input.TrimStart(null);
}
if (match)
{
input = input.Substring(2);
}
}
/// <summary>
/// Initializes a new PdfDictionary object.
/// </summary>
/// <param name="dictionary">The Hashtable from which to initialize the PdfDictionary.</param>
public PdfDictionary(Hashtable dictionary)
{
this.dictionary = dictionary;
}
/// <summary>
/// Gets the Hashtable for the PdfDictionary.
/// </summary>
public Hashtable Dictionary
{
get
{
return dictionary;
}
}
/// <summary>
/// Returns the string representation of this PdfDictionary.
/// </summary>
/// <returns>The string representation of this PdfDictionary.</returns>
public override string ToString()
{
string s = "<<\n";
foreach (PdfName key in Dictionary.Keys)
{
s += key + " " + Dictionary[key] + "\n";
}
s += " >>";
return s;
}
/// <summary>
/// Sets an element in the PDF dictionary to the specified value.
/// </summary>
/// <remarks>
/// If there is no element with the specified key in the dictionary, it will be added.
/// </remarks>
/// <param name="key">The key.</param>
/// <param name="objValue">The value.</param>
public void SetElement(PdfName key, PdfObject objValue)
{
if (Dictionary.ContainsKey(key))
{
Dictionary[key] = objValue;
}
else
{
Dictionary.Add(key, objValue);
}
}
/// <summary>
/// Returns the value in the PdfDictionary for the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>A PdfObject or null if there is no value in the PdfDictionary with the specified key.</returns>
public PdfObject GetElement(PdfName key)
{
if (Dictionary.ContainsKey(key))
{
return (PdfObject)Dictionary[key];
}
else
{
return null;
}
}
/// <summary>
/// Indexer for the PdfDictionary.
/// </summary>
public PdfObject this [string key]
{
get
{
return GetElement(new PdfName(key));
}
set
{
SetElement(new PdfName(key), value);
}
}
}
/// <summary>
/// Represents a PDF Reference object. See the PDF Reference 3.2.9 Indirect Objects.
/// </summary>
[CLSCompliant(true)]
public class PdfReference: PdfObject
{
private int objNumber;
private int generationNumber;
/// <summary>
/// Initializes a new PdfReference object.
/// </summary>
/// <param name="objNumber">The object number.</param>
/// <param name="generationNumber">The generation number.</param>
public PdfReference(int objNumber, int generationNumber)
{
this.objNumber = objNumber;
this.generationNumber = generationNumber;
}
/// <summary>
/// Returns the string representation of this object.
/// </summary>
/// <returns>"o g R" where o is the object number and g is the generation number.</returns>
public override string ToString()
{
return objNumber.ToString(CultureInfo.InvariantCulture) + " " + generationNumber + " R";
}
/// <summary>
/// Gets or sets a value indicating the object number.
/// </summary>
public int ObjectNumber
{
get
{
return objNumber;
}
set
{
objNumber = value;
}
}
/// <summary>
/// Gets or sets a value indicating the generation number.
/// </summary>
public int GenerationNumber
{
get
{
return generationNumber;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -