1 #include <qpdf/qpdf-c.h>
2 #include <stdio.h>
3 #include <assert.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7 #include "../libqpdf/qpdf/qpdf-config.h" // for LL_FMT
8
9 static char* whoami = 0;
10 static qpdf_data qpdf = 0;
11
safe_fopen(char const * filename,char const * mode)12 static FILE* safe_fopen(char const* filename, char const* mode)
13 {
14 // This function is basically a "C" port of QUtil::safe_fopen.
15 FILE* f = 0;
16 #ifdef _MSC_VER
17 errno_t err = fopen_s(&f, filename, mode);
18 if (err != 0)
19 {
20 char buf[94];
21 strerror_s(buf, sizeof(buf), errno);
22 fprintf(stderr, "%s: unable to open %s: %s\n",
23 whoami, filename, buf);
24 exit(2);
25 }
26 #else
27 f = fopen(filename, mode);
28 if (f == NULL)
29 {
30 fprintf(stderr, "%s: unable to open %s: %s\n",
31 whoami, filename, strerror(errno));
32 exit(2);
33 }
34 #endif
35 return f;
36 }
37
print_error(char const * label,qpdf_data q,qpdf_error e)38 static void print_error(char const* label, qpdf_data q, qpdf_error e)
39 {
40 #define POS_FMT " pos : " LL_FMT "\n"
41 printf("%s: %s\n", label, qpdf_get_error_full_text(q, e));
42 printf(" code: %d\n", qpdf_get_error_code(q, e));
43 printf(" file: %s\n", qpdf_get_error_filename(q, e));
44 printf(POS_FMT, qpdf_get_error_file_position(q, e));
45 printf(" text: %s\n", qpdf_get_error_message_detail(q, e));
46 }
47
report_errors()48 static void report_errors()
49 {
50 qpdf_error e = 0;
51 while (qpdf_more_warnings(qpdf))
52 {
53 e = qpdf_next_warning(qpdf);
54 print_error("warning", qpdf, e);
55 }
56 if (qpdf_has_error(qpdf))
57 {
58 e = qpdf_get_error(qpdf);
59 assert(qpdf_has_error(qpdf) == QPDF_FALSE);
60 print_error("error", qpdf, e);
61 }
62 else
63 {
64 e = qpdf_get_error(qpdf);
65 assert(e == 0);
66 assert(qpdf_get_error_code(qpdf, e) == qpdf_e_success);
67 // Call these to ensure that they can be called on a null
68 // error pointer.
69 (void)qpdf_get_error_full_text(qpdf, e);
70 (void)qpdf_get_error_filename(qpdf, e);
71 (void)qpdf_get_error_file_position(qpdf, e);
72 (void)qpdf_get_error_message_detail(qpdf, e);
73 }
74 }
75
handle_oh_error(qpdf_data q,char const * label)76 static void handle_oh_error(qpdf_data q, char const* label)
77 {
78 if (qpdf_has_error(q))
79 {
80 print_error(label, q, qpdf_get_error(q));
81 }
82 }
83
read_file_into_memory(char const * filename,char ** buf,unsigned long * size)84 static void read_file_into_memory(char const* filename,
85 char** buf, unsigned long* size)
86 {
87 char* buf_p = 0;
88 FILE* f = NULL;
89 size_t bytes_read = 0;
90 size_t len = 0;
91
92 f = safe_fopen(filename, "rb");
93 fseek(f, 0, SEEK_END);
94 *size = (unsigned long) ftell(f);
95 fseek(f, 0, SEEK_SET);
96 *buf = malloc(*size);
97 if (*buf == NULL)
98 {
99 fprintf(stderr, "%s: unable to allocate %lu bytes\n",
100 whoami, *size);
101 exit(2);
102 }
103 buf_p = *buf;
104 bytes_read = 0;
105 len = 0;
106 while ((len = fread(buf_p + bytes_read, 1, *size - bytes_read, f)) > 0)
107 {
108 bytes_read += len;
109 }
110 if (bytes_read != *size)
111 {
112 if (ferror(f))
113 {
114 fprintf(stderr, "%s: failure reading file %s into memory:",
115 whoami, filename);
116 }
117 else
118 {
119 fprintf(stderr, "%s: premature EOF reading file %s:",
120 whoami, filename);
121 }
122 fprintf(stderr, " read %lu, wanted %lu\n",
123 (unsigned long) bytes_read, (unsigned long) *size);
124 exit(2);
125 }
126 fclose(f);
127 }
128
count_progress(int percent,void * data)129 static void count_progress(int percent, void* data)
130 {
131 ++(*(int*)data);
132 }
133
test01(char const * infile,char const * password,char const * outfile,char const * xarg)134 static void test01(char const* infile,
135 char const* password,
136 char const* outfile,
137 char const* xarg)
138 {
139 qpdf_read(qpdf, infile, password);
140 printf("version: %s\n", qpdf_get_pdf_version(qpdf));
141 if (qpdf_get_pdf_extension_level(qpdf) > 0)
142 {
143 printf("extension level: %d\n", qpdf_get_pdf_extension_level(qpdf));
144 }
145 printf("linearized: %d\n", qpdf_is_linearized(qpdf));
146 printf("encrypted: %d\n", qpdf_is_encrypted(qpdf));
147 if (qpdf_is_encrypted(qpdf))
148 {
149 printf("user password: %s\n", qpdf_get_user_password(qpdf));
150 printf("extract for accessibility: %d\n",
151 qpdf_allow_accessibility(qpdf));
152 printf("extract for any purpose: %d\n",
153 qpdf_allow_extract_all(qpdf));
154 printf("print low resolution: %d\n",
155 qpdf_allow_print_low_res(qpdf));
156 printf("print high resolution: %d\n",
157 qpdf_allow_print_high_res(qpdf));
158 printf("modify document assembly: %d\n",
159 qpdf_allow_modify_assembly(qpdf));
160 printf("modify forms: %d\n",
161 qpdf_allow_modify_form(qpdf));
162 printf("modify annotations: %d\n",
163 qpdf_allow_modify_annotation(qpdf));
164 printf("modify other: %d\n",
165 qpdf_allow_modify_other(qpdf));
166 printf("modify anything: %d\n",
167 qpdf_allow_modify_all(qpdf));
168 }
169 report_errors();
170 }
171
test02(char const * infile,char const * password,char const * outfile,char const * xarg)172 static void test02(char const* infile,
173 char const* password,
174 char const* outfile,
175 char const* xarg)
176 {
177 qpdf_set_suppress_warnings(qpdf, QPDF_TRUE);
178 if (((qpdf_read(qpdf, infile, password) & QPDF_ERRORS) == 0) &&
179 ((qpdf_init_write(qpdf, outfile) & QPDF_ERRORS) == 0))
180 {
181 qpdf_set_static_ID(qpdf, QPDF_TRUE);
182 qpdf_write(qpdf);
183 }
184 report_errors();
185 }
186
test03(char const * infile,char const * password,char const * outfile,char const * xarg)187 static void test03(char const* infile,
188 char const* password,
189 char const* outfile,
190 char const* xarg)
191 {
192 qpdf_read(qpdf, infile, password);
193 qpdf_init_write(qpdf, outfile);
194 qpdf_set_static_ID(qpdf, QPDF_TRUE);
195 qpdf_set_content_normalization(qpdf, QPDF_TRUE);
196 qpdf_write(qpdf);
197 report_errors();
198 }
199
test04(char const * infile,char const * password,char const * outfile,char const * xarg)200 static void test04(char const* infile,
201 char const* password,
202 char const* outfile,
203 char const* xarg)
204 {
205 qpdf_set_ignore_xref_streams(qpdf, QPDF_TRUE);
206 qpdf_read(qpdf, infile, password);
207 qpdf_init_write(qpdf, outfile);
208 qpdf_set_static_ID(qpdf, QPDF_TRUE);
209 qpdf_write(qpdf);
210 report_errors();
211 }
212
test05(char const * infile,char const * password,char const * outfile,char const * xarg)213 static void test05(char const* infile,
214 char const* password,
215 char const* outfile,
216 char const* xarg)
217 {
218 int count = 0;
219 qpdf_read(qpdf, infile, password);
220 qpdf_init_write(qpdf, outfile);
221 qpdf_register_progress_reporter(qpdf, count_progress, (void*)&count);
222 qpdf_set_static_ID(qpdf, QPDF_TRUE);
223 qpdf_set_linearization(qpdf, QPDF_TRUE);
224 qpdf_write(qpdf);
225 /* make sure progress reporter was called */
226 assert(count > 0);
227 report_errors();
228 }
229
test06(char const * infile,char const * password,char const * outfile,char const * xarg)230 static void test06(char const* infile,
231 char const* password,
232 char const* outfile,
233 char const* xarg)
234 {
235 char* buf = NULL;
236 unsigned long size = 0;
237 read_file_into_memory(infile, &buf, &size);
238 qpdf_read_memory(qpdf, infile, buf, size, password);
239 qpdf_init_write(qpdf, outfile);
240 qpdf_set_static_ID(qpdf, QPDF_TRUE);
241 qpdf_set_object_stream_mode(qpdf, qpdf_o_generate);
242 qpdf_write(qpdf);
243 report_errors();
244 free(buf);
245 }
246
test07(char const * infile,char const * password,char const * outfile,char const * xarg)247 static void test07(char const* infile,
248 char const* password,
249 char const* outfile,
250 char const* xarg)
251 {
252 qpdf_read(qpdf, infile, password);
253 qpdf_init_write(qpdf, outfile);
254 qpdf_set_static_ID(qpdf, QPDF_TRUE);
255 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
256 qpdf_write(qpdf);
257 report_errors();
258 }
259
test08(char const * infile,char const * password,char const * outfile,char const * xarg)260 static void test08(char const* infile,
261 char const* password,
262 char const* outfile,
263 char const* xarg)
264 {
265 qpdf_read(qpdf, infile, password);
266 qpdf_init_write(qpdf, outfile);
267 qpdf_set_static_ID(qpdf, QPDF_TRUE);
268 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
269 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
270 qpdf_write(qpdf);
271 report_errors();
272 }
273
test09(char const * infile,char const * password,char const * outfile,char const * xarg)274 static void test09(char const* infile,
275 char const* password,
276 char const* outfile,
277 char const* xarg)
278 {
279 qpdf_read(qpdf, infile, password);
280 qpdf_init_write(qpdf, outfile);
281 qpdf_set_static_ID(qpdf, QPDF_TRUE);
282 qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress);
283 qpdf_write(qpdf);
284 report_errors();
285 }
286
test10(char const * infile,char const * password,char const * outfile,char const * xarg)287 static void test10(char const* infile,
288 char const* password,
289 char const* outfile,
290 char const* xarg)
291 {
292 qpdf_set_attempt_recovery(qpdf, QPDF_FALSE);
293 qpdf_read(qpdf, infile, password);
294 report_errors();
295 }
296
test11(char const * infile,char const * password,char const * outfile,char const * xarg)297 static void test11(char const* infile,
298 char const* password,
299 char const* outfile,
300 char const* xarg)
301 {
302 qpdf_read(qpdf, infile, password);
303 qpdf_init_write(qpdf, outfile);
304 qpdf_set_static_ID(qpdf, QPDF_TRUE);
305 qpdf_set_r2_encryption_parameters(
306 qpdf, "user1", "owner1", QPDF_FALSE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE);
307 qpdf_write(qpdf);
308 report_errors();
309 }
310
test12(char const * infile,char const * password,char const * outfile,char const * xarg)311 static void test12(char const* infile,
312 char const* password,
313 char const* outfile,
314 char const* xarg)
315 {
316 qpdf_read(qpdf, infile, password);
317 qpdf_init_write(qpdf, outfile);
318 qpdf_set_static_ID(qpdf, QPDF_TRUE);
319 qpdf_set_r3_encryption_parameters2(
320 qpdf, "user2", "owner2", QPDF_TRUE, QPDF_TRUE,
321 QPDF_TRUE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE,
322 qpdf_r3p_low);
323 qpdf_write(qpdf);
324 report_errors();
325 }
326
test13(char const * infile,char const * password,char const * outfile,char const * xarg)327 static void test13(char const* infile,
328 char const* password,
329 char const* outfile,
330 char const* xarg)
331 {
332 qpdf_read(qpdf, infile, password);
333 printf("user password: %s\n", qpdf_get_user_password(qpdf));
334 qpdf_init_write(qpdf, outfile);
335 qpdf_set_static_ID(qpdf, QPDF_TRUE);
336 qpdf_set_preserve_encryption(qpdf, QPDF_FALSE);
337 qpdf_write(qpdf);
338 report_errors();
339 }
340
test14(char const * infile,char const * password,char const * outfile,char const * xarg)341 static void test14(char const* infile,
342 char const* password,
343 char const* outfile,
344 char const* xarg)
345 {
346 qpdf_read(qpdf, infile, password);
347 qpdf_init_write(qpdf, outfile);
348 qpdf_set_static_ID(qpdf, QPDF_TRUE);
349 qpdf_set_minimum_pdf_version_and_extension(qpdf, "1.7", 8);
350 qpdf_write(qpdf);
351 qpdf_init_write(qpdf, xarg);
352 qpdf_set_static_ID(qpdf, QPDF_TRUE);
353 qpdf_force_pdf_version(qpdf, "1.4");
354 qpdf_write(qpdf);
355 report_errors();
356 }
357
test15(char const * infile,char const * password,char const * outfile,char const * xarg)358 static void test15(char const* infile,
359 char const* password,
360 char const* outfile,
361 char const* xarg)
362 {
363 qpdf_read(qpdf, infile, password);
364 qpdf_init_write(qpdf, outfile);
365 qpdf_set_static_ID(qpdf, QPDF_TRUE);
366 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
367 qpdf_set_r4_encryption_parameters2(
368 qpdf, "user2", "owner2", QPDF_TRUE, QPDF_TRUE,
369 QPDF_TRUE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE,
370 qpdf_r3p_low, QPDF_TRUE, QPDF_TRUE);
371 qpdf_write(qpdf);
372 report_errors();
373 }
374
print_info(char const * key)375 static void print_info(char const* key)
376 {
377 char const* value = qpdf_get_info_key(qpdf, key);
378 printf("Info key %s: %s\n",
379 key, (value ? value : "(null)"));
380 }
381
test16(char const * infile,char const * password,char const * outfile,char const * xarg)382 static void test16(char const* infile,
383 char const* password,
384 char const* outfile,
385 char const* xarg)
386 {
387 unsigned long buflen = 0L;
388 unsigned char const* buf = 0;
389 FILE* f = 0;
390
391 qpdf_read(qpdf, infile, password);
392 print_info("/Author");
393 print_info("/Producer");
394 print_info("/Creator");
395 qpdf_set_info_key(qpdf, "/Author", "Mr. Potato Head");
396 qpdf_set_info_key(qpdf, "/Producer", "QPDF library");
397 qpdf_set_info_key(qpdf, "/Creator", 0);
398 print_info("/Author");
399 print_info("/Producer");
400 print_info("/Creator");
401 qpdf_init_write_memory(qpdf);
402 qpdf_set_static_ID(qpdf, QPDF_TRUE);
403 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
404 qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress);
405 qpdf_write(qpdf);
406 f = safe_fopen(outfile, "wb");
407 buflen = (unsigned long)(qpdf_get_buffer_length(qpdf));
408 buf = qpdf_get_buffer(qpdf);
409 fwrite(buf, 1, buflen, f);
410 fclose(f);
411 report_errors();
412 }
413
test17(char const * infile,char const * password,char const * outfile,char const * xarg)414 static void test17(char const* infile,
415 char const* password,
416 char const* outfile,
417 char const* xarg)
418 {
419 qpdf_read(qpdf, infile, password);
420 qpdf_init_write(qpdf, outfile);
421 qpdf_set_static_ID(qpdf, QPDF_TRUE);
422 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
423 qpdf_set_r5_encryption_parameters2(
424 qpdf, "user3", "owner3", QPDF_TRUE, QPDF_TRUE,
425 QPDF_TRUE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE,
426 qpdf_r3p_low, QPDF_TRUE);
427 qpdf_write(qpdf);
428 report_errors();
429 }
430
test18(char const * infile,char const * password,char const * outfile,char const * xarg)431 static void test18(char const* infile,
432 char const* password,
433 char const* outfile,
434 char const* xarg)
435 {
436 qpdf_read(qpdf, infile, password);
437 qpdf_init_write(qpdf, outfile);
438 qpdf_set_static_ID(qpdf, QPDF_TRUE);
439 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
440 qpdf_set_r6_encryption_parameters2(
441 qpdf, "user4", "owner4", QPDF_TRUE, QPDF_TRUE,
442 QPDF_TRUE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE,
443 qpdf_r3p_low, QPDF_TRUE);
444 qpdf_write(qpdf);
445 report_errors();
446 }
447
test19(char const * infile,char const * password,char const * outfile,char const * xarg)448 static void test19(char const* infile,
449 char const* password,
450 char const* outfile,
451 char const* xarg)
452 {
453 qpdf_read(qpdf, infile, password);
454 qpdf_init_write(qpdf, outfile);
455 qpdf_set_deterministic_ID(qpdf, QPDF_TRUE);
456 qpdf_write(qpdf);
457 report_errors();
458 }
459
test20(char const * infile,char const * password,char const * outfile,char const * xarg)460 static void test20(char const* infile,
461 char const* password,
462 char const* outfile,
463 char const* xarg)
464 {
465 qpdf_read(qpdf, infile, password);
466 qpdf_init_write(qpdf, outfile);
467 qpdf_set_static_ID(qpdf, QPDF_TRUE);
468 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
469 qpdf_set_compress_streams(qpdf, QPDF_FALSE);
470 qpdf_set_decode_level(qpdf, qpdf_dl_specialized);
471 qpdf_write(qpdf);
472 report_errors();
473 }
474
test21(char const * infile,char const * password,char const * outfile,char const * xarg)475 static void test21(char const* infile,
476 char const* password,
477 char const* outfile,
478 char const* xarg)
479 {
480 qpdf_read(qpdf, infile, password);
481 qpdf_init_write(qpdf, outfile);
482 qpdf_set_static_ID(qpdf, QPDF_TRUE);
483 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
484 qpdf_set_preserve_unreferenced_objects(qpdf, QPDF_TRUE);
485 qpdf_write(qpdf);
486 report_errors();
487 }
488
test22(char const * infile,char const * password,char const * outfile,char const * xarg)489 static void test22(char const* infile,
490 char const* password,
491 char const* outfile,
492 char const* xarg)
493 {
494 qpdf_read(qpdf, infile, password);
495 qpdf_init_write(qpdf, outfile);
496 qpdf_set_static_ID(qpdf, QPDF_TRUE);
497 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
498 qpdf_set_compress_streams(qpdf, QPDF_FALSE);
499 qpdf_set_newline_before_endstream(qpdf, QPDF_TRUE);
500 qpdf_write(qpdf);
501 report_errors();
502 }
503
test23(char const * infile,char const * password,char const * outfile,char const * xarg)504 static void test23(char const* infile,
505 char const* password,
506 char const* outfile,
507 char const* xarg)
508 {
509 QPDF_ERROR_CODE status = 0;
510 qpdf_read(qpdf, infile, password);
511 status = qpdf_check_pdf(qpdf);
512 printf("status: %d\n", status);
513 report_errors();
514 }
515
test24(char const * infile,char const * password,char const * outfile,char const * xarg)516 static void test24(char const* infile,
517 char const* password,
518 char const* outfile,
519 char const* xarg)
520 {
521 /* This test case is designed for minimal.pdf. Pull objects out of
522 * minimal.pdf to make sure all our accessors work as expected.
523 */
524
525 qpdf_read(qpdf, infile, password);
526 qpdf_oh trailer = qpdf_get_trailer(qpdf);
527 /* The library never returns 0 */
528 assert(trailer == 1);
529
530 /* Get root two different ways */
531 qpdf_oh root = qpdf_get_root(qpdf);
532 assert(qpdf_oh_get_generation(qpdf, root) == 0);
533 qpdf_oh root_from_trailer = qpdf_oh_get_key(qpdf, trailer, "/Root");
534 assert(qpdf_oh_get_object_id(qpdf, root) ==
535 qpdf_oh_get_object_id(qpdf, root_from_trailer));
536
537 /* Go to the first page and look at all the keys */
538 qpdf_oh pages = qpdf_oh_get_key(qpdf, root, "/Pages");
539 assert(qpdf_oh_is_dictionary(qpdf, pages));
540 assert(qpdf_oh_get_type_code(qpdf, pages) == ot_dictionary);
541 assert(strcmp(qpdf_oh_get_type_name(qpdf, pages), "dictionary") == 0);
542 assert(qpdf_oh_is_initialized(qpdf, pages));
543 qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids");
544 assert(qpdf_oh_is_array(qpdf, kids));
545 assert(qpdf_oh_get_type_code(qpdf, kids) == ot_array);
546 assert(strcmp(qpdf_oh_get_type_name(qpdf, kids), "array") == 0);
547 assert(qpdf_oh_get_array_n_items(qpdf, kids) == 1);
548 qpdf_oh page1 = qpdf_oh_get_array_item(qpdf, kids, 0);
549 qpdf_oh_begin_dict_key_iter(qpdf, page1);
550 while (qpdf_oh_dict_more_keys(qpdf))
551 {
552 printf("page dictionary key: %s\n", qpdf_oh_dict_next_key(qpdf));
553 }
554
555 /* Inspect the first page */
556 qpdf_oh type = qpdf_oh_get_key(qpdf, page1, "/Type");
557 assert(qpdf_oh_is_name(qpdf, type));
558 assert(qpdf_oh_get_type_code(qpdf, type) == ot_name);
559 assert(strcmp(qpdf_oh_get_type_name(qpdf, type), "name") == 0);
560 assert(strcmp(qpdf_oh_get_name(qpdf, type), "/Page") == 0);
561 qpdf_oh parent = qpdf_oh_get_key(qpdf, page1, "/Parent");
562 assert(qpdf_oh_is_indirect(qpdf, parent));
563 qpdf_oh mediabox = qpdf_oh_get_key(qpdf, page1, "/MediaBox");
564 assert(! qpdf_oh_is_scalar(qpdf, mediabox));
565 assert(qpdf_oh_is_array(qpdf, mediabox));
566 assert(qpdf_oh_get_array_n_items(qpdf, mediabox) == 4);
567 for (int i = 0; i < 4; ++i)
568 {
569 qpdf_oh item = qpdf_oh_get_array_item(qpdf, mediabox, i);
570 printf("item %d: %d %.2f\n",
571 i, qpdf_oh_get_int_value_as_int(qpdf, item),
572 qpdf_oh_get_numeric_value(qpdf, item));
573 }
574
575 /* Exercise different ways of looking at integers */
576 qpdf_oh i2 = qpdf_oh_get_array_item(qpdf, mediabox, 2);
577 assert(qpdf_oh_get_int_value_as_int(qpdf, i2) == 612);
578 assert(qpdf_oh_get_int_value(qpdf, i2) == 612ll);
579 assert(qpdf_oh_get_uint_value_as_uint(qpdf, i2) == 612u);
580 assert(qpdf_oh_get_uint_value(qpdf, i2) == 612ull);
581 /* Exercise accessors of other object types */
582 assert(! qpdf_oh_is_operator(qpdf, i2));
583 assert(! qpdf_oh_is_inline_image(qpdf, i2));
584 /* Chain calls. */
585 qpdf_oh encoding = qpdf_oh_get_key(
586 qpdf, qpdf_oh_get_key(
587 qpdf, qpdf_oh_get_key(
588 qpdf, qpdf_oh_get_key(
589 qpdf, page1, "/Resources"),
590 "/Font"),
591 "/F1"),
592 "/Encoding");
593 assert(strcmp(qpdf_oh_get_name(qpdf, encoding), "/WinAnsiEncoding") == 0);
594
595 /* Look at page contents to exercise stream functions */
596 qpdf_oh contents = qpdf_oh_get_key(qpdf, page1, "/Contents");
597 assert(qpdf_oh_is_stream(qpdf, contents));
598 assert(qpdf_oh_get_type_code(qpdf, contents) == ot_stream);
599 assert(strcmp(qpdf_oh_get_type_name(qpdf, contents), "stream") == 0);
600 qpdf_oh contents_dict = qpdf_oh_get_dict(qpdf, contents);
601 assert(! qpdf_oh_is_scalar(qpdf, contents));
602 assert(! qpdf_oh_is_scalar(qpdf, contents_dict));
603 qpdf_oh contents_length = qpdf_oh_get_key(qpdf, contents_dict, "/Length");
604 assert(qpdf_oh_is_integer(qpdf, contents_length));
605 assert(qpdf_oh_get_type_code(qpdf, contents_length) == ot_integer);
606 assert(strcmp(qpdf_oh_get_type_name(qpdf, contents_length), "integer") == 0);
607 assert(qpdf_oh_is_scalar(qpdf, contents_length));
608 assert(qpdf_oh_is_number(qpdf, contents_length));
609 qpdf_oh contents_array = qpdf_oh_wrap_in_array(qpdf, contents);
610 assert(qpdf_oh_get_array_n_items(qpdf, contents_array) == 1);
611 assert(qpdf_oh_get_object_id(
612 qpdf, qpdf_oh_get_array_item(qpdf, contents_array, 0)) ==
613 qpdf_oh_get_object_id(qpdf, contents));
614 /* Wrap in array for a non-trivial case */
615 qpdf_oh wrapped_contents_array =
616 qpdf_oh_wrap_in_array(qpdf, contents_array);
617 assert(qpdf_oh_get_array_n_items(qpdf, wrapped_contents_array) == 1);
618 assert(qpdf_oh_get_object_id(
619 qpdf, qpdf_oh_get_array_item(qpdf, wrapped_contents_array, 0)) ==
620 qpdf_oh_get_object_id(qpdf, contents));
621
622 /* Exercise functions that work with indirect objects */
623 qpdf_oh resources = qpdf_oh_get_key(qpdf, page1, "/Resources");
624 qpdf_oh procset = qpdf_oh_get_key(qpdf, resources, "/ProcSet");
625 assert(strcmp(qpdf_oh_unparse(qpdf, procset),
626 "5 0 R") == 0);
627 assert(strcmp(qpdf_oh_unparse_resolved(qpdf, procset),
628 "[ /PDF /Text ]") == 0);
629 qpdf_oh_make_direct(qpdf, procset);
630 assert(strcmp(qpdf_oh_unparse(qpdf, procset),
631 "[ /PDF /Text ]") == 0);
632 /* The replaced /ProcSet can be seen to be a direct object in the
633 * expected output PDF.
634 */
635 qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset);
636
637 /* Release and access to exercise handling of object handle errors
638 * and to show that write still works after releasing. This test
639 * uses the default oh error handler, so messages get written to
640 * stderr. The warning about using the default error handler only
641 * appears once.
642 */
643 qpdf_oh_release(qpdf, page1);
644 contents = qpdf_oh_get_key(qpdf, page1, "/Contents");
645 assert(qpdf_oh_is_null(qpdf, contents));
646 assert(qpdf_oh_get_type_code(qpdf, contents) == ot_null);
647 assert(strcmp(qpdf_oh_get_type_name(qpdf, contents), "null") == 0);
648 assert(qpdf_oh_is_array(qpdf, mediabox));
649 qpdf_oh_release_all(qpdf);
650 assert(! qpdf_oh_is_null(qpdf, mediabox));
651 assert(! qpdf_oh_is_array(qpdf, mediabox));
652 /* Make sure something is assigned when we exit so we check that
653 * it gets properly freed.
654 */
655 qpdf_get_root(qpdf);
656
657 qpdf_init_write(qpdf, outfile);
658 qpdf_set_static_ID(qpdf, QPDF_TRUE);
659 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
660 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
661 qpdf_write(qpdf);
662 report_errors();
663 }
664
test25(char const * infile,char const * password,char const * outfile,char const * xarg)665 static void test25(char const* infile,
666 char const* password,
667 char const* outfile,
668 char const* xarg)
669 {
670 /* This test case is designed for minimal.pdf. */
671 qpdf_read(qpdf, infile, password);
672 qpdf_oh root = qpdf_get_root(qpdf);
673
674 /* Parse objects from a string */
675 qpdf_oh parsed = qpdf_oh_parse(
676 qpdf, "[ 1 2.0 (3\xf7) << /Four [/Five] >> null true ]");
677 qpdf_oh p_int = qpdf_oh_get_array_item(qpdf, parsed, 0);
678 qpdf_oh p_real = qpdf_oh_get_array_item(qpdf, parsed, 1);
679 qpdf_oh p_string = qpdf_oh_get_array_item(qpdf, parsed, 2);
680 qpdf_oh p_dict = qpdf_oh_get_array_item(qpdf, parsed, 3);
681 qpdf_oh p_null = qpdf_oh_get_array_item(qpdf, parsed, 4);
682 qpdf_oh p_bool = qpdf_oh_get_array_item(qpdf, parsed, 5);
683 assert(qpdf_oh_is_integer(qpdf, p_int) &&
684 qpdf_oh_get_int_value_as_int(qpdf, p_int) == 1);
685 assert(qpdf_oh_get_type_code(qpdf, p_int) == ot_integer);
686 assert(strcmp(qpdf_oh_get_type_name(qpdf, p_int), "integer") == 0);
687 assert(qpdf_oh_is_real(qpdf, p_real) &&
688 (strcmp(qpdf_oh_get_real_value(qpdf, p_real), "2.0") == 0) &&
689 qpdf_oh_get_numeric_value(qpdf, p_real) == 2.0);
690 assert(qpdf_oh_get_type_code(qpdf, p_real) == ot_real);
691 assert(strcmp(qpdf_oh_get_type_name(qpdf, p_real), "real") == 0);
692 assert(qpdf_oh_is_string(qpdf, p_string) &&
693 (strcmp(qpdf_oh_get_string_value(qpdf, p_string), "3\xf7") == 0) &&
694 (strcmp(qpdf_oh_get_utf8_value(qpdf, p_string), "3\xc3\xb7") == 0) &&
695 (strcmp(qpdf_oh_unparse_binary(qpdf, p_string), "<33f7>") == 0));
696 assert(qpdf_oh_get_type_code(qpdf, p_string) == ot_string);
697 assert(strcmp(qpdf_oh_get_type_name(qpdf, p_string), "string") == 0);
698 assert(qpdf_oh_is_dictionary(qpdf, p_dict));
699 qpdf_oh p_five = qpdf_oh_get_key(qpdf, p_dict, "/Four");
700 assert(qpdf_oh_is_or_has_name(qpdf, p_five, "/Five"));
701 assert(qpdf_oh_is_or_has_name(
702 qpdf, qpdf_oh_get_array_item(qpdf, p_five, 0), "/Five"));
703 assert(qpdf_oh_is_null(qpdf, p_null));
704 assert(qpdf_oh_get_type_code(qpdf, p_null) == ot_null);
705 assert(strcmp(qpdf_oh_get_type_name(qpdf, p_null), "null") == 0);
706 assert(qpdf_oh_is_bool(qpdf, p_bool) &&
707 (qpdf_oh_get_bool_value(qpdf, p_bool) == QPDF_TRUE));
708 assert(qpdf_oh_get_type_code(qpdf, p_bool) == ot_boolean);
709 assert(strcmp(qpdf_oh_get_type_name(qpdf, p_bool), "boolean") == 0);
710 qpdf_oh_erase_item(qpdf, parsed, 4);
711 qpdf_oh_insert_item(
712 qpdf, parsed, 2,
713 qpdf_oh_parse(qpdf, "<</A 1 /B 2 /C 3 /D 4>>"));
714 qpdf_oh new_dict = qpdf_oh_get_array_item(qpdf, parsed, 2);
715 assert(qpdf_oh_has_key(qpdf, new_dict, "/A"));
716 assert(qpdf_oh_has_key(qpdf, new_dict, "/D"));
717 qpdf_oh new_array = qpdf_oh_new_array(qpdf);
718 qpdf_oh_replace_or_remove_key(
719 qpdf, new_dict, "/A", qpdf_oh_new_null(qpdf));
720 qpdf_oh_replace_or_remove_key(
721 qpdf, new_dict, "/B", new_array);
722 qpdf_oh_replace_key(
723 qpdf, new_dict, "/C", qpdf_oh_new_dictionary(qpdf));
724 qpdf_oh_remove_key(qpdf, new_dict, "/D");
725 assert(! qpdf_oh_has_key(qpdf, new_dict, "/A"));
726 assert(! qpdf_oh_has_key(qpdf, new_dict, "/D"));
727 qpdf_oh_append_item(
728 qpdf, new_array, qpdf_oh_new_string(qpdf, "potato"));
729 qpdf_oh_append_item(
730 qpdf, new_array,
731 qpdf_oh_new_unicode_string(qpdf, "qww\xc3\xb7\xcf\x80"));
732 qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 2 */
733 qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 3 */
734 qpdf_oh_set_array_item(
735 qpdf, new_array, 2,
736 qpdf_oh_new_name(qpdf, "/Quack"));
737 qpdf_oh_append_item(
738 qpdf, new_array,
739 qpdf_oh_new_real_from_double(qpdf, 4.123, 2));
740 qpdf_oh_append_item(
741 qpdf, new_array,
742 qpdf_oh_new_real_from_string(qpdf, "5.0"));
743 qpdf_oh_append_item(
744 qpdf, new_array,
745 qpdf_oh_new_integer(qpdf, 6));
746 qpdf_oh_append_item(
747 qpdf, new_array, qpdf_oh_new_bool(qpdf, QPDF_TRUE));
748 qpdf_oh_replace_key(qpdf, root, "/QTest", new_dict);
749
750 qpdf_init_write(qpdf, outfile);
751 qpdf_set_static_ID(qpdf, QPDF_TRUE);
752 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
753 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
754 qpdf_write(qpdf);
755 report_errors();
756 }
test26(char const * infile,char const * password,char const * outfile,char const * xarg)757 static void test26(char const* infile,
758 char const* password,
759 char const* outfile,
760 char const* xarg)
761 {
762 /* Make sure we detect uninitialized objects */
763 qpdf_data qpdf2 = qpdf_init();
764 qpdf_oh trailer = qpdf_get_trailer(qpdf2);
765 assert(! qpdf_oh_is_initialized(qpdf2, trailer));
766 assert(qpdf_oh_get_type_code(qpdf, trailer) == ot_uninitialized);
767 qpdf_cleanup(&qpdf2);
768 }
769
test27(char const * infile,char const * password,char const * outfile,char const * xarg)770 static void test27(char const* infile,
771 char const* password,
772 char const* outfile,
773 char const* xarg)
774 {
775 /* Exercise a string with a null. Since the regular methods return
776 * char*, we can't see past the null character without looking
777 * explicitly at the length.
778 */
779 qpdf_oh p_string_with_null = qpdf_oh_parse(qpdf, "<6f6e650074776f>");
780 assert(qpdf_oh_is_string(qpdf, p_string_with_null));
781 assert(strcmp(qpdf_oh_get_string_value(qpdf, p_string_with_null),
782 "one") == 0);
783 assert(qpdf_get_last_string_length(qpdf) == 7);
784 /* memcmp adds a character to verify the trailing null */
785 assert(memcmp(qpdf_oh_get_string_value(qpdf, p_string_with_null),
786 "one\000two", 8) == 0);
787 size_t length = 0;
788 p_string_with_null = qpdf_oh_new_binary_string(qpdf, "potato\000salad", 12);
789 /* memcmp adds a character to verify the trailing null */
790 assert(memcmp(qpdf_oh_get_binary_string_value(
791 qpdf, p_string_with_null, &length),
792 "potato\000salad", 13) == 0);
793 assert(qpdf_get_last_string_length(qpdf) == 12);
794 assert(length == 12);
795 }
796
test28(char const * infile,char const * password,char const * outfile,char const * xarg)797 static void test28(char const* infile,
798 char const* password,
799 char const* outfile,
800 char const* xarg)
801 {
802 /* This test case is designed for minimal.pdf. */
803
804 /* Look at the media box. The media box is in array. Trivially
805 * wrap it and also clone it and make sure we get different
806 * handles with the same contents.
807 */
808 qpdf_read(qpdf, infile, password);
809 qpdf_oh root = qpdf_get_root(qpdf);
810 qpdf_oh pages = qpdf_oh_get_key(qpdf, root, "/Pages");
811 qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids");
812 qpdf_oh page1 = qpdf_oh_get_array_item(qpdf, kids, 0);
813 qpdf_oh mediabox = qpdf_oh_get_key(qpdf, page1, "/MediaBox");
814 qpdf_oh wrapped_mediabox = qpdf_oh_wrap_in_array(qpdf, mediabox);
815 qpdf_oh cloned_mediabox = qpdf_oh_new_object(qpdf, mediabox);
816 assert(wrapped_mediabox != mediabox);
817 assert(cloned_mediabox != mediabox);
818 assert(qpdf_oh_get_array_n_items(qpdf, wrapped_mediabox) == 4);
819 for (int i = 0; i < 4; ++i)
820 {
821 qpdf_oh item = qpdf_oh_get_array_item(qpdf, mediabox, i);
822 qpdf_oh item2 = qpdf_oh_get_array_item(qpdf, wrapped_mediabox, i);
823 qpdf_oh item3 = qpdf_oh_get_array_item(qpdf, cloned_mediabox, i);
824 assert(qpdf_oh_get_int_value_as_int(qpdf, item) ==
825 (i == 0 ? 0 :
826 i == 1 ? 0 :
827 i == 2 ? 612 :
828 i == 3 ? 792 :
829 -1));
830 assert(qpdf_oh_get_int_value_as_int(qpdf, item) ==
831 qpdf_oh_get_int_value_as_int(qpdf, item2));
832 assert(qpdf_oh_get_int_value_as_int(qpdf, item) ==
833 qpdf_oh_get_int_value_as_int(qpdf, item3));
834 qpdf_oh_release(qpdf, item);
835 }
836 }
837
test29(char const * infile,char const * password,char const * outfile,char const * xarg)838 static void test29(char const* infile,
839 char const* password,
840 char const* outfile,
841 char const* xarg)
842 {
843 /* Trap exceptions thrown by object accessors. Type mismatches are
844 * errors rather than warnings when they don't have an owning QPDF
845 * object.
846 */
847 qpdf_silence_errors(qpdf);
848
849 /* get_root fails when we have no trailer */
850 qpdf_oh root = qpdf_get_root(qpdf);
851 handle_oh_error(qpdf, "get root");
852 assert(root != 0);
853 assert(! qpdf_oh_is_initialized(qpdf, root));
854
855 assert(! qpdf_oh_is_initialized(qpdf, qpdf_oh_parse(qpdf, "[oops")));
856 handle_oh_error(qpdf, "bad parse");
857 report_errors();
858
859 assert(qpdf_oh_get_int_value_as_int(
860 qpdf, qpdf_oh_new_string(qpdf, "x")) == 0);
861 handle_oh_error(qpdf, "type mismatch (int operation on string)");
862 qpdf_oh int_oh = qpdf_oh_new_integer(qpdf, 12);
863 assert(strlen(qpdf_oh_get_string_value(qpdf, int_oh)) == 0);
864 handle_oh_error(qpdf, "type mismatch (string operation on int)");
865
866 // This doesn't test every possible error flow, but it tests each
867 // way of handling errors in the library code.
868 assert(qpdf_oh_get_array_n_items(qpdf, int_oh) == 0);
869 handle_oh_error(qpdf, "array type mismatch - n_items");
870 assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_array_item(qpdf, int_oh, 3)));
871 handle_oh_error(qpdf, "array type mismatch - item");
872 qpdf_oh_append_item(qpdf, int_oh, qpdf_oh_new_null(qpdf));
873 handle_oh_error(qpdf, "append to non-array");
874 qpdf_oh array = qpdf_oh_new_array(qpdf);
875 assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_array_item(qpdf, array, 3)));
876 handle_oh_error(qpdf, "array bounds");
877
878 qpdf_oh_begin_dict_key_iter(qpdf, int_oh);
879 assert(qpdf_oh_dict_more_keys(qpdf) == QPDF_FALSE);
880 handle_oh_error(qpdf, "dictionary iter type mismatch");
881 assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_key(qpdf, int_oh, "potato")));
882 handle_oh_error(qpdf, "dictionary type mismatch");
883 assert(qpdf_oh_has_key(qpdf, int_oh, "potato") == QPDF_FALSE);
884 handle_oh_error(qpdf, "dictionary type mismatch");
885
886 report_errors();
887 }
888
test30(char const * infile,char const * password,char const * outfile,char const * xarg)889 static void test30(char const* infile,
890 char const* password,
891 char const* outfile,
892 char const* xarg)
893 {
894 assert(qpdf_read(qpdf, infile, password) & QPDF_ERRORS);
895 /* Fail to handle error */
896 }
897
test31(char const * infile,char const * password,char const * outfile,char const * xarg)898 static void test31(char const* infile,
899 char const* password,
900 char const* outfile,
901 char const* xarg)
902 {
903 /* Make sure type warnings have a specific error code. This test
904 * case is designed for minimal.pdf.
905 */
906 qpdf_read(qpdf, infile, password);
907 qpdf_oh trailer = qpdf_get_trailer(qpdf);
908 assert(qpdf_oh_get_int_value(qpdf, trailer) == 0LL);
909 assert(! qpdf_has_error(qpdf));
910 assert(qpdf_more_warnings(qpdf));
911 qpdf_error e = qpdf_next_warning(qpdf);
912 assert(qpdf_get_error_code(qpdf, e) == qpdf_e_object);
913 report_errors();
914 }
915
test32(char const * infile,char const * password,char const * outfile,char const * xarg)916 static void test32(char const* infile,
917 char const* password,
918 char const* outfile,
919 char const* xarg)
920 {
921 /* This test case is designed for minimal.pdf. */
922 assert(qpdf_read(qpdf, infile, password) == 0);
923 qpdf_oh page = qpdf_get_object_by_id(qpdf, 3, 0);
924 assert(qpdf_oh_is_dictionary(qpdf, page));
925 assert(qpdf_oh_has_key(qpdf, page, "/MediaBox"));
926 report_errors();
927 }
928
test33(char const * infile,char const * password,char const * outfile,char const * xarg)929 static void test33(char const* infile,
930 char const* password,
931 char const* outfile,
932 char const* xarg)
933 {
934 /* This test case is designed for minimal.pdf. */
935
936 /* Convert a direct object to an indirect object and replace it. */
937 assert(qpdf_read(qpdf, infile, password) == 0);
938 qpdf_oh root = qpdf_get_root(qpdf);
939 qpdf_oh pages = qpdf_oh_get_key(qpdf, root, "/Pages");
940 qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids");
941 qpdf_oh page1 = qpdf_oh_get_array_item(qpdf, kids, 0);
942 qpdf_oh mediabox = qpdf_oh_get_key(qpdf, page1, "/MediaBox");
943 assert(! qpdf_oh_is_indirect(qpdf, mediabox));
944 qpdf_oh i_mediabox = qpdf_make_indirect_object(qpdf, mediabox);
945 assert(qpdf_oh_is_indirect(qpdf, i_mediabox));
946 qpdf_oh_replace_key(qpdf, page1, "/MediaBox", i_mediabox);
947
948 /* Replace a different indirect object */
949 qpdf_oh resources = qpdf_oh_get_key(qpdf, page1, "/Resources");
950 qpdf_oh procset = qpdf_oh_get_key(qpdf, resources, "/ProcSet");
951 assert(qpdf_oh_is_indirect(qpdf, procset));
952 qpdf_replace_object(
953 qpdf,
954 qpdf_oh_get_object_id(qpdf, procset),
955 qpdf_oh_get_generation(qpdf, procset),
956 qpdf_oh_parse(qpdf, "[/PDF]"));
957
958 qpdf_init_write(qpdf, outfile);
959 qpdf_set_static_ID(qpdf, QPDF_TRUE);
960 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
961 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
962 qpdf_write(qpdf);
963 report_errors();
964 }
965
test34(char const * infile,char const * password,char const * outfile,char const * xarg)966 static void test34(char const* infile,
967 char const* password,
968 char const* outfile,
969 char const* xarg)
970 {
971 /* This test expects 11-pages.pdf as file1 and minimal.pdf as xarg. */
972
973 /* Non-error cases for page API */
974
975 qpdf_data qpdf2 = qpdf_init();
976 assert(qpdf_read(qpdf, infile, password) == 0);
977 assert(qpdf_read(qpdf2, xarg, "") == 0);
978 assert(qpdf_get_num_pages(qpdf) == 11);
979 assert(qpdf_get_num_pages(qpdf2) == 1);
980
981 /* At this time, there is no C API for accessing stream data, so
982 * we hard-code object IDs from a known input file.
983 */
984 assert(qpdf_oh_get_object_id(qpdf, qpdf_get_page_n(qpdf, 0)) == 4);
985 assert(qpdf_oh_get_object_id(qpdf, qpdf_get_page_n(qpdf, 10)) == 14);
986 qpdf_oh page3 = qpdf_get_page_n(qpdf, 3);
987 assert(qpdf_find_page_by_oh(qpdf, page3) == 3);
988 assert(qpdf_find_page_by_id(
989 qpdf, qpdf_oh_get_object_id(qpdf, page3), 0) == 3);
990
991 /* Add other page to the end */
992 qpdf_oh opage0 = qpdf_get_page_n(qpdf2, 0);
993 assert(qpdf_add_page(qpdf, qpdf2, opage0, QPDF_FALSE) == 0);
994 /* Add other page before page 3 */
995 assert(qpdf_add_page_at(qpdf, qpdf2, opage0, QPDF_TRUE, page3) == 0);
996 /* Remove page 3 */
997 assert(qpdf_remove_page(qpdf, page3) == 0);
998 /* At page 3 back at the beginning */
999 assert(qpdf_add_page(qpdf, qpdf, page3, QPDF_TRUE) == 0);
1000
1001 qpdf_init_write(qpdf, outfile);
1002 qpdf_set_static_ID(qpdf, QPDF_TRUE);
1003 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
1004 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
1005 qpdf_write(qpdf);
1006 report_errors();
1007 qpdf_cleanup(&qpdf2);
1008 }
1009
test35(char const * infile,char const * password,char const * outfile,char const * xarg)1010 static void test35(char const* infile,
1011 char const* password,
1012 char const* outfile,
1013 char const* xarg)
1014 {
1015 /* This test uses 11-pages.pdf */
1016
1017 assert(qpdf_get_num_pages(qpdf) == -1);
1018 assert(qpdf_has_error(qpdf));
1019 qpdf_error e = qpdf_get_error(qpdf);
1020 assert(qpdf_get_error_code(qpdf, e) != QPDF_SUCCESS);
1021 assert(! qpdf_has_error(qpdf));
1022
1023 assert(qpdf_read(qpdf, infile, password) == 0);
1024
1025 qpdf_oh range = qpdf_get_page_n(qpdf, 11);
1026 assert(! qpdf_oh_is_initialized(qpdf, range));
1027 assert(qpdf_has_error(qpdf));
1028 e = qpdf_get_error(qpdf);
1029 assert(qpdf_get_error_code(qpdf, e) != QPDF_SUCCESS);
1030 assert(! qpdf_has_error(qpdf));
1031
1032 assert(qpdf_find_page_by_id(qpdf, 100, 0) == -1);
1033 assert(qpdf_has_error(qpdf));
1034 e = qpdf_get_error(qpdf);
1035 assert(qpdf_get_error_code(qpdf, e) != QPDF_SUCCESS);
1036 assert(! qpdf_has_error(qpdf));
1037
1038 assert(qpdf_find_page_by_oh(qpdf, qpdf_get_root(qpdf)) == -1);
1039 assert(qpdf_more_warnings(qpdf));
1040 e = qpdf_next_warning(qpdf);
1041 assert(qpdf_get_error_code(qpdf, e) != QPDF_SUCCESS);
1042 assert(qpdf_has_error(qpdf));
1043 e = qpdf_get_error(qpdf);
1044 assert(qpdf_get_error_code(qpdf, e) != QPDF_SUCCESS);
1045 assert(! qpdf_has_error(qpdf));
1046
1047 assert(qpdf_find_page_by_id(qpdf, 100, 0) == -1);
1048 assert(qpdf_has_error(qpdf));
1049 e = qpdf_get_error(qpdf);
1050 assert(qpdf_get_error_code(qpdf, e) != QPDF_SUCCESS);
1051 assert(! qpdf_has_error(qpdf));
1052
1053 assert(qpdf_add_page(qpdf, qpdf, 1000, QPDF_FALSE) != 0);
1054
1055 report_errors();
1056 }
1057
test36(char const * infile,char const * password,char const * outfile,char const * xarg)1058 static void test36(char const* infile,
1059 char const* password,
1060 char const* outfile,
1061 char const* xarg)
1062 {
1063 /* This test uses inherited-rotate.pdf */
1064
1065 assert(qpdf_read(qpdf, infile, password) == 0);
1066
1067 /* Non-trivially push inherited attributes */
1068 qpdf_oh page0 = qpdf_get_object_by_id(qpdf, 3, 0);
1069 assert(qpdf_oh_is_dictionary(qpdf, page0));
1070 qpdf_oh r = qpdf_oh_get_key(qpdf, page0, "/Rotate");
1071 assert(qpdf_oh_get_int_value(qpdf, r) == 90);
1072 qpdf_oh_remove_key(qpdf, page0, "/Rotate");
1073 assert(! qpdf_oh_has_key(qpdf, page0, "/Rotate"));
1074
1075 assert(qpdf_push_inherited_attributes_to_page(qpdf) == 0);
1076 r = qpdf_oh_get_key(qpdf, page0, "/Rotate");
1077 assert(qpdf_oh_get_int_value(qpdf, r) == 270);
1078
1079 assert(qpdf_add_page(qpdf, qpdf, page0, QPDF_TRUE) == 0);
1080 }
1081
test37(char const * infile,char const * password,char const * outfile,char const * xarg)1082 static void test37(char const* infile,
1083 char const* password,
1084 char const* outfile,
1085 char const* xarg)
1086 {
1087 /* This test uses 11-pages.pdf */
1088
1089 /* Manually manipulate pages tree */
1090 assert(qpdf_read(qpdf, infile, password) == 0);
1091 assert(qpdf_get_num_pages(qpdf) == 11);
1092 qpdf_oh pages = qpdf_get_object_by_id(qpdf, 3, 0);
1093 qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids");
1094 assert(qpdf_oh_get_array_n_items(qpdf, kids) == 11);
1095 qpdf_oh_erase_item(qpdf, kids, 0);
1096 assert(qpdf_get_num_pages(qpdf) == 11);
1097 assert(qpdf_update_all_pages_cache(qpdf) == 0);
1098 assert(qpdf_get_num_pages(qpdf) == 10);
1099 }
1100
test38(char const * infile,char const * password,char const * outfile,char const * xarg)1101 static void test38(char const* infile,
1102 char const* password,
1103 char const* outfile,
1104 char const* xarg)
1105 {
1106 /* This test expects 11-pages.pdf. */
1107
1108 /* Read stream data */
1109
1110 assert(qpdf_read(qpdf, infile, password) == 0);
1111 qpdf_oh stream = qpdf_get_object_by_id(qpdf, 17, 0);
1112 qpdf_oh dict = qpdf_oh_get_dict(qpdf, stream);
1113 assert(qpdf_oh_get_int_value_as_int(
1114 qpdf, qpdf_oh_get_key(qpdf, dict, "/Length")) == 53);
1115 /* Get raw data */
1116 unsigned char *buf = 0;
1117 size_t len = 0;
1118 assert(qpdf_oh_get_stream_data(
1119 qpdf, stream, qpdf_dl_none, 0, &buf, &len) == 0);
1120 assert(len == 53);
1121 assert(((int)buf[0] == 'x') && ((int)buf[1] == 0234));
1122 free(buf);
1123
1124 /* Test whether filterable */
1125 QPDF_BOOL filtered = QPDF_FALSE;
1126 assert(qpdf_oh_get_stream_data(
1127 qpdf, stream, qpdf_dl_all, &filtered, 0, 0) == 0);
1128 assert(filtered == QPDF_TRUE);
1129
1130 /* Get filtered data */
1131 assert(qpdf_oh_get_stream_data(
1132 qpdf, stream, qpdf_dl_all, 0, &buf, &len) == 0);
1133 assert(len == 47);
1134 assert(memcmp((char const*)buf,
1135 "BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET\n",
1136 len) == 0);
1137
1138 /* Get page data */
1139 qpdf_oh page2 = qpdf_get_page_n(qpdf, 1); /* 0-based index */
1140 unsigned char* buf2 = 0;
1141 assert(qpdf_oh_get_page_content_data(qpdf, page2, &buf2, &len) == 0);
1142 assert(len == 47);
1143 assert(memcmp(buf, buf2, len) == 0);
1144 free(buf);
1145 free(buf2);
1146
1147 /* errors */
1148 printf("page content on broken page\n");
1149 qpdf_oh_replace_key(qpdf, page2, "/Contents", qpdf_oh_new_integer(qpdf, 3));
1150 buf = 0;
1151 qpdf_oh_get_page_content_data(qpdf, page2, &buf, &len);
1152 assert(buf == 0);
1153 report_errors();
1154 printf("stream data for non stream\n");
1155 qpdf_oh root = qpdf_get_root(qpdf);
1156 assert(qpdf_oh_get_stream_data(qpdf, root, qpdf_dl_all, 0, 0, 0) != 0);
1157 report_errors();
1158 }
1159
test39(char const * infile,char const * password,char const * outfile,char const * xarg)1160 static void test39(char const* infile,
1161 char const* password,
1162 char const* outfile,
1163 char const* xarg)
1164 {
1165 /* This test expects 11-pages.pdf as file1 and minimal.pdf as xarg. */
1166
1167 /* Foreign object */
1168
1169 qpdf_data qpdf2 = qpdf_init();
1170 assert(qpdf_read(qpdf, infile, password) == 0);
1171 assert(qpdf_read(qpdf2, xarg, "") == 0);
1172
1173 qpdf_oh resources = qpdf_get_object_by_id(qpdf2, 3, 0);
1174 qpdf_oh copy = qpdf_oh_copy_foreign_object(qpdf, qpdf2, resources);
1175 qpdf_oh root = qpdf_get_root(qpdf);
1176 qpdf_oh_replace_key(qpdf, root, "/Copy", copy);
1177
1178 qpdf_init_write(qpdf, outfile);
1179 qpdf_set_static_ID(qpdf, QPDF_TRUE);
1180 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
1181 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
1182 qpdf_write(qpdf);
1183 report_errors();
1184 qpdf_cleanup(&qpdf2);
1185 }
1186
test40(char const * infile,char const * password,char const * outfile,char const * xarg)1187 static void test40(char const* infile,
1188 char const* password,
1189 char const* outfile,
1190 char const* xarg)
1191 {
1192 /* This test expects minimal.pdf. */
1193
1194 /* New stream */
1195
1196 assert(qpdf_read(qpdf, infile, password) == 0);
1197 qpdf_oh stream = qpdf_oh_new_stream(qpdf);
1198 qpdf_oh_replace_stream_data(
1199 qpdf, stream,
1200 (unsigned char*)"12345\000abcde", 11, /* embedded null */
1201 qpdf_oh_new_null(qpdf), qpdf_oh_new_null(qpdf));
1202 qpdf_oh root = qpdf_get_root(qpdf);
1203 qpdf_oh_replace_key(qpdf, root, "/Potato", stream);
1204
1205 qpdf_init_write(qpdf, outfile);
1206 qpdf_set_static_ID(qpdf, QPDF_TRUE);
1207 qpdf_set_qdf_mode(qpdf, QPDF_TRUE);
1208 qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE);
1209 qpdf_write(qpdf);
1210 report_errors();
1211 }
1212
main(int argc,char * argv[])1213 int main(int argc, char* argv[])
1214 {
1215 char* p = 0;
1216 int n = 0;
1217 char const* infile = 0;
1218 char const* password = 0;
1219 char const* outfile = 0;
1220 char const* xarg = 0;
1221 void (*fn)(char const*, char const*, char const*, char const*) = 0;
1222
1223 if ((p = strrchr(argv[0], '/')) != NULL)
1224 {
1225 whoami = p + 1;
1226 }
1227 else if ((p = strrchr(argv[0], '\\')) != NULL)
1228 {
1229 whoami = p + 1;
1230 }
1231 else
1232 {
1233 whoami = argv[0];
1234 }
1235 if ((argc == 2) && (strcmp(argv[1], "--version") == 0))
1236 {
1237 printf("qpdf-ctest version %s\n", qpdf_get_qpdf_version());
1238 return 0;
1239 }
1240
1241 if (argc < 5)
1242 {
1243 fprintf(stderr, "usage: %s n infile password outfile\n", whoami);
1244 exit(2);
1245 }
1246
1247 n = atoi(argv[1]);
1248 infile = argv[2];
1249 password = argv[3];
1250 outfile = argv[4];
1251 xarg = (argc > 5 ? argv[5] : 0);
1252
1253 fn = ((n == 1) ? test01 :
1254 (n == 2) ? test02 :
1255 (n == 3) ? test03 :
1256 (n == 4) ? test04 :
1257 (n == 5) ? test05 :
1258 (n == 6) ? test06 :
1259 (n == 7) ? test07 :
1260 (n == 8) ? test08 :
1261 (n == 9) ? test09 :
1262 (n == 10) ? test10 :
1263 (n == 11) ? test11 :
1264 (n == 12) ? test12 :
1265 (n == 13) ? test13 :
1266 (n == 14) ? test14 :
1267 (n == 15) ? test15 :
1268 (n == 16) ? test16 :
1269 (n == 17) ? test17 :
1270 (n == 18) ? test18 :
1271 (n == 19) ? test19 :
1272 (n == 20) ? test20 :
1273 (n == 21) ? test21 :
1274 (n == 22) ? test22 :
1275 (n == 23) ? test23 :
1276 (n == 24) ? test24 :
1277 (n == 25) ? test25 :
1278 (n == 26) ? test26 :
1279 (n == 27) ? test27 :
1280 (n == 28) ? test28 :
1281 (n == 29) ? test29 :
1282 (n == 30) ? test30 :
1283 (n == 31) ? test31 :
1284 (n == 32) ? test32 :
1285 (n == 33) ? test33 :
1286 (n == 34) ? test34 :
1287 (n == 35) ? test35 :
1288 (n == 36) ? test36 :
1289 (n == 37) ? test37 :
1290 (n == 38) ? test38 :
1291 (n == 39) ? test39 :
1292 (n == 40) ? test40 :
1293 0);
1294
1295 if (fn == 0)
1296 {
1297 fprintf(stderr, "%s: invalid test number %d\n", whoami, n);
1298 exit(2);
1299 }
1300
1301 qpdf = qpdf_init();
1302 fn(infile, password, outfile, xarg);
1303 qpdf_cleanup(&qpdf);
1304 assert(qpdf == 0);
1305 printf("C test %d done\n", n);
1306
1307 return 0;
1308 }
1309