Link libgnunetblockgroup to libgnunetblock
[oweals/gnunet.git] / src / util / container_meta_data.c
index a868e817da61580925a6200074a81aca3ed3e31a..ec527005a04680ec6960d883fb15d4144a7bd29c 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
-     (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  */
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_container_lib.h"
-#include "gnunet_strings_lib.h"
-#include "gnunet_time_lib.h"
+#include "gnunet_util_lib.h"
+#if HAVE_EXTRACTOR_H
 #include <extractor.h>
+#endif
 #include <zlib.h>
 
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-container-meta-data", __VA_ARGS__)
+
+
+
+/**
+ * Try to compress the given block of data using libz.  Only returns
+ * the compressed block if compression worked and the new block is
+ * actually smaller.  Decompress using #GNUNET_decompress().
+ *
+ * @param data block to compress; if compression
+ *        resulted in a smaller block, the first
+ *        bytes of data are updated to the compressed
+ *        data
+ * @param old_size number of bytes in data
+ * @param[out] result set to the compressed data, if compression worked
+ * @param[out] new_size set to size of result, if compression worked
+ * @return #GNUNET_YES if compression reduce the size,
+ *         #GNUNET_NO if compression did not help
+ */
+int
+GNUNET_try_compression (const char *data,
+                        size_t old_size,
+                        char **result,
+                        size_t *new_size)
+{
+  char *tmp;
+  uLongf dlen;
+
+  *result = NULL;
+  *new_size = 0;
+#ifdef compressBound
+  dlen = compressBound (old_size);
+#else
+  dlen = old_size + (old_size / 100) + 20;
+  /* documentation says 100.1% oldSize + 12 bytes, but we
+   * 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,
+                 old_size, 9))
+  {
+    if (dlen < old_size)
+    {
+      *result = tmp;
+      *new_size = dlen;
+      return GNUNET_YES;
+    }
+  }
+  GNUNET_free (tmp);
+  return GNUNET_NO;
+}
+
+
+/**
+ * Decompress input, return the decompressed data as output.  Dual to
+ * #GNUNET_try_compression(). Caller must set @a output_size to the
+ * number of bytes that were originally compressed.
+ *
+ * @param input compressed data
+ * @param input_size number of bytes in input
+ * @param output_size expected size of the output
+ * @return NULL on error, buffer of @a output_size decompressed bytes otherwise
+ */
+char *
+GNUNET_decompress (const char *input,
+                   size_t input_size,
+                   size_t output_size)
+{
+  char *output;
+  uLongf olen;
+
+  olen = output_size;
+  output = GNUNET_malloc (olen);
+  if (Z_OK ==
+      uncompress ((Bytef *) output,
+                  &olen,
+                  (const Bytef *) input,
+                  input_size))
+    return output;
+  GNUNET_free (output);
+  return NULL;
+}
+
 
 /**
  * Meta data item.
@@ -123,7 +207,7 @@ struct GNUNET_CONTAINER_MetaData
 struct GNUNET_CONTAINER_MetaData *
 GNUNET_CONTAINER_meta_data_create ()
 {
-  return GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData));
+  return GNUNET_new (struct GNUNET_CONTAINER_MetaData);
 }
 
 
@@ -211,7 +295,7 @@ GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md)
  *
  * @param md1 first value to check
  * @param md2 other value to check
- * @return GNUNET_YES if they are equal
+ * @return #GNUNET_YES if they are equal
  */
 int
 GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
@@ -263,8 +347,8 @@ GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
  * @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 GNUNET_OK on success, GNUNET_SYSERR if this entry already exists
+ * @param data_size number of bytes in @a 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
@@ -279,6 +363,10 @@ GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
   struct MetaItem *mi;
   char *p;
 
+  if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
+      (EXTRACTOR_METAFORMAT_C_STRING == format))
+    GNUNET_break ('\0' == data[data_size - 1]);
+
   for (pos = md->items_head; NULL != pos; pos = pos->next)
   {
     if (pos->data_size < data_size)
@@ -301,7 +389,7 @@ GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
     }
   }
   md->item_count++;
-  mi = GNUNET_malloc (sizeof (struct MetaItem));
+  mi = GNUNET_new (struct MetaItem);
   mi->type = type;
   mi->format = format;
   mi->data_size = data_size;
@@ -318,7 +406,7 @@ GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
       (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);
+  GNUNET_memcpy (mi->data, data, data_size);
   /* change all dir separators to POSIX style ('/') */
   if ( (EXTRACTOR_METATYPE_FILENAME == type) ||
        (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type) )
@@ -339,7 +427,7 @@ 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 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
@@ -349,7 +437,7 @@ GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
  * @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
+ * @param data_size number of bytes in @a data
  * @return 0 (to continue)
  */
 static int
@@ -387,8 +475,8 @@ GNUNET_CONTAINER_meta_data_merge (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_size number of bytes in data
- * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md
+ * @param data_size number of bytes in @a 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,
@@ -431,7 +519,8 @@ GNUNET_CONTAINER_meta_data_add_publication_date (struct
   struct GNUNET_TIME_Absolute t;
 
   t = GNUNET_TIME_absolute_get ();
-  GNUNET_CONTAINER_meta_data_delete (md, EXTRACTOR_METATYPE_PUBLICATION_DATE,
+  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>",
@@ -480,8 +569,8 @@ GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md,
  * @return NULL if no entry was found
  */
 char *
-GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData
-                                        *md, enum EXTRACTOR_MetaType type)
+GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData *md,
+                                        enum EXTRACTOR_MetaType type)
 {
   struct MetaItem *pos;
 
@@ -514,7 +603,7 @@ GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
 {
   char *ret;
   va_list args;
-  enum EXTRACTOR_MetaType type;
+  int type;
 
   if (NULL == md)
     return NULL;
@@ -522,7 +611,7 @@ GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
   va_start (args, md);
   while (1)
   {
-    type = va_arg (args, enum EXTRACTOR_MetaType);
+    type = va_arg (args, int);
     if (-1 == type)
       break;
     if (NULL != (ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type)))
@@ -567,13 +656,13 @@ GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData
   if ((NULL == match) || (0 == match->data_size))
     return 0;
   *thumb = GNUNET_malloc (match->data_size);
-  memcpy (*thumb, match->data, match->data_size);
+  GNUNET_memcpy (*thumb, match->data, match->data_size);
   return match->data_size;
 }
 
 
 /**
- * Duplicate struct GNUNET_CONTAINER_MetaData.
+ * Duplicate a `struct GNUNET_CONTAINER_MetaData`.
  *
  * @param md what to duplicate
  * @return duplicate meta-data container
@@ -596,50 +685,6 @@ GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData
 }
 
 
-
-/**
- * Try to compress the given block of data.
- *
- * @param data block to compress; if compression
- *        resulted in a smaller block, the first
- *        bytes of data are updated to the compressed
- *        data
- * @param oldSize number of bytes in data
- * @param result set to the compressed data
- * @param newSize set to size of result
- * @return GNUNET_YES if compression reduce the size,
- *         GNUNET_NO if compression did not help
- */
-static int
-try_compression (const char *data, size_t oldSize, char **result,
-                 size_t * newSize)
-{
-  char *tmp;
-  uLongf dlen;
-
-#ifdef compressBound
-  dlen = compressBound (oldSize);
-#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 */
-#endif
-  tmp = GNUNET_malloc (dlen);
-  if (Z_OK ==
-      compress2 ((Bytef *) tmp, &dlen, (const Bytef *) data, oldSize, 9))
-  {
-    if (dlen < oldSize)
-    {
-      *result = tmp;
-      *newSize = dlen;
-      return GNUNET_YES;
-    }
-  }
-  GNUNET_free (tmp);
-  return GNUNET_NO;
-}
-
-
 /**
  * Flag in 'version' that indicates compressed meta-data.
  */
@@ -730,7 +775,7 @@ struct MetaDataEntry
  *        meta-data to match the size constraint,
  *        possibly discarding some data?
  * @return number of bytes written on success,
- *         GNUNET_SYSERR on error (typically: not enough
+ *         #GNUNET_SYSERR on error (typically: not enough
  *         space)
  */
 ssize_t
@@ -771,7 +816,7 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
     {
       if (NULL == *target)
         *target = GNUNET_malloc (md->sbuf_size);
-      memcpy (*target, md->sbuf, md->sbuf_size);
+      GNUNET_memcpy (*target, md->sbuf, md->sbuf_size);
       return md->sbuf_size;
     }
     if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
@@ -809,24 +854,27 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
     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)
+    if (NULL == pos->plugin_name)
       plen = 0;
     else
       plen = strlen (pos->plugin_name) + 1;
     ent[i].plugin_name_len = htonl ((uint32_t) plen);
-    if (pos->mime_type == NULL)
+    if (NULL == pos->mime_type)
       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);
+    if ((EXTRACTOR_METAFORMAT_UTF8 == pos->format) ||
+        (EXTRACTOR_METAFORMAT_C_STRING == pos->format))
+      GNUNET_break ('\0' == pos->data[pos->data_size - 1]);
+    GNUNET_memcpy (&mdata[off], pos->data, pos->data_size);
     off -= plen;
-    if (pos->plugin_name != NULL)
-      memcpy (&mdata[off], pos->plugin_name, plen);
+    if (NULL != pos->plugin_name)
+      GNUNET_memcpy (&mdata[off], pos->plugin_name, plen);
     off -= mlen;
-    if (pos->mime_type != NULL)
-      memcpy (&mdata[off], pos->mime_type, mlen);
+    if (NULL != pos->mime_type)
+      GNUNET_memcpy (&mdata[off], pos->mime_type, mlen);
     i++;
   }
   GNUNET_assert (0 == off);
@@ -839,7 +887,10 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
   {
     comp = GNUNET_NO;
     if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))
-      comp = try_compression ((const char *) &ent[i], left, &cdata, &clen);
+      comp = GNUNET_try_compression ((const char *) &ent[i],
+                                     left,
+                                     &cdata,
+                                     &clen);
 
     if ((NULL == md->sbuf) && (0 == i))
     {
@@ -854,13 +905,13 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
       {
         GNUNET_assert (clen < left);
         hdr->version = htonl (2 | HEADER_COMPRESSED);
-        memcpy (&hdr[1], cdata, clen);
+        GNUNET_memcpy (&hdr[1], cdata, clen);
         vmd->sbuf_size = clen + sizeof (struct MetaDataHeader);
       }
       else
       {
         hdr->version = htonl (2);
-        memcpy (&hdr[1], &ent[0], left);
+        GNUNET_memcpy (&hdr[1], &ent[0], left);
         vmd->sbuf_size = left + sizeof (struct MetaDataHeader);
       }
       vmd->sbuf = (char *) hdr;
@@ -878,7 +929,7 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
         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_memcpy (&dst[sizeof (struct MetaDataHeader)], cdata, clen);
         GNUNET_free (cdata);
        cdata = NULL;
         GNUNET_free (ent);
@@ -892,16 +943,16 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
         hdr->version = htonl (2);
         hdr->entries = htonl (md->item_count - i);
         hdr->size = htonl (left);
-        memcpy (&dst[sizeof (struct MetaDataHeader)], &ent[i], left);
+        GNUNET_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));
+          GNUNET_memcpy (*target, dst, clen + sizeof (struct MetaDataHeader));
         else
-          memcpy (*target, dst, left + sizeof (struct MetaDataHeader));
+          GNUNET_memcpy (*target, dst, left + sizeof (struct MetaDataHeader));
         GNUNET_free (dst);
       }
       else
@@ -939,8 +990,8 @@ GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
   ihdr.entries = htonl (0);
   ihdr.size = htonl (0);
   if (NULL == *target)
-    *target = GNUNET_malloc (sizeof (struct MetaDataHeader));
-  memcpy (*target, &ihdr, sizeof (struct MetaDataHeader));
+    *target = (char *) GNUNET_new (struct MetaDataHeader);
+  GNUNET_memcpy (*target, &ihdr, sizeof (struct MetaDataHeader));
   return sizeof (struct MetaDataHeader);
 }
 
@@ -970,32 +1021,6 @@ GNUNET_CONTAINER_meta_data_get_serialized_size (const struct
 }
 
 
-/**
- * Decompress input, return the decompressed data
- * as output, set outputSize to the number of bytes
- * that were found.
- *
- * @param input compressed data
- * @param inputSize number of bytes in input
- * @param outputSize expected size of the output
- * @return NULL on error
- */
-static char *
-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;
-  GNUNET_free (output);
-  return NULL;  
-}
-
-
 /**
  * Deserialize meta-data.  Initializes md.
  *
@@ -1029,7 +1054,7 @@ GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
 
   if (size < sizeof (struct MetaDataHeader))
     return NULL;
-  memcpy (&hdr, input, sizeof (struct MetaDataHeader));
+  GNUNET_memcpy (&hdr, input, sizeof (struct MetaDataHeader));
   version = ntohl (hdr.version) & HEADER_VERSION_MASK;
   compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0;
 
@@ -1043,7 +1068,9 @@ GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
 
   ic = ntohl (hdr.entries);
   dataSize = ntohl (hdr.size);
-  if ((sizeof (struct MetaDataEntry) * ic) > dataSize)
+  if ( ((sizeof (struct MetaDataEntry) * ic) > dataSize) ||
+       ( (0 != ic) &&
+         (dataSize / ic < sizeof (struct MetaDataEntry)) ) )
   {
     GNUNET_break_op (0);
     return NULL;
@@ -1059,8 +1086,9 @@ GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
       return NULL;
     }
     data =
-        decompress ((const char *) &input[sizeof (struct MetaDataHeader)],
-                    size - sizeof (struct MetaDataHeader), dataSize);
+      GNUNET_decompress ((const char *) &input[sizeof (struct MetaDataHeader)],
+                         size - sizeof (struct MetaDataHeader),
+                         dataSize);
     if (NULL == data)
     {
       GNUNET_break_op (0);
@@ -1084,7 +1112,7 @@ GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
   mdata = &cdata[ic * sizeof (struct MetaDataEntry)];
   for (i = 0; i < ic; i++)
   {
-    memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)],
+    GNUNET_memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)],
             sizeof (struct MetaDataEntry));
     format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format);
     if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
@@ -1107,7 +1135,12 @@ GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
     if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
         (EXTRACTOR_METAFORMAT_C_STRING == format))
     {
-      if ((0 == dlen) || ('\0' != mdata[left + dlen - 1]))
+      if (0 == dlen)
+      {
+        GNUNET_break_op (0);
+        break;
+      }
+      if ('\0' != meta_data[dlen - 1])
       {
         GNUNET_break_op (0);
         break;