mirror of
https://github.com/qpdf/qpdf.git
synced 2024-09-28 21:19:06 +00:00
JSONHandler: rework dictionary and array handlers
This commit is contained in:
parent
acf8d18b6e
commit
1db0a7ffce
@ -31,6 +31,11 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
// This class allows a sax-like walk through a JSON object with
|
||||||
|
// functionality that mostly mirrors QPDFArgParser. It is primarily
|
||||||
|
// here to facilitate automatic generation of some of the code to help
|
||||||
|
// keep QPDFJob json consistent with command-line arguments.
|
||||||
|
|
||||||
class JSONHandler
|
class JSONHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -53,7 +58,8 @@ class JSONHandler
|
|||||||
// certain type. JSONHandler::Error is thrown otherwise. Multiple
|
// certain type. JSONHandler::Error is thrown otherwise. Multiple
|
||||||
// handlers may be registered, which allows the object to be of
|
// handlers may be registered, which allows the object to be of
|
||||||
// various types. If an anyHandler is added, no other handler will
|
// various types. If an anyHandler is added, no other handler will
|
||||||
// be called.
|
// be called. There is no "final" handler -- if the top-level is a
|
||||||
|
// dictionary or array, just use its end handler.
|
||||||
|
|
||||||
typedef std::function<void(
|
typedef std::function<void(
|
||||||
std::string const& path, JSON value)> json_handler_t;
|
std::string const& path, JSON value)> json_handler_t;
|
||||||
@ -80,19 +86,18 @@ class JSONHandler
|
|||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
void addBoolHandler(bool_handler_t fn);
|
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
|
QPDF_DLL
|
||||||
std::map<std::string, std::shared_ptr<JSONHandler>>& addDictHandlers();
|
void addDictHandlers(void_handler_t start_fn, void_handler_t end_fn);
|
||||||
|
QPDF_DLL
|
||||||
// Apply the given handler to any key not explicitly in dict
|
void addDictKeyHandler(
|
||||||
// handlers.
|
std::string const& key, std::shared_ptr<JSONHandler>);
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
void addFallbackDictHandler(std::shared_ptr<JSONHandler>);
|
void addFallbackDictHandler(std::shared_ptr<JSONHandler>);
|
||||||
|
|
||||||
// Apply the given handler to each element of the array.
|
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
void addArrayHandler(std::shared_ptr<JSONHandler>);
|
void addArrayHandlers(void_handler_t start_fn,
|
||||||
|
void_handler_t end_fn,
|
||||||
|
std::shared_ptr<JSONHandler> item_handlers);
|
||||||
|
|
||||||
// Apply handlers recursively to a JSON object.
|
// Apply handlers recursively to a JSON object.
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
@ -108,7 +113,12 @@ class JSONHandler
|
|||||||
null_handler(nullptr),
|
null_handler(nullptr),
|
||||||
string_handler(nullptr),
|
string_handler(nullptr),
|
||||||
number_handler(nullptr),
|
number_handler(nullptr),
|
||||||
bool_handler(nullptr)
|
bool_handler(nullptr),
|
||||||
|
dict_start_handler(nullptr),
|
||||||
|
dict_end_handler(nullptr),
|
||||||
|
array_start_handler(nullptr),
|
||||||
|
array_end_handler(nullptr),
|
||||||
|
final_handler(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,9 +127,14 @@ class JSONHandler
|
|||||||
string_handler_t string_handler;
|
string_handler_t string_handler;
|
||||||
string_handler_t number_handler;
|
string_handler_t number_handler;
|
||||||
bool_handler_t bool_handler;
|
bool_handler_t bool_handler;
|
||||||
|
void_handler_t dict_start_handler;
|
||||||
|
void_handler_t dict_end_handler;
|
||||||
|
void_handler_t array_start_handler;
|
||||||
|
void_handler_t array_end_handler;
|
||||||
|
void_handler_t final_handler;
|
||||||
std::map<std::string, std::shared_ptr<JSONHandler>> dict_handlers;
|
std::map<std::string, std::shared_ptr<JSONHandler>> dict_handlers;
|
||||||
std::shared_ptr<JSONHandler> fallback_dict_handler;
|
std::shared_ptr<JSONHandler> fallback_dict_handler;
|
||||||
std::shared_ptr<JSONHandler> array_handler;
|
std::shared_ptr<JSONHandler> array_item_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Members
|
class Members
|
||||||
|
@ -46,10 +46,18 @@ JSONHandler::addBoolHandler(bool_handler_t fn)
|
|||||||
this->m->h.bool_handler = fn;
|
this->m->h.bool_handler = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::shared_ptr<JSONHandler>>&
|
void
|
||||||
JSONHandler::addDictHandlers()
|
JSONHandler::addDictHandlers(void_handler_t start_fn, void_handler_t end_fn)
|
||||||
{
|
{
|
||||||
return this->m->h.dict_handlers;
|
this->m->h.dict_start_handler = start_fn;
|
||||||
|
this->m->h.dict_end_handler = end_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
JSONHandler::addDictKeyHandler(
|
||||||
|
std::string const& key, std::shared_ptr<JSONHandler> dkh)
|
||||||
|
{
|
||||||
|
this->m->h.dict_handlers[key] = dkh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -59,9 +67,13 @@ JSONHandler::addFallbackDictHandler(std::shared_ptr<JSONHandler> fdh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSONHandler::addArrayHandler(std::shared_ptr<JSONHandler> ah)
|
JSONHandler::addArrayHandlers(void_handler_t start_fn,
|
||||||
|
void_handler_t end_fn,
|
||||||
|
std::shared_ptr<JSONHandler> ah)
|
||||||
{
|
{
|
||||||
this->m->h.array_handler = ah;
|
this->m->h.array_start_handler = start_fn;
|
||||||
|
this->m->h.array_end_handler = end_fn;
|
||||||
|
this->m->h.array_item_handler = ah;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -95,9 +107,9 @@ JSONHandler::handle(std::string const& path, JSON j)
|
|||||||
this->m->h.bool_handler(path, bvalue);
|
this->m->h.bool_handler(path, bvalue);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
if ((this->m->h.fallback_dict_handler.get() ||
|
if (this->m->h.dict_start_handler && j.isDictionary())
|
||||||
(! this->m->h.dict_handlers.empty())) && j.isDictionary())
|
|
||||||
{
|
{
|
||||||
|
this->m->h.dict_start_handler(path);
|
||||||
std::string path_base = path;
|
std::string path_base = path;
|
||||||
if (path_base != ".")
|
if (path_base != ".")
|
||||||
{
|
{
|
||||||
@ -126,22 +138,19 @@ JSONHandler::handle(std::string const& path, JSON j)
|
|||||||
i->second->handle(path_base + k, v);
|
i->second->handle(path_base + k, v);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this->m->h.dict_end_handler(path);
|
||||||
// Set handled = true even if we didn't call any handlers.
|
|
||||||
// This dictionary could have been empty, but it's okay since
|
|
||||||
// it's a dictionary like it's supposed to be.
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
if (this->m->h.array_handler.get())
|
if (this->m->h.array_start_handler && j.isArray())
|
||||||
{
|
{
|
||||||
|
this->m->h.array_start_handler(path);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
j.forEachArrayItem([&i, &path, this](JSON v) {
|
j.forEachArrayItem([&i, &path, this](JSON v) {
|
||||||
this->m->h.array_handler->handle(
|
this->m->h.array_item_handler->handle(
|
||||||
path + "[" + QUtil::uint_to_string(i) + "]", v);
|
path + "[" + QUtil::uint_to_string(i) + "]", v);
|
||||||
++i;
|
++i;
|
||||||
});
|
});
|
||||||
// Set handled = true even if we didn't call any handlers.
|
this->m->h.array_end_handler(path);
|
||||||
// This could have been an empty array.
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,13 @@ static void print_json(std::string const& path, JSON value)
|
|||||||
std::cout << path << ": json: " << value.unparse() << std::endl;
|
std::cout << path << ": json: " << value.unparse() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSONHandler::void_handler_t make_print_message(std::string msg)
|
||||||
|
{
|
||||||
|
return [msg](std::string const& path) {
|
||||||
|
std::cout << path << ": json: " << msg << std::endl;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static void test_scalar()
|
static void test_scalar()
|
||||||
{
|
{
|
||||||
std::cout << "-- scalar --" << std::endl;
|
std::cout << "-- scalar --" << std::endl;
|
||||||
@ -40,41 +47,50 @@ static void test_scalar()
|
|||||||
static std::shared_ptr<JSONHandler> make_all_handler()
|
static std::shared_ptr<JSONHandler> make_all_handler()
|
||||||
{
|
{
|
||||||
auto h = std::make_shared<JSONHandler>();
|
auto h = std::make_shared<JSONHandler>();
|
||||||
auto& m = h->addDictHandlers();
|
h->addDictHandlers(
|
||||||
|
make_print_message("dict begin"),
|
||||||
|
make_print_message("dict end"));
|
||||||
auto h1 = std::make_shared<JSONHandler>();
|
auto h1 = std::make_shared<JSONHandler>();
|
||||||
h1->addStringHandler(print_string);
|
h1->addStringHandler(print_string);
|
||||||
m["one"] = h1;
|
h->addDictKeyHandler("one", h1);
|
||||||
auto h2 = std::make_shared<JSONHandler>();
|
auto h2 = std::make_shared<JSONHandler>();
|
||||||
h2->addNumberHandler(print_number);
|
h2->addNumberHandler(print_number);
|
||||||
m["two"] = h2;
|
h->addDictKeyHandler("two", h2);
|
||||||
auto h3 = std::make_shared<JSONHandler>();
|
auto h3 = std::make_shared<JSONHandler>();
|
||||||
h3->addBoolHandler(print_bool);
|
h3->addBoolHandler(print_bool);
|
||||||
m["three"] = h3;
|
h->addDictKeyHandler("three", h3);
|
||||||
auto h4 = std::make_shared<JSONHandler>();
|
auto h4 = std::make_shared<JSONHandler>();
|
||||||
h4->addAnyHandler(print_json);
|
h4->addAnyHandler(print_json);
|
||||||
m["four"] = h4;
|
h->addDictKeyHandler("four", h4);
|
||||||
m["phour"] = h4; // share h4
|
h->addDictKeyHandler("phour", h4); // share h4
|
||||||
auto h5 = std::make_shared<JSONHandler>();
|
auto h5 = std::make_shared<JSONHandler>();
|
||||||
// Allow to be either string or bool
|
// Allow to be either string or bool
|
||||||
h5->addBoolHandler(print_bool);
|
h5->addBoolHandler(print_bool);
|
||||||
h5->addStringHandler(print_string);
|
h5->addStringHandler(print_string);
|
||||||
h5->addNullHandler(print_null);
|
h5->addNullHandler(print_null);
|
||||||
auto h5s = std::make_shared<JSONHandler>();
|
auto h5s = std::make_shared<JSONHandler>();
|
||||||
m["five"] = h5s;
|
h->addDictKeyHandler("five", h5s);
|
||||||
h5s->addArrayHandler(h5);
|
h5s->addArrayHandlers(
|
||||||
|
make_print_message("array begin"),
|
||||||
|
make_print_message("array end"),
|
||||||
|
h5);
|
||||||
auto h6 = std::make_shared<JSONHandler>();
|
auto h6 = std::make_shared<JSONHandler>();
|
||||||
auto& m6 = h6->addDictHandlers();
|
h6->addDictHandlers(
|
||||||
|
make_print_message("dict begin"),
|
||||||
|
make_print_message("dict end"));
|
||||||
auto h6a = std::make_shared<JSONHandler>();
|
auto h6a = std::make_shared<JSONHandler>();
|
||||||
m6["a"] = h6a;
|
h6->addDictKeyHandler("a", h6a);
|
||||||
auto& m6a = h6a->addDictHandlers();
|
h6a->addDictHandlers(
|
||||||
|
make_print_message("dict begin"),
|
||||||
|
make_print_message("dict end"));
|
||||||
auto h6ab = std::make_shared<JSONHandler>();
|
auto h6ab = std::make_shared<JSONHandler>();
|
||||||
m6a["b"] = h6ab;
|
h6a->addDictKeyHandler("b", h6ab);
|
||||||
auto h6ax = std::make_shared<JSONHandler>();
|
auto h6ax = std::make_shared<JSONHandler>();
|
||||||
h6ax->addAnyHandler(print_json);
|
h6ax->addAnyHandler(print_json);
|
||||||
h6a->addFallbackDictHandler(h6ax);
|
h6a->addFallbackDictHandler(h6ax);
|
||||||
m6["b"] = h6ab; // share
|
h6->addDictKeyHandler("b", h6ab); // share
|
||||||
h6ab->addStringHandler(print_string);
|
h6ab->addStringHandler(print_string);
|
||||||
m["six"] = h6;
|
h->addDictKeyHandler("six", h6);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,31 @@
|
|||||||
-- scalar --
|
-- scalar --
|
||||||
.: string: potato
|
.: string: potato
|
||||||
-- all --
|
-- all --
|
||||||
|
.: json: dict begin
|
||||||
|
.five: json: array begin
|
||||||
.five[0]: string: x
|
.five[0]: string: x
|
||||||
.five[1]: bool: false
|
.five[1]: bool: false
|
||||||
.five[2]: string: y
|
.five[2]: string: y
|
||||||
.five[3]: null
|
.five[3]: null
|
||||||
.five[4]: bool: true
|
.five[4]: bool: true
|
||||||
|
.five: json: array end
|
||||||
.four: json: [
|
.four: json: [
|
||||||
"a",
|
"a",
|
||||||
1
|
1
|
||||||
]
|
]
|
||||||
.one: string: potato
|
.one: string: potato
|
||||||
.phour: json: null
|
.phour: json: null
|
||||||
|
.six: json: dict begin
|
||||||
|
.six.a: json: dict begin
|
||||||
.six.a.Q: json: "baaa"
|
.six.a.Q: json: "baaa"
|
||||||
.six.a.b: string: quack
|
.six.a.b: string: quack
|
||||||
|
.six.a: json: dict end
|
||||||
.six.b: string: moo
|
.six.b: string: moo
|
||||||
|
.six: json: dict end
|
||||||
.three: bool: true
|
.three: bool: true
|
||||||
.two: number: 3.14
|
.two: number: 3.14
|
||||||
|
.: json: dict end
|
||||||
-- errors --
|
-- errors --
|
||||||
bad type at top: JSON handler: value at . is not of expected type
|
bad type at top: JSON handler: value at . is not of expected type
|
||||||
|
.: json: dict begin
|
||||||
unexpected key: JSON handler found unexpected key x in object at .
|
unexpected key: JSON handler found unexpected key x in object at .
|
||||||
|
Loading…
Reference in New Issue
Block a user