1 /*
2  * This file Copyright (C) 2008-2014 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8 
9 #pragma once
10 
11 #ifdef __cplusplus
12 extern "C"
13 {
14 #endif
15 
16 #include <inttypes.h> /* for int64_t */
17 #include "quark.h"
18 
19 struct evbuffer;
20 
21 struct tr_error;
22 
23 /**
24  * @addtogroup tr_variant Variant
25  *
26  * An object that acts like a union for
27  * integers, strings, lists, dictionaries, booleans, and floating-point numbers.
28  * The structure is named tr_variant due to the historical reason that it was
29  * originally tightly coupled with bencoded data. It currently supports
30  * being parsed from, and serialized to, both bencoded notation and json notation.
31  *
32  * @{
33  */
34 
35 typedef enum
36 {
37     TR_STRING_TYPE_QUARK,
38     TR_STRING_TYPE_HEAP,
39     TR_STRING_TYPE_BUF
40 }
41 tr_string_type;
42 
43 /* these are PRIVATE IMPLEMENTATION details that should not be touched.
44  * I'll probably change them just to break your code! HA HA HA!
45  * it's included in the header for inlining and composition */
46 struct tr_variant_string
47 {
48     tr_string_type type;
49     tr_quark quark;
50     size_t len;
51     union
52     {
53         char buf[16];
54         char const* str;
55     }
56     str;
57 };
58 
59 /* these are PRIVATE IMPLEMENTATION details that should not be touched.
60  * I'll probably change them just to break your code! HA HA HA!
61  * it's included in the header for inlining and composition */
62 enum
63 {
64     TR_VARIANT_TYPE_INT = 1,
65     TR_VARIANT_TYPE_STR = 2,
66     TR_VARIANT_TYPE_LIST = 4,
67     TR_VARIANT_TYPE_DICT = 8,
68     TR_VARIANT_TYPE_BOOL = 16,
69     TR_VARIANT_TYPE_REAL = 32
70 };
71 
72 /* These are PRIVATE IMPLEMENTATION details that should not be touched.
73  * I'll probably change them just to break your code! HA HA HA!
74  * it's included in the header for inlining and composition */
75 typedef struct tr_variant
76 {
77     char type;
78 
79     tr_quark key;
80 
81     union
82     {
83         bool b;
84 
85         double d;
86 
87         int64_t i;
88 
89         struct tr_variant_string s;
90 
91         struct
92         {
93             size_t alloc;
94             size_t count;
95             struct tr_variant* vals;
96         } l;
97     }
98     val;
99 }
100 tr_variant;
101 
102 void tr_variantFree(tr_variant*);
103 
104 /***
105 ****  Serialization / Deserialization
106 ***/
107 
108 typedef enum
109 {
110     TR_VARIANT_FMT_BENC,
111     TR_VARIANT_FMT_JSON,
112     TR_VARIANT_FMT_JSON_LEAN /* saves bandwidth by omitting all whitespace. */
113 }
114 tr_variant_fmt;
115 
116 int tr_variantToFile(tr_variant const* variant, tr_variant_fmt fmt, char const* filename);
117 
118 char* tr_variantToStr(tr_variant const* variant, tr_variant_fmt fmt, size_t* len);
119 
120 struct evbuffer* tr_variantToBuf(tr_variant const* variant, tr_variant_fmt fmt);
121 
122 /* TR_VARIANT_FMT_JSON_LEAN and TR_VARIANT_FMT_JSON are equivalent here. */
123 bool tr_variantFromFile(tr_variant* setme, tr_variant_fmt fmt, char const* filename, struct tr_error** error);
124 
125 /* TR_VARIANT_FMT_JSON_LEAN and TR_VARIANT_FMT_JSON are equivalent here. */
126 int tr_variantFromBuf(tr_variant* setme, tr_variant_fmt fmt, void const* buf, size_t buflen, char const* optional_source,
127     char const** setme_end);
128 
tr_variantFromBenc(tr_variant * setme,void const * buf,size_t buflen)129 static inline int tr_variantFromBenc(tr_variant* setme, void const* buf, size_t buflen)
130 {
131     return tr_variantFromBuf(setme, TR_VARIANT_FMT_BENC, buf, buflen, NULL, NULL);
132 }
133 
tr_variantFromBencFull(tr_variant * setme,void const * buf,size_t buflen,char const * source,char const ** setme_end)134 static inline int tr_variantFromBencFull(tr_variant* setme, void const* buf, size_t buflen, char const* source,
135     char const** setme_end)
136 {
137     return tr_variantFromBuf(setme, TR_VARIANT_FMT_BENC, buf, buflen, source, setme_end);
138 }
139 
tr_variantFromJsonFull(tr_variant * setme,void const * buf,size_t buflen,char const * source,char const ** setme_end)140 static inline int tr_variantFromJsonFull(tr_variant* setme, void const* buf, size_t buflen, char const* source,
141     char const** setme_end)
142 {
143     return tr_variantFromBuf(setme, TR_VARIANT_FMT_JSON, buf, buflen, source, setme_end);
144 }
145 
tr_variantFromJson(tr_variant * setme,void const * buf,size_t buflen)146 static inline int tr_variantFromJson(tr_variant* setme, void const* buf, size_t buflen)
147 {
148     return tr_variantFromBuf(setme, TR_VARIANT_FMT_JSON, buf, buflen, NULL, NULL);
149 }
150 
tr_variantIsType(tr_variant const * b,int type)151 static inline bool tr_variantIsType(tr_variant const* b, int type)
152 {
153     return b != NULL && b->type == type;
154 }
155 
156 /***
157 ****  Strings
158 ***/
159 
tr_variantIsString(tr_variant const * b)160 static inline bool tr_variantIsString(tr_variant const* b)
161 {
162     return b != NULL && b->type == TR_VARIANT_TYPE_STR;
163 }
164 
165 bool tr_variantGetStr(tr_variant const* variant, char const** setme_str, size_t* setme_len);
166 
167 void tr_variantInitStr(tr_variant* initme, void const* str, size_t str_len);
168 void tr_variantInitQuark(tr_variant* initme, tr_quark const quark);
169 void tr_variantInitRaw(tr_variant* initme, void const* raw, size_t raw_len);
170 
171 bool tr_variantGetRaw(tr_variant const* variant, uint8_t const** raw_setme, size_t* len_setme);
172 
173 /***
174 ****  Real Numbers
175 ***/
176 
tr_variantIsReal(tr_variant const * v)177 static inline bool tr_variantIsReal(tr_variant const* v)
178 {
179     return v != NULL && v->type == TR_VARIANT_TYPE_REAL;
180 }
181 
182 void tr_variantInitReal(tr_variant* initme, double value);
183 bool tr_variantGetReal(tr_variant const* variant, double* value_setme);
184 
185 /***
186 ****  Booleans
187 ***/
188 
tr_variantIsBool(tr_variant const * v)189 static inline bool tr_variantIsBool(tr_variant const* v)
190 {
191     return v != NULL && v->type == TR_VARIANT_TYPE_BOOL;
192 }
193 
194 void tr_variantInitBool(tr_variant* initme, bool value);
195 bool tr_variantGetBool(tr_variant const* variant, bool* setme);
196 
197 /***
198 ****  Ints
199 ***/
200 
tr_variantIsInt(tr_variant const * v)201 static inline bool tr_variantIsInt(tr_variant const* v)
202 {
203     return v != NULL && v->type == TR_VARIANT_TYPE_INT;
204 }
205 
206 void tr_variantInitInt(tr_variant* variant, int64_t value);
207 bool tr_variantGetInt(tr_variant const* val, int64_t* setme);
208 
209 /***
210 ****  Lists
211 ***/
212 
tr_variantIsList(tr_variant const * v)213 static inline bool tr_variantIsList(tr_variant const* v)
214 {
215     return v != NULL && v->type == TR_VARIANT_TYPE_LIST;
216 }
217 
218 void tr_variantInitList(tr_variant* list, size_t reserve_count);
219 void tr_variantListReserve(tr_variant* list, size_t reserve_count);
220 
221 tr_variant* tr_variantListAdd(tr_variant* list);
222 tr_variant* tr_variantListAddBool(tr_variant* list, bool addme);
223 tr_variant* tr_variantListAddInt(tr_variant* list, int64_t addme);
224 tr_variant* tr_variantListAddReal(tr_variant* list, double addme);
225 tr_variant* tr_variantListAddStr(tr_variant* list, char const* addme);
226 tr_variant* tr_variantListAddQuark(tr_variant* list, tr_quark const addme);
227 tr_variant* tr_variantListAddRaw(tr_variant* list, void const* addme_value, size_t addme_len);
228 tr_variant* tr_variantListAddList(tr_variant* list, size_t reserve_count);
229 tr_variant* tr_variantListAddDict(tr_variant* list, size_t reserve_count);
230 tr_variant* tr_variantListChild(tr_variant* list, size_t pos);
231 
232 bool tr_variantListRemove(tr_variant* list, size_t pos);
233 size_t tr_variantListSize(tr_variant const* list);
234 
235 /***
236 ****  Dictionaries
237 ***/
238 
tr_variantIsDict(tr_variant const * v)239 static inline bool tr_variantIsDict(tr_variant const* v)
240 {
241     return v != NULL && v->type == TR_VARIANT_TYPE_DICT;
242 }
243 
244 void tr_variantInitDict(tr_variant* initme, size_t reserve_count);
245 void tr_variantDictReserve(tr_variant* dict, size_t reserve_count);
246 bool tr_variantDictRemove(tr_variant* dict, tr_quark const key);
247 
248 tr_variant* tr_variantDictAdd(tr_variant* dict, tr_quark const key);
249 tr_variant* tr_variantDictAddReal(tr_variant* dict, tr_quark const key, double value);
250 tr_variant* tr_variantDictAddInt(tr_variant* dict, tr_quark const key, int64_t value);
251 tr_variant* tr_variantDictAddBool(tr_variant* dict, tr_quark const key, bool value);
252 tr_variant* tr_variantDictAddStr(tr_variant* dict, tr_quark const key, char const* value);
253 tr_variant* tr_variantDictAddQuark(tr_variant* dict, tr_quark const key, tr_quark const val);
254 tr_variant* tr_variantDictAddList(tr_variant* dict, tr_quark const key, size_t reserve_count);
255 tr_variant* tr_variantDictAddDict(tr_variant* dict, tr_quark const key, size_t reserve_count);
256 tr_variant* tr_variantDictSteal(tr_variant* dict, tr_quark const key, tr_variant* value);
257 tr_variant* tr_variantDictAddRaw(tr_variant* dict, tr_quark const key, void const* value, size_t len);
258 
259 bool tr_variantDictChild(tr_variant* dict, size_t pos, tr_quark* setme_key, tr_variant** setme_value);
260 tr_variant* tr_variantDictFind(tr_variant* dict, tr_quark const key);
261 bool tr_variantDictFindList(tr_variant* dict, tr_quark const key, tr_variant** setme);
262 bool tr_variantDictFindDict(tr_variant* dict, tr_quark const key, tr_variant** setme_value);
263 bool tr_variantDictFindInt(tr_variant* dict, tr_quark const key, int64_t* setme);
264 bool tr_variantDictFindReal(tr_variant* dict, tr_quark const key, double* setme);
265 bool tr_variantDictFindBool(tr_variant* dict, tr_quark const key, bool* setme);
266 bool tr_variantDictFindStr(tr_variant* dict, tr_quark const key, char const** setme, size_t* len);
267 bool tr_variantDictFindRaw(tr_variant* dict, tr_quark const key, uint8_t const** setme_raw, size_t* setme_len);
268 
269 /* this is only quasi-supported. don't rely on it too heavily outside of libT */
270 void tr_variantMergeDicts(tr_variant* dict_target, tr_variant const* dict_source);
271 
272 /***
273 ****
274 ****
275 ***/
276 
277 /**
278 ***
279 **/
280 
281 /* @} */
282 
283 #ifdef __cplusplus
284 }
285 #endif
286