blob: 16dc4ae8870d31a3135cce0988733f47da6ce752 [file] [log] [blame]
K. Moon832a6942022-10-31 20:11:31 +00001// Copyright 2016 The PDFium Authors
Tom Sepez9eb811f2016-01-05 14:48:31 -08002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tom Sepezb0874842024-06-11 00:35:07 +00005#include <array>
Henrique Nakashima9fa50362017-11-10 22:40:44 +00006#include <string>
Tom Sepez9eb811f2016-01-05 14:48:31 -08007
dsinclaira52ab742016-09-29 13:59:29 -07008#include "core/fxcrt/fx_string.h"
Tom Sepeze08d2b12018-04-25 18:49:32 +00009#include "public/cpp/fpdf_scopers.h"
tsepez6e1d6032016-11-11 17:55:40 -080010#include "public/fpdf_edit.h"
11#include "public/fpdf_ppo.h"
Lei Zhanga98e3662018-02-07 20:28:35 +000012#include "public/fpdf_save.h"
Tom Sepez9eb811f2016-01-05 14:48:31 -080013#include "public/fpdfview.h"
14#include "testing/embedder_test.h"
Lei Zhang31425652022-03-16 16:53:50 +000015#include "testing/embedder_test_constants.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080016#include "testing/gmock/include/gmock/gmock-matchers.h"
Tom Sepez9eb811f2016-01-05 14:48:31 -080017#include "testing/gtest/include/gtest/gtest.h"
18
Lei Zhang50182402023-03-29 17:10:46 +000019using testing::HasSubstr;
20using testing::Not;
21using testing::StartsWith;
22
Nicolas Pena3ff54002017-07-05 11:55:35 -040023class FPDFSaveEmbedderTest : public EmbedderTest {};
Tom Sepez9eb811f2016-01-05 14:48:31 -080024
25TEST_F(FPDFSaveEmbedderTest, SaveSimpleDoc) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +000026 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Tom Sepez0aec19b2016-01-07 12:22:44 -080027 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhang50182402023-03-29 17:10:46 +000028 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
Lei Zhange0023992022-03-16 03:19:31 +000029 EXPECT_EQ(805u, GetString().size());
Tom Sepez9eb811f2016-01-05 14:48:31 -080030}
31
32TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocWithVersion) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +000033 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Tom Sepez0aec19b2016-01-07 12:22:44 -080034 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 14));
Lei Zhang50182402023-03-29 17:10:46 +000035 EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
Lei Zhange0023992022-03-16 03:19:31 +000036 EXPECT_EQ(805u, GetString().size());
Tom Sepez9eb811f2016-01-05 14:48:31 -080037}
Tom Sepez281c9682021-05-12 01:03:02 +000038
Tom Sepez9eb811f2016-01-05 14:48:31 -080039TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocWithBadVersion) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +000040 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Tom Sepez0aec19b2016-01-07 12:22:44 -080041 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, -1));
Lei Zhang50182402023-03-29 17:10:46 +000042 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
Tom Sepez0aec19b2016-01-07 12:22:44 -080043
44 ClearString();
45 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 0));
Lei Zhang50182402023-03-29 17:10:46 +000046 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
Tom Sepez0aec19b2016-01-07 12:22:44 -080047
48 ClearString();
49 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 0, 18));
Lei Zhang50182402023-03-29 17:10:46 +000050 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
Tom Sepez9eb811f2016-01-05 14:48:31 -080051}
52
Tom Sepez281c9682021-05-12 01:03:02 +000053TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocIncremental) {
54 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
55 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, FPDF_INCREMENTAL, 14));
56 // Version gets taken as-is from input document.
Lei Zhang50182402023-03-29 17:10:46 +000057 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\n%\xa0\xf2\xa4\xf4"));
Tom Sepez281c9682021-05-12 01:03:02 +000058 // Additional output produced vs. non incremental.
Lei Zhange0023992022-03-16 03:19:31 +000059 EXPECT_EQ(985u, GetString().size());
Tom Sepez281c9682021-05-12 01:03:02 +000060}
61
62TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocNoIncremental) {
63 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
64 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, FPDF_NO_INCREMENTAL, 14));
Lei Zhang50182402023-03-29 17:10:46 +000065 EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
Lei Zhange0023992022-03-16 03:19:31 +000066 EXPECT_EQ(805u, GetString().size());
Tom Sepez281c9682021-05-12 01:03:02 +000067}
68
69TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocRemoveSecurity) {
70 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
71 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, FPDF_REMOVE_SECURITY, 14));
Lei Zhang50182402023-03-29 17:10:46 +000072 EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
Lei Zhange0023992022-03-16 03:19:31 +000073 EXPECT_EQ(805u, GetString().size());
Tom Sepez281c9682021-05-12 01:03:02 +000074}
75
76TEST_F(FPDFSaveEmbedderTest, SaveSimpleDocBadFlags) {
77 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
78 EXPECT_TRUE(FPDF_SaveWithVersion(document(), this, 999999, 14));
Lei Zhang50182402023-03-29 17:10:46 +000079 EXPECT_THAT(GetString(), StartsWith("%PDF-1.4\r\n"));
Lei Zhange0023992022-03-16 03:19:31 +000080 EXPECT_EQ(805u, GetString().size());
Tom Sepez281c9682021-05-12 01:03:02 +000081}
82
tsepez6e1d6032016-11-11 17:55:40 -080083TEST_F(FPDFSaveEmbedderTest, SaveCopiedDoc) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +000084 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
tsepez6e1d6032016-11-11 17:55:40 -080085
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +000086 ScopedEmbedderTestPage page = LoadScopedPage(0);
tsepez6e1d6032016-11-11 17:55:40 -080087 EXPECT_TRUE(page);
88
Lei Zhang6ea677c2023-09-06 21:08:13 +000089 ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
tsepez6e1d6032016-11-11 17:55:40 -080090 EXPECT_TRUE(output_doc);
Lei Zhang6ea677c2023-09-06 21:08:13 +000091 EXPECT_TRUE(FPDF_ImportPages(output_doc.get(), document(), "1", 0));
92 EXPECT_TRUE(FPDF_SaveAsCopy(output_doc.get(), this, 0));
tsepez6e1d6032016-11-11 17:55:40 -080093
tsepez6e1d6032016-11-11 17:55:40 -080094}
95
JD Pierce03c611a2024-06-11 20:41:32 +000096TEST_F(FPDFSaveEmbedderTest, Bug42271133) {
97 ASSERT_TRUE(OpenDocument("bug_42271133.pdf"));
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +000098 ScopedEmbedderTestPage page = LoadScopedPage(0);
JD Pierce03c611a2024-06-11 20:41:32 +000099 ASSERT_TRUE(page);
100
101 // Arbitrarily remove the first page object.
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000102 auto text_object = FPDFPage_GetObject(page.get(), 0);
JD Pierce03c611a2024-06-11 20:41:32 +0000103 ASSERT_TRUE(text_object);
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000104 ASSERT_TRUE(FPDFPage_RemoveObject(page.get(), text_object));
JD Pierce03c611a2024-06-11 20:41:32 +0000105 FPDFPageObj_Destroy(text_object);
106
107 // Regenerate dirty stream and save the document.
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000108 ASSERT_TRUE(FPDFPage_GenerateContent(page.get()));
JD Pierce03c611a2024-06-11 20:41:32 +0000109 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
110
111 // Reload saved document.
112 ASSERT_TRUE(OpenSavedDocument());
113 FPDF_PAGE saved_page = LoadSavedPage(0);
114 ASSERT_TRUE(saved_page);
115
116 // Assert path fill color is not changed to black.
117 auto path_obj = FPDFPage_GetObject(saved_page, 0);
118 ASSERT_TRUE(path_obj);
119 unsigned int r;
120 unsigned int g;
121 unsigned int b;
122 unsigned int a;
123 ASSERT_TRUE(FPDFPageObj_GetFillColor(path_obj, &r, &g, &b, &a));
JD Pierce6664ba92024-06-14 16:27:44 +0000124 EXPECT_EQ(180u, r);
125 EXPECT_EQ(180u, g);
126 EXPECT_EQ(180u, b);
JD Pierce03c611a2024-06-11 20:41:32 +0000127
128 CloseSavedPage(saved_page);
129 CloseSavedDocument();
130}
131
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000132TEST_F(FPDFSaveEmbedderTest, SaveLinearizedDoc) {
133 const int kPageCount = 3;
Tom Sepezb0874842024-06-11 00:35:07 +0000134 std::array<std::string, kPageCount> original_md5;
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000135
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000136 ASSERT_TRUE(OpenDocument("linearized.pdf"));
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000137 for (int i = 0; i < kPageCount; ++i) {
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000138 ScopedEmbedderTestPage page = LoadScopedPage(i);
Lei Zhang6183a6e2018-02-07 23:00:07 +0000139 ASSERT_TRUE(page);
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000140 ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
Lei Zhang6183a6e2018-02-07 23:00:07 +0000141 EXPECT_EQ(612, FPDFBitmap_GetWidth(bitmap.get()));
142 EXPECT_EQ(792, FPDFBitmap_GetHeight(bitmap.get()));
143 original_md5[i] = HashBitmap(bitmap.get());
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000144 }
145
146 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhang50182402023-03-29 17:10:46 +0000147 EXPECT_THAT(GetString(), StartsWith("%PDF-1.6\r\n"));
148 EXPECT_THAT(GetString(), HasSubstr("/Root "));
149 EXPECT_THAT(GetString(), HasSubstr("/Info "));
Lei Zhang28f8db42023-03-30 19:19:38 +0000150 EXPECT_THAT(GetString(), HasSubstr("/Size 37"));
Lei Zhang1f4904f2023-03-29 17:58:17 +0000151 EXPECT_THAT(GetString(), HasSubstr("35 0 obj"));
152 EXPECT_THAT(GetString(), HasSubstr("36 0 obj"));
Lei Zhang28f8db42023-03-30 19:19:38 +0000153 EXPECT_THAT(GetString(), Not(HasSubstr("37 0 obj")));
Lei Zhang1f4904f2023-03-29 17:58:17 +0000154 EXPECT_THAT(GetString(), Not(HasSubstr("38 0 obj")));
Andy Phane6633a52024-09-21 01:15:31 +0000155 EXPECT_EQ(7986u, GetString().size());
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000156
157 // Make sure new document renders the same as the old one.
Lei Zhang0b494052019-01-31 21:41:15 +0000158 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000159 for (int i = 0; i < kPageCount; ++i) {
160 FPDF_PAGE page = LoadSavedPage(i);
Lei Zhanga98e3662018-02-07 20:28:35 +0000161 ASSERT_TRUE(page);
Tom Sepeze08d2b12018-04-25 18:49:32 +0000162 ScopedFPDFBitmap bitmap = RenderSavedPage(page);
Lei Zhanga98e3662018-02-07 20:28:35 +0000163 EXPECT_EQ(original_md5[i], HashBitmap(bitmap.get()));
Henrique Nakashima9fa50362017-11-10 22:40:44 +0000164 CloseSavedPage(page);
165 }
166 CloseSavedDocument();
167}
168
Lei Zhang31425652022-03-16 16:53:50 +0000169TEST_F(FPDFSaveEmbedderTest, Bug1409) {
170 ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000171 ScopedEmbedderTestPage page = LoadScopedPage(0);
Lei Zhang31425652022-03-16 16:53:50 +0000172 ASSERT_TRUE(page);
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000173 while (FPDFPage_CountObjects(page.get()) > 0) {
174 ScopedFPDFPageObject object(FPDFPage_GetObject(page.get(), 0));
Lei Zhang31425652022-03-16 16:53:50 +0000175 ASSERT_TRUE(object);
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000176 ASSERT_TRUE(FPDFPage_RemoveObject(page.get(), object.get()));
Lei Zhang31425652022-03-16 16:53:50 +0000177 }
AbdAlRahman Gad94fb0062024-08-17 01:08:28 +0000178 ASSERT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang31425652022-03-16 16:53:50 +0000179
180 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
181
182 // The new document should render as empty.
183 ASSERT_TRUE(OpenSavedDocument());
184 FPDF_PAGE saved_page = LoadSavedPage(0);
185 ASSERT_TRUE(saved_page);
186 ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
187 EXPECT_EQ(pdfium::kBlankPage612By792Checksum, HashBitmap(bitmap.get()));
188 CloseSavedPage(saved_page);
189 CloseSavedDocument();
190
Lei Zhang50182402023-03-29 17:10:46 +0000191 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
192 EXPECT_THAT(GetString(), HasSubstr("/Root "));
Lei Zhang69703b32023-03-30 22:26:48 +0000193 EXPECT_THAT(GetString(), Not(HasSubstr("/Image")));
194 EXPECT_LT(GetString().size(), 600u);
Lei Zhang31425652022-03-16 16:53:50 +0000195}
196
Tom Sepezfcb6cd62020-01-18 00:32:42 +0000197#ifdef PDF_ENABLE_XFA
198TEST_F(FPDFSaveEmbedderTest, SaveXFADoc) {
199 ASSERT_TRUE(OpenDocument("simple_xfa.pdf"));
200 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhang50182402023-03-29 17:10:46 +0000201 EXPECT_THAT(GetString(), StartsWith("%PDF-1.7\r\n"));
Tom Sepezfcb6cd62020-01-18 00:32:42 +0000202 ASSERT_TRUE(OpenSavedDocument());
203 // TODO(tsepez): check for XFA forms in document
204 CloseSavedDocument();
205}
206#endif // PDF_ENABLE_XFA
207
AbdAlRahmanGadc0589222024-06-28 01:28:29 +0000208TEST_F(FPDFSaveEmbedderTest, Bug342) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000209 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Tom Sepez0aec19b2016-01-07 12:22:44 -0800210 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhang50182402023-03-29 17:10:46 +0000211 EXPECT_THAT(GetString(), HasSubstr("0000000000 65535 f\r\n"));
212 EXPECT_THAT(GetString(), Not(HasSubstr("0000000000 65536 f\r\n")));
Tom Sepez9eb811f2016-01-05 14:48:31 -0800213}
Lei Zhangc1600692018-11-14 23:12:58 +0000214
AbdAlRahmanGadc0589222024-06-28 01:28:29 +0000215TEST_F(FPDFSaveEmbedderTest, Bug905142) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000216 ASSERT_TRUE(OpenDocument("bug_905142.pdf"));
Lei Zhangc1600692018-11-14 23:12:58 +0000217 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhang50182402023-03-29 17:10:46 +0000218 EXPECT_THAT(GetString(), HasSubstr("/Length 0"));
Lei Zhangc1600692018-11-14 23:12:58 +0000219}
Lei Zhang47adbc02022-05-25 07:26:34 +0000220
221// Should not trigger a DCHECK() failure in CFX_FileBufferArchive.
Lei Zhang259e2562022-05-25 18:51:44 +0000222// Fails because the PDF is malformed.
223TEST_F(FPDFSaveEmbedderTest, Bug1328389) {
Lei Zhang47adbc02022-05-25 07:26:34 +0000224 ASSERT_TRUE(OpenDocument("bug_1328389.pdf"));
225 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhang50182402023-03-29 17:10:46 +0000226 EXPECT_THAT(GetString(), HasSubstr("/Foo/"));
Lei Zhang47adbc02022-05-25 07:26:34 +0000227}