/// <summary> /// Get any embedded files contained in this PDF document. /// Since PDF 1.3 any external file referenced by the document may have its contents embedded within the referring PDF file, /// allowing its contents to be stored or transmitted along with the PDF file. /// </summary> /// <param name="embeddedFiles">The set of embedded files in this document.</param> /// <returns><see langword="true"/> if this document contains more than zero embedded files, otherwise <see langword="false"/>.</returns> public bool TryGetEmbeddedFiles(out IReadOnlyList <EmbeddedFile> embeddedFiles) { GuardDisposed(); embeddedFiles = null; if (!catalog.CatalogDictionary.TryGet(NameToken.Names, pdfScanner, out DictionaryToken namesDictionary) || !namesDictionary.TryGet(NameToken.EmbeddedFiles, pdfScanner, out DictionaryToken embeddedFileNamesDictionary)) { return(false); } var embeddedFileNames = NameTreeParser.FlattenNameTreeToDictionary(embeddedFileNamesDictionary, pdfScanner, isLenientParsing, x => x); if (embeddedFileNames.Count == 0) { return(false); } var result = new List <EmbeddedFile>(); foreach (var keyValuePair in embeddedFileNames) { if (!DirectObjectFinder.TryGet(keyValuePair.Value, pdfScanner, out DictionaryToken fileDescriptorDictionaryToken) || !fileDescriptorDictionaryToken.TryGet(NameToken.Ef, pdfScanner, out DictionaryToken efDictionary) || !efDictionary.TryGet(NameToken.F, pdfScanner, out StreamToken fileStreamToken)) { continue; } var fileSpecification = string.Empty; if (fileDescriptorDictionaryToken.TryGet(NameToken.F, pdfScanner, out IDataToken <string> fileSpecificationToken)) { fileSpecification = fileSpecificationToken.Data; } var fileBytes = fileStreamToken.Decode(filterProvider); result.Add(new EmbeddedFile(keyValuePair.Key, fileSpecification, fileBytes, fileStreamToken)); } embeddedFiles = result; return(embeddedFiles.Count > 0); }
private static IReadOnlyDictionary <string, ExplicitDestination> ReadNamedDestinations(Catalog catalog, IPdfTokenScanner pdfScanner, ILog log) { var result = new Dictionary <string, ExplicitDestination>(); if (catalog.CatalogDictionary.TryGet(NameToken.Dests, pdfScanner, out DictionaryToken dests)) { /* * In PDF 1.1, the correspondence between name objects and destinations is defined by the /Dests entry in the document catalog. * The value of this entry is a dictionary in which each key is a destination name and the corresponding value is either an array * defining the destination, using the explicit destination syntax, or a dictionary with a /D entry whose value is such an array. */ foreach (var kvp in dests.Data) { var value = kvp.Value; if (TryReadExplicitDestination(value, catalog, pdfScanner, log, out var destination)) { result[kvp.Key] = destination; } } } else if (catalog.CatalogDictionary.TryGet(NameToken.Names, pdfScanner, out DictionaryToken names) && names.TryGet(NameToken.Dests, pdfScanner, out dests)) { /* * In PDF 1.2, the correspondence between strings and destinations is defined by the /Dests entry in the document's name dictionary. * The value of the /Dests entry is a name tree mapping name strings to destinations. * The keys in the name tree may be treated as text strings for display purposes. * The destination value associated with a key in the name tree may be either an array or a dictionary. */ NameTreeParser.FlattenNameTree(dests, pdfScanner, value => { if (TryReadExplicitDestination(value, catalog, pdfScanner, log, out var destination)) { return(destination); } return(null); }, result); } return(result); }