Commit f1a2d3160a1dbaf735cce597d0f6f40e76f7f223

Authored by Jay Berkenbilt
1 parent 66f1fd2a

Add JSON v2 support to C API

ChangeLog
1 2022-09-08 Jay Berkenbilt <ejb@ql.org> 1 2022-09-08 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Added new functions to the C API to support qpdf JSON:
  4 + qpdf_create_from_json_file, qpdf_create_from_json_data,
  5 + qpdf_update_from_json_file, qpdf_update_from_json_data, and
  6 + qpdf_write_json. Examples can be found in qpdf-ctest.c (in the
  7 + source tree), tests 42 through 47.
  8 +
3 * Add QPDFObjectHandle::isDestroyed() to test whether an indirect 9 * Add QPDFObjectHandle::isDestroyed() to test whether an indirect
4 object was from a QPDF that has been destroyed. 10 object was from a QPDF that has been destroyed.
5 11
@@ -8,12 +8,6 @@ Always @@ -8,12 +8,6 @@ Always
8 Next 8 Next
9 ==== 9 ====
10 10
11 -Before Release:  
12 -  
13 -* Support json v2 in the C API. At a minimum, write_json,  
14 - create_from_json, and update_from_json need to be there and should  
15 - take the same kinds of functions as the C API for logger.  
16 -  
17 Pending changes: 11 Pending changes:
18 12
19 * Consider also exposing a way to set a new logger and to get the 13 * Consider also exposing a way to set a new logger and to get the
include/qpdf/qpdf-c.h
@@ -257,8 +257,6 @@ extern &quot;C&quot; { @@ -257,8 +257,6 @@ extern &quot;C&quot; {
257 QPDF_DLL 257 QPDF_DLL
258 QPDF_ERROR_CODE qpdf_check_pdf(qpdf_data qpdf); 258 QPDF_ERROR_CODE qpdf_check_pdf(qpdf_data qpdf);
259 259
260 - /* READ FUNCTIONS */  
261 -  
262 /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */ 260 /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */
263 261
264 QPDF_DLL 262 QPDF_DLL
@@ -267,6 +265,10 @@ extern &quot;C&quot; { @@ -267,6 +265,10 @@ extern &quot;C&quot; {
267 QPDF_DLL 265 QPDF_DLL
268 void qpdf_set_attempt_recovery(qpdf_data qpdf, QPDF_BOOL value); 266 void qpdf_set_attempt_recovery(qpdf_data qpdf, QPDF_BOOL value);
269 267
  268 + /* PROCESS FUNCTIONS */
  269 +
  270 + /* This functions process a PDF or JSON input source. */
  271 +
270 /* Calling qpdf_read causes processFile to be called in the C++ 272 /* Calling qpdf_read causes processFile to be called in the C++
271 * API. Basic parsing is performed, but data from the file is 273 * API. Basic parsing is performed, but data from the file is
272 * only read as needed. For files without passwords, pass a null 274 * only read as needed. For files without passwords, pass a null
@@ -297,8 +299,40 @@ extern &quot;C&quot; { @@ -297,8 +299,40 @@ extern &quot;C&quot; {
297 QPDF_DLL 299 QPDF_DLL
298 QPDF_ERROR_CODE qpdf_empty_pdf(qpdf_data qpdf); 300 QPDF_ERROR_CODE qpdf_empty_pdf(qpdf_data qpdf);
299 301
300 - /* Read functions below must be called after qpdf_read or  
301 - * qpdf_read_memory. */ 302 + /* Create a PDF from a JSON file. This calls createFromJSON in the
  303 + * C++ API.
  304 + */
  305 + QPDF_DLL
  306 + QPDF_ERROR_CODE
  307 + qpdf_create_from_json_file(qpdf_data qpdf, char const* filename);
  308 +
  309 + /* Create a PDF from JSON data in a null-terminated string. This
  310 + * calls createFromJSON in the C++ API.
  311 + */
  312 + QPDF_DLL
  313 + QPDF_ERROR_CODE
  314 + qpdf_create_from_json_data(
  315 + qpdf_data qpdf, char const* buffer, unsigned long long size);
  316 +
  317 + /* JSON UPDATE FUNCTIONS */
  318 +
  319 + /* Update a QPDF object from a JSON file or buffer. These
  320 + * functions call updateFromJSON. One of the other processing
  321 + * functions has to be called first so that the QPDF object is
  322 + * initialized with PDF data.
  323 + */
  324 + QPDF_DLL
  325 + QPDF_ERROR_CODE
  326 + qpdf_update_from_json_file(qpdf_data qpdf, char const* filename);
  327 + QPDF_DLL
  328 + QPDF_ERROR_CODE
  329 + qpdf_update_from_json_data(
  330 + qpdf_data qpdf, char const* buffer, unsigned long long size);
  331 +
  332 + /* READ FUNCTIONS */
  333 +
  334 + /* Read functions below must be called after qpdf_read or any of
  335 + * the other functions that process a PDF. */
302 336
303 /* 337 /*
304 * NOTE: Functions that return char* are returning a pointer to an 338 * NOTE: Functions that return char* are returning a pointer to an
@@ -371,6 +405,39 @@ extern &quot;C&quot; { @@ -371,6 +405,39 @@ extern &quot;C&quot; {
371 QPDF_DLL 405 QPDF_DLL
372 QPDF_BOOL qpdf_allow_modify_all(qpdf_data qpdf); 406 QPDF_BOOL qpdf_allow_modify_all(qpdf_data qpdf);
373 407
  408 + /* JSON WRITE FUNCTIONS */
  409 +
  410 + /* This function serializes the PDF to JSON. This calls writeJSON
  411 + * from the C++ API.
  412 + *
  413 + * - version: the JSON version, currently must be 2
  414 + * - fn: a function that will be called with blocks of JSON data;
  415 + * will be called with data, a length, and the value of the
  416 + * udata parameter to this function
  417 + * - udata: will be passed as the third argument to fn with each
  418 + * call; use this for your own tracking or pass a null pointer
  419 + * if you don't need it
  420 + * - For decode_level, json_stream_data, file_prefix, and
  421 + * wanted_objects, see comments in QPDF.hh. For this API,
  422 + * wanted_objects should be a null-terminated array of
  423 + * null-terminated strings. Pass a null pointer if you want all
  424 + * objects.
  425 + */
  426 +
  427 + /* Function should return 0 on success. */
  428 + typedef int (*qpdf_write_fn_t)(char const* data, size_t len, void* udata);
  429 +
  430 + QPDF_DLL
  431 + QPDF_ERROR_CODE qpdf_write_json(
  432 + qpdf_data qpdf,
  433 + int version,
  434 + qpdf_write_fn_t fn,
  435 + void* udata,
  436 + enum qpdf_stream_decode_level_e decode_level,
  437 + enum qpdf_json_stream_data_e json_stream_data,
  438 + char const* file_prefix,
  439 + char const* const* wanted_objects);
  440 +
374 /* WRITE FUNCTIONS */ 441 /* WRITE FUNCTIONS */
375 442
376 /* Set up for writing. No writing is actually performed until the 443 /* Set up for writing. No writing is actually performed until the
libqpdf/qpdf-c.cc
@@ -2,8 +2,10 @@ @@ -2,8 +2,10 @@
2 2
3 #include <qpdf/QPDF.hh> 3 #include <qpdf/QPDF.hh>
4 4
  5 +#include <qpdf/BufferInputSource.hh>
5 #include <qpdf/Pl_Buffer.hh> 6 #include <qpdf/Pl_Buffer.hh>
6 #include <qpdf/Pl_Discard.hh> 7 #include <qpdf/Pl_Discard.hh>
  8 +#include <qpdf/Pl_Function.hh>
7 #include <qpdf/QIntC.hh> 9 #include <qpdf/QIntC.hh>
8 #include <qpdf/QPDFExc.hh> 10 #include <qpdf/QPDFExc.hh>
9 #include <qpdf/QPDFLogger.hh> 11 #include <qpdf/QPDFLogger.hh>
@@ -2029,3 +2031,89 @@ qpdf_remove_page(qpdf_data qpdf, qpdf_oh page) @@ -2029,3 +2031,89 @@ qpdf_remove_page(qpdf_data qpdf, qpdf_oh page)
2029 auto p = qpdf_oh_item_internal(qpdf, page); 2031 auto p = qpdf_oh_item_internal(qpdf, page);
2030 return trap_errors(qpdf, [&p](qpdf_data q) { q->qpdf->removePage(p); }); 2032 return trap_errors(qpdf, [&p](qpdf_data q) { q->qpdf->removePage(p); });
2031 } 2033 }
  2034 +
  2035 +QPDF_ERROR_CODE
  2036 +qpdf_create_from_json_file(qpdf_data qpdf, char const* filename)
  2037 +{
  2038 + QPDF_ERROR_CODE status = QPDF_SUCCESS;
  2039 + qpdf->filename = filename;
  2040 + status = trap_errors(
  2041 + qpdf, [](qpdf_data q) { q->qpdf->createFromJSON(q->filename); });
  2042 + return status;
  2043 +}
  2044 +
  2045 +QPDF_ERROR_CODE
  2046 +qpdf_create_from_json_data(
  2047 + qpdf_data qpdf, char const* buffer, unsigned long long size)
  2048 +{
  2049 + QPDF_ERROR_CODE status = QPDF_SUCCESS;
  2050 + qpdf->filename = "json buffer";
  2051 + qpdf->buffer = buffer;
  2052 + qpdf->size = size;
  2053 + auto b =
  2054 + new Buffer(QUtil::unsigned_char_pointer(buffer), QIntC::to_size(size));
  2055 + auto is = std::make_shared<BufferInputSource>(qpdf->filename, b, true);
  2056 + status =
  2057 + trap_errors(qpdf, [&is](qpdf_data q) { q->qpdf->createFromJSON(is); });
  2058 + return status;
  2059 +}
  2060 +
  2061 +QPDF_ERROR_CODE
  2062 +qpdf_update_from_json_file(qpdf_data qpdf, char const* filename)
  2063 +{
  2064 + QPDF_ERROR_CODE status = QPDF_SUCCESS;
  2065 + status = trap_errors(
  2066 + qpdf, [filename](qpdf_data q) { q->qpdf->updateFromJSON(filename); });
  2067 + return status;
  2068 +}
  2069 +
  2070 +QPDF_ERROR_CODE
  2071 +qpdf_update_from_json_data(
  2072 + qpdf_data qpdf, char const* buffer, unsigned long long size)
  2073 +{
  2074 + QPDF_ERROR_CODE status = QPDF_SUCCESS;
  2075 + auto b =
  2076 + new Buffer(QUtil::unsigned_char_pointer(buffer), QIntC::to_size(size));
  2077 + auto is = std::make_shared<BufferInputSource>(qpdf->filename, b, true);
  2078 + status =
  2079 + trap_errors(qpdf, [&is](qpdf_data q) { q->qpdf->updateFromJSON(is); });
  2080 + return status;
  2081 +}
  2082 +
  2083 +QPDF_ERROR_CODE
  2084 +qpdf_write_json(
  2085 + qpdf_data qpdf,
  2086 + int version,
  2087 + qpdf_write_fn_t fn,
  2088 + void* udata,
  2089 + enum qpdf_stream_decode_level_e decode_level,
  2090 + enum qpdf_json_stream_data_e json_stream_data,
  2091 + char const* file_prefix,
  2092 + char const* const* wanted_objects)
  2093 +{
  2094 + QPDF_ERROR_CODE status = QPDF_SUCCESS;
  2095 + auto p = std::make_shared<Pl_Function>("write_json", nullptr, fn, udata);
  2096 + std::set<std::string> wanted_objects_set;
  2097 + if (wanted_objects) {
  2098 + for (auto i = wanted_objects; *i; ++i) {
  2099 + wanted_objects_set.insert(*i);
  2100 + }
  2101 + }
  2102 + status = trap_errors(
  2103 + qpdf,
  2104 + [version,
  2105 + p,
  2106 + decode_level,
  2107 + json_stream_data,
  2108 + file_prefix,
  2109 + &wanted_objects_set](qpdf_data q) {
  2110 + q->qpdf->writeJSON(
  2111 + version,
  2112 + p.get(),
  2113 + decode_level,
  2114 + json_stream_data,
  2115 + file_prefix,
  2116 + wanted_objects_set);
  2117 + });
  2118 + return status;
  2119 +}
manual/release-notes.rst
@@ -40,6 +40,10 @@ For a detailed list of changes, please see the file @@ -40,6 +40,10 @@ For a detailed list of changes, please see the file
40 - New C++ API calls: ``QPDF::writeJSON``, 40 - New C++ API calls: ``QPDF::writeJSON``,
41 ``QPDF::createFromJSON``, ``QPDF::updateFromJSON`` 41 ``QPDF::createFromJSON``, ``QPDF::updateFromJSON``
42 42
  43 + - New C API calls: ``qpdf_create_from_json_file``,
  44 + ``qpdf_create_from_json_data``, ``qpdf_update_from_json_file``,
  45 + ``qpdf_update_from_json_data``, and ``qpdf_write_json``.
  46 +
43 - Complete documentation can be found at :ref:`json`. A 47 - Complete documentation can be found at :ref:`json`. A
44 comprehensive list of changes from version 1 to version 2 can be 48 comprehensive list of changes from version 1 to version 2 can be
45 found at :ref:`json-v2-changes`. 49 found at :ref:`json-v2-changes`.
qpdf/qpdf-ctest.c
@@ -133,6 +133,13 @@ count_progress(int percent, void* data) @@ -133,6 +133,13 @@ count_progress(int percent, void* data)
133 ++(*(int*)data); 133 ++(*(int*)data);
134 } 134 }
135 135
  136 +static int
  137 +write_to_file(char const* data, size_t size, void* udata)
  138 +{
  139 + FILE* f = (FILE*)udata;
  140 + return fwrite(data, 1, size, f) != size;
  141 +}
  142 +
136 static void 143 static void
137 test01( 144 test01(
138 char const* infile, 145 char const* infile,
@@ -1458,7 +1465,7 @@ test41( @@ -1458,7 +1465,7 @@ test41(
1458 char const* outfile, 1465 char const* outfile,
1459 char const* xarg) 1466 char const* xarg)
1460 { 1467 {
1461 - /* Empty PDF -- infile is ignored*/ 1468 + /* Empty PDF -- infile is ignored */
1462 assert(qpdf_empty_pdf(qpdf) == 0); 1469 assert(qpdf_empty_pdf(qpdf) == 0);
1463 qpdf_init_write(qpdf, outfile); 1470 qpdf_init_write(qpdf, outfile);
1464 qpdf_set_static_ID(qpdf, QPDF_TRUE); 1471 qpdf_set_static_ID(qpdf, QPDF_TRUE);
@@ -1466,6 +1473,110 @@ test41( @@ -1466,6 +1473,110 @@ test41(
1466 report_errors(); 1473 report_errors();
1467 } 1474 }
1468 1475
  1476 +static void
  1477 +test42(
  1478 + char const* infile,
  1479 + char const* password,
  1480 + char const* outfile,
  1481 + char const* xarg)
  1482 +{
  1483 + assert(qpdf_create_from_json_file(qpdf, infile) == QPDF_SUCCESS);
  1484 + qpdf_init_write(qpdf, outfile);
  1485 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  1486 + qpdf_write(qpdf);
  1487 + report_errors();
  1488 +}
  1489 +
  1490 +static void
  1491 +test43(
  1492 + char const* infile,
  1493 + char const* password,
  1494 + char const* outfile,
  1495 + char const* xarg)
  1496 +{
  1497 + char* buf = NULL;
  1498 + unsigned long size = 0;
  1499 + read_file_into_memory(infile, &buf, &size);
  1500 + assert(qpdf_create_from_json_data(qpdf, buf, size) == QPDF_SUCCESS);
  1501 + qpdf_init_write(qpdf, outfile);
  1502 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  1503 + qpdf_write(qpdf);
  1504 + report_errors();
  1505 + free(buf);
  1506 +}
  1507 +
  1508 +static void
  1509 +test44(
  1510 + char const* infile,
  1511 + char const* password,
  1512 + char const* outfile,
  1513 + char const* xarg)
  1514 +{
  1515 + assert(qpdf_read(qpdf, infile, password) == 0);
  1516 + assert(qpdf_update_from_json_file(qpdf, xarg) == QPDF_SUCCESS);
  1517 + qpdf_init_write(qpdf, outfile);
  1518 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  1519 + qpdf_write(qpdf);
  1520 + report_errors();
  1521 +}
  1522 +
  1523 +static void
  1524 +test45(
  1525 + char const* infile,
  1526 + char const* password,
  1527 + char const* outfile,
  1528 + char const* xarg)
  1529 +{
  1530 + char* buf = NULL;
  1531 + unsigned long size = 0;
  1532 + read_file_into_memory(xarg, &buf, &size);
  1533 + assert(qpdf_read(qpdf, infile, password) == 0);
  1534 + assert(qpdf_update_from_json_data(qpdf, buf, size) == QPDF_SUCCESS);
  1535 + qpdf_init_write(qpdf, outfile);
  1536 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  1537 + qpdf_write(qpdf);
  1538 + report_errors();
  1539 + free(buf);
  1540 +}
  1541 +
  1542 +static void
  1543 +test46(
  1544 + char const* infile,
  1545 + char const* password,
  1546 + char const* outfile,
  1547 + char const* xarg)
  1548 +{
  1549 + FILE* f = safe_fopen(outfile, "wb");
  1550 + assert(qpdf_read(qpdf, infile, password) == 0);
  1551 + qpdf_write_json(
  1552 + qpdf, 2, write_to_file, f, qpdf_dl_none, qpdf_sj_inline, "", NULL);
  1553 + fclose(f);
  1554 + report_errors();
  1555 +}
  1556 +
  1557 +static void
  1558 +test47(
  1559 + char const* infile,
  1560 + char const* password,
  1561 + char const* outfile,
  1562 + char const* xarg)
  1563 +{
  1564 + FILE* f = safe_fopen(outfile, "wb");
  1565 + assert(qpdf_read(qpdf, infile, password) == 0);
  1566 + char const* wanted_objects[] = {"obj:4 0 R", "trailer", NULL};
  1567 + qpdf_write_json(
  1568 + qpdf,
  1569 + 2,
  1570 + write_to_file,
  1571 + f,
  1572 + qpdf_dl_specialized,
  1573 + qpdf_sj_file,
  1574 + xarg,
  1575 + wanted_objects);
  1576 + fclose(f);
  1577 + report_errors();
  1578 +}
  1579 +
1469 int 1580 int
1470 main(int argc, char* argv[]) 1581 main(int argc, char* argv[])
1471 { 1582 {
@@ -1542,6 +1653,12 @@ main(int argc, char* argv[]) @@ -1542,6 +1653,12 @@ main(int argc, char* argv[])
1542 : (n == 39) ? test39 1653 : (n == 39) ? test39
1543 : (n == 40) ? test40 1654 : (n == 40) ? test40
1544 : (n == 41) ? test41 1655 : (n == 41) ? test41
  1656 + : (n == 42) ? test42
  1657 + : (n == 43) ? test43
  1658 + : (n == 44) ? test44
  1659 + : (n == 45) ? test45
  1660 + : (n == 46) ? test46
  1661 + : (n == 47) ? test47
1545 : 0); 1662 : 0);
1546 1663
1547 if (fn == 0) { 1664 if (fn == 0) {
qpdf/qtest/qpdf-json.test
@@ -288,5 +288,58 @@ $td-&gt;runtest(&quot;simple version of writeJSON&quot;, @@ -288,5 +288,58 @@ $td-&gt;runtest(&quot;simple version of writeJSON&quot;,
288 {$td->FILE => "minimal-write-json.json", $td->EXIT_STATUS => 0}, 288 {$td->FILE => "minimal-write-json.json", $td->EXIT_STATUS => 0},
289 $td->NORMALIZE_NEWLINES); 289 $td->NORMALIZE_NEWLINES);
290 290
  291 +$n_tests += 13;
  292 +$td->runtest("C API create from json file",
  293 + {$td->COMMAND => "qpdf-ctest 42 minimal.json '' a.pdf"},
  294 + {$td->STRING => "C test 42 done\n", $td->EXIT_STATUS => 0},
  295 + $td->NORMALIZE_NEWLINES);
  296 +$td->runtest("check C API create from file",
  297 + {$td->FILE => "a.pdf"},
  298 + {$td->FILE => "qpdf-ctest-42-43.pdf"});
  299 +$td->runtest("C API create from json buffer",
  300 + {$td->COMMAND => "qpdf-ctest 43 minimal.json '' a.pdf"},
  301 + {$td->STRING => "C test 43 done\n", $td->EXIT_STATUS => 0},
  302 + $td->NORMALIZE_NEWLINES);
  303 +$td->runtest("check C API create from buffer",
  304 + {$td->FILE => "a.pdf"},
  305 + {$td->FILE => "qpdf-ctest-42-43.pdf"});
  306 +$td->runtest("C API update from json file",
  307 + {$td->COMMAND =>
  308 + "qpdf-ctest 44 minimal.pdf '' a.pdf minimal-update.json"},
  309 + {$td->STRING => "C test 44 done\n", $td->EXIT_STATUS => 0},
  310 + $td->NORMALIZE_NEWLINES);
  311 +$td->runtest("check C API update from file",
  312 + {$td->FILE => "a.pdf"},
  313 + {$td->FILE => "qpdf-ctest-44-45.pdf"});
  314 +$td->runtest("C API update from json buffer",
  315 + {$td->COMMAND =>
  316 + "qpdf-ctest 45 minimal.pdf '' a.pdf minimal-update.json"},
  317 + {$td->STRING => "C test 45 done\n", $td->EXIT_STATUS => 0},
  318 + $td->NORMALIZE_NEWLINES);
  319 +$td->runtest("check C API update from buffer",
  320 + {$td->FILE => "a.pdf"},
  321 + {$td->FILE => "qpdf-ctest-44-45.pdf"});
  322 +$td->runtest("C API write to JSON 1",
  323 + {$td->COMMAND =>
  324 + "qpdf-ctest 46 minimal.pdf '' a.json"},
  325 + {$td->STRING => "C test 46 done\n", $td->EXIT_STATUS => 0},
  326 + $td->NORMALIZE_NEWLINES);
  327 +$td->runtest("check C API write to JSON 1",
  328 + {$td->FILE => "a.json"},
  329 + {$td->FILE => "qpdf-ctest-46.json"},
  330 + $td->NORMALIZE_NEWLINES);
  331 +$td->runtest("C API write to JSON 2",
  332 + {$td->COMMAND =>
  333 + "qpdf-ctest 47 minimal.pdf '' a.json auto"},
  334 + {$td->STRING => "C test 47 done\n", $td->EXIT_STATUS => 0},
  335 + $td->NORMALIZE_NEWLINES);
  336 +$td->runtest("check C API write to JSON 2",
  337 + {$td->FILE => "a.json"},
  338 + {$td->FILE => "qpdf-ctest-47.json"},
  339 + $td->NORMALIZE_NEWLINES);
  340 +$td->runtest("check C API write to JSON stream",
  341 + {$td->FILE => "auto-4"},
  342 + {$td->FILE => "qpdf-ctest-47-4"});
  343 +
291 cleanup(); 344 cleanup();
292 $td->report($n_tests); 345 $td->report($n_tests);
qpdf/qtest/qpdf/minimal-update.json 0 → 100644
  1 +{
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pushedinheritedpageresources": false,
  6 + "calledgetallpages": false
  7 + },
  8 + {
  9 + "obj:4 0 R": {
  10 + "stream": {
  11 + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoU2FsYWQpIFRqCkVUCg==",
  12 + "dict": {}
  13 + }
  14 + }
  15 + }
  16 + ]
  17 +}
qpdf/qtest/qpdf/minimal.json 0 → 100644
  1 +{
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
  11 + "obj:1 0 R": {
  12 + "value": {
  13 + "/Pages": "2 0 R",
  14 + "/Type": "/Catalog"
  15 + }
  16 + },
  17 + "obj:2 0 R": {
  18 + "value": {
  19 + "/Count": 1,
  20 + "/Kids": [
  21 + "3 0 R"
  22 + ],
  23 + "/Type": "/Pages"
  24 + }
  25 + },
  26 + "obj:3 0 R": {
  27 + "value": {
  28 + "/Contents": "4 0 R",
  29 + "/MediaBox": [
  30 + 0,
  31 + 0,
  32 + 612,
  33 + 792
  34 + ],
  35 + "/Parent": "2 0 R",
  36 + "/Resources": {
  37 + "/Font": {
  38 + "/F1": "6 0 R"
  39 + },
  40 + "/ProcSet": "5 0 R"
  41 + },
  42 + "/Type": "/Page"
  43 + }
  44 + },
  45 + "obj:4 0 R": {
  46 + "stream": {
  47 + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=",
  48 + "dict": {}
  49 + }
  50 + },
  51 + "obj:5 0 R": {
  52 + "value": [
  53 + "/PDF",
  54 + "/Text"
  55 + ]
  56 + },
  57 + "obj:6 0 R": {
  58 + "value": {
  59 + "/BaseFont": "/Helvetica",
  60 + "/Encoding": "/WinAnsiEncoding",
  61 + "/Name": "/F1",
  62 + "/Subtype": "/Type1",
  63 + "/Type": "/Font"
  64 + }
  65 + },
  66 + "trailer": {
  67 + "value": {
  68 + "/Root": "1 0 R",
  69 + "/Size": 7
  70 + }
  71 + }
  72 + }
  73 + ]
  74 +}
qpdf/qtest/qpdf/qpdf-ctest-42-43.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/qpdf-ctest-44-45.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/qpdf-ctest-46.json 0 → 100644
  1 +{
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
  11 + "obj:1 0 R": {
  12 + "value": {
  13 + "/Pages": "2 0 R",
  14 + "/Type": "/Catalog"
  15 + }
  16 + },
  17 + "obj:2 0 R": {
  18 + "value": {
  19 + "/Count": 1,
  20 + "/Kids": [
  21 + "3 0 R"
  22 + ],
  23 + "/Type": "/Pages"
  24 + }
  25 + },
  26 + "obj:3 0 R": {
  27 + "value": {
  28 + "/Contents": "4 0 R",
  29 + "/MediaBox": [
  30 + 0,
  31 + 0,
  32 + 612,
  33 + 792
  34 + ],
  35 + "/Parent": "2 0 R",
  36 + "/Resources": {
  37 + "/Font": {
  38 + "/F1": "6 0 R"
  39 + },
  40 + "/ProcSet": "5 0 R"
  41 + },
  42 + "/Type": "/Page"
  43 + }
  44 + },
  45 + "obj:4 0 R": {
  46 + "stream": {
  47 + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=",
  48 + "dict": {}
  49 + }
  50 + },
  51 + "obj:5 0 R": {
  52 + "value": [
  53 + "/PDF",
  54 + "/Text"
  55 + ]
  56 + },
  57 + "obj:6 0 R": {
  58 + "value": {
  59 + "/BaseFont": "/Helvetica",
  60 + "/Encoding": "/WinAnsiEncoding",
  61 + "/Name": "/F1",
  62 + "/Subtype": "/Type1",
  63 + "/Type": "/Font"
  64 + }
  65 + },
  66 + "trailer": {
  67 + "value": {
  68 + "/Root": "1 0 R",
  69 + "/Size": 7
  70 + }
  71 + }
  72 + }
  73 + ]
  74 +}
qpdf/qtest/qpdf/qpdf-ctest-47-4 0 → 100644
  1 +BT
  2 + /F1 24 Tf
  3 + 72 720 Td
  4 + (Potato) Tj
  5 +ET
qpdf/qtest/qpdf/qpdf-ctest-47.json 0 → 100644
  1 +{
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
  11 + "obj:4 0 R": {
  12 + "stream": {
  13 + "datafile": "auto-4",
  14 + "dict": {}
  15 + }
  16 + },
  17 + "trailer": {
  18 + "value": {
  19 + "/Root": "1 0 R",
  20 + "/Size": 7
  21 + }
  22 + }
  23 + }
  24 + ]
  25 +}