1e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Use of this source code is governed by a BSD-style license that can be
3e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// found in the LICENSE file.
4e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
5e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <limits.h>
6e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <stdio.h>
7e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <stdlib.h>
8e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <string.h>
9e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
10d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <bitset>
11d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <iterator>
124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include <map>
13d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <memory>
14e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <sstream>
15e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <string>
16e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <utility>
17e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <vector>
18e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#if defined PDF_ENABLE_SKIA && !defined _SKIA_SUPPORT_
204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#define _SKIA_SUPPORT_
214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
23d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "public/cpp/fpdf_deleters.h"
24d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "public/fpdf_annot.h"
25d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "public/fpdf_attachment.h"
26ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "public/fpdf_dataavail.h"
27ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "public/fpdf_edit.h"
28ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "public/fpdf_ext.h"
29ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "public/fpdf_formfill.h"
30d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "public/fpdf_progressive.h"
31d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "public/fpdf_structtree.h"
32ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "public/fpdf_text.h"
33ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "public/fpdfview.h"
34d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "testing/image_diff/image_diff_png.h"
35ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#include "testing/test_support.h"
36d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/base/logging.h"
37ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef _WIN32
394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include <io.h>
404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#else
414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include <unistd.h>
424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
44d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
45d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <valgrind/callgrind.h>
46d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
47d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
48ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#ifdef PDF_ENABLE_V8
49e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "v8/include/libplatform/libplatform.h"
50e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "v8/include/v8.h"
51ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // PDF_ENABLE_V8
52e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_SKIA
544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "third_party/skia/include/core/SkPictureRecorder.h"
554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "third_party/skia/include/core/SkStream.h"
564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
58e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef _WIN32
594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#define access _access
60e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#define snprintf _snprintf
614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#define R_OK 4
62e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#endif
63e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
64e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovenum OutputFormat {
65e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  OUTPUT_NONE,
66d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  OUTPUT_STRUCTURE,
674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  OUTPUT_TEXT,
68e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  OUTPUT_PPM,
69e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  OUTPUT_PNG,
70d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  OUTPUT_ANNOT,
71e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef _WIN32
72e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  OUTPUT_BMP,
73e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  OUTPUT_EMF,
74d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  OUTPUT_PS2,
75d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  OUTPUT_PS3,
76e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#endif
774d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_SKIA
784d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  OUTPUT_SKP,
794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
80e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov};
81e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
82d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannnamespace {
83d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
84e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstruct Options {
854d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  Options()
864d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      : show_config(false),
87d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        show_metadata(false),
884d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        send_events(false),
89d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        render_oneshot(false),
90d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        save_attachments(false),
91d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        save_images(false),
92d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
93d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        callgrind_delimiters(false),
94d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        pages(false),
964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        md5(false),
97d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        output_format(OUTPUT_NONE) {
98d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  bool show_config;
101d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bool show_metadata;
1024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  bool send_events;
103d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bool render_oneshot;
104d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bool save_attachments;
105d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bool save_images;
106d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
107d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bool callgrind_delimiters;
108d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
1094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  bool pages;
1104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  bool md5;
111e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  OutputFormat output_format;
112e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  std::string scale_factor_as_string;
113e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  std::string exe_path;
114e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  std::string bin_directory;
115ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  std::string font_directory;
1164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // 0-based page numbers to be rendered.
1174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int first_page;
1184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int last_page;
119e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov};
120e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannstruct FPDF_FORMFILLINFO_PDFiumTest : public FPDF_FORMFILLINFO {
1224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // Hold a map of the currently loaded pages in order to avoid them
1234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // to get loaded twice.
124d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::map<int, std::unique_ptr<void, FPDFPageDeleter>> loaded_pages;
1254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // Hold a pointer of FPDF_FORMHANDLE so that PDFium app hooks can
1274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // make use of it.
1284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FPDF_FORMHANDLE form_handle;
1294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann};
1304d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
131d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannFPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(
1324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    FPDF_FORMFILLINFO* form_fill_info) {
1334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return static_cast<FPDF_FORMFILLINFO_PDFiumTest*>(form_fill_info);
1344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
1354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
136d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannbool CheckDimensions(int stride, int width, int height) {
137e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (stride < 0 || width < 0 || height < 0)
138e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return false;
139e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (height > 0 && width > INT_MAX / height)
140e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return false;
141e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  return true;
142e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
143e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
144d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid OutputMD5Hash(const char* file_name, const char* buffer, int len) {
1454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // Get the MD5 hash and write it to stdout.
146d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::string hash =
147d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      GenerateMD5Base16(reinterpret_cast<const uint8_t*>(buffer), len);
148d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  printf("MD5:%s:%s\n", file_name, hash.c_str());
1494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
1504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
151d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::string WritePpm(const char* pdf_name,
152d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int num,
153d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     const void* buffer_void,
154d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int stride,
155d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int width,
156d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int height) {
157d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  const auto* buffer = reinterpret_cast<const char*>(buffer_void);
158e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
159e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (!CheckDimensions(stride, width, height))
1604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
161e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
162e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  int out_len = width * height;
163e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (out_len > INT_MAX / 3)
1644d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
165e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  out_len *= 3;
166e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
167e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  char filename[256];
168e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num);
169e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  FILE* fp = fopen(filename, "wb");
170e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (!fp)
1714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
172e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
173e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  // Source data is B, G, R, unused.
174e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  // Dest data is R, G, B.
1754d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  std::vector<char> result(out_len);
176ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  for (int h = 0; h < height; ++h) {
177ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    const char* src_line = buffer + (stride * h);
1784d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    char* dest_line = result.data() + (width * h * 3);
179ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    for (int w = 0; w < width; ++w) {
180ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      // R
181ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      dest_line[w * 3] = src_line[(w * 4) + 2];
182ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      // G
183ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
184ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      // B
185ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      dest_line[(w * 3) + 2] = src_line[w * 4];
186e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
187e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
188d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (fwrite(result.data(), out_len, 1, fp) != 1)
189d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Failed to write to %s\n", filename);
190e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  fclose(fp);
1914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return std::string(filename);
192e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
193e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannvoid WriteText(FPDF_PAGE page, const char* pdf_name, int num) {
1954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  char filename[256];
1964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int chars_formatted =
1974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      snprintf(filename, sizeof(filename), "%s.%d.txt", pdf_name, num);
1984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (chars_formatted < 0 ||
1994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
2004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Filename %s is too long\n", filename);
201e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return;
2024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
2034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
2044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FILE* fp = fopen(filename, "w");
2054d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!fp) {
2064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Failed to open %s for output\n", filename);
2074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return;
2084d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
2094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
2104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // Output in UTF32-LE.
2114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  uint32_t bom = 0x0000FEFF;
212d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (fwrite(&bom, sizeof(bom), 1, fp) != 1) {
213d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Failed to write to %s\n", filename);
214d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    (void)fclose(fp);
215d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return;
216d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
2174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
218d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFTextPageDeleter> textpage(FPDFText_LoadPage(page));
219d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < FPDFText_CountChars(textpage.get()); i++) {
220d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    uint32_t c = FPDFText_GetUnicode(textpage.get(), i);
221d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (fwrite(&c, sizeof(c), 1, fp) != 1) {
222d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to write to %s\n", filename);
223d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
224d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
2254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
226d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  (void)fclose(fp);
227d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
2284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
229d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannconst char* AnnotSubtypeToCString(FPDF_ANNOTATION_SUBTYPE subtype) {
230d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_TEXT)
231d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Text";
232d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_LINK)
233d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Link";
234d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_FREETEXT)
235d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "FreeText";
236d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_LINE)
237d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Line";
238d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_SQUARE)
239d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Square";
240d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_CIRCLE)
241d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Circle";
242d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_POLYGON)
243d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Polygon";
244d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_POLYLINE)
245d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "PolyLine";
246d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_HIGHLIGHT)
247d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Highlight";
248d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_UNDERLINE)
249d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Underline";
250d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_SQUIGGLY)
251d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Squiggly";
252d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_STRIKEOUT)
253d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "StrikeOut";
254d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_STAMP)
255d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Stamp";
256d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_CARET)
257d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Caret";
258d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_INK)
259d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Ink";
260d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_POPUP)
261d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Popup";
262d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_FILEATTACHMENT)
263d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "FileAttachment";
264d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_SOUND)
265d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Sound";
266d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_MOVIE)
267d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Movie";
268d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_WIDGET)
269d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Widget";
270d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_SCREEN)
271d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Screen";
272d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_PRINTERMARK)
273d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "PrinterMark";
274d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_TRAPNET)
275d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "TrapNet";
276d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_WATERMARK)
277d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Watermark";
278d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_THREED)
279d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "3D";
280d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_RICHMEDIA)
281d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "RichMedia";
282d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (subtype == FPDF_ANNOT_XFAWIDGET)
283d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "XFAWidget";
284d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  NOTREACHED();
285d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return "";
286d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
287d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
288d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid AppendFlagString(const char* flag, std::string* output) {
289d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!output->empty())
290d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    *output += ", ";
291d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  *output += flag;
292d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
293d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
294d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::string AnnotFlagsToString(int flags) {
295d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::string str;
296d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_INVISIBLE)
297d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("Invisible", &str);
298d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_HIDDEN)
299d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("Hidden", &str);
300d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_PRINT)
301d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("Print", &str);
302d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_NOZOOM)
303d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("NoZoom", &str);
304d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_NOROTATE)
305d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("NoRotate", &str);
306d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_NOVIEW)
307d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("NoView", &str);
308d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_READONLY)
309d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("ReadOnly", &str);
310d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_LOCKED)
311d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("Locked", &str);
312d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (flags & FPDF_ANNOT_FLAG_TOGGLENOVIEW)
313d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    AppendFlagString("ToggleNoView", &str);
314d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return str;
315d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
316d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
317d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannconst char* PageObjectTypeToCString(int type) {
318d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (type == FPDF_PAGEOBJ_TEXT)
319d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Text";
320d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (type == FPDF_PAGEOBJ_PATH)
321d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Path";
322d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (type == FPDF_PAGEOBJ_IMAGE)
323d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Image";
324d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (type == FPDF_PAGEOBJ_SHADING)
325d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Shading";
326d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (type == FPDF_PAGEOBJ_FORM)
327d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return "Form";
328d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  NOTREACHED();
329d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return "";
330d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
331d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
332d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid WriteAnnot(FPDF_PAGE page, const char* pdf_name, int num) {
333d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // Open the output text file.
334d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  char filename[256];
335d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int chars_formatted =
336d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      snprintf(filename, sizeof(filename), "%s.%d.annot.txt", pdf_name, num);
337d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (chars_formatted < 0 ||
338d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
339d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Filename %s is too long\n", filename);
340d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return;
341d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
342d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FILE* fp = fopen(filename, "w");
343d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!fp) {
344d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Failed to open %s for output\n", filename);
345d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return;
346d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
347d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
348d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int annot_count = FPDFPage_GetAnnotCount(page);
349d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  fprintf(fp, "Number of annotations: %d\n\n", annot_count);
350d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
351d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // Iterate through all annotations on this page.
352d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < annot_count; ++i) {
353d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation object and its subtype.
354d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(fp, "Annotation #%d:\n", i + 1);
355d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, i);
356d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!annot) {
357d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Failed to retrieve annotation!\n\n");
358d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
359d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
360d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
361d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(fp, "Subtype: %s\n", AnnotSubtypeToCString(subtype));
362d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
363d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation flags.
364d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(fp, "Flags set: %s\n",
365d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            AnnotFlagsToString(FPDFAnnot_GetFlags(annot)).c_str());
366d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
367d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation's object count and object types.
368d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const int obj_count = FPDFAnnot_GetObjectCount(annot);
369d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(fp, "Number of objects: %d\n", obj_count);
370d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (obj_count > 0) {
371d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Object types: ");
372d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      for (int j = 0; j < obj_count; ++j) {
373d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        const char* type = PageObjectTypeToCString(
374d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            FPDFPageObj_GetType(FPDFAnnot_GetObject(annot, j)));
375d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(fp, "%s  ", type);
376d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
377d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "\n");
378d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
379d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
380d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation's color and interior color.
381d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned int R;
382d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned int G;
383d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned int B;
384d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned int A;
385d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A)) {
386d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Failed to retrieve color.\n");
387d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
388d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Color in RGBA: %d %d %d %d\n", R, G, B, A);
389d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
390d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_InteriorColor, &R, &G,
391d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                            &B, &A)) {
392d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Failed to retrieve interior color.\n");
393d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
394d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Interior color in RGBA: %d %d %d %d\n", R, G, B, A);
395d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
396d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
397d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation's contents and author.
398d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    static constexpr char kContentsKey[] = "Contents";
399d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    static constexpr char kAuthorKey[] = "T";
400d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned long len =
401d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        FPDFAnnot_GetStringValue(annot, kContentsKey, nullptr, 0);
402d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    std::vector<char> buf(len);
403d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDFAnnot_GetStringValue(annot, kContentsKey, buf.data(), len);
404d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(fp, "Content: %ls\n",
405d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
406d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                .c_str());
407d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    len = FPDFAnnot_GetStringValue(annot, kAuthorKey, nullptr, 0);
408d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    buf.clear();
409d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    buf.resize(len);
410d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDFAnnot_GetStringValue(annot, kAuthorKey, buf.data(), len);
411d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(fp, "Author: %ls\n",
412d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
413d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                .c_str());
414d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
415d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation's quadpoints if it is a markup annotation.
416d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (FPDFAnnot_HasAttachmentPoints(annot)) {
417d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      FS_QUADPOINTSF quadpoints;
418d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (FPDFAnnot_GetAttachmentPoints(annot, &quadpoints)) {
419d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(fp,
420d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                "Quadpoints: (%.3f, %.3f), (%.3f, %.3f), (%.3f, %.3f), (%.3f, "
421d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                "%.3f)\n",
422d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                quadpoints.x1, quadpoints.y1, quadpoints.x2, quadpoints.y2,
423d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                quadpoints.x3, quadpoints.y3, quadpoints.x4, quadpoints.y4);
424d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      } else {
425d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(fp, "Failed to retrieve quadpoints.\n");
426d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
427d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
428d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
429d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the annotation's rectangle coordinates.
430d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FS_RECTF rect;
431d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (FPDFAnnot_GetRect(annot, &rect)) {
432d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Rectangle: l - %.3f, b - %.3f, r - %.3f, t - %.3f\n\n",
433d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              rect.left, rect.bottom, rect.right, rect.top);
434d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
435d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(fp, "Failed to retrieve annotation rectangle.\n");
436d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
437d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
438d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDFPage_CloseAnnot(annot);
439d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
4404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
4414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  (void)fclose(fp);
4424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
4434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
444d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::string WritePng(const char* pdf_name,
445d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int num,
446d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     const void* buffer_void,
447d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int stride,
448d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int width,
449d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int height) {
4504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!CheckDimensions(stride, width, height))
4514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
452e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
453e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  std::vector<unsigned char> png_encoding;
454d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  const auto* buffer = static_cast<const unsigned char*>(buffer_void);
455e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (!image_diff_png::EncodeBGRAPNG(
456e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          buffer, width, height, stride, false, &png_encoding)) {
457e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    fprintf(stderr, "Failed to convert bitmap to PNG\n");
4584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
459e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
460e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
461e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  char filename[256];
462e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  int chars_formatted = snprintf(
463e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      filename, sizeof(filename), "%s.%d.png", pdf_name, num);
464e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (chars_formatted < 0 ||
465e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
4664d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Filename %s is too long\n", filename);
4674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
468e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
469e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
470e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  FILE* fp = fopen(filename, "wb");
471e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (!fp) {
472e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    fprintf(stderr, "Failed to open %s for output\n", filename);
4734d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
474e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
475e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
476e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  size_t bytes_written = fwrite(
477e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      &png_encoding.front(), 1, png_encoding.size(), fp);
478e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (bytes_written != png_encoding.size())
479d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Failed to write to %s\n", filename);
480e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
481ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  (void)fclose(fp);
4824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return std::string(filename);
483e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
484e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
485e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef _WIN32
486d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::string WriteBmp(const char* pdf_name,
487d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int num,
488d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     const void* buffer,
489d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int stride,
490d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int width,
491d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int height) {
492ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  if (!CheckDimensions(stride, width, height))
4934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
494ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
495e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  int out_len = stride * height;
496e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (out_len > INT_MAX / 3)
4974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
498e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
499e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  char filename[256];
500e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  snprintf(filename, sizeof(filename), "%s.%d.bmp", pdf_name, num);
501e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  FILE* fp = fopen(filename, "wb");
502e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (!fp)
5034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
504e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
505ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  BITMAPINFO bmi = {};
506e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
507e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biWidth = width;
508e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biHeight = -height;  // top-down image
509e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biPlanes = 1;
510e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biBitCount = 32;
511e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biCompression = BI_RGB;
512e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  bmi.bmiHeader.biSizeImage = 0;
513e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
514ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  BITMAPFILEHEADER file_header = {};
515e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_header.bfType = 0x4d42;
516e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
517e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_header.bfOffBits = file_header.bfSize - out_len;
518e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
519d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (fwrite(&file_header, sizeof(file_header), 1, fp) != 1 ||
520d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp) != 1 ||
521d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fwrite(buffer, out_len, 1, fp) != 1) {
522d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Failed to write to %s\n", filename);
523d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
524e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  fclose(fp);
5254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return std::string(filename);
526e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
527e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
528e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
529e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  char filename[256];
530e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
531e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
532ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  HDC dc = CreateEnhMetaFileA(nullptr, filename, nullptr, nullptr);
533e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
534d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int width = static_cast<int>(FPDF_GetPageWidth(page));
535d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int height = static_cast<int>(FPDF_GetPageHeight(page));
536e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  HRGN rgn = CreateRectRgn(0, 0, width, height);
537e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  SelectClipRgn(dc, rgn);
538e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  DeleteObject(rgn);
539e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
540e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  SelectObject(dc, GetStockObject(NULL_PEN));
541e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  SelectObject(dc, GetStockObject(WHITE_BRUSH));
542e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
543e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  Rectangle(dc, 0, 0, width + 1, height + 1);
544e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
545e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
546e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                  FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
547e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
548e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  DeleteEnhMetaFile(CloseEnhMetaFile(dc));
549e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
550d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
551d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannint CALLBACK EnhMetaFileProc(HDC hdc,
552d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                             HANDLETABLE* handle_table,
553d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                             const ENHMETARECORD* record,
554d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                             int objects_count,
555d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                             LPARAM param) {
556d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::vector<const ENHMETARECORD*>& items =
557d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      *reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
558d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  items.push_back(record);
559d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return 1;
560d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
561d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
562d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid WritePS(FPDF_PAGE page, const char* pdf_name, int num) {
563d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  char filename[256];
564d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  snprintf(filename, sizeof(filename), "%s.%d.ps", pdf_name, num);
565d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FILE* fp = fopen(filename, "wb");
566d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!fp)
567d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return;
568d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
569d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
570d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
571d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int width = static_cast<int>(FPDF_GetPageWidth(page));
572d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int height = static_cast<int>(FPDF_GetPageHeight(page));
573d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
574d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                  FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
575d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
576d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  HENHMETAFILE emf = CloseEnhMetaFile(dc);
577d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::vector<const ENHMETARECORD*> items;
578d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  EnumEnhMetaFile(nullptr, emf, &EnhMetaFileProc, &items, nullptr);
579d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (const ENHMETARECORD* record : items) {
580d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (record->iType != EMR_GDICOMMENT)
581d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
582d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
583d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
584d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const char* data = reinterpret_cast<const char*>(comment->Data);
585d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    uint16_t size = *reinterpret_cast<const uint16_t*>(data);
586d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (fwrite(data + sizeof(uint16_t), size, 1, fp) != 1) {
587d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to write to %s\n", filename);
588d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
589d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
590d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
591d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  fclose(fp);
592d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  DeleteEnhMetaFile(emf);
593d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
594d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // _WIN32
595e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
5964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_SKIA
597d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::string WriteSkp(const char* pdf_name,
598d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     int num,
599d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                     SkPictureRecorder* recorder) {
6004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  char filename[256];
6014d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int chars_formatted =
6024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      snprintf(filename, sizeof(filename), "%s.%d.skp", pdf_name, num);
6034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
6044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (chars_formatted < 0 ||
6054d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
6064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Filename %s is too long\n", filename);
6074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return "";
6084d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
6094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
6104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  sk_sp<SkPicture> picture(recorder->finishRecordingAsPicture());
6114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  SkFILEWStream wStream(filename);
6124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  picture->serialize(&wStream);
6134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return std::string(filename);
6144d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
6154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
6164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
6174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// These example JS platform callback handlers are entirely optional,
6184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// and exist here to show the flow of information from a document back
6194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// to the embedder.
6204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannint ExampleAppAlert(IPDF_JSPLATFORM*,
6214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING msg,
6224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING title,
6234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    int type,
6244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    int icon) {
6254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  printf("%ls", GetPlatformWString(title).c_str());
6264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (icon || type)
6274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    printf("[icon=%d,type=%d]", icon, type);
6284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  printf(": %ls\n", GetPlatformWString(msg).c_str());
629e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  return 0;
630e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
631e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
6324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannint ExampleAppResponse(IPDF_JSPLATFORM*,
6334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       FPDF_WIDESTRING question,
6344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       FPDF_WIDESTRING title,
6354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       FPDF_WIDESTRING default_value,
6364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       FPDF_WIDESTRING label,
6374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       FPDF_BOOL is_password,
6384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       void* response,
6394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       int length) {
6404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  printf("%ls: %ls, defaultValue=%ls, label=%ls, isPassword=%d, length=%d\n",
6414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(title).c_str(),
6424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(question).c_str(),
6434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(default_value).c_str(),
6444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(label).c_str(), is_password, length);
6454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
6464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  // UTF-16, always LE regardless of platform.
647d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  auto* ptr = static_cast<uint8_t*>(response);
6484d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  ptr[0] = 'N';
6494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  ptr[1] = 0;
6504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  ptr[2] = 'o';
6514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  ptr[3] = 0;
6524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return 4;
6534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
6544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
6554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannvoid ExampleDocGotoPage(IPDF_JSPLATFORM*, int page_number) {
6564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  printf("Goto Page: %d\n", page_number);
6574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
6584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
6594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannvoid ExampleDocMail(IPDF_JSPLATFORM*,
6604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    void* mailData,
6614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    int length,
6624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_BOOL UI,
6634d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING To,
6644d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING Subject,
6654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING CC,
6664d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING BCC,
6674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    FPDF_WIDESTRING Msg) {
6684d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  printf("Mail Msg: %d, to=%ls, cc=%ls, bcc=%ls, subject=%ls, body=%ls\n", UI,
6694d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(To).c_str(), GetPlatformWString(CC).c_str(),
6704d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(BCC).c_str(), GetPlatformWString(Subject).c_str(),
6714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann         GetPlatformWString(Msg).c_str());
672e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
673e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
674e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) {
675e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  std::string feature = "Unknown";
676e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  switch (type) {
677e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_XFAFORM:
678e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "XFA";
679e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
680e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_PORTABLECOLLECTION:
681e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Portfolios_Packages";
682e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
683e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_ATTACHMENT:
684e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_ATTACHMENT:
685e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Attachment";
686e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
687e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_SECURITY:
688e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Rights_Management";
689e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
690e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_SHAREDREVIEW:
691e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Shared_Review";
692e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
693e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
694e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
695e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
696e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Shared_Form";
697e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
698e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_3DANNOT:
699e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "3D";
700e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
701e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_MOVIE:
702e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Movie";
703e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
704e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_SOUND:
705e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Sound";
706e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
707e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
708e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
709e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Screen";
710e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
711e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    case FPDF_UNSP_ANNOT_SIG:
712e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      feature = "Digital_Signature";
713e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
714e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
715e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  printf("Unsupported feature: %s.\n", feature.c_str());
716e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
717e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
718e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovbool ParseCommandLine(const std::vector<std::string>& args,
7194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      Options* options,
7204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      std::vector<std::string>* files) {
7214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (args.empty())
722e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return false;
7234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
724e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  options->exe_path = args[0];
725e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  size_t cur_idx = 1;
726e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  for (; cur_idx < args.size(); ++cur_idx) {
727e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    const std::string& cur_arg = args[cur_idx];
7284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (cur_arg == "--show-config") {
7294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      options->show_config = true;
730d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--show-metadata") {
731d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->show_metadata = true;
7324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--send-events") {
7334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      options->send_events = true;
734d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--render-oneshot") {
735d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->render_oneshot = true;
736d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--save-attachments") {
737d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->save_attachments = true;
738d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--save-images") {
739d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->save_images = true;
740d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
741d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--callgrind-delim") {
742d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->callgrind_delimiters = true;
743d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
7444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--ppm") {
745e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      if (options->output_format != OUTPUT_NONE) {
746e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        fprintf(stderr, "Duplicate or conflicting --ppm argument\n");
747e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return false;
748e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      }
749e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      options->output_format = OUTPUT_PPM;
750e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else if (cur_arg == "--png") {
751e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      if (options->output_format != OUTPUT_NONE) {
752e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        fprintf(stderr, "Duplicate or conflicting --png argument\n");
753e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return false;
754e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      }
755e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      options->output_format = OUTPUT_PNG;
7564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--txt") {
7574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (options->output_format != OUTPUT_NONE) {
7584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "Duplicate or conflicting --txt argument\n");
7594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        return false;
7604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
7614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      options->output_format = OUTPUT_TEXT;
762d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--annot") {
763d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (options->output_format != OUTPUT_NONE) {
764d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(stderr, "Duplicate or conflicting --annot argument\n");
765d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        return false;
766d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
767d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->output_format = OUTPUT_ANNOT;
7684d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_SKIA
7694d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--skp") {
7704d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (options->output_format != OUTPUT_NONE) {
7714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "Duplicate or conflicting --skp argument\n");
7724d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        return false;
7734d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
7744d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      options->output_format = OUTPUT_SKP;
7754d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
776ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    } else if (cur_arg.size() > 11 &&
777ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann               cur_arg.compare(0, 11, "--font-dir=") == 0) {
778ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if (!options->font_directory.empty()) {
779ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        fprintf(stderr, "Duplicate --font-dir argument\n");
780ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return false;
781ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      }
782ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      options->font_directory = cur_arg.substr(11);
783e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef _WIN32
7844d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--emf") {
785e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      if (options->output_format != OUTPUT_NONE) {
786e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        fprintf(stderr, "Duplicate or conflicting --emf argument\n");
787e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return false;
788e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      }
789e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      options->output_format = OUTPUT_EMF;
790d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--ps2") {
791d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (options->output_format != OUTPUT_NONE) {
792d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(stderr, "Duplicate or conflicting --ps2 argument\n");
793d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        return false;
794d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
795d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->output_format = OUTPUT_PS2;
796d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--ps3") {
797d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (options->output_format != OUTPUT_NONE) {
798d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(stderr, "Duplicate or conflicting --ps3 argument\n");
799d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        return false;
800d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
801d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->output_format = OUTPUT_PS3;
8024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--bmp") {
803e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      if (options->output_format != OUTPUT_NONE) {
804e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        fprintf(stderr, "Duplicate or conflicting --bmp argument\n");
805e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return false;
806e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      }
807e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      options->output_format = OUTPUT_BMP;
808e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#endif  // _WIN32
8094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
810ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#ifdef PDF_ENABLE_V8
811e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef V8_USE_EXTERNAL_STARTUP_DATA
8124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg.size() > 10 &&
8134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann               cur_arg.compare(0, 10, "--bin-dir=") == 0) {
814e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      if (!options->bin_directory.empty()) {
815e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        fprintf(stderr, "Duplicate --bin-dir argument\n");
816e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return false;
817e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      }
818e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      options->bin_directory = cur_arg.substr(10);
819e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#endif  // V8_USE_EXTERNAL_STARTUP_DATA
820ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // PDF_ENABLE_V8
8214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
8224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg.size() > 8 && cur_arg.compare(0, 8, "--scale=") == 0) {
823e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      if (!options->scale_factor_as_string.empty()) {
824e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        fprintf(stderr, "Duplicate --scale argument\n");
825e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return false;
826e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      }
827e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      options->scale_factor_as_string = cur_arg.substr(8);
828d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (cur_arg == "--show-structure") {
829d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (options->output_format != OUTPUT_NONE) {
830d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(stderr, "Duplicate or conflicting --show-structure argument\n");
831d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        return false;
832d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
833d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      options->output_format = OUTPUT_STRUCTURE;
8344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg.size() > 8 && cur_arg.compare(0, 8, "--pages=") == 0) {
8354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (options->pages) {
8364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "Duplicate --pages argument\n");
8374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        return false;
8384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
8394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      options->pages = true;
8404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      const std::string pages_string = cur_arg.substr(8);
8414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      size_t first_dash = pages_string.find("-");
8424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (first_dash == std::string::npos) {
8434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        std::stringstream(pages_string) >> options->first_page;
8444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        options->last_page = options->first_page;
8454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } else {
8464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        std::stringstream(pages_string.substr(0, first_dash)) >>
8474d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            options->first_page;
8484d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        std::stringstream(pages_string.substr(first_dash + 1)) >>
8494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            options->last_page;
8504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
8514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg == "--md5") {
8524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      options->md5 = true;
8534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') {
8544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str());
8554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      return false;
8564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else {
857e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      break;
8584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
859e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
8604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  for (size_t i = cur_idx; i < args.size(); i++)
861e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    files->push_back(args[i]);
8624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
863e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  return true;
864e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
865e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
866d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid PrintLastError() {
867d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  unsigned long err = FPDF_GetLastError();
868d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  fprintf(stderr, "Load pdf docs unsuccessful: ");
869d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  switch (err) {
870d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_SUCCESS:
871d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Success");
872d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
873d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_UNKNOWN:
874d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Unknown error");
875d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
876d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_FILE:
877d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "File not found or could not be opened");
878d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
879d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_FORMAT:
880d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "File not in PDF format or corrupted");
881d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
882d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_PASSWORD:
883d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Password required or incorrect password");
884d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
885d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_SECURITY:
886d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Unsupported security scheme");
887d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
888d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case FPDF_ERR_PAGE:
889d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Page not found or content error");
890d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      break;
891d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    default:
892d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Unknown error %ld", err);
893d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
894d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  fprintf(stderr, ".\n");
895d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return;
896d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
897d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
8984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. MoltmannFPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size) {
899e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  return true;
900e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
901e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
9024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannvoid Add_Segment(FX_DOWNLOADHINTS* hints, size_t offset, size_t size) {}
9034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
904d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid SendPageEvents(FPDF_FORMHANDLE form,
905d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                    FPDF_PAGE page,
9064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    const std::string& events) {
9074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  auto lines = StringSplit(events, '\n');
9084d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  for (auto line : lines) {
9094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    auto command = StringSplit(line, '#');
9104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (command[0].empty())
9114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      continue;
9124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    auto tokens = StringSplit(command[0], ',');
913d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (tokens[0] == "charcode") {
914d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (tokens.size() == 2) {
915d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        int keycode = atoi(tokens[1].c_str());
916d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        FORM_OnChar(form, page, keycode, 0);
917d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      } else {
918d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(stderr, "charcode: bad args\n");
919d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
920d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (tokens[0] == "keycode") {
9214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (tokens.size() == 2) {
9224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int keycode = atoi(tokens[1].c_str());
9234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        FORM_OnKeyDown(form, page, keycode, 0);
9244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        FORM_OnKeyUp(form, page, keycode, 0);
9254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } else {
9264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "keycode: bad args\n");
9274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
9284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (tokens[0] == "mousedown") {
9294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (tokens.size() == 4) {
9304d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int x = atoi(tokens[2].c_str());
9314d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int y = atoi(tokens[3].c_str());
9324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        if (tokens[1] == "left")
9334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          FORM_OnLButtonDown(form, page, 0, x, y);
9344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_XFA
9354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        else if (tokens[1] == "right")
9364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          FORM_OnRButtonDown(form, page, 0, x, y);
9374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
9384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        else
9394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          fprintf(stderr, "mousedown: bad button name\n");
9404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } else {
9414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "mousedown: bad args\n");
9424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
9434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (tokens[0] == "mouseup") {
9444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (tokens.size() == 4) {
9454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int x = atoi(tokens[2].c_str());
9464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int y = atoi(tokens[3].c_str());
9474d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        if (tokens[1] == "left")
9484d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          FORM_OnLButtonUp(form, page, 0, x, y);
9494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_XFA
9504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        else if (tokens[1] == "right")
9514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          FORM_OnRButtonUp(form, page, 0, x, y);
9524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
9534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        else
9544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          fprintf(stderr, "mouseup: bad button name\n");
9554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } else {
9564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "mouseup: bad args\n");
9574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
9584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else if (tokens[0] == "mousemove") {
9594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (tokens.size() == 3) {
9604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int x = atoi(tokens[1].c_str());
9614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        int y = atoi(tokens[2].c_str());
9624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        FORM_OnMouseMove(form, page, 0, x, y);
9634d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } else {
9644d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        fprintf(stderr, "mousemove: bad args\n");
9654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
966d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else if (tokens[0] == "focus") {
967d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (tokens.size() == 3) {
968d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        int x = atoi(tokens[1].c_str());
969d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        int y = atoi(tokens[2].c_str());
970d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        FORM_OnFocus(form, page, 0, x, y);
971d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      } else {
972d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fprintf(stderr, "focus: bad args\n");
973d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
9744d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else {
9754d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      fprintf(stderr, "Unrecognized event: %s\n", tokens[0].c_str());
9764d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
9774d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
9784d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
9794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
9804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. MoltmannFPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,
9814d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                          FPDF_DOCUMENT doc,
9824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                          int index) {
9834d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FPDF_FORMFILLINFO_PDFiumTest* form_fill_info =
9844d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      ToPDFiumTestFormFillInfo(param);
9854d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  auto& loaded_pages = form_fill_info->loaded_pages;
9864d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  auto iter = loaded_pages.find(index);
9874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (iter != loaded_pages.end())
988d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return iter->second.get();
9894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
9904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FPDF_PAGE page = FPDF_LoadPage(doc, index);
9914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!page)
9924d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return nullptr;
9934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
9944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FPDF_FORMHANDLE& form_handle = form_fill_info->form_handle;
9954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FORM_OnAfterLoadPage(page, form_handle);
9964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FORM_DoPageAAction(page, form_handle, FPDFPAGE_AACTION_OPEN);
997d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  loaded_pages[index].reset(page);
9984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return page;
999e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
1000e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1001d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::wstring ConvertToWString(const unsigned short* buf,
1002d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                              unsigned long buf_size) {
1003d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::wstring result;
1004d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  result.reserve(buf_size);
1005d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::copy(buf, buf + buf_size, std::back_inserter(result));
1006d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return result;
1007d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1008d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1009d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid DumpChildStructure(FPDF_STRUCTELEMENT child, int indent) {
1010d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  static const size_t kBufSize = 1024;
1011d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  unsigned short buf[kBufSize];
1012d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  unsigned long len = FPDF_StructElement_GetType(child, buf, kBufSize);
1013d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  printf("%*s%ls", indent * 2, "", ConvertToWString(buf, len).c_str());
1014d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1015d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  memset(buf, 0, sizeof(buf));
1016d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  len = FPDF_StructElement_GetTitle(child, buf, kBufSize);
1017d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (len > 0)
1018d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    printf(": '%ls'", ConvertToWString(buf, len).c_str());
1019d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1020d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  memset(buf, 0, sizeof(buf));
1021d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  len = FPDF_StructElement_GetAltText(child, buf, kBufSize);
1022d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (len > 0)
1023d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    printf(" (%ls)", ConvertToWString(buf, len).c_str());
1024d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  printf("\n");
1025d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1026d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < FPDF_StructElement_CountChildren(child); ++i) {
1027d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_STRUCTELEMENT sub_child = FPDF_StructElement_GetChildAtIndex(child, i);
1028d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // If the child is not an Element then this will return null. This can
1029d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // happen if the element is things like an object reference or a stream.
1030d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!sub_child)
1031d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1032d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1033d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    DumpChildStructure(sub_child, indent + 1);
1034d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1035d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1036d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1037d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid DumpPageStructure(FPDF_PAGE page, const int page_idx) {
1038d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFStructTreeDeleter> tree(
1039d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      FPDF_StructTree_GetForPage(page));
1040d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!tree) {
1041d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fprintf(stderr, "Failed to load struct tree for page %d\n", page_idx);
1042d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return;
1043d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1044d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1045d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  printf("Structure Tree for Page %d\n", page_idx);
1046d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < FPDF_StructTree_CountChildren(tree.get()); ++i) {
1047d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_STRUCTELEMENT child = FPDF_StructTree_GetChildAtIndex(tree.get(), i);
1048d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!child) {
1049d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to load child %d for page %d\n", i, page_idx);
1050d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1051d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1052d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    DumpChildStructure(child, 0);
1053d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1054d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  printf("\n\n");
1055d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1056d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1057d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid DumpMetaData(FPDF_DOCUMENT doc) {
1058d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  constexpr const char* meta_tags[] = {"Title",        "Author",  "Subject",
1059d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                       "Keywords",     "Creator", "Producer",
1060d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                       "CreationDate", "ModDate"};
1061d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (const char* meta_tag : meta_tags) {
1062d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    char meta_buffer[4096];
1063d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned long len =
1064d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        FPDF_GetMetaText(doc, meta_tag, meta_buffer, sizeof(meta_buffer));
1065d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!len)
1066d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1067d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1068d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    auto* meta_string = reinterpret_cast<unsigned short*>(meta_buffer);
1069d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    printf("%-12s = %ls (%lu bytes)\n", meta_tag,
1070d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann           GetPlatformWString(meta_string).c_str(), len);
1071d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1072d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1073d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1074d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid SaveAttachments(FPDF_DOCUMENT doc, const std::string& name) {
1075d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < FPDFDoc_GetAttachmentCount(doc); ++i) {
1076d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(doc, i);
1077d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1078d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the attachment file name.
1079d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    std::string attachment_name;
1080d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
1081d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (len) {
1082d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      std::vector<char> buf(len);
1083d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      unsigned long actual_len =
1084d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          FPDFAttachment_GetName(attachment, buf.data(), len);
1085d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (actual_len == len) {
1086d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        attachment_name =
1087d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            GetPlatformString(reinterpret_cast<unsigned short*>(buf.data()));
1088d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
1089d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1090d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (attachment_name.empty()) {
1091d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Attachment #%d has an empty file name.\n", i + 1);
1092d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1093d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1094d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1095d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Calculate the full attachment file name.
1096d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    char save_name[256];
1097d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int chars_formatted =
1098d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        snprintf(save_name, sizeof(save_name), "%s.attachment.%s", name.c_str(),
1099d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                 attachment_name.c_str());
1100d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (chars_formatted < 0 ||
1101d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        static_cast<size_t>(chars_formatted) >= sizeof(save_name)) {
1102d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Filename %s is too long\n", save_name);
1103d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1104d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1105d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1106d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Retrieve the attachment.
1107d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    len = FPDFAttachment_GetFile(attachment, nullptr, 0);
1108d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    std::vector<char> data_buf(len);
1109d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (len) {
1110d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      unsigned long actual_len =
1111d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          FPDFAttachment_GetFile(attachment, data_buf.data(), len);
1112d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (actual_len != len)
1113d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        data_buf.clear();
1114d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1115d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (data_buf.empty()) {
1116d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Attachment \"%s\" is empty.\n", attachment_name.c_str());
1117d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1118d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1119d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1120d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    // Write the attachment file.
1121d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FILE* fp = fopen(save_name, "wb");
1122d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!fp) {
1123d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to open %s for saving attachment.\n", save_name);
1124d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1125d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1126d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1127d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    size_t written_len = fwrite(data_buf.data(), 1, len, fp);
1128d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (written_len == len) {
1129d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Saved attachment \"%s\" as: %s.\n",
1130d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              attachment_name.c_str(), save_name);
1131d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
1132d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to write to %s\n", save_name);
1133d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1134d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    fclose(fp);
1135d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1136d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1137d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1138d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid SaveImages(FPDF_PAGE page, const char* pdf_name, int page_num) {
1139d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < FPDFPage_CountObjects(page); ++i) {
1140d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
1141d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (FPDFPageObj_GetType(obj) != FPDF_PAGEOBJ_IMAGE)
1142d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1143d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1144d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    std::unique_ptr<void, FPDFBitmapDeleter> bitmap(
1145d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        FPDFImageObj_GetBitmap(obj));
1146d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!bitmap) {
1147d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Image object #%d on page #%d has an empty bitmap.\n",
1148d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              i + 1, page_num + 1);
1149d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1150d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1151d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1152d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int format = FPDFBitmap_GetFormat(bitmap.get());
1153d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (format == FPDFBitmap_Unknown) {
1154d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr,
1155d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              "Image object #%d on page #%d has a bitmap of unknown format.\n",
1156d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              i + 1, page_num + 1);
1157d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1158d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1159d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1160d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    std::vector<unsigned char> png_encoding;
1161d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const unsigned char* buffer =
1162d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        static_cast<const unsigned char*>(FPDFBitmap_GetBuffer(bitmap.get()));
1163d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int width = FPDFBitmap_GetWidth(bitmap.get());
1164d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int height = FPDFBitmap_GetHeight(bitmap.get());
1165d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int stride = FPDFBitmap_GetStride(bitmap.get());
1166d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    bool ret = false;
1167d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    switch (format) {
1168d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case FPDFBitmap_Gray:
1169d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        ret = image_diff_png::EncodeGrayPNG(buffer, width, height, stride,
1170d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                            &png_encoding);
1171d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        break;
1172d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case FPDFBitmap_BGR:
1173d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        ret = image_diff_png::EncodeBGRPNG(buffer, width, height, stride,
1174d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                           &png_encoding);
1175d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        break;
1176d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case FPDFBitmap_BGRx:
1177d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        ret = image_diff_png::EncodeBGRAPNG(buffer, width, height, stride, true,
1178d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                            &png_encoding);
1179d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        break;
1180d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case FPDFBitmap_BGRA:
1181d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        ret = image_diff_png::EncodeBGRAPNG(buffer, width, height, stride,
1182d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                            false, &png_encoding);
1183d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        break;
1184d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      default:
1185d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        NOTREACHED();
1186d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1187d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!ret) {
1188d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr,
1189d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              "Failed to convert image object #%d on page #%d to png.\n", i + 1,
1190d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              page_num + 1);
1191d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1192d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1193d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1194d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    char filename[256];
1195d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int chars_formatted = snprintf(filename, sizeof(filename), "%s.%d.%d.png",
1196d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                   pdf_name, page_num, i);
1197d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (chars_formatted < 0 ||
1198d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
1199d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Filename %s for saving image is too long\n", filename);
1200d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1201d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1202d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1203d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FILE* fp = fopen(filename, "wb");
1204d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!fp) {
1205d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to open %s for saving image.\n", filename);
1206d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      continue;
1207d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1208d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1209d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    size_t bytes_written =
1210d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        fwrite(&png_encoding.front(), 1, png_encoding.size(), fp);
1211d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (bytes_written != png_encoding.size())
1212d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Failed to write to %s.\n", filename);
1213d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    else
1214d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "Successfully wrote embedded image %s.\n", filename);
1215d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1216d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    (void)fclose(fp);
1217d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1218d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1219d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1220d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Note, for a client using progressive rendering you'd want to determine if you
1221d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// need the rendering to pause instead of always saying |true|. This is for
1222d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// testing to force the renderer to break whenever possible.
1223d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannFPDF_BOOL NeedToPauseNow(IFSDK_PAUSE* p) {
1224d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return true;
1225d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
1226d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1227ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmannbool RenderPage(const std::string& name,
12284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                FPDF_DOCUMENT doc,
1229d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                FPDF_FORMHANDLE form,
1230d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                FPDF_FORMFILLINFO_PDFiumTest* form_fill_info,
1231ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                const int page_index,
12324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                const Options& options,
12334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                const std::string& events) {
1234d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FPDF_PAGE page = GetPageForIndex(form_fill_info, doc, page_index);
12354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!page)
1236ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    return false;
12374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (options.send_events)
12384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    SendPageEvents(form, page, events);
1239d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (options.save_images)
1240d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    SaveImages(page, name.c_str(), page_index);
1241d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (options.output_format == OUTPUT_STRUCTURE) {
1242d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    DumpPageStructure(page, page_index);
1243d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return true;
1244d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
1245d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1246d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFTextPageDeleter> text_page(FPDFText_LoadPage(page));
1247ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1248ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  double scale = 1.0;
12494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!options.scale_factor_as_string.empty())
1250ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    std::stringstream(options.scale_factor_as_string) >> scale;
12514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1252d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  auto width = static_cast<int>(FPDF_GetPageWidth(page) * scale);
1253d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  auto height = static_cast<int>(FPDF_GetPageHeight(page) * scale);
1254ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
1255d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFBitmapDeleter> bitmap(
1256d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      FPDFBitmap_Create(width, height, alpha));
1257d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
12584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (bitmap) {
12594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
1260d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);
1261d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1262d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (options.render_oneshot) {
1263d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      // Note, client programs probably want to use this method instead of the
1264d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      // progressive calls. The progressive calls are if you need to pause the
1265d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      // rendering to update the UI, the PDF renderer will break when possible.
1266d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, width, height, 0,
1267d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                            FPDF_ANNOT);
1268d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
1269d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      IFSDK_PAUSE pause;
1270d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      pause.version = 1;
1271d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      pause.NeedToPauseNow = &NeedToPauseNow;
1272d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1273d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      int rv = FPDF_RenderPageBitmap_Start(bitmap.get(), page, 0, 0, width,
1274d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                                           height, 0, FPDF_ANNOT, &pause);
1275d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      while (rv == FPDF_RENDER_TOBECOUNTINUED)
1276d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        rv = FPDF_RenderPage_Continue(page, &pause);
1277d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
12784d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1279d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_FFLDraw(form, bitmap.get(), page, 0, 0, width, height, 0, FPDF_ANNOT);
1280d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1281d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!options.render_oneshot)
1282d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      FPDF_RenderPage_Close(page);
1283d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1284d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int stride = FPDFBitmap_GetStride(bitmap.get());
12854d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    const char* buffer =
1286d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        reinterpret_cast<const char*>(FPDFBitmap_GetBuffer(bitmap.get()));
12874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1288d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    std::string image_file_name;
12894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    switch (options.output_format) {
12904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef _WIN32
12914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      case OUTPUT_BMP:
12924d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        image_file_name =
12934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            WriteBmp(name.c_str(), page_index, buffer, stride, width, height);
12944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        break;
1295ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
12964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      case OUTPUT_EMF:
12974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        WriteEmf(page, name.c_str(), page_index);
12984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        break;
1299d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1300d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case OUTPUT_PS2:
1301d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case OUTPUT_PS3:
1302d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        WritePS(page, name.c_str(), page_index);
1303d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        break;
13044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
13054d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      case OUTPUT_TEXT:
13064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        WriteText(page, name.c_str(), page_index);
13074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        break;
1308ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1309d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      case OUTPUT_ANNOT:
1310d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        WriteAnnot(page, name.c_str(), page_index);
1311d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        break;
1312d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
13134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      case OUTPUT_PNG:
13144d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        image_file_name =
13154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            WritePng(name.c_str(), page_index, buffer, stride, width, height);
13164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        break;
1317ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
13184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      case OUTPUT_PPM:
13194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        image_file_name =
13204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            WritePpm(name.c_str(), page_index, buffer, stride, width, height);
13214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        break;
13224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
13234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_SKIA
13244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      case OUTPUT_SKP: {
13254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        std::unique_ptr<SkPictureRecorder> recorder(
13264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            reinterpret_cast<SkPictureRecorder*>(
13274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                FPDF_RenderPageSkp(page, width, height)));
13284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        FPDF_FFLRecord(form, recorder.get(), page, 0, 0, width, height, 0, 0);
13294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        image_file_name = WriteSkp(name.c_str(), page_index, recorder.get());
13304d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } break;
1331ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif
13324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      default:
13334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        break;
13344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
1335ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
13364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    // Write the filename and the MD5 of the buffer to stdout if we wrote a
13374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    // file.
1338d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (options.md5 && !image_file_name.empty())
13394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      OutputMD5Hash(image_file_name.c_str(), buffer, stride * height);
13404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
13414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Page was too large to be rendered.\n");
1342ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  }
1343ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1344ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE);
1345ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  FORM_OnBeforeClosePage(page, form);
13464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return !!bitmap;
1347ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann}
1348ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
13494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannvoid RenderPdf(const std::string& name,
13504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann               const char* pBuf,
13514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann               size_t len,
13524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann               const Options& options,
13534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann               const std::string& events) {
1354d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  IPDF_JSPLATFORM platform_callbacks = {};
1355ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  platform_callbacks.version = 3;
1356e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  platform_callbacks.app_alert = ExampleAppAlert;
13574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  platform_callbacks.app_response = ExampleAppResponse;
1358e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
13594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  platform_callbacks.Doc_mail = ExampleDocMail;
1360e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1361d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // The pdf_avail must outlive doc.
1362d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFAvailDeleter> pdf_avail;
1363d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // The document must outlive |form_callbacks.loaded_pages|.
1364d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFDocumentDeleter> doc;
13654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FPDF_FORMFILLINFO_PDFiumTest form_callbacks = {};
1366ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#ifdef PDF_ENABLE_XFA
1367ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  form_callbacks.version = 2;
1368ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#else   // PDF_ENABLE_XFA
1369e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  form_callbacks.version = 1;
1370ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // PDF_ENABLE_XFA
13714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  form_callbacks.FFI_GetPage = GetPageForIndex;
1372e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  form_callbacks.m_pJsPlatform = &platform_callbacks;
1373e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1374e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  TestLoader loader(pBuf, len);
1375d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FPDF_FILEACCESS file_access = {};
1376e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_access.m_FileLen = static_cast<unsigned long>(len);
1377ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  file_access.m_GetBlock = TestLoader::GetBlock;
1378e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_access.m_Param = &loader;
1379e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1380d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_FILEAVAIL file_avail = {};
1381e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_avail.version = 1;
1382e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  file_avail.IsDataAvail = Is_Data_Avail;
1383e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1384d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_DOWNLOADHINTS hints = {};
1385e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  hints.version = 1;
1386e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  hints.AddSegment = Add_Segment;
1387e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1388ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  int nRet = PDF_DATA_NOTAVAIL;
1389ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  bool bIsLinearized = false;
1390d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  pdf_avail.reset(FPDFAvail_Create(&file_avail, &file_access));
1391e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1392d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (FPDFAvail_IsLinearized(pdf_avail.get()) == PDF_LINEARIZED) {
1393d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), nullptr));
1394ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if (doc) {
13954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      while (nRet == PDF_DATA_NOTAVAIL)
1396d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        nRet = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints);
13974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1398ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if (nRet == PDF_DATA_ERROR) {
1399ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        fprintf(stderr, "Unknown error in checking if doc was available.\n");
1400ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return;
1401ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      }
1402d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      nRet = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints);
1403ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) {
1404ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        fprintf(stderr,
1405ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                "Error %d was returned in checking if form was available.\n",
1406ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                nRet);
1407ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return;
1408ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      }
1409ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      bIsLinearized = true;
1410ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    }
1411ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  } else {
1412d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr));
1413ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  }
1414ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1415ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  if (!doc) {
1416d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    PrintLastError();
1417ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    return;
1418e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
1419e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1420d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  (void)FPDF_GetDocPermissions(doc.get());
1421d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1422d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (options.show_metadata)
1423d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    DumpMetaData(doc.get());
1424e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1425d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (options.save_attachments)
1426d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    SaveAttachments(doc.get(), name);
1427d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1428d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<void, FPDFFormHandleDeleter> form(
1429d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
1430d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  form_callbacks.form_handle = form.get();
14314d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1432ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#ifdef PDF_ENABLE_XFA
1433d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int doc_type = FPDF_GetFormType(doc.get());
1434d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (doc_type == FORMTYPE_XFA_FULL || doc_type == FORMTYPE_XFA_FOREGROUND) {
1435d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!FPDF_LoadXFA(doc.get()))
1436d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      fprintf(stderr, "LoadXFA unsuccessful, continuing anyway.\n");
1437ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  }
1438ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // PDF_ENABLE_XFA
1439e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1440d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FPDF_SetFormFieldHighlightColor(form.get(), FPDF_FORMFIELD_UNKNOWN, 0xFFE4DD);
1441d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FPDF_SetFormFieldHighlightAlpha(form.get(), 100);
1442d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FORM_DoDocumentJSAction(form.get());
1443d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FORM_DoDocumentOpenAction(form.get());
1444e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1445d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _WIN32
1446d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (options.output_format == OUTPUT_PS2)
1447d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT2);
1448d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  else if (options.output_format == OUTPUT_PS3)
1449d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT3);
1450d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif
1451d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1452d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int page_count = FPDF_GetPageCount(doc.get());
1453e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  int rendered_pages = 0;
1454e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  int bad_pages = 0;
14554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int first_page = options.pages ? options.first_page : 0;
14564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int last_page = options.pages ? options.last_page + 1 : page_count;
14574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  for (int i = first_page; i < last_page; ++i) {
1458ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if (bIsLinearized) {
1459ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      nRet = PDF_DATA_NOTAVAIL;
14604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      while (nRet == PDF_DATA_NOTAVAIL)
1461d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        nRet = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints);
14624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1463ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if (nRet == PDF_DATA_ERROR) {
1464ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        fprintf(stderr, "Unknown error in checking if page %d is available.\n",
1465ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                i);
1466ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return;
1467ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      }
1468e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
1469d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (RenderPage(name, doc.get(), form.get(), &form_callbacks, i, options,
1470d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                   events)) {
1471ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      ++rendered_pages;
1472d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
1473ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      ++bad_pages;
1474d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
1475e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
1476e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1477d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FORM_DoDocumentAAction(form.get(), FPDFDOC_AACTION_WC);
1478e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  fprintf(stderr, "Rendered %d pages.\n", rendered_pages);
14794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (bad_pages)
14804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Skipped %d bad pages.\n", bad_pages);
14814d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
14824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1483d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid ShowConfig() {
14844d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  std::string config;
14854d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  std::string maybe_comma;
14864d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#if PDF_ENABLE_V8
14874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  config.append(maybe_comma);
14884d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  config.append("V8");
14894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  maybe_comma = ",";
14904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif  // PDF_ENABLE_V8
14914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef V8_USE_EXTERNAL_STARTUP_DATA
14924d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  config.append(maybe_comma);
14934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  config.append("V8_EXTERNAL");
14944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  maybe_comma = ",";
14954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif  // V8_USE_EXTERNAL_STARTUP_DATA
14964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_XFA
14974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  config.append(maybe_comma);
14984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  config.append("XFA");
14994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  maybe_comma = ",";
15004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif  // PDF_ENABLE_XFA
150133357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann#ifdef PDF_ENABLE_ASAN
150233357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  config.append(maybe_comma);
150333357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  config.append("ASAN");
150433357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  maybe_comma = ",";
150533357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann#endif  // PDF_ENABLE_ASAN
15064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  printf("%s\n", config.c_str());
1507e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
1508e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1509d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannconstexpr char kUsageString[] =
1510e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    "Usage: pdfium_test [OPTION] [FILE]...\n"
1511d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --show-config       - print build options and exit\n"
1512d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --show-metadata     - print the file metadata\n"
1513d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --show-structure    - print the structure elements from the document\n"
1514d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --send-events       - send input described by .evt file\n"
1515d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --render-oneshot    - render image without using progressive renderer\n"
1516d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --save-attachments  - write embedded attachments "
1517d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "<pdf-name>.attachment.<attachment-name>\n"
1518d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --save-images       - write embedded images "
1519d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "<pdf-name>.<page-number>.<object-number>.png\n"
1520d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
1521d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --callgrind-delim   - delimit interesting section when using callgrind\n"
1522d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
1523d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --bin-dir=<path>    - override path to v8 external data\n"
1524d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --font-dir=<path>   - override path to external fonts\n"
1525d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --scale=<number>    - scale output size by number (e.g. 0.5)\n"
15264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    "  --pages=<number>(-<number>) - only render the given 0-based page(s)\n"
1527e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef _WIN32
1528d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --bmp   - write page images <pdf-name>.<page-number>.bmp\n"
1529d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --emf   - write page meta files <pdf-name>.<page-number>.emf\n"
1530d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --ps2   - write page raw PostScript (Lvl 2) "
1531d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "<pdf-name>.<page-number>.ps\n"
1532d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --ps3   - write page raw PostScript (Lvl 3) "
1533d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "<pdf-name>.<page-number>.ps\n"
1534ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // _WIN32
1535d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --txt   - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n"
1536d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --png   - write page images <pdf-name>.<page-number>.png\n"
1537d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --ppm   - write page images <pdf-name>.<page-number>.ppm\n"
1538d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --annot - write annotation info <pdf-name>.<page-number>.annot.txt\n"
15394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef PDF_ENABLE_SKIA
1540d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --skp   - write page images <pdf-name>.<page-number>.skp\n"
15414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
1542d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    "  --md5   - write output image paths and their md5 hashes to stdout.\n"
15434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    "";
1544e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1545d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}  // namespace
1546d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1547e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovint main(int argc, const char* argv[]) {
1548e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  std::vector<std::string> args(argv, argv + argc);
1549e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  Options options;
15504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  std::vector<std::string> files;
1551e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  if (!ParseCommandLine(args, &options, &files)) {
15524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "%s", kUsageString);
15534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return 1;
15544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
15554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
15564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (options.show_config) {
15574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    ShowConfig();
15584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return 0;
15594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
15604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
15614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (files.empty()) {
15624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "No input files.\n");
1563e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return 1;
1564e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
1565e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1566ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#ifdef PDF_ENABLE_V8
1567ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  v8::Platform* platform;
1568e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1569e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  v8::StartupData natives;
1570e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  v8::StartupData snapshot;
1571ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  InitializeV8ForPDFium(options.exe_path, options.bin_directory, &natives,
1572ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                        &snapshot, &platform);
1573ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#else   // V8_USE_EXTERNAL_STARTUP_DATA
15744d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  InitializeV8ForPDFium(options.exe_path, &platform);
1575e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#endif  // V8_USE_EXTERNAL_STARTUP_DATA
1576ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // PDF_ENABLE_V8
1577ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1578ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  FPDF_LIBRARY_CONFIG config;
1579ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  config.version = 2;
1580ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  config.m_pUserFontPaths = nullptr;
1581ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  config.m_pIsolate = nullptr;
1582ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  config.m_v8EmbedderSlot = 0;
1583ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1584ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  const char* path_array[2];
1585ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  if (!options.font_directory.empty()) {
1586ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    path_array[0] = options.font_directory.c_str();
1587ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    path_array[1] = nullptr;
1588ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    config.m_pUserFontPaths = path_array;
1589ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  }
1590ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  FPDF_InitLibraryWithConfig(&config);
1591e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1592d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  UNSUPPORT_INFO unsupported_info = {};
15934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  unsupported_info.version = 1;
15944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  unsupported_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler;
1595e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
15964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FSDK_SetUnSpObjProcessHandler(&unsupported_info);
1597e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
15984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  for (const std::string& filename : files) {
1599e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    size_t file_length = 0;
1600ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    std::unique_ptr<char, pdfium::FreeDeleter> file_contents =
1601ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        GetFileContents(filename.c_str(), &file_length);
16024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (!file_contents)
16034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      continue;
16044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    fprintf(stderr, "Rendering PDF file %s.\n", filename.c_str());
1605d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1606d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
1607d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (options.callgrind_delimiters)
1608d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      CALLGRIND_START_INSTRUMENTATION;
1609d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
1610d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
16114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    std::string events;
16124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (options.send_events) {
16134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      std::string event_filename = filename;
16144d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      size_t event_length = 0;
16154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      size_t extension_pos = event_filename.find(".pdf");
16164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (extension_pos != std::string::npos) {
16174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        event_filename.replace(extension_pos, 4, ".evt");
16184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        if (access(event_filename.c_str(), R_OK) == 0) {
16194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          fprintf(stderr, "Using event file %s.\n", event_filename.c_str());
16204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          std::unique_ptr<char, pdfium::FreeDeleter> event_contents =
16214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann              GetFileContents(event_filename.c_str(), &event_length);
16224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          if (event_contents) {
16234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            fprintf(stderr, "Sending events from: %s\n",
16244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    event_filename.c_str());
16254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            events = std::string(event_contents.get(), event_length);
16264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          }
16274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        }
16284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
16294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
16304d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    RenderPdf(filename, file_contents.get(), file_length, options, events);
1631d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
1632d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifdef ENABLE_CALLGRIND
1633d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (options.callgrind_delimiters)
1634d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      CALLGRIND_STOP_INSTRUMENTATION;
1635d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // ENABLE_CALLGRIND
1636e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  }
1637e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1638e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  FPDF_DestroyLibrary();
1639ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#ifdef PDF_ENABLE_V8
1640e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  v8::V8::ShutdownPlatform();
1641e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  delete platform;
16424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
16434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#ifdef V8_USE_EXTERNAL_STARTUP_DATA
16444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  free(const_cast<char*>(natives.data));
16454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  free(const_cast<char*>(snapshot.data));
16464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif  // V8_USE_EXTERNAL_STARTUP_DATA
1647ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#endif  // PDF_ENABLE_V8
1648e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1649e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov  return 0;
1650e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
1651