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,7 +115,8 @@ SRCS_libqpdf = \ | ||
| 115 | libqpdf/SecureRandomDataProvider.cc \ | 115 | libqpdf/SecureRandomDataProvider.cc \ |
| 116 | libqpdf/SF_FlateLzwDecode.cc \ | 116 | libqpdf/SF_FlateLzwDecode.cc \ |
| 117 | libqpdf/SparseOHArray.cc \ | 117 | libqpdf/SparseOHArray.cc \ |
| 118 | - libqpdf/qpdf-c.cc | 118 | + libqpdf/qpdf-c.cc \ |
| 119 | + libqpdf/qpdfjob-c.cc | ||
| 119 | 120 | ||
| 120 | ifeq ($(USE_CRYPTO_NATIVE), 1) | 121 | ifeq ($(USE_CRYPTO_NATIVE), 1) |
| 121 | SRCS_libqpdf += $(CRYPTO_NATIVE) | 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,7 +14,7 @@ executable is available from inside the C++ library using the | ||
| 14 | 14 | ||
| 15 | - Use from the C++ API with ``QPDFJob::initializeFromArgv`` | 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 | - The job JSON file format | 19 | - The job JSON file format |
| 20 | 20 | ||
| @@ -22,7 +22,7 @@ executable is available from inside the C++ library using the | @@ -22,7 +22,7 @@ executable is available from inside the C++ library using the | ||
| 22 | 22 | ||
| 23 | - Use from the C++ API with ``QPDFJob::initializeFromJson`` | 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 | - The ``QPDFJob`` C++ API | 27 | - The ``QPDFJob`` C++ API |
| 28 | 28 |
qpdf/build.mk
| @@ -12,7 +12,9 @@ BINS_qpdf = \ | @@ -12,7 +12,9 @@ BINS_qpdf = \ | ||
| 12 | test_tokenizer \ | 12 | test_tokenizer \ |
| 13 | test_unicode_filenames \ | 13 | test_unicode_filenames \ |
| 14 | test_xref | 14 | test_xref |
| 15 | -CBINS_qpdf = qpdf-ctest | 15 | +CBINS_qpdf = \ |
| 16 | + qpdf-ctest \ | ||
| 17 | + qpdfjob-ctest | ||
| 16 | 18 | ||
| 17 | TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B))) | 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,7 +402,7 @@ my @good_json = ( | ||
| 402 | "underlay-overlay-password", | 402 | "underlay-overlay-password", |
| 403 | "misc-options", | 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 | foreach my $i (@bad_json) | 408 | foreach my $i (@bad_json) |
| @@ -457,6 +457,34 @@ $td->runtest("json output from job", | @@ -457,6 +457,34 @@ $td->runtest("json output from job", | ||
| 457 | {$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0}, | 457 | {$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0}, |
| 458 | $td->NORMALIZE_NEWLINES); | 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 | show_ntests(); | 488 | show_ntests(); |
| 461 | # ---------- | 489 | # ---------- |
| 462 | $td->notify("--- Form Tests ---"); | 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