Rapidjson vs JsonCPP

Here’s what I came up with for an initial JSON -> cocos2d::Value using rapidjson (included as part of cocostudio lib). It’s a first pass so there are possibly unnecessary copies or even memory leak, or bug in the conversion. But it’s working with a couple simple .json and .plist comparison tests. Since I’ve used ValueMap and ValueVector extensively within one project since it was a migration from 2.x to 3.x and initially used plists this works for that project. I’m not sure it’ll be useful for a brand new project which could use rapidjson directly instead of cocos2d::Value as well as using standard data c++11 data types and containers. Anyway, here’s my current util class.

.h

#pragma once

#include <base/CCValue.h>
#include <json/document.h>

class STValueMapFromJSON
{
public:
    static cocos2d::Value parseValueFromJsonValue(const rapidjson::Value& jvalue);
    static cocos2d::ValueMap getValueMapFromJsonFile(const std::string& filename);
    static cocos2d::ValueVector getValueVectorFromJsonFile(const std::string& filename);
};

.cpp

#include "STValueMapFromJSON.h"
#include <json/rapidjson.h>
#include <cocos2d.h>
#include <cocostudio/DictionaryHelper.h>

//USING_NS_CC;
//using namespace cocostudio;

// TODO: add any necessary 'const', 'const' & references, or error checking
cocos2d::Value STValueMapFromJSON::parseValueFromJsonValue(const rapidjson::Value& jvalue)
{
    // parse by type
    auto t = jvalue.GetType();

    if(t == rapidjson::Type::kNullType)
    {
        // don't add anything
        return cocos2d::Value();
    }

    if(t == rapidjson::Type::kFalseType) {
        return cocos2d::Value(false);
    }

    if(t == rapidjson::Type::kTrueType) {
        return cocos2d::Value(true);
    }

    if(t == rapidjson::Type::kStringType) {
        return cocos2d::Value(jvalue.GetString());
    }

    if(t == rapidjson::Type::kNumberType) {
        if(jvalue.IsDouble()) {
            return cocos2d::Value(jvalue.GetDouble());
        } else if(jvalue.IsUint()) {
            int temp = int(jvalue.GetUint());
            return cocos2d::Value(temp);
        } else if(jvalue.IsInt()) {
            return cocos2d::Value(jvalue.GetInt());
        }
    }

    if(t == rapidjson::Type::kObjectType) {
        cocos2d::ValueMap dict;
        for (rapidjson::Value::ConstMemberIterator itr = jvalue.MemberonBegin(); itr != jvalue.MemberonEnd(); ++itr)
        {
            auto jsonKey = itr->name.GetString();
            auto el = parseValueFromJsonValue(itr->value);
            dict[jsonKey] = el;
        }
        return cocos2d::Value(dict);
    }
    if(t == rapidjson::Type::kArrayType) {
        cocos2d::ValueVector arr;
        // rapidjson uses SizeType instead of size_t.
        for (rapidjson::SizeType i = 0; i < jvalue.Size(); i++) {
            auto el = parseValueFromJsonValue(jvalue[i]);
            arr.push_back(el);
        }
        return cocos2d::Value(arr);
    }

    // none
    return cocos2d::Value();
}

cocos2d::ValueMap STValueMapFromJSON::getValueMapFromJsonFile(const std::string& filename)
{
    auto content = cocos2d::FileUtils::getInstance()->getStringFromFile(filename);

    rapidjson::Document doc;
    doc.Parse<0>(content.c_str());
    if (! doc.HasParseError())
    {
        // check that root is object not array
        auto val = parseValueFromJsonValue(doc);
        if(val.getType() == cocos2d::Value::Type::MAP) {
            return val.asValueMap();
        }
        CCLOGERROR("JSON wasn't a ValueMap/Dict");
    }

    CCLOG("JSON Parse Error: %s\n", doc.GetParseError());

    cocos2d::ValueMap ret;
    return ret;
}

cocos2d::ValueVector STValueMapFromJSON::getValueVectorFromJsonFile(const std::string& filename)
{
    auto content = cocos2d::FileUtils::getInstance()->getStringFromFile(filename);

    rapidjson::Document doc;
    doc.Parse<0>(content.c_str());
    if (! doc.HasParseError())
    {
        // check that root is object not array
        auto val = parseValueFromJsonValue(doc);
        if(val.getType() == cocos2d::Value::Type::VECTOR) {
            return val.asValueVector();
        }
        CCLOGERROR("JSON wasn't a ValueVector/Array");
    }

    CCLOG("JSON Parse Error: %s\n", doc.GetParseError());

    cocos2d::ValueVector ret;
    return ret;
}
2 Likes