Created
April 10, 2011 13:42
-
-
Save stbuehler/912353 to your computer and use it in GitHub Desktop.
Torrent Announce Info extractor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Torrent Announce Info extractor | |
lists all announce urls from torrents on stdout | |
Build with ragel (http://www.complang.org/ragel/) and a c compiler: | |
ragel -T1 torrent-announce-info.rl && CFLAGS='-O2' make torrent-announce-info | |
list torrent files on stdin: | |
ls -1 /path/to/torrents/*.torrent | torrent-announce-info | |
or | |
find /path/to/torrents/ -name '*.torrent' | torrent-announce-info | |
*/ | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <errno.h> | |
#define MAXSTRLEN 1024 | |
/* | |
static char tempbuf[MAXSTRLEN+1]; | |
char* tostr(const char* str, int len) { | |
memcpy(tempbuf, str, len); | |
tempbuf[len] = '\0'; | |
return tempbuf; | |
} | |
*/ | |
void print_announce(const char* str, int len) { | |
write(1, str, len); | |
write(1, "\n", 1); | |
} | |
%%{ | |
machine torrent_parser; | |
prepush { | |
if (top >= 31) { | |
fprintf(stderr, "stack overflow\n"); | |
return; | |
} | |
} | |
action string_start { slen = 0; } | |
action string_len { | |
slen = 10*slen + (fc - '0'); | |
if (slen > MAXSTRLEN) { | |
fprintf(stderr, "string overflow\n"); | |
return; | |
} | |
} | |
action string_read { sstart = fpc+1; fpc += slen; } | |
dict = 'd' >{ fcall dict_start; }; | |
list = 'l' >{ fcall list_start; }; | |
num = 'i' ('-'|'') [0-9]* 'e'; | |
string = ([0-9]+) >string_start $string_len ':'>string_read; | |
value = dict | list | num | string; | |
dict_start := ( string value )* 'e' @{ fret; }; | |
list_start := ( value )* 'e' @{ fret; }; | |
action torrententry { | |
if (8 == slen && 0 == strncmp("announce", sstart, 8)) { | |
fcall torrentannounce; | |
} else if (13 == slen && 0 == strncmp("announce-list", sstart, 13)) { | |
fcall torrentannouncelist; | |
} else if (strncmp("announce-list", sstart, slen) < 0) { | |
/* fprintf(stderr, "stopping on '%s'\n", tostr(sstart, slen)); */ | |
return; /* done with announces, key too "big" */ | |
} else { | |
/* fprintf(stderr, "skipping '%s'\n", tostr(sstart, slen)); */ | |
fcall torrentdict_skipvalue; /* skip value */ | |
} | |
} | |
action announce { | |
print_announce(sstart, slen); | |
} | |
torrentannounce := string @announce @{ fret; }; | |
torrentannouncelist := 'l' ( string @announce | 'l' (string @announce)* 'e')* 'e' @{ fret; }; | |
torrentdict_skipvalue := value ( string @torrententry)* 'e'; | |
torrentdict := 'd' ( string @torrententry)* 'e'; | |
}%% | |
%% write data; | |
#define BLOCK_SIZE 4096 | |
#define INIT_READ BLOCK_SIZE | |
typedef struct tfile tfile; | |
struct tfile { | |
int fd; | |
const char *filename; | |
char data[2*BLOCK_SIZE]; | |
ssize_t len; | |
int eof; | |
}; | |
#ifndef O_NOATIME | |
# define O_NOATIME 0 | |
#endif | |
static void file_start(tfile *f, const char *filename) { | |
ssize_t r; | |
f->filename = filename; | |
f->fd = open(filename, O_RDONLY | O_NOATIME); | |
if (-1 == f->fd) { | |
fprintf(stderr, "couldn't open '%s': %s\n", filename, strerror(errno)); | |
f->len = 0; | |
f->eof = 1; | |
return; | |
} | |
r = read(f->fd, f->data, INIT_READ); | |
if (r <= 0) { | |
if (r < 0) { | |
fprintf(stderr, "couldn't read from '%s': %s\n", f->filename, strerror(errno)); | |
} | |
f->len = 0; | |
f->eof = 1; | |
return; | |
} | |
if (r < INIT_READ) f->eof = 1; | |
f->len = r; | |
} | |
static void file_forward(tfile *f, const char **sstart) { | |
ssize_t r; | |
memmove(f->data, f->data + BLOCK_SIZE, BLOCK_SIZE); | |
r = read(f->fd, f->data + BLOCK_SIZE, BLOCK_SIZE); | |
if (r <= 0) { | |
if (r < 0) { | |
fprintf(stderr, "couldn't read from '%s': %s\n", f->filename, strerror(errno)); | |
} | |
f->len = 0; | |
f->eof = 1; | |
return; | |
} | |
if (r < BLOCK_SIZE) f->eof = 1; | |
f->len = BLOCK_SIZE + r; | |
if (NULL != *sstart && (*sstart - f->data > BLOCK_SIZE)) { | |
*sstart -= BLOCK_SIZE; | |
} else { | |
*sstart = NULL; | |
} | |
} | |
static void file_close(tfile *f) { | |
close(f->fd); | |
} | |
static void do_parse_torrent(tfile *f) { | |
int stack[32], top = 0, cs; | |
%% write init; | |
const char *sstart = NULL; | |
int slen = 0; | |
for ( ; f->len > 0; ) { | |
const char *p = f->data, *pe = p+f->len, *eof = f->eof ? pe : NULL; | |
%% write exec; | |
/* fprintf(stderr, "cs: %i @pos: %i '%c'\n", cs, p - f->data, *p); */ | |
if (f->eof || cs == torrent_parser_error || cs >= torrent_parser_first_final) return; | |
file_forward(f, &sstart); | |
} | |
} | |
void parse_torrent(const char *filename) { | |
tfile f; | |
file_start(&f, filename); | |
do_parse_torrent(&f); | |
file_close(&f); | |
} | |
int main() { | |
char *filename = NULL; | |
size_t len = 0; | |
while (-1 != getline(&filename, &len, stdin)) { | |
char *delim; | |
if (0 == len) continue; | |
if (NULL != (delim = strchr(filename, '\n'))) *delim = '\0'; | |
parse_torrent(filename); | |
} | |
free(filename); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment