PdfStreamWriter: Error Checking and Code Formatting

This commit is contained in:
InusualZ
2020-03-08 15:33:38 -03:00
committed by Eliot Jones
parent c533d47386
commit 44ad5c8b0c

View File

@@ -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();
}
} }
} }