#include #include #include #include #include #include #include #include #include /* FD's */ FILE *in; FILE *out; struct yajl_handle_t *handle = NULL; struct yajl_gen_t *gen = NULL; #define BUF_SIZE (64 * 1024) void usage(int exitcode) { fprintf(stderr, "\ Usage: json2torrent []\n\ Where options are:\n\ -h This help.\n\ -i Input file. (Default: read from stdin)\n\ -o Output file. (Default: write to stdout)\n"); exit(exitcode); } static int write_integer(void *ctx, long long l) { return (fprintf(out, "i%llie", l) > 0 ? 1 : 0); } static int write_dict_start(void *ctx) { return fputc('d', out); } static int write_list_start(void *ctx) { return fputc('l', out); } /* for dictionary, list and integer * * end we have the same marker: 'e' */ static int write_end(void *ctx) { return fputc('e', out); return 0; } static int write_hexstring(void *ctx, const unsigned char *str, size_t len) { unsigned int a, b, i; fprintf(out, "%u:", (len - 3) / 3); for (i = 3; i < len; i += 3) { a = (str[i + 1] >= 'A' ? (str[i + 1] - 'A') + 10 : str[i + 1] - '0'); b = (str[i + 2] >= 'A' ? (str[i + 2] - 'A') + 10 : str[i + 2] - '0'); fprintf(out, "%c", (a << 4 | b)); } } static int write_string(void *ctx, const unsigned char *str, size_t len) { if (len < 4 || strncmp(str, "hex:", 4) != 0) return (!!fprintf(out, "%u:", len) && !!fwrite(str, 1, len, out)); return write_hexstring(ctx, str, len); } yajl_callbacks callbacks = { NULL, /* null */ NULL, /* bool */ write_integer, /* integer */ NULL, /* double */ NULL, /* number */ write_string, /* string */ write_dict_start, /* start map */ write_string, /* map key */ write_end, /* end map */ write_list_start, /* start array */ write_end /* end array */ }; void check_yajl_error(struct yajl_handle_t *handle, unsigned char *buf, size_t read) { unsigned char *yajl_error = NULL; if ((yajl_error = yajl_get_error(handle, 1, buf, read)) != NULL) { fwrite(buf, read, 1, stderr); fputc('\n', stderr); yajl_free_error(handle, yajl_error); } } int main(int argc, char **argv) { static unsigned char buf[BUF_SIZE]; char opt = '\0'; size_t read = 0; /* FILE */ in = stdin; /* FILE */ out = stdout; if ((gen = yajl_gen_alloc(NULL)) == NULL) { fprintf(stderr, "Can't allocate json generator. Exiting."); exit(EXIT_FAILURE); } yajl_gen_config(gen, yajl_gen_validate_utf8, 0); if ((handle = yajl_alloc(&callbacks, NULL, (void *) gen)) == NULL) { fprintf(stderr, "Can't allocate json parser. Exiting."); exit(EXIT_FAILURE); } while ((opt = getopt(argc, argv, "hi:o:")) != -1) switch (opt) { case 'h' : usage(EXIT_SUCCESS); break; case 'i' : if ((in = fopen(optarg, "r")) == NULL) { fprintf(stderr, "Can't open input file '%s'. Exiting.", optarg); exit(EXIT_FAILURE); } break; case 'o' : if ((out = fopen(optarg, "w")) == NULL) { fprintf(stderr, "Can't open output file '%s'. Exiting.", optarg); exit(EXIT_FAILURE); } break; default : usage(EXIT_FAILURE); break; } yajl_config(handle, yajl_allow_comments, 1); yajl_config(handle, yajl_dont_validate_strings, 1); while ((read = fread(buf, 1, (BUF_SIZE - 1), in)) != 0) { buf[read] = '\0'; if (yajl_parse(handle, buf, read) != yajl_status_ok) { check_yajl_error(handle, buf, read); break; } } if (yajl_complete_parse(handle) != yajl_status_ok) check_yajl_error(handle, buf, read); yajl_free(handle); exit(EXIT_SUCCESS); }