Commit bc4e2320e7dafea8b6d6b6150c808ed2a98d7d03

Authored by Jay Berkenbilt
1 parent 03e67a28

Add qpdfjob-c.h -- simple C API around parts of QPDFJob

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-&gt;runtest(&quot;json output from job&quot;,
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