[libgdata] core: Clarify handling of empty strings in some core APIs



commit c2610d1c15cbccd72529e25482045e7545e3b576
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Jan 8 22:59:23 2017 +0000

    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 f9de806..bb5565a 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 <ulink type="http"
  * url="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.author";>Atom 
specification</ulink>.
  *
+ * @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 b9da4ab..1d2109d 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 <ulink type="http"
  * url="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.category";>Atom 
specification</ulink>.
  *
+ * @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 bba7555..8bf54f8 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 8d2a973..30cb22d 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 <ulink type="http"
  * url="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.link";>Atom 
specification</ulink>.
  *
+ * @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 cc20d25..9b2c1f7 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 63ff162..b81e7cf 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 <ulink type="http" 
url="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.id";>
         * Atom specification</ulink>.
@@ -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
  * <ulink type="http" 
url="http://code.google.com/apis/gdata/docs/2.0/reference.html#ResourceVersioning";>online 
documentation</ulink>.
  *
- * 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 cfcbe39..66ec8a9 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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]