diff --git a/fpdfsdk/fpdf_doc.cpp b/fpdfsdk/fpdf_doc.cpp index 799c5a592..c9f84a07b 100644 --- a/fpdfsdk/fpdf_doc.cpp +++ b/fpdfsdk/fpdf_doc.cpp @@ -773,4 +773,63 @@ EPDF_GetMetaKeyName(FPDF_DOCUMENT document, } } return 0; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +EPDF_RemoveXMPMetadata(FPDF_DOCUMENT document) { + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return false; + + RetainPtr root = pDoc->GetMutableRoot(); + if (!root) + return false; + + // /Metadata is the catalog-level XMP stream (ISO 32000 §14.3.2). It is stored + // separately from /Info, so clearing Info via EPDF_SetMetaText() does not + // touch it. Removing the key drops the XMP from the document. + root->RemoveFor("Metadata"); + return true; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +EPDF_RemoveEmbeddedThumbnails(FPDF_DOCUMENT document) { + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return false; + + const int count = pDoc->GetPageCount(); + for (int i = 0; i < count; ++i) { + RetainPtr page = pDoc->GetMutablePageDictionary(i); + if (page) + page->RemoveFor("Thumb"); + } + return true; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +EPDF_RemoveAllJavaScript(FPDF_DOCUMENT document) { + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return false; + + RetainPtr root = pDoc->GetMutableRoot(); + if (!root) + return false; + + // (1) Catalog /Names /JavaScript name tree (document-level scripts). + RetainPtr names = root->GetMutableDictFor("Names"); + if (names) + names->RemoveFor("JavaScript"); + + // (2) /OpenAction, but only when it is a JavaScript action — a GoTo + // destination OpenAction is legitimate navigation and is left intact. + RetainPtr open_action = root->GetDictFor("OpenAction"); + if (open_action && open_action->GetNameFor("S") == "JavaScript") + root->RemoveFor("OpenAction"); + + // (3) Catalog-level /AA additional-actions (e.g. WillClose/WillPrint scripts). + root->RemoveFor("AA"); + + return true; } \ No newline at end of file diff --git a/public/fpdf_doc.h b/public/fpdf_doc.h index 2feee5303..d7c5bfe52 100644 --- a/public/fpdf_doc.h +++ b/public/fpdf_doc.h @@ -517,6 +517,40 @@ EPDF_GetMetaKeyName(FPDF_DOCUMENT document, void* buffer, unsigned long buflen); +// Experimental EmbedPDF Extension API. +// Remove the document's XMP metadata stream (the catalog /Metadata entry). +// +// document - handle to the document. +// +// XMP metadata (ISO 32000 §14.3.2) is stored separately from the Info +// dictionary, so clearing Info via EPDF_SetMetaText() does not remove it. This +// is the #1 redaction-sanitization miss: author/title/history can survive in +// XMP. Returns true on success, including when no /Metadata is present. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +EPDF_RemoveXMPMetadata(FPDF_DOCUMENT document); + +// Experimental EmbedPDF Extension API. +// Remove every page's embedded thumbnail (the page /Thumb entry). +// +// document - handle to the document. +// +// An embedded thumbnail can retain a pre-redaction image of the page. Returns +// true on success, including when no thumbnails are present. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +EPDF_RemoveEmbeddedThumbnails(FPDF_DOCUMENT document); + +// Experimental EmbedPDF Extension API. +// Remove all document-level JavaScript from |document|: the catalog +// /Names /JavaScript name tree, /OpenAction when it is a JavaScript action +// (GoTo destinations are preserved), and the catalog /AA additional-actions +// dictionary. +// +// document - handle to the document. +// +// Returns true on success, including when no JavaScript is present. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +EPDF_RemoveAllJavaScript(FPDF_DOCUMENT document); + // Experimental EmbedPDF Extension API. // Create a new destination array of the form [page /XYZ left top zoom]. //