1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
|
#ifndef _BENCODE_H_
#define _BENCODE_H_
#include <sys/uio.h>
#include <string.h>
#include "compat.h"
struct bencode_buffer;
enum bencode_type;
struct bencode_item;
struct __bencode_buffer_piece;
struct __bencode_free_list;
typedef enum bencode_type bencode_type_t;
typedef struct bencode_buffer bencode_buffer_t;
typedef struct bencode_item bencode_item_t;
typedef void (*free_func_t)(void *);
enum bencode_type {
BENCODE_INVALID = 0,
BENCODE_STRING, /* byte string */
BENCODE_INTEGER, /* long long int */
BENCODE_LIST, /* flat list of other objects */
BENCODE_DICTIONARY, /* dictionary of key/values pairs. keys are always strings */
BENCODE_END_MARKER, /* used internally only */
};
struct bencode_item {
bencode_type_t type;
struct iovec iov[2]; /* when decoding, iov[1] contains the contents of a string object */
unsigned int iov_cnt;
size_t str_len; /* length of the whole ENCODED object. NOT the length of a byte string */
long long int value; /* when decoding an integer, contains the value; otherwise used internally */
bencode_item_t *parent, *child, *last_child, *sibling;
bencode_buffer_t *buffer;
char __buf[0];
};
struct bencode_buffer {
struct __bencode_buffer_piece *pieces;
unsigned int error:1; /* set to !0 if allocation failed at any point */
};
/* to embed BENCODE_STRING objects into printf-like functions */
#define BENCODE_FORMAT "%.*s"
#define BENCODE_FMT(b) (int) (b)->iov[1].iov_len, (char *) (b)->iov[1].iov_base
/*** INIT & DESTROY ***/
/* Initializes a bencode_buffer_t object. This object is used to group together all memory allocations
* made when encoding or decoding. Its memory usage is always growing, until it is freed, at which point
* all objects created through it become invalid. The actual object must be allocated separately, for
* example by being put on the stack.
* Returns 0 on success or -1 on failure (if no memory could be allocated). */
int bencode_buffer_init(bencode_buffer_t *buf);
/* Allocate a piece of memory from the given buffer object */
void *bencode_buffer_alloc(bencode_buffer_t *, size_t);
/* Destroys a previously initialized bencode_buffer_t object. All memory used by the object is freed
* and all objects created through it become invalid. */
void bencode_buffer_free(bencode_buffer_t *buf);
// Move all objects from one buffer to another. The `from` buffer will be unusable afterwards.
void bencode_buffer_merge(bencode_buffer_t *to, bencode_buffer_t *from);
/* Creates a new empty dictionary object. Memory will be allocated from the bencode_buffer_t object.
* Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_dictionary(bencode_buffer_t *buf);
/* Creates a new empty list object. Memory will be allocated from the bencode_buffer_t object.
* Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_list(bencode_buffer_t *buf);
/* Returns the buffer associated with an item, or NULL if pointer given is NULL */
INLINE bencode_buffer_t *bencode_item_buffer(bencode_item_t *);
/* like strdup() but uses the bencode buffer to store the string */
INLINE char *bencode_strdup(bencode_buffer_t *, const char *);
/* ditto but returns a str object */
INLINE str bencode_strdup_str(bencode_buffer_t *, const char *);
/*** DICTIONARY BUILDING ***/
/* Adds a new key/value pair to a dictionary. Memory will be allocated from the same bencode_buffer_t
* object as the dictionary was allocated from. Returns NULL if no memory could be allocated, otherwise
* returns "val".
* The function does not check whether the key being added is already present in the dictionary.
* Also, the function does not reorder keys into lexicographical order; keys will be encoded in
* the same order as they've been added. The key must a null-terminated string.
* The value to be added must not have been previously linked into any other dictionary or list. */
INLINE bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val);
INLINE bencode_item_t *bencode_dictionary_str_add(bencode_item_t *dict, const str *key, bencode_item_t *val);
/* Identical to bencode_dictionary_add() but doesn't require the key string to be null-terminated */
bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, size_t keylen, bencode_item_t *val);
/* Convenience function to add a string value to a dictionary, possibly duplicated into the
* bencode_buffer_t object. */
INLINE void bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val);
/* Ditto, but for a "str" object */
INLINE void bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val);
INLINE void bencode_dictionary_str_add_str(bencode_item_t *dict, const str *key, const str *val);
INLINE void bencode_dictionary_add_str_dup(bencode_item_t *dict, const char *key, const str *val);
/* Convenience functions to add the respective (newly created) objects to a dictionary */
INLINE void bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val);
INLINE bencode_item_t *bencode_dictionary_add_dictionary(bencode_item_t *dict, const char *key);
INLINE bencode_item_t *bencode_dictionary_add_list(bencode_item_t *dict, const char *key);
/*** LIST BUILDING ***/
/* Adds a new item to a list. Returns "item".
* The item to be added must not have been previously linked into any other dictionary or list. */
bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item);
/* Convenience function to add the respective (newly created) objects to a list */
INLINE void bencode_list_add_string(bencode_item_t *list, const char *s);
INLINE void bencode_list_add_str(bencode_item_t *list, const str *s);
INLINE void bencode_list_add_str_dup(bencode_item_t *list, const str *s);
INLINE bencode_item_t *bencode_list_add_list(bencode_item_t *list);
INLINE bencode_item_t *bencode_list_add_dictionary(bencode_item_t *list);
/*** STRING BUILDING & HANDLING ***/
/* Creates a new byte-string object. The given string does not have to be null-terminated, instead
* the length of the string is specified by the "len" parameter. Returns NULL if no memory could
* be allocated.
* Strings are not copied or duplicated, so the string pointed to by "s" must remain valid until
* the complete document is finally encoded or sent out. */
bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, size_t len);
/* Creates a new byte-string object. The given string must be null-terminated. Otherwise identical
* to bencode_string_len(). */
INLINE bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s);
/* Creates a new byte-string object from a "str" object. The string does not have to be null-
* terminated. */
INLINE bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s);
/* Identical to the above three functions, but copies the string into the bencode_buffer_t object.
* Thus, the given string doesn't have to remain valid and accessible afterwards. */
bencode_item_t *bencode_string_len_dup(bencode_buffer_t *buf, const char *s, size_t len);
INLINE bencode_item_t *bencode_string_dup(bencode_buffer_t *buf, const char *s);
INLINE bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s);
/* Convenience function to compare a string object to a regular C string. Returns 2 if object
* isn't a string object, otherwise returns according to strcmp(). */
INLINE int bencode_strcmp(bencode_item_t *a, const char *b);
/* Converts the string object "in" into a str object "out". Returns "out" on success, or NULL on
* error ("in" was NULL or not a string object). */
INLINE str *bencode_get_str(bencode_item_t *in, str *out);
/*** INTEGER BUILDING ***/
/* Creates a new integer object. Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i);
// Return integer, possibly converted from string
INLINE long long bencode_get_integer_str(bencode_item_t *item, long long int defval);
/*** COLLAPSING & ENCODING ***/
/* Collapses and encodes the complete document structure under the "root" element (which normally
* is either a dictionary or a list) into an array of "iovec" structures. This array can then be
* passed to functions ala writev() or sendmsg() to output the encoded document as a whole. Memory
* is allocated from the same bencode_buffer_t object as the "root" object was allocated from.
* The "head" and "tail" parameters specify additional "iovec" structures that should be included
* in the allocated array before or after (respectively) the iovec structures used by the encoded
* document. Both parameters can be zero if no additional elements in the array are required.
* Returns a pointer to the allocated array or NULL if no memory could be allocated. The number of
* array elements is returned in "cnt" which must be a valid pointer to an int. This number does
* not include any additional elements allocated through the "head" or "tail" parameters.
*
* Therefore, the contents of the returned array are:
* [0 .. (head - 1)] = unused and uninitialized iovec structures
* [(head) .. (head + cnt - 1)] = the encoded document
* [(head + cnt) .. (head + cnt + tail - 1)] = unused and uninitialized iovec structures
*
* The returned array will be freed when the corresponding bencode_buffer_t object is destroyed. */
struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail);
/* Similar to bencode_iovec(), but instead returns the encoded document as a null-terminated string.
* Memory for the string is allocated from the same bencode_buffer_t object as the "root" object
* was allocated from. If "len" is a non-NULL pointer, the length of the generated string is returned
* in *len. This is important if the encoded document contains binary data, in which case null
* termination cannot be trusted. The returned string is freed when the corresponding
* bencode_buffer_t object is destroyed. */
char *bencode_collapse(bencode_item_t *root, size_t *len);
/* Identical to bencode_collapse() but returns a "str" object. */
INLINE str bencode_collapse_str(bencode_item_t *root);
/* Identical to bencode_collapse(), but the memory for the returned string is not allocated from
* a bencode_buffer_t object, but instead using the function defined as BENCODE_MALLOC (normally
* malloc() or pkg_malloc()), similar to strdup(). Using this function, the bencode_buffer_t
* object can be destroyed, but the returned string remains valid and usable. */
char *bencode_collapse_dup(bencode_item_t *root, size_t *len);
/*** DECODING ***/
/* Decodes an encoded document from a string into a tree of bencode_item_t objects. The string does
* not need to be null-terminated, instead the length of the string is given through the "len"
* parameter. Memory is allocated from the bencode_buffer_t object. Returns NULL if no memory could
* be allocated or if the document could not be successfully decoded.
*
* The returned element is the "root" of the document tree and normally is either a list object or
* a dictionary object, but can also be a single string or integer object with no other objects
* underneath or besides it (no childred and no siblings). The type of the object can be determined
* by its ->type property.
*
* The number of bytes that could successfully be decoded into an object tree can be accessed through
* the root element's ->str_len property. Normally, this number should be equal to the "len" parameter
* passed, in which case the full string could be decoded. If ->str_len is less than "len", then there
* was additional stray byte data after the end of the encoded document.
*
* The document tree can be traversed through the ->child and ->sibling pointers in each object. The
* ->child pointer will be NULL for string and integer objects, as they don't contain other objects.
* For lists and dictionaries, ->child will be a pointer to the first contained object. This first
* contained object's ->sibling pointer will point to the next (second) contained object of the list
* or the dictionary, and so on. The last contained element of a list of dictionary will have a
* NULL ->sibling pointer.
*
* Dictionaries are like lists with ordered key/value pairs. When traversing dictionaries like
* lists, the following applies: The first element in the list (where ->child points to) will be the
* key of the first key/value pair (guaranteed to be a string and guaranteed to be present). The
* next element (following one ->sibling) will be the value of the first key/value pair. Following
* another ->sibling will point to the key of the next (second) key/value pair, and so on.
*
* However, to access children objects of dictionaries, the special functions following the naming
* scheme bencode_dictionary_get_* below should be used. They perform key lookup through a simple
* hash built into the dictionary object and so perform the lookup much faster. Only dictionaries
* created through a decoding process (i.e. not ones created from bencode_dictionary()) have this
* property. The hash is efficient only up to a certain number of elements (BENCODE_HASH_BUCKETS
* in bencode.c) contained in the dictionary. If the number of children object exceeds this number,
* key lookup will be slower than simply linearly traversing the list.
*
* The decoding function for dictionary object does not check whether keys are unique within the
* dictionary. It also does not care about lexicographical order of the keys.
*
* Decoded string objects will contain the raw decoded byte string in ->iov[1] (including the correct
* length). Strings are NOT null-terminated. Decoded integer objects will contain the decoded value
* in ->value.
*
* All memory is freed when the bencode_buffer_t object is destroyed.
*/
bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, size_t len);
/* Identical to bencode_decode(), but returns successfully only if the type of the decoded object match
* "expect". */
INLINE bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, size_t len, bencode_type_t expect);
/* Identical to bencode_decode_expect() but takes a "str" argument. */
INLINE bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect);
/* Returns the number of bytes that could successfully be decoded from 's', -1 if more bytes are needed or -2 on error */
ssize_t bencode_valid(const char *s, size_t len);
/*** DICTIONARY LOOKUP & EXTRACTION ***/
/* Searches the given dictionary object for the given key and returns the respective value. Returns
* NULL if the given object isn't a dictionary or if the key doesn't exist. The key must be a
* null-terminated string. */
INLINE bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key);
/* Identical to bencode_dictionary_get() but doesn't require the key to be null-terminated. */
bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *key, size_t key_len);
/* Identical to bencode_dictionary_get() but returns the value only if its type is a string, and
* returns it as a pointer to the string itself. Returns NULL if the value is of some other type. The
* returned string is NOT null-terminated. Length of the string is returned in *len, which must be a
* valid pointer. The returned string will be valid until dict's bencode_buffer_t object is destroyed. */
INLINE char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, size_t *len);
/* Identical to bencode_dictionary_get_string() but fills in a "str" struct. Returns str->s, which
* may be NULL. */
INLINE char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *str);
/* Looks up the given key in the dictionary and compares the corresponding value to the given
* null-terminated string. Returns 2 if the key isn't found or if the value isn't a string, otherwise
* returns according to strcmp(). */
INLINE int bencode_dictionary_get_strcmp(bencode_item_t *dict, const char *key, const char *str);
/* Identical to bencode_dictionary_get() but returns the string in a newly allocated buffer (using the
* BENCODE_MALLOC function), which remains valid even after bencode_buffer_t is destroyed. */
INLINE char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, size_t *len);
/* Combines bencode_dictionary_get_str() and bencode_dictionary_get_string_dup(). Fills in a "str"
* struct, but copies the string into a newly allocated buffer. Returns str->s. */
INLINE char *bencode_dictionary_get_str_dup(bencode_item_t *dict, const char *key, str *str);
/* Identical to bencode_dictionary_get_string() but expects an integer object. The parameter "defval"
* specified which value should be returned if the key is not found or if the value is not an integer. */
INLINE long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval);
/* Identical to bencode_dictionary_get_integer() but allows for the item to be a string. */
INLINE long long int bencode_dictionary_get_int_str(bencode_item_t *dict, const char *key, long long int defval);
/* Identical to bencode_dictionary_get(), but returns the object only if its type matches "expect". */
INLINE bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect);
/**************************/
INLINE bencode_buffer_t *bencode_item_buffer(bencode_item_t *i) {
if (!i)
return NULL;
return i->buffer;
}
INLINE bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s) {
return bencode_string_len(buf, s, strlen(s));
}
INLINE bencode_item_t *bencode_string_dup(bencode_buffer_t *buf, const char *s) {
return bencode_string_len_dup(buf, s, strlen(s));
}
INLINE bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s) {
return bencode_string_len(buf, s->s, s->len);
}
INLINE bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s) {
return bencode_string_len_dup(buf, s->s, s->len);
}
INLINE char *bencode_strdup(bencode_buffer_t *buf, const char *s) {
char *ret = bencode_buffer_alloc(buf, strlen(s) + 1);
strcpy(ret, s);
return ret;
}
INLINE str bencode_strdup_str(bencode_buffer_t *buf, const char *s) {
str o = STR_NULL;
o.len = strlen(s);
o.s = bencode_buffer_alloc(buf, o.len);
memcpy(o.s, s, o.len);
return o;
}
INLINE str bencode_str_strdup(bencode_buffer_t *buf, const str *s) {
str o = *s;
o.s = bencode_buffer_alloc(buf, o.len);
#ifdef ASAN_BUILD
if (o.len)
#endif
memcpy(o.s, s->s, o.len);
return o;
}
INLINE str *bencode_str_str_dup(bencode_buffer_t *buf, const str *s) {
str *o = bencode_buffer_alloc(buf, sizeof(*o));
*o = *s;
o->s = bencode_buffer_alloc(buf, o->len);
memcpy(o->s, s->s, o->len);
return o;
}
INLINE bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val) {
if (!key)
return NULL;
return bencode_dictionary_add_len(dict, key, strlen(key), val);
}
INLINE bencode_item_t *bencode_dictionary_str_add(bencode_item_t *dict, const str *key, bencode_item_t *val) {
if (!key)
return NULL;
return bencode_dictionary_add_len(dict, key->s, key->len, val);
}
INLINE void bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val) {
if (val)
bencode_dictionary_add(dict, key, bencode_string(bencode_item_buffer(dict), val));
}
INLINE void bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val) {
if (val)
bencode_dictionary_add(dict, key, bencode_str(bencode_item_buffer(dict), val));
}
INLINE void bencode_dictionary_str_add_str(bencode_item_t *dict, const str *key, const str *val) {
if (val)
bencode_dictionary_str_add(dict, key, bencode_str(bencode_item_buffer(dict), val));
}
INLINE void bencode_dictionary_add_str_dup(bencode_item_t *dict, const char *key, const str *val) {
if (val)
bencode_dictionary_add(dict, key, bencode_str_dup(bencode_item_buffer(dict), val));
}
INLINE void bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val) {
bencode_dictionary_add(dict, key, bencode_integer(bencode_item_buffer(dict), val));
}
INLINE bencode_item_t *bencode_dictionary_add_dictionary(bencode_item_t *dict, const char *key) {
return bencode_dictionary_add(dict, key, bencode_dictionary(bencode_item_buffer(dict)));
}
INLINE bencode_item_t *bencode_dictionary_add_list(bencode_item_t *dict, const char *key) {
return bencode_dictionary_add(dict, key, bencode_list(bencode_item_buffer(dict)));
}
INLINE void bencode_list_add_string(bencode_item_t *list, const char *s) {
bencode_list_add(list, bencode_string(bencode_item_buffer(list), s));
}
INLINE void bencode_list_add_str(bencode_item_t *list, const str *s) {
bencode_list_add(list, bencode_str(bencode_item_buffer(list), s));
}
INLINE void bencode_list_add_str_dup(bencode_item_t *list, const str *s) {
if (s)
bencode_list_add(list, bencode_str_dup(bencode_item_buffer(list), s));
}
INLINE bencode_item_t *bencode_list_add_list(bencode_item_t *list) {
return bencode_list_add(list, bencode_list(bencode_item_buffer(list)));
}
INLINE bencode_item_t *bencode_list_add_dictionary(bencode_item_t *list) {
return bencode_list_add(list, bencode_dictionary(bencode_item_buffer(list)));
}
INLINE bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key) {
if (!key)
return NULL;
return bencode_dictionary_get_len(dict, key, strlen(key));
}
INLINE char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, size_t *len) {
bencode_item_t *val;
val = bencode_dictionary_get(dict, key);
if (!val || val->type != BENCODE_STRING)
return NULL;
*len = val->iov[1].iov_len;
return val->iov[1].iov_base;
}
INLINE char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *s) {
*s = STR_NULL;
s->s = bencode_dictionary_get_string(dict, key, &s->len);
if (!s->s)
s->len = 0;
return s->s;
}
INLINE char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, size_t *len) {
const char *s;
char *ret;
s = bencode_dictionary_get_string(dict, key, len);
if (!s)
return NULL;
ret = BENCODE_MALLOC(*len);
if (!ret)
return NULL;
memcpy(ret, s, *len);
return ret;
}
INLINE char *bencode_dictionary_get_str_dup(bencode_item_t *dict, const char *key, str *s) {
*s = STR_NULL;
s->s = bencode_dictionary_get_string_dup(dict, key, &s->len);
return s->s;
}
INLINE long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval) {
bencode_item_t *val;
val = bencode_dictionary_get(dict, key);
if (!val || val->type != BENCODE_INTEGER)
return defval;
return val->value;
}
INLINE long long bencode_get_integer_str(bencode_item_t *val, long long int defval) {
if (!val)
return defval;
if (val->type == BENCODE_INTEGER)
return val->value;
if (val->type != BENCODE_STRING)
return defval;
if (val->iov[1].iov_len == 0)
return defval;
// uh oh...
char *s = val->iov[1].iov_base;
char old = s[val->iov[1].iov_len];
s[val->iov[1].iov_len] = 0;
char *errp;
long long int ret = strtoll(val->iov[1].iov_base, &errp, 10);
s[val->iov[1].iov_len] = old;
if (errp != val->iov[1].iov_base + val->iov[1].iov_len)
return defval;
return ret;
}
INLINE long long int bencode_dictionary_get_int_str(bencode_item_t *dict, const char *key, long long int defval) {
bencode_item_t *val;
val = bencode_dictionary_get(dict, key);
return bencode_get_integer_str(val, defval);
}
INLINE bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, size_t len, bencode_type_t expect) {
bencode_item_t *ret;
ret = bencode_decode(buf, s, len);
if (!ret || ret->type != expect)
return NULL;
return ret;
}
INLINE bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect) {
return bencode_decode_expect(buf, s->s, s->len, expect);
}
INLINE bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect) {
bencode_item_t *ret;
ret = bencode_dictionary_get(dict, key);
if (!ret || ret->type != expect)
return NULL;
return ret;
}
INLINE str bencode_collapse_str(bencode_item_t *root) {
str out = STR_NULL;
out.s = bencode_collapse(root, &out.len);
return out;
}
INLINE int bencode_strcmp(bencode_item_t *a, const char *b) {
int len;
if (a->type != BENCODE_STRING)
return 2;
len = strlen(b);
if (a->iov[1].iov_len < len)
return -1;
if (a->iov[1].iov_len > len)
return 1;
return memcmp(a->iov[1].iov_base, b, len);
}
INLINE int bencode_dictionary_get_strcmp(bencode_item_t *dict, const char *key, const char *s) {
bencode_item_t *i;
i = bencode_dictionary_get(dict, key);
if (!i)
return 2;
return bencode_strcmp(i, s);
}
INLINE str *bencode_get_str(bencode_item_t *in, str *out) {
if (!in || in->type != BENCODE_STRING)
return NULL;
*out = STR_LEN(in->iov[1].iov_base, in->iov[1].iov_len);
return out;
}
#endif
|