1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2016 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker #include <string>
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_string.h"
8*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
9*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_edit.h"
10*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_ppo.h"
11*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_save.h"
12*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdfview.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "testing/embedder_test.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "testing/embedder_test_constants.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock-matchers.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
17*3ac0a46fSAndroid Build Coastguard Worker
18*3ac0a46fSAndroid Build Coastguard Worker using testing::HasSubstr;
19*3ac0a46fSAndroid Build Coastguard Worker using testing::Not;
20*3ac0a46fSAndroid Build Coastguard Worker using testing::StartsWith;
21*3ac0a46fSAndroid Build Coastguard Worker
22*3ac0a46fSAndroid Build Coastguard Worker class FPDFSaveEmbedderTest : public EmbedderTest {};
23*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDoc)24*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDoc) {
25*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
26*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
27*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
28*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(805u, GetString().size());
29*3ac0a46fSAndroid Build Coastguard Worker }
30*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDocWithVersion)31*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocWithVersion) {
32*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
33*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 14));
34*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
35*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(805u, GetString().size());
36*3ac0a46fSAndroid Build Coastguard Worker }
37*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDocWithBadVersion)38*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocWithBadVersion) {
39*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
40*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, -1));
41*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
42*3ac0a46fSAndroid Build Coastguard Worker
43*3ac0a46fSAndroid Build Coastguard Worker ClearString();
44*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 0));
45*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
46*3ac0a46fSAndroid Build Coastguard Worker
47*3ac0a46fSAndroid Build Coastguard Worker ClearString();
48*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 18));
49*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
50*3ac0a46fSAndroid Build Coastguard Worker }
51*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDocIncremental)52*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocIncremental) {
53*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
54*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, FPDF_INCREMENTAL, 14));
55*3ac0a46fSAndroid Build Coastguard Worker // Version gets taken as-is from input document.
56*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\n%\xa0\xf2\xa4\xf4"));
57*3ac0a46fSAndroid Build Coastguard Worker // Additional output produced vs. non incremental.
58*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(985u, GetString().size());
59*3ac0a46fSAndroid Build Coastguard Worker }
60*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDocNoIncremental)61*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocNoIncremental) {
62*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
63*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, FPDF_NO_INCREMENTAL, 14));
64*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
65*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(805u, GetString().size());
66*3ac0a46fSAndroid Build Coastguard Worker }
67*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDocRemoveSecurity)68*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocRemoveSecurity) {
69*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
70*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, FPDF_REMOVE_SECURITY, 14));
71*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
72*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(805u, GetString().size());
73*3ac0a46fSAndroid Build Coastguard Worker }
74*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveSimpleDocBadFlags)75*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocBadFlags) {
76*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
77*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 999999, 14));
78*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
79*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(805u, GetString().size());
80*3ac0a46fSAndroid Build Coastguard Worker }
81*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveCopiedDoc)82*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveCopiedDoc) {
83*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
84*3ac0a46fSAndroid Build Coastguard Worker
85*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
86*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(page);
87*3ac0a46fSAndroid Build Coastguard Worker
88*3ac0a46fSAndroid Build Coastguard Worker FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
89*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(output_doc);
90*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1", 0));
91*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(output_doc, this, 0));
92*3ac0a46fSAndroid Build Coastguard Worker FPDF_CloseDocument(output_doc);
93*3ac0a46fSAndroid Build Coastguard Worker
94*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
95*3ac0a46fSAndroid Build Coastguard Worker }
96*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,SaveLinearizedDoc)97*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveLinearizedDoc) {
98*3ac0a46fSAndroid Build Coastguard Worker const int kPageCount = 3;
99*3ac0a46fSAndroid Build Coastguard Worker std::string original_md5[kPageCount];
100*3ac0a46fSAndroid Build Coastguard Worker
101*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("linearized.pdf"));
102*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < kPageCount; ++i) {
103*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(i);
104*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
105*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
106*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(612, FPDFBitmap_GetWidth(bitmap.get()));
107*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(792, FPDFBitmap_GetHeight(bitmap.get()));
108*3ac0a46fSAndroid Build Coastguard Worker original_md5[i] = HashBitmap(bitmap.get());
109*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
110*3ac0a46fSAndroid Build Coastguard Worker }
111*3ac0a46fSAndroid Build Coastguard Worker
112*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
113*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.6\r\n"));
114*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("/Root "));
115*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("/Info "));
116*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("/Size 37"));
117*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("35 0 obj"));
118*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("36 0 obj"));
119*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), Not(HasSubstr("37 0 obj")));
120*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), Not(HasSubstr("38 0 obj")));
121*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(7908u, GetString().size());
122*3ac0a46fSAndroid Build Coastguard Worker
123*3ac0a46fSAndroid Build Coastguard Worker // Make sure new document renders the same as the old one.
124*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenSavedDocument());
125*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < kPageCount; ++i) {
126*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadSavedPage(i);
127*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
128*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFBitmap bitmap = RenderSavedPage(page);
129*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(original_md5[i], HashBitmap(bitmap.get()));
130*3ac0a46fSAndroid Build Coastguard Worker CloseSavedPage(page);
131*3ac0a46fSAndroid Build Coastguard Worker }
132*3ac0a46fSAndroid Build Coastguard Worker CloseSavedDocument();
133*3ac0a46fSAndroid Build Coastguard Worker }
134*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,Bug1409)135*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, Bug1409) {
136*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
137*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page = LoadPage(0);
138*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(page);
139*3ac0a46fSAndroid Build Coastguard Worker while (FPDFPage_CountObjects(page) > 0) {
140*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFPageObject object(FPDFPage_GetObject(page, 0));
141*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(object);
142*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFPage_RemoveObject(page, object.get()));
143*3ac0a46fSAndroid Build Coastguard Worker }
144*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDFPage_GenerateContent(page));
145*3ac0a46fSAndroid Build Coastguard Worker UnloadPage(page);
146*3ac0a46fSAndroid Build Coastguard Worker
147*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
148*3ac0a46fSAndroid Build Coastguard Worker
149*3ac0a46fSAndroid Build Coastguard Worker // The new document should render as empty.
150*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenSavedDocument());
151*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE saved_page = LoadSavedPage(0);
152*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(saved_page);
153*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
154*3ac0a46fSAndroid Build Coastguard Worker EXPECT_EQ(pdfium::kBlankPage612By792Checksum, HashBitmap(bitmap.get()));
155*3ac0a46fSAndroid Build Coastguard Worker CloseSavedPage(saved_page);
156*3ac0a46fSAndroid Build Coastguard Worker CloseSavedDocument();
157*3ac0a46fSAndroid Build Coastguard Worker
158*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
159*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("/Root "));
160*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), Not(HasSubstr("/Image")));
161*3ac0a46fSAndroid Build Coastguard Worker EXPECT_LT(GetString().size(), 600u);
162*3ac0a46fSAndroid Build Coastguard Worker }
163*3ac0a46fSAndroid Build Coastguard Worker
164*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
TEST_F(FPDFSaveEmbedderTest,SaveXFADoc)165*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, SaveXFADoc) {
166*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("simple_xfa.pdf"));
167*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
168*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
169*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenSavedDocument());
170*3ac0a46fSAndroid Build Coastguard Worker // TODO(tsepez): check for XFA forms in document
171*3ac0a46fSAndroid Build Coastguard Worker CloseSavedDocument();
172*3ac0a46fSAndroid Build Coastguard Worker }
173*3ac0a46fSAndroid Build Coastguard Worker #endif // PDF_ENABLE_XFA
174*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,BUG_342)175*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, BUG_342) {
176*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("hello_world.pdf"));
177*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
178*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("0000000000 65535 f\r\n"));
179*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), Not(HasSubstr("0000000000 65536 f\r\n")));
180*3ac0a46fSAndroid Build Coastguard Worker }
181*3ac0a46fSAndroid Build Coastguard Worker
TEST_F(FPDFSaveEmbedderTest,BUG_905142)182*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, BUG_905142) {
183*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_905142.pdf"));
184*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
185*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("/Length 0"));
186*3ac0a46fSAndroid Build Coastguard Worker }
187*3ac0a46fSAndroid Build Coastguard Worker
188*3ac0a46fSAndroid Build Coastguard Worker // Should not trigger a DCHECK() failure in CFX_FileBufferArchive.
189*3ac0a46fSAndroid Build Coastguard Worker // Fails because the PDF is malformed.
TEST_F(FPDFSaveEmbedderTest,Bug1328389)190*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFSaveEmbedderTest, Bug1328389) {
191*3ac0a46fSAndroid Build Coastguard Worker ASSERT_TRUE(OpenDocument("bug_1328389.pdf"));
192*3ac0a46fSAndroid Build Coastguard Worker EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
193*3ac0a46fSAndroid Build Coastguard Worker EXPECT_THAT(GetString(), HasSubstr("/Foo/"));
194*3ac0a46fSAndroid Build Coastguard Worker }
195