A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

359 line
7.4 KiB

  1. #include <assert.h>
  2. #include <ctype.h>
  3. #include <errno.h>
  4. #include <inttypes.h>
  5. #include <stdarg.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <strings.h>
  9. #include "benc.h"
  10. #include "subr.h"
  11. #define benc_safeset(out, val) if ((out) != NULL) *(out) = (val)
  12. static const char *benc_validate_aux(const char *p, const char *end);
  13. int
  14. benc_validate(const char *p, size_t len)
  15. {
  16. const char *end = p + len - 1;
  17. if (len <= 0)
  18. return EINVAL;
  19. return benc_validate_aux(p, end) == end ? 0 : EINVAL;
  20. }
  21. static const char *
  22. benc_validate_aux(const char *p, const char *end)
  23. {
  24. size_t d = 0;
  25. switch (*p) {
  26. case 'd':
  27. d = 1;
  28. case 'l':
  29. for (p++; p <= end && *p != 'e'; p++) {
  30. if (d != 0) {
  31. if (d % 2 == 1 && !isdigit(*p))
  32. return NULL;
  33. else
  34. d++;
  35. }
  36. if ((p = benc_validate_aux(p, end)) == NULL)
  37. return NULL;
  38. }
  39. if (p > end || (d != 0 && d % 2 != 1))
  40. return NULL;
  41. break;
  42. case 'i':
  43. p++;
  44. if (p > end)
  45. return NULL;
  46. if (*p == '-')
  47. p++;
  48. if (p > end || !isdigit(*p))
  49. return NULL;
  50. p++;
  51. while (p <= end && isdigit(*p))
  52. p++;
  53. if (p > end || *p != 'e')
  54. return NULL;
  55. break;
  56. default:
  57. if (isdigit(*p)) {
  58. size_t len = 0;
  59. while (p <= end && isdigit(*p)) {
  60. len *= 10;
  61. len += *p - '0';
  62. p++;
  63. }
  64. if (p <= end && *p == ':' && p + len <= end)
  65. p += len;
  66. else
  67. return NULL;
  68. }
  69. else
  70. return NULL;
  71. break;
  72. }
  73. return p;
  74. }
  75. int
  76. benc_strcmp(const char *str1, const char *str2)
  77. {
  78. size_t len1, len2;
  79. const char *cs1 = benc_mem(str1, &len1, NULL);
  80. const char *cs2 = benc_mem(str2, &len2, NULL);
  81. int test = strncmp(cs1, cs2, min(len1, len2));
  82. if (test == 0) {
  83. if (len1 == len2)
  84. return 0;
  85. else if (len1 < len2)
  86. return -1;
  87. else
  88. return 1;
  89. } else
  90. return test;
  91. }
  92. size_t
  93. benc_strlen(const char *p)
  94. {
  95. char *endptr;
  96. return strtoul(p, &endptr, 10);
  97. }
  98. size_t
  99. benc_length(const char *p)
  100. {
  101. size_t blen;
  102. const char *next;
  103. switch (*p) {
  104. case 'd':
  105. case 'l':
  106. blen = 2; // [l|d]...e
  107. next = p + 1;
  108. while (*next != 'e') {
  109. size_t len = benc_length(next);
  110. blen += len;
  111. next += len;
  112. }
  113. return blen;
  114. case 'i':
  115. for (next = p + 1; *next != 'e'; next++)
  116. ;
  117. return next - p + 1;
  118. default:
  119. assert((next = benc_mem(p, &blen, NULL)) != NULL);
  120. return next - p + blen;
  121. }
  122. }
  123. size_t
  124. benc_nelems(const char *p)
  125. {
  126. size_t nelems = 0;
  127. for (p = benc_first(p); p != NULL; p = benc_next(p))
  128. nelems++;
  129. return nelems;
  130. }
  131. const char *
  132. benc_first(const char *p)
  133. {
  134. assert(benc_islst(p));
  135. return *(p + 1) == 'e' ? NULL : p + 1;
  136. }
  137. const char *
  138. benc_next(const char *p)
  139. {
  140. size_t blen = benc_length(p);
  141. return *(p + blen) == 'e' ? NULL : p + blen;
  142. }
  143. const char *
  144. benc_mem(const char *p, size_t *len, const char**next)
  145. {
  146. if (!benc_isstr(p))
  147. return NULL;
  148. char *endptr;
  149. size_t blen = strtoul(p, &endptr, 10);
  150. assert(*endptr == ':');
  151. benc_safeset(len, blen);
  152. benc_safeset(next, *(endptr + blen + 1) == 'e' ? NULL : endptr + blen + 1);
  153. return endptr + 1;
  154. }
  155. char *
  156. benc_str(const char *p, size_t *len, const char **next)
  157. {
  158. size_t blen;
  159. const char *bstr;
  160. char *ret;
  161. if ((bstr = benc_mem(p, &blen, next)) == NULL)
  162. return NULL;
  163. if ((ret = malloc(blen + 1)) == NULL)
  164. return NULL;
  165. bcopy(bstr, ret, blen);
  166. ret[blen] = '\0';
  167. benc_safeset(len, blen);
  168. return ret;
  169. }
  170. char *
  171. benc_mema(const char *p, size_t *len, const char **next)
  172. {
  173. size_t blen;
  174. const char *bstr;
  175. char *ret;
  176. if ((bstr = benc_mem(p, &blen, next)) == NULL)
  177. return NULL;
  178. if ((ret = malloc(blen)) == NULL)
  179. return NULL;
  180. bcopy(bstr, ret, blen);
  181. benc_safeset(len, blen);
  182. return ret;
  183. }
  184. long long
  185. benc_int(const char *p, const char **next)
  186. {
  187. long long res;
  188. char *endptr;
  189. if (!benc_isint(p))
  190. return 0;
  191. res = strtoll(p + 1, &endptr, 10);
  192. assert(*endptr == 'e');
  193. benc_safeset(next, *(endptr + 1) == 'e' ? NULL : endptr + 1);
  194. return res;
  195. }
  196. const char *
  197. benc_dget_any(const char *p, const char *key)
  198. {
  199. int cmp;
  200. size_t len, blen;
  201. const char *bstr;
  202. if (!benc_isdct(p))
  203. return NULL;
  204. len = strlen(key);
  205. p = benc_first(p);
  206. while (p != NULL) {
  207. if (!benc_isstr(p))
  208. return NULL;
  209. bstr = benc_mem(p, &blen, &p);
  210. cmp = strncmp(bstr, key, blen);
  211. if (cmp == 0 && len == blen)
  212. return p;
  213. else
  214. p = benc_next(p);
  215. }
  216. return NULL;
  217. }
  218. const char *
  219. benc_dget_lst(const char *p, const char *key)
  220. {
  221. const char *ret = benc_dget_any(p, key);
  222. return ret != NULL && benc_islst(ret) ? ret : NULL;
  223. }
  224. const char *
  225. benc_dget_dct(const char *p, const char *key)
  226. {
  227. const char *ret = benc_dget_any(p, key);
  228. return ret != NULL && benc_isdct(ret) ? ret : NULL;
  229. }
  230. const char *
  231. benc_dget_mem(const char *p, const char *key, size_t *len)
  232. {
  233. const char *str = benc_dget_any(p, key);
  234. return str != NULL && benc_isstr(str) ? benc_mem(str, len, NULL) : NULL;
  235. }
  236. char *
  237. benc_dget_mema(const char *p, const char *key, size_t *len)
  238. {
  239. const char *str = benc_dget_any(p, key);
  240. return str != NULL && benc_isstr(str) ? benc_mema(str, len, NULL) : NULL;
  241. }
  242. char *
  243. benc_dget_str(const char *p, const char *key, size_t *len)
  244. {
  245. const char *str = benc_dget_any(p, key);
  246. return str != NULL && benc_isstr(str) ? benc_str(str, len, NULL) : NULL;
  247. }
  248. long long
  249. benc_dget_int(const char *p, const char *key)
  250. {
  251. const char *intp = benc_dget_any(p, key);
  252. return intp != NULL && benc_isint(intp) ? benc_int(intp, NULL) : 0;
  253. }
  254. int
  255. benc_islst(const char *p)
  256. {
  257. return *p == 'l' || *p == 'd';
  258. }
  259. int
  260. benc_isdct(const char *p)
  261. {
  262. return *p == 'd';
  263. }
  264. int
  265. benc_isint(const char *p)
  266. {
  267. return *p == 'i';
  268. }
  269. int
  270. benc_isstr(const char *p)
  271. {
  272. return isdigit(*p);
  273. }
  274. int
  275. benc_istype(const char *p, enum be_type type)
  276. {
  277. switch (type) {
  278. case BE_ANY:
  279. return benc_isdct(p) || benc_isint(p) ||
  280. benc_islst(p) || benc_isstr(p);
  281. case BE_DCT:
  282. return benc_isdct(p);
  283. case BE_INT:
  284. return benc_isint(p);
  285. case BE_LST:
  286. return benc_islst(p);
  287. case BE_STR:
  288. return benc_isstr(p);
  289. default:
  290. abort();
  291. }
  292. }
  293. int
  294. benc_dct_chk(const char *p, int count, ...)
  295. {
  296. int i, ok = 1;
  297. va_list ap;
  298. if (!benc_isdct(p))
  299. ok = 0;
  300. va_start(ap, count);
  301. for (i = 0; ok && i < count; i++) {
  302. enum be_type type = va_arg(ap, enum be_type);
  303. int level = va_arg(ap, int);
  304. const char *dct = p;
  305. const char *key = va_arg(ap, const char *);
  306. while (ok && level > 1) {
  307. if ((dct = benc_dget_dct(dct, key)) != NULL) {
  308. level--;
  309. key = va_arg(ap, const char *);
  310. } else
  311. ok = 0;
  312. }
  313. if (ok) {
  314. const char *val = benc_dget_any(dct, key);
  315. if (val == NULL || !benc_istype(val, type))
  316. ok = 0;
  317. }
  318. }
  319. va_end(ap);
  320. return ok;
  321. }