static gboolean reader_fill_compound_gvalue (JsonReader *reader, TopicValueType type, GValue *value, GError **error) { GDataFreebaseTopicObject *object; if (type != TYPE_COMPOUND) return FALSE; object = reader_create_object (reader, type); if (object == NULL) return FALSE; json_reader_read_member (reader, "property"); if (json_reader_get_error (reader) != NULL) { json_reader_end_member (reader); gdata_freebase_topic_object_unref (object); return FALSE; } reader_get_properties (reader, object, error); json_reader_end_member (reader); g_value_init (value, GDATA_TYPE_FREEBASE_TOPIC_OBJECT); g_value_take_boxed (value, object); return TRUE; }
/* Parsing functions to create GDataFreebaseTopicValues, and arrays of those */ static gchar * reader_dup_member_string (JsonReader *reader, const gchar *member, GError **error) { const GError *reader_error; gchar *str; if (error != NULL && *error != NULL) return NULL; json_reader_read_member (reader, member); str = g_strdup (json_reader_get_string_value (reader)); reader_error = json_reader_get_error (reader); if (reader_error != NULL) { g_free (str); str = NULL; if (error != NULL) *error = g_error_copy (reader_error); } json_reader_end_member (reader); return str; }
static gint64 reader_parse_timestamp (JsonReader *reader, const gchar *member, GError **error) { const GError *reader_error; const gchar *date_str; gint64 timestamp = -1; if (error != NULL && *error != NULL) return -1; json_reader_read_member (reader, member); date_str = json_reader_get_string_value (reader); reader_error = json_reader_get_error (reader); if (reader_error != NULL) { if (error != NULL) *error = g_error_copy (reader_error); } else if (date_str) { if (!gdata_parser_int64_from_iso8601 (date_str, ×tamp)) timestamp = -1; } json_reader_end_member (reader); return timestamp; }
/* * gdata_parser_boolean_from_json_member: * @reader: #JsonReader cursor object to read the JSON node from * @member_name: the name of the JSON object member to parse * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE * @output: (out caller-allocates): the return location for the parsed boolean value * @success: (out caller-allocates): the return location for a value which is %TRUE if the boolean was parsed successfully, %FALSE if an error was encountered, * and undefined if @member_name was not found in the current object in @reader * @error: (allow-none): a #GError, or %NULL * * Gets the boolean value of the @member_name member of the current object in the #JsonReader, subject to various checks specified by @options. * * If no member matching @member_name can be found in the current @reader JSON object, %FALSE will be returned, @error will be unset and @success will be unset. @output will be undefined. * * If @member_name is found but one of the checks specified by @options fails, %TRUE will be returned, @error will be set to a * %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error and @success will be set to %FALSE. @output will be undefined. * * If @member_name is found and all of the checks specified by @options pass, %TRUE will be returned, @error will be unset and * @success will be set to %TRUE. @output will be set to the parsed value. * * The reason for returning the success of the parsing in @success is so that calls to gdata_parser_boolean_from_json_node() can be chained * together in a large "or" statement based on their return values, for the purposes of determining whether any of the calls matched * a given JSON node. If any of the calls to gdata_parser_boolean_from_json_node() return %TRUE, the value of @success can be examined. * * Return value: %TRUE if @member_name was found, %FALSE otherwise * * Since: 0.15.0 */ gboolean gdata_parser_boolean_from_json_member (JsonReader *reader, const gchar *member_name, GDataParserOptions options, gboolean *output, gboolean *success, GError **error) { gboolean val; const GError *child_error = NULL; /* Check if there's such an element. */ if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) { return FALSE; } /* Get the boolean. Check for parse errors. */ val = json_reader_get_boolean_value (reader); child_error = json_reader_get_error (reader); if (child_error != NULL) { *success = parser_error_from_json_error (reader, child_error, error); return TRUE; } /* Success! */ *output = val; *success = TRUE; return TRUE; }
/* * gdata_parser_string_from_json_member: * @reader: #JsonReader cursor object to read JSON node from * @member_name: the name of the member to parse * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE * @output: the return location for the parsed string content * @success: the return location for a value which is %TRUE if the string was parsed successfully, %FALSE if an error was encountered, * and undefined if @element didn't match @element_name * @error: a #GError, or %NULL * * Gets the string content of @element if its name is @element_name, subject to various checks specified by @options. * * If @element doesn't match @element_name, %FALSE will be returned, @error will be unset and @success will be unset. * * If @element matches @element_name but one of the checks specified by @options fails, %TRUE will be returned, @error will be set to a * %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error and @success will be set to %FALSE. * * If @element matches @element_name and all of the checks specified by @options pass, %TRUE will be returned, @error will be unset and * @success will be set to %TRUE. * * The reason for returning the success of the parsing in @success is so that calls to gdata_parser_string_from_element() can be chained * together in a large "or" statement based on their return values, for the purposes of determining whether any of the calls matched * a given @element. If any of the calls to gdata_parser_string_from_element() return %TRUE, the value of @success can be examined. * * Return value: %TRUE if @element matched @element_name, %FALSE otherwise * * Since: 0.15.0 */ gboolean gdata_parser_string_from_json_member (JsonReader *reader, const gchar *member_name, GDataParserOptions options, gchar **output, gboolean *success, GError **error) { const gchar *text; const GError *child_error = NULL; /* Check if there's such element */ if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) { return FALSE; } /* Check if the output string has already been set. The JSON parser guarantees this can't happen. */ g_assert (!(options & P_NO_DUPES) || *output == NULL); /* Get the string and check it for NULLness or emptiness. Check for parser errors first. */ text = json_reader_get_string_value (reader); child_error = json_reader_get_error (reader); if (child_error != NULL) { *success = parser_error_from_json_error (reader, child_error, error); return TRUE; } else if ((options & P_REQUIRED && text == NULL) || (options & P_NON_EMPTY && text != NULL && *text == '\0')) { *success = gdata_parser_error_required_json_content_missing (reader, error); return TRUE; } else if (options & P_DEFAULT && (text == NULL || *text == '\0')) { text = ""; } /* Success! */ g_free (*output); *output = g_strdup (text); *success = TRUE; return TRUE; }
static gboolean reader_fill_simple_gvalue (JsonReader *reader, TopicValueType type, GValue *value) { gboolean retval = TRUE; gint64 datetime; json_reader_read_member (reader, "value"); if (json_reader_get_error (reader) != NULL) { json_reader_end_member (reader); return FALSE; } switch (type) { case TYPE_BOOL: case TYPE_INT: case TYPE_DOUBLE: case TYPE_STRING: json_node_get_value (json_reader_get_value (reader), value); break; case TYPE_DATETIME: if (gdata_parser_int64_from_iso8601 (json_reader_get_string_value (reader), &datetime) || gdata_parser_int64_from_date (json_reader_get_string_value (reader), &datetime)) { g_value_init (value, G_TYPE_INT64); g_value_set_int64 (value, datetime); } else { retval = FALSE; } break; case TYPE_NONE: case TYPE_COMPOUND: case TYPE_OBJECT: case TYPE_KEY: case TYPE_URI: default: retval = FALSE; } json_reader_end_member (reader); return retval; }
static GDataFreebaseTopicObject * reader_create_object (JsonReader *reader, TopicValueType type) { GDataFreebaseTopicObject *object; if (type != TYPE_OBJECT && type != TYPE_COMPOUND) return NULL; json_reader_read_member (reader, "id"); if (json_reader_get_error (reader) != NULL) { json_reader_end_member (reader); return NULL; } object = object_new (json_reader_get_string_value (reader)); json_reader_end_member (reader); return object; }
static guint reader_get_value_type (JsonReader *reader, const gchar *property, GError **error) { TopicValueType type = TYPE_NONE; const GError *reader_error; const gchar *valuestr; json_reader_read_member (reader, "valuetype"); valuestr = json_reader_get_string_value (reader); reader_error = json_reader_get_error (reader); if (reader_error != NULL) { if (error != NULL && *error == NULL) *error = g_error_copy (reader_error); } else { if (strcmp (valuestr, "key") == 0) type = TYPE_KEY; else if (strcmp (valuestr, "uri") == 0) type = TYPE_URI; else if (strcmp (valuestr, "compound") == 0) type = TYPE_COMPOUND; else if (strcmp (valuestr, "object") == 0) type = TYPE_OBJECT; else if (strcmp (valuestr, "float") == 0) type = TYPE_DOUBLE; else if (strcmp (valuestr, "string") == 0) type = TYPE_STRING; else if (strcmp (valuestr, "int") == 0) type = TYPE_INT; else if (strcmp (valuestr, "bool") == 0) type = TYPE_BOOL; else if (strcmp (valuestr, "datetime") == 0) type = TYPE_DATETIME; else gdata_parser_error_required_json_content_missing (reader, error); } json_reader_end_member (reader); return type; }
/* * gdata_parser_int64_time_from_json_member: * @reader: #JsonReader cursor object to read JSON node from * @element_name: the name of the element to parse * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE * @output: (out caller-allocates): the return location for the parsed time value * @success: the return location for a value which is %TRUE if the time val was parsed successfully, %FALSE if an error was encountered, * and undefined if @element didn't match @element_name * @error: a #GError, or %NULL * * Gets the time value of @element if its name is @element_name, subject to various checks specified by @options. It expects the text content * of @element to be a date or time value in ISO 8601 format. The returned time value will be a UNIX timestamp (seconds since the epoch). * * If @element doesn't match @element_name, %FALSE will be returned, @error will be unset and @success will be unset. * * If @element matches @element_name but one of the checks specified by @options fails, %TRUE will be returned, @error will be set to a * %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error and @success will be set to %FALSE. * * If @element matches @element_name and all of the checks specified by @options pass, %TRUE will be returned, @error will be unset and * @success will be set to %TRUE. * * The reason for returning the success of the parsing in @success is so that calls to gdata_parser_int64_time_from_element() can be chained * together in a large "or" statement based on their return values, for the purposes of determining whether any of the calls matched * a given @element. If any of the calls to gdata_parser_int64_time_from_element() return %TRUE, the value of @success can be examined. * * Return value: %TRUE if @element matched @element_name, %FALSE otherwise * * Since: 0.15.0 */ gboolean gdata_parser_int64_time_from_json_member (JsonReader *reader, const gchar *member_name, GDataParserOptions options, gint64 *output, gboolean *success, GError **error) { const gchar *text; GTimeVal time_val; const GError *child_error = NULL; /* Check if there's such element */ if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) { return FALSE; } /* Check if the output time val has already been set. The JSON parser guarantees this can't happen. */ g_assert (!(options & P_NO_DUPES) || *output == -1); /* Get the string and check it for NULLness. Check for errors first. */ text = json_reader_get_string_value (reader); child_error = json_reader_get_error (reader); if (child_error != NULL) { *success = parser_error_from_json_error (reader, child_error, error); return TRUE; } else if (options & P_REQUIRED && (text == NULL || *text == '\0')) { *success = gdata_parser_error_required_json_content_missing (reader, error); return TRUE; } /* Attempt to parse the string as a GTimeVal */ if (g_time_val_from_iso8601 ((gchar*) text, &time_val) == FALSE) { *success = gdata_parser_error_not_iso8601_format_json (reader, text, error); return TRUE; } /* Success! */ *output = time_val.tv_sec; *success = TRUE; return TRUE; }
/* Save key/values on the table in the stack if the value is an * object or an array, it calls recursively the function again. * * @param L, pointer to the L with nil on top of it; * @param reader, pointed to the first element of main object; * * returns: the table in the stack with all json values */ static void build_table_from_json_reader (lua_State *L, JsonReader *reader) { const GError *err = json_reader_get_error (reader); if (err != NULL) { GRL_WARNING ("Error when building json: %s", err->message); return; } if (lua_isnil (L, -1)) { /* In the first execution of this recursive call, the main json object * does not have a member name. The nil is in the top of the stack and * it shall be converted to the table with json content */ lua_pop (L, 1); } else if (lua_istable (L, -1)) { const gchar *member_name = json_reader_get_member_name (reader); if (member_name) lua_pushstring (L, member_name); } else if (!lua_isnumber (L, -1)) { GRL_DEBUG ("getting value to either table or array"); return; } if (json_reader_is_object (reader)) { guint index_member = 0; guint num_members = json_reader_count_members (reader); lua_createtable (L, num_members, 0); for (index_member = 0; index_member < num_members; index_member++) { json_reader_read_element (reader, index_member); build_table_from_json_reader (L, reader); json_reader_end_element (reader); } } else if (json_reader_is_array (reader)) { guint index_element = 0; guint num_elements = json_reader_count_elements (reader); lua_createtable (L, num_elements, 0); for (index_element = 0; index_element < num_elements; index_element++) { json_reader_read_element (reader, index_element); lua_pushinteger (L, index_element + 1); build_table_from_json_reader (L, reader); json_reader_end_element (reader); } } else if (json_reader_is_value (reader)) { if (json_reader_get_null_value (reader)) { lua_pushnil (L); } else { /* value of the element */ JsonNode *value = json_reader_get_value (reader); switch (json_node_get_value_type (value)) { case G_TYPE_STRING: lua_pushstring (L, json_reader_get_string_value (reader)); break; case G_TYPE_INT64: lua_pushinteger (L, json_reader_get_int_value (reader)); break; case G_TYPE_DOUBLE: lua_pushnumber (L, json_reader_get_double_value (reader)); break; case G_TYPE_BOOLEAN: lua_pushnumber (L, json_reader_get_boolean_value (reader)); break; default: GRL_DEBUG ("'%d' (json-node-type) is not being handled", (gint) json_node_get_value_type (value)); lua_pushnil (L); } } } if (lua_gettop (L) > 3) { /* save this key/value on previous table */ lua_settable (L, -3); } }
static void restore_state(session_callback_type type, gpointer data, gpointer user_data) { JsonParser* jp = NULL; JsonReader* jr = NULL; const gchar* sqs; saved_state* s = NULL; GError* err = NULL; /* Is it the callback we're interested in? */ if (type != SPOP_SESSION_LOGGED_IN) return; /* First disable the callback so it's not called again */ session_remove_callback(restore_state, NULL); g_debug("savestate: reading saved state..."); s = g_new0(saved_state, 1); /* Read and parse state file */ jp = json_parser_new(); if (!json_parser_load_from_file(jp, g_state_file_path, &err)) { g_warning("savestate: error while reading state file: %s", err->message); goto restorestate_error; } jr = json_reader_new(json_parser_get_root(jp)); /* Read basic state */ if (!json_reader_read_member(jr, "status")) goto restorestate_jr_error; sqs = json_reader_get_string_value(jr); json_reader_end_member(jr); if (strcmp(sqs, "stopped")) s->qs = STOPPED; else if (strcmp(sqs, "playing")) s->qs = PLAYING; else if (strcmp(sqs, "paused")) s->qs = PAUSED; else { g_warning("savestate: bad value for queue status: %s", sqs); goto restorestate_error; } if (!json_reader_read_member(jr, "repeat")) goto restorestate_jr_error; s->repeat = json_reader_get_boolean_value(jr); json_reader_end_member(jr); if (!json_reader_read_member(jr, "shuffle")) goto restorestate_jr_error; s->shuffle = json_reader_get_boolean_value(jr); json_reader_end_member(jr); if (!json_reader_read_member(jr, "current_track")) goto restorestate_jr_error; s->cur_track = json_reader_get_int_value(jr); json_reader_end_member(jr); /* Now read tracks URIs */ if (!json_reader_read_member(jr, "tracks")) goto restorestate_jr_error; if (!json_reader_is_array(jr)) { g_warning("savestate: error while parsing JSON: tracks is not an array"); goto restorestate_error; } gint tracks = json_reader_count_elements(jr); if (s->cur_track >= tracks) { g_warning("savestate: incoherent state file: cur_track >= tracks"); goto restorestate_error; } s->tracks = g_array_sized_new(FALSE, FALSE, sizeof(sp_track*), tracks); if (!s->tracks) g_error("Can't allocate array of %d tracks.", tracks); size_t i; gboolean can_restore_now = TRUE; for (i=0; i < tracks; i++) { json_reader_read_element(jr, i); const gchar* uri = json_reader_get_string_value(jr); json_reader_end_element(jr); sp_link* lnk = sp_link_create_from_string(uri); sp_linktype lt = sp_link_type(lnk); if (lt != SP_LINKTYPE_TRACK) { g_warning("savestate: invalid link type for track %zu: %d", i, lt); sp_link_release(lnk); goto restorestate_error; } sp_track* tr = sp_link_as_track(lnk); sp_track_add_ref(tr); sp_link_release(lnk); g_array_append_val(s->tracks, tr); if (!sp_track_is_loaded(tr)) can_restore_now = FALSE; } /* If possible, restore now, else wait for all tracks to be loaded */ if (can_restore_now) really_restore_state(s); else { g_timeout_add(100, (GSourceFunc) really_restore_state, s); g_debug("savestate: waiting for all tracks to be loaded before restoring saved state..."); } /* Add a notification callback */ if (!interface_notify_add_callback(savestate_notification_callback, NULL)) g_error("Could not add savestate callback."); goto restorestate_clean; restorestate_jr_error: err = (GError*) json_reader_get_error(jr); g_warning("savestate: error while parsing JSON: %s", err->message); restorestate_error: if (s) { if (s->tracks) g_array_free(s->tracks, TRUE); g_free(s); } restorestate_clean: if (jp) g_object_unref(jp); if (jr) g_object_unref(jr); }