blob: 14aa6c187df33a8923c82f788175de0f51b2be5f [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// Copyright (c) 2010 The Chromium 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 <limits.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
tonikitoo3e981582016-08-26 08:37:10 -070010#include <map>
Tom Sepezdaa2e842015-01-29 15:44:37 -080011#include <sstream>
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070012#include <string>
13#include <utility>
Tom Sepez5ee12d72014-12-17 16:24:01 -080014#include <vector>
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070015
Cary Clark399be5b2016-03-14 16:51:29 -040016#if defined PDF_ENABLE_SKIA && !defined _SKIA_SUPPORT_
17#define _SKIA_SUPPORT_
18#endif
19
stephanafa05e972017-01-02 06:19:41 -080020#include "core/fdrm/crypto/fx_crypt.h"
Tom Sepez1d17a042017-03-16 13:22:47 -070021#include "public/cpp/fpdf_deleters.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040022#include "public/fpdf_annot.h"
Lei Zhangb4e7f302015-11-06 15:52:32 -080023#include "public/fpdf_dataavail.h"
Lei Zhang453d96b2015-12-31 13:13:10 -080024#include "public/fpdf_edit.h"
Lei Zhangb4e7f302015-11-06 15:52:32 -080025#include "public/fpdf_ext.h"
26#include "public/fpdf_formfill.h"
Dan Sinclairddcb6e72017-04-05 10:30:33 -040027#include "public/fpdf_structtree.h"
Lei Zhangb4e7f302015-11-06 15:52:32 -080028#include "public/fpdf_text.h"
29#include "public/fpdfview.h"
Dan Sinclairefbc1912016-02-17 16:54:43 -050030#include "samples/image_diff_png.h"
Lei Zhangbde53d22015-11-12 22:21:30 -080031#include "testing/test_support.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040032#include "third_party/base/logging.h"
Tom Sepezd831dc72015-10-19 16:04:22 -070033
thestigf2b940c2016-10-13 06:48:47 -070034#ifdef _WIN32
35#include <io.h>
36#else
37#include <unistd.h>
38#endif
39
Tom Sepez452b4f32015-10-13 09:27:27 -070040#ifdef PDF_ENABLE_V8
John Abd-El-Malekb045ed22015-02-10 09:15:12 -080041#include "v8/include/libplatform/libplatform.h"
Tom Sepez1ed8a212015-05-11 15:25:39 -070042#include "v8/include/v8.h"
Lei Zhang8241df72015-11-06 14:38:48 -080043#endif // PDF_ENABLE_V8
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070044
Cary Clark399be5b2016-03-14 16:51:29 -040045#ifdef PDF_ENABLE_SKIA
46#include "third_party/skia/include/core/SkPictureRecorder.h"
47#include "third_party/skia/include/core/SkStream.h"
48#endif
49
thestigf2b940c2016-10-13 06:48:47 -070050#ifdef _WIN32
51#define access _access
52#define snprintf _snprintf
53#define R_OK 4
54#endif
55
Vitaly Buka9e0177a2014-07-22 18:15:42 -070056enum OutputFormat {
57 OUTPUT_NONE,
Dan Sinclair3c67fbd2017-04-05 16:07:50 -040058 OUTPUT_STRUCTURE,
dsinclairb63068f2016-06-16 07:58:09 -070059 OUTPUT_TEXT,
Vitaly Buka9e0177a2014-07-22 18:15:42 -070060 OUTPUT_PPM,
Tom Sepezaf18cb32015-02-05 15:06:01 -080061 OUTPUT_PNG,
Jane Liu4fd9a472017-06-01 18:56:09 -040062 OUTPUT_ANNOT,
Vitaly Buka9e0177a2014-07-22 18:15:42 -070063#ifdef _WIN32
64 OUTPUT_BMP,
65 OUTPUT_EMF,
Lei Zhangd1c9b452017-05-05 17:21:36 -070066 OUTPUT_PS2,
67 OUTPUT_PS3,
Vitaly Buka9e0177a2014-07-22 18:15:42 -070068#endif
Cary Clark399be5b2016-03-14 16:51:29 -040069#ifdef PDF_ENABLE_SKIA
70 OUTPUT_SKP,
71#endif
Vitaly Buka9e0177a2014-07-22 18:15:42 -070072};
73
Tom Sepez5ee12d72014-12-17 16:24:01 -080074struct Options {
tsepezf09bdfa2016-04-18 16:08:26 -070075 Options()
Dan Sinclair3c67fbd2017-04-05 16:07:50 -040076 : show_config(false),
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -040077 show_metadata(false),
npme3c73152016-11-14 09:14:52 -080078 send_events(false),
79 pages(false),
stephanafa05e972017-01-02 06:19:41 -080080 md5(false),
npme3c73152016-11-14 09:14:52 -080081 output_format(OUTPUT_NONE) {}
Tom Sepez5ee12d72014-12-17 16:24:01 -080082
Tom Sepez2991d8d2016-01-15 16:02:48 -080083 bool show_config;
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -040084 bool show_metadata;
tsepezf09bdfa2016-04-18 16:08:26 -070085 bool send_events;
npme3c73152016-11-14 09:14:52 -080086 bool pages;
stephanafa05e972017-01-02 06:19:41 -080087 bool md5;
Tom Sepez5ee12d72014-12-17 16:24:01 -080088 OutputFormat output_format;
Tom Sepezdaa2e842015-01-29 15:44:37 -080089 std::string scale_factor_as_string;
Tom Sepez5ee12d72014-12-17 16:24:01 -080090 std::string exe_path;
91 std::string bin_directory;
Lei Zhang6f62d532015-09-23 15:31:44 -070092 std::string font_directory;
npmfa20cd52016-11-14 13:33:40 -080093 // 0-based page numbers to be rendered.
94 int first_page;
95 int last_page;
Tom Sepez5ee12d72014-12-17 16:24:01 -080096};
97
tonikitoo81d92f82016-09-21 12:44:56 -070098struct FPDF_FORMFILLINFO_PDFiumTest : public FPDF_FORMFILLINFO {
99 // Hold a map of the currently loaded pages in order to avoid them
100 // to get loaded twice.
npmfa20cd52016-11-14 13:33:40 -0800101 std::map<int, FPDF_PAGE> loaded_pages;
tonikitoo81d92f82016-09-21 12:44:56 -0700102
103 // Hold a pointer of FPDF_FORMHANDLE so that PDFium app hooks can
104 // make use of it.
npmfa20cd52016-11-14 13:33:40 -0800105 FPDF_FORMHANDLE form_handle;
tonikitoo81d92f82016-09-21 12:44:56 -0700106};
107
108static FPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(
npmfa20cd52016-11-14 13:33:40 -0800109 FPDF_FORMFILLINFO* form_fill_info) {
110 return static_cast<FPDF_FORMFILLINFO_PDFiumTest*>(form_fill_info);
tonikitoo81d92f82016-09-21 12:44:56 -0700111}
112
Tom Sepezaf18cb32015-02-05 15:06:01 -0800113static bool CheckDimensions(int stride, int width, int height) {
114 if (stride < 0 || width < 0 || height < 0)
115 return false;
116 if (height > 0 && width > INT_MAX / height)
117 return false;
118 return true;
119}
120
stephanafa05e972017-01-02 06:19:41 -0800121static void OutputMD5Hash(const char* file_name, const char* buffer, int len) {
122 // Get the MD5 hash and write it to stdout.
123 uint8_t digest[16];
124 CRYPT_MD5Generate(reinterpret_cast<const uint8_t*>(buffer), len, digest);
125 printf("MD5:%s:", file_name);
126 for (int i = 0; i < 16; i++)
127 printf("%02x", digest[i]);
128 printf("\n");
129}
130
131static std::string WritePpm(const char* pdf_name,
132 int num,
133 const void* buffer_void,
134 int stride,
135 int width,
136 int height) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700137 const char* buffer = reinterpret_cast<const char*>(buffer_void);
138
Tom Sepezaf18cb32015-02-05 15:06:01 -0800139 if (!CheckDimensions(stride, width, height))
stephanafa05e972017-01-02 06:19:41 -0800140 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800141
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700142 int out_len = width * height;
143 if (out_len > INT_MAX / 3)
stephanafa05e972017-01-02 06:19:41 -0800144 return "";
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700145 out_len *= 3;
146
147 char filename[256];
148 snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num);
John Abd-El-Maleka548d302014-06-26 10:18:11 -0700149 FILE* fp = fopen(filename, "wb");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700150 if (!fp)
stephanafa05e972017-01-02 06:19:41 -0800151 return "";
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700152 fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
153 // Source data is B, G, R, unused.
154 // Dest data is R, G, B.
thestig514e8c92016-07-15 17:57:54 -0700155 std::vector<char> result(out_len);
Lei Zhange00660b2015-08-13 15:40:18 -0700156 for (int h = 0; h < height; ++h) {
157 const char* src_line = buffer + (stride * h);
thestig514e8c92016-07-15 17:57:54 -0700158 char* dest_line = result.data() + (width * h * 3);
Lei Zhange00660b2015-08-13 15:40:18 -0700159 for (int w = 0; w < width; ++w) {
160 // R
161 dest_line[w * 3] = src_line[(w * 4) + 2];
162 // G
163 dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
164 // B
165 dest_line[(w * 3) + 2] = src_line[w * 4];
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700166 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700167 }
thestig514e8c92016-07-15 17:57:54 -0700168 fwrite(result.data(), out_len, 1, fp);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700169 fclose(fp);
stephanafa05e972017-01-02 06:19:41 -0800170 return std::string(filename);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700171}
172
dsinclairb63068f2016-06-16 07:58:09 -0700173void WriteText(FPDF_PAGE page, const char* pdf_name, int num) {
174 char filename[256];
175 int chars_formatted =
176 snprintf(filename, sizeof(filename), "%s.%d.txt", pdf_name, num);
177 if (chars_formatted < 0 ||
178 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
179 fprintf(stderr, "Filename %s is too long\n", filename);
180 return;
181 }
182
183 FILE* fp = fopen(filename, "w");
184 if (!fp) {
185 fprintf(stderr, "Failed to open %s for output\n", filename);
186 return;
187 }
188
189 // Output in UTF32-LE.
190 uint32_t bom = 0x0000FEFF;
191 fwrite(&bom, sizeof(bom), 1, fp);
192
Tom Sepez1d17a042017-03-16 13:22:47 -0700193 std::unique_ptr<void, FPDFTextPageDeleter> textpage(FPDFText_LoadPage(page));
194 for (int i = 0; i < FPDFText_CountChars(textpage.get()); i++) {
195 uint32_t c = FPDFText_GetUnicode(textpage.get(), i);
dsinclairb63068f2016-06-16 07:58:09 -0700196 fwrite(&c, sizeof(c), 1, fp);
197 }
dsinclairb63068f2016-06-16 07:58:09 -0700198 (void)fclose(fp);
199}
200
Jane Liu4fd9a472017-06-01 18:56:09 -0400201std::string AnnotSubtypeToString(FPDF_ANNOTATION_SUBTYPE subtype) {
202 if (subtype == FPDF_ANNOT_TEXT)
203 return "Text";
204 if (subtype == FPDF_ANNOT_LINK)
205 return "Link";
206 if (subtype == FPDF_ANNOT_FREETEXT)
207 return "FreeText";
208 if (subtype == FPDF_ANNOT_LINE)
209 return "Line";
210 if (subtype == FPDF_ANNOT_SQUARE)
211 return "Square";
212 if (subtype == FPDF_ANNOT_CIRCLE)
213 return "Circle";
214 if (subtype == FPDF_ANNOT_POLYGON)
215 return "Polygon";
216 if (subtype == FPDF_ANNOT_POLYLINE)
217 return "PolyLine";
218 if (subtype == FPDF_ANNOT_HIGHLIGHT)
219 return "Highlight";
220 if (subtype == FPDF_ANNOT_UNDERLINE)
221 return "Underline";
222 if (subtype == FPDF_ANNOT_SQUIGGLY)
223 return "Squiggly";
224 if (subtype == FPDF_ANNOT_STRIKEOUT)
225 return "StrikeOut";
226 if (subtype == FPDF_ANNOT_STAMP)
227 return "Stamp";
228 if (subtype == FPDF_ANNOT_CARET)
229 return "Caret";
230 if (subtype == FPDF_ANNOT_INK)
231 return "Ink";
232 if (subtype == FPDF_ANNOT_POPUP)
233 return "Popup";
234 if (subtype == FPDF_ANNOT_FILEATTACHMENT)
235 return "FileAttachment";
236 if (subtype == FPDF_ANNOT_SOUND)
237 return "Sound";
238 if (subtype == FPDF_ANNOT_MOVIE)
239 return "Movie";
240 if (subtype == FPDF_ANNOT_WIDGET)
241 return "Widget";
242 if (subtype == FPDF_ANNOT_SCREEN)
243 return "Screen";
244 if (subtype == FPDF_ANNOT_PRINTERMARK)
245 return "PrinterMark";
246 if (subtype == FPDF_ANNOT_TRAPNET)
247 return "TrapNet";
248 if (subtype == FPDF_ANNOT_WATERMARK)
249 return "Watermark";
250 if (subtype == FPDF_ANNOT_THREED)
251 return "3D";
252 if (subtype == FPDF_ANNOT_RICHMEDIA)
253 return "RichMedia";
254 if (subtype == FPDF_ANNOT_XFAWIDGET)
255 return "XFAWidget";
256 NOTREACHED();
257 return "";
258}
259
260void WriteAnnot(FPDF_PAGE page, const char* pdf_name, int num) {
261 // Open the output text file.
262 char filename[256];
263 int chars_formatted =
264 snprintf(filename, sizeof(filename), "%s.%d.annot.txt", pdf_name, num);
265 if (chars_formatted < 0 ||
266 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
267 fprintf(stderr, "Filename %s is too long\n", filename);
268 return;
269 }
270 FILE* fp = fopen(filename, "w");
271 if (!fp) {
272 fprintf(stderr, "Failed to open %s for output\n", filename);
273 return;
274 }
275
276 int annot_count = FPDFPage_GetAnnotCount(page);
277 fprintf(fp, "Number of annotations: %d\n\n", annot_count);
278
279 // Iterate through all annotations on this page.
280 for (int i = 0; i < annot_count; i++) {
281 // Retrieve the annotation object and its subtype.
282 fprintf(fp, "Annotation #%d:\n", i + 1);
283 FPDF_ANNOTATION annot;
284 if (!FPDFPage_GetAnnot(page, i, &annot)) {
285 fprintf(fp, "Failed to retrieve annotation!\n\n");
286 continue;
287 }
288 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
289 fprintf(fp, "Subtype: %s\n", AnnotSubtypeToString(subtype).c_str());
290
291 // Retrieve the annotation's color and interior color.
292 unsigned int R;
293 unsigned int G;
294 unsigned int B;
295 unsigned int A;
296 if (!FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A)) {
297 fprintf(fp, "Failed to retrieve color.\n");
298 } else {
299 fprintf(fp, "Color in RGBA: %d %d %d %d\n", R, G, B, A);
300 }
301 if (!FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_InteriorColor, &R, &G,
302 &B, &A)) {
303 fprintf(fp, "Failed to retrieve interior color.\n");
304 } else {
305 fprintf(fp, "Interior color in RGBA: %d %d %d %d\n", R, G, B, A);
306 }
307
308 // Retrieve the annotation's contents and author.
309 unsigned long len =
310 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, nullptr, 0);
311 std::vector<char> buf(len);
312 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, buf.data(), len);
313 fprintf(fp, "Content: %ls\n",
314 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
315 .c_str());
316 len = FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Author, nullptr, 0);
317 buf.clear();
318 buf.resize(len);
319 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Author, buf.data(), len);
320 fprintf(fp, "Author: %ls\n",
321 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
322 .c_str());
323
324 // Retrieve the annotation's quadpoints if it is a markup annotation.
325 FS_QUADPOINTSF quadpoints;
326 if (FPDFAnnot_HasAttachmentPoints(annot)) {
327 if (!FPDFAnnot_GetAttachmentPoints(annot, &quadpoints)) {
328 fprintf(fp, "Failed to retrieve quadpoints.\n");
329 } else {
330 fprintf(fp, "Quadpoints: (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n",
331 quadpoints.x1, quadpoints.y1, quadpoints.x2, quadpoints.y2,
332 quadpoints.x3, quadpoints.y3, quadpoints.x4, quadpoints.y4);
333 }
334 }
335
336 // Retrieve the annotation's rectangle coordinates.
337 FS_RECTF rect;
338 if (!FPDFAnnot_GetRect(annot, &rect)) {
339 fprintf(fp, "Failed to retrieve rectangle.\n\n");
340 } else {
341 fprintf(fp, "Rectangle: l - %f, b - %f, r - %f, t - %f\n\n", rect.left,
342 rect.bottom, rect.right, rect.top);
343 }
344 }
345
346 (void)fclose(fp);
347}
348
stephanafa05e972017-01-02 06:19:41 -0800349static std::string WritePng(const char* pdf_name,
350 int num,
351 const void* buffer_void,
352 int stride,
353 int width,
354 int height) {
Tom Sepezaf18cb32015-02-05 15:06:01 -0800355 if (!CheckDimensions(stride, width, height))
stephanafa05e972017-01-02 06:19:41 -0800356 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800357
358 std::vector<unsigned char> png_encoding;
359 const unsigned char* buffer = static_cast<const unsigned char*>(buffer_void);
360 if (!image_diff_png::EncodeBGRAPNG(
361 buffer, width, height, stride, false, &png_encoding)) {
362 fprintf(stderr, "Failed to convert bitmap to PNG\n");
stephanafa05e972017-01-02 06:19:41 -0800363 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800364 }
365
366 char filename[256];
367 int chars_formatted = snprintf(
368 filename, sizeof(filename), "%s.%d.png", pdf_name, num);
369 if (chars_formatted < 0 ||
370 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
Cary Clark399be5b2016-03-14 16:51:29 -0400371 fprintf(stderr, "Filename %s is too long\n", filename);
stephanafa05e972017-01-02 06:19:41 -0800372 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800373 }
374
375 FILE* fp = fopen(filename, "wb");
376 if (!fp) {
377 fprintf(stderr, "Failed to open %s for output\n", filename);
stephanafa05e972017-01-02 06:19:41 -0800378 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800379 }
380
381 size_t bytes_written = fwrite(
382 &png_encoding.front(), 1, png_encoding.size(), fp);
383 if (bytes_written != png_encoding.size())
384 fprintf(stderr, "Failed to write to %s\n", filename);
385
Lei Zhang5377ebf2015-09-23 14:52:53 -0700386 (void)fclose(fp);
stephanafa05e972017-01-02 06:19:41 -0800387 return std::string(filename);
Tom Sepezaf18cb32015-02-05 15:06:01 -0800388}
389
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700390#ifdef _WIN32
stephanafa05e972017-01-02 06:19:41 -0800391static std::string WriteBmp(const char* pdf_name,
392 int num,
393 const void* buffer,
394 int stride,
395 int width,
396 int height) {
Tom Sepezaf18cb32015-02-05 15:06:01 -0800397 if (!CheckDimensions(stride, width, height))
stephanafa05e972017-01-02 06:19:41 -0800398 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800399
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700400 int out_len = stride * height;
401 if (out_len > INT_MAX / 3)
stephanafa05e972017-01-02 06:19:41 -0800402 return "";
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700403
404 char filename[256];
405 snprintf(filename, sizeof(filename), "%s.%d.bmp", pdf_name, num);
406 FILE* fp = fopen(filename, "wb");
407 if (!fp)
stephanafa05e972017-01-02 06:19:41 -0800408 return "";
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700409
Nico Weber2827bdd2015-07-01 14:08:08 -0700410 BITMAPINFO bmi = {};
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700411 bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
412 bmi.bmiHeader.biWidth = width;
413 bmi.bmiHeader.biHeight = -height; // top-down image
414 bmi.bmiHeader.biPlanes = 1;
415 bmi.bmiHeader.biBitCount = 32;
416 bmi.bmiHeader.biCompression = BI_RGB;
417 bmi.bmiHeader.biSizeImage = 0;
418
Nico Weber2827bdd2015-07-01 14:08:08 -0700419 BITMAPFILEHEADER file_header = {};
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700420 file_header.bfType = 0x4d42;
421 file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
422 file_header.bfOffBits = file_header.bfSize - out_len;
423
424 fwrite(&file_header, sizeof(file_header), 1, fp);
425 fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp);
426 fwrite(buffer, out_len, 1, fp);
427 fclose(fp);
stephanafa05e972017-01-02 06:19:41 -0800428 return std::string(filename);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700429}
430
431void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700432 char filename[256];
433 snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
434
Lei Zhang5377ebf2015-09-23 14:52:53 -0700435 HDC dc = CreateEnhMetaFileA(nullptr, filename, nullptr, nullptr);
Tom Sepezaf18cb32015-02-05 15:06:01 -0800436
Lei Zhangd1c9b452017-05-05 17:21:36 -0700437 int width = static_cast<int>(FPDF_GetPageWidth(page));
438 int height = static_cast<int>(FPDF_GetPageHeight(page));
Tom Sepezaf18cb32015-02-05 15:06:01 -0800439 HRGN rgn = CreateRectRgn(0, 0, width, height);
440 SelectClipRgn(dc, rgn);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700441 DeleteObject(rgn);
442
443 SelectObject(dc, GetStockObject(NULL_PEN));
444 SelectObject(dc, GetStockObject(WHITE_BRUSH));
445 // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
446 Rectangle(dc, 0, 0, width + 1, height + 1);
447
448 FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
449 FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
450
451 DeleteEnhMetaFile(CloseEnhMetaFile(dc));
452}
Lei Zhangd1c9b452017-05-05 17:21:36 -0700453
454int CALLBACK EnhMetaFileProc(HDC hdc,
455 HANDLETABLE* handle_table,
456 const ENHMETARECORD* record,
457 int objects_count,
458 LPARAM param) {
459 std::vector<const ENHMETARECORD*>& items =
460 *reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
461 items.push_back(record);
462 return 1;
463}
464
465void WritePS(FPDF_PAGE page, const char* pdf_name, int num) {
466 char filename[256];
467 snprintf(filename, sizeof(filename), "%s.%d.ps", pdf_name, num);
468 FILE* fp = fopen(filename, "wb");
469 if (!fp)
470 return;
471
472 HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
473
474 int width = static_cast<int>(FPDF_GetPageWidth(page));
475 int height = static_cast<int>(FPDF_GetPageHeight(page));
476 FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
477 FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
478
479 HENHMETAFILE emf = CloseEnhMetaFile(dc);
480 std::vector<const ENHMETARECORD*> items;
481 EnumEnhMetaFile(nullptr, emf, &EnhMetaFileProc, &items, nullptr);
482 for (const ENHMETARECORD* record : items) {
483 if (record->iType != EMR_GDICOMMENT)
484 continue;
485
486 const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
487 const char* data = reinterpret_cast<const char*>(comment->Data);
488 uint16_t size = *reinterpret_cast<const uint16_t*>(data);
489 fwrite(data + sizeof(uint16_t), size, 1, fp);
490 }
491 fclose(fp);
492 DeleteEnhMetaFile(emf);
493}
494#endif // _WIN32
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700495
Cary Clark399be5b2016-03-14 16:51:29 -0400496#ifdef PDF_ENABLE_SKIA
stephanafa05e972017-01-02 06:19:41 -0800497static std::string WriteSkp(const char* pdf_name,
498 int num,
499 SkPictureRecorder* recorder) {
Cary Clark399be5b2016-03-14 16:51:29 -0400500 char filename[256];
501 int chars_formatted =
502 snprintf(filename, sizeof(filename), "%s.%d.skp", pdf_name, num);
503
504 if (chars_formatted < 0 ||
505 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
506 fprintf(stderr, "Filename %s is too long\n", filename);
stephanafa05e972017-01-02 06:19:41 -0800507 return "";
Cary Clark399be5b2016-03-14 16:51:29 -0400508 }
509
thestigb97e07e2016-09-28 22:16:40 -0700510 sk_sp<SkPicture> picture(recorder->finishRecordingAsPicture());
Cary Clark399be5b2016-03-14 16:51:29 -0400511 SkFILEWStream wStream(filename);
512 picture->serialize(&wStream);
stephanafa05e972017-01-02 06:19:41 -0800513 return std::string(filename);
Cary Clark399be5b2016-03-14 16:51:29 -0400514}
515#endif
516
Tom Sepez58fb36a2016-02-01 10:32:14 -0800517// These example JS platform callback handlers are entirely optional,
518// and exist here to show the flow of information from a document back
519// to the embedder.
Tom Sepezbd932572016-01-29 09:10:41 -0800520int ExampleAppAlert(IPDF_JSPLATFORM*,
521 FPDF_WIDESTRING msg,
522 FPDF_WIDESTRING title,
npmfa20cd52016-11-14 13:33:40 -0800523 int type,
524 int icon) {
Tom Sepezbd932572016-01-29 09:10:41 -0800525 printf("%ls", GetPlatformWString(title).c_str());
npmfa20cd52016-11-14 13:33:40 -0800526 if (icon || type)
527 printf("[icon=%d,type=%d]", icon, type);
Tom Sepezbd932572016-01-29 09:10:41 -0800528 printf(": %ls\n", GetPlatformWString(msg).c_str());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700529 return 0;
530}
531
Tom Sepez58fb36a2016-02-01 10:32:14 -0800532int ExampleAppResponse(IPDF_JSPLATFORM*,
533 FPDF_WIDESTRING question,
534 FPDF_WIDESTRING title,
npmfa20cd52016-11-14 13:33:40 -0800535 FPDF_WIDESTRING default_value,
Tom Sepez58fb36a2016-02-01 10:32:14 -0800536 FPDF_WIDESTRING label,
npmfa20cd52016-11-14 13:33:40 -0800537 FPDF_BOOL is_password,
Tom Sepez58fb36a2016-02-01 10:32:14 -0800538 void* response,
539 int length) {
540 printf("%ls: %ls, defaultValue=%ls, label=%ls, isPassword=%d, length=%d\n",
541 GetPlatformWString(title).c_str(),
542 GetPlatformWString(question).c_str(),
npmfa20cd52016-11-14 13:33:40 -0800543 GetPlatformWString(default_value).c_str(),
544 GetPlatformWString(label).c_str(), is_password, length);
Tom Sepez58fb36a2016-02-01 10:32:14 -0800545
546 // UTF-16, always LE regardless of platform.
547 uint8_t* ptr = static_cast<uint8_t*>(response);
548 ptr[0] = 'N';
549 ptr[1] = 0;
550 ptr[2] = 'o';
551 ptr[3] = 0;
552 return 4;
553}
554
npmfa20cd52016-11-14 13:33:40 -0800555void ExampleDocGotoPage(IPDF_JSPLATFORM*, int page_number) {
556 printf("Goto Page: %d\n", page_number);
Tom Sepezb7cb36a2015-02-13 16:54:48 -0800557}
558
Tom Sepeze5fbd7a2016-01-29 17:05:08 -0800559void ExampleDocMail(IPDF_JSPLATFORM*,
560 void* mailData,
561 int length,
npmfa20cd52016-11-14 13:33:40 -0800562 FPDF_BOOL UI,
Tom Sepeze5fbd7a2016-01-29 17:05:08 -0800563 FPDF_WIDESTRING To,
564 FPDF_WIDESTRING Subject,
565 FPDF_WIDESTRING CC,
566 FPDF_WIDESTRING BCC,
567 FPDF_WIDESTRING Msg) {
npmfa20cd52016-11-14 13:33:40 -0800568 printf("Mail Msg: %d, to=%ls, cc=%ls, bcc=%ls, subject=%ls, body=%ls\n", UI,
Tom Sepeze5fbd7a2016-01-29 17:05:08 -0800569 GetPlatformWString(To).c_str(), GetPlatformWString(CC).c_str(),
570 GetPlatformWString(BCC).c_str(), GetPlatformWString(Subject).c_str(),
571 GetPlatformWString(Msg).c_str());
572}
573
Tom Sepezb7cb36a2015-02-13 16:54:48 -0800574void ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700575 std::string feature = "Unknown";
576 switch (type) {
577 case FPDF_UNSP_DOC_XFAFORM:
578 feature = "XFA";
579 break;
580 case FPDF_UNSP_DOC_PORTABLECOLLECTION:
581 feature = "Portfolios_Packages";
582 break;
583 case FPDF_UNSP_DOC_ATTACHMENT:
584 case FPDF_UNSP_ANNOT_ATTACHMENT:
585 feature = "Attachment";
586 break;
587 case FPDF_UNSP_DOC_SECURITY:
588 feature = "Rights_Management";
589 break;
590 case FPDF_UNSP_DOC_SHAREDREVIEW:
591 feature = "Shared_Review";
592 break;
593 case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
594 case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
595 case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
596 feature = "Shared_Form";
597 break;
598 case FPDF_UNSP_ANNOT_3DANNOT:
599 feature = "3D";
600 break;
601 case FPDF_UNSP_ANNOT_MOVIE:
602 feature = "Movie";
603 break;
604 case FPDF_UNSP_ANNOT_SOUND:
605 feature = "Sound";
606 break;
607 case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
608 case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
609 feature = "Screen";
610 break;
611 case FPDF_UNSP_ANNOT_SIG:
612 feature = "Digital_Signature";
613 break;
614 }
615 printf("Unsupported feature: %s.\n", feature.c_str());
616}
617
Tom Sepez5ee12d72014-12-17 16:24:01 -0800618bool ParseCommandLine(const std::vector<std::string>& args,
thestig514e8c92016-07-15 17:57:54 -0700619 Options* options,
620 std::vector<std::string>* files) {
621 if (args.empty())
Tom Sepez5ee12d72014-12-17 16:24:01 -0800622 return false;
thestig514e8c92016-07-15 17:57:54 -0700623
Tom Sepez5ee12d72014-12-17 16:24:01 -0800624 options->exe_path = args[0];
Bo Xud44e3922014-12-19 02:27:25 -0800625 size_t cur_idx = 1;
Tom Sepez5ee12d72014-12-17 16:24:01 -0800626 for (; cur_idx < args.size(); ++cur_idx) {
627 const std::string& cur_arg = args[cur_idx];
Tom Sepez2991d8d2016-01-15 16:02:48 -0800628 if (cur_arg == "--show-config") {
629 options->show_config = true;
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -0400630 } else if (cur_arg == "--show-metadata") {
631 options->show_metadata = true;
tsepezf09bdfa2016-04-18 16:08:26 -0700632 } else if (cur_arg == "--send-events") {
633 options->send_events = true;
Tom Sepez2991d8d2016-01-15 16:02:48 -0800634 } else if (cur_arg == "--ppm") {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800635 if (options->output_format != OUTPUT_NONE) {
636 fprintf(stderr, "Duplicate or conflicting --ppm argument\n");
637 return false;
638 }
639 options->output_format = OUTPUT_PPM;
Tom Sepezaf18cb32015-02-05 15:06:01 -0800640 } else if (cur_arg == "--png") {
641 if (options->output_format != OUTPUT_NONE) {
642 fprintf(stderr, "Duplicate or conflicting --png argument\n");
643 return false;
644 }
645 options->output_format = OUTPUT_PNG;
dsinclairb63068f2016-06-16 07:58:09 -0700646 } else if (cur_arg == "--txt") {
647 if (options->output_format != OUTPUT_NONE) {
648 fprintf(stderr, "Duplicate or conflicting --txt argument\n");
649 return false;
650 }
651 options->output_format = OUTPUT_TEXT;
Jane Liu4fd9a472017-06-01 18:56:09 -0400652 } else if (cur_arg == "--annot") {
653 if (options->output_format != OUTPUT_NONE) {
654 fprintf(stderr, "Duplicate or conflicting --annot argument\n");
655 return false;
656 }
657 options->output_format = OUTPUT_ANNOT;
Cary Clark399be5b2016-03-14 16:51:29 -0400658#ifdef PDF_ENABLE_SKIA
659 } else if (cur_arg == "--skp") {
660 if (options->output_format != OUTPUT_NONE) {
661 fprintf(stderr, "Duplicate or conflicting --skp argument\n");
662 return false;
663 }
664 options->output_format = OUTPUT_SKP;
665#endif
Lei Zhang6f62d532015-09-23 15:31:44 -0700666 } else if (cur_arg.size() > 11 &&
667 cur_arg.compare(0, 11, "--font-dir=") == 0) {
668 if (!options->font_directory.empty()) {
669 fprintf(stderr, "Duplicate --font-dir argument\n");
670 return false;
671 }
672 options->font_directory = cur_arg.substr(11);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700673#ifdef _WIN32
Dan Sinclair738b08c2016-03-01 14:45:20 -0500674 } else if (cur_arg == "--emf") {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800675 if (options->output_format != OUTPUT_NONE) {
676 fprintf(stderr, "Duplicate or conflicting --emf argument\n");
677 return false;
678 }
679 options->output_format = OUTPUT_EMF;
Lei Zhangd1c9b452017-05-05 17:21:36 -0700680 } else if (cur_arg == "--ps2") {
681 if (options->output_format != OUTPUT_NONE) {
682 fprintf(stderr, "Duplicate or conflicting --ps2 argument\n");
683 return false;
684 }
685 options->output_format = OUTPUT_PS2;
686 } else if (cur_arg == "--ps3") {
687 if (options->output_format != OUTPUT_NONE) {
688 fprintf(stderr, "Duplicate or conflicting --ps3 argument\n");
689 return false;
690 }
691 options->output_format = OUTPUT_PS3;
Dan Sinclair50cce602016-02-24 09:51:16 -0500692 } else if (cur_arg == "--bmp") {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800693 if (options->output_format != OUTPUT_NONE) {
694 fprintf(stderr, "Duplicate or conflicting --bmp argument\n");
695 return false;
696 }
697 options->output_format = OUTPUT_BMP;
Tom Sepez5ee12d72014-12-17 16:24:01 -0800698#endif // _WIN32
Dan Sinclair738b08c2016-03-01 14:45:20 -0500699
Tom Sepez452b4f32015-10-13 09:27:27 -0700700#ifdef PDF_ENABLE_V8
Tom Sepez5ee12d72014-12-17 16:24:01 -0800701#ifdef V8_USE_EXTERNAL_STARTUP_DATA
Dan Sinclair738b08c2016-03-01 14:45:20 -0500702 } else if (cur_arg.size() > 10 &&
703 cur_arg.compare(0, 10, "--bin-dir=") == 0) {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800704 if (!options->bin_directory.empty()) {
705 fprintf(stderr, "Duplicate --bin-dir argument\n");
706 return false;
707 }
708 options->bin_directory = cur_arg.substr(10);
Tom Sepez5ee12d72014-12-17 16:24:01 -0800709#endif // V8_USE_EXTERNAL_STARTUP_DATA
Tom Sepez452b4f32015-10-13 09:27:27 -0700710#endif // PDF_ENABLE_V8
Dan Sinclair738b08c2016-03-01 14:45:20 -0500711
712 } else if (cur_arg.size() > 8 && cur_arg.compare(0, 8, "--scale=") == 0) {
Tom Sepezdaa2e842015-01-29 15:44:37 -0800713 if (!options->scale_factor_as_string.empty()) {
714 fprintf(stderr, "Duplicate --scale argument\n");
715 return false;
716 }
717 options->scale_factor_as_string = cur_arg.substr(8);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400718 } else if (cur_arg == "--show-structure") {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400719 if (options->output_format != OUTPUT_NONE) {
720 fprintf(stderr, "Duplicate or conflicting --show-structure argument\n");
721 return false;
722 }
723 options->output_format = OUTPUT_STRUCTURE;
npme3c73152016-11-14 09:14:52 -0800724 } else if (cur_arg.size() > 8 && cur_arg.compare(0, 8, "--pages=") == 0) {
725 if (options->pages) {
726 fprintf(stderr, "Duplicate --pages argument\n");
727 return false;
728 }
729 options->pages = true;
npmfa20cd52016-11-14 13:33:40 -0800730 const std::string pages_string = cur_arg.substr(8);
731 size_t first_dash = pages_string.find("-");
732 if (first_dash == std::string::npos) {
733 std::stringstream(pages_string) >> options->first_page;
734 options->last_page = options->first_page;
npme3c73152016-11-14 09:14:52 -0800735 } else {
npmfa20cd52016-11-14 13:33:40 -0800736 std::stringstream(pages_string.substr(0, first_dash)) >>
737 options->first_page;
738 std::stringstream(pages_string.substr(first_dash + 1)) >>
739 options->last_page;
npme3c73152016-11-14 09:14:52 -0800740 }
stephanafa05e972017-01-02 06:19:41 -0800741 } else if (cur_arg == "--md5") {
742 options->md5 = true;
Tom Sepez2991d8d2016-01-15 16:02:48 -0800743 } else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') {
744 fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str());
745 return false;
Dan Sinclair738b08c2016-03-01 14:45:20 -0500746 } else {
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700747 break;
Dan Sinclair738b08c2016-03-01 14:45:20 -0500748 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700749 }
thestig514e8c92016-07-15 17:57:54 -0700750 for (size_t i = cur_idx; i < args.size(); i++)
Tom Sepez5ee12d72014-12-17 16:24:01 -0800751 files->push_back(args[i]);
thestig514e8c92016-07-15 17:57:54 -0700752
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700753 return true;
754}
755
npmfa20cd52016-11-14 13:33:40 -0800756FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700757 return true;
758}
759
npmfa20cd52016-11-14 13:33:40 -0800760void Add_Segment(FX_DOWNLOADHINTS* hints, size_t offset, size_t size) {}
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700761
Lei Zhang54d91ec2017-06-16 19:08:02 -0700762void SendPageEvents(FPDF_FORMHANDLE form,
763 FPDF_PAGE page,
tsepezf09bdfa2016-04-18 16:08:26 -0700764 const std::string& events) {
765 auto lines = StringSplit(events, '\n');
766 for (auto line : lines) {
767 auto command = StringSplit(line, '#');
768 if (command[0].empty())
769 continue;
770 auto tokens = StringSplit(command[0], ',');
Nicolas Penae30f07a2017-05-18 18:37:46 -0400771 if (tokens[0] == "charcode") {
772 if (tokens.size() == 2) {
773 int keycode = atoi(tokens[1].c_str());
774 FORM_OnChar(form, page, keycode, 0);
775 } else {
776 fprintf(stderr, "charcode: bad args\n");
777 }
778 } else if (tokens[0] == "keycode") {
tsepezf09bdfa2016-04-18 16:08:26 -0700779 if (tokens.size() == 2) {
780 int keycode = atoi(tokens[1].c_str());
781 FORM_OnKeyDown(form, page, keycode, 0);
782 FORM_OnKeyUp(form, page, keycode, 0);
783 } else {
784 fprintf(stderr, "keycode: bad args\n");
785 }
786 } else if (tokens[0] == "mousedown") {
787 if (tokens.size() == 4) {
788 int x = atoi(tokens[2].c_str());
789 int y = atoi(tokens[3].c_str());
790 if (tokens[1] == "left")
791 FORM_OnLButtonDown(form, page, 0, x, y);
792#ifdef PDF_ENABLE_XFA
793 else if (tokens[1] == "right")
794 FORM_OnRButtonDown(form, page, 0, x, y);
795#endif
796 else
797 fprintf(stderr, "mousedown: bad button name\n");
798 } else {
799 fprintf(stderr, "mousedown: bad args\n");
800 }
801 } else if (tokens[0] == "mouseup") {
802 if (tokens.size() == 4) {
803 int x = atoi(tokens[2].c_str());
804 int y = atoi(tokens[3].c_str());
805 if (tokens[1] == "left")
806 FORM_OnLButtonUp(form, page, 0, x, y);
807#ifdef PDF_ENABLE_XFA
808 else if (tokens[1] == "right")
809 FORM_OnRButtonUp(form, page, 0, x, y);
810#endif
811 else
812 fprintf(stderr, "mouseup: bad button name\n");
813 } else {
814 fprintf(stderr, "mouseup: bad args\n");
815 }
816 } else if (tokens[0] == "mousemove") {
817 if (tokens.size() == 3) {
818 int x = atoi(tokens[1].c_str());
819 int y = atoi(tokens[2].c_str());
820 FORM_OnMouseMove(form, page, 0, x, y);
821 } else {
822 fprintf(stderr, "mousemove: bad args\n");
823 }
824 } else {
825 fprintf(stderr, "Unrecognized event: %s\n", tokens[0].c_str());
826 }
827 }
828}
829
tonikitoo3e981582016-08-26 08:37:10 -0700830FPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,
831 FPDF_DOCUMENT doc,
832 int index) {
npmfa20cd52016-11-14 13:33:40 -0800833 FPDF_FORMFILLINFO_PDFiumTest* form_fill_info =
834 ToPDFiumTestFormFillInfo(param);
835 auto& loaded_pages = form_fill_info->loaded_pages;
npmfa20cd52016-11-14 13:33:40 -0800836 auto iter = loaded_pages.find(index);
837 if (iter != loaded_pages.end())
tonikitoo3e981582016-08-26 08:37:10 -0700838 return iter->second;
839
840 FPDF_PAGE page = FPDF_LoadPage(doc, index);
841 if (!page)
842 return nullptr;
843
npmfa20cd52016-11-14 13:33:40 -0800844 FPDF_FORMHANDLE& form_handle = form_fill_info->form_handle;
npmfa20cd52016-11-14 13:33:40 -0800845 FORM_OnAfterLoadPage(page, form_handle);
846 FORM_DoPageAAction(page, form_handle, FPDFPAGE_AACTION_OPEN);
npmfa20cd52016-11-14 13:33:40 -0800847 loaded_pages[index] = page;
tonikitoo3e981582016-08-26 08:37:10 -0700848 return page;
849}
850
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400851std::wstring ConvertToWString(const unsigned short* buf,
852 unsigned long buf_size) {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400853 std::wstring result;
854 result.reserve(buf_size);
855 std::copy(buf, buf + buf_size, std::back_inserter(result));
856 return result;
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400857}
858
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400859void DumpChildStructure(FPDF_STRUCTELEMENT child, int indent) {
860 static const size_t kBufSize = 1024;
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400861 unsigned short buf[kBufSize];
862 unsigned long len = FPDF_StructElement_GetType(child, buf, kBufSize);
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400863 printf("%*s%ls", indent * 2, "", ConvertToWString(buf, len).c_str());
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400864
865 memset(buf, 0, sizeof(buf));
dan sinclaird9dad3a2017-04-06 14:44:02 -0400866 len = FPDF_StructElement_GetTitle(child, buf, kBufSize);
867 if (len > 0)
868 printf(": '%ls'", ConvertToWString(buf, len).c_str());
869
870 memset(buf, 0, sizeof(buf));
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400871 len = FPDF_StructElement_GetAltText(child, buf, kBufSize);
872 if (len > 0)
873 printf(" (%ls)", ConvertToWString(buf, len).c_str());
874 printf("\n");
875
876 for (int i = 0; i < FPDF_StructElement_CountChildren(child); ++i) {
877 FPDF_STRUCTELEMENT sub_child = FPDF_StructElement_GetChildAtIndex(child, i);
878 // If the child is not an Element then this will return null. This can
879 // happen if the element is things like an object reference or a stream.
880 if (!sub_child)
881 continue;
882
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400883 DumpChildStructure(sub_child, indent + 1);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400884 }
885}
886
887void DumpPageStructure(FPDF_PAGE page, const int page_idx) {
888 std::unique_ptr<void, FPDFStructTreeDeleter> tree(
889 FPDF_StructTree_GetForPage(page));
890 if (!tree) {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400891 fprintf(stderr, "Failed to load struct tree for page %d\n", page_idx);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400892 return;
893 }
894
895 printf("Structure Tree for Page %d\n", page_idx);
896 for (int i = 0; i < FPDF_StructTree_CountChildren(tree.get()); ++i) {
897 FPDF_STRUCTELEMENT child = FPDF_StructTree_GetChildAtIndex(tree.get(), i);
898 if (!child) {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400899 fprintf(stderr, "Failed to load child %d for page %d\n", i, page_idx);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400900 continue;
901 }
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400902 DumpChildStructure(child, 0);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400903 }
904 printf("\n\n");
905}
906
Jun Fangb553bcb2015-11-10 18:49:04 +0800907bool RenderPage(const std::string& name,
tonikitoo3e981582016-08-26 08:37:10 -0700908 FPDF_DOCUMENT doc,
Tom Sepez1d17a042017-03-16 13:22:47 -0700909 FPDF_FORMHANDLE form,
npmfa20cd52016-11-14 13:33:40 -0800910 FPDF_FORMFILLINFO_PDFiumTest& form_fill_info,
Jun Fangb553bcb2015-11-10 18:49:04 +0800911 const int page_index,
tsepezf09bdfa2016-04-18 16:08:26 -0700912 const Options& options,
913 const std::string& events) {
Tom Sepez1d17a042017-03-16 13:22:47 -0700914 std::unique_ptr<void, FPDFPageDeleter> page(
915 GetPageForIndex(&form_fill_info, doc, page_index));
916 if (!page.get())
Jun Fangb553bcb2015-11-10 18:49:04 +0800917 return false;
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400918 if (options.send_events)
919 SendPageEvents(form, page.get(), events);
920 if (options.output_format == OUTPUT_STRUCTURE) {
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400921 DumpPageStructure(page.get(), page_index);
922 return true;
923 }
924
Tom Sepez1d17a042017-03-16 13:22:47 -0700925 std::unique_ptr<void, FPDFTextPageDeleter> text_page(
926 FPDFText_LoadPage(page.get()));
tsepezf09bdfa2016-04-18 16:08:26 -0700927
Jun Fangdf7f3662015-11-10 18:29:18 +0800928 double scale = 1.0;
thestig514e8c92016-07-15 17:57:54 -0700929 if (!options.scale_factor_as_string.empty())
Jun Fangdf7f3662015-11-10 18:29:18 +0800930 std::stringstream(options.scale_factor_as_string) >> scale;
thestig514e8c92016-07-15 17:57:54 -0700931
Tom Sepez1d17a042017-03-16 13:22:47 -0700932 int width = static_cast<int>(FPDF_GetPageWidth(page.get()) * scale);
933 int height = static_cast<int>(FPDF_GetPageHeight(page.get()) * scale);
934 int alpha = FPDFPage_HasTransparency(page.get()) ? 1 : 0;
935 std::unique_ptr<void, FPDFBitmapDeleter> bitmap(
936 FPDFBitmap_Create(width, height, alpha));
937
thestige97ea032016-05-19 10:59:15 -0700938 if (bitmap) {
939 FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
Tom Sepez1d17a042017-03-16 13:22:47 -0700940 FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);
941 FPDF_RenderPageBitmap(bitmap.get(), page.get(), 0, 0, width, height, 0,
942 FPDF_ANNOT);
Jun Fangdf7f3662015-11-10 18:29:18 +0800943
Tom Sepez1d17a042017-03-16 13:22:47 -0700944 FPDF_FFLDraw(form, bitmap.get(), page.get(), 0, 0, width, height, 0,
945 FPDF_ANNOT);
946 int stride = FPDFBitmap_GetStride(bitmap.get());
thestige97ea032016-05-19 10:59:15 -0700947 const char* buffer =
Tom Sepez1d17a042017-03-16 13:22:47 -0700948 reinterpret_cast<const char*>(FPDFBitmap_GetBuffer(bitmap.get()));
Jun Fangdf7f3662015-11-10 18:29:18 +0800949
stephanafa05e972017-01-02 06:19:41 -0800950 std::string&& image_file_name = "";
thestige97ea032016-05-19 10:59:15 -0700951 switch (options.output_format) {
Jun Fangdf7f3662015-11-10 18:29:18 +0800952#ifdef _WIN32
thestige97ea032016-05-19 10:59:15 -0700953 case OUTPUT_BMP:
stephanafa05e972017-01-02 06:19:41 -0800954 image_file_name =
955 WriteBmp(name.c_str(), page_index, buffer, stride, width, height);
thestige97ea032016-05-19 10:59:15 -0700956 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800957
thestige97ea032016-05-19 10:59:15 -0700958 case OUTPUT_EMF:
Tom Sepez1d17a042017-03-16 13:22:47 -0700959 WriteEmf(page.get(), name.c_str(), page_index);
thestige97ea032016-05-19 10:59:15 -0700960 break;
Lei Zhangd1c9b452017-05-05 17:21:36 -0700961
962 case OUTPUT_PS2:
963 case OUTPUT_PS3:
964 WritePS(page.get(), name.c_str(), page_index);
965 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800966#endif
dsinclairb63068f2016-06-16 07:58:09 -0700967 case OUTPUT_TEXT:
Tom Sepez1d17a042017-03-16 13:22:47 -0700968 WriteText(page.get(), name.c_str(), page_index);
dsinclairb63068f2016-06-16 07:58:09 -0700969 break;
970
Jane Liu4fd9a472017-06-01 18:56:09 -0400971 case OUTPUT_ANNOT:
972 WriteAnnot(page.get(), name.c_str(), page_index);
973 break;
974
thestige97ea032016-05-19 10:59:15 -0700975 case OUTPUT_PNG:
stephanafa05e972017-01-02 06:19:41 -0800976 image_file_name =
977 WritePng(name.c_str(), page_index, buffer, stride, width, height);
thestige97ea032016-05-19 10:59:15 -0700978 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800979
thestige97ea032016-05-19 10:59:15 -0700980 case OUTPUT_PPM:
stephanafa05e972017-01-02 06:19:41 -0800981 image_file_name =
982 WritePpm(name.c_str(), page_index, buffer, stride, width, height);
thestige97ea032016-05-19 10:59:15 -0700983 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800984
Cary Clark399be5b2016-03-14 16:51:29 -0400985#ifdef PDF_ENABLE_SKIA
thestige97ea032016-05-19 10:59:15 -0700986 case OUTPUT_SKP: {
987 std::unique_ptr<SkPictureRecorder> recorder(
thestigb97e07e2016-09-28 22:16:40 -0700988 reinterpret_cast<SkPictureRecorder*>(
Tom Sepez1d17a042017-03-16 13:22:47 -0700989 FPDF_RenderPageSkp(page.get(), width, height)));
990 FPDF_FFLRecord(form, recorder.get(), page.get(), 0, 0, width, height, 0,
991 0);
stephanafa05e972017-01-02 06:19:41 -0800992 image_file_name = WriteSkp(name.c_str(), page_index, recorder.get());
thestige97ea032016-05-19 10:59:15 -0700993 } break;
Cary Clark399be5b2016-03-14 16:51:29 -0400994#endif
thestige97ea032016-05-19 10:59:15 -0700995 default:
996 break;
997 }
Jun Fangdf7f3662015-11-10 18:29:18 +0800998
stephanafa05e972017-01-02 06:19:41 -0800999 // Write the filename and the MD5 of the buffer to stdout if we wrote a
1000 // file.
1001 if (options.md5 && image_file_name != "")
1002 OutputMD5Hash(image_file_name.c_str(), buffer, stride * height);
thestige97ea032016-05-19 10:59:15 -07001003 } else {
1004 fprintf(stderr, "Page was too large to be rendered.\n");
1005 }
tonikitoo3e981582016-08-26 08:37:10 -07001006
npmfa20cd52016-11-14 13:33:40 -08001007 form_fill_info.loaded_pages.erase(page_index);
Tom Sepez1d17a042017-03-16 13:22:47 -07001008 FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_CLOSE);
1009 FORM_OnBeforeClosePage(page.get(), form);
thestige97ea032016-05-19 10:59:15 -07001010 return !!bitmap;
Jun Fangdf7f3662015-11-10 18:29:18 +08001011}
1012
tsepezf09bdfa2016-04-18 16:08:26 -07001013void RenderPdf(const std::string& name,
1014 const char* pBuf,
1015 size_t len,
1016 const Options& options,
1017 const std::string& events) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001018 IPDF_JSPLATFORM platform_callbacks;
1019 memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
Tom Sepeza72e8e22015-10-07 10:17:53 -07001020 platform_callbacks.version = 3;
Tom Sepezb7cb36a2015-02-13 16:54:48 -08001021 platform_callbacks.app_alert = ExampleAppAlert;
Tom Sepez58fb36a2016-02-01 10:32:14 -08001022 platform_callbacks.app_response = ExampleAppResponse;
Tom Sepezb7cb36a2015-02-13 16:54:48 -08001023 platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
Tom Sepeze5fbd7a2016-01-29 17:05:08 -08001024 platform_callbacks.Doc_mail = ExampleDocMail;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001025
tonikitoo81d92f82016-09-21 12:44:56 -07001026 FPDF_FORMFILLINFO_PDFiumTest form_callbacks = {};
Tom Sepezc46d0002015-11-30 15:46:36 -08001027#ifdef PDF_ENABLE_XFA
Tom Sepezed631382014-11-18 14:10:25 -08001028 form_callbacks.version = 2;
Tom Sepezc46d0002015-11-30 15:46:36 -08001029#else // PDF_ENABLE_XFA
1030 form_callbacks.version = 1;
1031#endif // PDF_ENABLE_XFA
tonikitoo3e981582016-08-26 08:37:10 -07001032 form_callbacks.FFI_GetPage = GetPageForIndex;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001033 form_callbacks.m_pJsPlatform = &platform_callbacks;
1034
1035 TestLoader loader(pBuf, len);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001036 FPDF_FILEACCESS file_access;
1037 memset(&file_access, '\0', sizeof(file_access));
John Abd-El-Malek7dc51722014-05-26 12:54:31 -07001038 file_access.m_FileLen = static_cast<unsigned long>(len);
Tom Sepezd831dc72015-10-19 16:04:22 -07001039 file_access.m_GetBlock = TestLoader::GetBlock;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001040 file_access.m_Param = &loader;
1041
1042 FX_FILEAVAIL file_avail;
1043 memset(&file_avail, '\0', sizeof(file_avail));
1044 file_avail.version = 1;
1045 file_avail.IsDataAvail = Is_Data_Avail;
1046
1047 FX_DOWNLOADHINTS hints;
1048 memset(&hints, '\0', sizeof(hints));
1049 hints.version = 1;
1050 hints.AddSegment = Add_Segment;
1051
Jun Fangdf7f3662015-11-10 18:29:18 +08001052 int nRet = PDF_DATA_NOTAVAIL;
Jun Fangb553bcb2015-11-10 18:49:04 +08001053 bool bIsLinearized = false;
Tom Sepez1d17a042017-03-16 13:22:47 -07001054 std::unique_ptr<void, FPDFDocumentDeleter> doc;
1055 std::unique_ptr<void, FPDFAvailDeleter> pdf_avail(
1056 FPDFAvail_Create(&file_avail, &file_access));
Tom Sepezc98895c2015-11-24 15:30:36 -08001057
Tom Sepez1d17a042017-03-16 13:22:47 -07001058 if (FPDFAvail_IsLinearized(pdf_avail.get()) == PDF_LINEARIZED) {
1059 doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), nullptr));
Jun Fangdf7f3662015-11-10 18:29:18 +08001060 if (doc) {
thestig514e8c92016-07-15 17:57:54 -07001061 while (nRet == PDF_DATA_NOTAVAIL)
Tom Sepez1d17a042017-03-16 13:22:47 -07001062 nRet = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints);
thestig514e8c92016-07-15 17:57:54 -07001063
Jun Fangdf7f3662015-11-10 18:29:18 +08001064 if (nRet == PDF_DATA_ERROR) {
1065 fprintf(stderr, "Unknown error in checking if doc was available.\n");
1066 return;
1067 }
Tom Sepez1d17a042017-03-16 13:22:47 -07001068 nRet = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints);
Jun Fangdf7f3662015-11-10 18:29:18 +08001069 if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) {
1070 fprintf(stderr,
1071 "Error %d was returned in checking if form was available.\n",
1072 nRet);
1073 return;
1074 }
Jun Fangb553bcb2015-11-10 18:49:04 +08001075 bIsLinearized = true;
Jun Fangdf7f3662015-11-10 18:29:18 +08001076 }
1077 } else {
Tom Sepez1d17a042017-03-16 13:22:47 -07001078 doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr));
Jun Fangdf7f3662015-11-10 18:29:18 +08001079 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001080
Lei Zhang5377ebf2015-09-23 14:52:53 -07001081 if (!doc) {
Dan Sinclaireb815bf2015-10-27 13:08:41 -04001082 unsigned long err = FPDF_GetLastError();
1083 fprintf(stderr, "Load pdf docs unsuccessful: ");
1084 switch (err) {
1085 case FPDF_ERR_SUCCESS:
1086 fprintf(stderr, "Success");
1087 break;
1088 case FPDF_ERR_UNKNOWN:
1089 fprintf(stderr, "Unknown error");
1090 break;
1091 case FPDF_ERR_FILE:
1092 fprintf(stderr, "File not found or could not be opened");
1093 break;
1094 case FPDF_ERR_FORMAT:
1095 fprintf(stderr, "File not in PDF format or corrupted");
1096 break;
1097 case FPDF_ERR_PASSWORD:
1098 fprintf(stderr, "Password required or incorrect password");
1099 break;
1100 case FPDF_ERR_SECURITY:
1101 fprintf(stderr, "Unsupported security scheme");
1102 break;
1103 case FPDF_ERR_PAGE:
1104 fprintf(stderr, "Page not found or content error");
1105 break;
1106 default:
1107 fprintf(stderr, "Unknown error %ld", err);
1108 }
1109 fprintf(stderr, ".\n");
JUN FANG827a1722015-03-05 13:39:21 -08001110 return;
1111 }
1112
Tom Sepez1d17a042017-03-16 13:22:47 -07001113 (void)FPDF_GetDocPermissions(doc.get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001114
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -04001115 if (options.show_metadata) {
1116 const char* metaTags[] = {"Title", "Author", "Subject", "Keywords",
1117 "Creator", "Producer", "CreationDate", "ModDate"};
1118 for (const char* metaTag : metaTags) {
1119 char metaBuffer[4096];
1120 int len = FPDF_GetMetaText(doc.get(), metaTag, metaBuffer, 4096);
1121 printf("%-12s = %ls (%d bytes)\n", metaTag,
1122 GetPlatformWString(reinterpret_cast<unsigned short*>(metaBuffer))
1123 .c_str(),
1124 len);
1125 }
1126 }
1127
Tom Sepez1d17a042017-03-16 13:22:47 -07001128 std::unique_ptr<void, FPDFFormHandleDeleter> form(
1129 FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
1130 form_callbacks.form_handle = form.get();
tonikitoo81d92f82016-09-21 12:44:56 -07001131
Tom Sepezc46d0002015-11-30 15:46:36 -08001132#ifdef PDF_ENABLE_XFA
thestigb97e07e2016-09-28 22:16:40 -07001133 int doc_type = DOCTYPE_PDF;
Tom Sepez1d17a042017-03-16 13:22:47 -07001134 if (FPDF_HasXFAField(doc.get(), &doc_type) && doc_type != DOCTYPE_PDF &&
1135 !FPDF_LoadXFA(doc.get())) {
Lei Zhang5377ebf2015-09-23 14:52:53 -07001136 fprintf(stderr, "LoadXFA unsuccessful, continuing anyway.\n");
Tom Sepez56451382014-12-05 13:30:51 -08001137 }
Tom Sepezc46d0002015-11-30 15:46:36 -08001138#endif // PDF_ENABLE_XFA
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001139
Tom Sepez1d17a042017-03-16 13:22:47 -07001140 FPDF_SetFormFieldHighlightColor(form.get(), 0, 0xFFE4DD);
1141 FPDF_SetFormFieldHighlightAlpha(form.get(), 100);
1142 FORM_DoDocumentJSAction(form.get());
1143 FORM_DoDocumentOpenAction(form.get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001144
Lei Zhangd1c9b452017-05-05 17:21:36 -07001145#if _WIN32
1146 if (options.output_format == OUTPUT_PS2)
1147 FPDF_SetPrintPostscriptLevel(2);
1148 else if (options.output_format == OUTPUT_PS3)
1149 FPDF_SetPrintPostscriptLevel(3);
1150#endif
1151
Tom Sepez1d17a042017-03-16 13:22:47 -07001152 int page_count = FPDF_GetPageCount(doc.get());
Tom Sepez1ed8a212015-05-11 15:25:39 -07001153 int rendered_pages = 0;
1154 int bad_pages = 0;
npmfa20cd52016-11-14 13:33:40 -08001155 int first_page = options.pages ? options.first_page : 0;
1156 int last_page = options.pages ? options.last_page + 1 : page_count;
1157 for (int i = first_page; i < last_page; ++i) {
Jun Fangdf7f3662015-11-10 18:29:18 +08001158 if (bIsLinearized) {
1159 nRet = PDF_DATA_NOTAVAIL;
thestig514e8c92016-07-15 17:57:54 -07001160 while (nRet == PDF_DATA_NOTAVAIL)
Tom Sepez1d17a042017-03-16 13:22:47 -07001161 nRet = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints);
thestig514e8c92016-07-15 17:57:54 -07001162
Jun Fangdf7f3662015-11-10 18:29:18 +08001163 if (nRet == PDF_DATA_ERROR) {
1164 fprintf(stderr, "Unknown error in checking if page %d is available.\n",
1165 i);
1166 return;
1167 }
1168 }
Tom Sepez1d17a042017-03-16 13:22:47 -07001169 if (RenderPage(name, doc.get(), form.get(), form_callbacks, i, options,
1170 events))
Jun Fangdf7f3662015-11-10 18:29:18 +08001171 ++rendered_pages;
thestig514e8c92016-07-15 17:57:54 -07001172 else
Lei Zhang5377ebf2015-09-23 14:52:53 -07001173 ++bad_pages;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001174 }
1175
Tom Sepez1d17a042017-03-16 13:22:47 -07001176 FORM_DoDocumentAAction(form.get(), FPDFDOC_AACTION_WC);
Tom Sepez1ed8a212015-05-11 15:25:39 -07001177 fprintf(stderr, "Rendered %d pages.\n", rendered_pages);
tsepez10b01bf2016-05-04 12:52:42 -07001178 if (bad_pages)
1179 fprintf(stderr, "Skipped %d bad pages.\n", bad_pages);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001180}
1181
Tom Sepez2991d8d2016-01-15 16:02:48 -08001182static void ShowConfig() {
1183 std::string config;
1184 std::string maybe_comma;
1185#if PDF_ENABLE_V8
1186 config.append(maybe_comma);
1187 config.append("V8");
1188 maybe_comma = ",";
1189#endif // PDF_ENABLE_V8
1190#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1191 config.append(maybe_comma);
1192 config.append("V8_EXTERNAL");
1193 maybe_comma = ",";
1194#endif // V8_USE_EXTERNAL_STARTUP_DATA
1195#ifdef PDF_ENABLE_XFA
1196 config.append(maybe_comma);
1197 config.append("XFA");
1198 maybe_comma = ",";
1199#endif // PDF_ENABLE_XFA
dan sinclair00d40642017-01-30 19:48:54 -08001200#ifdef PDF_ENABLE_ASAN
1201 config.append(maybe_comma);
1202 config.append("ASAN");
1203 maybe_comma = ",";
1204#endif // PDF_ENABLE_ASAN
Tom Sepez2991d8d2016-01-15 16:02:48 -08001205 printf("%s\n", config.c_str());
1206}
1207
thestig514e8c92016-07-15 17:57:54 -07001208static const char kUsageString[] =
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001209 "Usage: pdfium_test [OPTION] [FILE]...\n"
Tom Sepez2991d8d2016-01-15 16:02:48 -08001210 " --show-config - print build options and exit\n"
Dan Sinclairddcb6e72017-04-05 10:30:33 -04001211 " --show-structure - print the structure elements from the document\n"
tsepez10b01bf2016-05-04 12:52:42 -07001212 " --send-events - send input described by .evt file\n"
Lei Zhang6f62d532015-09-23 15:31:44 -07001213 " --bin-dir=<path> - override path to v8 external data\n"
1214 " --font-dir=<path> - override path to external fonts\n"
1215 " --scale=<number> - scale output size by number (e.g. 0.5)\n"
npmfa20cd52016-11-14 13:33:40 -08001216 " --pages=<number>(-<number>) - only render the given 0-based page(s)\n"
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001217#ifdef _WIN32
1218 " --bmp - write page images <pdf-name>.<page-number>.bmp\n"
1219 " --emf - write page meta files <pdf-name>.<page-number>.emf\n"
Lei Zhangd1c9b452017-05-05 17:21:36 -07001220 " --ps2 - write page raw PostScript (Lvl 2) <pdf-name>.<page-number>.ps\n"
1221 " --ps3 - write page raw PostScript (Lvl 3) <pdf-name>.<page-number>.ps\n"
Tom Sepezc46d0002015-11-30 15:46:36 -08001222#endif // _WIN32
thestig514e8c92016-07-15 17:57:54 -07001223 " --txt - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n"
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001224 " --png - write page images <pdf-name>.<page-number>.png\n"
thestig514e8c92016-07-15 17:57:54 -07001225 " --ppm - write page images <pdf-name>.<page-number>.ppm\n"
Cary Clark399be5b2016-03-14 16:51:29 -04001226#ifdef PDF_ENABLE_SKIA
1227 " --skp - write page images <pdf-name>.<page-number>.skp\n"
1228#endif
stephanafa05e972017-01-02 06:19:41 -08001229 " --md5 - write output image paths and their md5 hashes to stdout.\n"
Cary Clark399be5b2016-03-14 16:51:29 -04001230 "";
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001231
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001232int main(int argc, const char* argv[]) {
Tom Sepez5ee12d72014-12-17 16:24:01 -08001233 std::vector<std::string> args(argv, argv + argc);
1234 Options options;
thestig514e8c92016-07-15 17:57:54 -07001235 std::vector<std::string> files;
Tom Sepez5ee12d72014-12-17 16:24:01 -08001236 if (!ParseCommandLine(args, &options, &files)) {
thestig514e8c92016-07-15 17:57:54 -07001237 fprintf(stderr, "%s", kUsageString);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001238 return 1;
1239 }
1240
Tom Sepez2991d8d2016-01-15 16:02:48 -08001241 if (options.show_config) {
1242 ShowConfig();
1243 return 0;
1244 }
1245
1246 if (files.empty()) {
1247 fprintf(stderr, "No input files.\n");
1248 return 1;
1249 }
1250
Tom Sepez452b4f32015-10-13 09:27:27 -07001251#ifdef PDF_ENABLE_V8
Tom Sepezd831dc72015-10-19 16:04:22 -07001252 v8::Platform* platform;
Tom Sepez5ee12d72014-12-17 16:24:01 -08001253#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1254 v8::StartupData natives;
1255 v8::StartupData snapshot;
Tom Sepezd831dc72015-10-19 16:04:22 -07001256 InitializeV8ForPDFium(options.exe_path, options.bin_directory, &natives,
1257 &snapshot, &platform);
1258#else // V8_USE_EXTERNAL_STARTUP_DATA
jochen9e077d22016-06-09 02:51:13 -07001259 InitializeV8ForPDFium(options.exe_path, &platform);
Tom Sepez5ee12d72014-12-17 16:24:01 -08001260#endif // V8_USE_EXTERNAL_STARTUP_DATA
Tom Sepez452b4f32015-10-13 09:27:27 -07001261#endif // PDF_ENABLE_V8
Tom Sepez5ee12d72014-12-17 16:24:01 -08001262
Tom Sepeza72e8e22015-10-07 10:17:53 -07001263 FPDF_LIBRARY_CONFIG config;
1264 config.version = 2;
1265 config.m_pUserFontPaths = nullptr;
1266 config.m_pIsolate = nullptr;
1267 config.m_v8EmbedderSlot = 0;
1268
1269 const char* path_array[2];
1270 if (!options.font_directory.empty()) {
Lei Zhang6f62d532015-09-23 15:31:44 -07001271 path_array[0] = options.font_directory.c_str();
1272 path_array[1] = nullptr;
Lei Zhang6f62d532015-09-23 15:31:44 -07001273 config.m_pUserFontPaths = path_array;
Lei Zhang6f62d532015-09-23 15:31:44 -07001274 }
Tom Sepeza72e8e22015-10-07 10:17:53 -07001275 FPDF_InitLibraryWithConfig(&config);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001276
npmfa20cd52016-11-14 13:33:40 -08001277 UNSUPPORT_INFO unsupported_info;
1278 memset(&unsupported_info, '\0', sizeof(unsupported_info));
1279 unsupported_info.version = 1;
1280 unsupported_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001281
npmfa20cd52016-11-14 13:33:40 -08001282 FSDK_SetUnSpObjProcessHandler(&unsupported_info);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001283
thestig514e8c92016-07-15 17:57:54 -07001284 for (const std::string& filename : files) {
Tom Sepez5ee12d72014-12-17 16:24:01 -08001285 size_t file_length = 0;
Tom Sepez0aa35312016-01-06 10:16:32 -08001286 std::unique_ptr<char, pdfium::FreeDeleter> file_contents =
1287 GetFileContents(filename.c_str(), &file_length);
tsepezf09bdfa2016-04-18 16:08:26 -07001288 if (!file_contents)
1289 continue;
tsepez10b01bf2016-05-04 12:52:42 -07001290 fprintf(stderr, "Rendering PDF file %s.\n", filename.c_str());
tsepezf09bdfa2016-04-18 16:08:26 -07001291 std::string events;
1292 if (options.send_events) {
1293 std::string event_filename = filename;
1294 size_t event_length = 0;
1295 size_t extension_pos = event_filename.find(".pdf");
1296 if (extension_pos != std::string::npos) {
1297 event_filename.replace(extension_pos, 4, ".evt");
thestigf2b940c2016-10-13 06:48:47 -07001298 if (access(event_filename.c_str(), R_OK) == 0) {
1299 fprintf(stderr, "Using event file %s.\n", event_filename.c_str());
1300 std::unique_ptr<char, pdfium::FreeDeleter> event_contents =
1301 GetFileContents(event_filename.c_str(), &event_length);
1302 if (event_contents) {
1303 fprintf(stderr, "Sending events from: %s\n",
1304 event_filename.c_str());
1305 events = std::string(event_contents.get(), event_length);
1306 }
tsepezf09bdfa2016-04-18 16:08:26 -07001307 }
1308 }
1309 }
1310 RenderPdf(filename, file_contents.get(), file_length, options, events);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001311 }
1312
1313 FPDF_DestroyLibrary();
Tom Sepez452b4f32015-10-13 09:27:27 -07001314#ifdef PDF_ENABLE_V8
John Abd-El-Malekb045ed22015-02-10 09:15:12 -08001315 v8::V8::ShutdownPlatform();
1316 delete platform;
thestigc08cd7a2016-06-27 09:47:59 -07001317
1318#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1319 free(const_cast<char*>(natives.data));
1320 free(const_cast<char*>(snapshot.data));
1321#endif // V8_USE_EXTERNAL_STARTUP_DATA
Tom Sepez452b4f32015-10-13 09:27:27 -07001322#endif // PDF_ENABLE_V8
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001323
1324 return 0;
1325}