From 04bebfe590d6d27a825b881fd234e31501843edc Mon Sep 17 00:00:00 2001 From: thestig Date: Fri, 4 Nov 2016 16:07:25 -0700 Subject: Implement FPDF_VIEWERREF_GetName() API. This is a generic API function to retrieve any viewer preference of type name. BUG=pdfium:414 Review-Url: https://codereview.chromium.org/2475923003 --- core/fpdfdoc/cpdf_viewerpreferences.cpp | 16 +++++++ core/fpdfdoc/cpdf_viewerpreferences.h | 5 ++ fpdfsdk/fpdfview.cpp | 19 ++++++++ fpdfsdk/fpdfview_c_api_test.c | 1 + fpdfsdk/fpdfview_embeddertest.cpp | 48 ++++++++++++++++++- public/fpdf_doc.h | 2 +- public/fpdfview.h | 19 ++++++++ testing/resources/viewer_ref.in | 57 +++++++++++++++++++++++ testing/resources/viewer_ref.pdf | 82 +++++++++++++++++++++++++++++++++ 9 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 testing/resources/viewer_ref.in create mode 100644 testing/resources/viewer_ref.pdf diff --git a/core/fpdfdoc/cpdf_viewerpreferences.cpp b/core/fpdfdoc/cpdf_viewerpreferences.cpp index 799f2d5814..f1fc4b0347 100644 --- a/core/fpdfdoc/cpdf_viewerpreferences.cpp +++ b/core/fpdfdoc/cpdf_viewerpreferences.cpp @@ -7,6 +7,7 @@ #include "core/fpdfdoc/cpdf_viewerpreferences.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" CPDF_ViewerPreferences::CPDF_ViewerPreferences(CPDF_Document* pDoc) : m_pDoc(pDoc) {} @@ -38,6 +39,21 @@ CFX_ByteString CPDF_ViewerPreferences::Duplex() const { return pDict ? pDict->GetStringFor("Duplex") : CFX_ByteString("None"); } +bool CPDF_ViewerPreferences::GenericName(const CFX_ByteString& bsKey, + CFX_ByteString* bsVal) const { + ASSERT(bsVal); + CPDF_Dictionary* pDict = GetViewerPreferences(); + if (!pDict) + return false; + + const CPDF_Name* pName = ToName(pDict->GetObjectFor(bsKey)); + if (!pName) + return false; + + *bsVal = pName->GetString(); + return true; +} + CPDF_Dictionary* CPDF_ViewerPreferences::GetViewerPreferences() const { CPDF_Dictionary* pDict = m_pDoc->GetRoot(); return pDict ? pDict->GetDictFor("ViewerPreferences") : nullptr; diff --git a/core/fpdfdoc/cpdf_viewerpreferences.h b/core/fpdfdoc/cpdf_viewerpreferences.h index c64292d9f9..c7e9112380 100644 --- a/core/fpdfdoc/cpdf_viewerpreferences.h +++ b/core/fpdfdoc/cpdf_viewerpreferences.h @@ -25,6 +25,11 @@ class CPDF_ViewerPreferences { CPDF_Array* PrintPageRange() const; CFX_ByteString Duplex() const; + // Gets the entry for |bsKey|. If the entry exists and it is of type name, + // then this method writes the value into |bsVal| and returns true. Otherwise + // returns false and |bsVal| is untouched. |bsVal| must not be NULL. + bool GenericName(const CFX_ByteString& bsKey, CFX_ByteString* bsVal) const; + private: CPDF_Dictionary* GetViewerPreferences() const; diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index cde15dff9b..9142dc78c9 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -942,6 +942,25 @@ FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) { return DuplexUndefined; } +DLLEXPORT unsigned long STDCALL FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, + FPDF_BYTESTRING key, + char* buffer, + unsigned long length) { + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return 0; + + CPDF_ViewerPreferences viewRef(pDoc); + CFX_ByteString bsVal; + if (!viewRef.GenericName(key, &bsVal)) + return 0; + + unsigned long dwStringLen = bsVal.GetLength() + 1; + if (buffer && length >= dwStringLen) + memcpy(buffer, bsVal.c_str(), dwStringLen); + return dwStringLen; +} + DLLEXPORT FPDF_DWORD STDCALL FPDF_CountNamedDests(FPDF_DOCUMENT document) { CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); if (!pDoc) diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index 2f0cb49fc2..4847180e46 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -228,6 +228,7 @@ int CheckPDFiumCApi() { CHK(FPDF_VIEWERREF_GetNumCopies); CHK(FPDF_VIEWERREF_GetPrintPageRange); CHK(FPDF_VIEWERREF_GetDuplex); + CHK(FPDF_VIEWERREF_GetName); CHK(FPDF_CountNamedDests); CHK(FPDF_GetNamedDestByName); CHK(FPDF_GetNamedDest); diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp index 820d496bdc..e712edb89a 100644 --- a/fpdfsdk/fpdfview_embeddertest.cpp +++ b/fpdfsdk/fpdfview_embeddertest.cpp @@ -56,6 +56,10 @@ TEST_F(FPDFViewEmbeddertest, EmptyDocument) { EXPECT_EQ(1, FPDF_VIEWERREF_GetNumCopies(document())); EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document())); + char buf[100]; + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", nullptr, 0)); + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", buf, sizeof(buf))); + EXPECT_EQ(0u, FPDF_CountNamedDests(document())); } @@ -69,11 +73,53 @@ TEST_F(FPDFViewEmbeddertest, Page) { EXPECT_EQ(nullptr, LoadPage(1)); } -TEST_F(FPDFViewEmbeddertest, ViewerRef) { +TEST_F(FPDFViewEmbeddertest, ViewerRefDummy) { EXPECT_TRUE(OpenDocument("about_blank.pdf")); EXPECT_TRUE(FPDF_VIEWERREF_GetPrintScaling(document())); EXPECT_EQ(1, FPDF_VIEWERREF_GetNumCopies(document())); EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document())); + + char buf[100]; + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", nullptr, 0)); + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", buf, sizeof(buf))); +} + +TEST_F(FPDFViewEmbeddertest, ViewerRef) { + EXPECT_TRUE(OpenDocument("viewer_ref.pdf")); + EXPECT_TRUE(FPDF_VIEWERREF_GetPrintScaling(document())); + EXPECT_EQ(5, FPDF_VIEWERREF_GetNumCopies(document())); + EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document())); + + // Test some corner cases. + char buf[100]; + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "", buf, sizeof(buf))); + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", nullptr, 0)); + EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", buf, sizeof(buf))); + + // Make sure |buf| does not get written into when it appears to be too small. + strcpy(buf, "ABCD"); + EXPECT_EQ(4U, FPDF_VIEWERREF_GetName(document(), "Foo", buf, 1)); + EXPECT_STREQ("ABCD", buf); + + // Note "Foo" is a different key from "foo". + EXPECT_EQ(4U, + FPDF_VIEWERREF_GetName(document(), "Foo", nullptr, sizeof(buf))); + ASSERT_EQ(4U, FPDF_VIEWERREF_GetName(document(), "Foo", buf, sizeof(buf))); + EXPECT_STREQ("foo", buf); + + // Try to retrieve a boolean and an integer. + EXPECT_EQ( + 0U, FPDF_VIEWERREF_GetName(document(), "HideToolbar", buf, sizeof(buf))); + EXPECT_EQ(0U, + FPDF_VIEWERREF_GetName(document(), "NumCopies", buf, sizeof(buf))); + + // Try more valid cases. + ASSERT_EQ(4U, + FPDF_VIEWERREF_GetName(document(), "Direction", buf, sizeof(buf))); + EXPECT_STREQ("R2L", buf); + ASSERT_EQ(8U, + FPDF_VIEWERREF_GetName(document(), "ViewArea", buf, sizeof(buf))); + EXPECT_STREQ("CropBox", buf); } TEST_F(FPDFViewEmbeddertest, NamedDests) { diff --git a/public/fpdf_doc.h b/public/fpdf_doc.h index 0b78743259..c3be0e0598 100644 --- a/public/fpdf_doc.h +++ b/public/fpdf_doc.h @@ -271,7 +271,7 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot, // Returns the number of bytes in the title, including trailing zeros. // // The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two -// bytes of zeros indicating the end of the string. If |buflen| is less then +// bytes of zeros indicating the end of the string. If |buflen| is less than // the returned length, or |buffer| is NULL, |buffer| will not be modified. DLLEXPORT unsigned long STDCALL FPDF_GetMetaText(FPDF_DOCUMENT doc, FPDF_BYTESTRING tag, diff --git a/public/fpdfview.h b/public/fpdfview.h index 499124d6e8..469053c4e8 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h @@ -914,6 +914,25 @@ FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document); DLLEXPORT FPDF_DUPLEXTYPE STDCALL FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document); +// Function: FPDF_VIEWERREF_GetName +// Gets the contents for a viewer ref, with a given key. The value must +// be of type "name". +// Parameters: +// document - Handle to the loaded document. +// key - Name of the key in the viewer pref dictionary. +// buffer - A string to write the contents of the key to. +// length - Length of the buffer. +// Return value: +// The number of bytes in the contents, including the NULL terminator. +// Thus if the return value is 0, then that indicates an error, such +// as when |document| is invalid or |buffer| is NULL. If |length| is +// less than the returned length, or |buffer| is NULL, |buffer| will +// not be modified. +DLLEXPORT unsigned long STDCALL FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, + FPDF_BYTESTRING key, + char* buffer, + unsigned long length); + // Function: FPDF_CountNamedDests // Get the count of named destinations in the PDF document. // Parameters: diff --git a/testing/resources/viewer_ref.in b/testing/resources/viewer_ref.in new file mode 100644 index 0000000000..62ae372dfe --- /dev/null +++ b/testing/resources/viewer_ref.in @@ -0,0 +1,57 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R + /ViewerPreferences << + /Foo /foo + /HideToolbar true + /Direction /R2L + /ViewArea /CropBox + /NumCopies 5 + >> +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [ + 3 0 R + ] +>> +endobj +% Page number 0. +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Resources << + /Font <> + >> + /Contents [21 0 R] + /MediaBox [0 0 612 792] +>> +endobj +% Font resource. +{{object 15 0}} << + /Type /Font + /Subtype /Type1 + /BaseFont /Arial +>> +endobj +% Content for page 0. +{{object 21 0}} << + /Length 0 +>> +stream +BT +/F1 20 Tf +100 600 TD (Page1)Tj +ET +endstream +endobj +{{xref}} +trailer << + /Size 6 + /Root 1 0 R +>> +{{startxref}} +%%EOF diff --git a/testing/resources/viewer_ref.pdf b/testing/resources/viewer_ref.pdf new file mode 100644 index 0000000000..fb72107b5b --- /dev/null +++ b/testing/resources/viewer_ref.pdf @@ -0,0 +1,82 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R + /ViewerPreferences << + /Foo /foo + /HideToolbar true + /Direction /R2L + /ViewArea /CropBox + /NumCopies 5 + >> +>> +endobj +2 0 obj << + /Type /Pages + /Count 1 + /Kids [ + 3 0 R + ] +>> +endobj +% Page number 0. +3 0 obj << + /Type /Page + /Parent 2 0 R + /Resources << + /Font <> + >> + /Contents [21 0 R] + /MediaBox [0 0 612 792] +>> +endobj +% Font resource. +15 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Arial +>> +endobj +% Content for page 0. +21 0 obj << + /Length 0 +>> +stream +BT +/F1 20 Tf +100 600 TD (Page1)Tj +ET +endstream +endobj +xref +0 22 +0000000000 65535 f +0000000015 00000 n +0000000193 00000 n +0000000281 00000 n +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000442 00000 n +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000537 00000 n +trailer << + /Size 6 + /Root 1 0 R +>> +startxref +625 +%%EOF -- cgit v1.2.3