662 lines
22 KiB
C#
662 lines
22 KiB
C#
|
#region PDFsharp - A .NET library for processing PDF
|
|||
|
//
|
|||
|
// Authors:
|
|||
|
// Stefan Lange
|
|||
|
//
|
|||
|
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
|
|||
|
//
|
|||
|
// http://www.pdfsharp.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 PdfSharp.Pdf.Advanced;
|
|||
|
using PdfSharp.Pdf.Security;
|
|||
|
using PdfSharp.Pdf.Internal;
|
|||
|
|
|||
|
namespace PdfSharp.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
|
|||
|
#if DEBUG
|
|||
|
_layout = PdfWriterLayout.Verbose;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public void Close(bool closeUnderlyingStream)
|
|||
|
{
|
|||
|
if (_stream != null && closeUnderlyingStream)
|
|||
|
{
|
|||
|
#if UWP
|
|||
|
_stream.Dispose();
|
|||
|
#else
|
|||
|
_stream.Close();
|
|||
|
#endif
|
|||
|
}
|
|||
|
_stream = null;
|
|||
|
}
|
|||
|
|
|||
|
public void Close()
|
|||
|
{
|
|||
|
Close(true);
|
|||
|
}
|
|||
|
|
|||
|
public int Position
|
|||
|
{
|
|||
|
get { return (int)_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);
|
|||
|
WriteRaw(value ? bool.TrueString : bool.FalseString);
|
|||
|
_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(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(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);
|
|||
|
#if true
|
|||
|
PdfStringEncoding encoding = (PdfStringEncoding)(value.Flags & PdfStringFlags.EncodingMask);
|
|||
|
string pdf = (value.Flags & PdfStringFlags.HexLiteral) == 0 ?
|
|||
|
PdfEncoders.ToStringLiteral(value.Value, encoding, SecurityHandler) :
|
|||
|
PdfEncoders.ToHexStringLiteral(value.Value, encoding, SecurityHandler);
|
|||
|
WriteRaw(pdf);
|
|||
|
#else
|
|||
|
switch (value.Flags & PdfStringFlags.EncodingMask)
|
|||
|
{
|
|||
|
case PdfStringFlags.Undefined:
|
|||
|
case PdfStringFlags.PDFDocEncoding:
|
|||
|
if ((value.Flags & PdfStringFlags.HexLiteral) == 0)
|
|||
|
WriteRaw(PdfEncoders.DocEncode(value.Value, false));
|
|||
|
else
|
|||
|
WriteRaw(PdfEncoders.DocEncodeHex(value.Value, false));
|
|||
|
break;
|
|||
|
|
|||
|
case PdfStringFlags.WinAnsiEncoding:
|
|||
|
throw new NotImplementedException("Unexpected encoding: WinAnsiEncoding");
|
|||
|
|
|||
|
case PdfStringFlags.Unicode:
|
|||
|
if ((value.Flags & PdfStringFlags.HexLiteral) == 0)
|
|||
|
WriteRaw(PdfEncoders.DocEncode(value.Value, true));
|
|||
|
else
|
|||
|
WriteRaw(PdfEncoders.DocEncodeHex(value.Value, true));
|
|||
|
break;
|
|||
|
|
|||
|
case PdfStringFlags.StandardEncoding:
|
|||
|
case PdfStringFlags.MacRomanEncoding:
|
|||
|
case PdfStringFlags.MacExpertEncoding:
|
|||
|
default:
|
|||
|
throw new NotImplementedException("Unexpected encoding");
|
|||
|
}
|
|||
|
#endif
|
|||
|
_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 '[':
|
|||
|
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(" <20>...stream content omitted...<2E>\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);
|
|||
|
if (_lastCat != CharCat.NewLine)
|
|||
|
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, int startxref)
|
|||
|
{
|
|||
|
WriteRaw("startxref\n");
|
|||
|
WriteRaw(startxref.ToString(CultureInfo.InvariantCulture));
|
|||
|
WriteRaw("\n%%EOF\n");
|
|||
|
int fileSize = (int)_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;
|
|||
|
}
|
|||
|
}
|