Tuesday 6 May 2014

Parse JSON file in Coco2dx

I have written a simple wrapper around rapidjson for parsing json file in Cocos2dx-2.3.3. You can not use this wrapper in lower versions of Cocos2dx because they don't have included rapidjon library by default, therefore you have to add rapidjson externally for use.

JsonReader.h

#ifndef __JSON_READER__
#define __JSON_READER__

#include "cocos2d.h"
#include "cocos-ext.h"

#include <string>

USING_NS_CC;
USING_NS_CC_EXT;

using namespace std;
using namespace rapidjson;

class JsonReader
{
public:
    static JsonReader* getInstance();
    void read(const char *fileName);
    void purge(void);
    void destroyInstance(void);   
    void moveNext(void);
   
    int getRowCount(void);
    int getInt(const char* key, int def = 0);
    float getFloat(const char* key, float def = 0.0f);
    string getString(const char* key, const char* def = "");
    bool getBool(const char* key, bool def = false);
   
private:
    JsonReader();
    ~JsonReader();
   
    const Value& getSubDict(void);
    static JsonReader* m_pJsonReader;
    Document doc;
   
    unsigned char* m_pBytes;
    string m_sFileName;
    int m_nRowId;
};
#endif


JsonReader.cpp
#include "JsonReader.h"

JsonReader* JsonReader::m_pJsonReader = NULL;

JsonReader::JsonReader() {
    m_pBytes = NULL;
    m_nRowId = -1;
}

JsonReader::~JsonReader() {
    purge();
}

JsonReader* JsonReader::getInstance() {
    if (m_pJsonReader == NULL) {
        m_pJsonReader = new JsonReader();
    }
    return m_pJsonReader;
}

void JsonReader::read(const char *fileName) {
    unsigned long size = 0;
    m_sFileName = fileName;
    string jsonFile = m_sFileName + ".json";
    string jsonpath = CCFileUtils::sharedFileUtils()->fullPathForFilename(jsonFile.c_str());
    m_pBytes = CCFileUtils::sharedFileUtils()->getFileData(jsonpath.c_str(), "r", &size);
    CCAssert( m_pBytes!= NULL, "JSON file not found");
    CCAssert( strcmp((char*)m_pBytes, "") != 0, "JSON file is empty");
    string load_str((const char*)m_pBytes, size);
    doc.Parse<0>(load_str.c_str());   
    if(doc.HasParseError()) {
        CCLog("Parsing for JSON file failed : %s", jsonFile.c_str());
    }
    CCAssert(!doc.HasParseError(), doc.GetParseError());
}

void JsonReader::purge(void) {
    if(m_pBytes) {
        delete m_pBytes;
        m_pBytes = NULL;       
        m_nRowId = -1;
    }
}

void JsonReader::destroyInstance(void) {
    DictionaryHelper::shareHelper()->purgeDictionaryHelper();
    if(m_pJsonReader) {
        purge();
        delete m_pJsonReader;
        m_pJsonReader = NULL;
    }
}

void JsonReader::moveNext(void) {   
    m_nRowId++;
}

const Value& JsonReader::getSubDict(void) {
    return DICTOOL->getSubDictionary_json(doc, m_sFileName.c_str(), m_nRowId);
}

int JsonReader::getRowCount(void) {
    return DICTOOL->getArrayCount_json(doc, m_sFileName.c_str());
}

int JsonReader::getInt(const char* key, int def /* = 0 */) {
    return DICTOOL->getIntValue_json(getSubDict(), key, def);
}

float JsonReader::getFloat(const char* key, float def /* = 0.0f */) {
    return DICTOOL->getFloatValue_json(getSubDict(), key, def);
}

string JsonReader::getString(const char* key, const char* def /* = "" */) {
    return DICTOOL->getStringValue_json(getSubDict(), key, def );
}

bool JsonReader::getBool(const char* key, bool def /* = false */) {
    return DICTOOL->getBooleanValue_json(getSubDict(), key, def);
}


Sample JSON file: LEVELS.json

{ "LEVELS" : [ {
        "ID" : 0,
        "LOCK" : false,
        "NAME" : "LEVEL0",
        "SCORE" : 100,
        "SPEED" : 10
      },
      { "ID" : 1,
        "LOCK" : true,
        "NAME" : "LEVEL1",
        "SCORE" : 100,
        "SPEED" : 10
      },
      {"ID" : 2,
        "LOCK" : true,
        "NAME" : "LEVEL2",
        "SCORE" : 100,
        "SPEED" : 10
      },
      {"ID" : 3,
        "LOCK" : true,
        "NAME" : "LEVEL3",
        "SCORE" : 100,
        "SPEED" : 10
      },
      {"ID" : 4,
        "LOCK" : true,
        "NAME" : "LEVEL4",
        "SCORE" : 100,
        "SPEED" : 10
      }
    ] }


Sample function to parse JSON file using JsonReader wrapper class.

void parseJsonFile(void) {
    struct LevelItem {
        int id;
        bool lock;
        int score;
        int velocity;
        std::string name;

        void Print() {
            CCLOG("ID: %d", id);
            CCLOG("LOCK: %s", lock ? "true" : "false");
            CCLOG("SCORE: %d", score);
            CCLOG("VELOCITY: %d", velocity);
            CCLOG("NAME: %s", name.c_str());
        }
    };


    JsonReader* pReader = JsonReader::getInstance();
    pReader->read("LEVELS");

    int rows = pReader->getRowCount();
    for (int i = 0; i < rows; i++) {
        pReader->moveNext();

        LevelItem* pLevelItem = new LevelItem();
        pLevelItem->id = pReader->getInt("ID");
        pLevelItem->lock = pReader->getBool("LOCK");
        pLevelItem->score = pReader->getInt("SCORE");
        pLevelItem->velocity = pReader->getInt("VELOCITY");
        pLevelItem->name = pReader->getString("NAME");

        pLevelItem->Print();
    }
    pReader->purge();
}