mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-01-18 19:51:24 +08:00
support writing non-sequential xref tables
This commit is contained in:
@@ -151,14 +151,6 @@
|
||||
outputStream.Write(Xref, 0, Xref.Length);
|
||||
WriteLineBreak(outputStream);
|
||||
|
||||
var min = objectOffsets.Min(x => x.Key.ObjectNumber);
|
||||
var max = objectOffsets.Max(x => x.Key.ObjectNumber);
|
||||
|
||||
if (max - min != objectOffsets.Count - 1)
|
||||
{
|
||||
throw new NotSupportedException("Object numbers must form a contiguous range");
|
||||
}
|
||||
|
||||
WriteLong(0, outputStream);
|
||||
WriteWhitespace(outputStream);
|
||||
// 1 extra for the free entry.
|
||||
@@ -231,6 +223,87 @@
|
||||
outputStream.Write(Eof, 0, Eof.Length);
|
||||
}
|
||||
|
||||
private static void WriteCrossReferenceTable(IReadOnlyDictionary<IndirectReference, long> objectOffsets, Stream outputStream)
|
||||
{
|
||||
var sets = new List<XrefSeries>();
|
||||
|
||||
var orderedList = objectOffsets.OrderBy(x => x.Key.ObjectNumber).ToList();
|
||||
|
||||
long firstObjectNumber = 0;
|
||||
long currentObjNum = 0;
|
||||
var items = new List<XrefSeries.OffsetAndGeneration>
|
||||
{
|
||||
// Zero entry
|
||||
null
|
||||
};
|
||||
|
||||
foreach (var item in orderedList)
|
||||
{
|
||||
var step = item.Key.ObjectNumber - currentObjNum;
|
||||
if (step == 1)
|
||||
{
|
||||
currentObjNum = item.Key.ObjectNumber;
|
||||
items.Add(new XrefSeries.OffsetAndGeneration(item.Value, item.Key.Generation));
|
||||
}
|
||||
else
|
||||
{
|
||||
sets.Add(new XrefSeries(firstObjectNumber, items));
|
||||
items = new List<XrefSeries.OffsetAndGeneration>
|
||||
{
|
||||
new XrefSeries.OffsetAndGeneration(item.Value, item.Key.Generation)
|
||||
};
|
||||
|
||||
currentObjNum = item.Key.ObjectNumber;
|
||||
firstObjectNumber = item.Key.ObjectNumber;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var series in sets)
|
||||
{
|
||||
WriteLong(0, outputStream);
|
||||
WriteWhitespace(outputStream);
|
||||
// 1 extra for the free entry.
|
||||
WriteLong(series.Offsets.Count, outputStream);
|
||||
|
||||
WriteWhitespace(outputStream);
|
||||
WriteLineBreak(outputStream);
|
||||
|
||||
foreach (var offset in series.Offsets)
|
||||
{
|
||||
if (offset != null)
|
||||
{
|
||||
/*
|
||||
* nnnnnnnnnn ggggg n eol
|
||||
* where:
|
||||
* nnnnnnnnnn is a 10-digit byte offset
|
||||
* ggggg is a 5-digit generation number
|
||||
* 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')
|
||||
*/
|
||||
var paddedOffset = OtherEncodings.StringAsLatin1Bytes(offset.Offset.ToString("D10", CultureInfo.InvariantCulture));
|
||||
outputStream.Write(paddedOffset, 0, paddedOffset.Length);
|
||||
|
||||
WriteWhitespace(outputStream);
|
||||
|
||||
var generation = OtherEncodings.StringAsLatin1Bytes(offset.Generation.ToString("D5", CultureInfo.InvariantCulture));
|
||||
outputStream.Write(generation, 0, generation.Length);
|
||||
|
||||
WriteWhitespace(outputStream);
|
||||
|
||||
outputStream.WriteByte(InUseEntry);
|
||||
|
||||
WriteWhitespace(outputStream);
|
||||
WriteLineBreak(outputStream);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteFirstXrefEmptyEntry(outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes pre-serialized token as an object token to the output stream.
|
||||
/// </summary>
|
||||
@@ -524,6 +597,32 @@
|
||||
|
||||
return bytes[0];
|
||||
}
|
||||
|
||||
private class XrefSeries
|
||||
{
|
||||
public long First { get; }
|
||||
|
||||
public IReadOnlyList<OffsetAndGeneration> Offsets { get; }
|
||||
|
||||
public XrefSeries(long first, IReadOnlyList<OffsetAndGeneration> offsets)
|
||||
{
|
||||
First = first;
|
||||
Offsets = offsets;
|
||||
}
|
||||
|
||||
public class OffsetAndGeneration
|
||||
{
|
||||
public long Offset { get; }
|
||||
|
||||
public long Generation { get; }
|
||||
|
||||
public OffsetAndGeneration(long offset, long generation)
|
||||
{
|
||||
Offset = offset;
|
||||
Generation = generation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user