📄 meta.c
字号:
/** * Decompress input, return the decompressed data * as output, set outputSize to the number of bytes * that were found. * * @return NULL on error */static char *decompress (const char *input, unsigned int inputSize, unsigned int 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; }}/** * Flag in 'version' that indicates compressed meta-data. */#define HEADER_COMPRESSED 0x80000000/** * Bits in 'version' that give the version number. */#define HEADER_VERSION_MASK 0x7FFFFFFFtypedef struct{ /** * The version of the MD serialization. * The highest bit is used to indicate * compression. * * Version 0 is the current version; * Version is 1 for a NULL pointer. * Other version numbers are not yet defined. */ unsigned int version; /** * How many MD entries are there? */ unsigned int entries; /** * Size of the MD (decompressed) */ unsigned int size; /** * This is followed by 'entries' values of type 'unsigned int' that * correspond to EXTRACTOR_KeywordTypes. After that, the meta-data * keywords follow (0-terminated). The MD block always ends with * 0-termination, padding with 0 until a multiple of 8 bytes. */} MetaDataHeader;/** * Serialize meta-data to target. * * @param size maximum number of bytes available * @param part is it ok to just write SOME of the * meta-data to match the size constraint, * possibly discarding some data? GNUNET_YES/GNUNET_NO. * @return number of bytes written on success, * GNUNET_SYSERR on error (typically: not enough * space) */intGNUNET_meta_data_serialize (struct GNUNET_GE_Context *ectx, const MetaData * md, char *target, unsigned int max, int part){ MetaDataHeader *hdr; size_t size; size_t pos; int i; int len; unsigned int ic; if (max < sizeof (MetaDataHeader)) return GNUNET_SYSERR; /* far too small */ ic = md ? md->itemCount : 0; hdr = NULL; while (1) { size = sizeof (MetaDataHeader); size += sizeof (unsigned int) * ic; for (i = 0; i < ic; i++) size += 1 + strlen (md->items[i].data); while (size % 8 != 0) size++; hdr = GNUNET_malloc (size); hdr->version = htonl (md == NULL ? 1 : 0); hdr->entries = htonl (ic); for (i = 0; i < ic; i++) ((unsigned int *) &hdr[1])[i] = htonl ((unsigned int) md->items[i].type); pos = sizeof (MetaDataHeader); pos += sizeof (unsigned int) * ic; for (i = 0; i < ic; i++) { len = strlen (md->items[i].data) + 1; memcpy (&((char *) hdr)[pos], md->items[i].data, len); pos += len; } hdr->size = htonl (size); if ((part & GNUNET_SERIALIZE_NO_COMPRESS) == 0) { pos = tryCompression ((char *) &hdr[1], size - sizeof (MetaDataHeader)); } else { pos = size - sizeof (MetaDataHeader); } if (pos < size - sizeof (MetaDataHeader)) { hdr->version = htonl (HEADER_COMPRESSED); size = pos + sizeof (MetaDataHeader); } if (size <= max) break; GNUNET_free (hdr); hdr = NULL; if ((part & GNUNET_SERIALIZE_PART) == 0) { return GNUNET_SYSERR; /* does not fit! */ } /* partial serialization ok, try again with less meta-data */ if (size > 2 * max) ic = ic * 2 / 3; /* still far too big, make big reductions */ else ic--; /* small steps, we're close */ } GNUNET_GE_ASSERT (ectx, size <= max); memcpy (target, hdr, size); GNUNET_free (hdr); /* extra check: deserialize! */#if EXTRA_CHECKS { MetaData *mdx; mdx = GNUNET_meta_data_deserialize (ectx, target, size); GNUNET_GE_ASSERT (ectx, NULL != mdx); GNUNET_meta_data_destroy (mdx); }#endif return size;}/** * Estimate (!) the size of the meta-data in * serialized form. The estimate MAY be higher * than what is strictly needed. */unsigned intGNUNET_meta_data_get_serialized_size (const MetaData * md, int part){ MetaDataHeader *hdr; size_t size; size_t pos; int i; int len; unsigned int ic; ic = md ? md->itemCount : 0; size = sizeof (MetaDataHeader); size += sizeof (unsigned int) * ic; for (i = 0; i < ic; i++) size += 1 + strlen (md->items[i].data); while (size % 8 != 0) size++; hdr = GNUNET_malloc (size); hdr->version = htonl (md == NULL ? 1 : 0); hdr->entries = htonl (ic); for (i = 0; i < ic; i++) ((unsigned int *) &hdr[1])[i] = htonl ((unsigned int) md->items[i].type); pos = sizeof (MetaDataHeader); pos += sizeof (unsigned int) * ic; for (i = 0; i < ic; i++) { len = strlen (md->items[i].data) + 1; memcpy (&((char *) hdr)[pos], md->items[i].data, len); pos += len; } if ((part & GNUNET_SERIALIZE_NO_COMPRESS) == 0) { pos = tryCompression ((char *) &hdr[1], size - sizeof (MetaDataHeader)); } else { pos = size - sizeof (MetaDataHeader); } if (pos < size - sizeof (MetaDataHeader)) size = pos + sizeof (MetaDataHeader); GNUNET_free (hdr); return size;}/** * Deserialize meta-data. Initializes md. * @param size number of bytes available * @return MD on success, NULL on error (i.e. * bad format) */struct GNUNET_MetaData *GNUNET_meta_data_deserialize (struct GNUNET_GE_Context *ectx, const char *input, unsigned int size){ MetaData *md; const MetaDataHeader *hdr; unsigned int ic; char *data; unsigned int dataSize; int compressed; int i; unsigned int pos; int len; unsigned int version; if (size < sizeof (MetaDataHeader)) return NULL; hdr = (const MetaDataHeader *) input; version = ntohl (MAKE_UNALIGNED (hdr->version)) & HEADER_VERSION_MASK; if (version == 1) return NULL; /* null pointer */ if (version != 0) { GNUNET_GE_BREAK_OP(NULL, 0); /* unsupported version */ return NULL; } ic = ntohl (MAKE_UNALIGNED (hdr->entries)); compressed = (ntohl (MAKE_UNALIGNED (hdr->version)) & HEADER_COMPRESSED) != 0; if (compressed) { dataSize = ntohl (MAKE_UNALIGNED (hdr->size)) - sizeof (MetaDataHeader); if (dataSize > 2 * 1042 * 1024) { GNUNET_GE_BREAK (ectx, 0); return NULL; /* only 2 MB allowed [to make sure we don't blow our memory limit because of a mal-formed message... ] */ } data = decompress ((char *) &input[sizeof (MetaDataHeader)], size - sizeof (MetaDataHeader), dataSize); if (data == NULL) { GNUNET_GE_BREAK (ectx, 0); return NULL; } } else { data = (char *) &hdr[1]; dataSize = size - sizeof (MetaDataHeader); if (size != ntohl (MAKE_UNALIGNED (hdr->size))) { GNUNET_GE_BREAK (ectx, 0); return NULL; } } if ((sizeof (unsigned int) * ic + ic) > dataSize) { GNUNET_GE_BREAK (ectx, 0); goto FAILURE; } if ((ic > 0) && (data[dataSize - 1] != '\0')) { GNUNET_GE_BREAK (ectx, 0); goto FAILURE; } md = GNUNET_meta_data_create (); GNUNET_array_grow (md->items, md->itemCount, ic); i = 0; pos = sizeof (unsigned int) * ic; while ((pos < dataSize) && (i < ic)) { len = strlen (&data[pos]) + 1; md->items[i].type = (EXTRACTOR_KeywordType) ntohl (MAKE_UNALIGNED (((unsigned int *) data)[i])); md->items[i].data = GNUNET_strdup (&data[pos]); pos += len; i++; } if (i < ic) { /* oops */ GNUNET_meta_data_destroy (md); goto FAILURE; } if (compressed) GNUNET_free (data); return md;FAILURE: if (compressed) GNUNET_free (data); return NULL; /* size too small */}/** * Test if two MDs are equal. */intGNUNET_meta_data_test_equal (const struct GNUNET_MetaData *md1, const struct GNUNET_MetaData *md2){ int i; int j; int found; if (md1->itemCount != md2->itemCount) return GNUNET_NO; for (i = 0; i < md1->itemCount; i++) { found = GNUNET_NO; for (j = 0; j < md2->itemCount; j++) if ((md1->items[i].type == md2->items[j].type) && (0 == strcmp (md1->items[i].data, md2->items[j].data))) found = GNUNET_YES; if (found == GNUNET_NO) return GNUNET_NO; } return GNUNET_YES;}/* end of meta.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -