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 <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
|
||||
{
|
||||
public:
|
||||
@ -53,7 +58,8 @@ class JSONHandler
|
||||
// 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.
|
||||
// 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(
|
||||
std::string const& path, JSON value)> json_handler_t;
|
||||
@ -80,19 +86,18 @@ class JSONHandler
|
||||
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<std::string, std::shared_ptr<JSONHandler>>& addDictHandlers();
|
||||
|
||||
// Apply the given handler to any key not explicitly in dict
|
||||
// handlers.
|
||||
void addDictHandlers(void_handler_t start_fn, void_handler_t end_fn);
|
||||
QPDF_DLL
|
||||
void addDictKeyHandler(
|
||||
std::string const& key, std::shared_ptr<JSONHandler>);
|
||||
QPDF_DLL
|
||||
void addFallbackDictHandler(std::shared_ptr<JSONHandler>);
|
||||
|
||||
// Apply the given handler to each element of the array.
|
||||
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.
|
||||
QPDF_DLL
|
||||
@ -108,7 +113,12 @@ class JSONHandler
|
||||
null_handler(nullptr),
|
||||
string_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 number_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::shared_ptr<JSONHandler> fallback_dict_handler;
|
||||
std::shared_ptr<JSONHandler> array_handler;
|
||||
std::shared_ptr<JSONHandler> array_item_handler;
|
||||
};
|
||||
|
||||
class Members
|
||||
|
@ -46,10 +46,18 @@ JSONHandler::addBoolHandler(bool_handler_t fn)
|
||||
this->m->h.bool_handler = fn;
|
||||
}
|
||||
|
||||
std::map<std::string, std::shared_ptr<JSONHandler>>&
|
||||
JSONHandler::addDictHandlers()
|
||||
void
|
||||
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
|
||||
@ -59,9 +67,13 @@ JSONHandler::addFallbackDictHandler(std::shared_ptr<JSONHandler> fdh)
|
||||
}
|
||||
|
||||
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
|
||||
@ -95,9 +107,9 @@ JSONHandler::handle(std::string const& path, JSON j)
|
||||
this->m->h.bool_handler(path, bvalue);
|
||||
handled = true;
|
||||
}
|
||||
if ((this->m->h.fallback_dict_handler.get() ||
|
||||
(! this->m->h.dict_handlers.empty())) && j.isDictionary())
|
||||
if (this->m->h.dict_start_handler && j.isDictionary())
|
||||
{
|
||||
this->m->h.dict_start_handler(path);
|
||||
std::string path_base = path;
|
||||
if (path_base != ".")
|
||||
{
|
||||
@ -126,22 +138,19 @@ JSONHandler::handle(std::string const& path, JSON j)
|
||||
i->second->handle(path_base + k, v);
|
||||
}
|
||||
});
|
||||
|
||||
// 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.
|
||||
this->m->h.dict_end_handler(path);
|
||||
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;
|
||||
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);
|
||||
++i;
|
||||
});
|
||||
// Set handled = true even if we didn't call any handlers.
|
||||
// This could have been an empty array.
|
||||
this->m->h.array_end_handler(path);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,13 @@ static void print_json(std::string const& path, JSON value)
|
||||
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()
|
||||
{
|
||||
std::cout << "-- scalar --" << std::endl;
|
||||
@ -40,41 +47,50 @@ static void test_scalar()
|
||||
static std::shared_ptr<JSONHandler> make_all_handler()
|
||||
{
|
||||
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>();
|
||||
h1->addStringHandler(print_string);
|
||||
m["one"] = h1;
|
||||
h->addDictKeyHandler("one", h1);
|
||||
auto h2 = std::make_shared<JSONHandler>();
|
||||
h2->addNumberHandler(print_number);
|
||||
m["two"] = h2;
|
||||
h->addDictKeyHandler("two", h2);
|
||||
auto h3 = std::make_shared<JSONHandler>();
|
||||
h3->addBoolHandler(print_bool);
|
||||
m["three"] = h3;
|
||||
h->addDictKeyHandler("three", h3);
|
||||
auto h4 = std::make_shared<JSONHandler>();
|
||||
h4->addAnyHandler(print_json);
|
||||
m["four"] = h4;
|
||||
m["phour"] = h4; // share h4
|
||||
h->addDictKeyHandler("four", h4);
|
||||
h->addDictKeyHandler("phour", h4); // share h4
|
||||
auto h5 = std::make_shared<JSONHandler>();
|
||||
// Allow to be either string or bool
|
||||
h5->addBoolHandler(print_bool);
|
||||
h5->addStringHandler(print_string);
|
||||
h5->addNullHandler(print_null);
|
||||
auto h5s = std::make_shared<JSONHandler>();
|
||||
m["five"] = h5s;
|
||||
h5s->addArrayHandler(h5);
|
||||
h->addDictKeyHandler("five", h5s);
|
||||
h5s->addArrayHandlers(
|
||||
make_print_message("array begin"),
|
||||
make_print_message("array end"),
|
||||
h5);
|
||||
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>();
|
||||
m6["a"] = h6a;
|
||||
auto& m6a = h6a->addDictHandlers();
|
||||
h6->addDictKeyHandler("a", h6a);
|
||||
h6a->addDictHandlers(
|
||||
make_print_message("dict begin"),
|
||||
make_print_message("dict end"));
|
||||
auto h6ab = std::make_shared<JSONHandler>();
|
||||
m6a["b"] = h6ab;
|
||||
h6a->addDictKeyHandler("b", h6ab);
|
||||
auto h6ax = std::make_shared<JSONHandler>();
|
||||
h6ax->addAnyHandler(print_json);
|
||||
h6a->addFallbackDictHandler(h6ax);
|
||||
m6["b"] = h6ab; // share
|
||||
h6->addDictKeyHandler("b", h6ab); // share
|
||||
h6ab->addStringHandler(print_string);
|
||||
m["six"] = h6;
|
||||
h->addDictKeyHandler("six", h6);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,31 @@
|
||||
-- scalar --
|
||||
.: string: potato
|
||||
-- all --
|
||||
.: json: dict begin
|
||||
.five: json: array begin
|
||||
.five[0]: string: x
|
||||
.five[1]: bool: false
|
||||
.five[2]: string: y
|
||||
.five[3]: null
|
||||
.five[4]: bool: true
|
||||
.five: json: array end
|
||||
.four: json: [
|
||||
"a",
|
||||
1
|
||||
]
|
||||
.one: string: potato
|
||||
.phour: json: null
|
||||
.six: json: dict begin
|
||||
.six.a: json: dict begin
|
||||
.six.a.Q: json: "baaa"
|
||||
.six.a.b: string: quack
|
||||
.six.a: json: dict end
|
||||
.six.b: string: moo
|
||||
.six: json: dict end
|
||||
.three: bool: true
|
||||
.two: number: 3.14
|
||||
.: json: dict end
|
||||
-- errors --
|
||||
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 .
|
||||
|
Loading…
Reference in New Issue
Block a user