bool JSON_ParseFile(char *filename, const unordered_map<const char*, jsonParseFunc>& parsers, void* output) { if(!filename || !filename[0]) { R_Message(PRIORITY_WARNING, "JSON_ParseFile: bad filename sent\n"); return false; } File* file = trap->OpenFile(filename, "rb"); if(!file) { R_Message(PRIORITY_WARNING, "JSON_ParseFile: could not open file %s\n", filename); return false; } size_t numChars = trap->GetFileSize(file); char* s = (char*)trap->Zone_Alloc(numChars * sizeof(char), "files"); trap->ReadPlaintext(file, numChars, s); trap->CloseFile(file); char error[1024] = {0}; cJSON* root = cJSON_ParsePooled(s, error, sizeof(error)); if(error[0] || !root) { R_Message(PRIORITY_ERROR, "ERROR: %s: %s\n", filename, error); trap->Zone_FastFree(s, "files"); return false; } for(auto it = cJSON_GetFirstItem(root); it; it = cJSON_GetNextItem(it)) { JSON_ParseFieldSet(root, parsers, output); } trap->Zone_FastFree(s, "files"); return true; }
void JKG_Bans_LoadBans() { char *buffer; char error[256]; fileHandle_t f; int len; int i, banCount; cJSON *root, *banlist, *item, *ip; banentry_t *entry; len = trap_FS_FOpenFile(g_banfile.string, &f, FS_READ); if (len < 1) { return; } buffer = malloc(len+1); trap_FS_Read(buffer, len, f); trap_FS_FCloseFile(f); buffer[len] = 0; root = cJSON_ParsePooled(buffer, error, sizeof(error)); free(buffer); if (!root) { G_Printf("Error: Could not parse banlist: %s\n", error); return; } JKG_Bans_Clear(); nextBanId = cJSON_ToInteger(cJSON_GetObjectItem(root, "nextid")); banlist = cJSON_GetObjectItem(root, "bans"); banCount = cJSON_GetArraySize(banlist); for (i=0; i<banCount; i++) { item = cJSON_GetArrayItem(banlist, i); ip = cJSON_GetObjectItem(item, "ip"); entry = malloc(sizeof(banentry_t)); entry->id = cJSON_ToInteger(cJSON_GetObjectItem(item, "id")); entry->mask = cJSON_ToInteger(cJSON_GetObjectItem(item, "mask")); entry->expireTime = cJSON_ToInteger(cJSON_GetObjectItem(item, "expire")); Q_strncpyz(entry->banreason, cJSON_ToString(cJSON_GetObjectItem(item, "reason")), sizeof(entry->banreason)); entry->ip[0] = cJSON_ToInteger(cJSON_GetArrayItem(ip, 0)); entry->ip[1] = cJSON_ToInteger(cJSON_GetArrayItem(ip, 1)); entry->ip[2] = cJSON_ToInteger(cJSON_GetArrayItem(ip, 2)); entry->ip[3] = cJSON_ToInteger(cJSON_GetArrayItem(ip, 3)); entry->next = bans; bans = entry; } cJSON_Delete(root); }
/* =================== CG_ParseLoadingScreenTips =================== */ void CG_ParseLoadingScreenTips(void) { fileHandle_t f; int len = trap->FS_Open("ext_data/tables/loadingTips.json", &f, FS_READ); char* buffer; char error[1024]; memset(error, 0, sizeof(error)); if (len == 0 || f == NULL_HANDLE) { Com_Printf("No loading tips to display\n"); return; } trap->TrueMalloc((void**)&buffer, len); if (buffer == nullptr) { return; } trap->FS_Read(buffer, len, f); trap->FS_Close(f); cJSON* json = cJSON_ParsePooled(buffer, error, 1024); if (json == nullptr) { Com_Printf("Couldn't parse loading tips: %s\n", error); trap->TrueFree((void**)&buffer); return; } cJSON* child = cJSON_GetObjectItem(json, "tips"); if (child) { int arraySize = cJSON_GetArraySize(child); for (int i = 0; i < arraySize; i++) { cJSON* arrayItem = cJSON_GetArrayItem(child, i); loadingTip_t tip; Q_strncpyz(tip.tipText, cJSON_ToStringOpt(arrayItem, ""), sizeof(tip)); cg_loadingTips.push_back(tip); } } trap->TrueFree((void**)&buffer); // Display this tip cg_displayTipNumber = rand() % (cg_loadingTips.size() - 1); //cg_displayTipNumber = Q_irand(0, cg_loadingTips.size() - 1); }
/* ============================ JKG_LoadAmmo Loads an individual ammo (.ammo) file. Called on both the client and the server. ============================ */ static qboolean JKG_LoadAmmo(const char* fileName, const char* dir) { int fileLen; fileHandle_t f; char fileBuffer[AMMO_FILEBUFFER]; char error[AMMO_ERRBUFFER]; fileLen = trap->FS_Open(va("%s%s", dir, fileName), &f, FS_READ); if (!f || fileLen == -1) { Com_Printf(S_COLOR_RED "Could not read %s\n", fileName); return qfalse; } if (fileLen == 0) { trap->FS_Close(f); Com_Printf(S_COLOR_RED "%s is blank\n", fileName); return qfalse; } if ((fileLen + 1) >= AMMO_FILEBUFFER) { trap->FS_Close(f); Com_Printf(S_COLOR_RED "%s is too big - max file size %d bytes (%.2f kb)\n", fileName, AMMO_FILEBUFFER, AMMO_FILEBUFFER / 1024.0f); return qfalse; } trap->FS_Read(&fileBuffer, fileLen, f); fileBuffer[fileLen] = '\0'; trap->FS_Close(f); cJSON* json = cJSON_ParsePooled(fileBuffer, error, AMMO_ERRBUFFER); if (!json) { Com_Printf(S_COLOR_RED "%s: %s\n", fileName, error); return qfalse; } // Read each node in the json file from top level as an ammo_t cJSON* child; for (child = cJSON_GetFirstItem(json); child; child = cJSON_GetNextItem(child)) { if (numAmmoLoaded >= MAX_AMMO_TYPES) { Com_Printf("MAX_AMMO_TYPES exceeded\n"); break; } if (JKG_ParseSingleAmmo(child)) { numAmmoLoaded++; } } cJSON_Delete(json); return qtrue; }
/* ============================ JKG_ParseJetpack Parses a jetpack file, from memory. ============================ */ static qboolean JKG_ParseJetpack(char* buffer, const char* fileName, jetpackData_t& jetpackData) { char errorBuffer[JETPACK_ERRBUFFER] {0}; cJSON* json; cJSON* jsonNode; json = cJSON_ParsePooled(buffer, errorBuffer, sizeof(errorBuffer)); if (json == nullptr) { Com_Printf(S_COLOR_RED "%s: %s\n", fileName, errorBuffer); return qfalse; } // Basic information jsonNode = cJSON_GetObjectItem(json, "ref"); if (!jsonNode) { Com_Printf(S_COLOR_RED "%s doesn't contain a valid ref name!\n", fileName); cJSON_Delete(json); return qfalse; } Q_strncpyz(jetpackData.ref, cJSON_ToString(jsonNode), sizeof(jetpackData.ref)); jsonNode = cJSON_GetObjectItem(json, "fuelCapacity"); jetpackData.fuelCapacity = cJSON_ToIntegerOpt(jsonNode, 100); jsonNode = cJSON_GetObjectItem(json, "fuelConsumption"); jetpackData.fuelConsumption = cJSON_ToNumberOpt(jsonNode, 1.0); jsonNode = cJSON_GetObjectItem(json, "thrustConsumption"); jetpackData.thrustConsumption = cJSON_ToNumberOpt(jsonNode, 2.0); jsonNode = cJSON_GetObjectItem(json, "fuelRegeneration"); jetpackData.fuelRegeneration = cJSON_ToNumberOpt(jsonNode, 1.0); // Movement related fields jsonNode = cJSON_GetObjectItem(json, "movement"); JKG_ParseJetpackMovement(jsonNode, jetpackData); // Visuals jsonNode = cJSON_GetObjectItem(json, "visuals"); JKG_ParseJetpackVisuals(jsonNode, jetpackData); cJSON_Delete(json); return qtrue; }
static int GLua_JSON_Register( lua_State *L ) { // Check and make sure the file exists, for starters fileHandle_t f; const char *fName = luaL_checkstring(L,1); int len = trap->FS_Open( fName, &f, FS_READ ); if( len < 0 || !f ) { lua_pushnil(L); return 1; } // Read it now. char *buff = (char *)malloc(len + 1); trap->FS_Read( buff, len, f ); buff[len] = '\0'; trap->FS_Close( f ); fJSON.fileBinding = buff; // fileBinding takes a copy of the buffer. Let's just free the original right now. free( buff ); // Okay, now handle the deal with the first node. char error[MAX_STRING_CHARS]; cJSON *json = cJSON_ParsePooled( fJSON.fileBinding.c_str(), error, sizeof( error ) ); if( json == NULL ) { trap->Print(va( S_COLOR_RED "Failed to get JSON node for Lua (file: %s): %s\n", fName, error)); lua_pushnil(L); return 1; } // Pass the result to Lua FJSON_PassLastElement( L, json ); return 1; }
/* ===================== JKG_ParseArmorFile ===================== */ static qboolean JKG_ParseArmorFile(char* buffer, const char* fileName, armorData_t& armorData) { char errorBuffer[ARMOR_ERRBUFFER] {0}; cJSON* json; cJSON* jsonNode; json = cJSON_ParsePooled(buffer, errorBuffer, sizeof(errorBuffer)); if (json == nullptr) { Com_Printf(S_COLOR_RED "%s: %s\n", fileName, errorBuffer); return qfalse; } // Basic information jsonNode = cJSON_GetObjectItem(json, "ref"); if (!jsonNode) { Com_Printf(S_COLOR_RED "%s doesn't contain a valid ref name!\n", fileName); cJSON_Delete(json); return qfalse; } Q_strncpyz(armorData.ref, cJSON_ToString(jsonNode), sizeof(armorData.ref)); jsonNode = cJSON_GetObjectItem(json, "slot"); armorData.slot = JKG_ArmorSlotFromText(cJSON_ToStringOpt(jsonNode, "")); jsonNode = cJSON_GetObjectItem(json, "armor"); armorData.armor = cJSON_ToIntegerOpt(jsonNode, 0); jsonNode = cJSON_GetObjectItem(json, "hp"); armorData.hp = cJSON_ToIntegerOpt(jsonNode, 0); jsonNode = cJSON_GetObjectItem(json, "movemodifier"); armorData.movemodifier = cJSON_ToNumberOpt(jsonNode, 1.0); jsonNode = cJSON_GetObjectItem(json, "visuals"); JKG_ParseArmorVisuals(jsonNode, armorData); cJSON_Delete(json); return qtrue; }
qboolean JKG_Items_LoadCraftFile( const char *filePath, craftRecipe_t *craftData, const char * const bench, const char * const type ) { char error[MAX_STRING_CHARS]; int i, j; cJSON *json = NULL; cJSON *jsonNode = NULL; char craftFileData[MAX_CRAFTING_FILE_SIZE]; fileHandle_t f; int fileLen = strap_FS_FOpenFile(filePath, &f, FS_READ); if(!f || fileLen == -1) { Com_Printf(S_COLOR_RED "Unreadable or empty loot file: %s\n", filePath); return qfalse; } if( (fileLen + 1) >= MAX_CRAFTING_FILE_SIZE ) { strap_FS_FCloseFile(f); Com_Printf(S_COLOR_RED "%s: File too large\n", filePath); return qfalse; } strap_FS_Read(&craftFileData, fileLen, f); craftFileData[fileLen] = '\0'; strap_FS_FCloseFile(f); json = cJSON_ParsePooled(craftFileData, error, sizeof(error)); if(json == NULL) { Com_Printf(S_COLOR_RED "%s:%s\n", filePath, error); return qfalse; } JKG_Array_Init(&craftData->input, sizeof(craftInput_t), 1); JKG_Array_Init(&craftData->output, sizeof(craftInput_t), 1); for(i = 0; i < MAX_INPUTS; i++) { int inputSize; cJSON *inputNode = NULL; jsonNode = cJSON_GetObjectItem(json, va("input%i", i)); inputSize = cJSON_GetArraySize(jsonNode); for(j = 0; j < inputSize; j++) { craftInput_t dummy2; inputNode = cJSON_GetArrayItem(jsonNode, j); dummy2.internalName = cJSON_ToString(cJSON_GetObjectItem(inputNode, "internal")); dummy2.itemID = cJSON_ToInteger(cJSON_GetObjectItem(inputNode, "itemid")); dummy2.quantity = 1; dummy2.quantity = cJSON_ToInteger(cJSON_GetObjectItem(inputNode, "quantity")); JKG_Array_Add(&craftData->input, &dummy2); } } for(i = 0; i < MAX_INPUTS; i++) { int outputSize; cJSON *outputNode = NULL; jsonNode = cJSON_GetObjectItem(json, va("output%i", i)); outputSize = cJSON_GetArraySize(jsonNode); for(j = 0; j < outputSize; j++) { craftInput_t dummy2; outputNode = cJSON_GetArrayItem(jsonNode, j); dummy2.internalName = cJSON_ToString(cJSON_GetObjectItem(outputNode, "internal")); dummy2.itemID = cJSON_ToInteger(cJSON_GetObjectItem(outputNode, "itemid")); dummy2.quantity = 1; dummy2.quantity = cJSON_ToInteger(cJSON_GetObjectItem(outputNode, "quantity")); JKG_Array_Add(&craftData->output, &dummy2); } } if(Q_stricmp(bench, "workbench")) craftData->craftBench = CRAFTING_WORKBENCH; else if(Q_stricmp(bench, "welding")) craftData->craftBench = CRAFTING_WELDING; else if(Q_stricmp(bench, "laboratory")) craftData->craftBench = CRAFTING_CHEMICAL; else craftData->craftBench = CRAFTING_WORKBENCH; craftData->freestyle = (Q_stricmp(type, "freestyle") == 0) ? qtrue : qfalse; craftData->group = (craftData->freestyle == qtrue) ? cJSON_ToInteger(cJSON_GetObjectItem(json, "group")) : -1; if(craftData->freestyle) JKG_Array_Add(&FreestyleRecipes[craftData->craftBench], craftData); else JKG_Array_Add(&CraftingRecipes[craftData->craftBench], craftData); cJSON_Delete(json); return qtrue; }
static void ParseAmmoFile ( const char *fileText ) { int i = 0; cJSON *json = NULL; char jsonError[MAX_STRING_CHARS] = { 0 }; json = cJSON_ParsePooled (fileText, jsonError, sizeof (jsonError)); if ( json == NULL ) { Com_Printf (S_COLOR_RED "Error: %s\n", jsonError); } else { ammo_t *ammo = &ammoTable[0]; cJSON *jsonNode; cJSON *field; const char *string = NULL; for ( jsonNode = cJSON_GetFirstItem (json); jsonNode; jsonNode = cJSON_GetNextItem (jsonNode), ammo++, numAmmoLoaded++, i++ ) { field = cJSON_GetObjectItem (jsonNode, "name"); string = cJSON_ToString (field); if(string && string[0]) Q_strncpyz (ammo->name, string, sizeof (ammo->name)); field = cJSON_GetObjectItem (jsonNode, "ammoMax"); ammo->ammoMax = cJSON_ToNumber(field); ammo->ammoIndex = i; #ifdef _CGAME { cJSON *visual = cJSON_GetObjectItem (jsonNode, "visual"); if ( visual ) { cJSON *child = NULL; field = cJSON_GetObjectItem (visual, "model"); string = cJSON_ToString (field); if ( string && string[0] ) { ammo->model = trap->R_RegisterModel (string); } field = cJSON_GetObjectItem (visual, "fx"); string = cJSON_ToString (field); if ( string && string[0] ) { ammo->fx = trap->FX_RegisterEffect (string); } field = cJSON_GetObjectItem (visual, "deathfx"); string = cJSON_ToString (field); if ( string && string[0] ) { ammo->deathFx = trap->FX_RegisterEffect (string); } child = cJSON_GetObjectItem (visual, "miss"); if ( child ) { field = cJSON_GetObjectItem (child, "impactfx"); string = cJSON_ToString (field); if ( string && string[0] ) { ammo->missFx = trap->FX_RegisterEffect (string); } } child = cJSON_GetObjectItem (visual, "hit"); if ( child ) { field = cJSON_GetObjectItem (child, "impactfx"); string = cJSON_ToString (field); if ( string && string[0] ) { ammo->hitFx = trap->FX_RegisterEffect (string); } } } } #endif } } cJSON_Delete (json); Com_Printf ("Successfully loaded %d ammo types.\n", numAmmoLoaded); }
static qboolean BG_ParseWeaponFile ( const char *weaponFilePath ) { cJSON *json = NULL; cJSON *jsonNode = NULL; char error[MAX_STRING_CHARS]; const char *str = NULL; int weapon; int i; char weaponFileData[MAX_WEAPON_FILE_LENGTH]; fileHandle_t f; int fileLen = strap_FS_FOpenFile (weaponFilePath, &f, FS_READ); weaponData_t weaponData; fmLoadCounter = 0; if ( !f || fileLen == -1 ) { Com_Printf (S_COLOR_RED "%s: failed to read the weapon file. File is unreadable or is empty.\n", weaponFilePath); return qfalse; } if ( (fileLen + 1) >= MAX_WEAPON_FILE_LENGTH ) { trap_FS_FCloseFile (f); Com_Printf (S_COLOR_RED "%s: file too big (%d bytes, maximum is %d).\n", weaponFilePath, fileLen, MAX_WEAPON_FILE_LENGTH - 1); return qfalse; } strap_FS_Read (&weaponFileData, fileLen, f); weaponFileData[fileLen] = '\0'; strap_FS_FCloseFile (f); json = cJSON_ParsePooled (weaponFileData, error, sizeof (error)); if ( json == NULL ) { Com_Printf (S_COLOR_RED "%s: %s\n", weaponFilePath, error); return qfalse; } BG_InitializeWeaponData (&weaponData); ReadString (json, "classname", weaponData.classname, sizeof (weaponData.classname)); jsonNode = cJSON_GetObjectItem (json, "type"); str = cJSON_ToString (jsonNode); weapon = GetIDForString (WPTable, str); weaponData.weaponBaseIndex = weapon; jsonNode = cJSON_GetObjectItem (json, "variation"); weapon = cJSON_ToNumber (jsonNode); weaponData.weaponModIndex = weapon; jsonNode = cJSON_GetObjectItem (json, "stats"); BG_ParseWeaponStats (&weaponData, jsonNode); weaponData.numFiringModes = 0; for(i = 0; i < MAX_FIREMODES; i++) { jsonNode = cJSON_GetObjectItem (json, va("firemode%i", i)); if(jsonNode != NULL) { BG_ParseWeaponFireMode (&weaponData.firemodes[i], jsonNode); weaponData.numFiringModes++; } } // Old stuff for when we had primary/alt attacks --eez /*jsonNode = cJSON_GetObjectItem (json, "primaryattack"); BG_ParseWeaponFireMode (&weaponData.firemodes[0], jsonNode); jsonNode = cJSON_GetObjectItem (json, "secondaryattack"); if ( jsonNode != NULL ) { weaponData.hasSecondary = 1; BG_ParseWeaponFireMode (&weaponData.firemodes[1], jsonNode); }*/ jsonNode = cJSON_GetObjectItem (json, "playeranims"); BG_ParseWeaponPlayerAnimations (&weaponData, jsonNode); jsonNode = cJSON_GetObjectItem (json, "name"); str = cJSON_ToString (jsonNode); Q_strncpyz (weaponData.displayName, str, sizeof (weaponData.displayName)); #ifdef CGAME // TODO: Maybe we can turn this into a loop somehow? It's just turning into a stupidly long list. jsonNode = cJSON_GetObjectItem (json, "weaponanims"); // TODO jsonNode = cJSON_GetObjectItem (json, "description"); str = cJSON_ToString (jsonNode); Q_strncpyz (weaponData.visuals.description, str, sizeof (weaponData.visuals.description)); jsonNode = cJSON_GetObjectItem (json, "visual"); BG_ParseVisuals (&weaponData, jsonNode); #endif /*if ( weaponData.zoomType != ZOOM_NONE ) { // If we have zoom mode, then copy over the data from the primary to the secondary // so it's as if we haven't changed fire modes at all! Ingenious! (And also temporary) weaponData.firemodes[1] = weaponData.firemodes[0]; }*/ BG_AddWeaponData (&weaponData); cJSON_Delete (json); return qtrue; }