Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2a63c96
Finished part of code to convert json_objects to objects.
Jun 4, 2020
89d37b5
Added getting type, now will have to figure out how to add attributes…
Jun 5, 2020
5d73bb5
now checks for json path; safer wdz loading
namanhd Jun 5, 2020
343f2fc
Merge 'wdl/parsing-wdz-namanhcopy' into wdl/parsing-wdz-namanh
namanhd Jun 5, 2020
95f5ba9
Merge branch 'dev' into wdl/parsing-wdz-namanh
namanhd Jun 7, 2020
cf2b879
Merge branch 'dev' into wdl/parsing-wdz-namanh
namanhd Jun 8, 2020
b1c2630
Polishing + added tests for wdz loading
namanhd Jun 8, 2020
e9513e5
Merge branch 'dev' into wdl/parsing-wdz-namanh
namanhd Jun 8, 2020
10fa722
Merge branch 'wdl/object-implementation' into wdl/parsing-wdz-namanh
namanhd Jun 8, 2020
90e602a
Implementing conversion from json to object_t
namanhd Jun 8, 2020
36656fa
conversion now doesn't always return NULL
namanhd Jun 8, 2020
648e372
String imports should now work?
namanhd Jun 8, 2020
b5eb78e
Merge branch 'dev' into wdl/parsing-wdz-namanh
namanhd Jun 8, 2020
13761d8
Change funcs to use double pointers for objstore
namanhd Jun 8, 2020
8721710
Merge branch 'dev' into wdl/parsing-wdz-namanh
MaxineK36 Jun 8, 2020
cf290e8
Made libzip and json-c available for wdl tests on CSIL
namanhd Jun 8, 2020
7933e46
Added tests for the objstore populate function
namanhd Jun 8, 2020
f08f06a
Merge branch 'wdl/parsing-wdz-namanh' of https://github.com/uchicago-…
namanhd Jun 8, 2020
e58aebc
Fixed all tests and now frees void* data
namanhd Jun 8, 2020
c29e1f2
Merge branch 'dev' into wdl/parsing-wdz-namanh
namanhd Jun 8, 2020
dce0de3
Cleaned up printouts
namanhd Jun 8, 2020
44bd5e7
Updated convert function docs
namanhd Jun 8, 2020
b01f377
Fixed segfault on _get_idx
namanhd Jun 9, 2020
beda7e3
Merge branch 'dev' into wdl/parsing-wdz-namanh
namanhd Jun 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/wdl/load_wdz_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "load_wdz.h" // Re-export the public header for internal use as well

#define DEFAULT_PLAYER_OBJ_ID "player"

/*
* filename_extension_is: Checks if a filename string has a certain extension
*
Expand Down
1 change: 1 addition & 0 deletions src/wdl/src/attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ int free_attr(obj_attr_t *head, obj_attr_t *a)
return FAILURE;
}
DL_DELETE(head, a);
free(a->data);
free(a);
return SUCCESS;
}
Expand Down
300 changes: 287 additions & 13 deletions src/wdl/src/load_wdz_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,259 @@

#include "wdl/load_wdz_internal.h"

// Helper macros for the json name -> game object type conversion

object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name)
#define SAME_STRING(s1, s2) (strcmp(s1, s2) == (0))
#define TYPE_PLAYER_STR "player"
#define TYPE_ROOM_STR "rooms"
#define TYPE_ITEM_STR "items"
#define TYPE_ACTION_STR "actions"
#define TYPE_GCONDITION_STR "globalconditions"
#define TYPE_DIALOG_STR "dialog"
#define TYPE_NPC_STR "npcs"
#define TYPE_CUSTOM_SCRIPT_STR "customscripts"

/*
* match_j_name_to_game_obj_type:
* Converts a raw json filename/top-level key name into
* the corresponding objtype_t enum value.
*
* Parameters:
* - j_name: A string that is the raw name
*
* Returns:
* - An objtype_t value corresponding to that name
*/
objtype_t match_j_name_to_game_obj_type(char *j_name)
{
// Not implemented yet. This is in progress inside branch wdl/parsing-wdz-namanh
// and will hopefully get resolved.
objtype_t game_obj_type;
if (SAME_STRING(j_name, TYPE_PLAYER_STR))
{
game_obj_type = TYPE_PLAYER;
}
else if (SAME_STRING(j_name, TYPE_ROOM_STR))
{
game_obj_type = TYPE_ROOM;
}
else if (SAME_STRING(j_name, TYPE_ITEM_STR))
{
game_obj_type = TYPE_ITEM;
}
else if (SAME_STRING(j_name, TYPE_ACTION_STR))
{
game_obj_type = TYPE_ACTION;
}
else if (SAME_STRING(j_name, TYPE_GCONDITION_STR))
{
game_obj_type = TYPE_GCONDITION;
}
else if (SAME_STRING(j_name, TYPE_NPC_STR))
{
game_obj_type = TYPE_NPC;
}
else if (SAME_STRING(j_name, TYPE_DIALOG_STR))
{
game_obj_type = TYPE_DIALOG;
}
else if (SAME_STRING(j_name, TYPE_CUSTOM_SCRIPT_STR))
{
game_obj_type = TYPE_CUSTOM_SCRIPT;
}
else if (strlen(j_name) == 0)
{
game_obj_type = TYPE_NONE;
}
else
{
game_obj_type = TYPE_ERR;
}

return game_obj_type;
}

/*
* make_data_from_j_value
* Recursively converts every JSON object that isn't formatted like a proper
* game object. This works on nested JSON objects and arrays, too.
* Serves to make the void ptr data field for attributes.
* WARNING: This mallocs the data, so they must later be freed.
*
* Parameters:
* - j_value: the json_object to be converted
*
* Returns:
* - a void pointer pointing to allocated memory containing the desired data
*/
void *make_data_from_j_value(json_object *j_value)
{
json_type j_type = json_object_get_type(j_value);
switch (j_type)
{
case json_type_boolean:
{
json_bool *val = malloc(sizeof(*val));
*val = json_object_get_boolean(j_value);
return (void*)val;
}
case json_type_double:
{
double *val = malloc(sizeof(*val));
*val = json_object_get_double(j_value);
return (void*)val;
}
case json_type_int:
{
int *val = malloc(sizeof(*val));
*val = json_object_get_int(j_value);
return (void*)val;
}
case json_type_string:
{
int str_len = json_object_get_string_len(j_value);
char *val = calloc(str_len + 1, sizeof(*val));

strcpy(val, json_object_get_string(j_value));
return (void*)val;
}
case json_type_null:
{
void *val = NULL;
return (void*)val;
}
/* the recursive converters */
case json_type_object:
{
object_t *val = new_object("", TYPE_NONE);
json_object_iter j_iterator;
json_object_object_foreachC(j_value, j_iterator)
{
char* attr_name = j_iterator.key;
json_object *attr_val = j_iterator.val;

add_attribute(&(val->attrs), attr_name,
make_data_from_j_value(attr_val));
}
return (void*)val;

}
case json_type_array:
{
int arr_len = json_object_array_length(j_value);
if (arr_len == 0)
{
void *val = NULL;
}
object_t *val = new_object("", TYPE_NONE);
for (int i = 0; i < arr_len; i++)
{
/* var->attrs is the head element */
json_object *arr_elt = json_object_array_get_idx(j_value, i);
void *raw_data = make_data_from_j_value(arr_elt);
assert(raw_data != NULL);
append_attr(val->attrs, raw_data);
}
return (void*)val;
}
default:
{
void *val = NULL;
return (void*)val;
}
}
return NULL;
}

/* convert_j_obj_to_game_obj
* Converts a JSON object of the form
* {
* "key_name":[ INDIVIDUAL NESTED OBJECTS HERE ]
* }
*
* or
* {
* "key_name":{ ATTRIBS HERE }
* }
*
* into the right internal object_t representation.
*
* Parameters:
* - j_game_obj: The JSON object to convert
* - j_name: The name of the top-level container of j_game_obj. E.g. "rooms"
* (NOT the id of j_game_obj itself!)
* This is also the filename of the JSON file that contains this JSON.
* Returns:
* - A pointer to the resulting object_t
*/
object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name)
{
/* First find game object type (e.g. a room, or an item) */
objtype_t game_obj_type = match_j_name_to_game_obj_type(j_name);

/* Then find the game object's ID */
char game_obj_id[MAXLEN_ID];
strncpy(game_obj_id, "", MAXLEN_ID);
json_object *game_obj_id_j_obj = NULL;
json_object_object_get_ex(j_game_obj, "id", &game_obj_id_j_obj);
if (!game_obj_id_j_obj)
{
/* Player object is a one-off obj that doesn't need an id field
* the Other object types also should not require an id field
*/
if (game_obj_type == TYPE_PLAYER)
{
strncpy(game_obj_id, DEFAULT_PLAYER_OBJ_ID, MAXLEN_ID);
}
else if ((game_obj_type != TYPE_NONE)
&& (game_obj_type != TYPE_ERR))
{
fprintf(stderr,
"No id key found in the JSON of this game object!\n");
return NULL;
}
}
if (json_object_is_type(game_obj_id_j_obj, json_type_string))
{
strncpy(game_obj_id, json_object_get_string(game_obj_id_j_obj), MAXLEN_ID);
}
else
{
if ((game_obj_type != TYPE_PLAYER)
&& (game_obj_type != TYPE_NONE)
&& (game_obj_type != TYPE_ERR))
{
fprintf(stderr,
"id key in the JSON of this game object has wrong value type (must be string!)\n");
return NULL;
}
}

/* Once type and id are obtained, create the game object */
object_t *game_obj = new_object(game_obj_id, game_obj_type);

if (!game_obj)
{
fprintf(stderr, "Unable to allocate memory for game object\n");
return NULL;
}

/* Loops through all attributes in the JSON object */
json_object_iter j_iterator;
json_object_object_foreachC(j_game_obj, j_iterator)
{
char *attr_name = j_iterator.key;
json_object *j_value = j_iterator.val;
if (SAME_STRING(attr_name, "id"))
{
continue; // we already added the ID above
}
else
{
add_attribute(&(game_obj->attrs), attr_name, make_data_from_j_value(j_value));
}
}
return game_obj;
}


/* See load_wdz_internal.h */
bool filename_extension_is(const char *ext, const char *str)
Expand All @@ -37,32 +282,61 @@ int load_game_objects_from_json_object
return FAILURE;
}

json_object_object_foreach(j_obj, j_name, j_value)
json_object_iter j_iterator;
json_object_object_foreachC(j_obj, j_iterator)
{
char *j_name = j_iterator.key;
json_object *j_value = j_iterator.val;
if (json_object_is_type(j_value, json_type_array))
{
int n_objects = json_object_array_length(j_value);
int omitted = 0;
int added = 0;
array_list *j_array = json_object_get_array(j_value);

for (int i = 0; i < n_objects; i++) // for each json_object in the array
{
json_object *j_game_obj = json_object_array_get_idx(j_value, i);
/* Using internal array_list because the public interface
* functions cause weird segfault on _get_idx
*/
json_object *j_game_obj = array_list_get_idx(j_array, i);
object_t *game_obj = convert_j_obj_to_game_obj(j_game_obj, j_name);
if (!game_obj)
{
return FAILURE;
fprintf(stderr, "Couldn't convert json object %s[%d] into game object\n", j_name, i);
omitted++;
continue;
}
if (add_objstore(obj_store, game_obj) == FAILURE)
{
omitted++;
}
else
{
added++;
}
add_objstore(obj_store, game_obj);
}
return SUCCESS;

if (omitted > 0)
{
fprintf(stderr, "Omitted import of %d game objects\n", omitted);
}
if (added > 0)
{
return SUCCESS;
}
else
{
return FAILURE;
}
}
else if (json_object_is_type(j_value, json_type_object))
{
/* The only file with an object-type value as top-level
* is players.json. Other special cases can go here, but unlikely.
*/
printf("Found player object.\n");
json_object *j_player_obj;
json_object_object_get_ex(j_value, j_name, &j_player_obj);
object_t *player = convert_j_obj_to_game_obj(j_player_obj, j_name);
object_t *player = convert_j_obj_to_game_obj(j_value, j_name);

if (!player)
{
return FAILURE;
Expand All @@ -75,7 +349,7 @@ int load_game_objects_from_json_object
return FAILURE;
}
}
// If no return yet by now then it failed.
/* If no return yet by now then it failed. */
return FAILURE;
}

9 changes: 9 additions & 0 deletions src/wdl/src/load_wdz_lzip.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "wdl/load_wdz_internal.h"

#define GAME_DIR "game/"

/* Maximum buffer size for json file, in bytes.
* This is currently set to 2 MiB.
*/
Expand Down Expand Up @@ -105,6 +107,13 @@ int populate_objstore_from_wdz
zip_file_t *curr_file = zip_fopen_index(wdz, i, 0);
{ // Within the context of this opened entry...
const char *j_path_and_name = zip_get_name(wdz, i, 0);

// check for actual correct path game_name/game/ before reading
if (strncmp(strchr(j_path_and_name, '/') + 1, GAME_DIR, strlen(GAME_DIR)))
{
continue;
}

struct json_object *j_obj =
get_json_obj_from_zip_file_entry(curr_file, j_path_and_name);

Expand Down
Loading