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