- test for external iterator
[oweals/gnunet.git] / src / util / container_meta_data.c
index b122982d53f3c42e4a4b9bc910f57ef070555236..a868e817da61580925a6200074a81aca3ed3e31a 100644 (file)
 #include <extractor.h>
 #include <zlib.h>
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
 /**
  * Meta data item.
  */
 struct MetaItem
 {
   /**
-   * This is a linked list.
-   */ 
+   * This is a doubly linked list.
+   */
   struct MetaItem *next;
 
+  /**
+   * This is a doubly linked list.
+   */
+  struct MetaItem *prev;
+
   /**
    * Name of the extracting plugin.
    */
@@ -80,9 +87,14 @@ struct MetaItem
 struct GNUNET_CONTAINER_MetaData
 {
   /**
-   * Linked list of the meta data items.
+   * Head of linked list of the meta data items.
    */
-  struct MetaItem *items;
+  struct MetaItem *items_head;
+
+  /**
+   * Tail of linked list of the meta data items.
+   */
+  struct MetaItem *items_tail;
 
   /**
    * Complete serialized and compressed buffer of the items.
@@ -105,7 +117,7 @@ struct GNUNET_CONTAINER_MetaData
 
 /**
  * Create a fresh struct CONTAINER_MetaData token.
- * 
+ *
  * @return empty meta-data container
  */
 struct GNUNET_CONTAINER_MetaData *
@@ -118,15 +130,15 @@ GNUNET_CONTAINER_meta_data_create ()
 /**
  * Free meta data item.
  *
- * @param item item to free
+ * @param mi item to free
  */
 static void
-meta_item_free (struct MetaItem *item)
+meta_item_free (struct MetaItem *mi)
 {
-  GNUNET_free_non_null (item->plugin_name);
-  GNUNET_free_non_null (item->mime_type);
-  GNUNET_free_non_null (item->data);
-  GNUNET_free (item);
+  GNUNET_free_non_null (mi->plugin_name);
+  GNUNET_free_non_null (mi->mime_type);
+  GNUNET_free_non_null (mi->data);
+  GNUNET_free (mi);
 }
 
 
@@ -139,7 +151,7 @@ meta_item_free (struct MetaItem *item)
 static void
 invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md)
 {
-  if (md->sbuf == NULL)
+  if (NULL == md->sbuf)
     return;
   GNUNET_free (md->sbuf);
   md->sbuf = NULL;
@@ -155,20 +167,42 @@ invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md)
 void
 GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md)
 {
-  struct MetaItem *item;
+  struct MetaItem *pos;
 
-  if (md == NULL)
+  if (NULL == md)
     return;
-  while (NULL != (item = md->items))
-    {
-      md->items = item->next;
-      meta_item_free (item);
-    }
+  while (NULL != (pos = md->items_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos);
+    meta_item_free (pos);
+  }
   GNUNET_free_non_null (md->sbuf);
   GNUNET_free (md);
 }
 
 
+/**
+ * Remove all items in the container.
+ *
+ * @param md metadata to manipulate
+ */
+void
+GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md)
+{
+  struct MetaItem *mi;
+
+  if (NULL == md)
+    return;
+  while (NULL != (mi = md->items_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, mi);
+    meta_item_free (mi);
+  }
+  GNUNET_free_non_null (md->sbuf);
+  memset (md, 0, sizeof (struct GNUNET_CONTAINER_MetaData));
+}
+
+
 /**
  * Test if two MDs are equal.  We consider them equal if
  * the meta types, formats and content match (we do not
@@ -193,30 +227,24 @@ GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
     return GNUNET_YES;
   if (md1->item_count != md2->item_count)
     return GNUNET_NO;
-
-  i = md1->items;
-  while (NULL != i)
+  for (i = md1->items_head; NULL != i; i = i->next)
+  {
+    found = GNUNET_NO;
+    for (j = md2->items_head; NULL != j; j = j->next)
     {
-      found = GNUNET_NO;
-      j = md2->items;
-      while (NULL != j)
-       {
-         if ( (i->type == j->type) &&
-              (i->format == j->format) &&
-              (i->data_size == j->data_size) &&
-              (0 == memcmp (i->data, 
-                            j->data,
-                            i->data_size)))
-           {
-             found = GNUNET_YES;
-             break;
-           }
-         j = j->next;
-       }
-      if (found == GNUNET_NO)
-        return GNUNET_NO;
-      i = i->next;
+      if ((i->type == j->type) && (i->format == j->format) &&
+          (i->data_size == j->data_size) &&
+          (0 == memcmp (i->data, j->data, i->data_size)))
+      {
+        found = GNUNET_YES;
+        break;
+      }
+      if (j->data_size < i->data_size)
+       break; /* elements are sorted by (decreasing) size... */
     }
+    if (GNUNET_NO == found)
+      return GNUNET_NO;
+  }
   return GNUNET_YES;
 }
 
@@ -231,85 +259,127 @@ GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
  *        used in the main libextractor library and yielding
  *        meta data).
  * @param type libextractor-type describing the meta data
- * @param format basic format information about data 
+ * @param format basic format information about data
  * @param data_mime_type mime-type of data (not of the original file);
  *        can be NULL (if mime-type is not known)
  * @param data actual meta-data found
- * @param data_len number of bytes in data
+ * @param data_size number of bytes in data
  * @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists
  *         data_mime_type and plugin_name are not considered for "exists" checks
  */
 int
 GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
-                                  const char *plugin_name,
-                                  enum EXTRACTOR_MetaType type,
-                                  enum EXTRACTOR_MetaFormat format,
-                                  const char *data_mime_type,
-                                  const char *data,
-                                  size_t data_len)
+                                   const char *plugin_name,
+                                   enum EXTRACTOR_MetaType type,
+                                   enum EXTRACTOR_MetaFormat format,
+                                   const char *data_mime_type, const char *data,
+                                   size_t data_size)
 {
-  struct MetaItem *prev;
   struct MetaItem *pos;
-  struct MetaItem *i;
+  struct MetaItem *mi;
   char *p;
 
-  prev = NULL;
-  pos = md->items;
-  while (NULL != pos)
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+  {
+    if (pos->data_size < data_size)
+      break; /* elements are sorted by size in the list */
+    if ((pos->type == type) && (pos->data_size == data_size) &&
+        (0 == memcmp (pos->data, data, data_size)))
     {
-      if (pos->data_size < data_len)
-       break;
-      if ( (pos->type == type) &&
-          (pos->format == format) &&
-          (pos->data_size == data_len) &&
-          (0 == memcmp (pos->data, 
-                        data,
-                        data_len)))
-       {
-         if ( (pos->mime_type == NULL) &&
-              (data_mime_type != NULL) )
-           {
-             pos->mime_type = GNUNET_strdup (data_mime_type);
-             invalidate_sbuf (md);  
-           }
-         return GNUNET_SYSERR;
-       }
-      prev = pos;
-      pos = pos->next;
+      if ((NULL == pos->mime_type) && (NULL != data_mime_type))
+      {
+        pos->mime_type = GNUNET_strdup (data_mime_type);
+        invalidate_sbuf (md);
+      }
+      if ((EXTRACTOR_METAFORMAT_C_STRING == pos->format) &&
+          (EXTRACTOR_METAFORMAT_UTF8 == format))
+      {
+        pos->format = EXTRACTOR_METAFORMAT_UTF8;
+        invalidate_sbuf (md);
+      }
+      return GNUNET_SYSERR;
     }
+  }
   md->item_count++;
-  i = GNUNET_malloc (sizeof (struct MetaItem));
-  i->type = type;
-  i->format = format;
-  i->data_size = data_len;
-  i->next = pos;
-  if (prev == NULL)
-    md->items = i;
+  mi = GNUNET_malloc (sizeof (struct MetaItem));
+  mi->type = type;
+  mi->format = format;
+  mi->data_size = data_size;
+  if (NULL == pos)
+    GNUNET_CONTAINER_DLL_insert_tail (md->items_head,
+                                     md->items_tail,
+                                     mi);
   else
-    prev->next = i;
-  i->mime_type = (data_mime_type == NULL) ? NULL : GNUNET_strdup (data_mime_type);
-  i->plugin_name = (plugin_name == NULL) ? NULL : GNUNET_strdup (plugin_name);
-  i->data = GNUNET_malloc (data_len);
-  memcpy (i->data, data, data_len);
-  /* change OS native dir separators to unix '/' and others to '_' */
-  if (type == EXTRACTOR_METATYPE_FILENAME)
+    GNUNET_CONTAINER_DLL_insert_after (md->items_head,
+                                      md->items_tail,
+                                      pos->prev,
+                                      mi);
+  mi->mime_type =
+      (NULL == data_mime_type) ? NULL : GNUNET_strdup (data_mime_type);
+  mi->plugin_name = (NULL == plugin_name) ? NULL : GNUNET_strdup (plugin_name);
+  mi->data = GNUNET_malloc (data_size);
+  memcpy (mi->data, data, data_size);
+  /* change all dir separators to POSIX style ('/') */
+  if ( (EXTRACTOR_METATYPE_FILENAME == type) ||
+       (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type) )
+  {
+    p = mi->data;
+    while (('\0' != *p) && (p < mi->data + data_size))
     {
-      p = i->data;
-      while ( (*p != '\0') &&
-             (p < i->data + data_len) )
-        {
-          if (*p == DIR_SEPARATOR)
-            *p = '/';
-          else if (*p == '\\')
-            *p = '_';
-          p++;
-        }
+      if ('\\' == *p)
+        *p = '/';
+      p++;
     }
+  }
   invalidate_sbuf (md);
   return GNUNET_OK;
 }
 
 
+/**
+ * Merge given meta data.
+ *
+ * @param cls the 'struct GNUNET_CONTAINER_MetaData' to merge into
+ * @param plugin_name name of the plugin that produced this value;
+ *        special values can be used (i.e. '&lt;zlib&gt;' for zlib being
+ *        used in the main libextractor library and yielding
+ *        meta data).
+ * @param type libextractor-type describing the meta data
+ * @param format basic format information about data
+ * @param data_mime_type mime-type of data (not of the original file);
+ *        can be NULL (if mime-type is not known)
+ * @param data actual meta-data found
+ * @param data_size number of bytes in data
+ * @return 0 (to continue)
+ */
+static int
+merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type,
+              enum EXTRACTOR_MetaFormat format, const char *data_mime_type,
+              const char *data, size_t data_size)
+{
+  struct GNUNET_CONTAINER_MetaData *md = cls;
+
+  (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
+                                            data_mime_type, data, data_size);
+  return 0;
+}
+
+
+/**
+ * Extend metadata.  Merges the meta data from the second argument
+ * into the first, discarding duplicate key-value pairs.
+ *
+ * @param md metadata to extend
+ * @param in metadata to merge
+ */
+void
+GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md,
+                                  const struct GNUNET_CONTAINER_MetaData *in)
+{
+  GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md);
+}
+
+
 /**
  * Remove an item.
  *
@@ -317,41 +387,32 @@ GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
  * @param type type of the item to remove
  * @param data specific value to remove, NULL to remove all
  *        entries of the given type
- * @param data_len number of bytes in data
+ * @param data_size number of bytes in data
  * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md
  */
 int
 GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md,
-                                  enum EXTRACTOR_MetaType type,
-                                  const char *data,
-                                  size_t data_len)
+                                   enum EXTRACTOR_MetaType type,
+                                   const char *data, size_t data_size)
 {
   struct MetaItem *pos;
-  struct MetaItem *prev;
 
-  prev = NULL;
-  pos = md->items;
-  while (NULL != pos)
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+  {
+    if (pos->data_size < data_size)
+      break; /* items are sorted by (decreasing) size */
+    if ((pos->type == type) &&
+        ((NULL == data) ||
+         ((pos->data_size == data_size) &&
+          (0 == memcmp (pos->data, data, data_size)))))
     {
-      if ( (pos->type == type) &&
-          ( (data == NULL) ||
-            ( (pos->data_size == data_len) &&
-              (0 == memcmp (pos->data, 
-                            data,
-                            data_len))) ) )
-       {
-         if (prev == NULL)
-           md->items = pos->next;
-         else
-           prev->next = pos->next;
-         meta_item_free (pos);
-         md->item_count--;
-         invalidate_sbuf (md);
-         return GNUNET_OK;
-       }
-      prev = pos;
-      pos = pos->next;
+      GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos);
+      meta_item_free (pos);
+      md->item_count--;
+      invalidate_sbuf (md);
+      return GNUNET_OK;
     }
+  }
   return GNUNET_SYSERR;
 }
 
@@ -364,26 +425,19 @@ GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md,
  */
 void
 GNUNET_CONTAINER_meta_data_add_publication_date (struct
-                                                 GNUNET_CONTAINER_MetaData
-                                                 *md)
+                                                 GNUNET_CONTAINER_MetaData *md)
 {
-  char *dat;
+  const char *dat;
   struct GNUNET_TIME_Absolute t;
 
   t = GNUNET_TIME_absolute_get ();
-  GNUNET_CONTAINER_meta_data_delete (md,
-                                    EXTRACTOR_METATYPE_PUBLICATION_DATE,
-                                    NULL,
-                                    0);
+  GNUNET_CONTAINER_meta_data_delete (md, EXTRACTOR_METATYPE_PUBLICATION_DATE,
+                                     NULL, 0);
   dat = GNUNET_STRINGS_absolute_time_to_string (t);
-  GNUNET_CONTAINER_meta_data_insert (md, 
-                                    "<gnunet>",
-                                    EXTRACTOR_METATYPE_PUBLICATION_DATE, 
-                                    EXTRACTOR_METAFORMAT_UTF8,
-                                    "text/plain",
-                                    dat,
-                                    strlen(dat)+1);
-  GNUNET_free (dat);
+  GNUNET_CONTAINER_meta_data_insert (md, "<gnunet>",
+                                     EXTRACTOR_METATYPE_PUBLICATION_DATE,
+                                     EXTRACTOR_METAFORMAT_UTF8, "text/plain",
+                                     dat, strlen (dat) + 1);
 }
 
 
@@ -396,28 +450,21 @@ GNUNET_CONTAINER_meta_data_add_publication_date (struct
  * @return number of entries
  */
 int
-GNUNET_CONTAINER_meta_data_iterate (const struct
-                                   GNUNET_CONTAINER_MetaData *md,
-                                   EXTRACTOR_MetaDataProcessor
-                                   iter, void *iter_cls)
+GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md,
+                                    EXTRACTOR_MetaDataProcessor iter,
+                                    void *iter_cls)
 {
   struct MetaItem *pos;
 
-  if (iter == NULL)
+  if (NULL == md)
+    return 0;
+  if (NULL == iter)
     return md->item_count;
-  pos = md->items;
-  while (NULL != pos)
-    {
-      if (0 != iter (iter_cls,
-                    pos->plugin_name,
-                    pos->type,
-                    pos->format,
-                    pos->mime_type,
-                    pos->data,
-                    pos->data_size))
-       return md->item_count;
-      pos = pos->next;
-    }
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+    if (0 !=
+        iter (iter_cls, pos->plugin_name, pos->type, pos->format,
+              pos->mime_type, pos->data, pos->data_size))
+      return md->item_count;
   return md->item_count;
 }
 
@@ -438,15 +485,13 @@ GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData
 {
   struct MetaItem *pos;
 
-  pos = md->items;
-  while (NULL != pos)
-    {
-      if ( (type == pos->type) &&
-          ( (pos->format == EXTRACTOR_METAFORMAT_UTF8) ||
-            (pos->format == EXTRACTOR_METAFORMAT_C_STRING) ) )
-       return GNUNET_strdup (pos->data);
-      pos = pos->next;
-    }
+  if (NULL == md)
+    return NULL;
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+    if ((type == pos->type) &&
+        ((pos->format == EXTRACTOR_METAFORMAT_UTF8) ||
+         (pos->format == EXTRACTOR_METAFORMAT_C_STRING)))
+      return GNUNET_strdup (pos->data);
   return NULL;
 }
 
@@ -471,17 +516,18 @@ GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
   va_list args;
   enum EXTRACTOR_MetaType type;
 
+  if (NULL == md)
+    return NULL;
   ret = NULL;
   va_start (args, md);
   while (1)
-    {
-      type = va_arg (args, enum EXTRACTOR_MetaType);
-      if (type == -1)
-        break;
-      ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type);
-      if (ret != NULL)
-        break;
-    }
+  {
+    type = va_arg (args, enum EXTRACTOR_MetaType);
+    if (-1 == type)
+      break;
+    if (NULL != (ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type)))
+      break;
+  }
   va_end (args);
   return ret;
 }
@@ -496,30 +542,29 @@ GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
  * @return number of bytes in thumbnail, 0 if not available
  */
 size_t
-GNUNET_CONTAINER_meta_data_get_thumbnail (const struct
-                                          GNUNET_CONTAINER_MetaData * md,
-                                          unsigned char **thumb)
+GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData
+                                          * md, unsigned char **thumb)
 {
   struct MetaItem *pos;
   struct MetaItem *match;
 
+  if (NULL == md)
+    return 0;
   match = NULL;
-  pos = md->items;
-  while (NULL != pos)
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+  {
+    if ((NULL != pos->mime_type) &&
+        (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) &&
+        (EXTRACTOR_METAFORMAT_BINARY == pos->format))
     {
-      if ( (0 == strncasecmp ("image/", pos->mime_type,
-                             strlen("image/"))) &&
-          (pos->format == EXTRACTOR_METAFORMAT_BINARY) )
-       {
-         if (match == NULL)
-           match = pos;
-         else if ( (match->type != EXTRACTOR_METATYPE_THUMBNAIL) &&
-                   (pos->type == EXTRACTOR_METATYPE_THUMBNAIL) )
-           match = pos;
-       }
-      pos = pos->next;
+      if (NULL == match)
+        match = pos;
+      else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) &&
+               (pos->type == EXTRACTOR_METATYPE_THUMBNAIL))
+        match = pos;
     }
-  if (match == NULL)
+  }
+  if ((NULL == match) || (0 == match->data_size))
     return 0;
   *thumb = GNUNET_malloc (match->data_size);
   memcpy (*thumb, match->data, match->data_size);
@@ -529,7 +574,7 @@ GNUNET_CONTAINER_meta_data_get_thumbnail (const struct
 
 /**
  * Duplicate struct GNUNET_CONTAINER_MetaData.
- * 
+ *
  * @param md what to duplicate
  * @return duplicate meta-data container
  */
@@ -540,90 +585,17 @@ GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData
   struct GNUNET_CONTAINER_MetaData *ret;
   struct MetaItem *pos;
 
-  if (md == NULL)
+  if (NULL == md)
     return NULL;
   ret = GNUNET_CONTAINER_meta_data_create ();
-  pos = md->items;
-  while (NULL != pos)
-    {
-      GNUNET_CONTAINER_meta_data_insert (ret, 
-                                        pos->plugin_name,
-                                        pos->type,
-                                        pos->format,
-                                        pos->mime_type,
-                                        pos->data,
-                                        pos->data_size);
-      pos = pos->next;
-    }
+  for (pos = md->items_tail; NULL != pos; pos = pos->prev)
+    GNUNET_CONTAINER_meta_data_insert (ret, pos->plugin_name, pos->type,
+                                       pos->format, pos->mime_type, pos->data,
+                                       pos->data_size);
   return ret;
 }
 
 
-/**
- * Add meta data that libextractor finds to our meta data
- * container.
- *
- * @param cls closure, our meta data container
- * @param plugin_name name of the plugin that produced this value;
- *        special values can be used (i.e. '&lt;zlib&gt;' for zlib being
- *        used in the main libextractor library and yielding
- *        meta data).
- * @param type libextractor-type describing the meta data
- * @param format basic format information about data
- * @param data_mime_type mime-type of data (not of the original file);
- *        can be NULL (if mime-type is not known)
- * @param data actual meta-data found
- * @param data_len number of bytes in data
- * @return always 0 to continue extracting
- */
-static int
-add_to_md(void *cls,
-         const char *plugin_name,
-         enum EXTRACTOR_MetaType type,
-         enum EXTRACTOR_MetaFormat format,
-         const char *data_mime_type,
-         const char *data,
-         size_t data_len)
-{
-  struct GNUNET_CONTAINER_MetaData *md = cls;
-  (void) GNUNET_CONTAINER_meta_data_insert (md,
-                                           plugin_name,
-                                           type,
-                                           format,
-                                           data_mime_type,
-                                           data,
-                                           data_len);
-  return 0;
-}
-
-
-/**
- * Extract meta-data from a file.
- *
- * @return GNUNET_SYSERR on error, otherwise the number
- *   of meta-data items obtained
- */
-int
-GNUNET_CONTAINER_meta_data_extract_from_file (struct GNUNET_CONTAINER_MetaData
-                                              *md, const char *filename,
-                                              struct EXTRACTOR_PluginList *
-                                              extractors)
-{
-  unsigned int old;
-
-  if (filename == NULL)
-    return GNUNET_SYSERR;
-  if (extractors == NULL)
-    return 0;
-  old = md->item_count;
-  EXTRACTOR_extract (extractors, 
-                    filename,
-                    NULL, 0,
-                    &add_to_md,
-                    md);
-  return (int) (md->item_count - old);
-}
-
 
 /**
  * Try to compress the given block of data.
@@ -639,10 +611,8 @@ GNUNET_CONTAINER_meta_data_extract_from_file (struct GNUNET_CONTAINER_MetaData
  *         GNUNET_NO if compression did not help
  */
 static int
-try_compression (const char *data, 
-                size_t oldSize,
-                char **result,
-                size_t *newSize)
+try_compression (const char *data, size_t oldSize, char **result,
+                 size_t * newSize)
 {
   char *tmp;
   uLongf dlen;
@@ -652,19 +622,19 @@ try_compression (const char *data,
 #else
   dlen = oldSize + (oldSize / 100) + 20;
   /* documentation says 100.1% oldSize + 12 bytes, but we
-     should be able to overshoot by more to be safe */
+   * should be able to overshoot by more to be safe */
 #endif
   tmp = GNUNET_malloc (dlen);
-  if (Z_OK == compress2 ((Bytef *) tmp,
-                         &dlen, (const Bytef *) data, oldSize, 9))
+  if (Z_OK ==
+      compress2 ((Bytef *) tmp, &dlen, (const Bytef *) data, oldSize, 9))
+  {
+    if (dlen < oldSize)
     {
-      if (dlen < oldSize)
-        {
-          *result = tmp;
-         *newSize = dlen;
-          return GNUNET_YES;
-        }
+      *result = tmp;
+      *newSize = dlen;
+      return GNUNET_YES;
     }
+  }
   GNUNET_free (tmp);
   return GNUNET_NO;
 }
@@ -723,7 +693,7 @@ struct MetaDataEntry
 {
   /**
    * Meta data type.  Corresponds to an 'enum EXTRACTOR_MetaType'
-   */ 
+   */
   uint32_t type;
 
   /**
@@ -772,8 +742,10 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
 {
   struct GNUNET_CONTAINER_MetaData *vmd;
   struct MetaItem *pos;
-  struct MetaDataHeader *hdr;  
+  struct MetaDataHeader ihdr;
+  struct MetaDataHeader *hdr;
   struct MetaDataEntry *ent;
+  char *dst;
   unsigned int i;
   uint64_t msize;
   size_t off;
@@ -784,194 +756,191 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
   size_t size;
   size_t left;
   size_t clen;
+  size_t rlen;
   int comp;
 
   if (max < sizeof (struct MetaDataHeader))
     return GNUNET_SYSERR;       /* far too small */
-  if (md == NULL)
+  if (NULL == md)
     return 0;
 
-  if (md->sbuf != NULL)
+  if (NULL != md->sbuf)
+  {
+    /* try to use serialization cache */
+    if (md->sbuf_size <= max)
     {
-      /* try to use serialization cache */
-      if (md->sbuf_size <= max)
-       {
-         if (NULL == *target)
-           *target = GNUNET_malloc (md->sbuf_size);
-         memcpy (*target,
-                 md->sbuf,
-                 md->sbuf_size);
-         return md->sbuf_size;
-       }
-      if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
-       return GNUNET_SYSERR; /* can say that this will fail */
-      /* need to compute a partial serialization, sbuf useless ... */
+      if (NULL == *target)
+        *target = GNUNET_malloc (md->sbuf_size);
+      memcpy (*target, md->sbuf, md->sbuf_size);
+      return md->sbuf_size;
     }
-
-
+    if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
+      return GNUNET_SYSERR;     /* can say that this will fail */
+    /* need to compute a partial serialization, sbuf useless ... */
+  }
+  dst = NULL;
   msize = 0;
-  pos = md->items;
-  while (NULL != pos)
-    {      
-      msize += sizeof (struct MetaDataEntry);
-      msize += pos->data_size;
-      if (pos->plugin_name != NULL)
-       msize += strlen (pos->plugin_name) + 1;
-      if (pos->mime_type != NULL)
-       msize += strlen (pos->mime_type) + 1;      
-      pos = pos->next;
-    }
+  for (pos = md->items_tail; NULL != pos; pos = pos->prev)
+  {
+    msize += sizeof (struct MetaDataEntry);
+    msize += pos->data_size;
+    if (NULL != pos->plugin_name)
+      msize += strlen (pos->plugin_name) + 1;
+    if (NULL != pos->mime_type)
+      msize += strlen (pos->mime_type) + 1;
+  }
   size = (size_t) msize;
   if (size != msize)
-    {      
-      GNUNET_break (0); /* integer overflow */
-      return GNUNET_SYSERR; 
-    }
+  {
+    GNUNET_break (0);           /* integer overflow */
+    return GNUNET_SYSERR;
+  }
   if (size >= GNUNET_MAX_MALLOC_CHECKED)
-    {
-      /* too large to be processed */
-      return GNUNET_SYSERR;
-    }
+  {
+    /* too large to be processed */
+    return GNUNET_SYSERR;
+  }
   ent = GNUNET_malloc (size);
   mdata = (char *) &ent[md->item_count];
-  off = size - (md->item_count * sizeof(struct MetaDataEntry));
+  off = size - (md->item_count * sizeof (struct MetaDataEntry));
   i = 0;
-  pos = md->items;
-  while (NULL != pos)
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+  {
+    ent[i].type = htonl ((uint32_t) pos->type);
+    ent[i].format = htonl ((uint32_t) pos->format);
+    ent[i].data_size = htonl ((uint32_t) pos->data_size);
+    if (pos->plugin_name == NULL)
+      plen = 0;
+    else
+      plen = strlen (pos->plugin_name) + 1;
+    ent[i].plugin_name_len = htonl ((uint32_t) plen);
+    if (pos->mime_type == NULL)
+      mlen = 0;
+    else
+      mlen = strlen (pos->mime_type) + 1;
+    ent[i].mime_type_len = htonl ((uint32_t) mlen);
+    off -= pos->data_size;
+    memcpy (&mdata[off], pos->data, pos->data_size);
+    off -= plen;
+    if (pos->plugin_name != NULL)
+      memcpy (&mdata[off], pos->plugin_name, plen);
+    off -= mlen;
+    if (pos->mime_type != NULL)
+      memcpy (&mdata[off], pos->mime_type, mlen);
+    i++;
+  }
+  GNUNET_assert (0 == off);
+
+  clen = 0;
+  cdata = NULL;
+  left = size;
+  i = 0;
+  for (pos = md->items_head; NULL != pos; pos = pos->next)
+  {
+    comp = GNUNET_NO;
+    if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))
+      comp = try_compression ((const char *) &ent[i], left, &cdata, &clen);
+
+    if ((NULL == md->sbuf) && (0 == i))
+    {
+      /* fill 'sbuf'; this "modifies" md, but since this is only
+       * an internal cache we will cast away the 'const' instead
+       * of making the API look strange. */
+      vmd = (struct GNUNET_CONTAINER_MetaData *) md;
+      hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
+      hdr->size = htonl (left);
+      hdr->entries = htonl (md->item_count);
+      if (GNUNET_YES == comp)
+      {
+        GNUNET_assert (clen < left);
+        hdr->version = htonl (2 | HEADER_COMPRESSED);
+        memcpy (&hdr[1], cdata, clen);
+        vmd->sbuf_size = clen + sizeof (struct MetaDataHeader);
+      }
+      else
+      {
+        hdr->version = htonl (2);
+        memcpy (&hdr[1], &ent[0], left);
+        vmd->sbuf_size = left + sizeof (struct MetaDataHeader);
+      }
+      vmd->sbuf = (char *) hdr;
+    }
+
+    if (((left + sizeof (struct MetaDataHeader)) <= max) ||
+        ((GNUNET_YES == comp) && (clen <= max)))
     {
-      ent[i].type = htonl ((uint32_t) pos->type);
-      ent[i].format = htonl ((uint32_t) pos->format);
-      ent[i].data_size = htonl ((uint32_t) pos->data_size);
-      if (pos->plugin_name == NULL)
-       plen = 0;
+      /* success, this now fits! */
+      if (GNUNET_YES == comp)
+      {
+        if (NULL == dst)
+          dst = GNUNET_malloc (clen + sizeof (struct MetaDataHeader));
+        hdr = (struct MetaDataHeader *) dst;
+        hdr->version = htonl (2 | HEADER_COMPRESSED);
+        hdr->size = htonl (left);
+        hdr->entries = htonl (md->item_count - i);
+        memcpy (&dst[sizeof (struct MetaDataHeader)], cdata, clen);
+        GNUNET_free (cdata);
+       cdata = NULL;
+        GNUNET_free (ent);
+        rlen = clen + sizeof (struct MetaDataHeader);
+      }
       else
-       plen = strlen (pos->plugin_name) + 1;
-      ent[i].plugin_name_len = htonl ( (uint32_t) plen);
-      if (pos->mime_type == NULL)
-       mlen = 0;
+      {
+        if (NULL == dst)
+          dst = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
+        hdr = (struct MetaDataHeader *) dst;
+        hdr->version = htonl (2);
+        hdr->entries = htonl (md->item_count - i);
+        hdr->size = htonl (left);
+        memcpy (&dst[sizeof (struct MetaDataHeader)], &ent[i], left);
+        GNUNET_free (ent);
+        rlen = left + sizeof (struct MetaDataHeader);
+      }
+      if (NULL != *target)
+      {
+        if (GNUNET_YES == comp)
+          memcpy (*target, dst, clen + sizeof (struct MetaDataHeader));
+        else
+          memcpy (*target, dst, left + sizeof (struct MetaDataHeader));
+        GNUNET_free (dst);
+      }
       else
-       mlen = strlen (pos->mime_type) + 1;
-      ent[i].mime_type_len = htonl ((uint32_t) mlen);
-      off -= pos->data_size;
-      memcpy (&mdata[off], pos->data, pos->data_size);
-      off -= plen;
-      memcpy (&mdata[off], pos->plugin_name, plen);
-      off -= mlen;
-      memcpy (&mdata[off], pos->mime_type, mlen);      
-      i++;
-      pos = pos->next;
-    }  
-  GNUNET_assert (off == 0);
+      {
+        *target = dst;
+      }
+      return rlen;
+    }
 
-  left = size;
-  for (i=0;i<md->item_count;i++)
-    {           
-      comp = GNUNET_NO;
-      if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))       
-       comp = try_compression ((const char*) &ent[i],
-                               left,
-                               &cdata,
-                               &clen);   
-
-      if ( (md->sbuf == NULL) &&
-          (i == 0) )
-       {
-         /* fill 'sbuf'; this "modifies" md, but since this is only
-            an internal cache we will cast away the 'const' instead
-            of making the API look strange. */
-         vmd = (struct GNUNET_CONTAINER_MetaData*) md;
-         hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
-         hdr->size = htonl (left);
-         hdr->entries = htonl (md->item_count);
-         if (GNUNET_YES == comp)
-           {
-             hdr->version = htonl (2 | HEADER_COMPRESSED);
-             memcpy (&hdr[1],
-                     cdata, 
-                     clen);
-             vmd->sbuf_size = clen + sizeof (struct MetaDataHeader);
-           }
-         else
-           {
-             hdr->version = htonl (2);
-             memcpy (&hdr[1],
-                     &ent[0], 
-                     left);
-             vmd->sbuf_size = left + sizeof (struct MetaDataHeader);
-           }
-         vmd->sbuf = (char*) hdr;
-       }
-
-      if ( ( (left + sizeof (struct MetaDataHeader)) <= max) ||
-          ( (comp == GNUNET_YES) &&
-            (clen <= max)) )
-       {
-         /* success, this now fits! */
-         if (GNUNET_YES == comp)
-           {
-             hdr = (struct MetaDataHeader*) *target;
-             if (hdr == NULL)
-               {
-                 hdr = GNUNET_malloc (clen + sizeof (struct MetaDataHeader));
-                 *target = (char*) hdr;
-               }
-             hdr->version = htonl (2 | HEADER_COMPRESSED);
-             hdr->size = htonl (left);
-             hdr->entries = htonl (md->item_count - i);
-             memcpy (&(*target)[sizeof(struct MetaDataHeader)],
-                     cdata, 
-                     clen);
-             GNUNET_free (cdata);
-             GNUNET_free (ent);
-             return clen + sizeof (struct MetaDataHeader);
-           }
-         else
-           {
-             hdr = (struct MetaDataHeader*) *target;
-             if (hdr == NULL)
-               {
-                 hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
-                 *target = (char*) hdr;
-               }
-             hdr->version = htonl (2);
-             hdr->entries = htonl (md->item_count - i);
-             hdr->size = htonl (left);
-             memcpy (&(*target)[sizeof(struct MetaDataHeader)],
-                     &ent[i], 
-                     left);
-             GNUNET_free (ent);
-             return left + sizeof (struct MetaDataHeader);           
-           }
-       }
-
-      if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
-       {
-         /* does not fit! */
-         GNUNET_free (ent);
-          return GNUNET_SYSERR;
-        }
-     
-      /* next iteration: ignore the corresponding meta data at the
-        end and try again without it */
-      left -= sizeof (struct MetaDataEntry);
-      left -= pos->data_size;
-      if (pos->plugin_name != NULL)
-       left -= strlen (pos->plugin_name) + 1;
-      if (pos->mime_type != NULL)
-       left -= strlen (pos->mime_type) + 1;      
+    if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
+    {
+      /* does not fit! */
+      GNUNET_free (ent);
+      return GNUNET_SYSERR;
     }
+
+    /* next iteration: ignore the corresponding meta data at the
+     * end and try again without it */
+    left -= sizeof (struct MetaDataEntry);
+    left -= pos->data_size;
+    if (NULL != pos->plugin_name)
+      left -= strlen (pos->plugin_name) + 1;
+    if (NULL != pos->mime_type)
+      left -= strlen (pos->mime_type) + 1;
+
+    GNUNET_free_non_null (cdata);
+    cdata = NULL;
+
+    i++;
+  }
   GNUNET_free (ent);
 
   /* nothing fit, only write header! */
-  hdr = (struct MetaDataHeader*) *target;
-  if (hdr == NULL)
-    {
-      hdr = GNUNET_malloc (sizeof (struct MetaDataHeader));
-      *target = (char*) hdr;
-    }
-  hdr->version = htonl (2);
-  hdr->entries = htonl (0);
-  hdr->size = htonl (0);
+  ihdr.version = htonl (2);
+  ihdr.entries = htonl (0);
+  ihdr.size = htonl (0);
+  if (NULL == *target)
+    *target = GNUNET_malloc (sizeof (struct MetaDataHeader));
+  memcpy (*target, &ihdr, sizeof (struct MetaDataHeader));
   return sizeof (struct MetaDataHeader);
 }
 
@@ -983,19 +952,19 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
  * @return number of bytes needed for serialization, -1 on error
  */
 ssize_t
-GNUNET_CONTAINER_meta_data_get_serialized_size (const struct GNUNET_CONTAINER_MetaData *md)
+GNUNET_CONTAINER_meta_data_get_serialized_size (const struct
+                                                GNUNET_CONTAINER_MetaData *md)
 {
   ssize_t ret;
   char *ptr;
-  
-  if (md->sbuf != NULL)
+
+  if (NULL != md->sbuf)
     return md->sbuf_size;
   ptr = NULL;
-  ret = GNUNET_CONTAINER_meta_data_serialize (md,
-                                             &ptr,
-                                             GNUNET_MAX_MALLOC_CHECKED,
-                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
-  if (ret != -1)
+  ret =
+      GNUNET_CONTAINER_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED,
+                                            GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
+  if (-1 != ret)
     GNUNET_free (ptr);
   return ret;
 }
@@ -1012,25 +981,18 @@ GNUNET_CONTAINER_meta_data_get_serialized_size (const struct GNUNET_CONTAINER_Me
  * @return NULL on error
  */
 static char *
-decompress (const char *input,
-            size_t inputSize, 
-           size_t outputSize)
+decompress (const char *input, size_t inputSize, size_t outputSize)
 {
   char *output;
   uLongf olen;
 
   olen = outputSize;
   output = GNUNET_malloc (olen);
-  if (Z_OK == uncompress ((Bytef *) output,
-                          &olen, (const Bytef *) input, inputSize))
-    {
-      return output;
-    }
-  else
-    {
-      GNUNET_free (output);
-      return NULL;
-    }
+  if (Z_OK ==
+      uncompress ((Bytef *) output, &olen, (const Bytef *) input, inputSize))
+    return output;
+  GNUNET_free (output);
+  return NULL;  
 }
 
 
@@ -1067,136 +1029,127 @@ GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
 
   if (size < sizeof (struct MetaDataHeader))
     return NULL;
-  memcpy (&hdr,
-         input,
-         sizeof (struct MetaDataHeader));
+  memcpy (&hdr, input, sizeof (struct MetaDataHeader));
   version = ntohl (hdr.version) & HEADER_VERSION_MASK;
   compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0;
 
-  if (version == 1)
-    return NULL;  /* null pointer */
-  if (version != 2)
-    {
-      GNUNET_break_op (0);      /* unsupported version */
-      return NULL;
-    }
+  if (1 == version)
+    return NULL;                /* null pointer */
+  if (2 != version)
+  {
+    GNUNET_break_op (0);        /* unsupported version */
+    return NULL;
+  }
 
   ic = ntohl (hdr.entries);
-  dataSize = ntohl (hdr.size); 
+  dataSize = ntohl (hdr.size);
   if ((sizeof (struct MetaDataEntry) * ic) > dataSize)
-    {
-      GNUNET_break_op (0);      
-      return NULL; 
-    }
+  {
+    GNUNET_break_op (0);
+    return NULL;
+  }
 
   if (compressed)
+  {
+    if (dataSize >= GNUNET_MAX_MALLOC_CHECKED)
     {
-      if (dataSize >= GNUNET_MAX_MALLOC_CHECKED)
-        {
-         /* make sure we don't blow our memory limit because of a mal-formed
-            message... */
-          GNUNET_break_op (0);
-          return NULL;          
-        }
-      data =
+      /* make sure we don't blow our memory limit because of a mal-formed
+       * message... */
+      GNUNET_break_op (0);
+      return NULL;
+    }
+    data =
         decompress ((const char *) &input[sizeof (struct MetaDataHeader)],
                     size - sizeof (struct MetaDataHeader), dataSize);
-      if (data == NULL)
-        {
-          GNUNET_break_op (0);
-          return NULL;
-        }
-      cdata = data;
+    if (NULL == data)
+    {
+      GNUNET_break_op (0);
+      return NULL;
     }
+    cdata = data;
+  }
   else
+  {
+    data = NULL;
+    cdata = (const char *) &input[sizeof (struct MetaDataHeader)];
+    if (dataSize != size - sizeof (struct MetaDataHeader))
     {
-      data = NULL;
-      cdata = (const char *) &input[sizeof (struct MetaDataHeader)];
-      if (dataSize != size - sizeof (struct MetaDataHeader))
-        {
-          GNUNET_break_op (0);
-          return NULL;
-        }
+      GNUNET_break_op (0);
+      return NULL;
     }
+  }
 
   md = GNUNET_CONTAINER_meta_data_create ();
   left = dataSize - ic * sizeof (struct MetaDataEntry);
   mdata = &cdata[ic * sizeof (struct MetaDataEntry)];
-  for (i=0;i<ic;i++)
+  for (i = 0; i < ic; i++)
+  {
+    memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)],
+            sizeof (struct MetaDataEntry));
+    format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format);
+    if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
+        (EXTRACTOR_METAFORMAT_C_STRING != format) &&
+        (EXTRACTOR_METAFORMAT_BINARY != format))
     {
-      memcpy (&ent,
-             &cdata[i * sizeof(struct MetaDataEntry)],
-             sizeof (struct MetaDataEntry));
-      format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format);
-      if ( (format != EXTRACTOR_METAFORMAT_UTF8) &&
-          (format != EXTRACTOR_METAFORMAT_C_STRING) &&
-          (format != EXTRACTOR_METAFORMAT_BINARY) )
-       {
-         GNUNET_break_op (0);
-         break;
-       }
-      dlen = ntohl (ent.data_size);
-      plen = ntohl (ent.plugin_name_len);
-      mlen = ntohl (ent.mime_type_len);
-      if (dlen > left)
-       {
-         GNUNET_break_op (0);
-         break;
-       }
-      left -= dlen;
-      meta_data = &mdata[left];
-      if ( (format == EXTRACTOR_METAFORMAT_UTF8) ||
-          (format == EXTRACTOR_METAFORMAT_C_STRING) )
-       {
-         if ( (dlen == 0) ||
-              (mdata[left + dlen - 1] != '\0') )
-           {
-             GNUNET_break_op (0);
-             break;
-           }     
-       }
-      if (plen > left)
-       {
-         GNUNET_break_op (0);
-         break;
-       }
-      left -= plen;
-      if ( (plen > 0) &&
-          (mdata[left + plen - 1] != '\0') )
-       {
-         GNUNET_break_op (0);
-         break;
-       }
-      if (plen == 0)
-       plugin_name = NULL;
-      else
-       plugin_name = &mdata[left];
-
-      if (mlen > left)
-       {
-         GNUNET_break_op (0);
-         break;
-       }
-      left -= mlen;
-      if ( (mlen > 0) &&
-          (mdata[left + mlen - 1] != '\0') )
-       {
-         GNUNET_break_op (0);
-         break;
-       }
-      if (mlen == 0)
-       mime_type = NULL;
-      else
-       mime_type = &mdata[left];      
-      GNUNET_CONTAINER_meta_data_insert (md,
-                                        plugin_name,
-                                        (enum EXTRACTOR_MetaType) ntohl (ent.type),
-                                        format,
-                                        mime_type,
-                                        meta_data,
-                                        dlen);
+      GNUNET_break_op (0);
+      break;
+    }
+    dlen = ntohl (ent.data_size);
+    plen = ntohl (ent.plugin_name_len);
+    mlen = ntohl (ent.mime_type_len);
+    if (dlen > left)
+    {
+      GNUNET_break_op (0);
+      break;
+    }
+    left -= dlen;
+    meta_data = &mdata[left];
+    if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
+        (EXTRACTOR_METAFORMAT_C_STRING == format))
+    {
+      if ((0 == dlen) || ('\0' != mdata[left + dlen - 1]))
+      {
+        GNUNET_break_op (0);
+        break;
+      }
+    }
+    if (plen > left)
+    {
+      GNUNET_break_op (0);
+      break;
+    }
+    left -= plen;
+    if ((plen > 0) && ('\0' != mdata[left + plen - 1]))
+    {
+      GNUNET_break_op (0);
+      break;
+    }
+    if (0 == plen)
+      plugin_name = NULL;
+    else
+      plugin_name = &mdata[left];
+
+    if (mlen > left)
+    {
+      GNUNET_break_op (0);
+      break;
+    }
+    left -= mlen;
+    if ((mlen > 0) && ('\0' != mdata[left + mlen - 1]))
+    {
+      GNUNET_break_op (0);
+      break;
     }
-  GNUNET_free_non_null (data);  
+    if (0 == mlen)
+      mime_type = NULL;
+    else
+      mime_type = &mdata[left];
+    GNUNET_CONTAINER_meta_data_insert (md, plugin_name,
+                                       (enum EXTRACTOR_MetaType)
+                                       ntohl (ent.type), format, mime_type,
+                                       meta_data, dlen);
+  }
+  GNUNET_free_non_null (data);
   return md;
 }