blob: acdc9a71f0f136b78790198b4d916c5c8b1fc77a [file] [log] [blame]
/*
* 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);
}