CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) { int err = 0; if (patches == NULL) { return 1; } if (cJSON_IsArray(patches)) { /* malformed patches. */ return 1; } if (patches) { patches = patches->child; } while (patches) { if ((err = cJSONUtils_ApplyPatch(object, patches))) { return err; } patches = patches->next; } return 0; }
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches) { const cJSON *current_patch = NULL; int status = 0; if (!cJSON_IsArray(patches)) { /* malformed patches. */ return 1; } if (patches != NULL) { current_patch = patches->child; } while (current_patch != NULL) { status = apply_patch(object, current_patch, true); if (status != 0) { return status; } current_patch = current_patch->next; } return 0; }
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target) { size_t child_index = 0; cJSON *current_child = 0; if (object == target) { /* found */ return (char*)cJSONUtils_strdup((const unsigned char*)""); } /* recursively search all children of the object or array */ for (current_child = object->child; current_child != NULL; (void)(current_child = current_child->next), child_index++) { unsigned char *target_pointer = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(current_child, target); /* found the target? */ if (target_pointer != NULL) { if (cJSON_IsArray(object)) { /* reserve enough memory for a 64 bit integer + '/' and '\0' */ unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/")); /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination * if size_t is an alias of unsigned long, or if it is bigger */ if (child_index > ULONG_MAX) { cJSON_free(target_pointer); return NULL; } sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* /<array_index><path> */ cJSON_free(target_pointer); return (char*)full_pointer; } if (cJSON_IsObject(object)) { unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2); full_pointer[0] = '/'; encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string); strcat((char*)full_pointer, (char*)target_pointer); cJSON_free(target_pointer); return (char*)full_pointer; } /* reached leaf of the tree, found nothing */ cJSON_free(target_pointer); return NULL; } } /* not found */ return NULL; }
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) { size_t c = 0; cJSON *obj = 0; if (object == target) { /* found */ return (char*)cJSONUtils_strdup((const unsigned char*)""); } /* recursively search all children of the object */ for (obj = object->child; obj; (void)(obj = obj->next), c++) { unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); if (found) { if (cJSON_IsArray(object)) { /* reserve enough memory for a 64 bit integer + '/' and '\0' */ unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23); /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination * if size_t is an alias of unsigned long, or if it is bigger */ if (c > ULONG_MAX) { free(found); return NULL; } sprintf((char*)ret, "/%lu%s", (unsigned long)c, found); /* /<array_index><path> */ free(found); return (char*)ret; } else if (cJSON_IsObject(object)) { unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2); *ret = '/'; cJSONUtils_PointerEncodedstrcpy(ret + 1, (unsigned char*)obj->string); strcat((char*)ret, (char*)found); free(found); return (char*)ret; } /* reached leaf of the tree, found nothing */ free(found); return NULL; } } /* not found */ return NULL; }
/* detach an item at the given path */ static cJSON *detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive) { unsigned char *parent_pointer = NULL; unsigned char *child_pointer = NULL; cJSON *parent = NULL; cJSON *detached_item = NULL; /* copy path and split it in parent and child */ parent_pointer = cJSONUtils_strdup(path); if (parent_pointer == NULL) { goto cleanup; } child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); /* last '/' */ if (child_pointer == NULL) { goto cleanup; } /* split strings */ child_pointer[0] = '\0'; child_pointer++; parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); decode_pointer_inplace(child_pointer); if (cJSON_IsArray(parent)) { size_t index = 0; if (!decode_array_index_from_pointer(child_pointer, &index)) { goto cleanup; } detached_item = detach_item_from_array(parent, index); } else if (cJSON_IsObject(parent)) { detached_item = cJSON_DetachItemFromObject(parent, (char*)child_pointer); } else { /* Couldn't find object to remove child from. */ goto cleanup; } cleanup: if (parent_pointer != NULL) { cJSON_free(parent_pointer); } return detached_item; }
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer) { /* follow path of the pointer */ while ((*pointer++ == '/') && object) { if (cJSON_IsArray(object)) { size_t which = 0; /* parse array index */ while ((*pointer >= '0') && (*pointer <= '9')) { which = (10 * which) + (size_t)(*pointer++ - '0'); } if (*pointer && (*pointer != '/')) { /* not end of string or new path token */ return NULL; } if (which > INT_MAX) { return NULL; } object = cJSON_GetArrayItem(object, (int)which); } else if (cJSON_IsObject(object)) { object = object->child; /* GetObjectItem. */ while (object && cJSONUtils_Pstrcasecmp((unsigned char*)object->string, (const unsigned char*)pointer)) { object = object->next; } /* skip to the next path token or end of string */ while (*pointer && (*pointer != '/')) { pointer++; } } else { return NULL; } } return object; }
static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) { unsigned char *parentptr = NULL; unsigned char *childptr = NULL; cJSON *parent = NULL; cJSON *ret = NULL; /* copy path and split it in parent and child */ parentptr = cJSONUtils_strdup(path); if (parentptr == NULL) { return NULL; } childptr = (unsigned char*)strrchr((char*)parentptr, '/'); /* last '/' */ if (childptr == NULL) { free(parentptr); return NULL; } /* split strings */ *childptr++ = '\0'; parent = cJSONUtils_GetPointer(object, (char*)parentptr); cJSONUtils_InplaceDecodePointerString(childptr); if (!parent) { /* Couldn't find object to remove child from. */ ret = NULL; } else if (cJSON_IsArray(parent)) { ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr)); } else if (cJSON_IsObject(parent)) { ret = cJSON_DetachItemFromObject(parent, (char*)childptr); } free(parentptr); /* return the detachted item */ return ret; }
static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive) { cJSON *current_element = object; /* follow path of the pointer */ while ((pointer[0] == '/') && (current_element != NULL)) { pointer++; if (cJSON_IsArray(current_element)) { size_t index = 0; if (!decode_array_index_from_pointer((const unsigned char*)pointer, &index)) { return NULL; } current_element = get_array_item(current_element, index); } else if (cJSON_IsObject(current_element)) { current_element = current_element->child; /* GetObjectItem. */ while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, case_sensitive)) { current_element = current_element->next; } /* skip to the next path token or end of string */ while ((pointer[0] != '\0') && (pointer[0] != '/')) { pointer++; } } else { return NULL; } } return current_element; }
static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive) { cJSON *path = NULL; cJSON *value = NULL; cJSON *parent = NULL; enum patch_operation opcode = INVALID; unsigned char *parent_pointer = NULL; unsigned char *child_pointer = NULL; int status = 0; path = get_object_item(patch, "path", case_sensitive); if (!cJSON_IsString(path)) { /* malformed patch. */ status = 2; goto cleanup; } opcode = decode_patch_operation(patch, case_sensitive); if (opcode == INVALID) { status = 3; goto cleanup; } else if (opcode == TEST) { /* compare value: {...} with the given path */ status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), get_object_item(patch, "value", case_sensitive), case_sensitive); goto cleanup; } /* special case for replacing the root */ if (path->valuestring[0] == '\0') { if (opcode == REMOVE) { static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL}; overwrite_item(object, invalid); status = 0; goto cleanup; } if ((opcode == REPLACE) || (opcode == ADD)) { value = get_object_item(patch, "value", case_sensitive); if (value == NULL) { /* missing "value" for add/replace. */ status = 7; goto cleanup; } value = cJSON_Duplicate(value, 1); if (value == NULL) { /* out of memory for add/replace. */ status = 8; goto cleanup; } overwrite_item(object, *value); /* delete the duplicated value */ cJSON_free(value); value = NULL; /* the string "value" isn't needed */ if (object->string != NULL) { cJSON_free(object->string); object->string = NULL; } status = 0; goto cleanup; } } if ((opcode == REMOVE) || (opcode == REPLACE)) { /* Get rid of old. */ cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring, case_sensitive); if (old_item == NULL) { status = 13; goto cleanup; } cJSON_Delete(old_item); if (opcode == REMOVE) { /* For Remove, this job is done. */ status = 0; goto cleanup; } } /* Copy/Move uses "from". */ if ((opcode == MOVE) || (opcode == COPY)) { cJSON *from = get_object_item(patch, "from", case_sensitive); if (from == NULL) { /* missing "from" for copy/move. */ status = 4; goto cleanup; } if (opcode == MOVE) { value = detach_path(object, (unsigned char*)from->valuestring, case_sensitive); } if (opcode == COPY) { value = get_item_from_pointer(object, from->valuestring, case_sensitive); } if (value == NULL) { /* missing "from" for copy/move. */ status = 5; goto cleanup; } if (opcode == COPY) { value = cJSON_Duplicate(value, 1); } if (value == NULL) { /* out of memory for copy/move. */ status = 6; goto cleanup; } } else /* Add/Replace uses "value". */ { value = get_object_item(patch, "value", case_sensitive); if (value == NULL) { /* missing "value" for add/replace. */ status = 7; goto cleanup; } value = cJSON_Duplicate(value, 1); if (value == NULL) { /* out of memory for add/replace. */ status = 8; goto cleanup; } } /* Now, just add "value" to "path". */ /* split pointer in parent and child */ parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring); child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); if (child_pointer != NULL) { child_pointer[0] = '\0'; child_pointer++; } parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); decode_pointer_inplace(child_pointer); /* add, remove, replace, move, copy, test. */ if ((parent == NULL) || (child_pointer == NULL)) { /* Couldn't find object to add to. */ status = 9; goto cleanup; } else if (cJSON_IsArray(parent)) { if (strcmp((char*)child_pointer, "-") == 0) { cJSON_AddItemToArray(parent, value); value = NULL; } else { size_t index = 0; if (!decode_array_index_from_pointer(child_pointer, &index)) { status = 11; goto cleanup; } if (!insert_item_in_array(parent, index, value)) { status = 10; goto cleanup; } value = NULL; } } else if (cJSON_IsObject(parent)) { cJSON_DeleteItemFromObject(parent, (char*)child_pointer); cJSON_AddItemToObject(parent, (char*)child_pointer, value); value = NULL; } cleanup: if (value != NULL) { cJSON_Delete(value); } if (parent_pointer != NULL) { cJSON_free(parent_pointer); } return status; }
static void BG_ParseVisualsFireMode ( weaponVisualFireMode_t *fireMode, cJSON *fireModeNode, int numFireModes ) { cJSON *node = NULL; cJSON *child = NULL; qboolean isGrenade = qfalse; qboolean isBlaster = qfalse; qboolean isTripmine = qfalse; qboolean isDetpack = qfalse; ReadString (fireModeNode, "type", fireMode->type, sizeof (fireMode->type)); isGrenade = (qboolean)(Q_stricmp (fireMode->type, "grenade") == 0); isBlaster = (qboolean)(Q_stricmp (fireMode->type, "blaster") == 0); isTripmine = (qboolean)(Q_stricmp (fireMode->type, "tripmine") == 0); isDetpack = (qboolean)(Q_stricmp (fireMode->type, "detpack") == 0); ReadString (fireModeNode, "displayName", fireMode->displayName, 128); ReadString (fireModeNode, "crosshairShader", fireMode->crosshairShader, MAX_QPATH); ReadString (fireModeNode, "switchToSound", fireMode->switchToSound, MAX_QPATH); if(!fireMode->switchToSound || !fireMode->switchToSound[0]) { if(fmLoadCounter == 0) { Com_sprintf(fireMode->switchToSound, MAX_QPATH, "sound/weapons/common/click%i.wav", numFireModes); } else { Com_sprintf(fireMode->switchToSound, MAX_QPATH, "sound/weapons/common/click1.wav"); } } node = cJSON_GetObjectItem (fireModeNode, "animType"); fireMode->animType = (firingModeAnim_t)cJSON_ToInteger (node); fireMode->overrideIndicatorFrame = -1; // set this as default since 0 is still a valid frame node = cJSON_GetObjectItem (fireModeNode, "overrideIndicatorFrame"); if(node) { fireMode->overrideIndicatorFrame = cJSON_ToInteger (node); } // TODO: Need to tie this to the table in cg_weapons.c somehow... // Weapon Render node = cJSON_GetObjectItem (fireModeNode, "muzzlelightintensity"); fireMode->weaponRender.generic.muzzleLightIntensity = (float)cJSON_ToNumber (node); ReadString (fireModeNode, "muzzlelightcolor", fireMode->weaponRender.generic.muzzleLightColor, sizeof (fireMode->weaponRender.generic.muzzleLightColor)); ReadString (fireModeNode, "chargingfx", fireMode->weaponRender.generic.chargingEffect, sizeof (fireMode->weaponRender.generic.chargingEffect)); ReadString (fireModeNode, "muzzlefx", fireMode->weaponRender.generic.muzzleEffect, sizeof (fireMode->weaponRender.generic.muzzleEffect)); // Weapon Fire child = cJSON_GetObjectItem (fireModeNode, "firesound"); if ( child ) { if ( cJSON_IsArray (child) ) { const char *fireSounds[8]; int numFireSounds = cJSON_ReadStringArray (child, 8, fireSounds); int i; for ( i = 0; i < numFireSounds; i++ ) { Q_strncpyz (fireMode->weaponFire.generic.fireSound[i], fireSounds[i], sizeof (fireMode->weaponFire.generic.fireSound[i])); } } else { const char *s = cJSON_ToString (child); if ( s ) Q_strncpyz (fireMode->weaponFire.generic.fireSound[0], s, sizeof (fireMode->weaponFire.generic.fireSound[0])); } } // Traceline Render ReadString (fireModeNode, "tracelineshader", fireMode->tracelineRender.generic.tracelineShader, sizeof (fireMode->tracelineRender.generic.tracelineShader)); node = cJSON_GetObjectItem (fireModeNode, "minsize"); fireMode->tracelineRender.generic.minSize = (float)cJSON_ToNumber (node); node = cJSON_GetObjectItem (fireModeNode, "maxsize"); fireMode->tracelineRender.generic.maxSize = (float)cJSON_ToNumber (node); node = cJSON_GetObjectItem (fireModeNode, "lifetime"); fireMode->tracelineRender.generic.lifeTime = cJSON_ToInteger (node); // Weapon Charge ReadString (fireModeNode, "chargingsound", fireMode->weaponCharge.chargingSound, sizeof (fireMode->weaponCharge.chargingSound)); // Projectile render ReadString (fireModeNode, "projectilemodel", fireMode->projectileRender.generic.projectileModel, sizeof (fireMode->projectileRender.generic.projectileModel)); ReadString (fireModeNode, "projectilefx", fireMode->projectileRender.generic.projectileEffect, sizeof (fireMode->projectileRender.generic.projectileEffect)); ReadString (fireModeNode, "runsound", fireMode->projectileRender.generic.runSound, sizeof (fireMode->projectileRender.generic.runSound)); node = cJSON_GetObjectItem (fireModeNode, "lightintensity"); fireMode->projectileRender.generic.lightIntensity = (float)cJSON_ToNumber (node); ReadString (fireModeNode, "lightcolor", fireMode->projectileRender.generic.lightColor, sizeof (fireMode->projectileRender.generic.lightColor)); ReadString (fireModeNode, "deathfx", fireMode->projectileRender.generic.deathEffect, sizeof (fireMode->projectileRender.generic.deathEffect)); // Projectile miss event child = cJSON_GetObjectItem (fireModeNode, "miss"); if ( isTripmine || isDetpack ) { ReadString (child, "sticksound", fireMode->projectileMiss.explosive.stickSound, sizeof (fireMode->projectileMiss.explosive.stickSound)); } else { ReadString (child, "impactfx", fireMode->projectileMiss.generic.impactEffect, sizeof (fireMode->projectileMiss.generic.impactEffect)); ReadString (child, "shockwavefx", fireMode->projectileMiss.grenade.shockwaveEffect, sizeof (fireMode->projectileMiss.grenade.shockwaveEffect)); } // Projectile hit event child = cJSON_GetObjectItem (fireModeNode, "hit"); ReadString (child, "impactfx", fireMode->projectileHitPlayer.generic.impactEffect, sizeof (fireMode->projectileHitPlayer.generic.impactEffect)); ReadString (child, "shockwavefx", fireMode->projectileHitPlayer.grenade.shockwaveEffect, sizeof (fireMode->projectileHitPlayer.grenade.shockwaveEffect)); // Projectile deflected event ReadString (fireModeNode, "deflectedfx", fireMode->projectileDeflected.generic.deflectEffect, sizeof (fireMode->projectileDeflected.generic.deflectEffect)); // Grenade bounce event child = cJSON_GetObjectItem (fireModeNode, "bouncesound"); if ( child ) { const char *bounceSounds[2]; int numBounceSounds = cJSON_ReadStringArray (child, 2, bounceSounds); int i; for ( i = 0; i < numBounceSounds; i++ ) { Q_strncpyz (fireMode->grenadeBounce.grenade.bounceSound[i], bounceSounds[i], sizeof (fireMode->grenadeBounce.grenade.bounceSound[i])); } } // Explosive render ReadString (fireModeNode, "g2model", fireMode->explosiveRender.detpack.g2Model, sizeof (fireMode->explosiveRender.detpack.g2Model)); node = cJSON_GetObjectItem (fireModeNode, "g2radius"); fireMode->explosiveRender.detpack.g2Radius = (float)cJSON_ToNumber (node); ReadString (fireModeNode, "linefx", fireMode->explosiveRender.tripmine.lineEffect, sizeof (fireMode->explosiveRender.tripmine.lineEffect)); // Explosive blow event ReadString (fireModeNode, "explodefx", fireMode->explosiveBlow.generic.explodeEffect, sizeof (fireMode->explosiveBlow.generic.explodeEffect)); // Explosive armed event ReadString (fireModeNode, "armsound", fireMode->explosiveArm.armSound, sizeof (fireMode->explosiveArm.armSound)); fmLoadCounter++; }
static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) { cJSON *op = NULL; cJSON *path = NULL; cJSON *value = NULL; cJSON *parent = NULL; int opcode = 0; unsigned char *parentptr = NULL; unsigned char *childptr = NULL; op = cJSON_GetObjectItem(patch, "op"); path = cJSON_GetObjectItem(patch, "path"); if (!op || !path) { /* malformed patch. */ return 2; } /* decode operation */ if (!strcmp(op->valuestring, "add")) { opcode = 0; } else if (!strcmp(op->valuestring, "remove")) { opcode = 1; } else if (!strcmp(op->valuestring, "replace")) { opcode = 2; } else if (!strcmp(op->valuestring, "move")) { opcode = 3; } else if (!strcmp(op->valuestring, "copy")) { opcode = 4; } else if (!strcmp(op->valuestring, "test")) { /* compare value: {...} with the given path */ return cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); } else { /* unknown opcode. */ return 3; } /* Remove/Replace */ if ((opcode == 1) || (opcode == 2)) { /* Get rid of old. */ cJSON_Delete(cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring)); if (opcode == 1) { /* For Remove, this is job done. */ return 0; } } /* Copy/Move uses "from". */ if ((opcode == 3) || (opcode == 4)) { cJSON *from = cJSON_GetObjectItem(patch, "from"); if (!from) { /* missing "from" for copy/move. */ return 4; } if (opcode == 3) { /* move */ value = cJSONUtils_PatchDetach(object, (unsigned char*)from->valuestring); } if (opcode == 4) { /* copy */ value = cJSONUtils_GetPointer(object, from->valuestring); } if (!value) { /* missing "from" for copy/move. */ return 5; } if (opcode == 4) { value = cJSON_Duplicate(value, 1); } if (!value) { /* out of memory for copy/move. */ return 6; } } else /* Add/Replace uses "value". */ { value = cJSON_GetObjectItem(patch, "value"); if (!value) { /* missing "value" for add/replace. */ return 7; } value = cJSON_Duplicate(value, 1); if (!value) { /* out of memory for add/replace. */ return 8; } } /* Now, just add "value" to "path". */ /* split pointer in parent and child */ parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring); childptr = (unsigned char*)strrchr((char*)parentptr, '/'); if (childptr) { *childptr++ = '\0'; } parent = cJSONUtils_GetPointer(object, (char*)parentptr); cJSONUtils_InplaceDecodePointerString(childptr); /* add, remove, replace, move, copy, test. */ if (!parent) { /* Couldn't find object to add to. */ free(parentptr); cJSON_Delete(value); return 9; } else if (cJSON_IsArray(parent)) { if (!strcmp((char*)childptr, "-")) { cJSON_AddItemToArray(parent, value); } else { cJSON_InsertItemInArray(parent, atoi((char*)childptr), value); } } else if (cJSON_IsObject(parent)) { cJSON_DeleteItemFromObject(parent, (char*)childptr); cJSON_AddItemToObject(parent, (char*)childptr, value); } else { cJSON_Delete(value); } free(parentptr); return 0; }