+++ /dev/null
-
-/*******************************************************************************
-
- 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 <fstream>
-#include <queue>
-
-#include <yajl/yajl_parse.h>
-
-#include "Deserializer.hh"
-#include "Log.hh"
-#include "Serializable.hh"
-
-
-namespace Mf {
-
-
-class Deserializer::Impl
-{
-public:
- 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);
- }
-
- Impl(std::istream& input, bool comments = false,
- bool check = false)
- {
- init(input, false, comments, check);
- }
-
- ~Impl()
- {
- while (!parsed.empty())
- {
- delete parsed.front();
- parsed.pop();
- }
-
- if (deleteWhenDone)
- {
- delete in;
- }
- yajl_free(hand);
- }
-
- void raise()
- {
- unsigned char* errorStr = yajl_get_error(hand, 0, 0, 0);
- logError("parser error: %s", errorStr);
- yajl_free_error(hand, errorStr);
-
- throw Exception(Exception::PARSING_FAILED);
- }
-
-
- static int parsedNull(void* ctx)
- {
- ((Impl*)ctx)->parsed.push(new SerializableNull);
- return 1;
- }
-
- static int parsedBoolean(void* ctx, int value)
- {
- ((Impl*)ctx)->parsed.push(new SerializableBasic<Serializable::Boolean>(value));
- return 1;
- }
-
- static int parsedInteger(void* ctx, long value)
- {
- ((Impl*)ctx)->parsed.push(new SerializableBasic<Serializable::Integer>(value));
- return 1;
- }
-
- static int parsedFloat(void* ctx, double value)
- {
- ((Impl*)ctx)->parsed.push(new SerializableBasic<Serializable::Float>(value));
- return 1;
- }
-
- static int parsedString(void* ctx, const unsigned char* value,
- unsigned length)
- {
- ((Impl*)ctx)->parsed.push(new SerializableBasic<Serializable::String>(std::string((char*)value, length)));
- return 1;
- }
-
- static int parsedBeginMap(void* ctx)
- {
- ((Impl*)ctx)->parsed.push(new SerializableBasic<Serializable::Map>);
- return 1;
- }
-
- static int parsedMapKey(void* ctx, const unsigned char* value,
- unsigned length)
- {
- // same thing as a string
- return parsedString(ctx, value, length);
- }
-
- static int parsedEndMap(void* ctx)
- {
- // null means the end of a structure
- ((Impl*)ctx)->parsed.push(0);
- return 1;
- }
-
- static int parsedBeginArray(void* ctx)
- {
- ((Impl*)ctx)->parsed.push(new SerializableBasic<Serializable::Array>);
- return 1;
- }
-
- static int parsedEndArray(void* ctx)
- {
- // null means the end of a structure
- ((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)
- {
- raise();
- }
- }
- }
-
-
- yajl_handle hand;
-
- std::istream* in;
- bool deleteWhenDone;
-
- std::queue<Serializable*> parsed;
-
-private:
- void init(std::istream& input, bool deleteIn, bool comments, bool check)
- {
- // this has to be static because yajl actually does not copy it into its
- // internal data structures but rather keeps a pointer to this
- static const yajl_callbacks callbacks =
- {
- Impl::parsedNull,
- Impl::parsedBoolean,
- Impl::parsedInteger,
- Impl::parsedFloat,
- 0,
- Impl::parsedString,
- Impl::parsedBeginMap,
- Impl::parsedMapKey,
- Impl::parsedEndMap,
- Impl::parsedBeginArray,
- 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) :
- // pass through
- impl_(new Deserializer::Impl(filePath, comments, check)) {}
-
-Deserializer::Deserializer(std::istream& input, bool comments, bool check) :
- // pass through
- impl_(new Deserializer::Impl(input, comments, check)) {}
-
-
-SerializableP Deserializer::deserialize()
-{
- Serializable* ptr = pullNext();
- if (ptr)
- {
- ptr->deserialize(*this);
- }
- return SerializableP(ptr);
-}
-
-
-Serializable* Deserializer::pullNext()
-{
- impl_->parse();
- if (!impl_->parsed.empty())
- {
- Serializable* ptr = impl_->parsed.front();
- return ptr;
- }
- return 0;
-}
-
-void Deserializer::pop()
-{
- // pass through
- impl_->parsed.pop();
-}
-
-
-} // namespace Mf
-
-/** vim: set ts=4 sw=4 tw=80: *************************************************/
-