From 37105710ee0b332a3020d4b3220c95b8f4267555 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Wed, 19 Jan 2022 09:31:28 -0500 Subject: Implement JSONHandler for recursively processing JSON --- include/qpdf/JSON.hh | 25 +++++++- include/qpdf/JSONHandler.hh | 142 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 include/qpdf/JSONHandler.hh (limited to 'include') diff --git a/include/qpdf/JSON.hh b/include/qpdf/JSON.hh index 676becbf..3b13b4fe 100644 --- a/include/qpdf/JSON.hh +++ b/include/qpdf/JSON.hh @@ -30,7 +30,10 @@ // create temporary JSON objects on the stack, add them to other // objects, and let them go out of scope safely. It also means that if // the json JSON object is added in more than one place, all copies -// share underlying data. +// share underlying data. This makes them similar in structure and +// behavior to QPDFObjectHandle and may feel natural within the QPDF +// codebase, but it is also a good reason not to use this as a +// general-purpose JSON package. #include #include @@ -38,6 +41,7 @@ #include #include #include +#include class JSON { @@ -77,6 +81,24 @@ class JSON QPDF_DLL bool isDictionary() const; + // Accessors. Accessor behavior: + // + // - If argument is wrong type, including null, return false + // - If argument is right type, return true and initialize the value + QPDF_DLL + bool getString(std::string& utf8) const; + QPDF_DLL + bool getNumber(std::string& value) const; + QPDF_DLL + bool getBool(bool& value) const; + QPDF_DLL + bool isNull() const; + QPDF_DLL + bool forEachDictItem( + std::function fn) const; + QPDF_DLL + bool forEachArrayItem(std::function fn) const; + // Check this JSON object against a "schema". This is not a schema // according to any standard. It's just a template of what the // JSON is supposed to contain. The checking does the following: @@ -129,6 +151,7 @@ class JSON JSON_string(std::string const& utf8); virtual ~JSON_string(); virtual std::string unparse(size_t depth) const; + std::string utf8; std::string encoded; }; struct JSON_number: public JSON_value diff --git a/include/qpdf/JSONHandler.hh b/include/qpdf/JSONHandler.hh new file mode 100644 index 00000000..bde134ac --- /dev/null +++ b/include/qpdf/JSONHandler.hh @@ -0,0 +1,142 @@ +// 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 JSONHANDLER_HH +#define JSONHANDLER_HH + +#include +#include +#include +#include +#include +#include +#include +#include + +class JSONHandler +{ + public: + // Error exception is thrown if there are any errors validating + // the JSON object. + class QPDF_DLL_CLASS Error: public std::runtime_error + { + public: + QPDF_DLL + Error(std::string const&); + }; + + QPDF_DLL + JSONHandler(); + + QPDF_DLL + ~JSONHandler() = default; + + // Based on the type of handler, expect the object to be of a + // certain type. JSONHandler::Error is thrown otherwise. Multiple + // handlers may be registered, which allows the object to be of + // various types. If an anyHandler is added, no other handler will + // be called. + + typedef std::function json_handler_t; + typedef std::function void_handler_t; + typedef std::function string_handler_t; + typedef std::function bool_handler_t; + + // If an any handler is added, it will be called for any value + // including null, and no other handler will be called. + QPDF_DLL + void addAnyHandler(json_handler_t fn); + + // If any of the remaining handlers are registered, each + // registered handle will be called. + QPDF_DLL + void addNullHandler(void_handler_t fn); + QPDF_DLL + void addStringHandler(string_handler_t fn); + QPDF_DLL + void addNumberHandler(string_handler_t fn); + QPDF_DLL + void addBoolHandler(bool_handler_t fn); + + // Returns a reference to a map: keys are expected object keys, + // and values are handlers for that object. + QPDF_DLL + std::map>& addDictHandlers(); + + // Apply the given handler to any key not explicitly in dict + // handlers. + QPDF_DLL + void addFallbackDictHandler(std::shared_ptr); + + // Apply the given handler to each element of the array. + QPDF_DLL + void addArrayHandler(std::shared_ptr); + + // Apply handlers recursively to a JSON object. + QPDF_DLL + void handle(std::string const& path, JSON j); + + private: + JSONHandler(JSONHandler const&) = delete; + + struct Handlers + { + Handlers() : + any_handler(nullptr), + null_handler(nullptr), + string_handler(nullptr), + number_handler(nullptr), + bool_handler(nullptr) + { + } + + json_handler_t any_handler; + void_handler_t null_handler; + string_handler_t string_handler; + string_handler_t number_handler; + bool_handler_t bool_handler; + std::map> dict_handlers; + std::shared_ptr fallback_dict_handler; + std::shared_ptr array_handler; + }; + + class Members + { + friend class JSONHandler; + + public: + QPDF_DLL + ~Members() = default; + + private: + Members(); + Members(Members const&) = delete; + + Handlers h; + }; + PointerHolder m; +}; + +#endif // JSONHANDLER_HH -- cgit v1.2.3-70-g09d2