--- /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 <yajl/yajl_gen.h>
+
+#include "Serializer.hh"
+#include "StringTools.hh"
+
+
+namespace Mf {
+
+
+class Serializer::SerializerImpl
+{
+public:
+ SerializerImpl(const std::string& filePath, const std::string& indent = "")
+ {
+ std::ofstream* output = new std::ofstream(filePath.c_str());
+ init(*output, true, indent);
+ }
+
+ SerializerImpl(std::ostream& output, const std::string& indent = "")
+ {
+ init(output, false, indent);
+ }
+
+ ~SerializerImpl()
+ {
+ if (deleteWhenDone)
+ {
+ delete out;
+ }
+ yajl_gen_free(gen);
+ }
+
+ static void throwError(yajl_gen_status err)
+ {
+ switch (err)
+ {
+ case yajl_gen_generation_complete:
+ throw Serializer::Exception("the archive has already terminated");
+ case yajl_gen_keys_must_be_strings:
+ throw Serializer::Exception("map keys must be strings");
+ case yajl_max_depth_exceeded:
+ throw Serializer::Exception("maximum archive depth exceeded");
+ case yajl_gen_in_error_state:
+ throw Serializer::Exception("serializer already in error state");
+ case yajl_gen_status_ok:
+ ; // There is no error here. Move along...
+ }
+ }
+
+ yajl_gen gen;
+
+ std::ostream* out;
+ bool deleteWhenDone;
+
+private:
+ void init(std::ostream& output, bool deleteOut, const std::string& indent)
+ {
+ yajl_gen_config config;
+
+ out = &output;
+ deleteWhenDone = deleteOut;
+
+ if (indent != "")
+ {
+ config.beautify = true;
+ config.indentString = 0;
+ // FIXME a yajl bug prevents using heap-allocated strings
+ //config.indentString = indent.c_str();
+ }
+ else
+ {
+ config.beautify = false;
+ }
+ gen = yajl_gen_alloc(&config, 0);
+ }
+};
+
+
+Serializer::Serializer(const std::string& filePath, const std::string& indent) :
+ // pass through
+ impl_(new Serializer::SerializerImpl(filePath, indent)) {}
+
+Serializer::Serializer(std::ostream& output, const std::string& indent) :
+ // pass through
+ impl_(new Serializer::SerializerImpl(output, indent)) {}
+
+Serializer::~Serializer()
+{
+ flush();
+}
+
+
+void Serializer::push(long value)
+{
+ yajl_gen_status stat = yajl_gen_integer(impl_->gen, value);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::push(double value)
+{
+ yajl_gen_status stat = yajl_gen_double(impl_->gen, value);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::push(bool value)
+{
+ yajl_gen_status stat = yajl_gen_bool(impl_->gen, value);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::push(const std::string& value)
+{
+ yajl_gen_status stat = yajl_gen_string(impl_->gen,
+ (const unsigned char*)value.c_str(), value.length());
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::push(const std::wstring& value)
+{
+ push(wideToMulti(value));
+}
+
+void Serializer::pushNull()
+{
+ yajl_gen_status stat = yajl_gen_null(impl_->gen);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+
+void Serializer::pushMapHead()
+{
+ yajl_gen_status stat = yajl_gen_map_open(impl_->gen);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::pushMapTail()
+{
+ yajl_gen_status stat = yajl_gen_map_close(impl_->gen);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::pushArrayHead()
+{
+ yajl_gen_status stat = yajl_gen_array_open(impl_->gen);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+void Serializer::pushArrayTail()
+{
+ yajl_gen_status stat = yajl_gen_array_close(impl_->gen);
+ if (stat != yajl_gen_status_ok)
+ Serializer::SerializerImpl::throwError(stat);
+}
+
+
+void Serializer::flush()
+{
+ const unsigned char* buffer;
+ unsigned length;
+
+ yajl_gen_get_buf(impl_->gen, &buffer, &length);
+ impl_->out->write((const char*)buffer, length);
+ yajl_gen_clear(impl_->gen);
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+