From 8082af09bea1132cecc2d148eeb23bc05e66f6b2 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Tue, 8 Feb 2022 10:50:55 -0500 Subject: [PATCH] Add PDFVersion class --- ChangeLog | 5 +++ include/qpdf/PDFVersion.hh | 73 +++++++++++++++++++++++++++++++++++++ libqpdf/PDFVersion.cc | 69 +++++++++++++++++++++++++++++++++++ libqpdf/build.mk | 1 + libtests/build.mk | 1 + libtests/pdf_version.cc | 39 ++++++++++++++++++++ libtests/qtest/version.test | 16 ++++++++ 7 files changed, 204 insertions(+) create mode 100644 include/qpdf/PDFVersion.hh create mode 100644 libqpdf/PDFVersion.cc create mode 100644 libtests/pdf_version.cc create mode 100644 libtests/qtest/version.test diff --git a/ChangeLog b/ChangeLog index c850eef8..c12675c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-02-08 Jay Berkenbilt + + * Add new class PDFVersion for more convenient comparison of PDF + version numbers from the %!PDF header. + 2022-02-06 Jay Berkenbilt * Pl_Buffer and QPDFWriter: add getBufferSharedPointer(), which diff --git a/include/qpdf/PDFVersion.hh b/include/qpdf/PDFVersion.hh new file mode 100644 index 00000000..3a8274ea --- /dev/null +++ b/include/qpdf/PDFVersion.hh @@ -0,0 +1,73 @@ +// Copyright (c) 2005-2022 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. + +// This class implements a simple writer for saving QPDF objects to +// new PDF files. See comments through the header file for additional +// details. + +#ifndef PDFVERSION_HH +#define PDFVERSION_HH + +#include +#include + +class PDFVersion +{ + public: + // Represent a PDF version. PDF versions are typically + // major.minor, but PDF 1.7 has several extension levels as the + // ISO 32000 spec was in progress. This class helps with + // comparison of versions. + QPDF_DLL + PDFVersion(); + QPDF_DLL + PDFVersion(PDFVersion const&) = default; + QPDF_DLL + PDFVersion(int major, int minor, int extension = 0); + QPDF_DLL + bool operator<(PDFVersion const& rhs) const; + QPDF_DLL + bool operator==(PDFVersion const& rhs) const; + + // Replace this version with the other one if the other one is + // greater. + QPDF_DLL + void updateIfGreater(PDFVersion const& other); + + // Initialize a string and integer suitable for passing to + // QPDFWriter::setMinimumPDFVersion or QPDFWriter::forcePDFVersion. + QPDF_DLL + void getVersion(std::string& version, int& extension_level) const; + + QPDF_DLL + int getMajor() const; + QPDF_DLL + int getMinor() const; + QPDF_DLL + int getExtensionLevel() const; + + private: + int major; + int minor; + int extension; +}; + +#endif // PDFVERSION_HH diff --git a/libqpdf/PDFVersion.cc b/libqpdf/PDFVersion.cc new file mode 100644 index 00000000..c2f28bf8 --- /dev/null +++ b/libqpdf/PDFVersion.cc @@ -0,0 +1,69 @@ +#include + +#include + +PDFVersion::PDFVersion() : + PDFVersion(0, 0, 0) +{ +} + +PDFVersion::PDFVersion(int major, int minor, int extension) : + major(major), + minor(minor), + extension(extension) +{ +} + +bool +PDFVersion::operator<(PDFVersion const& rhs) const +{ + return ((this->major < rhs.major) ? true : + (this->major > rhs.major) ? false : + (this->minor < rhs.minor) ? true : + (this->minor > rhs.minor) ? false : + (this->extension < rhs.minor) ? true : + false); +} + +bool +PDFVersion::operator==(PDFVersion const& rhs) const +{ + return ((this->major == rhs.major) && + (this->minor == rhs.minor) && + (this->extension == rhs.extension)); +} + +void +PDFVersion::updateIfGreater(PDFVersion const& other) +{ + if (*this < other) + { + *this = other; + } +} + +void +PDFVersion::getVersion(std::string& version, int& extension_level) const +{ + extension_level = this->extension; + version = QUtil::int_to_string(this->major) + "." + + QUtil::int_to_string(this->minor); +} + +int +PDFVersion::getMajor() const +{ + return this->major; +} + +int +PDFVersion::getMinor() const +{ + return this->minor; +} + +int +PDFVersion::getExtensionLevel() const +{ + return this->extension; +} diff --git a/libqpdf/build.mk b/libqpdf/build.mk index 3dedfc71..71b32d32 100644 --- a/libqpdf/build.mk +++ b/libqpdf/build.mk @@ -42,6 +42,7 @@ SRCS_libqpdf = \ libqpdf/MD5.cc \ libqpdf/NNTree.cc \ libqpdf/OffsetInputSource.cc \ + libqpdf/PDFVersion.cc \ libqpdf/Pipeline.cc \ libqpdf/Pl_AES_PDF.cc \ libqpdf/Pl_ASCII85Decoder.cc \ diff --git a/libtests/build.mk b/libtests/build.mk index 682c2b6d..40bd0829 100644 --- a/libtests/build.mk +++ b/libtests/build.mk @@ -21,6 +21,7 @@ BINS_libtests = \ md5 \ nntree \ numrange \ + pdf_version \ pointer_holder \ predictors \ qintc \ diff --git a/libtests/pdf_version.cc b/libtests/pdf_version.cc new file mode 100644 index 00000000..2776d43b --- /dev/null +++ b/libtests/pdf_version.cc @@ -0,0 +1,39 @@ +#include + +#include +#include + +int main() +{ + PDFVersion v1; + assert(v1.getMajor() == 0); + assert(v1.getMinor() == 0); + assert(v1.getExtensionLevel() == 0); + v1 = PDFVersion(1, 7, 8); + assert(v1.getMajor() == 1); + assert(v1.getMinor() == 7); + assert(v1.getExtensionLevel() == 8); + std::string version; + int extension_level = -1; + v1.getVersion(version, extension_level); + assert(version == "1.7"); + assert(extension_level == 8); + PDFVersion v2(1, 5); + v2.getVersion(version, extension_level); + assert(version == "1.5"); + assert(extension_level == 0); + assert(v2 < v1); + PDFVersion v3 = v1; + assert(v3 == v1); + v1.updateIfGreater(v2); + assert(v3 == v1); + assert(! (v3 == v2)); + assert(! (v2 == v1)); + v2.updateIfGreater(v1); + assert(v2 == v1); + v2.getVersion(version, extension_level); + assert(version == "1.7"); + assert(extension_level == 8); + std::cout << "PDFVersion assertions passed" << std::endl; + return 0; +} diff --git a/libtests/qtest/version.test b/libtests/qtest/version.test new file mode 100644 index 00000000..7a8182ee --- /dev/null +++ b/libtests/qtest/version.test @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +require 5.008; +use warnings; +use strict; + +require TestDriver; + +my $td = new TestDriver('pdf_version'); + +$td->runtest("pdf_version", + {$td->COMMAND => "pdf_version"}, + {$td->STRING => "PDFVersion assertions passed\n", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + +$td->report(1);