experiment #2 for JSON data



git-svn-id: http://skia.googlecode.com/svn/trunk@2940 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/SkJSON.cpp b/src/utils/SkJSON.cpp
new file mode 100644
index 0000000..acdc9a7
--- /dev/null
+++ b/src/utils/SkJSON.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkJSON.h"
+#include "SkString.h"
+
+struct SkJSON::Object::Slot {
+    Slot(const char name[], Type type) {
+        fNext = NULL;
+        
+        size_t len = strlen(name);
+        char* str = new char[len + 2];
+        str[0] = (char)type;
+        memcpy(str + 1, name, len + 1);
+        fName = str;
+        
+        // fValue is uninitialized
+    }
+    ~Slot();
+    
+    const char* name() const {
+        return fName ? &fName[1] : "";
+    }
+    
+    Type type() const {
+        return (Type)fName[0];
+    }
+    
+    Slot*   fNext;
+    char*   fName;    // fName[0] is the type
+    union {
+        SkJSON::Object* fObject;
+        SkJSON::Array*  fArray;
+        char*           fString;
+        int32_t         fInt;
+        float           fFloat;
+        bool            fBool;
+        intptr_t        fIntPtr;    // for generic getter
+    } fValue;
+};
+
+SkJSON::Object::Slot::~Slot() {
+    switch (this->type()) {
+        case kObject:
+            delete fValue.fObject;
+            break;
+        case kArray:
+        case kString:
+            delete[] fValue.fString;
+            break;
+        default:
+            break;
+    }
+    delete[] fName;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkJSON::Object::~Object() {
+    Slot* slot = fHead;
+    while (slot) {
+        Slot* next = slot->fNext;
+        delete slot;
+        slot = next;
+    }
+}
+
+SkJSON::Object::Slot* SkJSON::Object::addSlot(Slot* slot) {
+    SkASSERT(NULL == slot->fNext);
+    if (NULL == fHead) {
+        SkASSERT(NULL == fTail);
+        fHead = fTail = slot;
+    } else {
+        SkASSERT(fTail);
+        SkASSERT(NULL == fTail->fNext);
+        fTail->fNext = slot;
+        fTail = slot;
+    }
+}
+
+void SkJSON::Object::addObject(const char name[], SkJSON::Object* value) {
+    Slot* slot = addSlot(new Slot(name, kObject));
+    fTail->fValue.fObject = value;
+}
+
+void SkJSON::Object::addArray(const char name[], SkJSON::Array* value) {
+    Slot* slot = addSlot(new Slot(name, kArray));
+    fTail->fValue.fArray = value;
+}
+
+void SkJSON::Object::addString(const char name[], const char value[]) {
+    Slot* slot = addSlot(new Slot(name, kString));
+    size_t len = strlen(value);
+    char* str = new char[len + 1];
+    memcpy(str, value, len + 1);
+    slot->fValue.fString = str;
+}
+
+void SkJSON::Object::addInt(const char name[], int32_t value) {
+    Slot* slot = addSlot(new Slot(name, kInt));
+    fTail->fValue.fInt = value;
+}
+
+void SkJSON::Object::addFloat(const char name[], float value) {
+    Slot* slot = addSlot(new Slot(name, kFloat));
+    fTail->fValue.fFloat = value;
+}
+
+void SkJSON::Object::addBool(const char name[], bool value) {
+    Slot* slot = addSlot(new Slot(name, kBool));
+    fTail->fValue.fBool = value;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const SkJSON::Object::Slot* SkJSON::Object::findSlot(const char name[]) const {
+    for (const Slot* slot = fHead; slot; slot = slot->fNext) {
+        if (!strcmp(slot->name(), name)) {
+            return slot;
+        }
+    }
+    return NULL;
+}
+
+const SkJSON::Object::Slot* SkJSON::Object::findSlotAndType(const char name[],
+                                                        Type t) const {
+    const Slot* slot = this->findSlot(name);
+    if (slot && (slot->type() != t)) {
+        slot = NULL;
+    }
+    return slot;
+}
+
+bool SkJSON::Object::findString(const char name[], SkString* value) const {
+    const Slot* slot = this->findSlotAndType(name, kString);
+    if (slot) {
+        if (value) {
+            value->set(slot->fValue.fString);
+        }
+        return true;
+    }
+    return false;
+}
+
+bool SkJSON::Object::findInt(const char name[], int32_t* value) const {
+    const Slot* slot = this->findSlotAndType(name, kInt);
+    if (slot) {
+        if (value) {
+            *value = slot->fValue.fInt;
+        }
+        return true;
+    }
+    return false;
+}
+
+bool SkJSON::Object::findFloat(const char name[], float* value) const {
+    const Slot* slot = this->findSlotAndType(name, kFloat);
+    if (slot) {
+        if (value) {
+            *value = slot->fValue.fFloat;
+        }
+        return true;
+    }
+    return false;
+}
+
+bool SkJSON::Object::findBool(const char name[], bool* value) const {
+    const Slot* slot = this->findSlotAndType(name, kBool);
+    if (slot) {
+        if (value) {
+            *value = slot->fValue.fBool;
+        }
+        return true;
+    }
+    return false;
+}
+
+bool SkJSON::Object::findObject(const char name[], SkJSON::Object** value) const {
+    const Slot* slot = this->findSlotAndType(name, kObject);
+    if (slot) {
+        if (value) {
+            *value = slot->fValue.fObject;
+        }
+        return true;
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void tabForLevel(int level) {
+    for (int i = 0; i < level; ++i) {
+        SkDebugf("    ");
+    }
+}
+
+void SkJSON::Object::dump() const {
+    SkDebugf("{\n");
+    this->dumpLevel(0);
+    SkDebugf("}\n");
+}
+
+void SkJSON::Object::dumpLevel(int level) const {
+    for (Slot* slot = fHead; slot; slot = slot->fNext) {
+        Type t = slot->type();        
+        tabForLevel(level + 1);
+        SkDebugf("\"%s\" : ", slot->name());
+        switch (slot->type()) {
+            case kObject:
+                if (slot->fValue.fObject) {
+                    SkDebugf("{\n");
+                    slot->fValue.fObject->dumpLevel(level + 1);
+                    tabForLevel(level + 1);
+                    SkDebugf("}");
+                } else {
+                    SkDebugf("null");
+                }
+                break;
+            case kArray:
+                if (slot->fValue.fArray) {
+                    SkDebugf("[");
+                    slot->fValue.fArray->dumpLevel(level + 1);
+                    SkDebugf("]");
+                } else {
+                    SkDebugf("null");
+                }
+                break;
+            case kString:
+                SkDebugf("\"%s\"", slot->fValue.fString);
+                break;
+            case kInt:
+                SkDebugf("%d", slot->fValue.fInt);
+                break;
+            case kFloat:
+                SkDebugf("%g", slot->fValue.fFloat);
+                break;
+            case kBool:
+                SkDebugf("%s", slot->fValue.fBool ? "true" : "false");
+                break;
+            default:
+                SkASSERT(!"how did I get here");
+                break;
+        }
+        if (slot->fNext) {
+            SkDebugf(",");
+        }
+        SkDebugf("\n");
+    }
+}
+
+void SkJSON::Array::dumpLevel(int level) const {
+    if (0 == fCount) {
+        return;
+    }
+    int last = fCount - 1;
+
+    switch (this->type()) {
+        case kInt: {
+            for (int i = 0; i < last; ++i) {
+                SkDebugf(" %d,", fArray.fInts[i]);
+            }
+            SkDebugf(" %d ", fArray.fInts[last]);
+        } break;
+        case kFloat: {
+            for (int i = 0; i < last; ++i) {
+                SkDebugf(" %g,", fArray.fFloats[i]);
+            }
+            SkDebugf(" %g ", fArray.fFloats[last]);
+        } break;
+        case kBool: {
+            for (int i = 0; i < last; ++i) {
+                SkDebugf(" %s,", fArray.fBools[i] ? "true" : "false");
+            }
+            SkDebugf(" %s ", fArray.fInts[last] ? "true" : "false");
+        } break;
+        default:
+            SkASSERT(!"unsupported array type");
+            break;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const uint8_t gBytesPerType[] = {
+    sizeof(SkJSON::Object*),
+    sizeof(SkJSON::Array*),
+    sizeof(char*),
+    sizeof(int32_t),
+    sizeof(float),
+    sizeof(bool)
+};
+
+void SkJSON::Array::init(Type type, int count, const void* src) {
+    if (count < 0) {
+        count = 0;
+    }
+    size_t size = count * gBytesPerType[type];
+
+    fCount = count;
+    fType = type;
+    fArray.fVoids = sk_malloc_throw(size);
+    if (src) {
+        memcpy(fArray.fVoids, src, size);
+    }
+}
+
+SkJSON::Array::Array(Type type, int count) {
+    this->init(type, count, NULL);
+}
+
+SkJSON::Array::Array(const int32_t values[], int count) {
+    this->init(kInt, count, values);
+}
+    
+SkJSON::Array::Array(const float values[], int count) {
+    this->init(kFloat, count, values);
+}
+
+SkJSON::Array::Array(const bool values[], int count) {
+    this->init(kBool, count, values);
+}
+
+SkJSON::Array::Array(const Array& src) {
+    this->init(src.type(), src.count(), src.fArray.fVoids);
+}
+
+SkJSON::Array::~Array() {
+    sk_free(fArray.fVoids);
+}
+