mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-15 19:54:52 +08:00
PdfStreamWriter: Error Checking and Code Formatting
This commit is contained in:
@@ -1,31 +1,30 @@
|
|||||||
using System;
|
namespace UglyToad.PdfPig.Writer
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using UglyToad.PdfPig.Core;
|
|
||||||
using UglyToad.PdfPig.Graphics.Operations;
|
|
||||||
using UglyToad.PdfPig.Tokens;
|
|
||||||
|
|
||||||
namespace UglyToad.PdfPig.Writer
|
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Core;
|
||||||
|
using Graphics.Operations;
|
||||||
|
using Tokens;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class would lazily flush all token. Allowing us to make changes to references without need to rewrite the whole stream
|
/// This class would lazily flush all token. Allowing us to make changes to references without need to rewrite the whole stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class PdfStreamWriter : IDisposable
|
internal class PdfStreamWriter : IDisposable
|
||||||
{
|
{
|
||||||
private readonly SortedSet<int> reservedNumbers = new SortedSet<int>();
|
private readonly List<int> reservedNumbers = new List<int>();
|
||||||
|
|
||||||
private readonly Dictionary<IndirectReferenceToken, IToken> tokenReferences = new Dictionary<IndirectReferenceToken, IToken>();
|
private readonly Dictionary<IndirectReferenceToken, IToken> tokenReferences = new Dictionary<IndirectReferenceToken, IToken>();
|
||||||
|
|
||||||
public int CurrentNumber { get; private set; } = 1;
|
public int CurrentNumber { get; private set; } = 1;
|
||||||
|
|
||||||
public Stream Stream { get; }
|
public Stream Stream { get; private set; }
|
||||||
|
|
||||||
public PdfStreamWriter() : this(new MemoryStream()) { }
|
public PdfStreamWriter() : this(new MemoryStream()) { }
|
||||||
|
|
||||||
public PdfStreamWriter(Stream baseStream)
|
public PdfStreamWriter(Stream baseStream)
|
||||||
{
|
{
|
||||||
Stream = baseStream;
|
Stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush(decimal version, IndirectReferenceToken catalogReference)
|
public void Flush(decimal version, IndirectReferenceToken catalogReference)
|
||||||
@@ -57,7 +56,7 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
|
|
||||||
if (catalogToken == null && referenceToken == catalogReference)
|
if (catalogToken == null && referenceToken == catalogReference)
|
||||||
{
|
{
|
||||||
catalogToken = new ObjectToken(offset, referenceToken.Data, token);
|
catalogToken = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,9 +69,9 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
TokenWriter.WriteCrossReferenceTable(offsets, catalogToken, Stream, null);
|
TokenWriter.WriteCrossReferenceTable(offsets, catalogToken, Stream, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndirectReferenceToken WriteObject(IToken token, int? reservedNumber = null)
|
public IndirectReferenceToken WriteToken(IToken token, int? reservedNumber = null)
|
||||||
{
|
{
|
||||||
// if you can't consider deduplicating a token.
|
// if you can't consider deduplicating the token.
|
||||||
// It must be because it's referenced by his child element, so you must have reserved a number before hand
|
// It must be because it's referenced by his child element, so you must have reserved a number before hand
|
||||||
// Example /Pages Obj
|
// Example /Pages Obj
|
||||||
var canBeDuplicated = !reservedNumber.HasValue;
|
var canBeDuplicated = !reservedNumber.HasValue;
|
||||||
@@ -84,20 +83,57 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// When we end up writing this token, all of his child would already have been added and checked for duplicate
|
// When we end up writing this token, all of his child would already have been added and checked for duplicate
|
||||||
return AddObject(token, reservedNumber.Value);
|
return AddToken(token, reservedNumber.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var reference = FindToken(token);
|
var reference = FindToken(token);
|
||||||
if (reference == null)
|
if (reference == null)
|
||||||
{
|
{
|
||||||
// TODO: Check his children
|
return AddToken(token, CurrentNumber++);
|
||||||
return AddObject(token, CurrentNumber++);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndirectReferenceToken AddObject(IToken token, int reservedNumber)
|
public int ReserveNumber()
|
||||||
|
{
|
||||||
|
var reserved = CurrentNumber;
|
||||||
|
reservedNumbers.Add(reserved);
|
||||||
|
CurrentNumber++;
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndirectReferenceToken ReserveNumberToken()
|
||||||
|
{
|
||||||
|
return new IndirectReferenceToken(new IndirectReference(ReserveNumber(), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ToArray()
|
||||||
|
{
|
||||||
|
if (!Stream.CanSeek)
|
||||||
|
throw new NotSupportedException($"{Stream.GetType()} can't seek");
|
||||||
|
|
||||||
|
var currentPosition = Stream.Position;
|
||||||
|
Stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
var bytes = new byte[Stream.Length];
|
||||||
|
|
||||||
|
// Should we slice the reading into smaller chunks?
|
||||||
|
if (Stream.Read(bytes, 0, bytes.Length) != bytes.Length)
|
||||||
|
throw new Exception("Unable to read all the bytes from stream");
|
||||||
|
|
||||||
|
Stream.Seek(currentPosition, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stream?.Dispose();
|
||||||
|
Stream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndirectReferenceToken AddToken(IToken token, int reservedNumber)
|
||||||
{
|
{
|
||||||
var reference = new IndirectReference(reservedNumber, 0);
|
var reference = new IndirectReference(reservedNumber, 0);
|
||||||
var referenceToken = new IndirectReferenceToken(reference);
|
var referenceToken = new IndirectReferenceToken(reference);
|
||||||
@@ -120,45 +156,11 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReserveNumber()
|
|
||||||
{
|
|
||||||
var reserved = CurrentNumber;
|
|
||||||
reservedNumbers.Add(reserved);
|
|
||||||
CurrentNumber++;
|
|
||||||
return reserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IndirectReferenceToken ReserveNumberToken() => new IndirectReferenceToken(new IndirectReference(ReserveNumber(), 0));
|
|
||||||
|
|
||||||
private static void WriteString(string text, Stream stream)
|
private static void WriteString(string text, Stream stream)
|
||||||
{
|
{
|
||||||
var bytes = OtherEncodings.StringAsLatin1Bytes(text);
|
var bytes = OtherEncodings.StringAsLatin1Bytes(text);
|
||||||
stream.Write(bytes, 0, bytes.Length);
|
stream.Write(bytes, 0, bytes.Length);
|
||||||
stream.WriteNewLine();
|
stream.WriteNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ToArray()
|
|
||||||
{
|
|
||||||
if (!Stream.CanSeek)
|
|
||||||
throw new NotSupportedException("Stream can't seek");
|
|
||||||
|
|
||||||
var currentPosition = Stream.Position;
|
|
||||||
Stream.Seek(0, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
var bytes = new byte[Stream.Length];
|
|
||||||
|
|
||||||
// Should we slice the reading into smaller chunks?
|
|
||||||
if (Stream.Read(bytes, 0, bytes.Length) != bytes.Length)
|
|
||||||
throw new Exception("Unable to read all the bytes from stream");
|
|
||||||
|
|
||||||
Stream.Seek(currentPosition, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Stream.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user