writer util did not follow reference links #1032

when copying various dictionaries from a source document
to the builder any indirect references in the source document
would throw because the code expected the dictionary token
directly. now we follow the list of indirect references until we
find a non-indirect leaf token. also changes the exception type.
This commit is contained in:
EliotJones
2025-07-05 16:55:04 -05:00
committed by BobLd
parent f099dd5827
commit daaac9350d
2 changed files with 30 additions and 31 deletions

View File

@@ -831,7 +831,7 @@
// We need to relocate the resources, and we have to make sure that none of the resources collide with
// the already written operation's resources
var resources = pageDictionary.GetOrCreateDict(NameToken.Resources);
var resources = pageDictionary.GetOrCreateDict(NameToken.Resources, srcPage.pdfScanner);
foreach (var set in srcResourceDictionary.Data)
{
@@ -858,7 +858,7 @@
// Since we don't directly add font's to the pages resources, we have to go look at the document's font
if (srcResourceDictionary.TryGet(NameToken.Font, srcPage.pdfScanner, out DictionaryToken? fontsDictionary))
{
var pageFontsDictionary = resources.GetOrCreateDict(NameToken.Font);
var pageFontsDictionary = resources.GetOrCreateDict(NameToken.Font, srcPage.pdfScanner);
foreach (var fontSet in fontsDictionary.Data)
{
@@ -903,7 +903,7 @@
// Since we don't directly add xobjects's to the pages resources, we have to go look at the document's xobjects
if (srcResourceDictionary.TryGet(NameToken.Xobject, srcPage.pdfScanner, out DictionaryToken? xobjectsDictionary))
{
var pageXobjectsDictionary = resources.GetOrCreateDict(NameToken.Xobject);
var pageXobjectsDictionary = resources.GetOrCreateDict(NameToken.Xobject, srcPage.pdfScanner);
foreach (var xobjectSet in xobjectsDictionary.Data)
{
@@ -945,7 +945,7 @@
// Since we don't directly add xobjects's to the pages resources, we have to go look at the document's xobjects
if (srcResourceDictionary.TryGet(NameToken.ExtGState, srcPage.pdfScanner, out DictionaryToken? gsDictionary))
{
var pageGstateDictionary = resources.GetOrCreateDict(NameToken.ExtGState);
var pageGstateDictionary = resources.GetOrCreateDict(NameToken.ExtGState, srcPage.pdfScanner);
foreach (var gstate in gsDictionary.Data)
{

View File

@@ -12,13 +12,36 @@
internal static class WriterUtil
{
public static Dictionary<string, IToken> GetOrCreateDict(this Dictionary<NameToken, IToken> dict, NameToken key)
public static Dictionary<string, IToken> GetOrCreateDict<T>(
this Dictionary<T, IToken> dict,
T key,
IPdfTokenScanner? sourceScanner = null) where T : notnull
{
if (dict.TryGetValue(key, out var item))
{
if (!(item is DictionaryToken dt))
var chainCount = 0;
var itemChain = item;
while (itemChain is IndirectReferenceToken ir && chainCount < 100)
{
throw new ApplicationException("Expected dictionary token, got " + item.GetType());
if (sourceScanner == null)
{
break;
}
itemChain = sourceScanner.Get(ir.Data);
chainCount++;
if (itemChain is ObjectToken ot)
{
itemChain = ot.Data;
}
}
if (itemChain is not DictionaryToken dt)
{
throw new InvalidOperationException(
$"While trying to copy token called {key} which should have been a dictionary token we found a token of type {item.GetType()}");
}
if (dt.Data is Dictionary<string, IToken> mutable)
@@ -37,30 +60,6 @@
return created;
}
public static Dictionary<string, IToken> GetOrCreateDict(this Dictionary<string, IToken> dict, string key)
{
if (dict.TryGetValue(key, out var item))
{
if (!(item is DictionaryToken dt))
{
throw new ApplicationException("Expected dictionary token, got " + item.GetType());
}
if (dt.Data is Dictionary<string, IToken> mutable)
{
return mutable;
}
mutable = dt.Data.
ToDictionary(x => x.Key, x => x.Value);
dict[key] = DictionaryToken.With(mutable);
return mutable;
}
var created = new Dictionary<string, IToken>();
dict[key] = DictionaryToken.With(created);
return created;
}
/// <summary>
/// The purpose of this method is to resolve indirect reference. That mean copy the reference's content to the new document's stream
/// and replace the indirect reference with the correct/new one