tag: xmp: Add support for reading struct tags
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Tue, 19 Apr 2011 14:00:24 +0000 (11:00 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Sun, 15 May 2011 16:02:39 +0000 (13:02 -0300)
Adds a context variable that controls if the parsing is on
'top level' tags or inside a struct tag.

gst-libs/gst/tag/gstxmptag.c

index 1a6e3c1..296804a 100644 (file)
@@ -170,7 +170,6 @@ xmp_tag_get_type_name (XmpTag * xmptag)
 
 struct _PendingXmpTag
 {
-  const gchar *gst_tag;
   XmpTag *xmp_tag;
   gchar *str;
 };
@@ -1045,11 +1044,14 @@ struct _GstXmpNamespaceMap
 /* parsing */
 
 static void
-read_one_tag (GstTagList * list, const gchar * tag, XmpTag * xmptag,
+read_one_tag (GstTagList * list, XmpTag * xmptag,
     const gchar * v, GSList ** pending_tags)
 {
   GType tag_type;
   GstTagMergeMode merge_mode;
+  const gchar *tag = xmptag->gst_tag;
+
+  g_return_if_fail (tag != NULL);
 
   if (xmptag && xmptag->deserialize) {
     xmptag->deserialize (xmptag, list, tag, xmptag->tag_name, v, pending_tags);
@@ -1236,10 +1238,12 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
   gboolean in_tag;
   gchar *part, *pp;
   guint i;
-  const gchar *last_tag = NULL;
   XmpTag *last_xmp_tag = NULL;
   GSList *pending_tags = NULL;
 
+  /* Used for strucuture xmp tags */
+  XmpTag *context_tag = NULL;
+
   GstXmpNamespaceMap ns_map[] = {
     {"dc", NULL},
     {"exif", NULL},
@@ -1255,6 +1259,8 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
   g_return_val_if_fail (GST_BUFFER_SIZE (buffer) > 0, NULL);
 
+  GST_LOG ("Starting xmp parsing");
+
   xps = (const gchar *) GST_BUFFER_DATA (buffer);
   len = GST_BUFFER_SIZE (buffer);
   xpe = &xps[len + 1];
@@ -1354,19 +1360,41 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
                   }
                 }
               } else {
-                const gchar *gst_tag;
                 XmpTag *xmp_tag = NULL;
                 /* FIXME: eventualy rewrite ns
                  * find ':'
                  * check if ns before ':' is in ns_map and ns_map[i].gstreamer_ns!=NULL
                  * do 2 stage filter in tag_matches
                  */
-                gst_tag = _gst_xmp_tag_get_mapping_reverse (as, &xmp_tag);
-                if (gst_tag) {
+                if (context_tag) {
+                  GSList *iter;
+
+                  for (iter = context_tag->children; iter;
+                      iter = g_slist_next (iter)) {
+                    XmpTag *child = iter->data;
+
+                    GST_DEBUG ("Looking at child tag %s : %s", child->tag_name,
+                        as);
+                    if (strcmp (child->tag_name, as) == 0) {
+                      xmp_tag = child;
+                      break;
+                    }
+                  }
+
+                } else {
+                  GST_LOG ("Looking for tag: %s", as);
+                  _gst_xmp_tag_get_mapping_reverse (as, &xmp_tag);
+                }
+                if (xmp_tag) {
                   PendingXmpTag *ptag;
 
+                  GST_DEBUG ("Found xmp tag: %s -> %s", xmp_tag->tag_name,
+                      xmp_tag->gst_tag);
+
+                  /* we shouldn't find a xmp structure here */
+                  g_assert (xmp_tag->gst_tag != NULL);
+
                   ptag = g_slice_new (PendingXmpTag);
-                  ptag->gst_tag = gst_tag;
                   ptag->xmp_tag = xmp_tag;
                   ptag->str = g_strdup (v);
 
@@ -1393,15 +1421,42 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
 
           /* skip rdf tags for now */
           if (strncmp (part, "rdf:", 4)) {
-            const gchar *parttag;
+            /* if we're inside some struct, we look only on its children */
+            if (context_tag) {
+              GSList *iter;
+
+              /* check if this is the closing of the context */
+              if (part[0] == '/'
+                  && strcmp (part + 1, context_tag->tag_name) == 0) {
+                GST_DEBUG ("Closing context tag %s", part);
+                context_tag = NULL;
+              } else {
+
+                for (iter = context_tag->children; iter;
+                    iter = g_slist_next (iter)) {
+                  XmpTag *child = iter->data;
 
-            parttag = _gst_xmp_tag_get_mapping_reverse (part, &last_xmp_tag);
-            if (parttag) {
-              last_tag = parttag;
+                  GST_DEBUG ("Looking at child tag %s : %s", child->tag_name,
+                      part);
+                  if (strcmp (child->tag_name, part) == 0) {
+                    last_xmp_tag = child;
+                    break;
+                  }
+                }
+              }
+
+            } else {
+              GST_LOG ("Looking for tag: %s", part);
+              _gst_xmp_tag_get_mapping_reverse (part, &last_xmp_tag);
+              if (last_xmp_tag && last_xmp_tag->type == GstXmpTagTypeStruct) {
+                context_tag = last_xmp_tag;
+                last_xmp_tag = NULL;
+              }
             }
           }
         }
       }
+      GST_LOG ("Next cycle");
       /* next cycle */
       ne++;
       if (ne < xp2) {
@@ -1421,15 +1476,23 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
       if (ns[0] != '\n' && &ns[1] <= ne) {
         /* only log non-newline nodes, we still have to parse them */
         GST_INFO ("txt: %s", part);
-        if (last_tag) {
+        if (last_xmp_tag) {
           PendingXmpTag *ptag;
 
-          ptag = g_slice_new (PendingXmpTag);
-          ptag->gst_tag = last_tag;
-          ptag->xmp_tag = last_xmp_tag;
-          ptag->str = g_strdup (part);
+          GST_DEBUG ("Found tag %s -> %s", last_xmp_tag->tag_name,
+              last_xmp_tag->gst_tag);
+
+          if (last_xmp_tag->type == GstXmpTagTypeStruct) {
+            g_assert (context_tag == NULL);     /* we can't handle struct nesting currently */
 
-          pending_tags = g_slist_append (pending_tags, ptag);
+            context_tag = last_xmp_tag;
+          } else {
+            ptag = g_slice_new (PendingXmpTag);
+            ptag->xmp_tag = last_xmp_tag;
+            ptag->str = g_strdup (part);
+
+            pending_tags = g_slist_append (pending_tags, ptag);
+          }
         }
       }
       /* next cycle */
@@ -1444,7 +1507,7 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
 
     pending_tags = g_slist_delete_link (pending_tags, pending_tags);
 
-    read_one_tag (list, ptag->gst_tag, ptag->xmp_tag, ptag->str, &pending_tags);
+    read_one_tag (list, ptag->xmp_tag, ptag->str, &pending_tags);
 
     g_free (ptag->str);
     g_slice_free (PendingXmpTag, ptag);