1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkJSON.h"
9#include "SkString.h"
10
11#ifdef SK_DEBUG
12//    #define TRACE_SKJSON_LEAKS
13#endif
14
15#ifdef TRACE_SKJSON_LEAKS
16    static int gStringCount;
17    static int gSlotCount;
18    static int gObjectCount;
19    static int gArrayCount;
20    #define LEAK_CODE(code) code
21#else
22    #define LEAK_CODE(code)
23#endif
24
25///////////////////////////////////////////////////////////////////////////////
26
27static char* alloc_string(size_t len) {
28    LEAK_CODE(SkDebugf(" string[%d]\n", gStringCount++);)
29    char* str = (char*)sk_malloc_throw(len + 1);
30    str[len] = 0;
31    return str;
32}
33
34static char* dup_string(const char src[]) {
35    if (NULL == src) {
36        return NULL;
37    }
38    size_t len = strlen(src);
39    char* dst = alloc_string(len);
40    memcpy(dst, src, len);
41    return dst;
42}
43
44static void free_string(char* str) {
45    if (str) {
46        sk_free(str);
47        LEAK_CODE(SkASSERT(gStringCount > 0); SkDebugf("~string[%d]\n", --gStringCount);)
48    }
49}
50
51///////////////////////////////////////////////////////////////////////////////
52
53struct SkJSON::Object::Slot {
54    Slot(const char name[], Type type) {
55        LEAK_CODE(SkDebugf(" slot[%d]\n", gSlotCount++);)
56        SkASSERT(name);
57
58        fNext = NULL;
59
60        size_t len = strlen(name);
61        // extra 1 for str[0] which stores the type
62        char* str = alloc_string(1 + len);
63        str[0] = (char)type;
64        // str[1] skips the type, len+1 includes the terminating 0 byte.
65        memcpy(&str[1], name, len + 1);
66        fName = str;
67
68        // fValue is uninitialized
69    }
70    ~Slot();
71
72    Type type() const { return (Type)fName[0]; }
73    const char* name() const { return &fName[1]; }
74
75    Slot*   fNext;
76    char*   fName;    // fName[0] is the type, &fName[1] is the "name"
77    union {
78        Object* fObject;
79        Array*  fArray;
80        char*   fString;
81        int32_t fInt;
82        float   fFloat;
83        bool    fBool;
84    } fValue;
85};
86
87SkJSON::Object::Slot::~Slot() {
88    free_string(fName);
89    switch (this->type()) {
90        case kObject:
91            delete fValue.fObject;
92            break;
93        case kArray:
94            delete fValue.fArray;
95            break;
96        case kString:
97            free_string(fValue.fString);
98            break;
99        default:
100            break;
101    }
102    LEAK_CODE(SkASSERT(gSlotCount > 0); SkDebugf("~slot[%d]\n", --gSlotCount);)
103}
104
105///////////////////////////////////////////////////////////////////////////////
106
107SkJSON::Object::Iter::Iter(const Object& obj) : fSlot(obj.fHead) {}
108
109bool SkJSON::Object::Iter::done() const {
110    return NULL == fSlot;
111}
112
113void SkJSON::Object::Iter::next() {
114    SkASSERT(fSlot);
115    fSlot = fSlot->fNext;
116}
117
118SkJSON::Type SkJSON::Object::Iter::type() const {
119    SkASSERT(fSlot);
120    return fSlot->type();
121}
122
123const char* SkJSON::Object::Iter::name() const {
124    SkASSERT(fSlot);
125    return fSlot->name();
126}
127
128SkJSON::Object* SkJSON::Object::Iter::objectValue() const {
129    SkASSERT(fSlot);
130    SkASSERT(kObject == fSlot->type());
131    return fSlot->fValue.fObject;
132}
133
134SkJSON::Array* SkJSON::Object::Iter::arrayValue() const {
135    SkASSERT(fSlot);
136    SkASSERT(kArray == fSlot->type());
137    return fSlot->fValue.fArray;
138}
139
140const char* SkJSON::Object::Iter::stringValue() const {
141    SkASSERT(fSlot);
142    SkASSERT(kString == fSlot->type());
143    return fSlot->fValue.fString;
144}
145
146int32_t SkJSON::Object::Iter::intValue() const {
147    SkASSERT(fSlot);
148    SkASSERT(kInt == fSlot->type());
149    return fSlot->fValue.fInt;
150}
151
152float SkJSON::Object::Iter::floatValue() const {
153    SkASSERT(fSlot);
154    SkASSERT(kFloat == fSlot->type());
155    return fSlot->fValue.fFloat;
156}
157
158bool SkJSON::Object::Iter::boolValue() const {
159    SkASSERT(fSlot);
160    SkASSERT(kBool == fSlot->type());
161    return fSlot->fValue.fBool;
162}
163
164///////////////////////////////////////////////////////////////////////////////
165
166SkJSON::Object::Object() : fHead(NULL), fTail(NULL) {
167    LEAK_CODE(SkDebugf(" object[%d]\n", gObjectCount++);)
168}
169
170SkJSON::Object::Object(const Object& other) : fHead(NULL), fTail(NULL) {
171    LEAK_CODE(SkDebugf(" object[%d]\n", gObjectCount++);)
172
173    Iter iter(other);
174    while (!iter.done()) {
175        switch (iter.type()) {
176            case kObject:
177                this->addObject(iter.name(), new Object(*iter.objectValue()));
178                break;
179            case kArray:
180                this->addArray(iter.name(), new Array(*iter.arrayValue()));
181                break;
182            case kString:
183                this->addString(iter.name(), dup_string(iter.stringValue()));
184                break;
185            case kInt:
186                this->addInt(iter.name(), iter.intValue());
187                break;
188            case kFloat:
189                this->addFloat(iter.name(), iter.floatValue());
190                break;
191            case kBool:
192                this->addBool(iter.name(), iter.boolValue());
193                break;
194        }
195        iter.next();
196    }
197}
198
199SkJSON::Object::~Object() {
200    Slot* slot = fHead;
201    while (slot) {
202        Slot* next = slot->fNext;
203        delete slot;
204        slot = next;
205    }
206    LEAK_CODE(SkASSERT(gObjectCount > 0); SkDebugf("~object[%d]\n", --gObjectCount);)
207}
208
209int SkJSON::Object::count() const {
210    int n = 0;
211    for (const Slot* slot = fHead; slot; slot = slot->fNext) {
212        n += 1;
213    }
214    return n;
215}
216
217SkJSON::Object::Slot* SkJSON::Object::addSlot(Slot* slot) {
218    SkASSERT(NULL == slot->fNext);
219    if (NULL == fHead) {
220        SkASSERT(NULL == fTail);
221        fHead = fTail = slot;
222    } else {
223        SkASSERT(fTail);
224        SkASSERT(NULL == fTail->fNext);
225        fTail->fNext = slot;
226        fTail = slot;
227    }
228    return slot;
229}
230
231void SkJSON::Object::addObject(const char name[], SkJSON::Object* value) {
232    this->addSlot(new Slot(name, kObject))->fValue.fObject = value;
233}
234
235void SkJSON::Object::addArray(const char name[], SkJSON::Array* value) {
236    this->addSlot(new Slot(name, kArray))->fValue.fArray = value;
237}
238
239void SkJSON::Object::addString(const char name[], const char value[]) {
240    this->addSlot(new Slot(name, kString))->fValue.fString = dup_string(value);
241}
242
243void SkJSON::Object::addInt(const char name[], int32_t value) {
244    this->addSlot(new Slot(name, kInt))->fValue.fInt = value;
245}
246
247void SkJSON::Object::addFloat(const char name[], float value) {
248    this->addSlot(new Slot(name, kFloat))->fValue.fFloat = value;
249}
250
251void SkJSON::Object::addBool(const char name[], bool value) {
252    this->addSlot(new Slot(name, kBool))->fValue.fBool = value;
253}
254
255///////////////////////////////////////////////////////////////////////////////
256
257const SkJSON::Object::Slot* SkJSON::Object::findSlot(const char name[],
258                                                     Type t) const {
259    for (const Slot* slot = fHead; slot; slot = slot->fNext) {
260        if (t == slot->type() && !strcmp(slot->name(), name)) {
261            return slot;
262        }
263    }
264    return NULL;
265}
266
267bool SkJSON::Object::find(const char name[], Type t) const {
268    return this->findSlot(name, t) != NULL;
269}
270
271bool SkJSON::Object::findObject(const char name[], SkJSON::Object** value) const {
272    const Slot* slot = this->findSlot(name, kObject);
273    if (slot) {
274        if (value) {
275            *value = slot->fValue.fObject;
276        }
277        return true;
278    }
279    return false;
280}
281
282bool SkJSON::Object::findArray(const char name[], SkJSON::Array** value) const {
283    const Slot* slot = this->findSlot(name, kArray);
284    if (slot) {
285        if (value) {
286            *value = slot->fValue.fArray;
287        }
288        return true;
289    }
290    return false;
291}
292
293bool SkJSON::Object::findString(const char name[], SkString* value) const {
294    const Slot* slot = this->findSlot(name, kString);
295    if (slot) {
296        if (value) {
297            value->set(slot->fValue.fString);
298        }
299        return true;
300    }
301    return false;
302}
303
304bool SkJSON::Object::findInt(const char name[], int32_t* value) const {
305    const Slot* slot = this->findSlot(name, kInt);
306    if (slot) {
307        if (value) {
308            *value = slot->fValue.fInt;
309        }
310        return true;
311    }
312    return false;
313}
314
315bool SkJSON::Object::findFloat(const char name[], float* value) const {
316    const Slot* slot = this->findSlot(name, kFloat);
317    if (slot) {
318        if (value) {
319            *value = slot->fValue.fFloat;
320        }
321        return true;
322    }
323    return false;
324}
325
326bool SkJSON::Object::findBool(const char name[], bool* value) const {
327    const Slot* slot = this->findSlot(name, kBool);
328    if (slot) {
329        if (value) {
330            *value = slot->fValue.fBool;
331        }
332        return true;
333    }
334    return false;
335}
336
337bool SkJSON::Object::remove(const char name[], Type t) {
338    SkDEBUGCODE(int count = this->count();)
339    Slot* prev = NULL;
340    Slot* slot = fHead;
341    while (slot) {
342        Slot* next = slot->fNext;
343        if (t == slot->type() && !strcmp(slot->name(), name)) {
344            if (prev) {
345                SkASSERT(fHead != slot);
346                prev->fNext = next;
347            } else {
348                SkASSERT(fHead == slot);
349                fHead = next;
350            }
351            if (fTail == slot) {
352                fTail = prev;
353            }
354            delete slot;
355            SkASSERT(count - 1 == this->count());
356            return true;
357        }
358        prev = slot;
359        slot = next;
360    }
361    SkASSERT(count == this->count());
362    return false;
363}
364
365///////////////////////////////////////////////////////////////////////////////
366
367static void tabForLevel(int level) {
368    for (int i = 0; i < level; ++i) {
369        SkDebugf("    ");
370    }
371}
372
373void SkJSON::Object::toDebugf() const {
374    SkDebugf("{\n");
375    this->dumpLevel(0);
376    SkDebugf("}\n");
377}
378
379void SkJSON::Object::dumpLevel(int level) const {
380    for (Slot* slot = fHead; slot; slot = slot->fNext) {
381        Type t = slot->type();
382        tabForLevel(level + 1);
383        SkDebugf("\"%s\" : ", slot->name());
384        switch (slot->type()) {
385            case kObject:
386                if (slot->fValue.fObject) {
387                    SkDebugf("{\n");
388                    slot->fValue.fObject->dumpLevel(level + 1);
389                    tabForLevel(level + 1);
390                    SkDebugf("}");
391                } else {
392                    SkDebugf("null");
393                }
394                break;
395            case kArray:
396                if (slot->fValue.fArray) {
397                    SkDebugf("[");
398                    slot->fValue.fArray->dumpLevel(level + 1);
399                    SkDebugf("]");
400                } else {
401                    SkDebugf("null");
402                }
403                break;
404            case kString:
405                SkDebugf("\"%s\"", slot->fValue.fString);
406                break;
407            case kInt:
408                SkDebugf("%d", slot->fValue.fInt);
409                break;
410            case kFloat:
411                SkDebugf("%g", slot->fValue.fFloat);
412                break;
413            case kBool:
414                SkDebugf("%s", slot->fValue.fBool ? "true" : "false");
415                break;
416            default:
417                SkDEBUGFAIL("how did I get here");
418                break;
419        }
420        if (slot->fNext) {
421            SkDebugf(",");
422        }
423        SkDebugf("\n");
424    }
425}
426
427void SkJSON::Array::dumpLevel(int level) const {
428    if (0 == fCount) {
429        return;
430    }
431    int last = fCount - 1;
432
433    switch (this->type()) {
434        case kObject: {
435            SkDebugf("\n");
436            for (int i = 0; i <= last; ++i) {
437                Object* obj = fArray.fObjects[i];
438                tabForLevel(level + 1);
439                if (obj) {
440                    SkDebugf("{\n");
441                    obj->dumpLevel(level + 1);
442                    tabForLevel(level + 1);
443                    SkDebugf(i < last ? "}," : "}");
444                } else {
445                    SkDebugf(i < last ? "null," : "null");
446                }
447                SkDebugf("\n");
448            }
449        } break;
450        case kArray: {
451            SkDebugf("\n");
452            for (int i = 0; i <= last; ++i) {
453                Array* array = fArray.fArrays[i];
454                tabForLevel(level + 1);
455                if (array) {
456                    SkDebugf("[");
457                    array->dumpLevel(level + 1);
458                    tabForLevel(level + 1);
459                    SkDebugf(i < last ? "]," : "]");
460                } else {
461                    SkDebugf(i < last ? "null," : "null");
462                }
463                SkDebugf("\n");
464            }
465        } break;
466        case kString: {
467            for (int i = 0; i < last; ++i) {
468                const char* str = fArray.fStrings[i];
469                SkDebugf(str ? " \"%s\"," : " null,", str);
470            }
471            const char* str = fArray.fStrings[last];
472            SkDebugf(str ? " \"%s\" " : " null ", str);
473        } break;
474        case kInt: {
475            for (int i = 0; i < last; ++i) {
476                SkDebugf(" %d,", fArray.fInts[i]);
477            }
478            SkDebugf(" %d ", fArray.fInts[last]);
479        } break;
480        case kFloat: {
481            for (int i = 0; i < last; ++i) {
482                SkDebugf(" %g,", fArray.fFloats[i]);
483            }
484            SkDebugf(" %g ", fArray.fFloats[last]);
485        } break;
486        case kBool: {
487            for (int i = 0; i < last; ++i) {
488                SkDebugf(" %s,", fArray.fBools[i] ? "true" : "false");
489            }
490            SkDebugf(" %s ", fArray.fInts[last] ? "true" : "false");
491        } break;
492        default:
493            SkDEBUGFAIL("unsupported array type");
494            break;
495    }
496}
497
498///////////////////////////////////////////////////////////////////////////////
499
500static const uint8_t gBytesPerType[] = {
501    sizeof(SkJSON::Object*),
502    sizeof(SkJSON::Array*),
503    sizeof(char*),
504    sizeof(int32_t),
505    sizeof(float),
506    sizeof(bool)
507};
508
509typedef void* (*DupProc)(const void*);
510
511static void* dup_object(const void* src) {
512    return SkNEW_ARGS(SkJSON::Object, (*(SkJSON::Object*)src));
513}
514
515static void* dup_array(const void* src) {
516    return SkNEW_ARGS(SkJSON::Array, (*(SkJSON::Array*)src));
517}
518
519static const DupProc gDupProcs[] = {
520    dup_object,             // Object
521    dup_array,              // Array
522    (DupProc)dup_string,    // String
523    NULL,                   // int
524    NULL,                   // float
525    NULL,                   // bool
526};
527
528void SkJSON::Array::init(Type type, int count, const void* src) {
529    LEAK_CODE(SkDebugf(" array[%d]\n", gArrayCount++);)
530
531    SkASSERT((unsigned)type < SK_ARRAY_COUNT(gBytesPerType));
532
533    if (count < 0) {
534        count = 0;
535    }
536    size_t size = count * gBytesPerType[type];
537
538    fCount = count;
539    fType = type;
540    fArray.fVoids = sk_malloc_throw(size);
541    if (src) {
542        DupProc proc = gDupProcs[fType];
543        if (!proc) {
544            memcpy(fArray.fVoids, src, size);
545        } else {
546            void** srcPtr = (void**)src;
547            void** dstPtr = (void**)fArray.fVoids;
548            for (int i = 0; i < fCount; ++i) {
549                dstPtr[i] = proc(srcPtr[i]);
550            }
551        }
552    } else {
553        sk_bzero(fArray.fVoids, size);
554    }
555}
556
557SkJSON::Array::Array(Type type, int count) {
558    this->init(type, count, NULL);
559}
560
561SkJSON::Array::Array(const int32_t values[], int count) {
562    this->init(kInt, count, values);
563}
564
565SkJSON::Array::Array(const float values[], int count) {
566    this->init(kFloat, count, values);
567}
568
569SkJSON::Array::Array(const bool values[], int count) {
570    this->init(kBool, count, values);
571}
572
573SkJSON::Array::Array(const Array& other) {
574    this->init(other.type(), other.count(), other.fArray.fVoids);
575}
576
577typedef void (*FreeProc)(void*);
578
579static void free_object(void* obj) {
580    delete (SkJSON::Object*)obj;
581}
582
583static void free_array(void* array) {
584    delete (SkJSON::Array*)array;
585}
586
587static const FreeProc gFreeProcs[] = {
588    free_object,            // Object
589    free_array,             // Array
590    (FreeProc)free_string,  // String
591    NULL,                   // int
592    NULL,                   // float
593    NULL,                   // bool
594};
595
596SkJSON::Array::~Array() {
597    FreeProc proc = gFreeProcs[fType];
598    if (proc) {
599        void** ptr = (void**)fArray.fVoids;
600        for (int i = 0; i < fCount; ++i) {
601            proc(ptr[i]);
602        }
603    }
604    sk_free(fArray.fVoids);
605
606    LEAK_CODE(SkASSERT(gArrayCount > 0); SkDebugf("~array[%d]\n", --gArrayCount);)
607}
608
609void SkJSON::Array::setObject(int index, Object* object) {
610    SkASSERT((unsigned)index < (unsigned)fCount);
611    Object*& prev = fArray.fObjects[index];
612    if (prev != object) {
613        delete prev;
614        prev = object;
615    }
616}
617
618void SkJSON::Array::setArray(int index, Array* array) {
619    SkASSERT((unsigned)index < (unsigned)fCount);
620    Array*& prev = fArray.fArrays[index];
621    if (prev != array) {
622        delete prev;
623        prev = array;
624    }
625}
626
627void SkJSON::Array::setString(int index, const char str[]) {
628    SkASSERT((unsigned)index < (unsigned)fCount);
629    char*& prev = fArray.fStrings[index];
630    if (prev != str) {
631        free_string(prev);
632        prev = dup_string(str);
633    }
634}
635