Commit b4bdc42b4fd627529e1c4a4636d1631254a2f26e

Authored by Jay Berkenbilt
1 parent 164cbdde

New exception class QPDFSystemError (fixes #221)

ChangeLog
  1 +2018-08-13 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add new class QPDFSystemError, derived from std::runtime_error,
  4 + which is now thrown by QUtil::throw_system_error. This enables the
  5 + triggering errno value to be retrieved. Fixes #221.
  6 +
1 2018-08-12 Jay Berkenbilt <ejb@ql.org> 7 2018-08-12 Jay Berkenbilt <ejb@ql.org>
2 8
3 * qpdf command line: add --no-warn option to suppress issuing 9 * qpdf command line: add --no-warn option to suppress issuing
include/qpdf/QPDFSystemError.hh 0 → 100644
  1 +// Copyright (c) 2005-2018 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 +#ifndef QPDFSYSTEMERROR_HH
  23 +#define QPDFSYSTEMERROR_HH
  24 +
  25 +#include <qpdf/DLL.h>
  26 +#include <qpdf/Types.h>
  27 +
  28 +#include <qpdf/Constants.h>
  29 +#include <string>
  30 +#include <stdexcept>
  31 +
  32 +class QPDFSystemError: public std::runtime_error
  33 +{
  34 + public:
  35 + QPDF_DLL
  36 + QPDFSystemError(std::string const& description,
  37 + int system_errno);
  38 + QPDF_DLL
  39 + virtual ~QPDFSystemError() throw ();
  40 +
  41 + // To get a complete error string, call what(), provided by
  42 + // std::exception. The accessors below return the original values
  43 + // used to create the exception.
  44 +
  45 + QPDF_DLL
  46 + std::string const& getDescription() const;
  47 + QPDF_DLL
  48 + int getErrno() const;
  49 +
  50 + private:
  51 + static std::string createWhat(std::string const& description,
  52 + int system_errno);
  53 +
  54 + std::string description;
  55 + int system_errno;
  56 +};
  57 +
  58 +#endif // QPDFSYSTEMERROR_HH
include/qpdf/QUtil.hh
@@ -61,9 +61,14 @@ namespace QUtil @@ -61,9 +61,14 @@ namespace QUtil
61 QPDF_DLL 61 QPDF_DLL
62 unsigned char* unsigned_char_pointer(char const* str); 62 unsigned char* unsigned_char_pointer(char const* str);
63 63
64 - // Throw std::runtime_error with a string formed by appending to 64 + // Throw QPDFSystemError, which is derived from
  65 + // std::runtime_error, with a string formed by appending to
65 // "description: " the standard string corresponding to the 66 // "description: " the standard string corresponding to the
66 - // current value of errno. 67 + // current value of errno. You can retrieve the value of errno by
  68 + // calling getErrno() on the QPDFSystemError. Prior to qpdf 8.2.0,
  69 + // this method threw system::runtime_error directly, but since
  70 + // QPDFSystemError is derived from system::runtime_error, old code
  71 + // that specifically catches std::runtime_error will still work.
67 QPDF_DLL 72 QPDF_DLL
68 void throw_system_error(std::string const& description); 73 void throw_system_error(std::string const& description);
69 74
libqpdf/QPDFSystemError.cc 0 → 100644
  1 +#include <qpdf/QPDFSystemError.hh>
  2 +#include <qpdf/QUtil.hh>
  3 +#include <string.h>
  4 +
  5 +QPDFSystemError::QPDFSystemError(std::string const& description,
  6 + int system_errno) :
  7 + std::runtime_error(createWhat(description, system_errno)),
  8 + description(description),
  9 + system_errno(system_errno)
  10 +{
  11 +}
  12 +
  13 +QPDFSystemError::~QPDFSystemError() throw ()
  14 +{
  15 +}
  16 +
  17 +std::string
  18 +QPDFSystemError::createWhat(std::string const& description,
  19 + int system_errno)
  20 +{
  21 + std::string message;
  22 +#ifdef _MSC_VER
  23 + // "94" is mentioned in the MSVC docs, but it's still safe if the
  24 + // message is longer. strerror_s is a templated function that
  25 + // knows the size of buf and truncates.
  26 + char buf[94];
  27 + if (strerror_s(buf, errno) != 0)
  28 + {
  29 + message = description + ": failed with an unknown error";
  30 + }
  31 + else
  32 + {
  33 + message = description + ": " + buf;
  34 + }
  35 +#else
  36 + message = description + ": " + strerror(errno);
  37 +#endif
  38 + return message;
  39 +}
  40 +
  41 +std::string const&
  42 +QPDFSystemError::getDescription() const
  43 +{
  44 + return this->description;
  45 +}
  46 +
  47 +int
  48 +QPDFSystemError::getErrno() const
  49 +{
  50 + return this->system_errno;
  51 +}
libqpdf/QUtil.cc
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 # include <qpdf/InsecureRandomDataProvider.hh> 7 # include <qpdf/InsecureRandomDataProvider.hh>
8 #endif 8 #endif
9 #include <qpdf/SecureRandomDataProvider.hh> 9 #include <qpdf/SecureRandomDataProvider.hh>
  10 +#include <qpdf/QPDFSystemError.hh>
10 11
11 #include <cmath> 12 #include <cmath>
12 #include <iomanip> 13 #include <iomanip>
@@ -132,22 +133,7 @@ QUtil::unsigned_char_pointer(char const* str) @@ -132,22 +133,7 @@ QUtil::unsigned_char_pointer(char const* str)
132 void 133 void
133 QUtil::throw_system_error(std::string const& description) 134 QUtil::throw_system_error(std::string const& description)
134 { 135 {
135 -#ifdef _MSC_VER  
136 - // "94" is mentioned in the MSVC docs, but it's still safe if the  
137 - // message is longer. strerror_s is a templated function that  
138 - // knows the size of buf and truncates.  
139 - char buf[94];  
140 - if (strerror_s(buf, errno) != 0)  
141 - {  
142 - throw std::runtime_error(description + ": failed with an unknown error");  
143 - }  
144 - else  
145 - {  
146 - throw std::runtime_error(description + ": " + buf);  
147 - }  
148 -#else  
149 - throw std::runtime_error(description + ": " + strerror(errno));  
150 -#endif 136 + throw QPDFSystemError(description, errno);
151 } 137 }
152 138
153 int 139 int
libqpdf/build.mk
@@ -45,6 +45,7 @@ SRCS_libqpdf = \ @@ -45,6 +45,7 @@ SRCS_libqpdf = \
45 libqpdf/QPDFObjectHandle.cc \ 45 libqpdf/QPDFObjectHandle.cc \
46 libqpdf/QPDFPageDocumentHelper.cc \ 46 libqpdf/QPDFPageDocumentHelper.cc \
47 libqpdf/QPDFPageObjectHelper.cc \ 47 libqpdf/QPDFPageObjectHelper.cc \
  48 + libqpdf/QPDFSystemError.cc \
48 libqpdf/QPDFTokenizer.cc \ 49 libqpdf/QPDFTokenizer.cc \
49 libqpdf/QPDFWriter.cc \ 50 libqpdf/QPDFWriter.cc \
50 libqpdf/QPDFXRefEntry.cc \ 51 libqpdf/QPDFXRefEntry.cc \
libtests/qutil.cc
@@ -5,8 +5,10 @@ @@ -5,8 +5,10 @@
5 #include <fcntl.h> 5 #include <fcntl.h>
6 #include <qpdf/QUtil.hh> 6 #include <qpdf/QUtil.hh>
7 #include <qpdf/PointerHolder.hh> 7 #include <qpdf/PointerHolder.hh>
  8 +#include <qpdf/QPDFSystemError.hh>
8 #include <string.h> 9 #include <string.h>
9 #include <limits.h> 10 #include <limits.h>
  11 +#include <assert.h>
10 12
11 #ifdef _WIN32 13 #ifdef _WIN32
12 # include <io.h> 14 # include <io.h>
@@ -137,9 +139,10 @@ void fopen_wrapper_test() @@ -137,9 +139,10 @@ void fopen_wrapper_test()
137 std::cout << "after fopen" << std::endl; 139 std::cout << "after fopen" << std::endl;
138 (void) fclose(f); 140 (void) fclose(f);
139 } 141 }
140 - catch (std::runtime_error& s) 142 + catch (QPDFSystemError& s)
141 { 143 {
142 std::cout << "exception: " << s.what() << std::endl; 144 std::cout << "exception: " << s.what() << std::endl;
  145 + assert(s.getErrno() != 0);
143 } 146 }
144 } 147 }
145 148