blob: 6636c69d053bb216804c30f76476a6e39ddc6efc [file] [log] [blame]
mike@reedtribe.org0f175a62012-01-02 00:34:50 +00001/*
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
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000011#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
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000053struct SkJSON::Object::Slot {
54 Slot(const char name[], Type type) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000055 LEAK_CODE(SkDebugf(" slot[%d]\n", gSlotCount++);)
56 SkASSERT(name);
57
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000058 fNext = NULL;
59
60 size_t len = strlen(name);
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000061 // extra 1 for str[0] which stores the type
62 char* str = alloc_string(1 + len);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000063 str[0] = (char)type;
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000064 // str[1] skips the type, len+1 includes the terminating 0 byte.
65 memcpy(&str[1], name, len + 1);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000066 fName = str;
67
68 // fValue is uninitialized
69 }
70 ~Slot();
71
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000072 Type type() const { return (Type)fName[0]; }
73 const char* name() const { return &fName[1]; }
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000074
75 Slot* fNext;
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000076 char* fName; // fName[0] is the type, &fName[1] is the "name"
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000077 union {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000078 Object* fObject;
79 Array* fArray;
80 char* fString;
81 int32_t fInt;
82 float fFloat;
83 bool fBool;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000084 } fValue;
85};
86
87SkJSON::Object::Slot::~Slot() {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000088 free_string(fName);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000089 switch (this->type()) {
90 case kObject:
91 delete fValue.fObject;
92 break;
93 case kArray:
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000094 delete fValue.fArray;
95 break;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000096 case kString:
mike@reedtribe.orge4058b42012-01-04 03:37:40 +000097 free_string(fValue.fString);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +000098 break;
99 default:
100 break;
101 }
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000102 LEAK_CODE(SkASSERT(gSlotCount > 0); SkDebugf("~slot[%d]\n", --gSlotCount);)
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000103}
104
105///////////////////////////////////////////////////////////////////////////////
106
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000107SkJSON::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
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000199SkJSON::Object::~Object() {
200 Slot* slot = fHead;
201 while (slot) {
202 Slot* next = slot->fNext;
203 delete slot;
204 slot = next;
205 }
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000206 LEAK_CODE(SkASSERT(gObjectCount > 0); SkDebugf("~object[%d]\n", --gObjectCount);)
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000207}
208
209SkJSON::Object::Slot* SkJSON::Object::addSlot(Slot* slot) {
210 SkASSERT(NULL == slot->fNext);
211 if (NULL == fHead) {
212 SkASSERT(NULL == fTail);
213 fHead = fTail = slot;
214 } else {
215 SkASSERT(fTail);
216 SkASSERT(NULL == fTail->fNext);
217 fTail->fNext = slot;
218 fTail = slot;
219 }
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000220 return slot;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000221}
222
223void SkJSON::Object::addObject(const char name[], SkJSON::Object* value) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000224 this->addSlot(new Slot(name, kObject))->fValue.fObject = value;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000225}
226
227void SkJSON::Object::addArray(const char name[], SkJSON::Array* value) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000228 this->addSlot(new Slot(name, kArray))->fValue.fArray = value;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000229}
230
231void SkJSON::Object::addString(const char name[], const char value[]) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000232 this->addSlot(new Slot(name, kString))->fValue.fString = dup_string(value);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000233}
234
235void SkJSON::Object::addInt(const char name[], int32_t value) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000236 this->addSlot(new Slot(name, kInt))->fValue.fInt = value;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000237}
238
239void SkJSON::Object::addFloat(const char name[], float value) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000240 this->addSlot(new Slot(name, kFloat))->fValue.fFloat = value;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000241}
242
243void SkJSON::Object::addBool(const char name[], bool value) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000244 this->addSlot(new Slot(name, kBool))->fValue.fBool = value;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000245}
246
247///////////////////////////////////////////////////////////////////////////////
248
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000249const SkJSON::Object::Slot* SkJSON::Object::findSlot(const char name[],
250 Type t) const {
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000251 for (const Slot* slot = fHead; slot; slot = slot->fNext) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000252 if (t == slot->type() && !strcmp(slot->name(), name)) {
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000253 return slot;
254 }
255 }
256 return NULL;
257}
258
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000259bool SkJSON::Object::find(const char name[], Type t) const {
260 return this->findSlot(name, t) != NULL;
261}
262
263bool SkJSON::Object::findObject(const char name[], SkJSON::Object** value) const {
264 const Slot* slot = this->findSlot(name, kObject);
265 if (slot) {
266 if (value) {
267 *value = slot->fValue.fObject;
268 }
269 return true;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000270 }
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000271 return false;
272}
273
274bool SkJSON::Object::findArray(const char name[], SkJSON::Array** value) const {
275 const Slot* slot = this->findSlot(name, kArray);
276 if (slot) {
277 if (value) {
278 *value = slot->fValue.fArray;
279 }
280 return true;
281 }
282 return false;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000283}
284
285bool SkJSON::Object::findString(const char name[], SkString* value) const {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000286 const Slot* slot = this->findSlot(name, kString);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000287 if (slot) {
288 if (value) {
289 value->set(slot->fValue.fString);
290 }
291 return true;
292 }
293 return false;
294}
295
296bool SkJSON::Object::findInt(const char name[], int32_t* value) const {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000297 const Slot* slot = this->findSlot(name, kInt);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000298 if (slot) {
299 if (value) {
300 *value = slot->fValue.fInt;
301 }
302 return true;
303 }
304 return false;
305}
306
307bool SkJSON::Object::findFloat(const char name[], float* value) const {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000308 const Slot* slot = this->findSlot(name, kFloat);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000309 if (slot) {
310 if (value) {
311 *value = slot->fValue.fFloat;
312 }
313 return true;
314 }
315 return false;
316}
317
318bool SkJSON::Object::findBool(const char name[], bool* value) const {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000319 const Slot* slot = this->findSlot(name, kBool);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000320 if (slot) {
321 if (value) {
322 *value = slot->fValue.fBool;
323 }
324 return true;
325 }
326 return false;
327}
328
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000329bool SkJSON::Object::remove(const char name[], Type t) {
330 Slot* prev = NULL;
331 Slot* slot = fHead;
332 while (slot) {
333 Slot* next = slot->fNext;
334 if (t == slot->type() && !strcmp(slot->name(), name)) {
335 if (fHead == slot) {
336 fHead = next;
337 }
338 if (fTail == slot) {
339 fTail = next;
340 }
341 delete slot;
342 return true;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000343 }
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000344 prev = slot;
345 slot = next;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000346 }
347 return false;
348}
349
350///////////////////////////////////////////////////////////////////////////////
351
352static void tabForLevel(int level) {
353 for (int i = 0; i < level; ++i) {
354 SkDebugf(" ");
355 }
356}
357
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000358void SkJSON::Object::toDebugf() const {
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000359 SkDebugf("{\n");
360 this->dumpLevel(0);
361 SkDebugf("}\n");
362}
363
364void SkJSON::Object::dumpLevel(int level) const {
365 for (Slot* slot = fHead; slot; slot = slot->fNext) {
366 Type t = slot->type();
367 tabForLevel(level + 1);
368 SkDebugf("\"%s\" : ", slot->name());
369 switch (slot->type()) {
370 case kObject:
371 if (slot->fValue.fObject) {
372 SkDebugf("{\n");
373 slot->fValue.fObject->dumpLevel(level + 1);
374 tabForLevel(level + 1);
375 SkDebugf("}");
376 } else {
377 SkDebugf("null");
378 }
379 break;
380 case kArray:
381 if (slot->fValue.fArray) {
382 SkDebugf("[");
383 slot->fValue.fArray->dumpLevel(level + 1);
384 SkDebugf("]");
385 } else {
386 SkDebugf("null");
387 }
388 break;
389 case kString:
390 SkDebugf("\"%s\"", slot->fValue.fString);
391 break;
392 case kInt:
393 SkDebugf("%d", slot->fValue.fInt);
394 break;
395 case kFloat:
396 SkDebugf("%g", slot->fValue.fFloat);
397 break;
398 case kBool:
399 SkDebugf("%s", slot->fValue.fBool ? "true" : "false");
400 break;
401 default:
402 SkASSERT(!"how did I get here");
403 break;
404 }
405 if (slot->fNext) {
406 SkDebugf(",");
407 }
408 SkDebugf("\n");
409 }
410}
411
412void SkJSON::Array::dumpLevel(int level) const {
413 if (0 == fCount) {
414 return;
415 }
416 int last = fCount - 1;
417
418 switch (this->type()) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000419 case kObject: {
420 SkDebugf("\n");
421 for (int i = 0; i <= last; ++i) {
422 Object* obj = fArray.fObjects[i];
423 tabForLevel(level + 1);
424 if (obj) {
425 SkDebugf("{\n");
426 obj->dumpLevel(level + 1);
427 tabForLevel(level + 1);
428 SkDebugf(i < last ? "}," : "}");
429 } else {
430 SkDebugf(i < last ? "null," : "null");
431 }
432 SkDebugf("\n");
433 }
434 } break;
435 case kArray: {
436 SkDebugf("\n");
437 for (int i = 0; i <= last; ++i) {
438 Array* array = fArray.fArrays[i];
439 tabForLevel(level + 1);
440 if (array) {
441 SkDebugf("[");
442 array->dumpLevel(level + 1);
443 tabForLevel(level + 1);
444 SkDebugf(i < last ? "]," : "]");
445 } else {
446 SkDebugf(i < last ? "null," : "null");
447 }
448 SkDebugf("\n");
449 }
450 } break;
451 case kString: {
452 for (int i = 0; i < last; ++i) {
453 const char* str = fArray.fStrings[i];
454 SkDebugf(str ? " \"%s\"," : " null,", str);
455 }
456 const char* str = fArray.fStrings[last];
457 SkDebugf(str ? " \"%s\" " : " null ", str);
458 } break;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000459 case kInt: {
460 for (int i = 0; i < last; ++i) {
461 SkDebugf(" %d,", fArray.fInts[i]);
462 }
463 SkDebugf(" %d ", fArray.fInts[last]);
464 } break;
465 case kFloat: {
466 for (int i = 0; i < last; ++i) {
467 SkDebugf(" %g,", fArray.fFloats[i]);
468 }
469 SkDebugf(" %g ", fArray.fFloats[last]);
470 } break;
471 case kBool: {
472 for (int i = 0; i < last; ++i) {
473 SkDebugf(" %s,", fArray.fBools[i] ? "true" : "false");
474 }
475 SkDebugf(" %s ", fArray.fInts[last] ? "true" : "false");
476 } break;
477 default:
478 SkASSERT(!"unsupported array type");
479 break;
480 }
481}
482
483///////////////////////////////////////////////////////////////////////////////
484
485static const uint8_t gBytesPerType[] = {
486 sizeof(SkJSON::Object*),
487 sizeof(SkJSON::Array*),
488 sizeof(char*),
489 sizeof(int32_t),
490 sizeof(float),
491 sizeof(bool)
492};
493
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000494typedef void* (*DupProc)(const void*);
495
496static void* dup_object(const void* src) {
497 return SkNEW_ARGS(SkJSON::Object, (*(SkJSON::Object*)src));
498}
499
500static void* dup_array(const void* src) {
501 return SkNEW_ARGS(SkJSON::Array, (*(SkJSON::Array*)src));
502}
503
504static const DupProc gDupProcs[] = {
505 dup_object, // Object
506 dup_array, // Array
507 (DupProc)dup_string, // String
508 NULL, // int
509 NULL, // float
510 NULL, // bool
511};
512
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000513void SkJSON::Array::init(Type type, int count, const void* src) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000514 LEAK_CODE(SkDebugf(" array[%d]\n", gArrayCount++);)
515
516 SkASSERT((unsigned)type < SK_ARRAY_COUNT(gBytesPerType));
517
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000518 if (count < 0) {
519 count = 0;
520 }
521 size_t size = count * gBytesPerType[type];
522
523 fCount = count;
524 fType = type;
525 fArray.fVoids = sk_malloc_throw(size);
526 if (src) {
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000527 DupProc proc = gDupProcs[fType];
528 if (!proc) {
529 memcpy(fArray.fVoids, src, size);
530 } else {
531 void** srcPtr = (void**)src;
532 void** dstPtr = (void**)fArray.fVoids;
533 for (int i = 0; i < fCount; ++i) {
534 dstPtr[i] = proc(srcPtr[i]);
535 }
536 }
537 } else {
538 sk_bzero(fArray.fVoids, size);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000539 }
540}
541
542SkJSON::Array::Array(Type type, int count) {
543 this->init(type, count, NULL);
544}
545
546SkJSON::Array::Array(const int32_t values[], int count) {
547 this->init(kInt, count, values);
548}
549
550SkJSON::Array::Array(const float values[], int count) {
551 this->init(kFloat, count, values);
552}
553
554SkJSON::Array::Array(const bool values[], int count) {
555 this->init(kBool, count, values);
556}
557
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000558SkJSON::Array::Array(const Array& other) {
559 this->init(other.type(), other.count(), other.fArray.fVoids);
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000560}
561
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000562typedef void (*FreeProc)(void*);
563
564static void free_object(void* obj) {
565 delete (SkJSON::Object*)obj;
mike@reedtribe.org0f175a62012-01-02 00:34:50 +0000566}
567
mike@reedtribe.orge4058b42012-01-04 03:37:40 +0000568static void free_array(void* array) {
569 delete (SkJSON::Array*)array;
570}
571
572static const FreeProc gFreeProcs[] = {
573 free_object, // Object
574 free_array, // Array
575 (FreeProc)free_string, // String
576 NULL, // int
577 NULL, // float
578 NULL, // bool
579};
580
581SkJSON::Array::~Array() {
582 FreeProc proc = gFreeProcs[fType];
583 if (proc) {
584 void** ptr = (void**)fArray.fVoids;
585 for (int i = 0; i < fCount; ++i) {
586 proc(ptr[i]);
587 }
588 }
589 sk_free(fArray.fVoids);
590
591 LEAK_CODE(SkASSERT(gArrayCount > 0); SkDebugf("~array[%d]\n", --gArrayCount);)
592}
593
594void SkJSON::Array::setObject(int index, Object* object) {
595 SkASSERT((unsigned)index < (unsigned)fCount);
596 Object*& prev = fArray.fObjects[index];
597 if (prev != object) {
598 delete prev;
599 prev = object;
600 }
601}
602
603void SkJSON::Array::setArray(int index, Array* array) {
604 SkASSERT((unsigned)index < (unsigned)fCount);
605 Array*& prev = fArray.fArrays[index];
606 if (prev != array) {
607 delete prev;
608 prev = array;
609 }
610}
611
612void SkJSON::Array::setString(int index, const char str[]) {
613 SkASSERT((unsigned)index < (unsigned)fCount);
614 char*& prev = fArray.fStrings[index];
615 if (prev != str) {
616 free_string(prev);
617 prev = dup_string(str);
618 }
619}
620
621
622