aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/qpdf/qpdfjob-c.h79
-rw-r--r--libqpdf/build.mk3
-rw-r--r--libqpdf/qpdfjob-c.cc50
-rw-r--r--manual/qpdf-job.rst4
-rw-r--r--qpdf/build.mk4
-rw-r--r--qpdf/qpdfjob-ctest.c73
-rw-r--r--qpdf/qtest/qpdf.test30
-rw-r--r--qpdf/qtest/qpdf/qpdfjob-ctest-wide.pdfbin0 -> 799 bytes
-rw-r--r--qpdf/qtest/qpdf/qpdfjob-ctest.out7
-rw-r--r--qpdf/qtest/qpdf/qpdfjob-ctest1.pdfbin0 -> 799 bytes
-rw-r--r--qpdf/qtest/qpdf/qpdfjob-ctest2.pdfbin0 -> 3379 bytes
-rw-r--r--qpdf/qtest/qpdf/qpdfjob-ctest3.pdfbin0 -> 16504 bytes
12 files changed, 245 insertions, 5 deletions
diff --git a/include/qpdf/qpdfjob-c.h b/include/qpdf/qpdfjob-c.h
new file mode 100644
index 00000000..59c42822
--- /dev/null
+++ b/include/qpdf/qpdfjob-c.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2005-2021 Jay Berkenbilt
+ *
+ * This file is part of qpdf.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Versions of qpdf prior to version 7 were released under the terms
+ * of version 2.0 of the Artistic License. At your option, you may
+ * continue to consider qpdf to be licensed under those terms. Please
+ * see the manual for additional information.
+ */
+
+#ifndef QPDFJOB_C_H
+#define QPDFJOB_C_H
+
+/*
+ * This file defines a basic "C" API for QPDFJob. See also qpdf-c.h,
+ * which defines an API that exposes more of the library's API. This
+ * API is primarily intended to make it simpler for programs in
+ * languages other than C++ to incorporate functionality that could be
+ * run directly from the command-line.
+ */
+
+#include <qpdf/DLL.h>
+#include <string.h>
+#ifndef QPDF_NO_WCHAR_T
+# include <wchar.h>
+#endif
+
+/*
+ * This file provides a minimal wrapper around QPDFJob. See
+ * examples/qpdf-job.c for an example of its use.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* This function does the equivalent of running the qpdf
+ * command-line with the given arguments and returns the exit code
+ * that qpdf would use. Note that arguments must be UTF8-encoded.
+ * If calling this from wmain on Windows, use
+ * qpdfjob_run_from_wide_argv instead.
+ */
+ QPDF_DLL
+ int qpdfjob_run_from_argv(int argc, char* argv[]);
+
+#ifndef QPDF_NO_WCHAR_T
+ /* This function is the same as qpdfjob_run_from_argv except argv
+ * is encoded with wide characters. This would suitable for
+ * calling from a Windows wmain function.
+ */
+ QPDF_DLL
+ int qpdfjob_run_from_wide_argv(int argc, wchar_t* argv[]);
+#endif /* QPDF_NO_WCHAR_T */
+
+ /* This function runs QPDFJob from a job JSON file. See the "QPDF
+ * Job" section of the manual for details. The JSON string must be
+ * UTF8-encoded. It returns the error code that qpdf would return
+ * with the equivalent command-line invocation.
+ */
+ QPDF_DLL
+ int qpdfjob_run_from_json(char const* json);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* QPDFJOB_C_H */
diff --git a/libqpdf/build.mk b/libqpdf/build.mk
index e16ba5e1..3dedfc71 100644
--- a/libqpdf/build.mk
+++ b/libqpdf/build.mk
@@ -115,7 +115,8 @@ SRCS_libqpdf = \
libqpdf/SecureRandomDataProvider.cc \
libqpdf/SF_FlateLzwDecode.cc \
libqpdf/SparseOHArray.cc \
- libqpdf/qpdf-c.cc
+ libqpdf/qpdf-c.cc \
+ libqpdf/qpdfjob-c.cc
ifeq ($(USE_CRYPTO_NATIVE), 1)
SRCS_libqpdf += $(CRYPTO_NATIVE)
diff --git a/libqpdf/qpdfjob-c.cc b/libqpdf/qpdfjob-c.cc
new file mode 100644
index 00000000..7b3f6b60
--- /dev/null
+++ b/libqpdf/qpdfjob-c.cc
@@ -0,0 +1,50 @@
+#include <qpdf/qpdfjob-c.h>
+
+#include <qpdf/QPDFJob.hh>
+#include <qpdf/QUtil.hh>
+#include <qpdf/QPDFUsage.hh>
+
+#include <cstdio>
+#include <cstring>
+
+int qpdfjob_run_from_argv(int argc, char* argv[])
+{
+ auto whoami = QUtil::getWhoami(argv[0]);
+ QUtil::setLineBuf(stdout);
+
+ QPDFJob j;
+ try
+ {
+ j.initializeFromArgv(argc, argv);
+ j.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << whoami << ": " << e.what() << std::endl;
+ return QPDFJob::EXIT_ERROR;
+ }
+ return j.getExitCode();
+}
+
+#ifndef QPDF_NO_WCHAR_T
+int qpdfjob_run_from_wide_argv(int argc, wchar_t* argv[])
+{
+ return QUtil::call_main_from_wmain(argc, argv, qpdfjob_run_from_argv);
+}
+#endif // QPDF_NO_WCHAR_T
+
+int qpdfjob_run_from_json(char const* json)
+{
+ QPDFJob j;
+ try
+ {
+ j.initializeFromJson(json);
+ j.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "qpdfjob json: " << e.what() << std::endl;
+ return QPDFJob::EXIT_ERROR;
+ }
+ return j.getExitCode();
+}
diff --git a/manual/qpdf-job.rst b/manual/qpdf-job.rst
index 72e02305..5ee497b1 100644
--- a/manual/qpdf-job.rst
+++ b/manual/qpdf-job.rst
@@ -14,7 +14,7 @@ executable is available from inside the C++ library using the
- Use from the C++ API with ``QPDFJob::initializeFromArgv``
- - Use from the C API with QXXXQ
+ - Use from the C API with ``qpdfjob_run_from_argv`` from :file:`qpdfjob-c.h`
- The job JSON file format
@@ -22,7 +22,7 @@ executable is available from inside the C++ library using the
- Use from the C++ API with ``QPDFJob::initializeFromJson``
- - Use from the C API with QXXXQ
+ - Use from the C API with ``qpdfjob_run_from_json`` from :file:`qpdfjob-c.h`
- The ``QPDFJob`` C++ API
diff --git a/qpdf/build.mk b/qpdf/build.mk
index bf1f52f8..36224090 100644
--- a/qpdf/build.mk
+++ b/qpdf/build.mk
@@ -12,7 +12,9 @@ BINS_qpdf = \
test_tokenizer \
test_unicode_filenames \
test_xref
-CBINS_qpdf = qpdf-ctest
+CBINS_qpdf = \
+ qpdf-ctest \
+ qpdfjob-ctest
TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B)))
diff --git a/qpdf/qpdfjob-ctest.c b/qpdf/qpdfjob-ctest.c
new file mode 100644
index 00000000..3de2fa96
--- /dev/null
+++ b/qpdf/qpdfjob-ctest.c
@@ -0,0 +1,73 @@
+#include <qpdf/qpdfjob-c.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef QPDF_NO_WCHAR_T
+static void wide_test()
+{
+ wchar_t* argv[5];
+ argv[0] = (wchar_t*)(L"qpdfjob");
+ argv[1] = (wchar_t*)(L"minimal.pdf");
+ argv[2] = (wchar_t*)(L"a.pdf");
+ argv[3] = (wchar_t*)(L"--static-id");
+ argv[4] = NULL;
+ assert(qpdfjob_run_from_wide_argv(4, argv) == 0);
+ printf("wide test passed\n");
+}
+#endif // QPDF_NO_WCHAR_T
+
+static void run_tests()
+{
+ /* Be sure to use a different output file for each test. */
+
+ char* argv[5];
+ argv[0] = (char*)("qpdfjob");
+ argv[1] = (char*)("minimal.pdf");
+ argv[2] = (char*)("a.pdf");
+ argv[3] = (char*)("--deterministic-id");
+ argv[4] = NULL;
+ assert(qpdfjob_run_from_argv(4, argv) == 0);
+ printf("argv test passed\n");
+
+ assert(qpdfjob_run_from_json("{\n\
+ \"inputFile\": \"20-pages.pdf\",\n\
+ \"password\": \"user\",\n\
+ \"outputFile\": \"b.pdf\",\n\
+ \"staticId\": \"\",\n\
+ \"decrypt\": \"\",\n\
+ \"objectStreams\": \"generate\"\n\
+}") == 0);
+ printf("json test passed\n");
+
+ assert(qpdfjob_run_from_json("{\n\
+ \"inputFile\": \"xref-with-short-size.pdf\",\n\
+ \"outputFile\": \"c.pdf\",\n\
+ \"staticId\": \"\",\n\
+ \"decrypt\": \"\",\n\
+ \"objectStreams\": \"generate\"\n\
+}") == 3);
+ printf("json warn test passed\n");
+
+ assert(qpdfjob_run_from_json("{\n\
+ \"inputFile\": \"nothing-there.pdf\"\n\
+}") == 2);
+ printf("json error test passed\n");
+}
+
+int main(int argc, char* argv[])
+{
+ if ((argc == 2) && (strcmp(argv[1], "wide") == 0))
+ {
+#ifndef QPDF_NO_WCHAR_T
+ wide_test();
+#else
+ printf("skipped wide\n");
+#endif // QPDF_NO_WCHAR_T
+ return 0;
+ }
+
+ run_tests();
+ return 0;
+}
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 040567cf..dcc707a3 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -402,7 +402,7 @@ my @good_json = (
"underlay-overlay-password",
"misc-options",
);
-$n_tests += 4 + scalar(@bad_json) + (2 * scalar(@good_json));
+$n_tests += 10 + scalar(@bad_json) + (2 * scalar(@good_json));
foreach my $i (@bad_json)
@@ -457,6 +457,34 @@ $td->runtest("json output from job",
{$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+$td->runtest("C job API",
+ {$td->COMMAND => "qpdfjob-ctest"},
+ {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3])
+{
+ $td->runtest("check output",
+ {$td->FILE => $i->[0]},
+ {$td->FILE => "qpdfjob-ctest$i->[1].pdf"});
+}
+my $wide_out = `qpdfjob-ctest wide`;
+$td->runtest("qpdfjob-ctest wide",
+ {$td->STRING => "$?: $wide_out"},
+ {$td->REGEXP => "0: (wide test passed|skipped wide)\n"},
+ $td->NORMALIZE_NEWLINES);
+if ($wide_out =~ m/skipped/)
+{
+ $td->runtest("skipped wide",
+ {$td->STRING => "yes"},
+ {$td->STRING => "yes"});
+}
+else
+{
+ $td->runtest("check output",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "qpdfjob-ctest-wide.pdf"});
+}
+
show_ntests();
# ----------
$td->notify("--- Form Tests ---");
diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest-wide.pdf b/qpdf/qtest/qpdf/qpdfjob-ctest-wide.pdf
new file mode 100644
index 00000000..b8c692ed
--- /dev/null
+++ b/qpdf/qtest/qpdf/qpdfjob-ctest-wide.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest.out b/qpdf/qtest/qpdf/qpdfjob-ctest.out
new file mode 100644
index 00000000..1d7df741
--- /dev/null
+++ b/qpdf/qtest/qpdf/qpdfjob-ctest.out
@@ -0,0 +1,7 @@
+argv test passed
+json test passed
+WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
+qpdf: operation succeeded with warnings; resulting file may have some problems
+json warn test passed
+qpdfjob json: an output file name is required; use - for standard output
+json error test passed
diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest1.pdf b/qpdf/qtest/qpdf/qpdfjob-ctest1.pdf
new file mode 100644
index 00000000..b2c4c2c0
--- /dev/null
+++ b/qpdf/qtest/qpdf/qpdfjob-ctest1.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest2.pdf b/qpdf/qtest/qpdf/qpdfjob-ctest2.pdf
new file mode 100644
index 00000000..a5b2d868
--- /dev/null
+++ b/qpdf/qtest/qpdf/qpdfjob-ctest2.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest3.pdf b/qpdf/qtest/qpdf/qpdfjob-ctest3.pdf
new file mode 100644
index 00000000..0031d7c4
--- /dev/null
+++ b/qpdf/qtest/qpdf/qpdfjob-ctest3.pdf
Binary files differ