Commit 20509770999f705c25670bb14a8bb83aa1cc5b96

Authored by Jay Berkenbilt
1 parent 78b9d6bf

Add QPDFObjectHandle manipulation to C API

ChangeLog
  1 +2020-11-28 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add new functions to the C API for manipulating
  4 + QPDFObjectHandles. The new functions allow creation and
  5 + modification of objects, which brings a lot of additional power to
  6 + the C API. See include/qpdf/qpdf-c.h for details and
  7 + examples/pdf-c-objects.c for a simple example.
  8 +
1 2020-11-21 Jay Berkenbilt <ejb@ql.org> 9 2020-11-21 Jay Berkenbilt <ejb@ql.org>
2 10
3 * 10.0.4: release 11 * 10.0.4: release
examples/build.mk
@@ -11,7 +11,9 @@ BINS_examples = \ @@ -11,7 +11,9 @@ BINS_examples = \
11 pdf-count-strings \ 11 pdf-count-strings \
12 pdf-set-form-values \ 12 pdf-set-form-values \
13 pdf-overlay-page 13 pdf-overlay-page
14 -CBINS_examples = pdf-linearize 14 +CBINS_examples = \
  15 + pdf-c-objects \
  16 + pdf-linearize
15 17
16 TARGETS_examples = $(foreach B,$(BINS_examples) $(CBINS_examples),examples/$(OUTPUT_DIR)/$(call binname,$(B))) 18 TARGETS_examples = $(foreach B,$(BINS_examples) $(CBINS_examples),examples/$(OUTPUT_DIR)/$(call binname,$(B)))
17 19
examples/pdf-c-objects.c 0 → 100644
  1 +/*
  2 + * This is an example program to demonstrate use of object handle
  3 + * functions in the C API.
  4 + */
  5 +
  6 +#include <qpdf/qpdf-c.h>
  7 +#include <stdio.h>
  8 +#include <stdlib.h>
  9 +#include <string.h>
  10 +
  11 +static char const* whoami = 0;
  12 +
  13 +static void usage()
  14 +{
  15 + fprintf(stderr, "Usage: %s infile infile-password outfile\n", whoami);
  16 + exit(2);
  17 +}
  18 +
  19 +QPDF_BOOL
  20 +modify_file(qpdf_data qpdf)
  21 +{
  22 + /* This small example performs the following operation on the
  23 + * document catalog (a.k.a. root):
  24 + * - Remove PageLayout
  25 + * - Remove OpenAction
  26 + * - If there are outlines, set PageMode to UseOutlines; otherwise,
  27 + * remove it.
  28 + */
  29 +
  30 + qpdf_oh root = qpdf_get_root(qpdf);
  31 + qpdf_oh_remove_key(qpdf, root, "/PageLayout");
  32 + qpdf_oh_remove_key(qpdf, root, "/OpenAction");
  33 + /* 0 is never a valid qpdf_oh */
  34 + qpdf_oh pagemode = 0;
  35 + if (qpdf_oh_is_dictionary(
  36 + qpdf, qpdf_oh_get_key(qpdf, root, "/PageLabels")))
  37 + {
  38 + pagemode = qpdf_oh_new_name(qpdf, "/UseOutlines");
  39 + }
  40 + else
  41 + {
  42 + pagemode = qpdf_oh_new_null(qpdf);
  43 + }
  44 + qpdf_oh_replace_or_remove_key(qpdf, root, "/PageMode", pagemode);
  45 +
  46 + return QPDF_TRUE;
  47 +}
  48 +
  49 +int main(int argc, char* argv[])
  50 +{
  51 + char* infile = NULL;
  52 + char* password = NULL;
  53 + char* outfile = NULL;
  54 + qpdf_data qpdf = qpdf_init();
  55 + int warnings = 0;
  56 + int errors = 0;
  57 + char* p = 0;
  58 +
  59 + if ((p = strrchr(argv[0], '/')) != NULL)
  60 + {
  61 + whoami = p + 1;
  62 + }
  63 + else if ((p = strrchr(argv[0], '\\')) != NULL)
  64 + {
  65 + whoami = p + 1;
  66 + }
  67 + else
  68 + {
  69 + whoami = argv[0];
  70 + }
  71 +
  72 + if (argc != 4)
  73 + {
  74 + usage();
  75 + }
  76 +
  77 + infile = argv[1];
  78 + password = argv[2];
  79 + outfile = argv[3];
  80 +
  81 + if (((qpdf_read(qpdf, infile, password) & QPDF_ERRORS) == 0) &&
  82 + modify_file(qpdf) &&
  83 + ((qpdf_init_write(qpdf, outfile) & QPDF_ERRORS) == 0))
  84 + {
  85 + /* Use static ID for testing only. For production, a
  86 + * non-static ID is used. See also
  87 + * qpdf_set_deterministic_ID. */
  88 + qpdf_set_static_ID(qpdf, QPDF_TRUE); /* for testing only */
  89 + qpdf_write(qpdf);
  90 + }
  91 + while (qpdf_more_warnings(qpdf))
  92 + {
  93 + warnings = 1;
  94 + printf("warning: %s\n",
  95 + qpdf_get_error_full_text(qpdf, qpdf_next_warning(qpdf)));
  96 + }
  97 + if (qpdf_has_error(qpdf))
  98 + {
  99 + errors = 1;
  100 + printf("error: %s\n",
  101 + qpdf_get_error_full_text(qpdf, qpdf_get_error(qpdf)));
  102 + }
  103 + qpdf_cleanup(&qpdf);
  104 + if (errors)
  105 + {
  106 + return 2;
  107 + }
  108 + else if (warnings)
  109 + {
  110 + return 3;
  111 + }
  112 +
  113 + return 0;
  114 +}
examples/qtest/c-objects.test 0 → 100644
  1 +#!/usr/bin/env perl
  2 +require 5.008;
  3 +BEGIN { $^W = 1; }
  4 +use strict;
  5 +
  6 +chdir("c-objects") or die "chdir testdir failed: $!\n";
  7 +
  8 +require TestDriver;
  9 +
  10 +cleanup();
  11 +
  12 +my $td = new TestDriver('c-objects');
  13 +
  14 +my $qpdf = $ENV{'QPDF_BIN'} or die;
  15 +
  16 +foreach my $i (qw(1 2))
  17 +{
  18 + $td->runtest("c-objects ($i)",
  19 + {$td->COMMAND => "pdf-c-objects $i.pdf '' a.pdf"},
  20 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  21 + $td->runtest("check output",
  22 + {$td->FILE => "a.pdf"},
  23 + {$td->FILE => "$i-out.pdf"});
  24 +}
  25 +
  26 +cleanup();
  27 +
  28 +$td->report(4);
  29 +
  30 +sub cleanup
  31 +{
  32 + unlink "a.pdf";
  33 +}
examples/qtest/c-objects/1-out.pdf 0 → 100644
No preview for this file type
examples/qtest/c-objects/1.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +1 0 obj
  6 +<<
  7 + /PageLabels << /Nums [
  8 + 0 << /P () >>
  9 + 2 << /S /r /St 1 >>
  10 + 7 << /P () >>
  11 + 9 << /S /r /St 6 >>
  12 + 11 << /P () >>
  13 + 12 << /S /D /St 2 >>
  14 + 15 << /S /D /St 6 >>
  15 + 19 << /P () >>
  16 + 20 << /S /D /St 12 >>
  17 + 22 << /S /D /St 16059 >>
  18 + 23 << /S /r /St 50 >>
  19 + 29 << /S /r /St 54 >>
  20 + ] >>
  21 + /Pages 2 0 R
  22 + /Type /Catalog
  23 + /Outlines 95 0 R
  24 +>>
  25 +endobj
  26 +
  27 +2 0 obj
  28 +<<
  29 + /Count 30
  30 + /Kids [
  31 + 3 0 R
  32 + 4 0 R
  33 + 5 0 R
  34 + 6 0 R
  35 + 7 0 R
  36 + 8 0 R
  37 + 9 0 R
  38 + 10 0 R
  39 + 11 0 R
  40 + 12 0 R
  41 + 13 0 R
  42 + 14 0 R
  43 + 15 0 R
  44 + 16 0 R
  45 + 17 0 R
  46 + 18 0 R
  47 + 19 0 R
  48 + 20 0 R
  49 + 21 0 R
  50 + 22 0 R
  51 + 23 0 R
  52 + 24 0 R
  53 + 25 0 R
  54 + 26 0 R
  55 + 27 0 R
  56 + 28 0 R
  57 + 29 0 R
  58 + 30 0 R
  59 + 31 0 R
  60 + 32 0 R
  61 + ]
  62 + /Type /Pages
  63 +>>
  64 +endobj
  65 +
  66 +%% Page 1
  67 +3 0 obj
  68 +<<
  69 + /Contents 33 0 R
  70 + /MediaBox [
  71 + 0
  72 + 0
  73 + 612
  74 + 792
  75 + ]
  76 + /Parent 2 0 R
  77 + /Resources <<
  78 + /Font <<
  79 + /F1 35 0 R
  80 + >>
  81 + /ProcSet 36 0 R
  82 + >>
  83 + /Type /Page
  84 +>>
  85 +endobj
  86 +
  87 +%% Page 2
  88 +4 0 obj
  89 +<<
  90 + /Contents 37 0 R
  91 + /MediaBox [
  92 + 0
  93 + 0
  94 + 612
  95 + 792
  96 + ]
  97 + /Parent 2 0 R
  98 + /Resources <<
  99 + /Font <<
  100 + /F1 35 0 R
  101 + >>
  102 + /ProcSet 36 0 R
  103 + >>
  104 + /Type /Page
  105 +>>
  106 +endobj
  107 +
  108 +%% Page 3
  109 +5 0 obj
  110 +<<
  111 + /Contents 39 0 R
  112 + /MediaBox [
  113 + 0
  114 + 0
  115 + 612
  116 + 792
  117 + ]
  118 + /Parent 2 0 R
  119 + /Resources <<
  120 + /Font <<
  121 + /F1 35 0 R
  122 + >>
  123 + /ProcSet 36 0 R
  124 + >>
  125 + /Type /Page
  126 +>>
  127 +endobj
  128 +
  129 +%% Page 4
  130 +6 0 obj
  131 +<<
  132 + /Contents 41 0 R
  133 + /MediaBox [
  134 + 0
  135 + 0
  136 + 612
  137 + 792
  138 + ]
  139 + /Parent 2 0 R
  140 + /Resources <<
  141 + /Font <<
  142 + /F1 35 0 R
  143 + >>
  144 + /ProcSet 36 0 R
  145 + >>
  146 + /Type /Page
  147 +>>
  148 +endobj
  149 +
  150 +%% Page 5
  151 +7 0 obj
  152 +<<
  153 + /Contents 43 0 R
  154 + /MediaBox [
  155 + 0
  156 + 0
  157 + 612
  158 + 792
  159 + ]
  160 + /Parent 2 0 R
  161 + /Resources <<
  162 + /Font <<
  163 + /F1 35 0 R
  164 + >>
  165 + /ProcSet 36 0 R
  166 + >>
  167 + /Type /Page
  168 +>>
  169 +endobj
  170 +
  171 +%% Page 6
  172 +8 0 obj
  173 +<<
  174 + /Contents 45 0 R
  175 + /MediaBox [
  176 + 0
  177 + 0
  178 + 612
  179 + 792
  180 + ]
  181 + /Parent 2 0 R
  182 + /Resources <<
  183 + /Font <<
  184 + /F1 35 0 R
  185 + >>
  186 + /ProcSet 36 0 R
  187 + >>
  188 + /Type /Page
  189 +>>
  190 +endobj
  191 +
  192 +%% Page 7
  193 +9 0 obj
  194 +<<
  195 + /Contents 47 0 R
  196 + /MediaBox [
  197 + 0
  198 + 0
  199 + 612
  200 + 792
  201 + ]
  202 + /Parent 2 0 R
  203 + /Resources <<
  204 + /Font <<
  205 + /F1 35 0 R
  206 + >>
  207 + /ProcSet 36 0 R
  208 + >>
  209 + /Type /Page
  210 +>>
  211 +endobj
  212 +
  213 +%% Page 8
  214 +10 0 obj
  215 +<<
  216 + /Contents 49 0 R
  217 + /MediaBox [
  218 + 0
  219 + 0
  220 + 612
  221 + 792
  222 + ]
  223 + /Parent 2 0 R
  224 + /Resources <<
  225 + /Font <<
  226 + /F1 35 0 R
  227 + >>
  228 + /ProcSet 36 0 R
  229 + >>
  230 + /Type /Page
  231 +>>
  232 +endobj
  233 +
  234 +%% Page 9
  235 +11 0 obj
  236 +<<
  237 + /Contents 51 0 R
  238 + /MediaBox [
  239 + 0
  240 + 0
  241 + 612
  242 + 792
  243 + ]
  244 + /Parent 2 0 R
  245 + /Resources <<
  246 + /Font <<
  247 + /F1 35 0 R
  248 + >>
  249 + /ProcSet 36 0 R
  250 + >>
  251 + /Type /Page
  252 +>>
  253 +endobj
  254 +
  255 +%% Page 10
  256 +12 0 obj
  257 +<<
  258 + /Contents 53 0 R
  259 + /MediaBox [
  260 + 0
  261 + 0
  262 + 612
  263 + 792
  264 + ]
  265 + /Parent 2 0 R
  266 + /Resources <<
  267 + /Font <<
  268 + /F1 35 0 R
  269 + >>
  270 + /ProcSet 36 0 R
  271 + >>
  272 + /Type /Page
  273 +>>
  274 +endobj
  275 +
  276 +%% Page 11
  277 +13 0 obj
  278 +<<
  279 + /Contents 55 0 R
  280 + /MediaBox [
  281 + 0
  282 + 0
  283 + 612
  284 + 792
  285 + ]
  286 + /Parent 2 0 R
  287 + /Resources <<
  288 + /Font <<
  289 + /F1 35 0 R
  290 + >>
  291 + /ProcSet 36 0 R
  292 + >>
  293 + /Type /Page
  294 +>>
  295 +endobj
  296 +
  297 +%% Page 12
  298 +14 0 obj
  299 +<<
  300 + /Contents 57 0 R
  301 + /MediaBox [
  302 + 0
  303 + 0
  304 + 612
  305 + 792
  306 + ]
  307 + /Parent 2 0 R
  308 + /Resources <<
  309 + /Font <<
  310 + /F1 35 0 R
  311 + >>
  312 + /ProcSet 36 0 R
  313 + >>
  314 + /Type /Page
  315 +>>
  316 +endobj
  317 +
  318 +%% Page 13
  319 +15 0 obj
  320 +<<
  321 + /Contents 59 0 R
  322 + /MediaBox [
  323 + 0
  324 + 0
  325 + 612
  326 + 792
  327 + ]
  328 + /Parent 2 0 R
  329 + /Resources <<
  330 + /Font <<
  331 + /F1 35 0 R
  332 + >>
  333 + /ProcSet 36 0 R
  334 + >>
  335 + /Type /Page
  336 +>>
  337 +endobj
  338 +
  339 +%% Page 14
  340 +16 0 obj
  341 +<<
  342 + /Contents 61 0 R
  343 + /MediaBox [
  344 + 0
  345 + 0
  346 + 612
  347 + 792
  348 + ]
  349 + /Parent 2 0 R
  350 + /Resources <<
  351 + /Font <<
  352 + /F1 35 0 R
  353 + >>
  354 + /ProcSet 36 0 R
  355 + >>
  356 + /Type /Page
  357 +>>
  358 +endobj
  359 +
  360 +%% Page 15
  361 +17 0 obj
  362 +<<
  363 + /Contents 63 0 R
  364 + /MediaBox [
  365 + 0
  366 + 0
  367 + 612
  368 + 792
  369 + ]
  370 + /Parent 2 0 R
  371 + /Resources <<
  372 + /Font <<
  373 + /F1 35 0 R
  374 + >>
  375 + /ProcSet 36 0 R
  376 + >>
  377 + /Type /Page
  378 +>>
  379 +endobj
  380 +
  381 +%% Page 16
  382 +18 0 obj
  383 +<<
  384 + /Contents 65 0 R
  385 + /MediaBox [
  386 + 0
  387 + 0
  388 + 612
  389 + 792
  390 + ]
  391 + /Parent 2 0 R
  392 + /Resources <<
  393 + /Font <<
  394 + /F1 35 0 R
  395 + >>
  396 + /ProcSet 36 0 R
  397 + >>
  398 + /Type /Page
  399 +>>
  400 +endobj
  401 +
  402 +%% Page 17
  403 +19 0 obj
  404 +<<
  405 + /Contents 67 0 R
  406 + /MediaBox [
  407 + 0
  408 + 0
  409 + 612
  410 + 792
  411 + ]
  412 + /Parent 2 0 R
  413 + /Resources <<
  414 + /Font <<
  415 + /F1 35 0 R
  416 + >>
  417 + /ProcSet 36 0 R
  418 + >>
  419 + /Type /Page
  420 +>>
  421 +endobj
  422 +
  423 +%% Page 18
  424 +20 0 obj
  425 +<<
  426 + /Contents 69 0 R
  427 + /MediaBox [
  428 + 0
  429 + 0
  430 + 612
  431 + 792
  432 + ]
  433 + /Parent 2 0 R
  434 + /Resources <<
  435 + /Font <<
  436 + /F1 35 0 R
  437 + >>
  438 + /ProcSet 36 0 R
  439 + >>
  440 + /Type /Page
  441 +>>
  442 +endobj
  443 +
  444 +%% Page 19
  445 +21 0 obj
  446 +<<
  447 + /Contents 71 0 R
  448 + /MediaBox [
  449 + 0
  450 + 0
  451 + 612
  452 + 792
  453 + ]
  454 + /Parent 2 0 R
  455 + /Resources <<
  456 + /Font <<
  457 + /F1 35 0 R
  458 + >>
  459 + /ProcSet 36 0 R
  460 + >>
  461 + /Type /Page
  462 +>>
  463 +endobj
  464 +
  465 +%% Page 20
  466 +22 0 obj
  467 +<<
  468 + /Contents 73 0 R
  469 + /MediaBox [
  470 + 0
  471 + 0
  472 + 612
  473 + 792
  474 + ]
  475 + /Parent 2 0 R
  476 + /Resources <<
  477 + /Font <<
  478 + /F1 35 0 R
  479 + >>
  480 + /ProcSet 36 0 R
  481 + >>
  482 + /Type /Page
  483 +>>
  484 +endobj
  485 +
  486 +%% Page 21
  487 +23 0 obj
  488 +<<
  489 + /Contents 75 0 R
  490 + /MediaBox [
  491 + 0
  492 + 0
  493 + 612
  494 + 792
  495 + ]
  496 + /Parent 2 0 R
  497 + /Resources <<
  498 + /Font <<
  499 + /F1 35 0 R
  500 + >>
  501 + /ProcSet 36 0 R
  502 + >>
  503 + /Type /Page
  504 +>>
  505 +endobj
  506 +
  507 +%% Page 22
  508 +24 0 obj
  509 +<<
  510 + /Contents 77 0 R
  511 + /MediaBox [
  512 + 0
  513 + 0
  514 + 612
  515 + 792
  516 + ]
  517 + /Parent 2 0 R
  518 + /Resources <<
  519 + /Font <<
  520 + /F1 35 0 R
  521 + >>
  522 + /ProcSet 36 0 R
  523 + >>
  524 + /Type /Page
  525 +>>
  526 +endobj
  527 +
  528 +%% Page 23
  529 +25 0 obj
  530 +<<
  531 + /Contents 79 0 R
  532 + /MediaBox [
  533 + 0
  534 + 0
  535 + 612
  536 + 792
  537 + ]
  538 + /Parent 2 0 R
  539 + /Resources <<
  540 + /Font <<
  541 + /F1 35 0 R
  542 + >>
  543 + /ProcSet 36 0 R
  544 + >>
  545 + /Type /Page
  546 +>>
  547 +endobj
  548 +
  549 +%% Page 24
  550 +26 0 obj
  551 +<<
  552 + /Contents 81 0 R
  553 + /MediaBox [
  554 + 0
  555 + 0
  556 + 612
  557 + 792
  558 + ]
  559 + /Parent 2 0 R
  560 + /Resources <<
  561 + /Font <<
  562 + /F1 35 0 R
  563 + >>
  564 + /ProcSet 36 0 R
  565 + >>
  566 + /Type /Page
  567 +>>
  568 +endobj
  569 +
  570 +%% Page 25
  571 +27 0 obj
  572 +<<
  573 + /Contents 83 0 R
  574 + /MediaBox [
  575 + 0
  576 + 0
  577 + 612
  578 + 792
  579 + ]
  580 + /Parent 2 0 R
  581 + /Resources <<
  582 + /Font <<
  583 + /F1 35 0 R
  584 + >>
  585 + /ProcSet 36 0 R
  586 + >>
  587 + /Type /Page
  588 +>>
  589 +endobj
  590 +
  591 +%% Page 26
  592 +28 0 obj
  593 +<<
  594 + /Contents 85 0 R
  595 + /MediaBox [
  596 + 0
  597 + 0
  598 + 612
  599 + 792
  600 + ]
  601 + /Parent 2 0 R
  602 + /Resources <<
  603 + /Font <<
  604 + /F1 35 0 R
  605 + >>
  606 + /ProcSet 36 0 R
  607 + >>
  608 + /Type /Page
  609 +>>
  610 +endobj
  611 +
  612 +%% Page 27
  613 +29 0 obj
  614 +<<
  615 + /Contents 87 0 R
  616 + /MediaBox [
  617 + 0
  618 + 0
  619 + 612
  620 + 792
  621 + ]
  622 + /Parent 2 0 R
  623 + /Resources <<
  624 + /Font <<
  625 + /F1 35 0 R
  626 + >>
  627 + /ProcSet 36 0 R
  628 + >>
  629 + /Type /Page
  630 +>>
  631 +endobj
  632 +
  633 +%% Page 28
  634 +30 0 obj
  635 +<<
  636 + /Contents 89 0 R
  637 + /MediaBox [
  638 + 0
  639 + 0
  640 + 612
  641 + 792
  642 + ]
  643 + /Parent 2 0 R
  644 + /Resources <<
  645 + /Font <<
  646 + /F1 35 0 R
  647 + >>
  648 + /ProcSet 36 0 R
  649 + >>
  650 + /Type /Page
  651 +>>
  652 +endobj
  653 +
  654 +%% Page 29
  655 +31 0 obj
  656 +<<
  657 + /Contents 91 0 R
  658 + /MediaBox [
  659 + 0
  660 + 0
  661 + 612
  662 + 792
  663 + ]
  664 + /Parent 2 0 R
  665 + /Resources <<
  666 + /Font <<
  667 + /F1 35 0 R
  668 + >>
  669 + /ProcSet 36 0 R
  670 + >>
  671 + /Type /Page
  672 +>>
  673 +endobj
  674 +
  675 +%% Page 30
  676 +32 0 obj
  677 +<<
  678 + /Contents 93 0 R
  679 + /MediaBox [
  680 + 0
  681 + 0
  682 + 612
  683 + 792
  684 + ]
  685 + /Parent 2 0 R
  686 + /Resources <<
  687 + /Font <<
  688 + /F1 35 0 R
  689 + >>
  690 + /ProcSet 36 0 R
  691 + >>
  692 + /Type /Page
  693 +>>
  694 +endobj
  695 +
  696 +%% Contents for page 1
  697 +33 0 obj
  698 +<<
  699 + /Length 34 0 R
  700 +>>
  701 +stream
  702 +BT
  703 + /F1 24 Tf
  704 + 72 720 Td
  705 + (Potato 0) Tj
  706 +ET
  707 +endstream
  708 +endobj
  709 +
  710 +34 0 obj
  711 +46
  712 +endobj
  713 +
  714 +35 0 obj
  715 +<<
  716 + /BaseFont /Helvetica
  717 + /Encoding /WinAnsiEncoding
  718 + /Name /F1
  719 + /Subtype /Type1
  720 + /Type /Font
  721 +>>
  722 +endobj
  723 +
  724 +36 0 obj
  725 +[
  726 + /PDF
  727 + /Text
  728 +]
  729 +endobj
  730 +
  731 +%% Contents for page 2
  732 +37 0 obj
  733 +<<
  734 + /Length 38 0 R
  735 +>>
  736 +stream
  737 +BT
  738 + /F1 24 Tf
  739 + 72 720 Td
  740 + (Potato 1) Tj
  741 +ET
  742 +endstream
  743 +endobj
  744 +
  745 +38 0 obj
  746 +46
  747 +endobj
  748 +
  749 +%% Contents for page 3
  750 +39 0 obj
  751 +<<
  752 + /Length 40 0 R
  753 +>>
  754 +stream
  755 +BT
  756 + /F1 24 Tf
  757 + 72 720 Td
  758 + (Potato 2) Tj
  759 +ET
  760 +endstream
  761 +endobj
  762 +
  763 +40 0 obj
  764 +46
  765 +endobj
  766 +
  767 +%% Contents for page 4
  768 +41 0 obj
  769 +<<
  770 + /Length 42 0 R
  771 +>>
  772 +stream
  773 +BT
  774 + /F1 24 Tf
  775 + 72 720 Td
  776 + (Potato 3) Tj
  777 +ET
  778 +endstream
  779 +endobj
  780 +
  781 +42 0 obj
  782 +46
  783 +endobj
  784 +
  785 +%% Contents for page 5
  786 +43 0 obj
  787 +<<
  788 + /Length 44 0 R
  789 +>>
  790 +stream
  791 +BT
  792 + /F1 24 Tf
  793 + 72 720 Td
  794 + (Potato 4) Tj
  795 +ET
  796 +endstream
  797 +endobj
  798 +
  799 +44 0 obj
  800 +46
  801 +endobj
  802 +
  803 +%% Contents for page 6
  804 +45 0 obj
  805 +<<
  806 + /Length 46 0 R
  807 +>>
  808 +stream
  809 +BT
  810 + /F1 24 Tf
  811 + 72 720 Td
  812 + (Potato 5) Tj
  813 +ET
  814 +endstream
  815 +endobj
  816 +
  817 +46 0 obj
  818 +46
  819 +endobj
  820 +
  821 +%% Contents for page 7
  822 +47 0 obj
  823 +<<
  824 + /Length 48 0 R
  825 +>>
  826 +stream
  827 +BT
  828 + /F1 24 Tf
  829 + 72 720 Td
  830 + (Potato 6) Tj
  831 +ET
  832 +endstream
  833 +endobj
  834 +
  835 +48 0 obj
  836 +46
  837 +endobj
  838 +
  839 +%% Contents for page 8
  840 +49 0 obj
  841 +<<
  842 + /Length 50 0 R
  843 +>>
  844 +stream
  845 +BT
  846 + /F1 24 Tf
  847 + 72 720 Td
  848 + (Potato 7) Tj
  849 +ET
  850 +endstream
  851 +endobj
  852 +
  853 +50 0 obj
  854 +46
  855 +endobj
  856 +
  857 +%% Contents for page 9
  858 +51 0 obj
  859 +<<
  860 + /Length 52 0 R
  861 +>>
  862 +stream
  863 +BT
  864 + /F1 24 Tf
  865 + 72 720 Td
  866 + (Potato 8) Tj
  867 +ET
  868 +endstream
  869 +endobj
  870 +
  871 +52 0 obj
  872 +46
  873 +endobj
  874 +
  875 +%% Contents for page 10
  876 +53 0 obj
  877 +<<
  878 + /Length 54 0 R
  879 +>>
  880 +stream
  881 +BT
  882 + /F1 24 Tf
  883 + 72 720 Td
  884 + (Potato 9) Tj
  885 +ET
  886 +endstream
  887 +endobj
  888 +
  889 +54 0 obj
  890 +46
  891 +endobj
  892 +
  893 +%% Contents for page 11
  894 +55 0 obj
  895 +<<
  896 + /Length 56 0 R
  897 +>>
  898 +stream
  899 +BT
  900 + /F1 24 Tf
  901 + 72 720 Td
  902 + (Potato 10) Tj
  903 +ET
  904 +endstream
  905 +endobj
  906 +
  907 +56 0 obj
  908 +47
  909 +endobj
  910 +
  911 +%% Contents for page 12
  912 +57 0 obj
  913 +<<
  914 + /Length 58 0 R
  915 +>>
  916 +stream
  917 +BT
  918 + /F1 24 Tf
  919 + 72 720 Td
  920 + (Potato 11) Tj
  921 +ET
  922 +endstream
  923 +endobj
  924 +
  925 +58 0 obj
  926 +47
  927 +endobj
  928 +
  929 +%% Contents for page 13
  930 +59 0 obj
  931 +<<
  932 + /Length 60 0 R
  933 +>>
  934 +stream
  935 +BT
  936 + /F1 24 Tf
  937 + 72 720 Td
  938 + (Potato 12) Tj
  939 +ET
  940 +endstream
  941 +endobj
  942 +
  943 +60 0 obj
  944 +47
  945 +endobj
  946 +
  947 +%% Contents for page 14
  948 +61 0 obj
  949 +<<
  950 + /Length 62 0 R
  951 +>>
  952 +stream
  953 +BT
  954 + /F1 24 Tf
  955 + 72 720 Td
  956 + (Potato 13) Tj
  957 +ET
  958 +endstream
  959 +endobj
  960 +
  961 +62 0 obj
  962 +47
  963 +endobj
  964 +
  965 +%% Contents for page 15
  966 +63 0 obj
  967 +<<
  968 + /Length 64 0 R
  969 +>>
  970 +stream
  971 +BT
  972 + /F1 24 Tf
  973 + 72 720 Td
  974 + (Potato 14) Tj
  975 +ET
  976 +endstream
  977 +endobj
  978 +
  979 +64 0 obj
  980 +47
  981 +endobj
  982 +
  983 +%% Contents for page 16
  984 +65 0 obj
  985 +<<
  986 + /Length 66 0 R
  987 +>>
  988 +stream
  989 +BT
  990 + /F1 24 Tf
  991 + 72 720 Td
  992 + (Potato 15) Tj
  993 +ET
  994 +endstream
  995 +endobj
  996 +
  997 +66 0 obj
  998 +47
  999 +endobj
  1000 +
  1001 +%% Contents for page 17
  1002 +67 0 obj
  1003 +<<
  1004 + /Length 68 0 R
  1005 +>>
  1006 +stream
  1007 +BT
  1008 + /F1 24 Tf
  1009 + 72 720 Td
  1010 + (Potato 16) Tj
  1011 +ET
  1012 +endstream
  1013 +endobj
  1014 +
  1015 +68 0 obj
  1016 +47
  1017 +endobj
  1018 +
  1019 +%% Contents for page 18
  1020 +69 0 obj
  1021 +<<
  1022 + /Length 70 0 R
  1023 +>>
  1024 +stream
  1025 +BT
  1026 + /F1 24 Tf
  1027 + 72 720 Td
  1028 + (Potato 17) Tj
  1029 +ET
  1030 +endstream
  1031 +endobj
  1032 +
  1033 +70 0 obj
  1034 +47
  1035 +endobj
  1036 +
  1037 +%% Contents for page 19
  1038 +71 0 obj
  1039 +<<
  1040 + /Length 72 0 R
  1041 +>>
  1042 +stream
  1043 +BT
  1044 + /F1 24 Tf
  1045 + 72 720 Td
  1046 + (Potato 18) Tj
  1047 +ET
  1048 +endstream
  1049 +endobj
  1050 +
  1051 +72 0 obj
  1052 +47
  1053 +endobj
  1054 +
  1055 +%% Contents for page 20
  1056 +73 0 obj
  1057 +<<
  1058 + /Length 74 0 R
  1059 +>>
  1060 +stream
  1061 +BT
  1062 + /F1 24 Tf
  1063 + 72 720 Td
  1064 + (Potato 19) Tj
  1065 +ET
  1066 +endstream
  1067 +endobj
  1068 +
  1069 +74 0 obj
  1070 +47
  1071 +endobj
  1072 +
  1073 +%% Contents for page 21
  1074 +75 0 obj
  1075 +<<
  1076 + /Length 76 0 R
  1077 +>>
  1078 +stream
  1079 +BT
  1080 + /F1 24 Tf
  1081 + 72 720 Td
  1082 + (Potato 20) Tj
  1083 +ET
  1084 +endstream
  1085 +endobj
  1086 +
  1087 +76 0 obj
  1088 +47
  1089 +endobj
  1090 +
  1091 +%% Contents for page 22
  1092 +77 0 obj
  1093 +<<
  1094 + /Length 78 0 R
  1095 +>>
  1096 +stream
  1097 +BT
  1098 + /F1 24 Tf
  1099 + 72 720 Td
  1100 + (Potato 21) Tj
  1101 +ET
  1102 +endstream
  1103 +endobj
  1104 +
  1105 +78 0 obj
  1106 +47
  1107 +endobj
  1108 +
  1109 +%% Contents for page 23
  1110 +79 0 obj
  1111 +<<
  1112 + /Length 80 0 R
  1113 +>>
  1114 +stream
  1115 +BT
  1116 + /F1 24 Tf
  1117 + 72 720 Td
  1118 + (Potato 22) Tj
  1119 +ET
  1120 +endstream
  1121 +endobj
  1122 +
  1123 +80 0 obj
  1124 +47
  1125 +endobj
  1126 +
  1127 +%% Contents for page 24
  1128 +81 0 obj
  1129 +<<
  1130 + /Length 82 0 R
  1131 +>>
  1132 +stream
  1133 +BT
  1134 + /F1 24 Tf
  1135 + 72 720 Td
  1136 + (Potato 23) Tj
  1137 +ET
  1138 +endstream
  1139 +endobj
  1140 +
  1141 +82 0 obj
  1142 +47
  1143 +endobj
  1144 +
  1145 +%% Contents for page 25
  1146 +83 0 obj
  1147 +<<
  1148 + /Length 84 0 R
  1149 +>>
  1150 +stream
  1151 +BT
  1152 + /F1 24 Tf
  1153 + 72 720 Td
  1154 + (Potato 24) Tj
  1155 +ET
  1156 +endstream
  1157 +endobj
  1158 +
  1159 +84 0 obj
  1160 +47
  1161 +endobj
  1162 +
  1163 +%% Contents for page 26
  1164 +85 0 obj
  1165 +<<
  1166 + /Length 86 0 R
  1167 +>>
  1168 +stream
  1169 +BT
  1170 + /F1 24 Tf
  1171 + 72 720 Td
  1172 + (Potato 25) Tj
  1173 +ET
  1174 +endstream
  1175 +endobj
  1176 +
  1177 +86 0 obj
  1178 +47
  1179 +endobj
  1180 +
  1181 +%% Contents for page 27
  1182 +87 0 obj
  1183 +<<
  1184 + /Length 88 0 R
  1185 +>>
  1186 +stream
  1187 +BT
  1188 + /F1 24 Tf
  1189 + 72 720 Td
  1190 + (Potato 26) Tj
  1191 +ET
  1192 +endstream
  1193 +endobj
  1194 +
  1195 +88 0 obj
  1196 +47
  1197 +endobj
  1198 +
  1199 +%% Contents for page 28
  1200 +89 0 obj
  1201 +<<
  1202 + /Length 90 0 R
  1203 +>>
  1204 +stream
  1205 +BT
  1206 + /F1 24 Tf
  1207 + 72 720 Td
  1208 + (Potato 27) Tj
  1209 +ET
  1210 +endstream
  1211 +endobj
  1212 +
  1213 +90 0 obj
  1214 +47
  1215 +endobj
  1216 +
  1217 +%% Contents for page 29
  1218 +91 0 obj
  1219 +<<
  1220 + /Length 92 0 R
  1221 +>>
  1222 +stream
  1223 +BT
  1224 + /F1 24 Tf
  1225 + 72 720 Td
  1226 + (Potato 28) Tj
  1227 +ET
  1228 +endstream
  1229 +endobj
  1230 +
  1231 +92 0 obj
  1232 +47
  1233 +endobj
  1234 +
  1235 +%% Contents for page 30
  1236 +93 0 obj
  1237 +<<
  1238 + /Length 94 0 R
  1239 +>>
  1240 +stream
  1241 +BT
  1242 + /F1 24 Tf
  1243 + 72 720 Td
  1244 + (Potato 29) Tj
  1245 +ET
  1246 +endstream
  1247 +endobj
  1248 +
  1249 +94 0 obj
  1250 +47
  1251 +endobj
  1252 +
  1253 +95 0 obj
  1254 +<<
  1255 + /Type /Outlines
  1256 + /First 97 0 R
  1257 + /Last 96 0 R
  1258 + /Count 6
  1259 +>>
  1260 +endobj
  1261 +
  1262 +96 0 obj
  1263 +<<
  1264 + /Type /Outline
  1265 + /Title (Isis 1 -> 5: /XYZ null null null)
  1266 + /Parent 95 0 R
  1267 + /Count 4
  1268 + /Prev 97 0 R
  1269 + /First 98 0 R
  1270 + /Last 99 0 R
  1271 + /Dest [ 8 0 R /XYZ null null null ]
  1272 +>>
  1273 +endobj
  1274 +
  1275 +97 0 obj
  1276 +<<
  1277 + /Type /Outline
  1278 + /Title (Trepak 2 -> 15: /XYZ 66 756 3)
  1279 + /Parent 95 0 R
  1280 + /Next 96 0 R
  1281 + /Dest [ 18 0 R /XYZ 66 756 3 ]
  1282 +>>
  1283 +endobj
  1284 +
  1285 +98 0 obj
  1286 +<<
  1287 + /Type /Outline
  1288 + /Title (Amanda 1.1 -> 11: /Fit)
  1289 + /Parent 96 0 R
  1290 + /Next 99 0 R
  1291 + /First 100 0 R
  1292 + /Last 101 0 R
  1293 + /Count -3
  1294 + /Dest [ 14 0 R /Fit ]
  1295 +>>
  1296 +endobj
  1297 +
  1298 +99 0 obj
  1299 +<<
  1300 + /Type /Outline
  1301 + /Title (Sandy 1.2 -> 13: /FitH 792)
  1302 + /Parent 96 0 R
  1303 + /Prev 98 0 R
  1304 + /First 105 0 R
  1305 + /Last 106 0 R
  1306 + /Count 2
  1307 + /Dest [ 16 0 R /FitH 792 ]
  1308 +>>
  1309 +endobj
  1310 +
  1311 +100 0 obj
  1312 +<<
  1313 + /Type /Outline
  1314 + /Title (Isosicle 1.1.1 -> 12: /FitV 100)
  1315 + /Parent 98 0 R
  1316 + /Next 101 0 R
  1317 + /First 102 0 R
  1318 + /Last 103 0 R
  1319 + /Count -2
  1320 + /Dest [ 15 0 R /FitV 100 ]
  1321 +>>
  1322 +endobj
  1323 +
  1324 +101 0 obj
  1325 +<<
  1326 + /Type /Outline
  1327 + /Title (Isosicle 1.1.2 -> 12: /XYZ null null null)
  1328 + /Parent 98 0 R
  1329 + /Prev 100 0 R
  1330 + /First 104 0 R
  1331 + /Last 104 0 R
  1332 + /Count 1
  1333 + /Dest [ 15 0 R /XYZ null null null ]
  1334 +>>
  1335 +endobj
  1336 +
  1337 +102 0 obj
  1338 +<<
  1339 + /Type /Outline
  1340 + /Title (Isosicle 1.1.1.1 -> 18: /XYZ null null null)
  1341 + /Parent 100 0 R
  1342 + /Next 103 0 R
  1343 + /Dest [ 21 0 R /XYZ null null null ]
  1344 +>>
  1345 +endobj
  1346 +
  1347 +103 0 obj
  1348 +<<
  1349 + /Type /Outline
  1350 + /Title (Isosicle 1.1.1.2 -> 19: /XYZ null null null)
  1351 + /Parent 100 0 R
  1352 + /Prev 102 0 R
  1353 + /Dest [ 22 0 R /XYZ null null null ]
  1354 +>>
  1355 +endobj
  1356 +
  1357 +104 0 obj
  1358 +<<
  1359 + /Type /Outline
  1360 + /Title (Isosicle 1.1.2.1 -> 22: /XYZ null null null)
  1361 + /Parent 101 0 R
  1362 + /Dest [ 25 0 R /XYZ null null null ]
  1363 +>>
  1364 +endobj
  1365 +
  1366 +105 0 obj
  1367 +<<
  1368 + /Type /Outline
  1369 + /Title (Trepsichord 1.2.1 -> 1: /FitR 66 714 180 770)
  1370 + /Parent 99 0 R
  1371 + /Next 106 0 R
  1372 + /Dest [ 4 0 R /FitR 66 714 180 770 ]
  1373 +>>
  1374 +endobj
  1375 +
  1376 +106 0 obj
  1377 +<<
  1378 + /Type /Outline
  1379 + /Title (Trepsicle 1.2.2 -> 0: /XYZ null null null)
  1380 + /Parent 99 0 R
  1381 + /Prev 105 0 R
  1382 + /Dest [ 3 0 R /XYZ null null null ]
  1383 +>>
  1384 +endobj
  1385 +
  1386 +xref
  1387 +0 107
  1388 +0000000000 65535 f
  1389 +0000000025 00000 n
  1390 +0000000409 00000 n
  1391 +0000000805 00000 n
  1392 +0000001010 00000 n
  1393 +0000001215 00000 n
  1394 +0000001420 00000 n
  1395 +0000001625 00000 n
  1396 +0000001830 00000 n
  1397 +0000002035 00000 n
  1398 +0000002240 00000 n
  1399 +0000002446 00000 n
  1400 +0000002653 00000 n
  1401 +0000002860 00000 n
  1402 +0000003067 00000 n
  1403 +0000003274 00000 n
  1404 +0000003481 00000 n
  1405 +0000003688 00000 n
  1406 +0000003895 00000 n
  1407 +0000004102 00000 n
  1408 +0000004309 00000 n
  1409 +0000004516 00000 n
  1410 +0000004723 00000 n
  1411 +0000004930 00000 n
  1412 +0000005137 00000 n
  1413 +0000005344 00000 n
  1414 +0000005551 00000 n
  1415 +0000005758 00000 n
  1416 +0000005965 00000 n
  1417 +0000006172 00000 n
  1418 +0000006379 00000 n
  1419 +0000006586 00000 n
  1420 +0000006793 00000 n
  1421 +0000007012 00000 n
  1422 +0000007115 00000 n
  1423 +0000007135 00000 n
  1424 +0000007254 00000 n
  1425 +0000007313 00000 n
  1426 +0000007416 00000 n
  1427 +0000007459 00000 n
  1428 +0000007562 00000 n
  1429 +0000007605 00000 n
  1430 +0000007708 00000 n
  1431 +0000007751 00000 n
  1432 +0000007854 00000 n
  1433 +0000007897 00000 n
  1434 +0000008000 00000 n
  1435 +0000008043 00000 n
  1436 +0000008146 00000 n
  1437 +0000008189 00000 n
  1438 +0000008292 00000 n
  1439 +0000008335 00000 n
  1440 +0000008438 00000 n
  1441 +0000008482 00000 n
  1442 +0000008585 00000 n
  1443 +0000008629 00000 n
  1444 +0000008733 00000 n
  1445 +0000008777 00000 n
  1446 +0000008881 00000 n
  1447 +0000008925 00000 n
  1448 +0000009029 00000 n
  1449 +0000009073 00000 n
  1450 +0000009177 00000 n
  1451 +0000009221 00000 n
  1452 +0000009325 00000 n
  1453 +0000009369 00000 n
  1454 +0000009473 00000 n
  1455 +0000009517 00000 n
  1456 +0000009621 00000 n
  1457 +0000009665 00000 n
  1458 +0000009769 00000 n
  1459 +0000009813 00000 n
  1460 +0000009917 00000 n
  1461 +0000009961 00000 n
  1462 +0000010065 00000 n
  1463 +0000010109 00000 n
  1464 +0000010213 00000 n
  1465 +0000010257 00000 n
  1466 +0000010361 00000 n
  1467 +0000010405 00000 n
  1468 +0000010509 00000 n
  1469 +0000010553 00000 n
  1470 +0000010657 00000 n
  1471 +0000010701 00000 n
  1472 +0000010805 00000 n
  1473 +0000010849 00000 n
  1474 +0000010953 00000 n
  1475 +0000010997 00000 n
  1476 +0000011101 00000 n
  1477 +0000011145 00000 n
  1478 +0000011249 00000 n
  1479 +0000011293 00000 n
  1480 +0000011397 00000 n
  1481 +0000011441 00000 n
  1482 +0000011545 00000 n
  1483 +0000011565 00000 n
  1484 +0000011652 00000 n
  1485 +0000011848 00000 n
  1486 +0000011994 00000 n
  1487 +0000012169 00000 n
  1488 +0000012352 00000 n
  1489 +0000012543 00000 n
  1490 +0000012753 00000 n
  1491 +0000012922 00000 n
  1492 +0000013091 00000 n
  1493 +0000013244 00000 n
  1494 +0000013413 00000 n
  1495 +trailer <<
  1496 + /Root 1 0 R
  1497 + /Size 107
  1498 +>>
  1499 +startxref
  1500 +13578
  1501 +%%EOF
examples/qtest/c-objects/2-out.pdf 0 → 100644
No preview for this file type
examples/qtest/c-objects/2.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +1 0 obj
  6 +<<
  7 + /Pages 2 0 R
  8 + /Type /Catalog
  9 + /PageLayout /v1
  10 + /OpenAction /v2
  11 +>>
  12 +endobj
  13 +
  14 +2 0 obj
  15 +<<
  16 + /Count 1
  17 + /Kids [
  18 + 3 0 R
  19 + ]
  20 + /Type /Pages
  21 +>>
  22 +endobj
  23 +
  24 +%% Page 1
  25 +3 0 obj
  26 +<<
  27 + /Contents 4 0 R
  28 + /MediaBox [
  29 + 0
  30 + 0
  31 + 612
  32 + 792
  33 + ]
  34 + /Parent 2 0 R
  35 + /Resources <<
  36 + /Font <<
  37 + /F1 6 0 R
  38 + >>
  39 + /ProcSet 7 0 R
  40 + >>
  41 + /Type /Page
  42 +>>
  43 +endobj
  44 +
  45 +%% Contents for page 1
  46 +4 0 obj
  47 +<<
  48 + /Length 5 0 R
  49 +>>
  50 +stream
  51 +BT
  52 + /F1 24 Tf
  53 + 72 720 Td
  54 + (Potato) Tj
  55 +ET
  56 +endstream
  57 +endobj
  58 +
  59 +5 0 obj
  60 +44
  61 +endobj
  62 +
  63 +6 0 obj
  64 +<<
  65 + /BaseFont /Helvetica
  66 + /Encoding /WinAnsiEncoding
  67 + /Name /F1
  68 + /Subtype /Type1
  69 + /Type /Font
  70 +>>
  71 +endobj
  72 +
  73 +7 0 obj
  74 +[
  75 + /PDF
  76 + /Text
  77 +]
  78 +endobj
  79 +
  80 +xref
  81 +0 8
  82 +0000000000 65535 f
  83 +0000000025 00000 n
  84 +0000000115 00000 n
  85 +0000000197 00000 n
  86 +0000000412 00000 n
  87 +0000000511 00000 n
  88 +0000000530 00000 n
  89 +0000000648 00000 n
  90 +trailer <<
  91 + /Root 1 0 R
  92 + /Size 8
  93 + /ID [<ed2874a4596cc552b835f7f40431a8f5><ed2874a4596cc552b835f7f40431a8f5>]
  94 +>>
  95 +startxref
  96 +683
  97 +%%EOF
include/qpdf/qpdf-c.h
@@ -471,6 +471,230 @@ extern &quot;C&quot; { @@ -471,6 +471,230 @@ extern &quot;C&quot; {
471 QPDF_DLL 471 QPDF_DLL
472 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf); 472 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf);
473 473
  474 + /* Object handling.
  475 + *
  476 + * These methods take and return a qpdf_oh, which is just an
  477 + * unsigned integer. The value 0 is never returned, which makes it
  478 + * usable as an uninitialized value.
  479 + *
  480 + * Each function below, starting with qpdf_oh, corresponds to a
  481 + * specific method of QPDFObjectHandler. For example,
  482 + * qpdf_oh_is_bool corresponds to QPDFObjectHandle::isBool. If the
  483 + * C++ method is overloaded, the C function's name will be
  484 + * disambiguated. If the C++ method takes optional argumens, the C
  485 + * method will have required arguments in those positions. For
  486 + * details about the method, please see comments in
  487 + * QPDFObjectHandle.hh. Comments here only explain things that are
  488 + * specific to the "C" API.
  489 + *
  490 + * Only a fraction of the methods of QPDFObjectHandle are
  491 + * available here. Most of the basic methods for creating,
  492 + * accessing, and modifying most types of objects are present.
  493 + * Most of the higher-level functions are not implemented.
  494 + * Functions for dealing with content streams as well as objects
  495 + * that only exist in content streams (operators and inline
  496 + * images) are mostly not provided.
  497 + *
  498 + * To refer to a specific QPDFObjectHandle, you need a pair
  499 + * consisting of a qpdf_data and a qpdf_oh, which is just an index
  500 + * into an internal table of objects. All memory allocated by any
  501 + * of these methods is returned when qpdf_cleanup is called.
  502 + *
  503 + * Regarding memory, the same rules apply as the above functions.
  504 + * Specifically, if a method returns a char*, the memory is
  505 + * managed by the library and, unless otherwise specified, is not
  506 + * expected to be valid after the next qpdf call.
  507 + *
  508 + * The qpdf_data object keeps a cache of objects returned by these
  509 + * methods. Once you are finished referencing an object, you can
  510 + * optionally release it. Releasing objects is optional since they
  511 + * will all get released by qpdf_cleanup, but it can help to
  512 + * reduce the memory footprint of the qpdf_data object to release
  513 + * them when you're done. Releasing an object does not destroy the
  514 + * object. All QPDFObjectHandle objects are deleted when they are
  515 + * no longer referenced. Releasing an object simply invalidates
  516 + * the qpdf_oh handle to it. For example, if you create an object,
  517 + * add it to an existing dictionary or array, and then release it,
  518 + * the object is safely part of the dictionary or array.
  519 + * Explicitly releasing an object is essentially the same as
  520 + * letting a QPDFObjectHandle go out of scope in the C++ API.
  521 + */
  522 +
  523 + /* For examples of using this API, see examples/pdf-c-objects.c */
  524 +
  525 + typedef unsigned int qpdf_oh;
  526 +
  527 + /* Releasing objects -- see comments above. These methods have no
  528 + * equivalent in the C++ API.
  529 + */
  530 + QPDF_DLL
  531 + void qpdf_oh_release(qpdf_data data, qpdf_oh oh);
  532 + QPDF_DLL
  533 + void qpdf_oh_release_all(qpdf_data data);
  534 +
  535 + /* Get trailer and root objects */
  536 + QPDF_DLL
  537 + qpdf_oh qpdf_get_trailer(qpdf_data data);
  538 + QPDF_DLL
  539 + qpdf_oh qpdf_get_root(qpdf_data data);
  540 +
  541 + /* Wrappers around QPDFObjectHandle methods. Be sure to read
  542 + * corresponding comments in QPDFObjectHandle.hh to understand
  543 + * what each function does and what kinds of objects it applies
  544 + * to.
  545 + */
  546 +
  547 + QPDF_DLL
  548 + QPDF_BOOL qpdf_oh_is_bool(qpdf_data data, qpdf_oh oh);
  549 + QPDF_DLL
  550 + QPDF_BOOL qpdf_oh_is_null(qpdf_data data, qpdf_oh oh);
  551 + QPDF_DLL
  552 + QPDF_BOOL qpdf_oh_is_integer(qpdf_data data, qpdf_oh oh);
  553 + QPDF_DLL
  554 + QPDF_BOOL qpdf_oh_is_real(qpdf_data data, qpdf_oh oh);
  555 + QPDF_DLL
  556 + QPDF_BOOL qpdf_oh_is_name(qpdf_data data, qpdf_oh oh);
  557 + QPDF_DLL
  558 + QPDF_BOOL qpdf_oh_is_string(qpdf_data data, qpdf_oh oh);
  559 + QPDF_DLL
  560 + QPDF_BOOL qpdf_oh_is_operator(qpdf_data data, qpdf_oh oh);
  561 + QPDF_DLL
  562 + QPDF_BOOL qpdf_oh_is_inline_image(qpdf_data data, qpdf_oh oh);
  563 + QPDF_DLL
  564 + QPDF_BOOL qpdf_oh_is_array(qpdf_data data, qpdf_oh oh);
  565 + QPDF_DLL
  566 + QPDF_BOOL qpdf_oh_is_dictionary(qpdf_data data, qpdf_oh oh);
  567 + QPDF_DLL
  568 + QPDF_BOOL qpdf_oh_is_stream(qpdf_data data, qpdf_oh oh);
  569 + QPDF_DLL
  570 + QPDF_BOOL qpdf_oh_is_indirect(qpdf_data data, qpdf_oh oh);
  571 + QPDF_DLL
  572 + QPDF_BOOL qpdf_oh_is_scalar(qpdf_data data, qpdf_oh oh);
  573 +
  574 + QPDF_DLL
  575 + qpdf_oh qpdf_oh_wrap_in_array(qpdf_data data, qpdf_oh oh);
  576 +
  577 + QPDF_DLL
  578 + qpdf_oh qpdf_oh_parse(qpdf_data data, char const* object_str);
  579 +
  580 + QPDF_DLL
  581 + QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data data, qpdf_oh oh);
  582 +
  583 + QPDF_DLL
  584 + long long qpdf_oh_get_int_value(qpdf_data data, qpdf_oh oh);
  585 + QPDF_DLL
  586 + int qpdf_oh_get_int_value_as_int(qpdf_data data, qpdf_oh oh);
  587 + QPDF_DLL
  588 + unsigned long long qpdf_oh_get_uint_value(qpdf_data data, qpdf_oh oh);
  589 + QPDF_DLL
  590 + unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data data, qpdf_oh oh);
  591 +
  592 + QPDF_DLL
  593 + char const* qpdf_oh_get_real_value(qpdf_data data, qpdf_oh oh);
  594 +
  595 + QPDF_DLL
  596 + QPDF_BOOL qpdf_oh_is_number(qpdf_data data, qpdf_oh oh);
  597 + QPDF_DLL
  598 + double qpdf_oh_get_numeric_value(qpdf_data data, qpdf_oh oh);
  599 +
  600 + QPDF_DLL
  601 + char const* qpdf_oh_get_name(qpdf_data data, qpdf_oh oh);
  602 +
  603 + QPDF_DLL
  604 + char const* qpdf_oh_get_string_value(qpdf_data data, qpdf_oh oh);
  605 + QPDF_DLL
  606 + char const* qpdf_oh_get_utf8_value(qpdf_data data, qpdf_oh oh);
  607 +
  608 + QPDF_DLL
  609 + int qpdf_oh_get_array_n_items(qpdf_data data, qpdf_oh oh);
  610 + QPDF_DLL
  611 + qpdf_oh qpdf_oh_get_array_item(qpdf_data data, qpdf_oh oh, int n);
  612 +
  613 + /* "C"-specific dictionary key iteration */
  614 +
  615 + /* Iteration is allowed on only one dictionary at a time. */
  616 + QPDF_DLL
  617 + void qpdf_oh_begin_dict_key_iter(qpdf_data data, qpdf_oh dict);
  618 + QPDF_DLL
  619 + QPDF_BOOL qpdf_oh_dict_more_keys(qpdf_data data);
  620 + /* The memory returned by qpdf_oh_dict_next_key is owned by
  621 + * qpdf_data. It is good until the next call to
  622 + * qpdf_oh_dict_next_key with the same qpdf_data object. Calling
  623 + * the method again, even with a different dict, invalidates
  624 + * previous return values.
  625 + */
  626 + QPDF_DLL
  627 + char const* qpdf_oh_dict_next_key(qpdf_data data);
  628 +
  629 + /* end "C"-specific dictionary key iteration */
  630 +
  631 + QPDF_DLL
  632 + QPDF_BOOL qpdf_oh_has_key(qpdf_data data, qpdf_oh oh, char const* key);
  633 + QPDF_DLL
  634 + qpdf_oh qpdf_oh_get_key(qpdf_data data, qpdf_oh oh, char const* key);
  635 +
  636 + QPDF_DLL
  637 + QPDF_BOOL qpdf_oh_is_or_has_name(
  638 + qpdf_data data, qpdf_oh oh, char const* key);
  639 +
  640 + QPDF_DLL
  641 + qpdf_oh qpdf_oh_new_null(qpdf_data data);
  642 + QPDF_DLL
  643 + qpdf_oh qpdf_oh_new_bool(qpdf_data data, QPDF_BOOL value);
  644 + QPDF_DLL
  645 + qpdf_oh qpdf_oh_new_integer(qpdf_data data, long long value);
  646 + QPDF_DLL
  647 + qpdf_oh qpdf_oh_new_real_from_string(qpdf_data data, char const* value);
  648 + QPDF_DLL
  649 + qpdf_oh qpdf_oh_new_real_from_double(qpdf_data data,
  650 + double value, int decimal_places);
  651 + QPDF_DLL
  652 + qpdf_oh qpdf_oh_new_name(qpdf_data data, char const* name);
  653 + QPDF_DLL
  654 + qpdf_oh qpdf_oh_new_string(qpdf_data data, char const* str);
  655 + QPDF_DLL
  656 + qpdf_oh qpdf_oh_new_unicode_string(qpdf_data data, char const* utf8_str);
  657 + QPDF_DLL
  658 + qpdf_oh qpdf_oh_new_array(qpdf_data data);
  659 + QPDF_DLL
  660 + qpdf_oh qpdf_oh_new_dictionary(qpdf_data data);
  661 +
  662 + QPDF_DLL
  663 + void qpdf_oh_make_direct(qpdf_data data, qpdf_oh oh);
  664 +
  665 + QPDF_DLL
  666 + void qpdf_oh_set_array_item(qpdf_data data, qpdf_oh oh,
  667 + int at, qpdf_oh item);
  668 + QPDF_DLL
  669 + void qpdf_oh_insert_item(qpdf_data data, qpdf_oh oh, int at, qpdf_oh item);
  670 + QPDF_DLL
  671 + void qpdf_oh_append_item(qpdf_data data, qpdf_oh oh, qpdf_oh item);
  672 + QPDF_DLL
  673 + void qpdf_oh_erase_item(qpdf_data data, qpdf_oh oh, int at);
  674 +
  675 + QPDF_DLL
  676 + void qpdf_oh_replace_key(qpdf_data data, qpdf_oh oh,
  677 + char const* key, qpdf_oh item);
  678 + QPDF_DLL
  679 + void qpdf_oh_remove_key(qpdf_data data, qpdf_oh oh, char const* key);
  680 + QPDF_DLL
  681 + void qpdf_oh_replace_or_remove_key(qpdf_data data, qpdf_oh oh,
  682 + char const* key, qpdf_oh item);
  683 +
  684 + QPDF_DLL
  685 + qpdf_oh qpdf_oh_get_dict(qpdf_data data, qpdf_oh oh);
  686 +
  687 + QPDF_DLL
  688 + int qpdf_oh_get_object_id(qpdf_data data, qpdf_oh oh);
  689 + QPDF_DLL
  690 + int qpdf_oh_get_generation(qpdf_data data, qpdf_oh oh);
  691 +
  692 + QPDF_DLL
  693 + char const* qpdf_oh_unparse(qpdf_data data, qpdf_oh oh);
  694 + QPDF_DLL
  695 + char const* qpdf_oh_unparse_resolved(qpdf_data data, qpdf_oh oh);
  696 + QPDF_DLL
  697 + char const* qpdf_oh_unparse_binary(qpdf_data data, qpdf_oh oh);
474 #ifdef __cplusplus 698 #ifdef __cplusplus
475 } 699 }
476 #endif 700 #endif
libqpdf/qpdf-c.cc
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 #include <qpdf/QPDFExc.hh> 6 #include <qpdf/QPDFExc.hh>
7 #include <qpdf/Pl_Discard.hh> 7 #include <qpdf/Pl_Discard.hh>
8 #include <qpdf/QIntC.hh> 8 #include <qpdf/QIntC.hh>
  9 +#include <qpdf/QUtil.hh>
9 10
10 #include <list> 11 #include <list>
11 #include <string> 12 #include <string>
@@ -37,10 +38,18 @@ struct _qpdf_data @@ -37,10 +38,18 @@ struct _qpdf_data
37 char const* password; 38 char const* password;
38 bool write_memory; 39 bool write_memory;
39 PointerHolder<Buffer> output_buffer; 40 PointerHolder<Buffer> output_buffer;
  41 +
  42 + // QPDFObjectHandle support
  43 + std::map<qpdf_oh, PointerHolder<QPDFObjectHandle>> oh_cache;
  44 + qpdf_oh next_oh;
  45 + std::set<std::string> cur_iter_dict_keys;
  46 + std::set<std::string>::const_iterator dict_iter;
  47 + std::string cur_dict_key;
40 }; 48 };
41 49
42 _qpdf_data::_qpdf_data() : 50 _qpdf_data::_qpdf_data() :
43 - write_memory(false) 51 + write_memory(false),
  52 + next_oh(0)
44 { 53 {
45 } 54 }
46 55
@@ -134,6 +143,7 @@ qpdf_data qpdf_init() @@ -134,6 +143,7 @@ qpdf_data qpdf_init()
134 void qpdf_cleanup(qpdf_data* qpdf) 143 void qpdf_cleanup(qpdf_data* qpdf)
135 { 144 {
136 QTC::TC("qpdf", "qpdf-c called qpdf_cleanup"); 145 QTC::TC("qpdf", "qpdf-c called qpdf_cleanup");
  146 + qpdf_oh_release_all(*qpdf);
137 delete *qpdf; 147 delete *qpdf;
138 *qpdf = 0; 148 *qpdf = 0;
139 } 149 }
@@ -749,3 +759,592 @@ QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf) @@ -749,3 +759,592 @@ QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf)
749 QTC::TC("qpdf", "qpdf-c called qpdf_write", (status == 0) ? 0 : 1); 759 QTC::TC("qpdf", "qpdf-c called qpdf_write", (status == 0) ? 0 : 1);
750 return status; 760 return status;
751 } 761 }
  762 +
  763 +static qpdf_oh
  764 +new_object(qpdf_data qpdf, QPDFObjectHandle const& qoh)
  765 +{
  766 + qpdf_oh oh = ++qpdf->next_oh; // never return 0
  767 + qpdf->oh_cache[oh] = new QPDFObjectHandle(qoh);
  768 + return oh;
  769 +}
  770 +
  771 +void qpdf_oh_release(qpdf_data qpdf, qpdf_oh oh)
  772 +{
  773 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_release");
  774 + qpdf->oh_cache.erase(oh);
  775 +}
  776 +
  777 +void qpdf_oh_release_all(qpdf_data qpdf)
  778 +{
  779 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_release_all");
  780 + qpdf->oh_cache.clear();
  781 +}
  782 +
  783 +qpdf_oh qpdf_get_trailer(qpdf_data qpdf)
  784 +{
  785 + QTC::TC("qpdf", "qpdf-c called qpdf_get_trailer");
  786 + return new_object(qpdf, qpdf->qpdf->getTrailer());
  787 +}
  788 +
  789 +qpdf_oh qpdf_get_root(qpdf_data qpdf)
  790 +{
  791 + QTC::TC("qpdf", "qpdf-c called qpdf_get_root");
  792 + return new_object(qpdf, qpdf->qpdf->getRoot());
  793 +}
  794 +
  795 +static bool
  796 +qpdf_oh_valid_internal(qpdf_data qpdf, qpdf_oh oh)
  797 +{
  798 + auto i = qpdf->oh_cache.find(oh);
  799 + bool result = ((i != qpdf->oh_cache.end()) &&
  800 + (i->second).getPointer() &&
  801 + (i->second)->isInitialized());
  802 + if (! result)
  803 + {
  804 + QTC::TC("qpdf", "qpdf-c invalid object handle");
  805 + qpdf->warnings.push_back(
  806 + QPDFExc(
  807 + qpdf_e_damaged_pdf,
  808 + qpdf->qpdf->getFilename(),
  809 + std::string("C API object handle ") +
  810 + QUtil::uint_to_string(oh),
  811 + 0, "attempted access to unknown/uninitialized object handle"));
  812 + }
  813 + return result;
  814 +}
  815 +
  816 +QPDF_BOOL qpdf_oh_is_bool(qpdf_data qpdf, qpdf_oh oh)
  817 +{
  818 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_bool");
  819 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  820 + qpdf->oh_cache[oh]->isBool());
  821 +}
  822 +
  823 +QPDF_BOOL qpdf_oh_is_null(qpdf_data qpdf, qpdf_oh oh)
  824 +{
  825 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_null");
  826 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  827 + qpdf->oh_cache[oh]->isNull());
  828 +}
  829 +
  830 +QPDF_BOOL qpdf_oh_is_integer(qpdf_data qpdf, qpdf_oh oh)
  831 +{
  832 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_integer");
  833 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  834 + qpdf->oh_cache[oh]->isInteger());
  835 +}
  836 +
  837 +QPDF_BOOL qpdf_oh_is_real(qpdf_data qpdf, qpdf_oh oh)
  838 +{
  839 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_real");
  840 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  841 + qpdf->oh_cache[oh]->isReal());
  842 +}
  843 +
  844 +QPDF_BOOL qpdf_oh_is_name(qpdf_data qpdf, qpdf_oh oh)
  845 +{
  846 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_name");
  847 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  848 + qpdf->oh_cache[oh]->isName());
  849 +}
  850 +
  851 +QPDF_BOOL qpdf_oh_is_string(qpdf_data qpdf, qpdf_oh oh)
  852 +{
  853 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_string");
  854 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  855 + qpdf->oh_cache[oh]->isString());
  856 +}
  857 +
  858 +QPDF_BOOL qpdf_oh_is_operator(qpdf_data qpdf, qpdf_oh oh)
  859 +{
  860 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_operator");
  861 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  862 + qpdf->oh_cache[oh]->isOperator());
  863 +}
  864 +
  865 +QPDF_BOOL qpdf_oh_is_inline_image(qpdf_data qpdf, qpdf_oh oh)
  866 +{
  867 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_inline_image");
  868 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  869 + qpdf->oh_cache[oh]->isInlineImage());
  870 +}
  871 +
  872 +QPDF_BOOL qpdf_oh_is_array(qpdf_data qpdf, qpdf_oh oh)
  873 +{
  874 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_array");
  875 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  876 + qpdf->oh_cache[oh]->isArray());
  877 +}
  878 +
  879 +QPDF_BOOL qpdf_oh_is_dictionary(qpdf_data qpdf, qpdf_oh oh)
  880 +{
  881 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_dictionary");
  882 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  883 + qpdf->oh_cache[oh]->isDictionary());
  884 +}
  885 +
  886 +QPDF_BOOL qpdf_oh_is_stream(qpdf_data qpdf, qpdf_oh oh)
  887 +{
  888 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_stream");
  889 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  890 + qpdf->oh_cache[oh]->isStream());
  891 +}
  892 +
  893 +QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh)
  894 +{
  895 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_indirect");
  896 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  897 + qpdf->oh_cache[oh]->isIndirect());
  898 +}
  899 +
  900 +QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh)
  901 +{
  902 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_scalar");
  903 + return (qpdf_oh_valid_internal(qpdf, oh) &&
  904 + qpdf->oh_cache[oh]->isScalar());
  905 +}
  906 +
  907 +qpdf_oh qpdf_oh_wrap_in_array(qpdf_data qpdf, qpdf_oh oh)
  908 +{
  909 + if (! qpdf_oh_valid_internal(qpdf, oh))
  910 + {
  911 + return qpdf_oh_new_array(qpdf);
  912 + }
  913 + auto qoh = qpdf->oh_cache[oh];
  914 + if (qoh->isArray())
  915 + {
  916 + QTC::TC("qpdf", "qpdf-c array to wrap_in_array");
  917 + return oh;
  918 + }
  919 + else
  920 + {
  921 + QTC::TC("qpdf", "qpdf-c non-array to wrap_in_array");
  922 + return new_object(qpdf,
  923 + QPDFObjectHandle::newArray(
  924 + std::vector<QPDFObjectHandle>{
  925 + *qpdf->oh_cache[oh]}));
  926 + }
  927 +}
  928 +
  929 +qpdf_oh qpdf_oh_parse(qpdf_data qpdf, char const* object_str)
  930 +{
  931 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_parse");
  932 + return new_object(qpdf, QPDFObjectHandle::parse(object_str));
  933 +}
  934 +
  935 +QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh)
  936 +{
  937 + if (! qpdf_oh_valid_internal(qpdf, oh))
  938 + {
  939 + return QPDF_FALSE;
  940 + }
  941 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_bool_value");
  942 + return qpdf->oh_cache[oh]->getBoolValue();
  943 +}
  944 +
  945 +long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh)
  946 +{
  947 + if (! qpdf_oh_valid_internal(qpdf, oh))
  948 + {
  949 + return 0LL;
  950 + }
  951 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value");
  952 + return qpdf->oh_cache[oh]->getIntValue();
  953 +}
  954 +
  955 +int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh)
  956 +{
  957 + if (! qpdf_oh_valid_internal(qpdf, oh))
  958 + {
  959 + return 0;
  960 + }
  961 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value_as_int");
  962 + return qpdf->oh_cache[oh]->getIntValueAsInt();
  963 +}
  964 +
  965 +unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh)
  966 +{
  967 + if (! qpdf_oh_valid_internal(qpdf, oh))
  968 + {
  969 + return 0ULL;
  970 + }
  971 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value");
  972 + return qpdf->oh_cache[oh]->getUIntValue();
  973 +}
  974 +
  975 +unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh)
  976 +{
  977 + if (! qpdf_oh_valid_internal(qpdf, oh))
  978 + {
  979 + return 0U;
  980 + }
  981 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value_as_uint");
  982 + return qpdf->oh_cache[oh]->getUIntValueAsUInt();
  983 +}
  984 +
  985 +char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh)
  986 +{
  987 + if (! qpdf_oh_valid_internal(qpdf, oh))
  988 + {
  989 + return "";
  990 + }
  991 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_real_value");
  992 + qpdf->tmp_string = qpdf->oh_cache[oh]->getRealValue();
  993 + return qpdf->tmp_string.c_str();
  994 +}
  995 +
  996 +QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh)
  997 +{
  998 + if (! qpdf_oh_valid_internal(qpdf, oh))
  999 + {
  1000 + return QPDF_FALSE;
  1001 + }
  1002 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_number");
  1003 + return qpdf->oh_cache[oh]->isNumber();
  1004 +}
  1005 +
  1006 +double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh)
  1007 +{
  1008 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1009 + {
  1010 + return 0.0;
  1011 + }
  1012 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_numeric_value");
  1013 + return qpdf->oh_cache[oh]->getNumericValue();
  1014 +}
  1015 +
  1016 +char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh)
  1017 +{
  1018 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1019 + {
  1020 + return "";
  1021 + }
  1022 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_name");
  1023 + qpdf->tmp_string = qpdf->oh_cache[oh]->getName();
  1024 + return qpdf->tmp_string.c_str();
  1025 +}
  1026 +
  1027 +char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh)
  1028 +{
  1029 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1030 + {
  1031 + return "";
  1032 + }
  1033 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_string_value");
  1034 + qpdf->tmp_string = qpdf->oh_cache[oh]->getStringValue();
  1035 + return qpdf->tmp_string.c_str();
  1036 +}
  1037 +
  1038 +char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh)
  1039 +{
  1040 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1041 + {
  1042 + return "";
  1043 + }
  1044 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_utf8_value");
  1045 + qpdf->tmp_string = qpdf->oh_cache[oh]->getUTF8Value();
  1046 + return qpdf->tmp_string.c_str();
  1047 +}
  1048 +
  1049 +int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh)
  1050 +{
  1051 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1052 + {
  1053 + return 0;
  1054 + }
  1055 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_n_items");
  1056 + return qpdf->oh_cache[oh]->getArrayNItems();
  1057 +}
  1058 +
  1059 +qpdf_oh qpdf_oh_get_array_item(qpdf_data qpdf, qpdf_oh oh, int n)
  1060 +{
  1061 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1062 + {
  1063 + return qpdf_oh_new_null(qpdf);
  1064 + }
  1065 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_item");
  1066 + return new_object(qpdf, qpdf->oh_cache[oh]->getArrayItem(n));
  1067 +}
  1068 +
  1069 +void qpdf_oh_begin_dict_key_iter(qpdf_data qpdf, qpdf_oh oh)
  1070 +{
  1071 + if (qpdf_oh_valid_internal(qpdf, oh) &&
  1072 + qpdf_oh_is_dictionary(qpdf, oh))
  1073 + {
  1074 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_begin_dict_key_iter");
  1075 + qpdf->cur_iter_dict_keys = qpdf->oh_cache[oh]->getKeys();
  1076 + }
  1077 + else
  1078 + {
  1079 + qpdf->cur_iter_dict_keys = {};
  1080 + }
  1081 + qpdf->dict_iter = qpdf->cur_iter_dict_keys.begin();
  1082 +}
  1083 +
  1084 +QPDF_BOOL qpdf_oh_dict_more_keys(qpdf_data qpdf)
  1085 +{
  1086 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_dict_more_keys");
  1087 + return qpdf->dict_iter != qpdf->cur_iter_dict_keys.end();
  1088 +}
  1089 +
  1090 +char const* qpdf_oh_dict_next_key(qpdf_data qpdf)
  1091 +{
  1092 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_dict_next_key");
  1093 + if (qpdf_oh_dict_more_keys(qpdf))
  1094 + {
  1095 + qpdf->cur_dict_key = *qpdf->dict_iter;
  1096 + ++qpdf->dict_iter;
  1097 + return qpdf->cur_dict_key.c_str();
  1098 + }
  1099 + else
  1100 + {
  1101 + return nullptr;
  1102 + }
  1103 +}
  1104 +
  1105 +QPDF_BOOL qpdf_oh_has_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
  1106 +{
  1107 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1108 + {
  1109 + return QPDF_FALSE;
  1110 + }
  1111 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_has_key");
  1112 + return qpdf->oh_cache[oh]->hasKey(key);
  1113 +}
  1114 +
  1115 +qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
  1116 +{
  1117 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1118 + {
  1119 + return qpdf_oh_new_null(qpdf);
  1120 + }
  1121 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_key");
  1122 + return new_object(qpdf, qpdf->oh_cache[oh]->getKey(key));
  1123 +}
  1124 +
  1125 +QPDF_BOOL qpdf_oh_is_or_has_name(qpdf_data qpdf, qpdf_oh oh, char const* key)
  1126 +{
  1127 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1128 + {
  1129 + return QPDF_FALSE;
  1130 + }
  1131 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_or_has_name");
  1132 + return qpdf->oh_cache[oh]->isOrHasName(key);
  1133 +}
  1134 +
  1135 +qpdf_oh qpdf_oh_new_null(qpdf_data qpdf)
  1136 +{
  1137 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_null");
  1138 + return new_object(qpdf, QPDFObjectHandle::newNull());
  1139 +}
  1140 +
  1141 +qpdf_oh qpdf_oh_new_bool(qpdf_data qpdf, QPDF_BOOL value)
  1142 +{
  1143 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_bool");
  1144 + return new_object(qpdf, QPDFObjectHandle::newBool(value));
  1145 +}
  1146 +
  1147 +qpdf_oh qpdf_oh_new_integer(qpdf_data qpdf, long long value)
  1148 +{
  1149 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_integer");
  1150 + return new_object(qpdf, QPDFObjectHandle::newInteger(value));
  1151 +}
  1152 +
  1153 +qpdf_oh qpdf_oh_new_real_from_string(qpdf_data qpdf, char const* value)
  1154 +{
  1155 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_real_from_string");
  1156 + return new_object(qpdf, QPDFObjectHandle::newReal(value));
  1157 +}
  1158 +
  1159 +qpdf_oh qpdf_oh_new_real_from_double(qpdf_data qpdf,
  1160 + double value, int decimal_places)
  1161 +{
  1162 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_real_from_double");
  1163 + return new_object(qpdf, QPDFObjectHandle::newReal(value, decimal_places));
  1164 +}
  1165 +
  1166 +qpdf_oh qpdf_oh_new_name(qpdf_data qpdf, char const* name)
  1167 +{
  1168 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_name");
  1169 + return new_object(qpdf, QPDFObjectHandle::newName(name));
  1170 +}
  1171 +
  1172 +qpdf_oh qpdf_oh_new_string(qpdf_data qpdf, char const* str)
  1173 +{
  1174 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_string");
  1175 + return new_object(qpdf, QPDFObjectHandle::newString(str));
  1176 +}
  1177 +
  1178 +qpdf_oh qpdf_oh_new_unicode_string(qpdf_data qpdf, char const* utf8_str)
  1179 +{
  1180 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_unicode_string");
  1181 + return new_object(qpdf, QPDFObjectHandle::newUnicodeString(utf8_str));
  1182 +}
  1183 +
  1184 +qpdf_oh qpdf_oh_new_array(qpdf_data qpdf)
  1185 +{
  1186 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_array");
  1187 + return new_object(qpdf, QPDFObjectHandle::newArray());
  1188 +}
  1189 +
  1190 +qpdf_oh qpdf_oh_new_dictionary(qpdf_data qpdf)
  1191 +{
  1192 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_dictionary");
  1193 + return new_object(qpdf, QPDFObjectHandle::newDictionary());
  1194 +}
  1195 +
  1196 +void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh)
  1197 +{
  1198 + if (qpdf_oh_valid_internal(qpdf, oh))
  1199 + {
  1200 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_make_direct");
  1201 + qpdf->oh_cache[oh]->makeDirect();
  1202 + }
  1203 +}
  1204 +
  1205 +static QPDFObjectHandle
  1206 +qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item)
  1207 +{
  1208 + if (qpdf_oh_valid_internal(qpdf, item))
  1209 + {
  1210 + return *(qpdf->oh_cache[item]);
  1211 + }
  1212 + else
  1213 + {
  1214 + return QPDFObjectHandle::newNull();
  1215 + }
  1216 +}
  1217 +
  1218 +void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh,
  1219 + int at, qpdf_oh item)
  1220 +{
  1221 + if (qpdf_oh_is_array(qpdf, oh))
  1222 + {
  1223 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_set_array_item");
  1224 + qpdf->oh_cache[oh]->setArrayItem(
  1225 + at, qpdf_oh_item_internal(qpdf, item));
  1226 + }
  1227 +}
  1228 +
  1229 +void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item)
  1230 +{
  1231 + if (qpdf_oh_is_array(qpdf, oh))
  1232 + {
  1233 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_insert_item");
  1234 + qpdf->oh_cache[oh]->insertItem(
  1235 + at, qpdf_oh_item_internal(qpdf, item));
  1236 + }
  1237 +}
  1238 +
  1239 +void qpdf_oh_append_item(qpdf_data qpdf, qpdf_oh oh, qpdf_oh item)
  1240 +{
  1241 + if (qpdf_oh_is_array(qpdf, oh))
  1242 + {
  1243 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_append_item");
  1244 + qpdf->oh_cache[oh]->appendItem(
  1245 + qpdf_oh_item_internal(qpdf, item));
  1246 + }
  1247 +}
  1248 +
  1249 +void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at)
  1250 +{
  1251 + if (qpdf_oh_is_array(qpdf, oh))
  1252 + {
  1253 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_erase_item");
  1254 + qpdf->oh_cache[oh]->eraseItem(at);
  1255 + }
  1256 +}
  1257 +
  1258 +void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh,
  1259 + char const* key, qpdf_oh item)
  1260 +{
  1261 + if (qpdf_oh_is_dictionary(qpdf, oh))
  1262 + {
  1263 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_key");
  1264 + qpdf->oh_cache[oh]->replaceKey(
  1265 + key, qpdf_oh_item_internal(qpdf, item));
  1266 + }
  1267 +}
  1268 +
  1269 +void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
  1270 +{
  1271 + if (qpdf_oh_is_dictionary(qpdf, oh))
  1272 + {
  1273 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_remove_key");
  1274 + qpdf->oh_cache[oh]->removeKey(key);
  1275 + }
  1276 +}
  1277 +
  1278 +void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh,
  1279 + char const* key, qpdf_oh item)
  1280 +{
  1281 + if (qpdf_oh_is_dictionary(qpdf, oh))
  1282 + {
  1283 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_or_remove_key");
  1284 + qpdf->oh_cache[oh]->replaceOrRemoveKey(
  1285 + key, qpdf_oh_item_internal(qpdf, item));
  1286 + }
  1287 +}
  1288 +
  1289 +qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh)
  1290 +{
  1291 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1292 + {
  1293 + return qpdf_oh_new_null(qpdf);
  1294 + }
  1295 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_dict");
  1296 + return new_object(qpdf, qpdf->oh_cache[oh]->getDict());
  1297 +}
  1298 +
  1299 +int qpdf_oh_get_object_id(qpdf_data qpdf, qpdf_oh oh)
  1300 +{
  1301 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1302 + {
  1303 + return 0;
  1304 + }
  1305 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_object_id");
  1306 + return qpdf->oh_cache[oh]->getObjectID();
  1307 +}
  1308 +
  1309 +int qpdf_oh_get_generation(qpdf_data qpdf, qpdf_oh oh)
  1310 +{
  1311 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1312 + {
  1313 + return 0;
  1314 + }
  1315 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_generation");
  1316 + return qpdf->oh_cache[oh]->getGeneration();
  1317 +}
  1318 +
  1319 +char const* qpdf_oh_unparse(qpdf_data qpdf, qpdf_oh oh)
  1320 +{
  1321 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1322 + {
  1323 + return "";
  1324 + }
  1325 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse");
  1326 + qpdf->tmp_string = qpdf->oh_cache[oh]->unparse();
  1327 + return qpdf->tmp_string.c_str();
  1328 +}
  1329 +
  1330 +char const* qpdf_oh_unparse_resolved(qpdf_data qpdf, qpdf_oh oh)
  1331 +{
  1332 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1333 + {
  1334 + return "";
  1335 + }
  1336 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_resolved");
  1337 + qpdf->tmp_string = qpdf->oh_cache[oh]->unparseResolved();
  1338 + return qpdf->tmp_string.c_str();
  1339 +}
  1340 +
  1341 +char const* qpdf_oh_unparse_binary(qpdf_data qpdf, qpdf_oh oh)
  1342 +{
  1343 + if (! qpdf_oh_valid_internal(qpdf, oh))
  1344 + {
  1345 + return "";
  1346 + }
  1347 + QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_binary");
  1348 + qpdf->tmp_string = qpdf->oh_cache[oh]->unparseBinary();
  1349 + return qpdf->tmp_string.c_str();
  1350 +}
qpdf/qpdf-ctest.c
@@ -495,6 +495,177 @@ static void test23(char const* infile, @@ -495,6 +495,177 @@ static void test23(char const* infile,
495 report_errors(); 495 report_errors();
496 } 496 }
497 497
  498 +static void test24(char const* infile,
  499 + char const* password,
  500 + char const* outfile,
  501 + char const* outfile2)
  502 +{
  503 + /* This test case is designed for minimal.pdf. */
  504 + qpdf_read(qpdf, infile, password);
  505 + qpdf_oh trailer = qpdf_get_trailer(qpdf);
  506 + /* The library never returns 0 */
  507 + assert(trailer == 1);
  508 + qpdf_oh root = qpdf_get_root(qpdf);
  509 + assert(qpdf_oh_get_generation(qpdf, root) == 0);
  510 + qpdf_oh root_from_trailer = qpdf_oh_get_key(qpdf, trailer, "/Root");
  511 + assert(qpdf_oh_get_object_id(qpdf, root) ==
  512 + qpdf_oh_get_object_id(qpdf, root_from_trailer));
  513 + qpdf_oh pages = qpdf_oh_get_key(qpdf, root, "/Pages");
  514 + assert(qpdf_oh_is_dictionary(qpdf, pages));
  515 + qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids");
  516 + assert(qpdf_oh_is_array(qpdf, kids));
  517 + assert(qpdf_oh_get_array_n_items(qpdf, kids) == 1);
  518 + qpdf_oh page1 = qpdf_oh_get_array_item(qpdf, kids, 0);
  519 + qpdf_oh_begin_dict_key_iter(qpdf, page1);
  520 + while (qpdf_oh_dict_more_keys(qpdf))
  521 + {
  522 + printf("page dictionary key: %s\n", qpdf_oh_dict_next_key(qpdf));
  523 + }
  524 + qpdf_oh type = qpdf_oh_get_key(qpdf, page1, "/Type");
  525 + assert(qpdf_oh_is_name(qpdf, type));
  526 + assert(strcmp(qpdf_oh_get_name(qpdf, type), "/Page") == 0);
  527 + qpdf_oh parent = qpdf_oh_get_key(qpdf, page1, "/Parent");
  528 + assert(qpdf_oh_is_indirect(qpdf, parent));
  529 + qpdf_oh mediabox = qpdf_oh_get_key(qpdf, page1, "/MediaBox");
  530 + assert(! qpdf_oh_is_scalar(qpdf, mediabox));
  531 + assert(qpdf_oh_is_array(qpdf, mediabox));
  532 + assert(qpdf_oh_get_array_n_items(qpdf, mediabox) == 4);
  533 + assert(qpdf_oh_wrap_in_array(qpdf, mediabox) == mediabox);
  534 + for (int i = 0; i < 4; ++i)
  535 + {
  536 + qpdf_oh item = qpdf_oh_get_array_item(qpdf, mediabox, i);
  537 + printf("item %d: %d %.2f\n",
  538 + i, qpdf_oh_get_int_value_as_int(qpdf, item),
  539 + qpdf_oh_get_numeric_value(qpdf, item));
  540 + qpdf_oh_release(qpdf, item);
  541 + }
  542 + qpdf_oh i2 = qpdf_oh_get_array_item(qpdf, mediabox, 2);
  543 + assert(qpdf_oh_get_int_value_as_int(qpdf, i2) == 612);
  544 + assert(qpdf_oh_get_int_value(qpdf, i2) == 612ll);
  545 + assert(qpdf_oh_get_uint_value_as_uint(qpdf, i2) == 612u);
  546 + assert(qpdf_oh_get_uint_value(qpdf, i2) == 612ull);
  547 + assert(! qpdf_oh_is_operator(qpdf, i2));
  548 + assert(! qpdf_oh_is_inline_image(qpdf, i2));
  549 + qpdf_oh encoding = qpdf_oh_get_key(
  550 + qpdf, qpdf_oh_get_key(
  551 + qpdf, qpdf_oh_get_key(
  552 + qpdf, qpdf_oh_get_key(
  553 + qpdf, page1, "/Resources"),
  554 + "/Font"),
  555 + "/F1"),
  556 + "/Encoding");
  557 + assert(strcmp(qpdf_oh_get_name(qpdf, encoding), "/WinAnsiEncoding") == 0);
  558 + qpdf_oh contents = qpdf_oh_get_key(qpdf, page1, "/Contents");
  559 + assert(qpdf_oh_is_stream(qpdf, contents));
  560 + qpdf_oh contents_dict = qpdf_oh_get_dict(qpdf, contents);
  561 + assert(! qpdf_oh_is_scalar(qpdf, contents));
  562 + assert(! qpdf_oh_is_scalar(qpdf, contents_dict));
  563 + qpdf_oh contents_length = qpdf_oh_get_key(qpdf, contents_dict, "/Length");
  564 + assert(qpdf_oh_is_integer(qpdf, contents_length));
  565 + assert(qpdf_oh_is_scalar(qpdf, contents_length));
  566 + assert(qpdf_oh_is_number(qpdf, contents_length));
  567 + qpdf_oh contents_array = qpdf_oh_wrap_in_array(qpdf, contents);
  568 + assert(qpdf_oh_get_array_n_items(qpdf, contents_array) == 1);
  569 + assert(qpdf_oh_get_object_id(
  570 + qpdf, qpdf_oh_get_array_item(qpdf, contents_array, 0)) ==
  571 + qpdf_oh_get_object_id(qpdf, contents));
  572 + qpdf_oh resources = qpdf_oh_get_key(qpdf, page1, "/Resources");
  573 + qpdf_oh procset = qpdf_oh_get_key(qpdf, resources, "/ProcSet");
  574 + assert(strcmp(qpdf_oh_unparse(qpdf, procset),
  575 + "5 0 R") == 0);
  576 + assert(strcmp(qpdf_oh_unparse_resolved(qpdf, procset),
  577 + "[ /PDF /Text ]") == 0);
  578 + qpdf_oh_make_direct(qpdf, procset);
  579 + assert(strcmp(qpdf_oh_unparse(qpdf, procset),
  580 + "[ /PDF /Text ]") == 0);
  581 + qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset);
  582 +
  583 + qpdf_oh parsed = qpdf_oh_parse(
  584 + qpdf, "[ 1 2.0 (3\xf7) << /Four [/Five] >> null true ]");
  585 + qpdf_oh p_int = qpdf_oh_get_array_item(qpdf, parsed, 0);
  586 + qpdf_oh p_real = qpdf_oh_get_array_item(qpdf, parsed, 1);
  587 + qpdf_oh p_string = qpdf_oh_get_array_item(qpdf, parsed, 2);
  588 + qpdf_oh p_dict = qpdf_oh_get_array_item(qpdf, parsed, 3);
  589 + qpdf_oh p_null = qpdf_oh_get_array_item(qpdf, parsed, 4);
  590 + qpdf_oh p_bool = qpdf_oh_get_array_item(qpdf, parsed, 5);
  591 + assert(qpdf_oh_is_integer(qpdf, p_int) &&
  592 + qpdf_oh_get_int_value_as_int(qpdf, p_int) == 1);
  593 + assert(qpdf_oh_is_real(qpdf, p_real) &&
  594 + (strcmp(qpdf_oh_get_real_value(qpdf, p_real), "2.0") == 0) &&
  595 + qpdf_oh_get_numeric_value(qpdf, p_real) == 2.0);
  596 + assert(qpdf_oh_is_string(qpdf, p_string) &&
  597 + (strcmp(qpdf_oh_get_string_value(qpdf, p_string), "3\xf7") == 0) &&
  598 + (strcmp(qpdf_oh_get_utf8_value(qpdf, p_string), "3\xc3\xb7") == 0) &&
  599 + (strcmp(qpdf_oh_unparse_binary(qpdf, p_string), "<33f7>") == 0));
  600 + assert(qpdf_oh_is_dictionary(qpdf, p_dict));
  601 + qpdf_oh p_five = qpdf_oh_get_key(qpdf, p_dict, "/Four");
  602 + assert(qpdf_oh_is_or_has_name(qpdf, p_five, "/Five"));
  603 + assert(qpdf_oh_is_or_has_name(
  604 + qpdf, qpdf_oh_get_array_item(qpdf, p_five, 0), "/Five"));
  605 + assert(qpdf_oh_is_null(qpdf, p_null));
  606 + assert(qpdf_oh_is_bool(qpdf, p_bool) &&
  607 + (qpdf_oh_get_bool_value(qpdf, p_bool) == QPDF_TRUE));
  608 + qpdf_oh_erase_item(qpdf, parsed, 4);
  609 + qpdf_oh_insert_item(
  610 + qpdf, parsed, 2,
  611 + qpdf_oh_parse(qpdf, "<</A 1 /B 2 /C 3 /D 4>>"));
  612 + qpdf_oh new_dict = qpdf_oh_get_array_item(qpdf, parsed, 2);
  613 + assert(qpdf_oh_has_key(qpdf, new_dict, "/A"));
  614 + assert(qpdf_oh_has_key(qpdf, new_dict, "/D"));
  615 + qpdf_oh new_array = qpdf_oh_new_array(qpdf);
  616 + qpdf_oh_replace_or_remove_key(
  617 + qpdf, new_dict, "/A", qpdf_oh_new_null(qpdf));
  618 + qpdf_oh_replace_or_remove_key(
  619 + qpdf, new_dict, "/B", new_array);
  620 + qpdf_oh_replace_key(
  621 + qpdf, new_dict, "/C", qpdf_oh_new_dictionary(qpdf));
  622 + qpdf_oh_remove_key(qpdf, new_dict, "/D");
  623 + assert(! qpdf_oh_has_key(qpdf, new_dict, "/A"));
  624 + assert(! qpdf_oh_has_key(qpdf, new_dict, "/D"));
  625 + qpdf_oh_append_item(
  626 + qpdf, new_array, qpdf_oh_new_string(qpdf, "potato"));
  627 + qpdf_oh_append_item(
  628 + qpdf, new_array,
  629 + qpdf_oh_new_unicode_string(qpdf, "qww\xc3\xb7\xcf\x80"));
  630 + qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 2 */
  631 + qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 3 */
  632 + qpdf_oh_set_array_item(
  633 + qpdf, new_array, 2,
  634 + qpdf_oh_new_name(qpdf, "/Quack"));
  635 + qpdf_oh_append_item(
  636 + qpdf, new_array,
  637 + qpdf_oh_new_real_from_double(qpdf, 4.0, 2));
  638 + qpdf_oh_append_item(
  639 + qpdf, new_array,
  640 + qpdf_oh_new_real_from_string(qpdf, "5.0"));
  641 + qpdf_oh_append_item(
  642 + qpdf, new_array,
  643 + qpdf_oh_new_integer(qpdf, 6));
  644 + qpdf_oh_append_item(
  645 + qpdf, new_array, qpdf_oh_new_bool(qpdf, QPDF_TRUE));
  646 + qpdf_oh_replace_key(qpdf, root, "/QTest", new_dict);
  647 +
  648 + /* Release and access to exercise warnings */
  649 + qpdf_oh_release(qpdf, page1);
  650 + contents = qpdf_oh_get_key(qpdf, page1, "/Contents");
  651 + assert(qpdf_oh_is_null(qpdf, contents));
  652 + assert(qpdf_oh_is_array(qpdf, mediabox));
  653 + qpdf_oh_release_all(qpdf);
  654 + assert(! qpdf_oh_is_null(qpdf, mediabox));
  655 + assert(! qpdf_oh_is_array(qpdf, mediabox));
  656 + /* Make sure something is assigned when we exit so we check that
  657 + * it gets properl freed.
  658 + */
  659 + qpdf_get_root(qpdf);
  660 +
  661 + qpdf_init_write(qpdf, outfile);
  662 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  663 + qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
  664 + qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
  665 + qpdf_write(qpdf);
  666 + report_errors();
  667 +}
  668 +
498 int main(int argc, char* argv[]) 669 int main(int argc, char* argv[])
499 { 670 {
500 char* p = 0; 671 char* p = 0;
@@ -558,6 +729,7 @@ int main(int argc, char* argv[]) @@ -558,6 +729,7 @@ int main(int argc, char* argv[])
558 (n == 21) ? test21 : 729 (n == 21) ? test21 :
559 (n == 22) ? test22 : 730 (n == 22) ? test22 :
560 (n == 23) ? test23 : 731 (n == 23) ? test23 :
  732 + (n == 24) ? test24 :
561 0); 733 0);
562 734
563 if (fn == 0) 735 if (fn == 0)
qpdf/qpdf.testcov
@@ -457,3 +457,67 @@ QPDF copy foreign with data 1 @@ -457,3 +457,67 @@ QPDF copy foreign with data 1
457 QPDF copy foreign with foreign_stream 1 457 QPDF copy foreign with foreign_stream 1
458 QPDFObjectHandle need_newline 1 458 QPDFObjectHandle need_newline 1
459 qpdf pages range omitted with . 0 459 qpdf pages range omitted with . 0
  460 +qpdf-c invalid object handle 0
  461 +qpdf-c called qpdf_oh_release 0
  462 +qpdf-c called qpdf_oh_release_all 0
  463 +qpdf-c called qpdf_get_trailer 0
  464 +qpdf-c called qpdf_get_root 0
  465 +qpdf-c called qpdf_oh_is_bool 0
  466 +qpdf-c called qpdf_oh_is_null 0
  467 +qpdf-c called qpdf_oh_is_integer 0
  468 +qpdf-c called qpdf_oh_is_real 0
  469 +qpdf-c called qpdf_oh_is_name 0
  470 +qpdf-c called qpdf_oh_is_string 0
  471 +qpdf-c called qpdf_oh_is_operator 0
  472 +qpdf-c called qpdf_oh_is_inline_image 0
  473 +qpdf-c called qpdf_oh_is_array 0
  474 +qpdf-c called qpdf_oh_is_dictionary 0
  475 +qpdf-c called qpdf_oh_is_stream 0
  476 +qpdf-c called qpdf_oh_is_indirect 0
  477 +qpdf-c called qpdf_oh_is_scalar 0
  478 +qpdf-c array to wrap_in_array 0
  479 +qpdf-c non-array to wrap_in_array 0
  480 +qpdf-c called qpdf_oh_parse 0
  481 +qpdf-c called qpdf_oh_get_bool_value 0
  482 +qpdf-c called qpdf_oh_get_int_value 0
  483 +qpdf-c called qpdf_oh_get_int_value_as_int 0
  484 +qpdf-c called qpdf_oh_get_uint_value 0
  485 +qpdf-c called qpdf_oh_get_uint_value_as_uint 0
  486 +qpdf-c called qpdf_oh_get_real_value 0
  487 +qpdf-c called qpdf_oh_is_number 0
  488 +qpdf-c called qpdf_oh_get_numeric_value 0
  489 +qpdf-c called qpdf_oh_get_name 0
  490 +qpdf-c called qpdf_oh_get_string_value 0
  491 +qpdf-c called qpdf_oh_get_utf8_value 0
  492 +qpdf-c called qpdf_oh_get_array_n_items 0
  493 +qpdf-c called qpdf_oh_get_array_item 0
  494 +qpdf-c called qpdf_oh_begin_dict_key_iter 0
  495 +qpdf-c called qpdf_oh_dict_more_keys 0
  496 +qpdf-c called qpdf_oh_dict_next_key 0
  497 +qpdf-c called qpdf_oh_has_key 0
  498 +qpdf-c called qpdf_oh_get_key 0
  499 +qpdf-c called qpdf_oh_is_or_has_name 0
  500 +qpdf-c called qpdf_oh_new_null 0
  501 +qpdf-c called qpdf_oh_new_bool 0
  502 +qpdf-c called qpdf_oh_new_integer 0
  503 +qpdf-c called qpdf_oh_new_real_from_string 0
  504 +qpdf-c called qpdf_oh_new_real_from_double 0
  505 +qpdf-c called qpdf_oh_new_name 0
  506 +qpdf-c called qpdf_oh_new_string 0
  507 +qpdf-c called qpdf_oh_new_unicode_string 0
  508 +qpdf-c called qpdf_oh_new_array 0
  509 +qpdf-c called qpdf_oh_new_dictionary 0
  510 +qpdf-c called qpdf_oh_make_direct 0
  511 +qpdf-c called qpdf_oh_set_array_item 0
  512 +qpdf-c called qpdf_oh_insert_item 0
  513 +qpdf-c called qpdf_oh_append_item 0
  514 +qpdf-c called qpdf_oh_erase_item 0
  515 +qpdf-c called qpdf_oh_replace_key 0
  516 +qpdf-c called qpdf_oh_remove_key 0
  517 +qpdf-c called qpdf_oh_replace_or_remove_key 0
  518 +qpdf-c called qpdf_oh_get_dict 0
  519 +qpdf-c called qpdf_oh_get_object_id 0
  520 +qpdf-c called qpdf_oh_get_generation 0
  521 +qpdf-c called qpdf_oh_unparse 0
  522 +qpdf-c called qpdf_oh_unparse_resolved 0
  523 +qpdf-c called qpdf_oh_unparse_binary 0
qpdf/qtest/qpdf.test
@@ -4120,6 +4120,21 @@ foreach my $i (@c_check_types) @@ -4120,6 +4120,21 @@ foreach my $i (@c_check_types)
4120 4120
4121 show_ntests(); 4121 show_ntests();
4122 # ---------- 4122 # ----------
  4123 +$td->notify("--- C API Object Handle ---");
  4124 +$n_tests += scalar(@c_check_types);
  4125 +
  4126 +$td->runtest("C check object handles",
  4127 + {$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"},
  4128 + {$td->FILE => "c-object-handles.out",
  4129 + $td->EXIT_STATUS => 0},
  4130 + $td->NORMALIZE_NEWLINES);
  4131 +
  4132 +$td->runtest("check output",
  4133 + {$td->FILE => 'a.pdf'},
  4134 + {$td->FILE => 'c-object-handles-out.pdf'});
  4135 +
  4136 +show_ntests();
  4137 +# ----------
4123 $td->notify("--- Content Preservation Tests ---"); 4138 $td->notify("--- Content Preservation Tests ---");
4124 # $n_tests incremented below 4139 # $n_tests incremented below
4125 4140
qpdf/qtest/qpdf/c-object-handles-out.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +1 0 obj
  6 +<<
  7 + /Pages 2 0 R
  8 + /QTest <<
  9 + /B [
  10 + (potato)
  11 + <feff00710077007700f703c0>
  12 + /Quack
  13 + null
  14 + 4.00
  15 + 5.0
  16 + 6
  17 + true
  18 + ]
  19 + /C <<
  20 + >>
  21 + >>
  22 + /Type /Catalog
  23 +>>
  24 +endobj
  25 +
  26 +2 0 obj
  27 +<<
  28 + /Count 1
  29 + /Kids [
  30 + 3 0 R
  31 + ]
  32 + /Type /Pages
  33 +>>
  34 +endobj
  35 +
  36 +%% Page 1
  37 +3 0 obj
  38 +<<
  39 + /Contents 4 0 R
  40 + /MediaBox [
  41 + 0
  42 + 0
  43 + 612
  44 + 792
  45 + ]
  46 + /Parent 2 0 R
  47 + /Resources <<
  48 + /Font <<
  49 + /F1 6 0 R
  50 + >>
  51 + /ProcSet [
  52 + /PDF
  53 + /Text
  54 + ]
  55 + >>
  56 + /Type /Page
  57 +>>
  58 +endobj
  59 +
  60 +%% Contents for page 1
  61 +4 0 obj
  62 +<<
  63 + /Length 5 0 R
  64 +>>
  65 +stream
  66 +BT
  67 + /F1 24 Tf
  68 + 72 720 Td
  69 + (Potato) Tj
  70 +ET
  71 +endstream
  72 +endobj
  73 +
  74 +5 0 obj
  75 +44
  76 +endobj
  77 +
  78 +6 0 obj
  79 +<<
  80 + /BaseFont /Helvetica
  81 + /Encoding /WinAnsiEncoding
  82 + /Name /F1
  83 + /Subtype /Type1
  84 + /Type /Font
  85 +>>
  86 +endobj
  87 +
  88 +xref
  89 +0 7
  90 +0000000000 65535 f
  91 +0000000025 00000 n
  92 +0000000240 00000 n
  93 +0000000322 00000 n
  94 +0000000562 00000 n
  95 +0000000661 00000 n
  96 +0000000680 00000 n
  97 +trailer <<
  98 + /Root 1 0 R
  99 + /Size 7
  100 + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
  101 +>>
  102 +startxref
  103 +798
  104 +%%EOF
qpdf/qtest/qpdf/c-object-handles.out 0 → 100644
  1 +page dictionary key: /Contents
  2 +page dictionary key: /MediaBox
  3 +page dictionary key: /Parent
  4 +page dictionary key: /Resources
  5 +page dictionary key: /Type
  6 +item 0: 0 0.00
  7 +item 1: 0 0.00
  8 +item 2: 612 612.00
  9 +item 3: 792 792.00
  10 +warning: minimal.pdf (C API object handle 6): attempted access to unknown/uninitialized object handle
  11 + code: 5
  12 + file: minimal.pdf
  13 + pos : 0
  14 + text: attempted access to unknown/uninitialized object handle
  15 +warning: minimal.pdf (C API object handle 9): attempted access to unknown/uninitialized object handle
  16 + code: 5
  17 + file: minimal.pdf
  18 + pos : 0
  19 + text: attempted access to unknown/uninitialized object handle
  20 +warning: minimal.pdf (C API object handle 9): attempted access to unknown/uninitialized object handle
  21 + code: 5
  22 + file: minimal.pdf
  23 + pos : 0
  24 + text: attempted access to unknown/uninitialized object handle