trying to port statvfs call to BSD
[oweals/gnunet.git] / src / util / container_meta_data.c
index a614f3c4fb62b6b5c1f00a21cbe6e8ee273ba425..039ba86ab2dfc4c26dca7a3194efced41aa99e3b 100644 (file)
@@ -169,6 +169,29 @@ GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *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 *item;
+
+  if (md == NULL)
+    return;
+  while (NULL != (item = md->items))
+    {
+      md->items = item->next;
+      meta_item_free (item);
+    }
+  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
@@ -227,7 +250,7 @@ GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
  *
  * @param md metadata to extend
  * @param plugin_name name of the plugin that produced this value;
- *        special values can be used (i.e. '<zlib>' for zlib being
+ *        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
@@ -310,6 +333,54 @@ GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
 }
 
 
+/**
+ * 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_len 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_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;
+}
+
+
+/**
+ * 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.
  *
@@ -403,6 +474,8 @@ GNUNET_CONTAINER_meta_data_iterate (const struct
 {
   struct MetaItem *pos;
 
+  if (md == NULL)
+    return 0;
   if (iter == NULL)
     return md->item_count;
   pos = md->items;
@@ -438,6 +511,8 @@ GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData
 {
   struct MetaItem *pos;
 
+  if (md == NULL)
+    return NULL;
   pos = md->items;
   while (NULL != pos)
     {
@@ -471,6 +546,8 @@ GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
   va_list args;
   enum EXTRACTOR_MetaType type;
 
+  if (md == NULL)
+    return NULL;
   ret = NULL;
   va_start (args, md);
   while (1)
@@ -503,11 +580,14 @@ GNUNET_CONTAINER_meta_data_get_thumbnail (const struct
   struct MetaItem *pos;
   struct MetaItem *match;
 
+  if (md == NULL)
+    return 0;
   match = NULL;
   pos = md->items;
   while (NULL != pos)
-    {
-      if ( (0 == strncasecmp ("image/", pos->mime_type,
+    {      
+      if ( (NULL != pos->mime_type) && 
+          (0 == strncasecmp ("image/", pos->mime_type,
                              strlen("image/"))) &&
           (pos->format == EXTRACTOR_METAFORMAT_BINARY) )
        {
@@ -519,7 +599,8 @@ GNUNET_CONTAINER_meta_data_get_thumbnail (const struct
        }
       pos = pos->next;
     }
-  if (match == NULL)
+  if ( (match == NULL) ||
+       (match->data_size == 0) )
     return 0;
   *thumb = GNUNET_malloc (match->data_size);
   memcpy (*thumb, match->data, match->data_size);
@@ -559,71 +640,6 @@ GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData
 }
 
 
-/**
- * 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. '<zlib>' 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.
@@ -772,8 +788,10 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
 {
   struct GNUNET_CONTAINER_MetaData *vmd;
   struct MetaItem *pos;
+  struct MetaDataHeader ihdr;  
   struct MetaDataHeader *hdr;  
   struct MetaDataEntry *ent;
+  char *dst;
   unsigned int i;
   uint64_t msize;
   size_t off;
@@ -784,13 +802,14 @@ 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)
     return 0;
-
   if (md->sbuf != NULL)
     {
       /* try to use serialization cache */
@@ -807,8 +826,7 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
        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)
@@ -855,16 +873,22 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
       off -= pos->data_size;
       memcpy (&mdata[off], pos->data, pos->data_size);
       off -= plen;
-      memcpy (&mdata[off], pos->plugin_name, plen);
+      if (pos->plugin_name != NULL)
+       memcpy (&mdata[off], pos->plugin_name, plen);
       off -= mlen;
-      memcpy (&mdata[off], pos->mime_type, mlen);      
+      if (pos->mime_type != NULL)
+       memcpy (&mdata[off], pos->mime_type, mlen);      
       i++;
       pos = pos->next;
     }  
   GNUNET_assert (off == 0);
 
+  clen = 0;
+  cdata = NULL;
   left = size;
-  for (i=0;i<md->item_count;i++)
+  i = 0;
+  pos = md->items;
+  while (pos != NULL)
     {           
       comp = GNUNET_NO;
       if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))       
@@ -885,6 +909,7 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
          hdr->entries = htonl (md->item_count);
          if (GNUNET_YES == comp)
            {
+             GNUNET_assert (clen < left);
              hdr->version = htonl (2 | HEADER_COMPRESSED);
              memcpy (&hdr[1],
                      cdata, 
@@ -909,39 +934,43 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
          /* 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;
-               }
+             if (dst == NULL)
+               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 (&(*target)[sizeof(struct MetaDataHeader)],
+             memcpy (&dst[sizeof(struct MetaDataHeader)],
                      cdata, 
                      clen);
              GNUNET_free (cdata);
              GNUNET_free (ent);
-             return clen + sizeof (struct MetaDataHeader);
+             rlen = clen + sizeof (struct MetaDataHeader);
            }
          else
            {
-             hdr = (struct MetaDataHeader*) *target;
-             if (hdr == NULL)
-               {
-                 hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
-                 *target = (char*) hdr;
-               }
+             if (dst == NULL)
+               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 (&(*target)[sizeof(struct MetaDataHeader)],
+             memcpy (&dst[sizeof(struct MetaDataHeader)],
                      &ent[i], 
                      left);
              GNUNET_free (ent);
-             return left + sizeof (struct MetaDataHeader);           
+             rlen = left + sizeof (struct MetaDataHeader);           
+           }
+         if (NULL != *target)
+           {
+             memcpy (*target, dst, clen + sizeof (struct MetaDataHeader));
+             GNUNET_free (dst);
+           }
+         else
+           {
+             *target = dst;
            }
+         return rlen;
        }
 
       if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
@@ -958,20 +987,19 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
       if (pos->plugin_name != NULL)
        left -= strlen (pos->plugin_name) + 1;
       if (pos->mime_type != NULL)
-       left -= strlen (pos->mime_type) + 1;      
+       left -= strlen (pos->mime_type) + 1;
+      pos = pos->next;
+      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 (*target == NULL)    
+    *target = GNUNET_malloc (sizeof (struct MetaDataHeader));
+  memcpy (*target, &ihdr, sizeof (struct MetaDataHeader));
   return sizeof (struct MetaDataHeader);
 }