From c2610d1c15cbccd72529e25482045e7545e3b576 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Sun, 8 Jan 2017 22:59:23 +0000 Subject: core: Clarify handling of empty strings in some core APIs --- gdata/atom/gdata-author.c | 14 ++++++++------ gdata/atom/gdata-category.c | 24 +++++++++++++++++------- gdata/atom/gdata-generator.c | 21 ++++++++++++++------- gdata/atom/gdata-link.c | 39 ++++++++++++++++++++++----------------- gdata/gdata-access-rule.c | 7 +++++-- gdata/gdata-entry.c | 22 ++++++++++++++++------ gdata/gdata-feed.c | 5 +++-- 7 files changed, 85 insertions(+), 47 deletions(-) diff --git a/gdata/atom/gdata-author.c b/gdata/atom/gdata-author.c index f9de806d..bb5565a4 100644 --- a/gdata/atom/gdata-author.c +++ b/gdata/atom/gdata-author.c @@ -252,6 +252,8 @@ get_xml (GDataParsable *parsable, GString *xml_string) * Creates a new #GDataAuthor. More information is available in the Atom specification. * + * @name must be non-%NULL and non-empty. + * * Return value: a new #GDataAuthor, or %NULL; unref with g_object_unref() **/ GDataAuthor * @@ -265,7 +267,7 @@ gdata_author_new (const gchar *name, const gchar *uri, const gchar *email_addres * gdata_author_get_name: * @self: a #GDataAuthor * - * Gets the #GDataAuthor:name property. + * Gets the #GDataAuthor:name property. The name will always be a non-%NULL, non-empty string. * * Return value: the author's name * @@ -283,7 +285,7 @@ gdata_author_get_name (GDataAuthor *self) * @self: a #GDataAuthor * @name: the new name for the author * - * Sets the #GDataAuthor:name property to @name. + * Sets the #GDataAuthor:name property to @name. @name must be non-%NULL and non-empty. * * Since: 0.4.0 **/ @@ -302,7 +304,7 @@ gdata_author_set_name (GDataAuthor *self, const gchar *name) * gdata_author_get_uri: * @self: a #GDataAuthor * - * Gets the #GDataAuthor:uri property. + * Gets the #GDataAuthor:uri property. If the URI is non-%NULL, it will be non-empty. * * Return value: the author's URI, or %NULL * @@ -320,7 +322,7 @@ gdata_author_get_uri (GDataAuthor *self) * @self: a #GDataAuthor * @uri: (allow-none): the new URI for the author, or %NULL * - * Sets the #GDataAuthor:uri property to @uri. + * Sets the #GDataAuthor:uri property to @uri. @uri must be %NULL or non-empty. * * Set @uri to %NULL to unset the property in the author. * @@ -340,7 +342,7 @@ gdata_author_set_uri (GDataAuthor *self, const gchar *uri) * gdata_author_get_email_address: * @self: a #GDataAuthor * - * Gets the #GDataAuthor:email-address property. + * Gets the #GDataAuthor:email-address property. If the e-mail address is non-%NULL, it will be non-empty. * * Return value: the author's e-mail address, or %NULL * @@ -358,7 +360,7 @@ gdata_author_get_email_address (GDataAuthor *self) * @self: a #GDataAuthor * @email_address: (allow-none): the new e-mail address for the author, or %NULL * - * Sets the #GDataAuthor:email-address property to @email_address. + * Sets the #GDataAuthor:email-address property to @email_address. @email_address must be %NULL or non-empty. * * Set @email_address to %NULL to unset the property in the author. * diff --git a/gdata/atom/gdata-category.c b/gdata/atom/gdata-category.c index b9da4ab9..1d2109df 100644 --- a/gdata/atom/gdata-category.c +++ b/gdata/atom/gdata-category.c @@ -205,7 +205,7 @@ gdata_category_set_property (GObject *object, guint property_id, const GValue *v static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error) { - xmlChar *term; + xmlChar *term, *scheme; GDataCategory *self = GDATA_CATEGORY (parsable); term = xmlGetProp (root_node, (xmlChar*) "term"); @@ -213,9 +213,16 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe xmlFree (term); return gdata_parser_error_required_property_missing (root_node, "term", error); } - self->priv->term = (gchar*) term; - self->priv->scheme = (gchar*) xmlGetProp (root_node, (xmlChar*) "scheme"); + scheme = xmlGetProp (root_node, (xmlChar*) "scheme"); + if (scheme != NULL && *scheme == '\0') { + xmlFree (term); + xmlFree (scheme); + return gdata_parser_error_required_property_missing (root_node, "scheme", error); + } + + self->priv->term = (gchar*) term; + self->priv->scheme = (gchar*) scheme; self->priv->label = (gchar*) xmlGetProp (root_node, (xmlChar*) "label"); return TRUE; @@ -244,12 +251,15 @@ pre_get_xml (GDataParsable *parsable, GString *xml_string) * Creates a new #GDataCategory. More information is available in the Atom specification. * + * @term must be non-%NULL and non-empty. @scheme must be %NULL or non-empty. + * * Return value: a new #GDataCategory, or %NULL; unref with g_object_unref() **/ GDataCategory * gdata_category_new (const gchar *term, const gchar *scheme, const gchar *label) { g_return_val_if_fail (term != NULL && *term != '\0', NULL); + g_return_val_if_fail (scheme == NULL || *scheme != '\0', NULL); return g_object_new (GDATA_TYPE_CATEGORY, "term", term, "scheme", scheme, "label", label, NULL); } @@ -257,7 +267,7 @@ gdata_category_new (const gchar *term, const gchar *scheme, const gchar *label) * gdata_category_get_term: * @self: a #GDataCategory * - * Gets the #GDataCategory:term property. + * Gets the #GDataCategory:term property. The term will always be a non-%NULL, non-empty string. * * Return value: the category's term * @@ -275,7 +285,7 @@ gdata_category_get_term (GDataCategory *self) * @self: a #GDataCategory * @term: the new term for the category * - * Sets the #GDataCategory:term property to @term. + * Sets the #GDataCategory:term property to @term. @term must be non-%NULL and non-empty. * * Since: 0.4.0 **/ @@ -294,7 +304,7 @@ gdata_category_set_term (GDataCategory *self, const gchar *term) * gdata_category_get_scheme: * @self: a #GDataCategory * - * Gets the #GDataCategory:scheme property. + * Gets the #GDataCategory:scheme property. If the scheme is non-%NULL, it will be non-empty. * * Return value: the category's scheme, or %NULL * @@ -312,7 +322,7 @@ gdata_category_get_scheme (GDataCategory *self) * @self: a #GDataCategory * @scheme: (allow-none): the new scheme for the category, or %NULL * - * Sets the #GDataCategory:scheme property to @scheme. + * Sets the #GDataCategory:scheme property to @scheme. @scheme must be %NULL or non-empty. * * Set @scheme to %NULL to unset the property in the category. * diff --git a/gdata/atom/gdata-generator.c b/gdata/atom/gdata-generator.c index bba75552..8bf54f84 100644 --- a/gdata/atom/gdata-generator.c +++ b/gdata/atom/gdata-generator.c @@ -179,7 +179,7 @@ gdata_generator_get_property (GObject *object, guint property_id, GValue *value, static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error) { - xmlChar *uri; + xmlChar *uri, *name; GDataGeneratorPrivate *priv = GDATA_GENERATOR (parsable)->priv; uri = xmlGetProp (root_node, (xmlChar*) "uri"); @@ -187,9 +187,16 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe xmlFree (uri); return gdata_parser_error_required_property_missing (root_node, "uri", error); } - priv->uri = (gchar*) uri; - priv->name = (gchar*) xmlNodeListGetString (doc, root_node->children, TRUE); + name = xmlNodeListGetString (doc, root_node->children, TRUE); + if (name != NULL && *name == '\0') { + xmlFree (uri); + xmlFree (name); + return gdata_parser_error_required_content_missing (root_node, error); + } + + priv->uri = (gchar*) uri; + priv->name = (gchar*) name; priv->version = (gchar*) xmlGetProp (root_node, (xmlChar*) "version"); return TRUE; @@ -209,9 +216,9 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da * gdata_generator_get_name: * @self: a #GDataGenerator * - * Gets the #GDataGenerator:name property. + * Gets the #GDataGenerator:name property. The name will be %NULL or non-empty. * - * Return value: the generator's name + * Return value: (nullable): the generator's name * * Since: 0.4.0 **/ @@ -226,9 +233,9 @@ gdata_generator_get_name (GDataGenerator *self) * gdata_generator_get_uri: * @self: a #GDataGenerator * - * Gets the #GDataGenerator:uri property. + * Gets the #GDataGenerator:uri property. The URI will be %NULL or non-empty. * - * Return value: the generator's URI, or %NULL + * Return value: (nullable): the generator's URI, or %NULL * * Since: 0.4.0 **/ diff --git a/gdata/atom/gdata-link.c b/gdata/atom/gdata-link.c index 8d2a9730..30cb22de 100644 --- a/gdata/atom/gdata-link.c +++ b/gdata/atom/gdata-link.c @@ -293,38 +293,41 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe xmlFree (uri); return gdata_parser_error_required_property_missing (root_node, "href", error); } - self->priv->uri = (gchar*) uri; /* rel */ relation_type = xmlGetProp (root_node, (xmlChar*) "rel"); if (relation_type != NULL && *relation_type == '\0') { + xmlFree (uri); xmlFree (relation_type); return gdata_parser_error_required_property_missing (root_node, "rel", error); } - gdata_link_set_relation_type (self, (const gchar*) relation_type); - xmlFree (relation_type); - /* type */ content_type = xmlGetProp (root_node, (xmlChar*) "type"); if (content_type != NULL && *content_type == '\0') { + xmlFree (uri); + xmlFree (relation_type); xmlFree (content_type); return gdata_parser_error_required_property_missing (root_node, "type", error); } - self->priv->content_type = (gchar*) content_type; /* hreflang */ language = xmlGetProp (root_node, (xmlChar*) "hreflang"); if (language != NULL && *language == '\0') { + xmlFree (uri); + xmlFree (relation_type); + xmlFree (content_type); xmlFree (language); return gdata_parser_error_required_property_missing (root_node, "hreflang", error); } - self->priv->language = (gchar*) language; - /* title */ + self->priv->uri = (gchar*) uri; + gdata_link_set_relation_type (self, (const gchar*) relation_type); + xmlFree (relation_type); + self->priv->content_type = (gchar*) content_type; + self->priv->language = (gchar*) language; self->priv->title = (gchar*) xmlGetProp (root_node, (xmlChar*) "title"); - /* length */ length = xmlGetProp (root_node, (xmlChar*) "length"); if (length == NULL) self->priv->length = -1; @@ -362,6 +365,8 @@ pre_get_xml (GDataParsable *parsable, GString *xml_string) * Creates a new #GDataLink. More information is available in the Atom specification. * + * @uri must be non-%NULL and non-empty. @relation_type must be %NULL or non-empty. + * * Return value: a new #GDataLink, or %NULL; unref with g_object_unref() **/ GDataLink * @@ -400,7 +405,7 @@ gdata_link_get_uri (GDataLink *self) * @self: a #GDataLink * @uri: the new URI for the link * - * Sets the #GDataLink:uri property to @uri. + * Sets the #GDataLink:uri property to @uri. @uri must be non-%NULL and non-empty. * * Since: 0.4.0 **/ @@ -419,9 +424,9 @@ gdata_link_set_uri (GDataLink *self, const gchar *uri) * gdata_link_get_relation_type: * @self: a #GDataLink * - * Gets the #GDataLink:relation-type property. + * Gets the #GDataLink:relation-type property. If the relation type is non-%NULL, it will be non-empty. * - * Return value: the link's relation type + * Return value: (nullable): the link's relation type * * Since: 0.4.0 **/ @@ -469,9 +474,9 @@ gdata_link_set_relation_type (GDataLink *self, const gchar *relation_type) * gdata_link_get_content_type: * @self: a #GDataLink * - * Gets the #GDataLink:content-type property. + * Gets the #GDataLink:content-type property. If the content type is non-%NULL, it will be non-empty. * - * Return value: the link's content type, or %NULL + * Return value: (nullable): the link's content type, or %NULL * * Since: 0.4.0 **/ @@ -487,7 +492,7 @@ gdata_link_get_content_type (GDataLink *self) * @self: a #GDataLink * @content_type: (allow-none): the new content type for the link, or %NULL * - * Sets the #GDataLink:content-type property to @content_type. + * Sets the #GDataLink:content-type property to @content_type. @content_type must be %NULL or non-empty. * * Set @content_type to %NULL to unset the property in the link. * @@ -508,9 +513,9 @@ gdata_link_set_content_type (GDataLink *self, const gchar *content_type) * gdata_link_get_language: * @self: a #GDataLink * - * Gets the #GDataLink:language property. + * Gets the #GDataLink:language property. If the language is non-%NULL, it will be non-empty. * - * Return value: the link's language, or %NULL + * Return value: (nullable): the link's language, or %NULL * * Since: 0.4.0 **/ @@ -526,7 +531,7 @@ gdata_link_get_language (GDataLink *self) * @self: a #GDataLink * @language: (allow-none): the new language for the link, or %NULL * - * Sets the #GDataLink:language property to @language. + * Sets the #GDataLink:language property to @language. @language must be %NULL or non-empty. * * Set @language to %NULL to unset the property in the link. * diff --git a/gdata/gdata-access-rule.c b/gdata/gdata-access-rule.c index cc20d255..9b2c1f76 100644 --- a/gdata/gdata-access-rule.c +++ b/gdata/gdata-access-rule.c @@ -362,8 +362,10 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da if (xmlStrcmp (node->name, (xmlChar*) "role") == 0) { /* gAcl:role */ xmlChar *role = xmlGetProp (node, (xmlChar*) "value"); - if (role == NULL) + if (role == NULL || *role == '\0') { + xmlFree (role); return gdata_parser_error_required_property_missing (node, "value", error); + } self->priv->role = (gchar*) role; } else if (xmlStrcmp (node->name, (xmlChar*) "scope") == 0) { /* gAcl:scope */ @@ -501,7 +503,7 @@ gdata_access_rule_new (const gchar *id) * @self: a #GDataAccessRule * @role: a new role, or %NULL * - * Sets the #GDataAccessRule:role property to @role. + * Sets the #GDataAccessRule:role property to @role. @role must be a non-empty string, such as %GDATA_ACCESS_ROLE_NONE. * * Set @role to %NULL to unset the property in the access rule. * @@ -511,6 +513,7 @@ void gdata_access_rule_set_role (GDataAccessRule *self, const gchar *role) { g_return_if_fail (GDATA_IS_ACCESS_RULE (self)); + g_return_if_fail (role == NULL || *role != '\0'); g_free (self->priv->role); self->priv->role = g_strdup (role); diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c index 63ff162a..b81e7cf1 100644 --- a/gdata/gdata-entry.c +++ b/gdata/gdata-entry.c @@ -153,7 +153,8 @@ gdata_entry_class_init (GDataEntryClass *klass) /** * GDataEntry:id: * - * A permanent, universally unique identifier for the entry, in IRI form. + * A permanent, universally unique identifier for the entry, in IRI form. This is %NULL for new entries (i.e. ones which haven't yet been + * inserted on the server, created with gdata_entry_new()), and a non-empty IRI string for all other entries. * * For more information, see the * Atom specification. @@ -433,7 +434,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da GDataEntryPrivate *priv = GDATA_ENTRY (parsable)->priv; if (gdata_parser_is_namespace (node, "http://www.w3.org/2005/Atom") == TRUE) { - if (gdata_parser_string_from_element (node, "title", P_DEFAULT, &(priv->title), &success, error) == TRUE || + if (gdata_parser_string_from_element (node, "title", P_DEFAULT | P_NO_DUPES, &(priv->title), &success, error) == TRUE || gdata_parser_string_from_element (node, "id", P_REQUIRED | P_NON_EMPTY | P_NO_DUPES, &(priv->id), &success, error) == TRUE || gdata_parser_string_from_element (node, "summary", P_NONE, &(priv->summary), &success, error) == TRUE || gdata_parser_string_from_element (node, "rights", P_NONE, &(priv->rights), &success, error) == TRUE || @@ -699,14 +700,19 @@ get_json (GDataParsable *parsable, JsonBuilder *builder) GDataEntry * gdata_entry_new (const gchar *id) { - return g_object_new (GDATA_TYPE_ENTRY, "id", id, NULL); + GDataEntry *entry = GDATA_ENTRY (g_object_new (GDATA_TYPE_ENTRY, "id", id, NULL)); + + /* Set this here, as it interferes with P_NO_DUPES when parsing */ + entry->priv->title = g_strdup (""); /* title can't be NULL */ + + return entry; } /** * gdata_entry_get_title: * @self: a #GDataEntry * - * Returns the title of the entry. + * Returns the title of the entry. This will never be %NULL, but may be an empty string. * * Return value: the entry's title **/ @@ -776,7 +782,9 @@ gdata_entry_set_summary (GDataEntry *self, const gchar *summary) * * Returns the URN ID of the entry; a unique and permanent identifier for the object the entry represents. * - * Return value: the entry's ID + * The ID may be %NULL if and only if the #GDataEntry has been newly created, and hasn't yet been inserted on the server. + * + * Return value: (nullable): the entry's ID, or %NULL **/ const gchar * gdata_entry_get_id (GDataEntry *self) @@ -802,7 +810,9 @@ gdata_entry_get_id (GDataEntry *self) * Returns the ETag of the entry; a unique identifier for each version of the entry. For more information, see the * online documentation. * - * Return value: the entry's ETag + * The ETag will never be empty; it's either %NULL or a valid ETag. + * + * Return value: (nullable): the entry's ETag, or %NULL * * Since: 0.2.0 **/ diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c index cfcbe39e..66ec8a9a 100644 --- a/gdata/gdata-feed.c +++ b/gdata/gdata-feed.c @@ -456,9 +456,10 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da _gdata_feed_call_progress_callback (self, data, entry); _gdata_feed_add_entry (self, entry); g_object_unref (entry); - } else if (gdata_parser_string_from_element (node, "title", P_NO_DUPES, &(self->priv->title), &success, error) == TRUE || + } else if (gdata_parser_string_from_element (node, "title", P_DEFAULT | P_NO_DUPES, &(self->priv->title), &success, error) == TRUE || gdata_parser_string_from_element (node, "subtitle", P_NO_DUPES, &(self->priv->subtitle), &success, error) == TRUE || - gdata_parser_string_from_element (node, "id", P_NO_DUPES, &(self->priv->id), &success, error) == TRUE || + gdata_parser_string_from_element (node, "id", P_REQUIRED | P_NON_EMPTY | P_NO_DUPES, + &(self->priv->id), &success, error) == TRUE || gdata_parser_string_from_element (node, "logo", P_NO_DUPES, &(self->priv->logo), &success, error) == TRUE || gdata_parser_string_from_element (node, "icon", P_NO_DUPES, &(self->priv->icon), &success, error) == TRUE || gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_CATEGORY, -- cgit v1.2.1