2 This file is part of GNUnet.
3 (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file util/container_meta_data.c
23 * @brief Storing of meta data
24 * @author Christian Grothoff
28 #include "gnunet_common.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_strings_lib.h"
31 #include "gnunet_time_lib.h"
32 #include <extractor.h>
35 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
43 * This is a doubly linked list.
45 struct MetaItem *next;
48 * This is a doubly linked list.
50 struct MetaItem *prev;
53 * Name of the extracting plugin.
63 * The actual meta data.
68 * Number of bytes in 'data'.
73 * Type of the meta data.
75 enum EXTRACTOR_MetaType type;
78 * Format of the meta data.
80 enum EXTRACTOR_MetaFormat format;
85 * Meta data to associate with a file, directory or namespace.
87 struct GNUNET_CONTAINER_MetaData
90 * Head of linked list of the meta data items.
92 struct MetaItem *items_head;
95 * Tail of linked list of the meta data items.
97 struct MetaItem *items_tail;
100 * Complete serialized and compressed buffer of the items.
101 * NULL if we have not computed that buffer yet.
106 * Number of bytes in 'sbuf'. 0 if the buffer is stale.
111 * Number of items in the linked list.
113 unsigned int item_count;
119 * Create a fresh struct CONTAINER_MetaData token.
121 * @return empty meta-data container
123 struct GNUNET_CONTAINER_MetaData *
124 GNUNET_CONTAINER_meta_data_create ()
126 return GNUNET_new (struct GNUNET_CONTAINER_MetaData);
131 * Free meta data item.
133 * @param mi item to free
136 meta_item_free (struct MetaItem *mi)
138 GNUNET_free_non_null (mi->plugin_name);
139 GNUNET_free_non_null (mi->mime_type);
140 GNUNET_free_non_null (mi->data);
146 * The meta data has changed, invalidate its serialization
149 * @param md meta data that changed
152 invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md)
154 if (NULL == md->sbuf)
156 GNUNET_free (md->sbuf);
165 * @param md what to free
168 GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md)
170 struct MetaItem *pos;
174 while (NULL != (pos = md->items_head))
176 GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos);
177 meta_item_free (pos);
179 GNUNET_free_non_null (md->sbuf);
185 * Remove all items in the container.
187 * @param md metadata to manipulate
190 GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md)
196 while (NULL != (mi = md->items_head))
198 GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, mi);
201 GNUNET_free_non_null (md->sbuf);
202 memset (md, 0, sizeof (struct GNUNET_CONTAINER_MetaData));
207 * Test if two MDs are equal. We consider them equal if
208 * the meta types, formats and content match (we do not
209 * include the mime types and plugins names in this
212 * @param md1 first value to check
213 * @param md2 other value to check
214 * @return #GNUNET_YES if they are equal
217 GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
219 const struct GNUNET_CONTAINER_MetaData
228 if (md1->item_count != md2->item_count)
230 for (i = md1->items_head; NULL != i; i = i->next)
233 for (j = md2->items_head; NULL != j; j = j->next)
235 if ((i->type == j->type) && (i->format == j->format) &&
236 (i->data_size == j->data_size) &&
237 (0 == memcmp (i->data, j->data, i->data_size)))
242 if (j->data_size < i->data_size)
243 break; /* elements are sorted by (decreasing) size... */
245 if (GNUNET_NO == found)
253 * Extend metadata. Note that the list of meta data items is
254 * sorted by size (largest first).
256 * @param md metadata to extend
257 * @param plugin_name name of the plugin that produced this value;
258 * special values can be used (i.e. '<zlib>' for zlib being
259 * used in the main libextractor library and yielding
261 * @param type libextractor-type describing the meta data
262 * @param format basic format information about data
263 * @param data_mime_type mime-type of data (not of the original file);
264 * can be NULL (if mime-type is not known)
265 * @param data actual meta-data found
266 * @param data_size number of bytes in @a data
267 * @return #GNUNET_OK on success, #GNUNET_SYSERR if this entry already exists
268 * data_mime_type and plugin_name are not considered for "exists" checks
271 GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
272 const char *plugin_name,
273 enum EXTRACTOR_MetaType type,
274 enum EXTRACTOR_MetaFormat format,
275 const char *data_mime_type, const char *data,
278 struct MetaItem *pos;
282 if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
283 (EXTRACTOR_METAFORMAT_C_STRING == format))
284 GNUNET_break ('\0' == data[data_size - 1]);
286 for (pos = md->items_head; NULL != pos; pos = pos->next)
288 if (pos->data_size < data_size)
289 break; /* elements are sorted by size in the list */
290 if ((pos->type == type) && (pos->data_size == data_size) &&
291 (0 == memcmp (pos->data, data, data_size)))
293 if ((NULL == pos->mime_type) && (NULL != data_mime_type))
295 pos->mime_type = GNUNET_strdup (data_mime_type);
296 invalidate_sbuf (md);
298 if ((EXTRACTOR_METAFORMAT_C_STRING == pos->format) &&
299 (EXTRACTOR_METAFORMAT_UTF8 == format))
301 pos->format = EXTRACTOR_METAFORMAT_UTF8;
302 invalidate_sbuf (md);
304 return GNUNET_SYSERR;
308 mi = GNUNET_new (struct MetaItem);
311 mi->data_size = data_size;
313 GNUNET_CONTAINER_DLL_insert_tail (md->items_head,
317 GNUNET_CONTAINER_DLL_insert_after (md->items_head,
322 (NULL == data_mime_type) ? NULL : GNUNET_strdup (data_mime_type);
323 mi->plugin_name = (NULL == plugin_name) ? NULL : GNUNET_strdup (plugin_name);
324 mi->data = GNUNET_malloc (data_size);
325 memcpy (mi->data, data, data_size);
326 /* change all dir separators to POSIX style ('/') */
327 if ( (EXTRACTOR_METATYPE_FILENAME == type) ||
328 (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type) )
331 while (('\0' != *p) && (p < mi->data + data_size))
338 invalidate_sbuf (md);
344 * Merge given meta data.
346 * @param cls the `struct GNUNET_CONTAINER_MetaData` to merge into
347 * @param plugin_name name of the plugin that produced this value;
348 * special values can be used (i.e. '<zlib>' for zlib being
349 * used in the main libextractor library and yielding
351 * @param type libextractor-type describing the meta data
352 * @param format basic format information about data
353 * @param data_mime_type mime-type of data (not of the original file);
354 * can be NULL (if mime-type is not known)
355 * @param data actual meta-data found
356 * @param data_size number of bytes in @a data
357 * @return 0 (to continue)
360 merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type,
361 enum EXTRACTOR_MetaFormat format, const char *data_mime_type,
362 const char *data, size_t data_size)
364 struct GNUNET_CONTAINER_MetaData *md = cls;
366 (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
367 data_mime_type, data, data_size);
373 * Extend metadata. Merges the meta data from the second argument
374 * into the first, discarding duplicate key-value pairs.
376 * @param md metadata to extend
377 * @param in metadata to merge
380 GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md,
381 const struct GNUNET_CONTAINER_MetaData *in)
383 GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md);
390 * @param md metadata to manipulate
391 * @param type type of the item to remove
392 * @param data specific value to remove, NULL to remove all
393 * entries of the given type
394 * @param data_size number of bytes in @a data
395 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the item does not exist in md
398 GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md,
399 enum EXTRACTOR_MetaType type,
400 const char *data, size_t data_size)
402 struct MetaItem *pos;
404 for (pos = md->items_head; NULL != pos; pos = pos->next)
406 if (pos->data_size < data_size)
407 break; /* items are sorted by (decreasing) size */
408 if ((pos->type == type) &&
410 ((pos->data_size == data_size) &&
411 (0 == memcmp (pos->data, data, data_size)))))
413 GNUNET_CONTAINER_DLL_remove (md->items_head, md->items_tail, pos);
414 meta_item_free (pos);
416 invalidate_sbuf (md);
420 return GNUNET_SYSERR;
425 * Add the current time as the publication date
428 * @param md metadata to modify
431 GNUNET_CONTAINER_meta_data_add_publication_date (struct
432 GNUNET_CONTAINER_MetaData *md)
435 struct GNUNET_TIME_Absolute t;
437 t = GNUNET_TIME_absolute_get ();
438 GNUNET_CONTAINER_meta_data_delete (md, EXTRACTOR_METATYPE_PUBLICATION_DATE,
440 dat = GNUNET_STRINGS_absolute_time_to_string (t);
441 GNUNET_CONTAINER_meta_data_insert (md, "<gnunet>",
442 EXTRACTOR_METATYPE_PUBLICATION_DATE,
443 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
444 dat, strlen (dat) + 1);
449 * Iterate over MD entries.
451 * @param md metadata to inspect
452 * @param iter function to call on each entry
453 * @param iter_cls closure for iterator
454 * @return number of entries
457 GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md,
458 EXTRACTOR_MetaDataProcessor iter,
461 struct MetaItem *pos;
466 return md->item_count;
467 for (pos = md->items_head; NULL != pos; pos = pos->next)
469 iter (iter_cls, pos->plugin_name, pos->type, pos->format,
470 pos->mime_type, pos->data, pos->data_size))
471 return md->item_count;
472 return md->item_count;
477 * Get the first MD entry of the given type. Caller
478 * is responsible for freeing the return value.
479 * Also, only meta data items that are strings (0-terminated)
480 * are returned by this function.
482 * @param md metadata to inspect
483 * @param type type to look for
484 * @return NULL if no entry was found
487 GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData
488 *md, enum EXTRACTOR_MetaType type)
490 struct MetaItem *pos;
494 for (pos = md->items_head; NULL != pos; pos = pos->next)
495 if ((type == pos->type) &&
496 ((pos->format == EXTRACTOR_METAFORMAT_UTF8) ||
497 (pos->format == EXTRACTOR_METAFORMAT_C_STRING)))
498 return GNUNET_strdup (pos->data);
504 * Get the first matching MD entry of the given types. Caller is
505 * responsible for freeing the return value. Also, only meta data
506 * items that are strings (0-terminated) are returned by this
509 * @param md metadata to inspect
510 * @param ... -1-terminated list of types
511 * @return NULL if we do not have any such entry,
512 * otherwise client is responsible for freeing the value!
515 GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
516 GNUNET_CONTAINER_MetaData *md,
521 enum EXTRACTOR_MetaType type;
529 type = va_arg (args, enum EXTRACTOR_MetaType);
532 if (NULL != (ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type)))
541 * Get a thumbnail from the meta-data (if present).
543 * @param md metadata to get the thumbnail from
544 * @param thumb will be set to the thumbnail data. Must be
545 * freed by the caller!
546 * @return number of bytes in thumbnail, 0 if not available
549 GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData
550 * md, unsigned char **thumb)
552 struct MetaItem *pos;
553 struct MetaItem *match;
558 for (pos = md->items_head; NULL != pos; pos = pos->next)
560 if ((NULL != pos->mime_type) &&
561 (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) &&
562 (EXTRACTOR_METAFORMAT_BINARY == pos->format))
566 else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) &&
567 (pos->type == EXTRACTOR_METATYPE_THUMBNAIL))
571 if ((NULL == match) || (0 == match->data_size))
573 *thumb = GNUNET_malloc (match->data_size);
574 memcpy (*thumb, match->data, match->data_size);
575 return match->data_size;
580 * Duplicate a `struct GNUNET_CONTAINER_MetaData`.
582 * @param md what to duplicate
583 * @return duplicate meta-data container
585 struct GNUNET_CONTAINER_MetaData *
586 GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData
589 struct GNUNET_CONTAINER_MetaData *ret;
590 struct MetaItem *pos;
594 ret = GNUNET_CONTAINER_meta_data_create ();
595 for (pos = md->items_tail; NULL != pos; pos = pos->prev)
596 GNUNET_CONTAINER_meta_data_insert (ret, pos->plugin_name, pos->type,
597 pos->format, pos->mime_type, pos->data,
605 * Try to compress the given block of data.
607 * @param data block to compress; if compression
608 * resulted in a smaller block, the first
609 * bytes of data are updated to the compressed
611 * @param oldSize number of bytes in data
612 * @param result set to the compressed data
613 * @param newSize set to size of result
614 * @return #GNUNET_YES if compression reduce the size,
615 * #GNUNET_NO if compression did not help
618 try_compression (const char *data, size_t oldSize, char **result,
625 dlen = compressBound (oldSize);
627 dlen = oldSize + (oldSize / 100) + 20;
628 /* documentation says 100.1% oldSize + 12 bytes, but we
629 * should be able to overshoot by more to be safe */
631 tmp = GNUNET_malloc (dlen);
633 compress2 ((Bytef *) tmp, &dlen, (const Bytef *) data, oldSize, 9))
648 * Flag in 'version' that indicates compressed meta-data.
650 #define HEADER_COMPRESSED 0x80000000
654 * Bits in 'version' that give the version number.
656 #define HEADER_VERSION_MASK 0x7FFFFFFF
660 * Header for serialized meta data.
662 struct MetaDataHeader
665 * The version of the MD serialization. The highest bit is used to
666 * indicate compression.
668 * Version 0 is traditional (pre-0.9) meta data (unsupported)
669 * Version is 1 for a NULL pointer
670 * Version 2 is for 0.9.x (and possibly higher)
671 * Other version numbers are not yet defined.
676 * How many MD entries are there?
681 * Size of the decompressed meta data.
686 * This is followed by 'entries' values of type 'struct MetaDataEntry'
687 * and then by 'entry' plugin names, mime-types and data blocks
688 * as specified in those meta data entries.
694 * Entry of serialized meta data.
699 * Meta data type. Corresponds to an 'enum EXTRACTOR_MetaType'
704 * Meta data format. Corresponds to an 'enum EXTRACTOR_MetaFormat'
709 * Number of bytes of meta data.
714 * Number of bytes in the plugin name including 0-terminator. 0 for NULL.
716 uint32_t plugin_name_len;
719 * Number of bytes in the mime type including 0-terminator. 0 for NULL.
721 uint32_t mime_type_len;
727 * Serialize meta-data to target.
729 * @param md metadata to serialize
730 * @param target where to write the serialized metadata;
731 * *target can be NULL, in which case memory is allocated
732 * @param max maximum number of bytes available in target
733 * @param opt is it ok to just write SOME of the
734 * meta-data to match the size constraint,
735 * possibly discarding some data?
736 * @return number of bytes written on success,
737 * #GNUNET_SYSERR on error (typically: not enough
741 GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
742 *md, char **target, size_t max,
744 GNUNET_CONTAINER_MetaDataSerializationOptions
747 struct GNUNET_CONTAINER_MetaData *vmd;
748 struct MetaItem *pos;
749 struct MetaDataHeader ihdr;
750 struct MetaDataHeader *hdr;
751 struct MetaDataEntry *ent;
766 if (max < sizeof (struct MetaDataHeader))
767 return GNUNET_SYSERR; /* far too small */
771 if (NULL != md->sbuf)
773 /* try to use serialization cache */
774 if (md->sbuf_size <= max)
777 *target = GNUNET_malloc (md->sbuf_size);
778 memcpy (*target, md->sbuf, md->sbuf_size);
779 return md->sbuf_size;
781 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
782 return GNUNET_SYSERR; /* can say that this will fail */
783 /* need to compute a partial serialization, sbuf useless ... */
787 for (pos = md->items_tail; NULL != pos; pos = pos->prev)
789 msize += sizeof (struct MetaDataEntry);
790 msize += pos->data_size;
791 if (NULL != pos->plugin_name)
792 msize += strlen (pos->plugin_name) + 1;
793 if (NULL != pos->mime_type)
794 msize += strlen (pos->mime_type) + 1;
796 size = (size_t) msize;
799 GNUNET_break (0); /* integer overflow */
800 return GNUNET_SYSERR;
802 if (size >= GNUNET_MAX_MALLOC_CHECKED)
804 /* too large to be processed */
805 return GNUNET_SYSERR;
807 ent = GNUNET_malloc (size);
808 mdata = (char *) &ent[md->item_count];
809 off = size - (md->item_count * sizeof (struct MetaDataEntry));
811 for (pos = md->items_head; NULL != pos; pos = pos->next)
813 ent[i].type = htonl ((uint32_t) pos->type);
814 ent[i].format = htonl ((uint32_t) pos->format);
815 ent[i].data_size = htonl ((uint32_t) pos->data_size);
816 if (NULL == pos->plugin_name)
819 plen = strlen (pos->plugin_name) + 1;
820 ent[i].plugin_name_len = htonl ((uint32_t) plen);
821 if (NULL == pos->mime_type)
824 mlen = strlen (pos->mime_type) + 1;
825 ent[i].mime_type_len = htonl ((uint32_t) mlen);
826 off -= pos->data_size;
827 if ((EXTRACTOR_METAFORMAT_UTF8 == pos->format) ||
828 (EXTRACTOR_METAFORMAT_C_STRING == pos->format))
829 GNUNET_break ('\0' == pos->data[pos->data_size - 1]);
830 memcpy (&mdata[off], pos->data, pos->data_size);
832 if (NULL != pos->plugin_name)
833 memcpy (&mdata[off], pos->plugin_name, plen);
835 if (NULL != pos->mime_type)
836 memcpy (&mdata[off], pos->mime_type, mlen);
839 GNUNET_assert (0 == off);
845 for (pos = md->items_head; NULL != pos; pos = pos->next)
848 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))
849 comp = try_compression ((const char *) &ent[i], left, &cdata, &clen);
851 if ((NULL == md->sbuf) && (0 == i))
853 /* fill 'sbuf'; this "modifies" md, but since this is only
854 * an internal cache we will cast away the 'const' instead
855 * of making the API look strange. */
856 vmd = (struct GNUNET_CONTAINER_MetaData *) md;
857 hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
858 hdr->size = htonl (left);
859 hdr->entries = htonl (md->item_count);
860 if (GNUNET_YES == comp)
862 GNUNET_assert (clen < left);
863 hdr->version = htonl (2 | HEADER_COMPRESSED);
864 memcpy (&hdr[1], cdata, clen);
865 vmd->sbuf_size = clen + sizeof (struct MetaDataHeader);
869 hdr->version = htonl (2);
870 memcpy (&hdr[1], &ent[0], left);
871 vmd->sbuf_size = left + sizeof (struct MetaDataHeader);
873 vmd->sbuf = (char *) hdr;
876 if (((left + sizeof (struct MetaDataHeader)) <= max) ||
877 ((GNUNET_YES == comp) && (clen <= max)))
879 /* success, this now fits! */
880 if (GNUNET_YES == comp)
883 dst = GNUNET_malloc (clen + sizeof (struct MetaDataHeader));
884 hdr = (struct MetaDataHeader *) dst;
885 hdr->version = htonl (2 | HEADER_COMPRESSED);
886 hdr->size = htonl (left);
887 hdr->entries = htonl (md->item_count - i);
888 memcpy (&dst[sizeof (struct MetaDataHeader)], cdata, clen);
892 rlen = clen + sizeof (struct MetaDataHeader);
897 dst = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
898 hdr = (struct MetaDataHeader *) dst;
899 hdr->version = htonl (2);
900 hdr->entries = htonl (md->item_count - i);
901 hdr->size = htonl (left);
902 memcpy (&dst[sizeof (struct MetaDataHeader)], &ent[i], left);
904 rlen = left + sizeof (struct MetaDataHeader);
908 if (GNUNET_YES == comp)
909 memcpy (*target, dst, clen + sizeof (struct MetaDataHeader));
911 memcpy (*target, dst, left + sizeof (struct MetaDataHeader));
921 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
925 return GNUNET_SYSERR;
928 /* next iteration: ignore the corresponding meta data at the
929 * end and try again without it */
930 left -= sizeof (struct MetaDataEntry);
931 left -= pos->data_size;
932 if (NULL != pos->plugin_name)
933 left -= strlen (pos->plugin_name) + 1;
934 if (NULL != pos->mime_type)
935 left -= strlen (pos->mime_type) + 1;
937 GNUNET_free_non_null (cdata);
944 /* nothing fit, only write header! */
945 ihdr.version = htonl (2);
946 ihdr.entries = htonl (0);
947 ihdr.size = htonl (0);
949 *target = (char *) GNUNET_new (struct MetaDataHeader);
950 memcpy (*target, &ihdr, sizeof (struct MetaDataHeader));
951 return sizeof (struct MetaDataHeader);
956 * Get the size of the full meta-data in serialized form.
958 * @param md metadata to inspect
959 * @return number of bytes needed for serialization, -1 on error
962 GNUNET_CONTAINER_meta_data_get_serialized_size (const struct
963 GNUNET_CONTAINER_MetaData *md)
968 if (NULL != md->sbuf)
969 return md->sbuf_size;
972 GNUNET_CONTAINER_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED,
973 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
981 * Decompress input, return the decompressed data
982 * as output, set outputSize to the number of bytes
985 * @param input compressed data
986 * @param inputSize number of bytes in input
987 * @param outputSize expected size of the output
988 * @return NULL on error
991 decompress (const char *input, size_t inputSize, size_t outputSize)
997 output = GNUNET_malloc (olen);
999 uncompress ((Bytef *) output, &olen, (const Bytef *) input, inputSize))
1001 GNUNET_free (output);
1007 * Deserialize meta-data. Initializes md.
1009 * @param input buffer with the serialized metadata
1010 * @param size number of bytes available in input
1011 * @return MD on success, NULL on error (i.e.
1014 struct GNUNET_CONTAINER_MetaData *
1015 GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
1017 struct GNUNET_CONTAINER_MetaData *md;
1018 struct MetaDataHeader hdr;
1019 struct MetaDataEntry ent;
1032 const char *meta_data;
1033 const char *plugin_name;
1034 const char *mime_type;
1035 enum EXTRACTOR_MetaFormat format;
1037 if (size < sizeof (struct MetaDataHeader))
1039 memcpy (&hdr, input, sizeof (struct MetaDataHeader));
1040 version = ntohl (hdr.version) & HEADER_VERSION_MASK;
1041 compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0;
1044 return NULL; /* null pointer */
1047 GNUNET_break_op (0); /* unsupported version */
1051 ic = ntohl (hdr.entries);
1052 dataSize = ntohl (hdr.size);
1053 if ((sizeof (struct MetaDataEntry) * ic) > dataSize)
1055 GNUNET_break_op (0);
1061 if (dataSize >= GNUNET_MAX_MALLOC_CHECKED)
1063 /* make sure we don't blow our memory limit because of a mal-formed
1065 GNUNET_break_op (0);
1069 decompress ((const char *) &input[sizeof (struct MetaDataHeader)],
1070 size - sizeof (struct MetaDataHeader), dataSize);
1073 GNUNET_break_op (0);
1081 cdata = (const char *) &input[sizeof (struct MetaDataHeader)];
1082 if (dataSize != size - sizeof (struct MetaDataHeader))
1084 GNUNET_break_op (0);
1089 md = GNUNET_CONTAINER_meta_data_create ();
1090 left = dataSize - ic * sizeof (struct MetaDataEntry);
1091 mdata = &cdata[ic * sizeof (struct MetaDataEntry)];
1092 for (i = 0; i < ic; i++)
1094 memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)],
1095 sizeof (struct MetaDataEntry));
1096 format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format);
1097 if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
1098 (EXTRACTOR_METAFORMAT_C_STRING != format) &&
1099 (EXTRACTOR_METAFORMAT_BINARY != format))
1101 GNUNET_break_op (0);
1104 dlen = ntohl (ent.data_size);
1105 plen = ntohl (ent.plugin_name_len);
1106 mlen = ntohl (ent.mime_type_len);
1109 GNUNET_break_op (0);
1113 meta_data = &mdata[left];
1114 if ((EXTRACTOR_METAFORMAT_UTF8 == format) ||
1115 (EXTRACTOR_METAFORMAT_C_STRING == format))
1119 GNUNET_break_op (0);
1122 if ('\0' != meta_data[dlen - 1])
1124 GNUNET_break_op (0);
1130 GNUNET_break_op (0);
1134 if ((plen > 0) && ('\0' != mdata[left + plen - 1]))
1136 GNUNET_break_op (0);
1142 plugin_name = &mdata[left];
1146 GNUNET_break_op (0);
1150 if ((mlen > 0) && ('\0' != mdata[left + mlen - 1]))
1152 GNUNET_break_op (0);
1158 mime_type = &mdata[left];
1159 GNUNET_CONTAINER_meta_data_insert (md, plugin_name,
1160 (enum EXTRACTOR_MetaType)
1161 ntohl (ent.type), format, mime_type,
1164 GNUNET_free_non_null (data);
1169 /* end of container_meta_data.c */