transmission/libtransmission/bencode.h

265 lines
8.1 KiB
C

/*
* This file Copyright (C) Mnemosyne LLC
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2 (b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#ifndef TR_BENCODE_H
#define TR_BENCODE_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h> /* for int64_t */
struct evbuffer;
/**
* @addtogroup tr_benc Variant
*
* An object that acts like a union for
* integers, strings, lists, dictionaries, booleans, and floating-point numbers.
* The structure is named tr_benc due to the historical reason that it was
* originally tightly coupled with bencoded data. It currently supports
* being parsed from, and serialized to, both bencoded notation and json notation.
*
* @{
*/
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
* I'll probably change them just to break your code! HA HA HA!
* it's included in the header for inlining and composition */
enum
{
TR_TYPE_INT = 1,
TR_TYPE_STR = 2,
TR_TYPE_LIST = 4,
TR_TYPE_DICT = 8,
TR_TYPE_BOOL = 16,
TR_TYPE_REAL = 32
};
/* These are PRIVATE IMPLEMENTATION details that should not be touched.
* I'll probably change them just to break your code! HA HA HA!
* it's included in the header for inlining and composition */
typedef struct tr_benc
{
union
{
uint8_t b; /* bool type */
double d; /* double type */
int64_t i; /* int type */
struct /* string type */
{
size_t len; /* the string length */
union {
char buf[16]; /* local buffer for short strings */
char * ptr; /* alloc'ed pointer for long strings */
} str;
} s;
struct /* list & dict types */
{
struct tr_benc * vals; /* nodes */
size_t alloc; /* nodes allocated */
size_t count; /* nodes used */
} l;
} val;
char type;
} tr_benc;
/***
****
***/
int tr_bencParse (const void * buf,
const void * bufend,
tr_benc * setme_benc,
const uint8_t ** setme_end);
int tr_bencLoad (const void * buf,
size_t buflen,
tr_benc * setme_benc,
char ** setme_end);
void tr_bencFree (tr_benc *);
void tr_bencInitStr (tr_benc *, const void * str, int str_len);
void tr_bencInitRaw (tr_benc *, const void * raw, size_t raw_len);
void tr_bencInitInt (tr_benc *, int64_t num);
int tr_bencInitDict (tr_benc *, size_t reserveCount);
int tr_bencInitList (tr_benc *, size_t reserveCount);
void tr_bencInitBool (tr_benc *, int value);
void tr_bencInitReal (tr_benc *, double value);
/***
**** Serialization / Deserialization
***/
typedef enum
{
TR_FMT_BENC,
TR_FMT_JSON,
TR_FMT_JSON_LEAN /* saves bandwidth by omitting all whitespace. */
}
tr_fmt_mode;
int tr_bencToFile (const tr_benc *, tr_fmt_mode, const char * filename);
char* tr_bencToStr (const tr_benc *, tr_fmt_mode, int * len);
struct evbuffer * tr_bencToBuf (const tr_benc *, tr_fmt_mode);
/* TR_FMT_JSON_LEAN and TR_FMT_JSON are equivalent in this function. */
int tr_bencLoadFile (tr_benc * setme, tr_fmt_mode, const char * filename);
/***
****
***/
int tr_bencListReserve (tr_benc *, size_t reserveCount);
tr_benc * tr_bencListAdd (tr_benc *);
tr_benc * tr_bencListAddBool (tr_benc *, bool val);
tr_benc * tr_bencListAddInt (tr_benc *, int64_t val);
tr_benc * tr_bencListAddReal (tr_benc *, double val);
tr_benc * tr_bencListAddStr (tr_benc *, const char * val);
tr_benc * tr_bencListAddRaw (tr_benc *, const uint8_t * val, size_t len);
tr_benc * tr_bencListAddList (tr_benc *, size_t reserveCount);
tr_benc * tr_bencListAddDict (tr_benc *, size_t reserveCount);
size_t tr_bencListSize (const tr_benc * list);
tr_benc * tr_bencListChild (tr_benc * list, size_t n);
int tr_bencListRemove (tr_benc *, size_t n);
/***
****
***/
int tr_bencDictReserve (tr_benc *, size_t reserveCount);
int tr_bencDictRemove (tr_benc *, const char * key);
tr_benc * tr_bencDictAdd (tr_benc *, const char * key);
tr_benc * tr_bencDictAddReal (tr_benc *, const char * key, double);
tr_benc * tr_bencDictAddInt (tr_benc *, const char * key, int64_t);
tr_benc * tr_bencDictAddBool (tr_benc *, const char * key, bool);
tr_benc * tr_bencDictAddStr (tr_benc *, const char * key, const char *);
tr_benc * tr_bencDictAddList (tr_benc *, const char * key, size_t reserve);
tr_benc * tr_bencDictAddDict (tr_benc *, const char * key, size_t reserve);
tr_benc * tr_bencDictAddRaw (tr_benc *, const char * key,
const void * raw, size_t rawlen);
bool tr_bencDictChild (tr_benc *, size_t i, const char ** key, tr_benc ** val);
tr_benc* tr_bencDictFind (tr_benc *, const char * key);
bool tr_bencDictFindList (tr_benc *, const char * key, tr_benc ** setme);
bool tr_bencDictFindDict (tr_benc *, const char * key, tr_benc ** setme);
bool tr_bencDictFindInt (tr_benc *, const char * key, int64_t * setme);
bool tr_bencDictFindReal (tr_benc *, const char * key, double * setme);
bool tr_bencDictFindBool (tr_benc *, const char * key, bool * setme);
bool tr_bencDictFindStr (tr_benc *, const char * key, const char ** setme);
bool tr_bencDictFindRaw (tr_benc *, const char * key,
const uint8_t ** setme_raw, size_t * setme_len);
/***
****
***/
/** @brief Get an int64_t from a variant object
@return true if successful, or false if the variant could not be represented as an int64_t */
bool tr_bencGetInt (const tr_benc * val, int64_t * setme);
/** @brief Get an string from a variant object
@return true if successful, or false if the variant could not be represented as a string */
bool tr_bencGetStr (const tr_benc * val, const char ** setme);
/** @brief Get a raw byte array from a variant object
@return true if successful, or false if the variant could not be represented as a raw byte array */
bool tr_bencGetRaw (const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len);
/** @brief Get a boolean from a variant object
@return true if successful, or false if the variant could not be represented as a boolean */
bool tr_bencGetBool (const tr_benc * val, bool * setme);
/** @brief Get a floating-point number from a variant object
@return true if successful, or false if the variant could not be represented as a floating-point number */
bool tr_bencGetReal (const tr_benc * val, double * setme);
static inline bool tr_bencIsType (const tr_benc * b, int type) { return (b != NULL) && (b->type == type); }
static inline bool tr_bencIsInt (const tr_benc * b) { return tr_bencIsType (b, TR_TYPE_INT); }
static inline bool tr_bencIsDict (const tr_benc * b) { return tr_bencIsType (b, TR_TYPE_DICT); }
static inline bool tr_bencIsList (const tr_benc * b) { return tr_bencIsType (b, TR_TYPE_LIST); }
static inline bool tr_bencIsString (const tr_benc * b) { return tr_bencIsType (b, TR_TYPE_STR); }
static inline bool tr_bencIsBool (const tr_benc * b) { return tr_bencIsType (b, TR_TYPE_BOOL); }
static inline bool tr_bencIsReal (const tr_benc * b) { return tr_bencIsType (b, TR_TYPE_REAL); }
/** @brief Private function that's exposed here only for unit tests */
int tr_bencParseInt (const uint8_t * buf,
const uint8_t * bufend,
const uint8_t ** setme_end,
int64_t * setme_val);
/** @brief Private function that's exposed here only for unit tests */
int tr_bencParseStr (const uint8_t * buf,
const uint8_t * bufend,
const uint8_t ** setme_end,
const uint8_t ** setme_str,
size_t * setme_strlen);
/**
***
**/
/* this is only quasi-supported. don't rely on it too heavily outside of libT */
void tr_bencMergeDicts (tr_benc * target, const tr_benc * source);
/* @} */
#ifdef __cplusplus
}
#endif
#endif