X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fdeserializer.cc;fp=src%2Fdeserializer.cc;h=abb6d01843ed0e8247fc6ce47d4cdb013a2f666e;hp=0000000000000000000000000000000000000000;hb=79b5f738f2e38acb60cda7e09f54802933a17105;hpb=a891a2dcbbb63d9e771da6efff00a33da614e737 diff --git a/src/deserializer.cc b/src/deserializer.cc new file mode 100644 index 0000000..abb6d01 --- /dev/null +++ b/src/deserializer.cc @@ -0,0 +1,243 @@ + +/******************************************************************************* + + Copyright (c) 2009, Charles McGarvey + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include + +#include + +#include "serializable.hh" +#include "deserializer.hh" + + +namespace dc { + + +class deserializer_impl +{ +public: + deserializer_impl(const std::string& filePath, bool comments = false, + bool check = false) + { + std::ifstream* input = new std::ifstream(filePath.c_str()); + init(*input, true, comments, check); + } + + deserializer_impl(std::istream& input, bool comments = false, + bool check = false) + { + init(input, false, comments, check); + } + + ~deserializer_impl() + { + while (!parsed.empty()) + { + delete parsed.front(); + parsed.pop(); + } + + if (deleteWhenDone) + { + delete in; + } + yajl_free(hand); + } + + void throwError() + { + unsigned char* errorMsg = yajl_get_error(hand, 0, 0, 0); + deserializer::parser_error error((char*)errorMsg); + yajl_free_error(hand, errorMsg); + throw error; + } + + + static int parsedNull(void* ctx) + { + ((deserializer_impl*)ctx)->parsed.push(new null); + return 1; + } + + static int parsedBoolean(void* ctx, int value) + { + ((deserializer_impl*)ctx)->parsed.push(new wrapped_boolean(value)); + return 1; + } + + static int parsedInteger(void* ctx, long value) + { + ((deserializer_impl*)ctx)->parsed.push(new wrapped_integer(value)); + return 1; + } + + static int parsedFloat(void* ctx, double value) + { + ((deserializer_impl*)ctx)->parsed.push(new wrapped_real(value)); + return 1; + } + + static int parsedString(void* ctx, const unsigned char* value, + unsigned length) + { + wrapped_string* parsed = new wrapped_string(std::string((char*)value, + length)); + ((deserializer_impl*)ctx)->parsed.push(parsed); + return 1; + } + + static int parsedBeginMap(void* ctx) + { + ((deserializer_impl*)ctx)->parsed.push(new wrapped_dictionary); + } + + static int parsedMapKey(void* ctx, const unsigned char* value, + unsigned length) + { + return parsedString(ctx, value, length); + } + + static int parsedEndMap(void* ctx) + { + ((deserializer_impl*)ctx)->parsed.push(0); + return 1; + } + + static int parsedBeginArray(void* ctx) + { + ((deserializer_impl*)ctx)->parsed.push(new wrapped_array); + return 1; + } + + static int parsedEndArray(void* ctx) + { + ((deserializer_impl*)ctx)->parsed.push(0); + return 1; + } + + + void parse() + { + unsigned char buffer[4096]; + + yajl_status stat; + + while (parsed.empty() && in->good()) + { + in->read((char*)buffer, sizeof(buffer)); + unsigned readIn = in->gcount(); + + if (readIn > 0) + { + stat = yajl_parse(hand, buffer, readIn); + } + else + { + stat = yajl_parse_complete(hand); + } + + if (stat != yajl_status_ok && + stat != yajl_status_insufficient_data) + { + throwError(); + } + } + } + + + yajl_handle hand; + + std::istream* in; + bool deleteWhenDone; + + std::queue parsed; + +private: + void init(std::istream& input, bool deleteIn, bool comments, bool check) + { + const yajl_callbacks callbacks = + { + deserializer_impl::parsedNull, + deserializer_impl::parsedBoolean, + deserializer_impl::parsedInteger, + deserializer_impl::parsedFloat, + 0, + deserializer_impl::parsedString, + deserializer_impl::parsedBeginMap, + deserializer_impl::parsedMapKey, + deserializer_impl::parsedEndMap, + deserializer_impl::parsedBeginArray, + deserializer_impl::parsedEndArray + }; + + in = &input; + deleteWhenDone = deleteIn; + + yajl_parser_config config = {comments, check}; + hand = yajl_alloc(&callbacks, &config, NULL, this); + } +}; + + +deserializer::deserializer(const std::string& filePath, bool comments, + bool check) : impl(new deserializer_impl(filePath, comments, check)) {} + +deserializer::deserializer(std::istream& input, bool comments, bool check) : + impl(new deserializer_impl(input, comments, check)) {} + + +serializable_ptr deserializer::deserialize() +{ + serializable* ptr = pullNext(); + if (ptr) + { + ptr->deserialize(*this); + } + return serializable_ptr(ptr); +} + + +serializable* deserializer::pullNext() +{ + impl->parse(); + if (!impl->parsed.empty()) + { + serializable* ptr = impl->parsed.front(); + return ptr; + } + return 0; +} + +void deserializer::pop() +{ + impl->parsed.pop(); +} + + +} // namespace dc +