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 2, 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 linked list.
45 struct MetaItem *next;
48 * Name of the extracting plugin.
58 * The actual meta data.
63 * Number of bytes in 'data'.
68 * Type of the meta data.
70 enum EXTRACTOR_MetaType type;
73 * Format of the meta data.
75 enum EXTRACTOR_MetaFormat format;
80 * Meta data to associate with a file, directory or namespace.
82 struct GNUNET_CONTAINER_MetaData
85 * Linked list of the meta data items.
87 struct MetaItem *items;
90 * Complete serialized and compressed buffer of the items.
91 * NULL if we have not computed that buffer yet.
96 * Number of bytes in 'sbuf'. 0 if the buffer is stale.
101 * Number of items in the linked list.
103 unsigned int item_count;
109 * Create a fresh struct CONTAINER_MetaData token.
111 * @return empty meta-data container
113 struct GNUNET_CONTAINER_MetaData *
114 GNUNET_CONTAINER_meta_data_create ()
116 return GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData));
121 * Free meta data item.
123 * @param item item to free
126 meta_item_free (struct MetaItem *item)
128 GNUNET_free_non_null (item->plugin_name);
129 GNUNET_free_non_null (item->mime_type);
130 GNUNET_free_non_null (item->data);
136 * The meta data has changed, invalidate its serialization
139 * @param md meta data that changed
142 invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md)
144 if (md->sbuf == NULL)
146 GNUNET_free (md->sbuf);
155 * @param md what to free
158 GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md)
160 struct MetaItem *item;
164 while (NULL != (item = md->items))
166 md->items = item->next;
167 meta_item_free (item);
169 GNUNET_free_non_null (md->sbuf);
175 * Remove all items in the container.
177 * @param md metadata to manipulate
180 GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md)
182 struct MetaItem *item;
186 while (NULL != (item = md->items))
188 md->items = item->next;
189 meta_item_free (item);
191 GNUNET_free_non_null (md->sbuf);
192 memset (md, 0, sizeof (struct GNUNET_CONTAINER_MetaData));
198 * Test if two MDs are equal. We consider them equal if
199 * the meta types, formats and content match (we do not
200 * include the mime types and plugins names in this
203 * @param md1 first value to check
204 * @param md2 other value to check
205 * @return GNUNET_YES if they are equal
208 GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData
210 const struct GNUNET_CONTAINER_MetaData
219 if (md1->item_count != md2->item_count)
229 if ((i->type == j->type) && (i->format == j->format) &&
230 (i->data_size == j->data_size) &&
231 (0 == memcmp (i->data, j->data, i->data_size)))
238 if (found == GNUNET_NO)
247 * Extend metadata. Note that the list of meta data items is
248 * sorted by size (largest first).
250 * @param md metadata to extend
251 * @param plugin_name name of the plugin that produced this value;
252 * special values can be used (i.e. '<zlib>' for zlib being
253 * used in the main libextractor library and yielding
255 * @param type libextractor-type describing the meta data
256 * @param format basic format information about data
257 * @param data_mime_type mime-type of data (not of the original file);
258 * can be NULL (if mime-type is not known)
259 * @param data actual meta-data found
260 * @param data_len number of bytes in data
261 * @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists
262 * data_mime_type and plugin_name are not considered for "exists" checks
265 GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md,
266 const char *plugin_name,
267 enum EXTRACTOR_MetaType type,
268 enum EXTRACTOR_MetaFormat format,
269 const char *data_mime_type, const char *data,
272 struct MetaItem *prev;
273 struct MetaItem *pos;
281 if (pos->data_size < data_len)
283 if ((pos->type == type) && (pos->data_size == data_len) &&
284 (0 == memcmp (pos->data, data, data_len)))
286 if ((pos->mime_type == NULL) && (data_mime_type != NULL))
288 pos->mime_type = GNUNET_strdup (data_mime_type);
289 invalidate_sbuf (md);
291 if ((pos->format == EXTRACTOR_METAFORMAT_C_STRING) &&
292 (format == EXTRACTOR_METAFORMAT_UTF8))
294 pos->format = EXTRACTOR_METAFORMAT_UTF8;
295 invalidate_sbuf (md);
297 return GNUNET_SYSERR;
303 i = GNUNET_malloc (sizeof (struct MetaItem));
306 i->data_size = data_len;
313 (data_mime_type == NULL) ? NULL : GNUNET_strdup (data_mime_type);
314 i->plugin_name = (plugin_name == NULL) ? NULL : GNUNET_strdup (plugin_name);
315 i->data = GNUNET_malloc (data_len);
316 memcpy (i->data, data, data_len);
317 /* change OS native dir separators to unix '/' and others to '_' */
318 if ( (type == EXTRACTOR_METATYPE_FILENAME) ||
319 (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) )
322 while ((*p != '\0') && (p < i->data + data_len))
324 if (*p == DIR_SEPARATOR)
331 invalidate_sbuf (md);
337 * Merge given meta data.
339 * @param cls the 'struct GNUNET_CONTAINER_MetaData' to merge into
340 * @param plugin_name name of the plugin that produced this value;
341 * special values can be used (i.e. '<zlib>' for zlib being
342 * used in the main libextractor library and yielding
344 * @param type libextractor-type describing the meta data
345 * @param format basic format information about data
346 * @param data_mime_type mime-type of data (not of the original file);
347 * can be NULL (if mime-type is not known)
348 * @param data actual meta-data found
349 * @param data_len number of bytes in data
350 * @return 0 (to continue)
353 merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type,
354 enum EXTRACTOR_MetaFormat format, const char *data_mime_type,
355 const char *data, size_t data_len)
357 struct GNUNET_CONTAINER_MetaData *md = cls;
359 (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format,
360 data_mime_type, data, data_len);
366 * Extend metadata. Merges the meta data from the second argument
367 * into the first, discarding duplicate key-value pairs.
369 * @param md metadata to extend
370 * @param in metadata to merge
373 GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md,
374 const struct GNUNET_CONTAINER_MetaData *in)
376 GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md);
383 * @param md metadata to manipulate
384 * @param type type of the item to remove
385 * @param data specific value to remove, NULL to remove all
386 * entries of the given type
387 * @param data_len number of bytes in data
388 * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md
391 GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md,
392 enum EXTRACTOR_MetaType type,
393 const char *data, size_t data_len)
395 struct MetaItem *pos;
396 struct MetaItem *prev;
402 if ((pos->type == type) &&
404 ((pos->data_size == data_len) &&
405 (0 == memcmp (pos->data, data, data_len)))))
408 md->items = pos->next;
410 prev->next = pos->next;
411 meta_item_free (pos);
413 invalidate_sbuf (md);
419 return GNUNET_SYSERR;
424 * Add the current time as the publication date
427 * @param md metadata to modify
430 GNUNET_CONTAINER_meta_data_add_publication_date (struct
431 GNUNET_CONTAINER_MetaData *md)
434 struct GNUNET_TIME_Absolute t;
436 t = GNUNET_TIME_absolute_get ();
437 GNUNET_CONTAINER_meta_data_delete (md, EXTRACTOR_METATYPE_PUBLICATION_DATE,
439 dat = GNUNET_STRINGS_absolute_time_to_string (t);
440 GNUNET_CONTAINER_meta_data_insert (md, "<gnunet>",
441 EXTRACTOR_METATYPE_PUBLICATION_DATE,
442 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
443 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;
471 iter (iter_cls, pos->plugin_name, pos->type, pos->format,
472 pos->mime_type, pos->data, pos->data_size))
473 return md->item_count;
476 return md->item_count;
481 * Get the first MD entry of the given type. Caller
482 * is responsible for freeing the return value.
483 * Also, only meta data items that are strings (0-terminated)
484 * are returned by this function.
486 * @param md metadata to inspect
487 * @param type type to look for
488 * @return NULL if no entry was found
491 GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData
492 *md, enum EXTRACTOR_MetaType type)
494 struct MetaItem *pos;
501 if ((type == pos->type) &&
502 ((pos->format == EXTRACTOR_METAFORMAT_UTF8) ||
503 (pos->format == EXTRACTOR_METAFORMAT_C_STRING)))
504 return GNUNET_strdup (pos->data);
512 * Get the first matching MD entry of the given types. Caller is
513 * responsible for freeing the return value. Also, only meta data
514 * items that are strings (0-terminated) are returned by this
517 * @param md metadata to inspect
518 * @param ... -1-terminated list of types
519 * @return NULL if we do not have any such entry,
520 * otherwise client is responsible for freeing the value!
523 GNUNET_CONTAINER_meta_data_get_first_by_types (const struct
524 GNUNET_CONTAINER_MetaData *md,
529 enum EXTRACTOR_MetaType type;
537 type = va_arg (args, enum EXTRACTOR_MetaType);
541 ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type);
551 * Get a thumbnail from the meta-data (if present).
553 * @param md metadata to get the thumbnail from
554 * @param thumb will be set to the thumbnail data. Must be
555 * freed by the caller!
556 * @return number of bytes in thumbnail, 0 if not available
559 GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData
560 * md, unsigned char **thumb)
562 struct MetaItem *pos;
563 struct MetaItem *match;
571 if ((NULL != pos->mime_type) &&
572 (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) &&
573 (pos->format == EXTRACTOR_METAFORMAT_BINARY))
577 else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) &&
578 (pos->type == EXTRACTOR_METATYPE_THUMBNAIL))
583 if ((match == NULL) || (match->data_size == 0))
585 *thumb = GNUNET_malloc (match->data_size);
586 memcpy (*thumb, match->data, match->data_size);
587 return match->data_size;
592 * Duplicate struct GNUNET_CONTAINER_MetaData.
594 * @param md what to duplicate
595 * @return duplicate meta-data container
597 struct GNUNET_CONTAINER_MetaData *
598 GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData
601 struct GNUNET_CONTAINER_MetaData *ret;
602 struct MetaItem *pos;
606 ret = GNUNET_CONTAINER_meta_data_create ();
610 GNUNET_CONTAINER_meta_data_insert (ret, pos->plugin_name, pos->type,
611 pos->format, pos->mime_type, pos->data,
621 * Try to compress the given block of data.
623 * @param data block to compress; if compression
624 * resulted in a smaller block, the first
625 * bytes of data are updated to the compressed
627 * @param oldSize number of bytes in data
628 * @param result set to the compressed data
629 * @param newSize set to size of result
630 * @return GNUNET_YES if compression reduce the size,
631 * GNUNET_NO if compression did not help
634 try_compression (const char *data, size_t oldSize, char **result,
641 dlen = compressBound (oldSize);
643 dlen = oldSize + (oldSize / 100) + 20;
644 /* documentation says 100.1% oldSize + 12 bytes, but we
645 * should be able to overshoot by more to be safe */
647 tmp = GNUNET_malloc (dlen);
649 compress2 ((Bytef *) tmp, &dlen, (const Bytef *) data, oldSize, 9))
664 * Flag in 'version' that indicates compressed meta-data.
666 #define HEADER_COMPRESSED 0x80000000
670 * Bits in 'version' that give the version number.
672 #define HEADER_VERSION_MASK 0x7FFFFFFF
676 * Header for serialized meta data.
678 struct MetaDataHeader
681 * The version of the MD serialization. The highest bit is used to
682 * indicate compression.
684 * Version 0 is traditional (pre-0.9) meta data (unsupported)
685 * Version is 1 for a NULL pointer
686 * Version 2 is for 0.9.x (and possibly higher)
687 * Other version numbers are not yet defined.
692 * How many MD entries are there?
697 * Size of the decompressed meta data.
702 * This is followed by 'entries' values of type 'struct MetaDataEntry'
703 * and then by 'entry' plugin names, mime-types and data blocks
704 * as specified in those meta data entries.
710 * Entry of serialized meta data.
715 * Meta data type. Corresponds to an 'enum EXTRACTOR_MetaType'
720 * Meta data format. Corresponds to an 'enum EXTRACTOR_MetaFormat'
725 * Number of bytes of meta data.
730 * Number of bytes in the plugin name including 0-terminator. 0 for NULL.
732 uint32_t plugin_name_len;
735 * Number of bytes in the mime type including 0-terminator. 0 for NULL.
737 uint32_t mime_type_len;
743 * Serialize meta-data to target.
745 * @param md metadata to serialize
746 * @param target where to write the serialized metadata;
747 * *target can be NULL, in which case memory is allocated
748 * @param max maximum number of bytes available in target
749 * @param opt is it ok to just write SOME of the
750 * meta-data to match the size constraint,
751 * possibly discarding some data?
752 * @return number of bytes written on success,
753 * GNUNET_SYSERR on error (typically: not enough
757 GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData
758 *md, char **target, size_t max,
760 GNUNET_CONTAINER_MetaDataSerializationOptions
763 struct GNUNET_CONTAINER_MetaData *vmd;
764 struct MetaItem *pos;
765 struct MetaDataHeader ihdr;
766 struct MetaDataHeader *hdr;
767 struct MetaDataEntry *ent;
782 if (max < sizeof (struct MetaDataHeader))
783 return GNUNET_SYSERR; /* far too small */
787 if (md->sbuf != NULL)
789 /* try to use serialization cache */
790 if (md->sbuf_size <= max)
793 *target = GNUNET_malloc (md->sbuf_size);
794 memcpy (*target, md->sbuf, md->sbuf_size);
795 return md->sbuf_size;
797 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
798 return GNUNET_SYSERR; /* can say that this will fail */
799 /* need to compute a partial serialization, sbuf useless ... */
806 msize += sizeof (struct MetaDataEntry);
807 msize += pos->data_size;
808 if (pos->plugin_name != NULL)
809 msize += strlen (pos->plugin_name) + 1;
810 if (pos->mime_type != NULL)
811 msize += strlen (pos->mime_type) + 1;
814 size = (size_t) msize;
817 GNUNET_break (0); /* integer overflow */
818 return GNUNET_SYSERR;
820 if (size >= GNUNET_MAX_MALLOC_CHECKED)
822 /* too large to be processed */
823 return GNUNET_SYSERR;
825 ent = GNUNET_malloc (size);
826 mdata = (char *) &ent[md->item_count];
827 off = size - (md->item_count * sizeof (struct MetaDataEntry));
832 ent[i].type = htonl ((uint32_t) pos->type);
833 ent[i].format = htonl ((uint32_t) pos->format);
834 ent[i].data_size = htonl ((uint32_t) pos->data_size);
835 if (pos->plugin_name == NULL)
838 plen = strlen (pos->plugin_name) + 1;
839 ent[i].plugin_name_len = htonl ((uint32_t) plen);
840 if (pos->mime_type == NULL)
843 mlen = strlen (pos->mime_type) + 1;
844 ent[i].mime_type_len = htonl ((uint32_t) mlen);
845 off -= pos->data_size;
846 memcpy (&mdata[off], pos->data, pos->data_size);
848 if (pos->plugin_name != NULL)
849 memcpy (&mdata[off], pos->plugin_name, plen);
851 if (pos->mime_type != NULL)
852 memcpy (&mdata[off], pos->mime_type, mlen);
856 GNUNET_assert (off == 0);
866 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS))
867 comp = try_compression ((const char *) &ent[i], left, &cdata, &clen);
869 if ((md->sbuf == NULL) && (i == 0))
871 /* fill 'sbuf'; this "modifies" md, but since this is only
872 * an internal cache we will cast away the 'const' instead
873 * of making the API look strange. */
874 vmd = (struct GNUNET_CONTAINER_MetaData *) md;
875 hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
876 hdr->size = htonl (left);
877 hdr->entries = htonl (md->item_count);
878 if (GNUNET_YES == comp)
880 GNUNET_assert (clen < left);
881 hdr->version = htonl (2 | HEADER_COMPRESSED);
882 memcpy (&hdr[1], cdata, clen);
883 vmd->sbuf_size = clen + sizeof (struct MetaDataHeader);
887 hdr->version = htonl (2);
888 memcpy (&hdr[1], &ent[0], left);
889 vmd->sbuf_size = left + sizeof (struct MetaDataHeader);
891 vmd->sbuf = (char *) hdr;
894 if (((left + sizeof (struct MetaDataHeader)) <= max) ||
895 ((comp == GNUNET_YES) && (clen <= max)))
897 /* success, this now fits! */
898 if (GNUNET_YES == comp)
901 dst = GNUNET_malloc (clen + sizeof (struct MetaDataHeader));
902 hdr = (struct MetaDataHeader *) dst;
903 hdr->version = htonl (2 | HEADER_COMPRESSED);
904 hdr->size = htonl (left);
905 hdr->entries = htonl (md->item_count - i);
906 memcpy (&dst[sizeof (struct MetaDataHeader)], cdata, clen);
909 rlen = clen + sizeof (struct MetaDataHeader);
914 dst = GNUNET_malloc (left + sizeof (struct MetaDataHeader));
915 hdr = (struct MetaDataHeader *) dst;
916 hdr->version = htonl (2);
917 hdr->entries = htonl (md->item_count - i);
918 hdr->size = htonl (left);
919 memcpy (&dst[sizeof (struct MetaDataHeader)], &ent[i], left);
921 rlen = left + sizeof (struct MetaDataHeader);
925 memcpy (*target, dst, clen + sizeof (struct MetaDataHeader));
935 if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART))
939 return GNUNET_SYSERR;
942 /* next iteration: ignore the corresponding meta data at the
943 * end and try again without it */
944 left -= sizeof (struct MetaDataEntry);
945 left -= pos->data_size;
946 if (pos->plugin_name != NULL)
947 left -= strlen (pos->plugin_name) + 1;
948 if (pos->mime_type != NULL)
949 left -= strlen (pos->mime_type) + 1;
955 /* nothing fit, only write header! */
956 ihdr.version = htonl (2);
957 ihdr.entries = htonl (0);
958 ihdr.size = htonl (0);
960 *target = GNUNET_malloc (sizeof (struct MetaDataHeader));
961 memcpy (*target, &ihdr, sizeof (struct MetaDataHeader));
962 return sizeof (struct MetaDataHeader);
967 * Get the size of the full meta-data in serialized form.
969 * @param md metadata to inspect
970 * @return number of bytes needed for serialization, -1 on error
973 GNUNET_CONTAINER_meta_data_get_serialized_size (const struct
974 GNUNET_CONTAINER_MetaData *md)
979 if (md->sbuf != NULL)
980 return md->sbuf_size;
983 GNUNET_CONTAINER_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED,
984 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
992 * Decompress input, return the decompressed data
993 * as output, set outputSize to the number of bytes
996 * @param input compressed data
997 * @param inputSize number of bytes in input
998 * @param outputSize expected size of the output
999 * @return NULL on error
1002 decompress (const char *input, size_t inputSize, size_t outputSize)
1008 output = GNUNET_malloc (olen);
1010 uncompress ((Bytef *) output, &olen, (const Bytef *) input, inputSize))
1016 GNUNET_free (output);
1023 * Deserialize meta-data. Initializes md.
1025 * @param input buffer with the serialized metadata
1026 * @param size number of bytes available in input
1027 * @return MD on success, NULL on error (i.e.
1030 struct GNUNET_CONTAINER_MetaData *
1031 GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size)
1033 struct GNUNET_CONTAINER_MetaData *md;
1034 struct MetaDataHeader hdr;
1035 struct MetaDataEntry ent;
1048 const char *meta_data;
1049 const char *plugin_name;
1050 const char *mime_type;
1051 enum EXTRACTOR_MetaFormat format;
1053 if (size < sizeof (struct MetaDataHeader))
1055 memcpy (&hdr, input, sizeof (struct MetaDataHeader));
1056 version = ntohl (hdr.version) & HEADER_VERSION_MASK;
1057 compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0;
1060 return NULL; /* null pointer */
1063 GNUNET_break_op (0); /* unsupported version */
1067 ic = ntohl (hdr.entries);
1068 dataSize = ntohl (hdr.size);
1069 if ((sizeof (struct MetaDataEntry) * ic) > dataSize)
1071 GNUNET_break_op (0);
1077 if (dataSize >= GNUNET_MAX_MALLOC_CHECKED)
1079 /* make sure we don't blow our memory limit because of a mal-formed
1081 GNUNET_break_op (0);
1085 decompress ((const char *) &input[sizeof (struct MetaDataHeader)],
1086 size - sizeof (struct MetaDataHeader), dataSize);
1089 GNUNET_break_op (0);
1097 cdata = (const char *) &input[sizeof (struct MetaDataHeader)];
1098 if (dataSize != size - sizeof (struct MetaDataHeader))
1100 GNUNET_break_op (0);
1105 md = GNUNET_CONTAINER_meta_data_create ();
1106 left = dataSize - ic * sizeof (struct MetaDataEntry);
1107 mdata = &cdata[ic * sizeof (struct MetaDataEntry)];
1108 for (i = 0; i < ic; i++)
1110 memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)],
1111 sizeof (struct MetaDataEntry));
1112 format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format);
1113 if ((format != EXTRACTOR_METAFORMAT_UTF8) &&
1114 (format != EXTRACTOR_METAFORMAT_C_STRING) &&
1115 (format != EXTRACTOR_METAFORMAT_BINARY))
1117 GNUNET_break_op (0);
1120 dlen = ntohl (ent.data_size);
1121 plen = ntohl (ent.plugin_name_len);
1122 mlen = ntohl (ent.mime_type_len);
1125 GNUNET_break_op (0);
1129 meta_data = &mdata[left];
1130 if ((format == EXTRACTOR_METAFORMAT_UTF8) ||
1131 (format == EXTRACTOR_METAFORMAT_C_STRING))
1133 if ((dlen == 0) || (mdata[left + dlen - 1] != '\0'))
1135 GNUNET_break_op (0);
1141 GNUNET_break_op (0);
1145 if ((plen > 0) && (mdata[left + plen - 1] != '\0'))
1147 GNUNET_break_op (0);
1153 plugin_name = &mdata[left];
1157 GNUNET_break_op (0);
1161 if ((mlen > 0) && (mdata[left + mlen - 1] != '\0'))
1163 GNUNET_break_op (0);
1169 mime_type = &mdata[left];
1170 GNUNET_CONTAINER_meta_data_insert (md, plugin_name,
1171 (enum EXTRACTOR_MetaType)
1172 ntohl (ent.type), format, mime_type,
1175 GNUNET_free_non_null (data);
1180 /* end of container_meta_data.c */