static gboolean
parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
{
	gboolean success;

	if (g_strcmp0 (json_reader_get_member_name (reader), "role") == 0) {
		gchar *role = NULL;  /* owned */

		g_assert (gdata_parser_string_from_json_member (reader, "role",
		                                                P_REQUIRED |
		                                                P_NON_EMPTY,
		                                                &role, &success,
		                                                error));

		if (!success) {
			return FALSE;
		}

		gdata_access_rule_set_role (GDATA_ACCESS_RULE (parsable),
		                            role_v3_to_v2 (role));
		g_free (role);

		return TRUE;
	} else if (g_strcmp0 (json_reader_get_member_name (reader),
	                                                   "scope") == 0) {
		const gchar *scope_type;
		const gchar *scope_value;

		/* Check this is an object. */
		if (!json_reader_is_object (reader)) {
			return gdata_parser_error_required_json_content_missing (reader,
			                                                         error);
		}

		json_reader_read_member (reader, "type");
		scope_type = json_reader_get_string_value (reader);
		json_reader_end_member (reader);

		json_reader_read_member (reader, "value");
		scope_value = json_reader_get_string_value (reader);
		json_reader_end_member (reader);

		/* Scope type is required. */
		if (scope_type == NULL) {
			return gdata_parser_error_required_json_content_missing (reader,
			                                                         error);
		}

		gdata_access_rule_set_scope (GDATA_ACCESS_RULE (parsable),
		                             scope_type_v3_to_v2 (scope_type),
		                             scope_value);

		return TRUE;
	}

	return GDATA_PARSABLE_CLASS (gdata_calendar_access_rule_parent_class)->parse_json (parsable, reader, user_data, error);
}
static gboolean
parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
{
	GDataFreebaseTopicResultPrivate *priv = GDATA_FREEBASE_TOPIC_RESULT (parsable)->priv;
	const gchar *member_name;

	GDATA_PARSABLE_CLASS (gdata_freebase_topic_result_parent_class)->parse_json (parsable, reader, user_data, error);

	member_name = json_reader_get_member_name (reader);

	if (member_name == NULL)
		return FALSE;

	if (strcmp (member_name, "id") == 0) {
		/* We only expect one member containing information */
		g_assert (priv->object == NULL);
		priv->object = object_new (json_reader_get_string_value (reader));
	} else if (strcmp (member_name, "property") == 0) {
		reader_get_properties (reader, priv->object, error);
	} else {
		return FALSE;
	}

	return TRUE;
}
Exemple #3
0
/*
 * 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;
}
Exemple #4
0
/*
 * 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;
}
Exemple #5
0
gboolean
gdata_parser_error_duplicate_json_element (JsonReader *reader, GError **error)
{
	const gchar *element_string = json_reader_get_member_name (reader);

	/* Translators: the parameter is the name of an JSON element.
	 *
	 * For example:
	 *  A singleton element (title) was duplicated. */
	g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR, _("A singleton element (%s) was duplicated."), element_string);

	return FALSE;
}
Exemple #6
0
gboolean
gdata_parser_error_required_json_content_missing (JsonReader *reader, GError **error)
{
	const gchar *element_string = json_reader_get_member_name (reader);

	/* Translators: the parameter is the name of an JSON element.
	 *
	 * For example:
	 *  A 'title' element was missing required content. */
	g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR, _("A \'%s\' element was missing required content."), element_string);

	return FALSE;
}
Exemple #7
0
gboolean
gdata_parser_error_not_iso8601_format_json (JsonReader *reader, const gchar *actual_value, GError **error)
{
	const gchar *element_string = json_reader_get_member_name (reader);

	g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
	             /* Translators: the first parameter is the name of an JSON element,
	              * and the second parameter is the erroneous value (which was not in ISO 8601 format).
	              *
	              * For example:
	              *  The content of a 'uploaded' element ("2009-05-06 26:30Z") was not in ISO 8601 format. */
	             _("The content of a \'%s\' element (\"%s\") was not in ISO 8601 format."), element_string, actual_value);

	return FALSE;
}
static gboolean
reader_get_properties (JsonReader *reader, GDataFreebaseTopicObject *object, GError **error)
{
	GDataFreebaseTopicValueArray *array;
	gboolean retval = TRUE;
	gint count, i;

	count = json_reader_count_members (reader);

	for (i = 0; i < count; i++) {
		GError *inner_error = NULL;
		const gchar *name;
		gchar *property;

		json_reader_read_element (reader, i);
		property = g_strdup (json_reader_get_member_name (reader));
		name = property;

		/* Reverse properties start with !, display those as
		 * regular properties, and skip that char
		 */
		if (name[0] == '!')
			name++;

		/* All Freebase properties and IDs start with '/' */
		if (name[0] != '/')
			continue;

		/* Parse the value for this property, possibly with nested contents */
		array = reader_create_value_array (reader, name, &inner_error);
		json_reader_end_element (reader);

		if (inner_error != NULL) {
			g_propagate_error (error, inner_error);
			retval = FALSE;
			break;
		} else if (array != NULL) {
			/* Takes ownership of array */
			object_add_value (object, name, array);
		}

		g_free (property);
	}

	return retval;
}
Exemple #9
0
/*
 * 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 gboolean
parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
{
	gboolean success = TRUE;
	gchar *next_uri = NULL;

	/* JSON format: https://developers.google.com/drive/v2/reference/files/list */

	if (gdata_parser_string_from_json_member (reader, "nextLink", P_DEFAULT, &next_uri, &success, error) == TRUE) {
		if (success && next_uri != NULL && next_uri[0] != '\0') {
			GDataLink *_link;

			_link = gdata_link_new (next_uri, "http://www.iana.org/assignments/relation/next");
			_gdata_feed_add_link (GDATA_FEED (parsable), _link);
			g_object_unref (_link);
		}

		g_free (next_uri);
		return success;
	} else if (g_strcmp0 (json_reader_get_member_name (reader), "items") == 0) {
		guint i, elements;

		if (json_reader_is_array (reader) == FALSE) {
			g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
			             /* Translators: the parameter is an error message */
			             _("Error parsing JSON: %s"),
			             "JSON node ‘items’ is not an array.");
			return FALSE;
		}

		/* Loop through the elements array. */
		for (i = 0, elements = (guint) json_reader_count_elements (reader); success && i < elements; i++) {
			GDataEntry *entry = NULL;
			GError *child_error = NULL;
			GType entry_type = G_TYPE_INVALID;
			gchar *kind = NULL;
			gchar *mime_type = NULL;

			json_reader_read_element (reader, i);

			if (json_reader_is_object (reader) == FALSE) {
				g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
				             /* Translators: the parameter is an error message */
				             _("Error parsing JSON: %s"),
				             "JSON node inside ‘items’ is not an object");
				success = FALSE;
				goto continuation;
			}

			get_kind_and_mime_type (reader, &kind, &mime_type, &child_error);
			if (child_error != NULL) {
				g_propagate_error (error, child_error);
				success = FALSE;
				goto continuation;
			}

			if (g_strcmp0 (kind, "drive#file") == 0) {
				entry_type = gdata_documents_utils_get_type_from_content_type (mime_type);
			} else {
				g_warning ("%s files are not handled yet", kind);
			}

			if (entry_type == G_TYPE_INVALID)
				goto continuation;

			entry = GDATA_ENTRY (_gdata_parsable_new_from_json_node (entry_type, reader, NULL, error));
			/* Call the progress callback in the main thread */
			_gdata_feed_call_progress_callback (GDATA_FEED (parsable), user_data, entry);
			_gdata_feed_add_entry (GDATA_FEED (parsable), entry);

		continuation:
			g_clear_object (&entry);
			g_free (kind);
			g_free (mime_type);
			json_reader_end_element (reader);
		}

		return success;
	}

	return GDATA_PARSABLE_CLASS (gdata_documents_feed_parent_class)->parse_json (parsable, reader, user_data, error);
}