Commit bc4e2320e7dafea8b6d6b6150c808ed2a98d7d03
1 parent
03e67a28
Add qpdfjob-c.h -- simple C API around parts of QPDFJob
Showing
12 changed files
with
245 additions
and
5 deletions
include/qpdf/qpdfjob-c.h
0 → 100644
| 1 | +/* Copyright (c) 2005-2021 Jay Berkenbilt | |
| 2 | + * | |
| 3 | + * This file is part of qpdf. | |
| 4 | + * | |
| 5 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
| 6 | + * you may not use this file except in compliance with the License. | |
| 7 | + * You may obtain a copy of the License at | |
| 8 | + * | |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | + * | |
| 11 | + * Unless required by applicable law or agreed to in writing, software | |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | + * See the License for the specific language governing permissions and | |
| 15 | + * limitations under the License. | |
| 16 | + * | |
| 17 | + * Versions of qpdf prior to version 7 were released under the terms | |
| 18 | + * of version 2.0 of the Artistic License. At your option, you may | |
| 19 | + * continue to consider qpdf to be licensed under those terms. Please | |
| 20 | + * see the manual for additional information. | |
| 21 | + */ | |
| 22 | + | |
| 23 | +#ifndef QPDFJOB_C_H | |
| 24 | +#define QPDFJOB_C_H | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * This file defines a basic "C" API for QPDFJob. See also qpdf-c.h, | |
| 28 | + * which defines an API that exposes more of the library's API. This | |
| 29 | + * API is primarily intended to make it simpler for programs in | |
| 30 | + * languages other than C++ to incorporate functionality that could be | |
| 31 | + * run directly from the command-line. | |
| 32 | + */ | |
| 33 | + | |
| 34 | +#include <qpdf/DLL.h> | |
| 35 | +#include <string.h> | |
| 36 | +#ifndef QPDF_NO_WCHAR_T | |
| 37 | +# include <wchar.h> | |
| 38 | +#endif | |
| 39 | + | |
| 40 | +/* | |
| 41 | + * This file provides a minimal wrapper around QPDFJob. See | |
| 42 | + * examples/qpdf-job.c for an example of its use. | |
| 43 | + */ | |
| 44 | + | |
| 45 | +#ifdef __cplusplus | |
| 46 | +extern "C" { | |
| 47 | +#endif | |
| 48 | + /* This function does the equivalent of running the qpdf | |
| 49 | + * command-line with the given arguments and returns the exit code | |
| 50 | + * that qpdf would use. Note that arguments must be UTF8-encoded. | |
| 51 | + * If calling this from wmain on Windows, use | |
| 52 | + * qpdfjob_run_from_wide_argv instead. | |
| 53 | + */ | |
| 54 | + QPDF_DLL | |
| 55 | + int qpdfjob_run_from_argv(int argc, char* argv[]); | |
| 56 | + | |
| 57 | +#ifndef QPDF_NO_WCHAR_T | |
| 58 | + /* This function is the same as qpdfjob_run_from_argv except argv | |
| 59 | + * is encoded with wide characters. This would suitable for | |
| 60 | + * calling from a Windows wmain function. | |
| 61 | + */ | |
| 62 | + QPDF_DLL | |
| 63 | + int qpdfjob_run_from_wide_argv(int argc, wchar_t* argv[]); | |
| 64 | +#endif /* QPDF_NO_WCHAR_T */ | |
| 65 | + | |
| 66 | + /* This function runs QPDFJob from a job JSON file. See the "QPDF | |
| 67 | + * Job" section of the manual for details. The JSON string must be | |
| 68 | + * UTF8-encoded. It returns the error code that qpdf would return | |
| 69 | + * with the equivalent command-line invocation. | |
| 70 | + */ | |
| 71 | + QPDF_DLL | |
| 72 | + int qpdfjob_run_from_json(char const* json); | |
| 73 | + | |
| 74 | +#ifdef __cplusplus | |
| 75 | +} | |
| 76 | +#endif | |
| 77 | + | |
| 78 | + | |
| 79 | +#endif /* QPDFJOB_C_H */ | ... | ... |
libqpdf/build.mk
| ... | ... | @@ -115,7 +115,8 @@ SRCS_libqpdf = \ |
| 115 | 115 | libqpdf/SecureRandomDataProvider.cc \ |
| 116 | 116 | libqpdf/SF_FlateLzwDecode.cc \ |
| 117 | 117 | libqpdf/SparseOHArray.cc \ |
| 118 | - libqpdf/qpdf-c.cc | |
| 118 | + libqpdf/qpdf-c.cc \ | |
| 119 | + libqpdf/qpdfjob-c.cc | |
| 119 | 120 | |
| 120 | 121 | ifeq ($(USE_CRYPTO_NATIVE), 1) |
| 121 | 122 | SRCS_libqpdf += $(CRYPTO_NATIVE) | ... | ... |
libqpdf/qpdfjob-c.cc
0 → 100644
| 1 | +#include <qpdf/qpdfjob-c.h> | |
| 2 | + | |
| 3 | +#include <qpdf/QPDFJob.hh> | |
| 4 | +#include <qpdf/QUtil.hh> | |
| 5 | +#include <qpdf/QPDFUsage.hh> | |
| 6 | + | |
| 7 | +#include <cstdio> | |
| 8 | +#include <cstring> | |
| 9 | + | |
| 10 | +int qpdfjob_run_from_argv(int argc, char* argv[]) | |
| 11 | +{ | |
| 12 | + auto whoami = QUtil::getWhoami(argv[0]); | |
| 13 | + QUtil::setLineBuf(stdout); | |
| 14 | + | |
| 15 | + QPDFJob j; | |
| 16 | + try | |
| 17 | + { | |
| 18 | + j.initializeFromArgv(argc, argv); | |
| 19 | + j.run(); | |
| 20 | + } | |
| 21 | + catch (std::exception& e) | |
| 22 | + { | |
| 23 | + std::cerr << whoami << ": " << e.what() << std::endl; | |
| 24 | + return QPDFJob::EXIT_ERROR; | |
| 25 | + } | |
| 26 | + return j.getExitCode(); | |
| 27 | +} | |
| 28 | + | |
| 29 | +#ifndef QPDF_NO_WCHAR_T | |
| 30 | +int qpdfjob_run_from_wide_argv(int argc, wchar_t* argv[]) | |
| 31 | +{ | |
| 32 | + return QUtil::call_main_from_wmain(argc, argv, qpdfjob_run_from_argv); | |
| 33 | +} | |
| 34 | +#endif // QPDF_NO_WCHAR_T | |
| 35 | + | |
| 36 | +int qpdfjob_run_from_json(char const* json) | |
| 37 | +{ | |
| 38 | + QPDFJob j; | |
| 39 | + try | |
| 40 | + { | |
| 41 | + j.initializeFromJson(json); | |
| 42 | + j.run(); | |
| 43 | + } | |
| 44 | + catch (std::exception& e) | |
| 45 | + { | |
| 46 | + std::cerr << "qpdfjob json: " << e.what() << std::endl; | |
| 47 | + return QPDFJob::EXIT_ERROR; | |
| 48 | + } | |
| 49 | + return j.getExitCode(); | |
| 50 | +} | ... | ... |
manual/qpdf-job.rst
| ... | ... | @@ -14,7 +14,7 @@ executable is available from inside the C++ library using the |
| 14 | 14 | |
| 15 | 15 | - Use from the C++ API with ``QPDFJob::initializeFromArgv`` |
| 16 | 16 | |
| 17 | - - Use from the C API with QXXXQ | |
| 17 | + - Use from the C API with ``qpdfjob_run_from_argv`` from :file:`qpdfjob-c.h` | |
| 18 | 18 | |
| 19 | 19 | - The job JSON file format |
| 20 | 20 | |
| ... | ... | @@ -22,7 +22,7 @@ executable is available from inside the C++ library using the |
| 22 | 22 | |
| 23 | 23 | - Use from the C++ API with ``QPDFJob::initializeFromJson`` |
| 24 | 24 | |
| 25 | - - Use from the C API with QXXXQ | |
| 25 | + - Use from the C API with ``qpdfjob_run_from_json`` from :file:`qpdfjob-c.h` | |
| 26 | 26 | |
| 27 | 27 | - The ``QPDFJob`` C++ API |
| 28 | 28 | ... | ... |
qpdf/build.mk
| ... | ... | @@ -12,7 +12,9 @@ BINS_qpdf = \ |
| 12 | 12 | test_tokenizer \ |
| 13 | 13 | test_unicode_filenames \ |
| 14 | 14 | test_xref |
| 15 | -CBINS_qpdf = qpdf-ctest | |
| 15 | +CBINS_qpdf = \ | |
| 16 | + qpdf-ctest \ | |
| 17 | + qpdfjob-ctest | |
| 16 | 18 | |
| 17 | 19 | TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B))) |
| 18 | 20 | ... | ... |
qpdf/qpdfjob-ctest.c
0 → 100644
| 1 | +#include <qpdf/qpdfjob-c.h> | |
| 2 | +#include <stdio.h> | |
| 3 | +#include <assert.h> | |
| 4 | +#include <stdlib.h> | |
| 5 | +#include <string.h> | |
| 6 | + | |
| 7 | +#ifndef QPDF_NO_WCHAR_T | |
| 8 | +static void wide_test() | |
| 9 | +{ | |
| 10 | + wchar_t* argv[5]; | |
| 11 | + argv[0] = (wchar_t*)(L"qpdfjob"); | |
| 12 | + argv[1] = (wchar_t*)(L"minimal.pdf"); | |
| 13 | + argv[2] = (wchar_t*)(L"a.pdf"); | |
| 14 | + argv[3] = (wchar_t*)(L"--static-id"); | |
| 15 | + argv[4] = NULL; | |
| 16 | + assert(qpdfjob_run_from_wide_argv(4, argv) == 0); | |
| 17 | + printf("wide test passed\n"); | |
| 18 | +} | |
| 19 | +#endif // QPDF_NO_WCHAR_T | |
| 20 | + | |
| 21 | +static void run_tests() | |
| 22 | +{ | |
| 23 | + /* Be sure to use a different output file for each test. */ | |
| 24 | + | |
| 25 | + char* argv[5]; | |
| 26 | + argv[0] = (char*)("qpdfjob"); | |
| 27 | + argv[1] = (char*)("minimal.pdf"); | |
| 28 | + argv[2] = (char*)("a.pdf"); | |
| 29 | + argv[3] = (char*)("--deterministic-id"); | |
| 30 | + argv[4] = NULL; | |
| 31 | + assert(qpdfjob_run_from_argv(4, argv) == 0); | |
| 32 | + printf("argv test passed\n"); | |
| 33 | + | |
| 34 | + assert(qpdfjob_run_from_json("{\n\ | |
| 35 | + \"inputFile\": \"20-pages.pdf\",\n\ | |
| 36 | + \"password\": \"user\",\n\ | |
| 37 | + \"outputFile\": \"b.pdf\",\n\ | |
| 38 | + \"staticId\": \"\",\n\ | |
| 39 | + \"decrypt\": \"\",\n\ | |
| 40 | + \"objectStreams\": \"generate\"\n\ | |
| 41 | +}") == 0); | |
| 42 | + printf("json test passed\n"); | |
| 43 | + | |
| 44 | + assert(qpdfjob_run_from_json("{\n\ | |
| 45 | + \"inputFile\": \"xref-with-short-size.pdf\",\n\ | |
| 46 | + \"outputFile\": \"c.pdf\",\n\ | |
| 47 | + \"staticId\": \"\",\n\ | |
| 48 | + \"decrypt\": \"\",\n\ | |
| 49 | + \"objectStreams\": \"generate\"\n\ | |
| 50 | +}") == 3); | |
| 51 | + printf("json warn test passed\n"); | |
| 52 | + | |
| 53 | + assert(qpdfjob_run_from_json("{\n\ | |
| 54 | + \"inputFile\": \"nothing-there.pdf\"\n\ | |
| 55 | +}") == 2); | |
| 56 | + printf("json error test passed\n"); | |
| 57 | +} | |
| 58 | + | |
| 59 | +int main(int argc, char* argv[]) | |
| 60 | +{ | |
| 61 | + if ((argc == 2) && (strcmp(argv[1], "wide") == 0)) | |
| 62 | + { | |
| 63 | +#ifndef QPDF_NO_WCHAR_T | |
| 64 | + wide_test(); | |
| 65 | +#else | |
| 66 | + printf("skipped wide\n"); | |
| 67 | +#endif // QPDF_NO_WCHAR_T | |
| 68 | + return 0; | |
| 69 | + } | |
| 70 | + | |
| 71 | + run_tests(); | |
| 72 | + return 0; | |
| 73 | +} | ... | ... |
qpdf/qtest/qpdf.test
| ... | ... | @@ -402,7 +402,7 @@ my @good_json = ( |
| 402 | 402 | "underlay-overlay-password", |
| 403 | 403 | "misc-options", |
| 404 | 404 | ); |
| 405 | -$n_tests += 4 + scalar(@bad_json) + (2 * scalar(@good_json)); | |
| 405 | +$n_tests += 10 + scalar(@bad_json) + (2 * scalar(@good_json)); | |
| 406 | 406 | |
| 407 | 407 | |
| 408 | 408 | foreach my $i (@bad_json) |
| ... | ... | @@ -457,6 +457,34 @@ $td->runtest("json output from job", |
| 457 | 457 | {$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0}, |
| 458 | 458 | $td->NORMALIZE_NEWLINES); |
| 459 | 459 | |
| 460 | +$td->runtest("C job API", | |
| 461 | + {$td->COMMAND => "qpdfjob-ctest"}, | |
| 462 | + {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, | |
| 463 | + $td->NORMALIZE_NEWLINES); | |
| 464 | +foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3]) | |
| 465 | +{ | |
| 466 | + $td->runtest("check output", | |
| 467 | + {$td->FILE => $i->[0]}, | |
| 468 | + {$td->FILE => "qpdfjob-ctest$i->[1].pdf"}); | |
| 469 | +} | |
| 470 | +my $wide_out = `qpdfjob-ctest wide`; | |
| 471 | +$td->runtest("qpdfjob-ctest wide", | |
| 472 | + {$td->STRING => "$?: $wide_out"}, | |
| 473 | + {$td->REGEXP => "0: (wide test passed|skipped wide)\n"}, | |
| 474 | + $td->NORMALIZE_NEWLINES); | |
| 475 | +if ($wide_out =~ m/skipped/) | |
| 476 | +{ | |
| 477 | + $td->runtest("skipped wide", | |
| 478 | + {$td->STRING => "yes"}, | |
| 479 | + {$td->STRING => "yes"}); | |
| 480 | +} | |
| 481 | +else | |
| 482 | +{ | |
| 483 | + $td->runtest("check output", | |
| 484 | + {$td->FILE => "a.pdf"}, | |
| 485 | + {$td->FILE => "qpdfjob-ctest-wide.pdf"}); | |
| 486 | +} | |
| 487 | + | |
| 460 | 488 | show_ntests(); |
| 461 | 489 | # ---------- |
| 462 | 490 | $td->notify("--- Form Tests ---"); | ... | ... |
qpdf/qtest/qpdf/qpdfjob-ctest-wide.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/qpdfjob-ctest.out
0 → 100644
| 1 | +argv test passed | |
| 2 | +json test passed | |
| 3 | +WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56 | |
| 4 | +qpdf: operation succeeded with warnings; resulting file may have some problems | |
| 5 | +json warn test passed | |
| 6 | +qpdfjob json: an output file name is required; use - for standard output | |
| 7 | +json error test passed | ... | ... |
qpdf/qtest/qpdf/qpdfjob-ctest1.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/qpdfjob-ctest2.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdf/qpdfjob-ctest3.pdf
0 → 100644
No preview for this file type