• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "testing/embedder_test.h"
6 
7 #include <limits.h>
8 
9 #include <list>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "core/fdrm/crypto/fx_crypt.h"
15 #include "public/fpdf_dataavail.h"
16 #include "public/fpdf_edit.h"
17 #include "public/fpdf_text.h"
18 #include "public/fpdfview.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/test_support.h"
21 #include "testing/utils/path_service.h"
22 
23 #ifdef PDF_ENABLE_V8
24 #include "v8/include/v8-platform.h"
25 #include "v8/include/v8.h"
26 #endif  // PDF_ENABLE_V8
27 
28 namespace {
29 
30 const char* g_exe_path = nullptr;
31 
32 #ifdef PDF_ENABLE_V8
33 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
34 v8::StartupData* g_v8_natives = nullptr;
35 v8::StartupData* g_v8_snapshot = nullptr;
36 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
37 #endif  // PDF_ENABLE_V8
38 
Is_Data_Avail(FX_FILEAVAIL * pThis,size_t offset,size_t size)39 FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
40   return true;
41 }
42 
Add_Segment(FX_DOWNLOADHINTS * pThis,size_t offset,size_t size)43 void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {}
44 
CRYPT_ToBase16(const uint8_t * digest)45 std::string CRYPT_ToBase16(const uint8_t* digest) {
46   static char const zEncode[] = "0123456789abcdef";
47   std::string ret;
48   ret.resize(32);
49   for (int i = 0, j = 0; i < 16; i++, j += 2) {
50     uint8_t a = digest[i];
51     ret[j] = zEncode[(a >> 4) & 0xf];
52     ret[j + 1] = zEncode[a & 0xf];
53   }
54   return ret;
55 }
56 
57 }  // namespace
58 
EmbedderTest()59 EmbedderTest::EmbedderTest()
60     : default_delegate_(new EmbedderTest::Delegate()),
61       document_(nullptr),
62       form_handle_(nullptr),
63       avail_(nullptr),
64       external_isolate_(nullptr),
65       loader_(nullptr),
66       file_length_(0),
67       file_contents_(nullptr) {
68   memset(&hints_, 0, sizeof(hints_));
69   memset(&file_access_, 0, sizeof(file_access_));
70   memset(&file_avail_, 0, sizeof(file_avail_));
71   delegate_ = default_delegate_.get();
72 
73 #ifdef PDF_ENABLE_V8
74 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
75   if (g_v8_natives && g_v8_snapshot) {
76     InitializeV8ForPDFium(g_exe_path, std::string(), nullptr, nullptr,
77                           &platform_);
78   } else {
79     g_v8_natives = new v8::StartupData;
80     g_v8_snapshot = new v8::StartupData;
81     InitializeV8ForPDFium(g_exe_path, std::string(), g_v8_natives,
82                           g_v8_snapshot, &platform_);
83   }
84 #else
85   InitializeV8ForPDFium(g_exe_path, &platform_);
86 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
87 #endif  // FPDF_ENABLE_V8
88 }
89 
~EmbedderTest()90 EmbedderTest::~EmbedderTest() {
91 #ifdef PDF_ENABLE_V8
92   v8::V8::ShutdownPlatform();
93   delete platform_;
94 #endif  // PDF_ENABLE_V8
95 }
96 
SetUp()97 void EmbedderTest::SetUp() {
98   FPDF_LIBRARY_CONFIG config;
99   config.version = 2;
100   config.m_pUserFontPaths = nullptr;
101   config.m_v8EmbedderSlot = 0;
102   config.m_pIsolate = external_isolate_;
103   FPDF_InitLibraryWithConfig(&config);
104 
105   UNSUPPORT_INFO* info = static_cast<UNSUPPORT_INFO*>(this);
106   memset(info, 0, sizeof(UNSUPPORT_INFO));
107   info->version = 1;
108   info->FSDK_UnSupport_Handler = UnsupportedHandlerTrampoline;
109   FSDK_SetUnSpObjProcessHandler(info);
110 }
111 
TearDown()112 void EmbedderTest::TearDown() {
113   if (document_) {
114     FORM_DoDocumentAAction(form_handle_, FPDFDOC_AACTION_WC);
115     FPDFDOC_ExitFormFillEnvironment(form_handle_);
116     FPDF_CloseDocument(document_);
117   }
118 
119   FPDFAvail_Destroy(avail_);
120   FPDF_DestroyLibrary();
121 
122   delete loader_;
123 }
124 
CreateEmptyDocument()125 bool EmbedderTest::CreateEmptyDocument() {
126   document_ = FPDF_CreateNewDocument();
127   if (!document_)
128     return false;
129 
130   SetupFormFillEnvironment();
131   return true;
132 }
133 
OpenDocument(const std::string & filename,const char * password,bool must_linearize)134 bool EmbedderTest::OpenDocument(const std::string& filename,
135                                 const char* password,
136                                 bool must_linearize) {
137   std::string file_path;
138   if (!PathService::GetTestFilePath(filename, &file_path))
139     return false;
140   file_contents_ = GetFileContents(file_path.c_str(), &file_length_);
141   if (!file_contents_)
142     return false;
143 
144   EXPECT_TRUE(!loader_);
145   loader_ = new TestLoader(file_contents_.get(), file_length_);
146   file_access_.m_FileLen = static_cast<unsigned long>(file_length_);
147   file_access_.m_GetBlock = TestLoader::GetBlock;
148   file_access_.m_Param = loader_;
149 
150   file_avail_.version = 1;
151   file_avail_.IsDataAvail = Is_Data_Avail;
152 
153   hints_.version = 1;
154   hints_.AddSegment = Add_Segment;
155 
156   avail_ = FPDFAvail_Create(&file_avail_, &file_access_);
157 
158   if (FPDFAvail_IsLinearized(avail_) == PDF_LINEARIZED) {
159     document_ = FPDFAvail_GetDocument(avail_, password);
160     if (!document_) {
161       return false;
162     }
163     int32_t nRet = PDF_DATA_NOTAVAIL;
164     while (nRet == PDF_DATA_NOTAVAIL) {
165       nRet = FPDFAvail_IsDocAvail(avail_, &hints_);
166     }
167     if (nRet == PDF_DATA_ERROR) {
168       return false;
169     }
170     nRet = FPDFAvail_IsFormAvail(avail_, &hints_);
171     if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) {
172       return false;
173     }
174     int page_count = FPDF_GetPageCount(document_);
175     for (int i = 0; i < page_count; ++i) {
176       nRet = PDF_DATA_NOTAVAIL;
177       while (nRet == PDF_DATA_NOTAVAIL) {
178         nRet = FPDFAvail_IsPageAvail(avail_, i, &hints_);
179       }
180       if (nRet == PDF_DATA_ERROR) {
181         return false;
182       }
183     }
184   } else {
185     if (must_linearize) {
186       return false;
187     }
188     document_ = FPDF_LoadCustomDocument(&file_access_, password);
189     if (!document_) {
190       return false;
191     }
192   }
193 
194 #ifdef PDF_ENABLE_XFA
195   int docType = DOCTYPE_PDF;
196   if (FPDF_HasXFAField(document_, &docType)) {
197     if (docType != DOCTYPE_PDF)
198       (void)FPDF_LoadXFA(document_);
199   }
200 #endif  // PDF_ENABLE_XFA
201 
202   (void)FPDF_GetDocPermissions(document_);
203   SetupFormFillEnvironment();
204   return true;
205 }
206 
SetupFormFillEnvironment()207 void EmbedderTest::SetupFormFillEnvironment() {
208   IPDF_JSPLATFORM* platform = static_cast<IPDF_JSPLATFORM*>(this);
209   memset(platform, 0, sizeof(IPDF_JSPLATFORM));
210   platform->version = 2;
211   platform->app_alert = AlertTrampoline;
212 
213   FPDF_FORMFILLINFO* formfillinfo = static_cast<FPDF_FORMFILLINFO*>(this);
214   memset(formfillinfo, 0, sizeof(FPDF_FORMFILLINFO));
215 #ifdef PDF_ENABLE_XFA
216   formfillinfo->version = 2;
217 #else   // PDF_ENABLE_XFA
218   formfillinfo->version = 1;
219 #endif  // PDF_ENABLE_XFA
220   formfillinfo->FFI_SetTimer = SetTimerTrampoline;
221   formfillinfo->FFI_KillTimer = KillTimerTrampoline;
222   formfillinfo->FFI_GetPage = GetPageTrampoline;
223   formfillinfo->m_pJsPlatform = platform;
224 
225   form_handle_ = FPDFDOC_InitFormFillEnvironment(document_, formfillinfo);
226   FPDF_SetFormFieldHighlightColor(form_handle_, 0, 0xFFE4DD);
227   FPDF_SetFormFieldHighlightAlpha(form_handle_, 100);
228 }
229 
DoOpenActions()230 void EmbedderTest::DoOpenActions() {
231   FORM_DoDocumentJSAction(form_handle_);
232   FORM_DoDocumentOpenAction(form_handle_);
233 }
234 
GetFirstPageNum()235 int EmbedderTest::GetFirstPageNum() {
236   int first_page = FPDFAvail_GetFirstPageNum(document_);
237   (void)FPDFAvail_IsPageAvail(avail_, first_page, &hints_);
238   return first_page;
239 }
240 
GetPageCount()241 int EmbedderTest::GetPageCount() {
242   int page_count = FPDF_GetPageCount(document_);
243   for (int i = 0; i < page_count; ++i) {
244     (void)FPDFAvail_IsPageAvail(avail_, i, &hints_);
245   }
246   return page_count;
247 }
248 
LoadPage(int page_number)249 FPDF_PAGE EmbedderTest::LoadPage(int page_number) {
250   // First check whether it is loaded already.
251   auto it = page_map_.find(page_number);
252   if (it != page_map_.end())
253     return it->second;
254 
255   FPDF_PAGE page = FPDF_LoadPage(document_, page_number);
256   if (!page) {
257     return nullptr;
258   }
259   FORM_OnAfterLoadPage(page, form_handle_);
260   FORM_DoPageAAction(page, form_handle_, FPDFPAGE_AACTION_OPEN);
261   // Cache the page.
262   page_map_[page_number] = page;
263   page_reverse_map_[page] = page_number;
264   return page;
265 }
266 
RenderPage(FPDF_PAGE page)267 FPDF_BITMAP EmbedderTest::RenderPage(FPDF_PAGE page) {
268   int width = static_cast<int>(FPDF_GetPageWidth(page));
269   int height = static_cast<int>(FPDF_GetPageHeight(page));
270   int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
271   FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, alpha);
272   FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
273   FPDFBitmap_FillRect(bitmap, 0, 0, width, height, fill_color);
274   FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
275   FPDF_FFLDraw(form_handle_, bitmap, page, 0, 0, width, height, 0, 0);
276   return bitmap;
277 }
278 
UnloadPage(FPDF_PAGE page)279 void EmbedderTest::UnloadPage(FPDF_PAGE page) {
280   FORM_DoPageAAction(page, form_handle_, FPDFPAGE_AACTION_CLOSE);
281   FORM_OnBeforeClosePage(page, form_handle_);
282   FPDF_ClosePage(page);
283 
284   auto it = page_reverse_map_.find(page);
285   if (it == page_reverse_map_.end())
286     return;
287 
288   page_map_.erase(it->second);
289   page_reverse_map_.erase(it);
290 }
291 
GetPage(FPDF_FORMFILLINFO * info,FPDF_DOCUMENT document,int page_index)292 FPDF_PAGE EmbedderTest::Delegate::GetPage(FPDF_FORMFILLINFO* info,
293                                           FPDF_DOCUMENT document,
294                                           int page_index) {
295   EmbedderTest* test = static_cast<EmbedderTest*>(info);
296   auto it = test->page_map_.find(page_index);
297   return it != test->page_map_.end() ? it->second : nullptr;
298 }
299 
300 // static
UnsupportedHandlerTrampoline(UNSUPPORT_INFO * info,int type)301 void EmbedderTest::UnsupportedHandlerTrampoline(UNSUPPORT_INFO* info,
302                                                 int type) {
303   EmbedderTest* test = static_cast<EmbedderTest*>(info);
304   test->delegate_->UnsupportedHandler(type);
305 }
306 
307 // static
AlertTrampoline(IPDF_JSPLATFORM * platform,FPDF_WIDESTRING message,FPDF_WIDESTRING title,int type,int icon)308 int EmbedderTest::AlertTrampoline(IPDF_JSPLATFORM* platform,
309                                   FPDF_WIDESTRING message,
310                                   FPDF_WIDESTRING title,
311                                   int type,
312                                   int icon) {
313   EmbedderTest* test = static_cast<EmbedderTest*>(platform);
314   return test->delegate_->Alert(message, title, type, icon);
315 }
316 
317 // static
SetTimerTrampoline(FPDF_FORMFILLINFO * info,int msecs,TimerCallback fn)318 int EmbedderTest::SetTimerTrampoline(FPDF_FORMFILLINFO* info,
319                                      int msecs,
320                                      TimerCallback fn) {
321   EmbedderTest* test = static_cast<EmbedderTest*>(info);
322   return test->delegate_->SetTimer(msecs, fn);
323 }
324 
325 // static
KillTimerTrampoline(FPDF_FORMFILLINFO * info,int id)326 void EmbedderTest::KillTimerTrampoline(FPDF_FORMFILLINFO* info, int id) {
327   EmbedderTest* test = static_cast<EmbedderTest*>(info);
328   return test->delegate_->KillTimer(id);
329 }
330 
331 // static
GetPageTrampoline(FPDF_FORMFILLINFO * info,FPDF_DOCUMENT document,int page_index)332 FPDF_PAGE EmbedderTest::GetPageTrampoline(FPDF_FORMFILLINFO* info,
333                                           FPDF_DOCUMENT document,
334                                           int page_index) {
335   return static_cast<EmbedderTest*>(info)->delegate_->GetPage(info, document,
336                                                               page_index);
337 }
338 
339 // static
CompareBitmap(FPDF_BITMAP bitmap,int expected_width,int expected_height,const char * expected_md5sum)340 void EmbedderTest::CompareBitmap(FPDF_BITMAP bitmap,
341                                  int expected_width,
342                                  int expected_height,
343                                  const char* expected_md5sum) {
344   ASSERT_EQ(expected_width, FPDFBitmap_GetWidth(bitmap));
345   ASSERT_EQ(expected_height, FPDFBitmap_GetHeight(bitmap));
346   const int expected_stride = expected_width * 4;
347   ASSERT_EQ(expected_stride, FPDFBitmap_GetStride(bitmap));
348 
349   if (!expected_md5sum)
350     return;
351 
352   uint8_t digest[16];
353   CRYPT_MD5Generate(static_cast<uint8_t*>(FPDFBitmap_GetBuffer(bitmap)),
354                     expected_stride * expected_height, digest);
355   EXPECT_EQ(expected_md5sum, CRYPT_ToBase16(digest));
356 }
357 
358 // Can't use gtest-provided main since we need to stash the path to the
359 // executable in order to find the external V8 binary data files.
main(int argc,char ** argv)360 int main(int argc, char** argv) {
361   g_exe_path = argv[0];
362   testing::InitGoogleTest(&argc, argv);
363   testing::InitGoogleMock(&argc, argv);
364   int ret_val = RUN_ALL_TESTS();
365 
366 #ifdef PDF_ENABLE_V8
367 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
368   if (g_v8_natives)
369     free(const_cast<char*>(g_v8_natives->data));
370   if (g_v8_snapshot)
371     free(const_cast<char*>(g_v8_snapshot->data));
372 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
373 #endif  // PDF_ENABLE_V8
374 
375   return ret_val;
376 }
377