--- /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 "stringtools.hh"
+#include "serializer.hh"
+
+
+namespace dc {
+
+
+class serializer_impl
+{
+public:
+ serializer_impl(const std::string& filePath, const std::string& indent = "")
+ {
+ std::ofstream* output = new std::ofstream(filePath.c_str());
+ init(*output, true, indent);
+ }
+
+ serializer_impl(std::ostream& output, const std::string& indent = "")
+ {
+ init(output, false, indent);
+ }
+
+ ~serializer_impl()
+ {
+ if (deleteWhenDone)
+ {
+ delete out;
+ }
+ yajl_gen_free(gen);
+ }
+
+ static void throwError(yajl_gen_status err)
+ {
+ switch (err)
+ {
+ case yajl_gen_generation_complete:
+ throw serializer::generator_error("the archive has already terminated");
+ case yajl_gen_keys_must_be_strings:
+ throw serializer::generator_error("map keys must be strings");
+ case yajl_max_depth_exceeded:
+ throw serializer::generator_error("maximum archive depth exceeded");
+ case yajl_gen_in_error_state:
+ throw serializer::generator_error("serializer already in error state");
+ }
+ }
+
+ 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) :
+ impl(new serializer_impl(filePath, indent)) {}
+
+serializer::serializer(std::ostream& output, const std::string& indent) :
+ impl(new serializer_impl(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_impl::throwError(stat);
+}
+
+void serializer::push(double value)
+{
+ yajl_gen_status stat = yajl_gen_double(impl->gen, value);
+ if (stat != yajl_gen_status_ok) serializer_impl::throwError(stat);
+}
+
+void serializer::push(bool value)
+{
+ yajl_gen_status stat = yajl_gen_bool(impl->gen, value);
+ if (stat != yajl_gen_status_ok) serializer_impl::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_impl::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_impl::throwError(stat);
+}
+
+
+void serializer::pushMapHead()
+{
+ yajl_gen_status stat = yajl_gen_map_open(impl->gen);
+ if (stat != yajl_gen_status_ok) serializer_impl::throwError(stat);
+}
+
+void serializer::pushMapTail()
+{
+ yajl_gen_status stat = yajl_gen_map_close(impl->gen);
+ if (stat != yajl_gen_status_ok) serializer_impl::throwError(stat);
+}
+
+void serializer::pushArrayHead()
+{
+ yajl_gen_status stat = yajl_gen_array_open(impl->gen);
+ if (stat != yajl_gen_status_ok) serializer_impl::throwError(stat);
+}
+
+void serializer::pushArrayTail()
+{
+ yajl_gen_status stat = yajl_gen_array_close(impl->gen);
+ if (stat != yajl_gen_status_ok) serializer_impl::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 dc
+