Revert "extra non printable char" due to github changing new lines

This reverts commit 1f6ecd7ab4.
This commit is contained in:
Michael Plaisted
2021-12-22 13:22:03 -06:00
parent 1f6ecd7ab4
commit 8834bff378

View File

@@ -1,305 +1,305 @@
namespace UglyToad.PdfPig.Writer namespace UglyToad.PdfPig.Writer
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Core; using Core;
using Graphics.Operations; using Graphics.Operations;
using Tokens; using Tokens;
using Util; using Util;
/// <summary> /// <summary>
/// Writes any type of <see cref="IToken"/> to the corresponding PDF document format output. /// Writes any type of <see cref="IToken"/> to the corresponding PDF document format output.
/// </summary> /// </summary>
public class TokenWriter public class TokenWriter
{ {
private static readonly byte Backslash = GetByte("\\"); private static readonly byte Backslash = GetByte("\\");
private static readonly byte ArrayStart = GetByte("["); private static readonly byte ArrayStart = GetByte("[");
private static readonly byte ArrayEnd = GetByte("]"); private static readonly byte ArrayEnd = GetByte("]");
private static readonly byte[] DictionaryStart = OtherEncodings.StringAsLatin1Bytes("<<"); private static readonly byte[] DictionaryStart = OtherEncodings.StringAsLatin1Bytes("<<");
private static readonly byte[] DictionaryEnd = OtherEncodings.StringAsLatin1Bytes(">>"); private static readonly byte[] DictionaryEnd = OtherEncodings.StringAsLatin1Bytes(">>");
private static readonly byte Comment = GetByte("%"); private static readonly byte Comment = GetByte("%");
private static readonly byte[] Eof = OtherEncodings.StringAsLatin1Bytes("%%EOF"); private static readonly byte[] Eof = OtherEncodings.StringAsLatin1Bytes("%%EOF");
private static readonly byte[] FalseBytes = OtherEncodings.StringAsLatin1Bytes("false"); private static readonly byte[] FalseBytes = OtherEncodings.StringAsLatin1Bytes("false");
private static readonly byte HexStart = GetByte("<"); private static readonly byte HexStart = GetByte("<");
private static readonly byte HexEnd = GetByte(">"); private static readonly byte HexEnd = GetByte(">");
private static readonly byte InUseEntry = GetByte("n"); private static readonly byte InUseEntry = GetByte("n");
private static readonly byte NameStart = GetByte("/"); private static readonly byte NameStart = GetByte("/");
private static readonly byte[] Null = OtherEncodings.StringAsLatin1Bytes("null"); private static readonly byte[] Null = OtherEncodings.StringAsLatin1Bytes("null");
private static readonly byte[] ObjStart = OtherEncodings.StringAsLatin1Bytes("obj"); private static readonly byte[] ObjStart = OtherEncodings.StringAsLatin1Bytes("obj");
private static readonly byte[] ObjEnd = OtherEncodings.StringAsLatin1Bytes("endobj"); private static readonly byte[] ObjEnd = OtherEncodings.StringAsLatin1Bytes("endobj");
private static readonly byte RByte = GetByte("R"); private static readonly byte RByte = GetByte("R");
private static readonly byte[] StartXref = OtherEncodings.StringAsLatin1Bytes("startxref"); private static readonly byte[] StartXref = OtherEncodings.StringAsLatin1Bytes("startxref");
private static readonly byte[] StreamStart = OtherEncodings.StringAsLatin1Bytes("stream"); private static readonly byte[] StreamStart = OtherEncodings.StringAsLatin1Bytes("stream");
private static readonly byte[] StreamEnd = OtherEncodings.StringAsLatin1Bytes("endstream"); private static readonly byte[] StreamEnd = OtherEncodings.StringAsLatin1Bytes("endstream");
private static readonly byte StringStart = GetByte("("); private static readonly byte StringStart = GetByte("(");
private static readonly byte StringEnd = GetByte(")"); private static readonly byte StringEnd = GetByte(")");
private static readonly byte[] Trailer = OtherEncodings.StringAsLatin1Bytes("trailer"); private static readonly byte[] Trailer = OtherEncodings.StringAsLatin1Bytes("trailer");
private static readonly byte[] TrueBytes = OtherEncodings.StringAsLatin1Bytes("true"); private static readonly byte[] TrueBytes = OtherEncodings.StringAsLatin1Bytes("true");
private static readonly byte Whitespace = GetByte(" "); private static readonly byte Whitespace = GetByte(" ");
private static readonly byte[] Xref = OtherEncodings.StringAsLatin1Bytes("xref"); private static readonly byte[] Xref = OtherEncodings.StringAsLatin1Bytes("xref");
private static readonly HashSet<char> DelimiterChars = new HashSet<char> private static readonly HashSet<char> DelimiterChars = new HashSet<char>
{ {
'(', '(',
')', ')',
'<', '<',
'>', '>',
'[', '[',
']', ']',
'{', '{',
'}', '}',
'/', '/',
'%' '%'
}; };
/// <summary> /// <summary>
/// Writes the given input token to the output stream with the correct PDF format and encoding including whitespace and line breaks as applicable. /// Writes the given input token to the output stream with the correct PDF format and encoding including whitespace and line breaks as applicable.
/// </summary> /// </summary>
/// <param name="token">The token to write to the stream.</param> /// <param name="token">The token to write to the stream.</param>
/// <param name="outputStream">The stream to write the token to.</param> /// <param name="outputStream">The stream to write the token to.</param>
public static void WriteToken(IToken token, Stream outputStream) public static void WriteToken(IToken token, Stream outputStream)
{ {
if (token == null) if (token == null)
{ {
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
switch (token) switch (token)
{ {
case ArrayToken array: case ArrayToken array:
WriteArray(array, outputStream); WriteArray(array, outputStream);
break; break;
case BooleanToken boolean: case BooleanToken boolean:
WriteBoolean(boolean, outputStream); WriteBoolean(boolean, outputStream);
break; break;
case CommentToken comment: case CommentToken comment:
WriteComment(comment, outputStream); WriteComment(comment, outputStream);
break; break;
case DictionaryToken dictionary: case DictionaryToken dictionary:
WriteDictionary(dictionary, outputStream); WriteDictionary(dictionary, outputStream);
break; break;
case HexToken hex: case HexToken hex:
WriteHex(hex, outputStream); WriteHex(hex, outputStream);
break; break;
case IndirectReferenceToken reference: case IndirectReferenceToken reference:
WriteIndirectReference(reference, outputStream); WriteIndirectReference(reference, outputStream);
break; break;
case NameToken name: case NameToken name:
WriteName(name, outputStream); WriteName(name, outputStream);
break; break;
case NullToken _: case NullToken _:
outputStream.Write(Null, 0, Null.Length); outputStream.Write(Null, 0, Null.Length);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
break; break;
case NumericToken number: case NumericToken number:
WriteNumber(number, outputStream); WriteNumber(number, outputStream);
break; break;
case ObjectToken objectToken: case ObjectToken objectToken:
WriteObject(objectToken, outputStream); WriteObject(objectToken, outputStream);
break; break;
case StreamToken streamToken: case StreamToken streamToken:
WriteStream(streamToken, outputStream); WriteStream(streamToken, outputStream);
break; break;
case StringToken stringToken: case StringToken stringToken:
WriteString(stringToken, outputStream); WriteString(stringToken, outputStream);
break; break;
default: default:
throw new PdfDocumentFormatException($"Attempted to write token type of {token.GetType()} but was not known."); throw new PdfDocumentFormatException($"Attempted to write token type of {token.GetType()} but was not known.");
} }
} }
/// <summary> /// <summary>
/// Writes a valid single section cross-reference (xref) table plus trailer dictionary to the output for the set of object offsets. /// Writes a valid single section cross-reference (xref) table plus trailer dictionary to the output for the set of object offsets.
/// </summary> /// </summary>
/// <param name="objectOffsets">The byte offset from the start of the document for each object in the document.</param> /// <param name="objectOffsets">The byte offset from the start of the document for each object in the document.</param>
/// <param name="catalogToken">The object representing the catalog dictionary which is referenced from the trailer dictionary.</param> /// <param name="catalogToken">The object representing the catalog dictionary which is referenced from the trailer dictionary.</param>
/// <param name="outputStream">The output stream to write to.</param> /// <param name="outputStream">The output stream to write to.</param>
/// <param name="documentInformationReference">The object reference for the document information dictionary if present.</param> /// <param name="documentInformationReference">The object reference for the document information dictionary if present.</param>
internal static void WriteCrossReferenceTable(IReadOnlyDictionary<IndirectReference, long> objectOffsets, internal static void WriteCrossReferenceTable(IReadOnlyDictionary<IndirectReference, long> objectOffsets,
IndirectReference catalogToken, IndirectReference catalogToken,
Stream outputStream, Stream outputStream,
IndirectReference? documentInformationReference) IndirectReference? documentInformationReference)
{ {
if (objectOffsets.Count == 0) if (objectOffsets.Count == 0)
{ {
throw new InvalidOperationException("Could not write empty cross reference table."); throw new InvalidOperationException("Could not write empty cross reference table.");
} }
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
var position = outputStream.Position; var position = outputStream.Position;
outputStream.Write(Xref, 0, Xref.Length); outputStream.Write(Xref, 0, Xref.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
var min = objectOffsets.Min(x => x.Key.ObjectNumber); var min = objectOffsets.Min(x => x.Key.ObjectNumber);
var max = objectOffsets.Max(x => x.Key.ObjectNumber); var max = objectOffsets.Max(x => x.Key.ObjectNumber);
if (max - min != objectOffsets.Count - 1) if (max - min != objectOffsets.Count - 1)
{ {
throw new NotSupportedException("Object numbers must form a contiguous range"); throw new NotSupportedException("Object numbers must form a contiguous range");
} }
WriteLong(0, outputStream); WriteLong(0, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
// 1 extra for the free entry. // 1 extra for the free entry.
WriteLong(objectOffsets.Count + 1, outputStream); WriteLong(objectOffsets.Count + 1, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
WriteFirstXrefEmptyEntry(outputStream); WriteFirstXrefEmptyEntry(outputStream);
foreach (var keyValuePair in objectOffsets.OrderBy(x => x.Key.ObjectNumber)) foreach (var keyValuePair in objectOffsets.OrderBy(x => x.Key.ObjectNumber))
{ {
/* /*
* nnnnnnnnnn ggggg n eol * nnnnnnnnnn ggggg n eol
* where: * where:
* nnnnnnnnnn is a 10-digit byte offset * nnnnnnnnnn is a 10-digit byte offset
* ggggg is a 5-digit generation number * ggggg is a 5-digit generation number
* n is a literal keyword identifying this as an in-use entry * n is a literal keyword identifying this as an in-use entry
* eol is a 2-character end-of-line sequence ('\r\n' or ' \n') * eol is a 2-character end-of-line sequence ('\r\n' or ' \n')
*/ */
var paddedOffset = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Value.ToString("D10")); var paddedOffset = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Value.ToString("D10"));
outputStream.Write(paddedOffset, 0, paddedOffset.Length); outputStream.Write(paddedOffset, 0, paddedOffset.Length);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
var generation = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Key.Generation.ToString("D5")); var generation = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Key.Generation.ToString("D5"));
outputStream.Write(generation, 0, generation.Length); outputStream.Write(generation, 0, generation.Length);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
outputStream.WriteByte(InUseEntry); outputStream.WriteByte(InUseEntry);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
} }
outputStream.Write(Trailer, 0, Trailer.Length); outputStream.Write(Trailer, 0, Trailer.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
var identifier = new ArrayToken(new IToken[] var identifier = new ArrayToken(new IToken[]
{ {
new HexToken(Guid.NewGuid().ToString("N").ToCharArray()), new HexToken(Guid.NewGuid().ToString("N").ToCharArray()),
new HexToken(Guid.NewGuid().ToString("N").ToCharArray()) new HexToken(Guid.NewGuid().ToString("N").ToCharArray())
}); });
var trailerDictionaryData = new Dictionary<NameToken, IToken> var trailerDictionaryData = new Dictionary<NameToken, IToken>
{ {
// 1 for the free entry. // 1 for the free entry.
{NameToken.Size, new NumericToken(objectOffsets.Count + 1)}, {NameToken.Size, new NumericToken(objectOffsets.Count + 1)},
{NameToken.Root, new IndirectReferenceToken(catalogToken)}, {NameToken.Root, new IndirectReferenceToken(catalogToken)},
{NameToken.Id, identifier} {NameToken.Id, identifier}
}; };
if (documentInformationReference.HasValue) if (documentInformationReference.HasValue)
{ {
trailerDictionaryData[NameToken.Info] = new IndirectReferenceToken(documentInformationReference.Value); trailerDictionaryData[NameToken.Info] = new IndirectReferenceToken(documentInformationReference.Value);
} }
var trailerDictionary = new DictionaryToken(trailerDictionaryData); var trailerDictionary = new DictionaryToken(trailerDictionaryData);
WriteDictionary(trailerDictionary, outputStream); WriteDictionary(trailerDictionary, outputStream);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(StartXref, 0, StartXref.Length); outputStream.Write(StartXref, 0, StartXref.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
WriteLong(position, outputStream); WriteLong(position, outputStream);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
// Complete! // Complete!
outputStream.Write(Eof, 0, Eof.Length); outputStream.Write(Eof, 0, Eof.Length);
} }
/// <summary> /// <summary>
/// Writes pre-serialized token as an object token to the output stream. /// Writes pre-serialized token as an object token to the output stream.
/// </summary> /// </summary>
/// <param name="objectNumber">Object number of the indirect object.</param> /// <param name="objectNumber">Object number of the indirect object.</param>
/// <param name="generation">Generation of the indirect object.</param> /// <param name="generation">Generation of the indirect object.</param>
/// <param name="data">Pre-serialized object contents.</param> /// <param name="data">Pre-serialized object contents.</param>
/// <param name="outputStream">The stream to write the token to.</param> /// <param name="outputStream">The stream to write the token to.</param>
internal static void WriteObject(long objectNumber, int generation, byte[] data, Stream outputStream) internal static void WriteObject(long objectNumber, int generation, byte[] data, Stream outputStream)
{ {
WriteLong(objectNumber, outputStream); WriteLong(objectNumber, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
WriteInt(generation, outputStream); WriteInt(generation, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
outputStream.Write(ObjStart, 0, ObjStart.Length); outputStream.Write(ObjStart, 0, ObjStart.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(data, 0, data.Length); outputStream.Write(data, 0, data.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(ObjEnd, 0, ObjEnd.Length); outputStream.Write(ObjEnd, 0, ObjEnd.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
} }
private static void WriteHex(HexToken hex, Stream stream) private static void WriteHex(HexToken hex, Stream stream)
{ {
stream.WriteByte(HexStart); stream.WriteByte(HexStart);
stream.WriteText(hex.GetHexString()); stream.WriteText(hex.GetHexString());
stream.WriteByte(HexEnd); stream.WriteByte(HexEnd);
} }
private static void WriteArray(ArrayToken array, Stream outputStream) private static void WriteArray(ArrayToken array, Stream outputStream)
{ {
outputStream.WriteByte(ArrayStart); outputStream.WriteByte(ArrayStart);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
for (var i = 0; i < array.Data.Count; i++) for (var i = 0; i < array.Data.Count; i++)
{ {
var value = array.Data[i]; var value = array.Data[i];
WriteToken(value, outputStream); WriteToken(value, outputStream);
} }
outputStream.WriteByte(ArrayEnd); outputStream.WriteByte(ArrayEnd);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
} }
private static void WriteBoolean(BooleanToken boolean, Stream outputStream) private static void WriteBoolean(BooleanToken boolean, Stream outputStream)
{ {
var bytes = boolean.Data ? TrueBytes : FalseBytes; var bytes = boolean.Data ? TrueBytes : FalseBytes;
outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(bytes, 0, bytes.Length);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
} }
private static void WriteComment(CommentToken comment, Stream outputStream) private static void WriteComment(CommentToken comment, Stream outputStream)
{ {
var bytes = OtherEncodings.StringAsLatin1Bytes(comment.Data); var bytes = OtherEncodings.StringAsLatin1Bytes(comment.Data);
outputStream.WriteByte(Comment); outputStream.WriteByte(Comment);
outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(bytes, 0, bytes.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
} }
private static void WriteDictionary(DictionaryToken dictionary, Stream outputStream) private static void WriteDictionary(DictionaryToken dictionary, Stream outputStream)
{ {
outputStream.Write(DictionaryStart, 0, DictionaryStart.Length); outputStream.Write(DictionaryStart, 0, DictionaryStart.Length);
foreach (var pair in dictionary.Data) foreach (var pair in dictionary.Data)
{ {
WriteName(pair.Key, outputStream); WriteName(pair.Key, outputStream);
// handle scenario where PdfPig has a null value under some circumstances // handle scenario where PdfPig has a null value under some circumstances
@@ -310,104 +310,104 @@
else else
{ {
WriteToken(pair.Value, outputStream); WriteToken(pair.Value, outputStream);
} }
} }
outputStream.Write(DictionaryEnd, 0, DictionaryEnd.Length); outputStream.Write(DictionaryEnd, 0, DictionaryEnd.Length);
} }
private static void WriteIndirectReference(IndirectReferenceToken reference, Stream outputStream) private static void WriteIndirectReference(IndirectReferenceToken reference, Stream outputStream)
{ {
WriteLong(reference.Data.ObjectNumber, outputStream); WriteLong(reference.Data.ObjectNumber, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
WriteInt(reference.Data.Generation, outputStream); WriteInt(reference.Data.Generation, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
outputStream.WriteByte(RByte); outputStream.WriteByte(RByte);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
} }
private static void WriteName(NameToken name, Stream outputStream) private static void WriteName(NameToken name, Stream outputStream)
{ {
WriteName(name.Data, outputStream); WriteName(name.Data, outputStream);
} }
private static void WriteName(string name, Stream outputStream) private static void WriteName(string name, Stream outputStream)
{ {
/* /*
* Beginning with PDF 1.2, any character except null (character code 0) may be * Beginning with PDF 1.2, any character except null (character code 0) may be
* included in a name by writing its 2-digit hexadecimal code, preceded by the number sign character (#). * included in a name by writing its 2-digit hexadecimal code, preceded by the number sign character (#).
* This is required for delimiter and whitespace characters. * This is required for delimiter and whitespace characters.
* This is recommended for characters whose codes are outside the range 33 (!) to 126 (~). * This is recommended for characters whose codes are outside the range 33 (!) to 126 (~).
*/ */
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var c in name) foreach (var c in name)
{ {
if (c < 33 || c > 126 || DelimiterChars.Contains(c)) if (c < 33 || c > 126 || DelimiterChars.Contains(c))
{ {
var str = Hex.GetString(new[] { (byte)c }); var str = Hex.GetString(new[] { (byte)c });
sb.Append('#').Append(str); sb.Append('#').Append(str);
} }
else else
{ {
sb.Append(c); sb.Append(c);
} }
} }
var bytes = OtherEncodings.StringAsLatin1Bytes(sb.ToString()); var bytes = OtherEncodings.StringAsLatin1Bytes(sb.ToString());
outputStream.WriteByte(NameStart); outputStream.WriteByte(NameStart);
outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(bytes, 0, bytes.Length);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
} }
private static void WriteNumber(NumericToken number, Stream outputStream) private static void WriteNumber(NumericToken number, Stream outputStream)
{ {
if (!number.HasDecimalPlaces) if (!number.HasDecimalPlaces)
{ {
WriteInt(number.Int, outputStream); WriteInt(number.Int, outputStream);
} }
else else
{ {
var bytes = OtherEncodings.StringAsLatin1Bytes(number.Data.ToString("G", CultureInfo.InvariantCulture)); var bytes = OtherEncodings.StringAsLatin1Bytes(number.Data.ToString("G", CultureInfo.InvariantCulture));
outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(bytes, 0, bytes.Length);
} }
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
} }
private static void WriteObject(ObjectToken objectToken, Stream outputStream) private static void WriteObject(ObjectToken objectToken, Stream outputStream)
{ {
WriteLong(objectToken.Number.ObjectNumber, outputStream); WriteLong(objectToken.Number.ObjectNumber, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
WriteInt(objectToken.Number.Generation, outputStream); WriteInt(objectToken.Number.Generation, outputStream);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
outputStream.Write(ObjStart, 0, ObjStart.Length); outputStream.Write(ObjStart, 0, ObjStart.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
WriteToken(objectToken.Data, outputStream); WriteToken(objectToken.Data, outputStream);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(ObjEnd, 0, ObjEnd.Length); outputStream.Write(ObjEnd, 0, ObjEnd.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
} }
private static void WriteStream(StreamToken streamToken, Stream outputStream) private static void WriteStream(StreamToken streamToken, Stream outputStream)
{ {
WriteDictionary(streamToken.StreamDictionary, outputStream); WriteDictionary(streamToken.StreamDictionary, outputStream);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(StreamStart, 0, StreamStart.Length); outputStream.Write(StreamStart, 0, StreamStart.Length);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(streamToken.Data.ToArray(), 0, streamToken.Data.Count); outputStream.Write(streamToken.Data.ToArray(), 0, streamToken.Data.Count);
WriteLineBreak(outputStream); WriteLineBreak(outputStream);
outputStream.Write(StreamEnd, 0, StreamEnd.Length); outputStream.Write(StreamEnd, 0, StreamEnd.Length);
} }
private static int[] EscapeNeeded = new int[] private static int[] EscapeNeeded = new int[]
{ {
@@ -416,12 +416,12 @@
private static int[] Escaped = new int[] private static int[] Escaped = new int[]
{ {
'r', 'n', 't', 'b', 'f', '\\' 'r', 'n', 't', 'b', 'f', '\\'
}; };
private static void WriteString(StringToken stringToken, Stream outputStream) private static void WriteString(StringToken stringToken, Stream outputStream)
{ {
outputStream.WriteByte(StringStart); outputStream.WriteByte(StringStart);
if (stringToken.EncodedWith == StringToken.Encoding.Iso88591) if (stringToken.EncodedWith == StringToken.Encoding.Iso88591)
{ {
// iso 88591 (or really PdfDocEncoding in non-contentstream circumstances shouldn't // iso 88591 (or really PdfDocEncoding in non-contentstream circumstances shouldn't
// have these chars but seems like internally this isn't obeyed (see: // have these chars but seems like internally this isn't obeyed (see:
@@ -448,7 +448,7 @@
outputStream.WriteByte((byte)'\\'); outputStream.WriteByte((byte)'\\');
outputStream.WriteByte((byte)Escaped[ei]); outputStream.WriteByte((byte)Escaped[ei]);
} }
else if (c < 32 || c > 126) // non printable else if (c < 32 || c > 127) // non printable
{ {
var b3 = c / 64; var b3 = c / 64;
var b2 = (c - b3 * 64) / 8; var b2 = (c - b3 * 64) / 8;
@@ -472,58 +472,58 @@
} }
outputStream.WriteByte(StringEnd); outputStream.WriteByte(StringEnd);
WriteWhitespace(outputStream); WriteWhitespace(outputStream);
} }
private static void WriteInt(int value, Stream outputStream) private static void WriteInt(int value, Stream outputStream)
{ {
var bytes = OtherEncodings.StringAsLatin1Bytes(value.ToString("G", CultureInfo.InvariantCulture)); var bytes = OtherEncodings.StringAsLatin1Bytes(value.ToString("G", CultureInfo.InvariantCulture));
outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(bytes, 0, bytes.Length);
} }
private static void WriteLineBreak(Stream outputStream) private static void WriteLineBreak(Stream outputStream)
{ {
outputStream.WriteNewLine(); outputStream.WriteNewLine();
} }
private static void WriteLong(long value, Stream outputStream) private static void WriteLong(long value, Stream outputStream)
{ {
var bytes = OtherEncodings.StringAsLatin1Bytes(value.ToString("G", CultureInfo.InvariantCulture)); var bytes = OtherEncodings.StringAsLatin1Bytes(value.ToString("G", CultureInfo.InvariantCulture));
outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(bytes, 0, bytes.Length);
} }
private static void WriteWhitespace(Stream outputStream) private static void WriteWhitespace(Stream outputStream)
{ {
outputStream.WriteByte(Whitespace); outputStream.WriteByte(Whitespace);
} }
private static void WriteFirstXrefEmptyEntry(Stream outputStream) private static void WriteFirstXrefEmptyEntry(Stream outputStream)
{ {
/* /*
* The first entry in the table (object number 0) is always free and has a generation number of 65,535; * The first entry in the table (object number 0) is always free and has a generation number of 65,535;
* it is the head of the linked list of free objects. * it is the head of the linked list of free objects.
*/ */
outputStream.WriteText(new string('0', 10)); outputStream.WriteText(new string('0', 10));
outputStream.WriteWhiteSpace(); outputStream.WriteWhiteSpace();
outputStream.WriteText("65535"); outputStream.WriteText("65535");
outputStream.WriteWhiteSpace(); outputStream.WriteWhiteSpace();
outputStream.WriteText("f"); outputStream.WriteText("f");
outputStream.WriteWhiteSpace(); outputStream.WriteWhiteSpace();
outputStream.WriteNewLine(); outputStream.WriteNewLine();
} }
private static byte GetByte(string value) private static byte GetByte(string value)
{ {
var bytes = OtherEncodings.StringAsLatin1Bytes(value); var bytes = OtherEncodings.StringAsLatin1Bytes(value);
if (bytes.Length > 1) if (bytes.Length > 1)
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
return bytes[0]; return bytes[0];
} }
} }
} }