Commit f1a2d3160a1dbaf735cce597d0f6f40e76f7f223
1 parent
66f1fd2a
Add JSON v2 support to C API
Showing
14 changed files
with
535 additions
and
11 deletions
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 |
TODO
| @@ -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 "C" { | @@ -257,8 +257,6 @@ extern "C" { | ||
| 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 "C" { | @@ -267,6 +265,10 @@ extern "C" { | ||
| 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 "C" { | @@ -297,8 +299,40 @@ extern "C" { | ||
| 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 "C" { | @@ -371,6 +405,39 @@ extern "C" { | ||
| 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->runtest("simple version of writeJSON", | @@ -288,5 +288,58 @@ $td->runtest("simple version of writeJSON", | ||
| 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
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
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 | +} |