mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-21 04:17:57 +08:00
move the usages of cos object key to indirect reference
This commit is contained in:
@@ -87,7 +87,7 @@ startxref
|
|||||||
|
|
||||||
foreach (var keyValuePair in locations)
|
foreach (var keyValuePair in locations)
|
||||||
{
|
{
|
||||||
Assert.Contains(newLocations.Keys, x => ReferenceEquals(x, keyValuePair.Key));
|
Assert.Contains(newLocations.Keys, x => x.Equals(keyValuePair.Key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -122,14 +122,14 @@ trailer
|
|||||||
|
|
||||||
Assert.Equal(2, result.ObjectOffsets.Count);
|
Assert.Equal(2, result.ObjectOffsets.Count);
|
||||||
|
|
||||||
var results = result.ObjectOffsets.Select(x => new {x.Key.Number, x.Key.Generation, x.Value}).ToList();
|
var results = result.ObjectOffsets.Select(x => new {x.Key.ObjectNumber, x.Key.Generation, x.Value}).ToList();
|
||||||
|
|
||||||
Assert.Equal(100, results[0].Value);
|
Assert.Equal(100, results[0].Value);
|
||||||
Assert.Equal(1, results[0].Number);
|
Assert.Equal(1, results[0].ObjectNumber);
|
||||||
Assert.Equal(0, results[0].Generation);
|
Assert.Equal(0, results[0].Generation);
|
||||||
|
|
||||||
Assert.Equal(200, results[1].Value);
|
Assert.Equal(200, results[1].Value);
|
||||||
Assert.Equal(2, results[1].Number);
|
Assert.Equal(2, results[1].ObjectNumber);
|
||||||
Assert.Equal(5, results[1].Generation);
|
Assert.Equal(5, results[1].Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,14 +147,14 @@ trailer
|
|||||||
|
|
||||||
Assert.Equal(2, result.ObjectOffsets.Count);
|
Assert.Equal(2, result.ObjectOffsets.Count);
|
||||||
|
|
||||||
var results = result.ObjectOffsets.Select(x => new { x.Key.Number, x.Key.Generation, x.Value }).ToList();
|
var results = result.ObjectOffsets.Select(x => new { x.Key.ObjectNumber, x.Key.Generation, x.Value }).ToList();
|
||||||
|
|
||||||
Assert.Equal(190, results[0].Value);
|
Assert.Equal(190, results[0].Value);
|
||||||
Assert.Equal(15, results[0].Number);
|
Assert.Equal(15, results[0].ObjectNumber);
|
||||||
Assert.Equal(0, results[0].Generation);
|
Assert.Equal(0, results[0].Generation);
|
||||||
|
|
||||||
Assert.Equal(250, results[1].Value);
|
Assert.Equal(250, results[1].Value);
|
||||||
Assert.Equal(16, results[1].Number);
|
Assert.Equal(16, results[1].ObjectNumber);
|
||||||
Assert.Equal(32, results[1].Generation);
|
Assert.Equal(32, results[1].Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,14 +173,14 @@ trailer
|
|||||||
|
|
||||||
Assert.Equal(2, result.ObjectOffsets.Count);
|
Assert.Equal(2, result.ObjectOffsets.Count);
|
||||||
|
|
||||||
var results = result.ObjectOffsets.Select(x => new { x.Key.Number, x.Key.Generation, x.Value }).ToList();
|
var results = result.ObjectOffsets.Select(x => new { x.Key.ObjectNumber, x.Key.Generation, x.Value }).ToList();
|
||||||
|
|
||||||
Assert.Equal(190, results[0].Value);
|
Assert.Equal(190, results[0].Value);
|
||||||
Assert.Equal(15, results[0].Number);
|
Assert.Equal(15, results[0].ObjectNumber);
|
||||||
Assert.Equal(0, results[0].Generation);
|
Assert.Equal(0, results[0].Generation);
|
||||||
|
|
||||||
Assert.Equal(250, results[1].Value);
|
Assert.Equal(250, results[1].Value);
|
||||||
Assert.Equal(16, results[1].Number);
|
Assert.Equal(16, results[1].ObjectNumber);
|
||||||
Assert.Equal(32, results[1].Generation);
|
Assert.Equal(32, results[1].Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,26 +203,26 @@ trailer
|
|||||||
|
|
||||||
Assert.Equal(5, result.ObjectOffsets.Count);
|
Assert.Equal(5, result.ObjectOffsets.Count);
|
||||||
|
|
||||||
var results = result.ObjectOffsets.Select(x => new { x.Key.Number, x.Key.Generation, x.Value }).ToList();
|
var results = result.ObjectOffsets.Select(x => new { x.Key.ObjectNumber, x.Key.Generation, x.Value }).ToList();
|
||||||
|
|
||||||
Assert.Equal(100, results[0].Value);
|
Assert.Equal(100, results[0].Value);
|
||||||
Assert.Equal(1, results[0].Number);
|
Assert.Equal(1, results[0].ObjectNumber);
|
||||||
Assert.Equal(0, results[0].Generation);
|
Assert.Equal(0, results[0].Generation);
|
||||||
|
|
||||||
Assert.Equal(200, results[1].Value);
|
Assert.Equal(200, results[1].Value);
|
||||||
Assert.Equal(2, results[1].Number);
|
Assert.Equal(2, results[1].ObjectNumber);
|
||||||
Assert.Equal(5, results[1].Generation);
|
Assert.Equal(5, results[1].Generation);
|
||||||
|
|
||||||
Assert.Equal(230, results[2].Value);
|
Assert.Equal(230, results[2].Value);
|
||||||
Assert.Equal(3, results[2].Number);
|
Assert.Equal(3, results[2].ObjectNumber);
|
||||||
Assert.Equal(5, results[2].Generation);
|
Assert.Equal(5, results[2].Generation);
|
||||||
|
|
||||||
Assert.Equal(190, results[3].Value);
|
Assert.Equal(190, results[3].Value);
|
||||||
Assert.Equal(15, results[3].Number);
|
Assert.Equal(15, results[3].ObjectNumber);
|
||||||
Assert.Equal(7, results[3].Generation);
|
Assert.Equal(7, results[3].Generation);
|
||||||
|
|
||||||
Assert.Equal(250, results[4].Value);
|
Assert.Equal(250, results[4].Value);
|
||||||
Assert.Equal(16, results[4].Number);
|
Assert.Equal(16, results[4].ObjectNumber);
|
||||||
Assert.Equal(32, results[4].Generation);
|
Assert.Equal(32, results[4].Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,34 +1,29 @@
|
|||||||
namespace UglyToad.PdfPig.Cos
|
namespace UglyToad.PdfPig.Cos
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using ContentStream;
|
||||||
|
|
||||||
internal class CosObjectPool
|
internal class CosObjectPool
|
||||||
{
|
{
|
||||||
private readonly Dictionary<CosObjectKey, CosObject> objects = new Dictionary<CosObjectKey, CosObject>();
|
private readonly Dictionary<IndirectReference, CosObject> objects = new Dictionary<IndirectReference, CosObject>();
|
||||||
|
|
||||||
public CosObject Get(CosObjectKey key)
|
public CosObject Get(IndirectReference key)
|
||||||
{
|
{
|
||||||
if (key != null)
|
if (objects.TryGetValue(key, out var value))
|
||||||
{
|
{
|
||||||
if (objects.TryGetValue(key, out var value))
|
return value;
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this was a forward reference, make "proxy" object
|
// this was a forward reference, make "proxy" object
|
||||||
var obj = new CosObject(null);
|
var obj = new CosObject(null);
|
||||||
if (key != null)
|
obj.SetObjectNumber(key.ObjectNumber);
|
||||||
{
|
obj.SetGenerationNumber(key.Generation);
|
||||||
obj.SetObjectNumber(key.Number);
|
objects[key] = obj;
|
||||||
obj.SetGenerationNumber((int)key.Generation);
|
|
||||||
objects[key] = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CosObject GetOrCreateDefault(CosObjectKey key)
|
public CosObject GetOrCreateDefault(IndirectReference key)
|
||||||
{
|
{
|
||||||
if (!objects.TryGetValue(key, out CosObject obj))
|
if (!objects.TryGetValue(key, out CosObject obj))
|
||||||
{
|
{
|
||||||
|
@@ -9,15 +9,15 @@
|
|||||||
{
|
{
|
||||||
public CrossReferenceType Type { get; }
|
public CrossReferenceType Type { get; }
|
||||||
|
|
||||||
private readonly Dictionary<CosObjectKey, long> objectOffsets;
|
private readonly Dictionary<IndirectReference, long> objectOffsets;
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
public IReadOnlyDictionary<CosObjectKey, long> ObjectOffsets => objectOffsets;
|
public IReadOnlyDictionary<IndirectReference, long> ObjectOffsets => objectOffsets;
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
public PdfDictionary Dictionary { get; }
|
public PdfDictionary Dictionary { get; }
|
||||||
|
|
||||||
public CrossReferenceTable(CrossReferenceType type, IReadOnlyDictionary<CosObjectKey, long> objectOffsets, PdfDictionary dictionary)
|
public CrossReferenceTable(CrossReferenceType type, IReadOnlyDictionary<IndirectReference, long> objectOffsets, PdfDictionary dictionary)
|
||||||
{
|
{
|
||||||
if (objectOffsets == null)
|
if (objectOffsets == null)
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
Type = type;
|
Type = type;
|
||||||
Dictionary = dictionary ?? throw new ArgumentNullException(nameof(dictionary));
|
Dictionary = dictionary ?? throw new ArgumentNullException(nameof(dictionary));
|
||||||
|
|
||||||
var result = new Dictionary<CosObjectKey, long>();
|
var result = new Dictionary<IndirectReference, long>();
|
||||||
foreach (var objectOffset in objectOffsets)
|
foreach (var objectOffset in objectOffsets)
|
||||||
{
|
{
|
||||||
result[objectOffset.Key] = objectOffset.Value;
|
result[objectOffset.Key] = objectOffset.Value;
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
this.objectOffsets = result;
|
this.objectOffsets = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateOffset(CosObjectKey key, long offset)
|
public void UpdateOffset(IndirectReference key, long offset)
|
||||||
{
|
{
|
||||||
objectOffsets[key] = offset;
|
objectOffsets[key] = offset;
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,7 @@
|
|||||||
{
|
{
|
||||||
CrossReferenceType type = CrossReferenceType.Table;
|
CrossReferenceType type = CrossReferenceType.Table;
|
||||||
PdfDictionary trailerDictionary = new PdfDictionary();
|
PdfDictionary trailerDictionary = new PdfDictionary();
|
||||||
Dictionary<CosObjectKey, long> objectOffsets = new Dictionary<CosObjectKey, long>();
|
Dictionary<IndirectReference, long> objectOffsets = new Dictionary<IndirectReference, long>();
|
||||||
|
|
||||||
List<long> xrefSeqBytePos = new List<long>();
|
List<long> xrefSeqBytePos = new List<long>();
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal class CrossReferenceTablePart
|
internal class CrossReferenceTablePart
|
||||||
{
|
{
|
||||||
public IReadOnlyDictionary<CosObjectKey, long> ObjectOffsets { get; }
|
public IReadOnlyDictionary<IndirectReference, long> ObjectOffsets { get; }
|
||||||
|
|
||||||
public long Offset { get; private set; }
|
public long Offset { get; private set; }
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
public CrossReferenceType Type { get; }
|
public CrossReferenceType Type { get; }
|
||||||
|
|
||||||
public CrossReferenceTablePart(IReadOnlyDictionary<CosObjectKey, long> objectOffsets, long offset, long previous, PdfDictionary dictionary, CrossReferenceType type)
|
public CrossReferenceTablePart(IReadOnlyDictionary<IndirectReference, long> objectOffsets, long offset, long previous, PdfDictionary dictionary, CrossReferenceType type)
|
||||||
{
|
{
|
||||||
ObjectOffsets = objectOffsets;
|
ObjectOffsets = objectOffsets;
|
||||||
Offset = offset;
|
Offset = offset;
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
internal class CrossReferenceTablePartBuilder
|
internal class CrossReferenceTablePartBuilder
|
||||||
{
|
{
|
||||||
private readonly Dictionary<CosObjectKey, long> objects = new Dictionary<CosObjectKey, long>();
|
private readonly Dictionary<IndirectReference, long> objects = new Dictionary<IndirectReference, long>();
|
||||||
|
|
||||||
public long Offset { get; set; }
|
public long Offset { get; set; }
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
public void Add(long objectId, int generationNumber, long offset)
|
public void Add(long objectId, int generationNumber, long offset)
|
||||||
{
|
{
|
||||||
CosObjectKey objKey = new CosObjectKey(objectId, generationNumber);
|
IndirectReference objKey = new IndirectReference(objectId, generationNumber);
|
||||||
|
|
||||||
if (!objects.ContainsKey(objKey))
|
if (!objects.ContainsKey(objKey))
|
||||||
{
|
{
|
||||||
|
@@ -63,7 +63,7 @@
|
|||||||
throw new ArgumentNullException(nameof(pool));
|
throw new ArgumentNullException(nameof(pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = new CosObjectKey(objectNumber, objectGeneration);
|
var key = new IndirectReference(objectNumber, objectGeneration);
|
||||||
|
|
||||||
var pdfObject = pool.GetOrCreateDefault(key);
|
var pdfObject = pool.GetOrCreateDefault(key);
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CosBase ParseObjectFromFile(long offset, IRandomAccessRead reader,
|
private CosBase ParseObjectFromFile(long offset, IRandomAccessRead reader,
|
||||||
CosObjectKey key,
|
IndirectReference key,
|
||||||
CosObjectPool pool,
|
CosObjectPool pool,
|
||||||
bool isLenientParsing)
|
bool isLenientParsing)
|
||||||
{
|
{
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
|
|
||||||
ReadHelper.ReadExpectedString(reader, "obj", true);
|
ReadHelper.ReadExpectedString(reader, "obj", true);
|
||||||
|
|
||||||
if (objectNumber != key.Number || objectGeneration != key.Generation)
|
if (objectNumber != key.ObjectNumber || objectGeneration != key.Generation)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Xref for {key} points to object {objectNumber} {objectGeneration} at {offset}");
|
throw new InvalidOperationException($"Xref for {key} points to object {objectNumber} {objectGeneration} at {offset}");
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@
|
|||||||
// register all objects which are referenced to be contained in object stream
|
// register all objects which are referenced to be contained in object stream
|
||||||
foreach (var next in objects)
|
foreach (var next in objects)
|
||||||
{
|
{
|
||||||
var streamKey = new CosObjectKey(next);
|
var streamKey = new IndirectReference(next.GetObjectNumber(), next.GetGenerationNumber());
|
||||||
var offset = TryGet(streamKey, crossReferenceTable.ObjectOffsets);
|
var offset = TryGet(streamKey, crossReferenceTable.ObjectOffsets);
|
||||||
|
|
||||||
if (offset != null && offset == -streamObjectNumber)
|
if (offset != null && offset == -streamObjectNumber)
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using ContentStream;
|
||||||
using Cos;
|
using Cos;
|
||||||
using IO;
|
using IO;
|
||||||
using Parts;
|
using Parts;
|
||||||
@@ -12,9 +13,9 @@
|
|||||||
{
|
{
|
||||||
private static readonly long MINIMUM_SEARCH_OFFSET = 6;
|
private static readonly long MINIMUM_SEARCH_OFFSET = 6;
|
||||||
|
|
||||||
private Dictionary<CosObjectKey, long> bfSearchCOSObjectKeyOffsets;
|
private Dictionary<IndirectReference, long> bfSearchCOSObjectKeyOffsets;
|
||||||
|
|
||||||
private bool validateXrefOffsets(IRandomAccessRead reader, Dictionary<CosObjectKey, long> xrefOffset)
|
private bool validateXrefOffsets(IRandomAccessRead reader, Dictionary<IndirectReference, long> xrefOffset)
|
||||||
{
|
{
|
||||||
if (xrefOffset == null)
|
if (xrefOffset == null)
|
||||||
{
|
{
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
}
|
}
|
||||||
foreach (var objectEntry in xrefOffset)
|
foreach (var objectEntry in xrefOffset)
|
||||||
{
|
{
|
||||||
CosObjectKey objectKey = objectEntry.Key;
|
IndirectReference objectKey = objectEntry.Key;
|
||||||
long objectOffset = objectEntry.Value;
|
long objectOffset = objectEntry.Value;
|
||||||
// a negative offset number represents a object number itself
|
// a negative offset number represents a object number itself
|
||||||
// see type 2 entry in xref stream
|
// see type 2 entry in xref stream
|
||||||
@@ -37,14 +38,14 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool checkObjectKeys(IRandomAccessRead source, CosObjectKey objectKey, long offset)
|
private bool checkObjectKeys(IRandomAccessRead source, IndirectReference objectKey, long offset)
|
||||||
{
|
{
|
||||||
// there can't be any object at the very beginning of a pdf
|
// there can't be any object at the very beginning of a pdf
|
||||||
if (offset < MINIMUM_SEARCH_OFFSET)
|
if (offset < MINIMUM_SEARCH_OFFSET)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long objectNr = objectKey.Number;
|
long objectNr = objectKey.ObjectNumber;
|
||||||
long objectGen = objectKey.Generation;
|
long objectGen = objectKey.Generation;
|
||||||
long originOffset = source.GetPosition();
|
long originOffset = source.GetPosition();
|
||||||
string objectString = ObjectHelper.createObjectString(objectNr, objectGen);
|
string objectString = ObjectHelper.createObjectString(objectNr, objectGen);
|
||||||
@@ -71,7 +72,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Dictionary<CosObjectKey, long> getBFCosObjectOffsets(IRandomAccessRead reader)
|
private Dictionary<IndirectReference, long> getBFCosObjectOffsets(IRandomAccessRead reader)
|
||||||
{
|
{
|
||||||
if (bfSearchCOSObjectKeyOffsets == null)
|
if (bfSearchCOSObjectKeyOffsets == null)
|
||||||
{
|
{
|
||||||
@@ -83,7 +84,7 @@
|
|||||||
private void bfSearchForObjects(IRandomAccessRead source)
|
private void bfSearchForObjects(IRandomAccessRead source)
|
||||||
{
|
{
|
||||||
bfSearchForLastEOFMarker(source);
|
bfSearchForLastEOFMarker(source);
|
||||||
bfSearchCOSObjectKeyOffsets = new Dictionary<CosObjectKey, long>();
|
bfSearchCOSObjectKeyOffsets = new Dictionary<IndirectReference, long>();
|
||||||
long originOffset = source.GetPosition();
|
long originOffset = source.GetPosition();
|
||||||
long currentOffset = MINIMUM_SEARCH_OFFSET;
|
long currentOffset = MINIMUM_SEARCH_OFFSET;
|
||||||
long lastObjectId = long.MinValue;
|
long lastObjectId = long.MinValue;
|
||||||
@@ -125,7 +126,7 @@
|
|||||||
if (lastObjOffset > 0)
|
if (lastObjOffset > 0)
|
||||||
{
|
{
|
||||||
// add the former object ID only if there was a subsequent object ID
|
// add the former object ID only if there was a subsequent object ID
|
||||||
bfSearchCOSObjectKeyOffsets[new CosObjectKey(lastObjectId, lastGenID)] = lastObjOffset;
|
bfSearchCOSObjectKeyOffsets[new IndirectReference(lastObjectId, lastGenID)] = lastObjOffset;
|
||||||
}
|
}
|
||||||
lastObjectId = objectId;
|
lastObjectId = objectId;
|
||||||
lastGenID = genID;
|
lastGenID = genID;
|
||||||
@@ -147,7 +148,7 @@
|
|||||||
{
|
{
|
||||||
// if the pdf wasn't cut off in the middle or if the last object ends with a "endobj" marker
|
// if the pdf wasn't cut off in the middle or if the last object ends with a "endobj" marker
|
||||||
// the last object id has to be added here so that it can't get lost as there isn't any subsequent object id
|
// the last object id has to be added here so that it can't get lost as there isn't any subsequent object id
|
||||||
bfSearchCOSObjectKeyOffsets[new CosObjectKey(lastObjectId, lastGenID)] = lastObjOffset;
|
bfSearchCOSObjectKeyOffsets[new IndirectReference(lastObjectId, lastGenID)] = lastObjOffset;
|
||||||
}
|
}
|
||||||
// reestablish origin position
|
// reestablish origin position
|
||||||
|
|
||||||
@@ -166,33 +167,33 @@
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Dictionary<CosObjectKey, long> xrefOffset = xrefTrailerResolver.ObjectOffsets.ToDictionary(x => x.Key, x => x.Value);
|
Dictionary<IndirectReference, long> xrefOffset = xrefTrailerResolver.ObjectOffsets.ToDictionary(x => x.Key, x => x.Value);
|
||||||
if (validateXrefOffsets(reader, xrefOffset))
|
if (validateXrefOffsets(reader, xrefOffset))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<CosObjectKey, long> bfCOSObjectKeyOffsets = getBFCosObjectOffsets(reader);
|
Dictionary<IndirectReference, long> bfCOSObjectKeyOffsets = getBFCosObjectOffsets(reader);
|
||||||
if (bfCOSObjectKeyOffsets.Count > 0)
|
if (bfCOSObjectKeyOffsets.Count > 0)
|
||||||
{
|
{
|
||||||
List<CosObjectKey> objStreams = new List<CosObjectKey>();
|
List<IndirectReference> objStreams = new List<IndirectReference>();
|
||||||
// find all object streams
|
// find all object streams
|
||||||
foreach (var entry in xrefOffset)
|
foreach (var entry in xrefOffset)
|
||||||
{
|
{
|
||||||
long offset = entry.Value;
|
long offset = entry.Value;
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
{
|
{
|
||||||
CosObjectKey objStream = new CosObjectKey(-offset, 0);
|
IndirectReference objStream = new IndirectReference(-offset, 0);
|
||||||
if (!objStreams.Contains(objStream))
|
if (!objStreams.Contains(objStream))
|
||||||
{
|
{
|
||||||
objStreams.Add(new CosObjectKey(-offset, 0));
|
objStreams.Add(new IndirectReference(-offset, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove all found object streams
|
// remove all found object streams
|
||||||
if (objStreams.Count > 0)
|
if (objStreams.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (CosObjectKey key in objStreams)
|
foreach (IndirectReference key in objStreams)
|
||||||
{
|
{
|
||||||
if (bfCOSObjectKeyOffsets.ContainsKey(key))
|
if (bfCOSObjectKeyOffsets.ContainsKey(key))
|
||||||
{
|
{
|
||||||
|
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
public CosBase Parse(IndirectReference indirectReference, IRandomAccessRead reader, bool isLenientParsing = true, bool requireExistingObject = false)
|
public CosBase Parse(IndirectReference indirectReference, IRandomAccessRead reader, bool isLenientParsing = true, bool requireExistingObject = false)
|
||||||
{
|
{
|
||||||
var key = new CosObjectKey(indirectReference.ObjectNumber, indirectReference.Generation);
|
var key = new IndirectReference(indirectReference.ObjectNumber, indirectReference.Generation);
|
||||||
|
|
||||||
var pdfObject = objectPool.GetOrCreateDefault(key);
|
var pdfObject = objectPool.GetOrCreateDefault(key);
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
return CosNull.Null;
|
return CosNull.Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidOperationException($"Could not locate the object {key.Number} which was not found in the cross reference table.");
|
throw new InvalidOperationException($"Could not locate the object {key.ObjectNumber} which was not found in the cross reference table.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var isCompressedStreamObject = offsetOrStreamNumber <= 0;
|
var isCompressedStreamObject = offsetOrStreamNumber <= 0;
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CosBase ParseObjectFromFile(long offset, IRandomAccessRead reader,
|
private CosBase ParseObjectFromFile(long offset, IRandomAccessRead reader,
|
||||||
CosObjectKey key,
|
IndirectReference key,
|
||||||
CosObjectPool pool,
|
CosObjectPool pool,
|
||||||
bool isLenientParsing)
|
bool isLenientParsing)
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
|
|
||||||
ReadHelper.ReadExpectedString(reader, "obj", true);
|
ReadHelper.ReadExpectedString(reader, "obj", true);
|
||||||
|
|
||||||
if (objectNumber != key.Number || objectGeneration != key.Generation)
|
if (objectNumber != key.ObjectNumber || objectGeneration != key.Generation)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Xref for {key} points to object {objectNumber} {objectGeneration} at {offset}");
|
throw new InvalidOperationException($"Xref for {key} points to object {objectNumber} {objectGeneration} at {offset}");
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@
|
|||||||
// register all objects which are referenced to be contained in object stream
|
// register all objects which are referenced to be contained in object stream
|
||||||
foreach (var next in objects)
|
foreach (var next in objects)
|
||||||
{
|
{
|
||||||
var streamKey = new CosObjectKey(next);
|
var streamKey = new IndirectReference(next.GetObjectNumber(), next.GetGenerationNumber());
|
||||||
var offset = TryGet(streamKey, crossReferenceTable.ObjectOffsets);
|
var offset = TryGet(streamKey, crossReferenceTable.ObjectOffsets);
|
||||||
|
|
||||||
if (offset != null && offset == -streamObjectNumber)
|
if (offset != null && offset == -streamObjectNumber)
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Cos;
|
using ContentStream;
|
||||||
using IO;
|
using IO;
|
||||||
using Util;
|
using Util;
|
||||||
using Util.JetBrains.Annotations;
|
using Util.JetBrains.Annotations;
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
private readonly IRandomAccessRead reader;
|
private readonly IRandomAccessRead reader;
|
||||||
|
|
||||||
private Dictionary<CosObjectKey, long> objectLocations;
|
private Dictionary<IndirectReference, long> objectLocations;
|
||||||
|
|
||||||
public BruteForceSearcher([NotNull] IRandomAccessRead reader)
|
public BruteForceSearcher([NotNull] IRandomAccessRead reader)
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
public IReadOnlyDictionary<CosObjectKey, long> GetObjectLocations()
|
public IReadOnlyDictionary<IndirectReference, long> GetObjectLocations()
|
||||||
{
|
{
|
||||||
if (objectLocations != null)
|
if (objectLocations != null)
|
||||||
{
|
{
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
var lastEndOfFile = GetLastEndOfFileMarker();
|
var lastEndOfFile = GetLastEndOfFileMarker();
|
||||||
|
|
||||||
var results = new Dictionary<CosObjectKey, long>();
|
var results = new Dictionary<IndirectReference, long>();
|
||||||
|
|
||||||
var originPosition = reader.GetPosition();
|
var originPosition = reader.GetPosition();
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
if (lastObjOffset > 0)
|
if (lastObjOffset > 0)
|
||||||
{
|
{
|
||||||
// add the former object ID only if there was a subsequent object ID
|
// add the former object ID only if there was a subsequent object ID
|
||||||
results[new CosObjectKey(lastObjectId, lastGenerationId)] = lastObjOffset;
|
results[new IndirectReference(lastObjectId, lastGenerationId)] = lastObjOffset;
|
||||||
}
|
}
|
||||||
lastObjectId = objectId;
|
lastObjectId = objectId;
|
||||||
lastGenerationId = generationId;
|
lastGenerationId = generationId;
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
{
|
{
|
||||||
// if the pdf wasn't cut off in the middle or if the last object ends with a "endobj" marker
|
// if the pdf wasn't cut off in the middle or if the last object ends with a "endobj" marker
|
||||||
// the last object id has to be added here so that it can't get lost as there isn't any subsequent object id
|
// the last object id has to be added here so that it can't get lost as there isn't any subsequent object id
|
||||||
results[new CosObjectKey(lastObjectId, lastGenerationId)] = lastObjOffset;
|
results[new IndirectReference(lastObjectId, lastGenerationId)] = lastObjOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reestablish origin position
|
// reestablish origin position
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace UglyToad.PdfPig.Parser.Parts
|
namespace UglyToad.PdfPig.Parser.Parts
|
||||||
{
|
{
|
||||||
|
using ContentStream;
|
||||||
using Cos;
|
using Cos;
|
||||||
using IO;
|
using IO;
|
||||||
using Util;
|
using Util;
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
if (po.get(po.size() - 1) is CosInt)
|
if (po.get(po.size() - 1) is CosInt)
|
||||||
{
|
{
|
||||||
var number = (CosInt)po.remove(po.size() - 1);
|
var number = (CosInt)po.remove(po.size() - 1);
|
||||||
CosObjectKey key = new CosObjectKey(number.AsLong(), genNumber.AsInt());
|
IndirectReference key = new IndirectReference(number.AsLong(), genNumber.AsInt());
|
||||||
pbo = pool.Get(key);
|
pbo = pool.Get(key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -156,7 +156,7 @@
|
|||||||
throw new InvalidOperationException("expected number, actual=" + value + " at offset " + genOffset);
|
throw new InvalidOperationException("expected number, actual=" + value + " at offset " + genOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = new CosObjectKey(((CosInt)value).AsLong(), ((CosInt)generationNumber).AsInt());
|
var key = new IndirectReference(((CosInt)value).AsLong(), ((CosInt)generationNumber).AsInt());
|
||||||
|
|
||||||
// dereference the object
|
// dereference the object
|
||||||
return pool.Get(key);
|
return pool.Get(key);
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
using Content;
|
using Content;
|
||||||
using ContentStream;
|
using ContentStream;
|
||||||
using Cos;
|
using Cos;
|
||||||
|
using Exceptions;
|
||||||
using FileStructure;
|
using FileStructure;
|
||||||
using Filters;
|
using Filters;
|
||||||
using Fonts;
|
using Fonts;
|
||||||
@@ -102,7 +103,7 @@
|
|||||||
|
|
||||||
if (!(root is PdfDictionary rootDictionary))
|
if (!(root is PdfDictionary rootDictionary))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Expected root dictionary, but got this: " + root);
|
throw new PdfDocumentFormatException("Expected root dictionary, but got this: " + root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// in some pdfs the type value "Catalog" is missing in the root object
|
// in some pdfs the type value "Catalog" is missing in the root object
|
||||||
@@ -117,6 +118,8 @@
|
|||||||
|
|
||||||
var caching = new ParsingCachingProviders(pool, bruteForceSearcher, resourceContainer);
|
var caching = new ParsingCachingProviders(pool, bruteForceSearcher, resourceContainer);
|
||||||
|
|
||||||
|
var pdfScanner = new PdfTokenScanner(inputBytes, null);
|
||||||
|
|
||||||
return new PdfDocument(log, reader, version, crossReferenceTable, isLenientParsing, caching, pageFactory, pdfObjectParser, catalog, information);
|
return new PdfDocument(log, reader, version, crossReferenceTable, isLenientParsing, caching, pageFactory, pdfObjectParser, catalog, information);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
namespace UglyToad.PdfPig.Tokenization.Scanner
|
namespace UglyToad.PdfPig.Tokenization.Scanner
|
||||||
{
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
using ContentStream;
|
using ContentStream;
|
||||||
|
using Cos;
|
||||||
|
using Parser.Parts;
|
||||||
|
|
||||||
internal interface IObjectLocationProvider
|
internal interface IObjectLocationProvider
|
||||||
{
|
{
|
||||||
@@ -8,4 +11,30 @@
|
|||||||
|
|
||||||
void UpdateOffset(IndirectReference reference, long offset);
|
void UpdateOffset(IndirectReference reference, long offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class ObjectLocationProvider : IObjectLocationProvider
|
||||||
|
{
|
||||||
|
private readonly CrossReferenceTable crossReferenceTable;
|
||||||
|
private readonly CosObjectPool pool;
|
||||||
|
private readonly BruteForceSearcher searcher;
|
||||||
|
|
||||||
|
private readonly Dictionary<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
|
||||||
|
|
||||||
|
public ObjectLocationProvider(CrossReferenceTable crossReferenceTable, CosObjectPool pool, BruteForceSearcher searcher)
|
||||||
|
{
|
||||||
|
this.crossReferenceTable = crossReferenceTable;
|
||||||
|
this.pool = pool;
|
||||||
|
this.searcher = searcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetOffset(IndirectReference reference, out long offset)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateOffset(IndirectReference reference, long offset)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user