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.
255 lines
5.3 KiB
255 lines
5.3 KiB
#include <ctype.h> |
|
#include <stdbool.h> |
|
#include <stdio.h> |
|
#include <stdint.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
|
#include <yajl/yajl_gen.h> |
|
|
|
/* FD's */ |
|
FILE *in; |
|
FILE *out; |
|
|
|
struct yajl_gen_t *gen = NULL; |
|
|
|
void (*select_handler(int))(int); |
|
|
|
void |
|
usage(int exitcode) |
|
{ |
|
fprintf(stderr, "\ |
|
Usage: torrent2json [<options>]\n\ |
|
Where options are:\n\ |
|
-h This help.\n\ |
|
-i <file> Input file. (Default: read from stdin)\n\ |
|
-o <file> Output file. (Default: write to stdout)\n\ |
|
-c Compact json. (Default: no)\n"); |
|
exit(exitcode); |
|
} |
|
|
|
void |
|
hexencode(unsigned char *buf, unsigned int len) { |
|
unsigned char *encbuf = NULL; |
|
unsigned int enclen = sizeof(char) * (len * 3 + 3); /* "hex" + "FF," x len */ |
|
unsigned int i, j; |
|
unsigned int a, b; |
|
|
|
if ((encbuf = malloc(enclen)) == NULL) { |
|
fprintf(stderr, "Can't allocate memory, exiting.\n"); |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
memcpy(encbuf, "hex", 3); |
|
|
|
for (i = 0, j = 3; i < len; i++, j += 3) { |
|
a = (buf[i] & 0xF0) >> 4; |
|
b = (buf[i] & 0x0F) >> 0; |
|
encbuf[j + 0] = ','; |
|
encbuf[j + 1] = (a > 9) ? 'A' + (a - 10) : '0' + a; |
|
encbuf[j + 2] = (b > 9) ? 'A' + (b - 10) : '0' + b; |
|
} |
|
|
|
encbuf[3] = ':'; |
|
yajl_gen_string(gen, encbuf, enclen); |
|
|
|
free(encbuf); |
|
} |
|
|
|
/* handlers */ |
|
void |
|
get_integer(int chr) |
|
{ /* 'chr' always 'i' in this case */ |
|
int c = '\0'; |
|
bool cont = true; |
|
bool negative = false; |
|
long int value = 0; /* signed */ |
|
|
|
while (cont) |
|
{ |
|
c = fgetc(in); |
|
switch ((isdigit(c) != 0) ? '0' : c) /* little hack here */ |
|
{ |
|
case '0' : |
|
value *= 10; /* (0 * 10) -> 0, so it works correct */ |
|
value += c - '0'; |
|
break; |
|
case 'e' : /* integer end marker */ |
|
cont = false; |
|
break; |
|
case '-' : |
|
if (value == 0) /* true if '-' - first char after 'i' */ |
|
{ |
|
negative = true; |
|
break; |
|
} /* else we consider it as garbage */ |
|
default : |
|
fprintf(stderr, "Garbage after integer: %i%c<\n", value, c); |
|
exit(EXIT_FAILURE); |
|
break; |
|
} |
|
} |
|
|
|
if (negative) value *= -1; |
|
yajl_gen_integer(gen, value); |
|
} |
|
|
|
void |
|
get_string(int chr) |
|
{ |
|
/* in this case 'chr' first digit of string lenght */ |
|
unsigned int len = (unsigned char) chr - '0'; |
|
int c = '\0'; |
|
unsigned int i = 0; |
|
unsigned char *buf = NULL; |
|
unsigned int hex = 0; |
|
|
|
/* first, get string lenght */ |
|
while (isdigit((c = fgetc(in)))) |
|
len *= 10, len += c - '0'; |
|
/* 'c' now should contain ':' */ |
|
|
|
if ((buf = malloc(sizeof(char) * (len + 1))) == NULL) |
|
{ |
|
fprintf(stderr, "Can't allocate memory, exiting.\n"); |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
memset(buf, '\0', sizeof(char) * (len + 1)); |
|
for (i = 0; i < len; i++) { |
|
buf[i] = fgetc(in); |
|
if (buf[i] < 0x20) /* string has control chars */ |
|
hex = 1; |
|
} |
|
|
|
if (hex == 1) { |
|
hexencode(buf, len); |
|
} else { |
|
yajl_gen_string(gen, buf, len); |
|
} |
|
|
|
free(buf); |
|
} |
|
|
|
void |
|
get_dict(int chr) |
|
{ /* 'chr' always 'd' in this case */ |
|
void (*handler)(int) = NULL; |
|
int c = '\0'; |
|
|
|
yajl_gen_map_open(gen); |
|
|
|
while ((c = fgetc(in)) != 'e') |
|
{ |
|
handler = select_handler(c); |
|
if (handler) handler(c); |
|
} |
|
|
|
yajl_gen_map_close(gen); |
|
} |
|
|
|
void |
|
get_list(int chr) |
|
{ /* 'chr' always 'l' in this case */ |
|
void (*handler)(int) = NULL; |
|
int c = '\0'; |
|
|
|
yajl_gen_array_open(gen); |
|
|
|
while ((c = fgetc(in)) != 'e') |
|
{ |
|
handler = select_handler(c); |
|
if (handler) handler(c); |
|
} |
|
|
|
yajl_gen_array_close(gen); |
|
} |
|
|
|
/* general purpose functions */ |
|
void (*select_handler(int chr))(int) |
|
{ |
|
switch ((isdigit(chr) != 0) ? '0' : chr) |
|
{ |
|
case 'd' : /* dictionary */ |
|
return get_dict; |
|
break; |
|
case 'i' : /* integer */ |
|
return get_integer; |
|
break; |
|
case 'l' : /* list */ |
|
return get_list; |
|
break; |
|
case '0' : /* string */ |
|
return get_string; |
|
break; |
|
default: |
|
fprintf(stderr, "Unknown marker: %u\n", chr); |
|
break; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
int |
|
main(int argc, char **argv) |
|
{ |
|
void (*handler)(int) = NULL; |
|
int c = '\0'; |
|
const unsigned char *buf = NULL; |
|
char opt = '\0'; |
|
size_t len = 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_beautify, 1); |
|
yajl_gen_config(gen, yajl_gen_indent_string, "\t"); |
|
|
|
while ((opt = getopt(argc, argv, "hi:o:c")) != -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; |
|
case 'c' : |
|
yajl_gen_config(gen, yajl_gen_beautify, 0); |
|
break; |
|
default : |
|
usage(EXIT_FAILURE); |
|
break; |
|
} |
|
|
|
while ((c = fgetc(in)) != EOF) |
|
{ |
|
handler = select_handler(c); |
|
if (handler) handler(c); |
|
} |
|
|
|
yajl_gen_get_buf(gen, &buf, &len); |
|
if (len > 0 && buf) fprintf(out, "%s", buf); |
|
yajl_gen_free(gen); |
|
|
|
exit(EXIT_SUCCESS); |
|
} |
|
|
|
|