X-Git-Url: http://royale.zerezo.com/git/?p=FAPG;a=blobdiff_plain;f=fapg.c;h=bd2b3f0ea2c1d79ee2c29ff3d177621c524e2de8;hp=8a6667d848eccef1649b746bbfe80472357bb149;hb=refs%2Ftags%2Fv0.43;hpb=ff081934d3f79e659ca14c93b147028b59880ee8 diff --git a/fapg.c b/fapg.c index 8a6667d..bd2b3f0 100644 --- a/fapg.c +++ b/fapg.c @@ -1,6 +1,4 @@ /* - * FAPG version 0.31 - * * FAPG means Fast Audio Playlist Generator. * It is a tool to generate list of audio files (Wav, MP3, Ogg, etc) * in various formats (M3U, PLS, HTML, etc). @@ -36,629 +34,1614 @@ #include #include #include +#include #include #include "genres.h" +#ifdef HAVE_LIBURIPARSER +# include +#endif #define MP3_BASE 1024 #define OGG_BASE 1024*10 -#define MAX 1024*200 /* 200ko for ID3 with JPEG images in it */ - -int debug=0; -int format=0; /* 0 = m3u ; 1 = pls ; 2 = html */ -char *genrelist=NULL; -unsigned char *prefix=""; -int recursive=0; -int avoidhlinked=0; -int separator='/'; -int skip=0; -int windows=0; -unsigned char *eol="\n"; +#define MAX 1024*250 /* 250ko for ID3 with JPEG images in it */ + +#define FORMAT_M3U 0 +#define FORMAT_PLS 1 +#define FORMAT_HTML 2 +#define FORMAT_RSS 3 +#define FORMAT_PLP 4 +#define FORMAT_UMS 5 +#ifdef HAVE_LIBURIPARSER +# define FORMAT_XSPF 6 +#endif + +int debug = 0; +int format = FORMAT_M3U; +char *genrelist = NULL; +unsigned char *prefix = ""; +unsigned char *base = ""; +unsigned char *dir = ""; +unsigned char *hostname = "fritzserver.de"; +// unsigned char *referal="/usr/local/bin/fapg-rss.sh"; +unsigned char *referal = NULL; +//int windows=0; +int fromstdin = 0; +int recursive = 0; +int avoidhlinked = 0; +int separator = '/'; +unsigned char *eol = "\n"; unsigned char buffer[MAX]; -int counter=0; +int counter = 0; unsigned char artist[1024]; unsigned char title[1024]; unsigned char genrebuf[1024]; -unsigned char genre=0; +unsigned char genre = 0; int duration; +#define MP2ENC 1 +#define MP3ENC 2 +#define MPCENC 3 +#define MPPENC 4 +#define OGGENC 5 +#define WAVENC 6 +#define WMAENC 7 + +char *magic[] = { NULL, + "audio/mpeg", "audio/mpeg", + "audio/mpeg", "audio/mpeg", + "audio/ogg-vorbis", "audio/x-wav", + "audio/x-ms-wma", + NULL +}; + +unsigned char unix2dos[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 70, 35, 36, 37, 38, 39, 40, 41, 82, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 84, 59, 36, 61, 65, 71, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 36, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 36, 125, 126, 127, + 199, 252, 233, 226, 228, 224, 229, 231, + 234, 235, 232, 239, 238, 236, 196, 197, + 201, 230, 198, 244, 246, 242, 251, 249, + 255, 214, 220, 248, 163, 216, 215, 131, + 225, 237, 243, 250, 241, 209, 170, 186, + 191, 174, 172, 189, 188, 161, 171, 187, + 166, 166, 166, 166, 166, 193, 194, 192, + 169, 166, 166, 43, 43, 162, 165, 43, + 43, 45, 45, 43, 45, 43, 227, 195, + 43, 43, 45, 45, 166, 45, 43, 164, + 240, 208, 202, 203, 200, 105, 205, 206, + 207, 43, 43, 166, 220, 166, 204, 175, + 211, 223, 212, 210, 245, 213, 181, 254, + 222, 218, 219, 217, 253, 221, 175, 180, + 173, 177, 61, 190, 182, 167, 247, 184, + 176, 168, 183, 185, 179, 178, 166, 160 +}; -unsigned char unix2dos[256]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,70,35,36,37,38,39,40,41,82,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,84,59,36,61,65,71,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,36,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,36,125,126,127,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,248,163,216,215,131,225,237,243,250,241,209,170,186,191,174,172,189,188,161,171,187,166,166,166,166,166,193,194,192,169,166,166,43,43,162,165,43,43,45,45,43,45,43,227,195,43,43,45,45,166,45,43,164,240,208,202,203,200,105,205,206,207,43,43,166,220,166,204,175,211,223,212,210,245,213,181,254,222,218,219,217,253,221,175,180,173,177,61,190,182,167,247,184,176,168,183,185,179,178,166,160}; +unsigned char *basemap; +unsigned char *winorunix; +unsigned char one2one[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255 +}; /* identical mapping */ + +unsigned char noand[256] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 43, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255 +}; /* only '&' is mapped to '+' */ + +unsigned char *iso2web[256] = { + "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", + "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", + "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", + "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", + "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", + "%28", "%29", "%2a", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "%3c", "=", "%3e", "%3f", + "@", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "%5B", "\\", "%5D", "^", "_", + "`", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "%7b", "|", "%7d", "~", "%7f", + "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", + "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", + "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", + "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", + "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", + "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", + "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", + "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf", + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", + "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", + "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" +}; void usage() { - fprintf(stderr,"Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n"); - exit(1); +#ifdef HAVE_LIBURIPARSER +# define FAPG_FORMATS "m3u|pls|xspf|html|rss|pla|txx" +#else +# define FAPG_FORMATS "m3u|pls|html|rss|pla|txx" +#endif + fprintf(stderr, + "Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=" FAPG_FORMATS "] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-c|--command=] [-x|--exclude=#:#:...] [-s|--stdin] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n"); +#undef FAPG_FORMATS + exit(1); } -void parse_options(int argc,char **argv) +#define mywebputchar(x) { fputs(iso2web[(unsigned char)winorunix[(unsigned char)x]], stdout); } +#define myputchar(x) { putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]); } +/* #define myplaputchar(x) { putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]);putchar('\0');} */ +void myplaputchar(const char x) { - static char const short_options[]="bdf:g:lo:np:rwx:"; - static struct option long_options[]= - { - {"backslash",no_argument,NULL,'b'}, - {"debug",no_argument,NULL,'d'}, - {"format",required_argument,NULL,'f'}, - {"genre",required_argument,NULL,'g'}, - {"nohardlink",no_argument,NULL,'n'}, - {"output",required_argument,NULL,'o'}, - {"prefix",required_argument,NULL,'p'}, - {"recursive",no_argument,NULL,'r'}, - {"windows",no_argument,NULL,'w'}, - {"exclude",required_argument,NULL,'x'} - }; - int c; - int option_index=0; - while ((c=getopt_long(argc,argv,short_options,long_options,&option_index))!=-1) - { - switch(c) - { - case 'b': - separator='\\'; - break; - case 'd': - debug=1; - break; - case 'f': - if (strcmp(optarg,"m3u")==0) format=0; else - if (strcmp(optarg,"pls")==0) format=1; else - if (strcmp(optarg,"html")==0) format=2; else - usage(); - break; - case 'g': - if (genrelist==NULL) genrelist=calloc(257,sizeof(char)); /* allow multiple includes/excludes */ - if (genrelist==NULL) { fprintf(stderr,"Error >> unable to allocate cleared memory\n"); exit(2); } + putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]); + putchar('\0'); +} + +void mywebputstr(const char *c) +{ + while(*c != 0) { + mywebputchar(*c); + c++; + } +} + +void myplaputstr(const char *c) +{ + while(*c != 0) { + if(*c == '/') + myplaputchar('\\'); /* translate slash to backslash */ else - { - int n=0; - while (n> genrelist entry activting : %d\n",atoi(&optarg[n])); - genrelist[atoi(&optarg[n])]=1; - while (isdigit(optarg[n++])); - } + myplaputchar(*c); + c++; + /* remove multiple slashes "//" when parsing a directory ending with a "/" */ + while(*c == '/' && c[1] == '/') + c++; + } +} + +void myputstr(const char *c) +{ + while(*c != 0) { + if(*c == '/') + putchar(separator); + else + myputchar(*c); + c++; + /* remove multiple slashes "//" when parsing a directory ending with a "/" */ + while(*c == '/' && c[1] == '/') + c++; + } +} + +void txxputheader(const char *c) +{ + int cnt = 0; + + while(*c != 0) { + myputchar(*c); + cnt++; + c++; + } + + while(cnt < 512) { + putchar('\0'); + cnt++; + } +} + +void txxputnameoffset(const char *c) +{ + int pos = 0; + int cnt = 0; + char b; + unsigned char *prefx; + + prefx = prefix; + + if(*prefx != 0) { + while(*prefx != 0) { + if(*prefx == '/') { + pos = cnt; + } + cnt++; + prefx++; } - break; - case 'n': - avoidhlinked=1; - break; - case 'o': - close(1); - if (fopen(optarg,"w")==NULL) { fprintf(stderr,"Error >> unable to open output file : %s\n",optarg); exit(2); } - break; - case 'p': - prefix=malloc(strlen(optarg)+1); - strcpy(prefix,optarg); - break; - case 'r': - recursive=1; - break; - case 'w': - windows=1; - eol="\r\n"; - break; - case 'x': - if (genrelist==NULL) /* allow multiple includes/excludes - not recommended (confusing) but possible */ - { - int n=0; - genrelist=calloc(257,sizeof(char)); - while (n<256) genrelist[n++]=1; + + cnt--; // skip the leading dot of the filepath + } + + while(*c != 0) { + if(*c == '/') { + pos = cnt; } - if (genrelist==NULL) { fprintf(stderr,"Error >> unable to allocate cleared memory\n"); exit(2); } + cnt++; + c++; + } + + pos += 2; + + b = (pos & 0xFF00) >> 8; + putchar(b); + b = (pos & 0x00FF); + putchar(b); +} + +void txxputstr(const char *c) +{ + int cnt = 0; + int pos; + unsigned char *prefx; + + txxputnameoffset(c); + + prefx = prefix; + fprintf(stderr, "prefix: '%s'\n", prefx); + + if(*prefx != 0) { + while(*prefx != 0) { + myputchar('\0'); + cnt++; + + if(*prefx == '/') + putchar(separator); + else + myputchar(*prefx); + cnt++; + + prefx++; + } + + c++; // skip the leading dot + } + + while(*c != 0) { + myputchar('\0'); + cnt++; + + if(*c == '/') + putchar(separator); else - { - int n=0; - while (n> genrelist entry activting : %d\n",atoi(&optarg[n])); - genrelist[atoi(&optarg[n])]=0; - while (isdigit(optarg[n++])); - } + myputchar(*c); + cnt++; + + c++; + } + + while(cnt < 510) { + myputchar('\0'); + cnt++; + } +} + +void txxputcounter(int c) +{ + int b; + + rewind(stdout); + + b = (c & 0xFF000000) >> 24; + putchar(b); + b = (c & 0x00FF0000) >> 16; + putchar(b); + b = (c & 0x0000FF00) >> 8; + putchar(b); + b = (c & 0x000000FF); + putchar(b); +} + +/* remove spaces at beginning and end of string */ +void trim(char *c) +{ + char *p; + /* remove spaces at beginning ... */ + while(*c == ' ') { + p = c; + while(*p != '\0') { + *p = *(p + 1); + p++; } - break; - default: - usage(); } - } - if (genrelist==NULL) - { - genrelist=calloc(257,sizeof(char)); - if (genrelist==NULL) { fprintf(stderr,"Error >> unable to allocate cleared memory\n"); exit(2); } - else - { - int n=0; - while (n<256) genrelist[n++]=1; + /* ... and end of string */ + p = c + strlen(c); + while(--p > c && *p == ' ') + *p = '\0'; +} + +void print_webpath(const char *path) +{ + const char *c = path; + + printf("%s", prefix); /* we must not modify this part */ + if(*c == '.' && c[1] == '/') { /* remove leading "./" when parsing current directory */ + c += 2; + /* maybe there follow many slashes */ + while(*c == '/') + c++; + } + for(; *c != '\0'; c++) { + mywebputchar(*c); + /* remove multiple "//" when parsing a directory ending with a "/" */ + while(*c == '/' && c[1] == '/') + c++; } - } } -void parse_mp3(unsigned char *file) +void print_path(const char *path) { - int bitrates[2][3][15]= - {{{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, - {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, - {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}}, - {{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}}}; - FILE *fic; - unsigned char *c; - int lus; - - genre=0; - genrebuf[0]=0; - if (debug) fprintf(stderr,"Debug >> parsing mp3 : %s\n",file); - - /* read header */ - if ((fic=fopen(file,"r"))==NULL) { fprintf(stderr,"Warning >> can't open file : %s\n",file); return; } - lus=fread(buffer,1,MP3_BASE,fic); - c=buffer; - - /* try ID3v2 */ - if (buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3') - { - int size; - int version; - version=*(buffer+3); - if (version<2 || version>4) - fprintf(stderr,"Warning >> ID3 v2.%d not implemented ! trying anyway : %s\n",version,file); - if (*(buffer+5)!=0) - fprintf(stderr,"Warning >> specials headers not implemented (%d) ! trying anyway : %s\n",*(buffer+5),file); - c=buffer+6; - size=(*c<<21)+(*(c+1)<<14)+(*(c+2)<<7)+(*(c+3)); - /* read more header */ - if (size+lus>MAX) - { - lus+=fread(buffer+lus,1,MAX-lus,fic); - fprintf(stderr,"Warning >> ID3 header is huge (%d bytes) ! trying anyway : %s\n",size,file); + const char *c = path; + printf("%s", prefix); + /* skip leading "./" when parsing current directory */ + if(*c == '.' && *(c + 1) == '/') { + c += 2; + /* maybe there follow more slashes */ + while(*c == '/') + c++; } + myputstr(c); +} + +void print_pathtail(const char *path) +{ + const char *c; + c = strrchr(path, separator); + if(c != NULL) + c++; else - lus+=fread(buffer+lus,1,size,fic); - if (size>lus) size=lus; - c+=4; - if (version==2) while (c>3&1); - lay=4-(*(c+1)>>1&3); - bitrate_index=*(c+2)>>4&0xF; - if (version>=1 && version<=2 && lay-1>=0 && lay-1<=2 && bitrate_index>=0 && bitrate_index<=14) - bitrate=bitrates[version-1][lay-1][bitrate_index]; - else - bitrate=0; - if (bitrate!=0) - { - fseek(fic,0,SEEK_END); - duration=(ftell(fic)+buffer-c)/125/bitrate; - } - else - duration=0; - break; - } - c++; - } - - /* try ID3v1 */ - if (strlen(artist)==0 && strlen(title)==0) - { - fseek(fic,-128,SEEK_END); - lus=fread(buffer,1,128,fic); - if (lus==128 && buffer[0]=='T' && buffer[1]=='A' && buffer[2]=='G') - { - strncpy(title,buffer+3,30); - title[30]='\0'; - c=title+29; - while (c>title && *c==' ') *(c--)='\0'; - strncpy(artist,buffer+33,30); - artist[30]='\0'; - c=artist+29; - while (c>artist && *c==' ') *(c--)='\0'; - /* strncpy(album,buffer+65,30); */ - /* strncpy(year,buffer+97,4); */ - /* strncpy(comment,buffer+101,30); */ - /* strncpy(genrebuf,buffer+127,1); genre[1]=0; */ - genre=buffer[127]; - } - } - - fclose(fic); -} + c = path; + myputstr(c); +} -void parse_ogg(unsigned char *file) +void noreferal(const char *path, const char *artist, const char *title) +{ + printf("\t\t"); + myputstr(artist); + printf("
"); + myputstr(title); + printf("


Direct Link to Audiofile

]]>
%s", + eol); +} + +void reference(const char *title) { - FILE *fic; - unsigned char *c; - int lus; - int sample_rate; - int samples; - - if (debug) fprintf(stderr,"Debug >> parsing ogg : %s\n",file); - - /* read header */ - if ((fic=fopen(file,"r"))==NULL) { fprintf(stderr,"Warning >> can't open file : %s\n",file); return; } - lus=fread(buffer,1,OGG_BASE,fic); - - /* try Ogg */ - if (buffer[0]!='O' && buffer[1]!='g' && buffer[2]!='g') - { - fprintf(stderr,"Warning >> not a Ogg header : %s\n",file); + FILE *pipe = NULL; + static char command[2048], buffer[1024]; + int buflen = 8192; + + buflen = strlen(title) + strlen(referal) + 3; + assert((buflen < 2046)); + strcpy(command, referal); + buflen = strlen(command); + command[buflen] = ' '; + command[buflen + 1] = '"'; + command[buflen + 2] = 0; + strcat(command, title); + buflen = strlen(command); + command[buflen] = '"'; + command[buflen + 1] = 0; + if(debug) + fprintf(stderr, "Debug >> processing command: %s\n", command); + pipe = popen(command, "r"); + if(pipe == NULL) { + fprintf(stderr, "Warning >> can't open pipe >%s< !\n", command); + return; + } + fgets(buffer, 1020, pipe); + while(!feof(pipe)) { + fputs(buffer, stdout); + fgets(buffer, 1020, pipe); + } + pclose(pipe); return; - } - - c=buffer+0x28; - sample_rate=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24); +} - while (c> unable to allocate cleared memory\n"); + exit(2); + } else { + unsigned int n = 0; + while(n < strlen(optarg)) { + if(debug) + fprintf(stderr, + "Debug >> genrelist entry activting : %d\n", + atoi(&optarg[n])); + genrelist[atoi(&optarg[n])] = 1; + while(isdigit(optarg[n++])); + } + } + break; + case 'n': + avoidhlinked = 1; + break; + case 'o': + close(1); + if(fopen(optarg, "w") == NULL) { + fprintf(stderr, + "Error >> unable to open output file : %s\n", + optarg); + exit(2); + } + break; + case 'p': + prefix = malloc(strlen(optarg) + 1); + strcpy(prefix, optarg); + base = malloc(strlen(prefix) + 1); + strcpy(base, prefix); + dir = strchr(base, '/'); + if((dir != NULL) && (dir[1] == '/')) + dir = strchr(dir + 2, '/'); + if(dir != NULL) + *dir++ = 0; + else + dir = ""; + /* if prefix is a weblink, base is the baselink, dir is the path */ + break; + case 'r': + recursive = 1; + break; + case 'u': + winorunix = one2one; + eol = "\n"; + break; + case 'w': + winorunix = unix2dos; + eol = "\r\n"; + break; + case 'x': + if(genrelist == NULL) { /* allow multiple includes/excludes - not recommended (confusing) but possible */ + int n = 0; + genrelist = calloc(257, sizeof(char)); + while(n < 256) + genrelist[n++] = 1; + } + if(genrelist == NULL) { + fprintf(stderr, + "Error >> unable to allocate cleared memory\n"); + exit(2); + } else { + unsigned int n = 0; + while(n < strlen(optarg)) { + if(debug) + fprintf(stderr, + "Debug >> genrelist entry activting : %d\n", + atoi(&optarg[n])); + genrelist[atoi(&optarg[n])] = 0; + while(isdigit(optarg[n++])); + } + } + break; + case 's': + fromstdin = 1; + break; + default: + usage(); + } } - if (strncasecmp(c,"ARTIST=",7)==0) - { - size=*(c-4)+(*(c-3)<<8)+(*(c-2)<<16)+(*(c-1)<<24); - strncpy(artist,c+7,size-7); - artist[size-7]='\0'; - c+=size; + /* hostname = getenv("HOSTNAME"); */ + if(genrelist == NULL) { + genrelist = calloc(257, sizeof(char)); + if(genrelist == NULL) { + fprintf(stderr, + "Error >> unable to allocate cleared memory\n"); + exit(2); + } else { + int n = 0; + while(n < 256) + genrelist[n++] = 1; + } } - if (strncasecmp(c,"GENRE=",6)==0) - { - static int i=0; - size=*(c-4)+(*(c-3)<<8)+(*(c-2)<<16)+(*(c-1)<<24); - strncpy(genrebuf,c+6,size-6); - genrebuf[size-6]='\0'; - c+=size; - for(i=0;i> parsing mp3 : %s\n", file); + + /* read header */ + if((fic = fopen(file, "r")) == NULL) { + fprintf(stderr, "Warning >> can't open file : %s\n", file); + return; + } + lus = fread(buffer, 1, MP3_BASE, fic); + c = buffer; + + /* try ID3v2 */ + if(buffer[0] == 'I' && buffer[1] == 'D' && buffer[2] == '3') { + int size; + int version; + version = *(buffer + 3); + if(version < 2 || version > 4) + fprintf(stderr, + "Warning >> ID3 v2.%d not implemented ! trying anyway : %s\n", + version, file); + if(*(buffer + 5) != 0) + fprintf(stderr, + "Warning >> specials headers not implemented (%d) ! trying anyway : %s\n", + *(buffer + 5), file); + c = buffer + 6; + size = + (*c << 21) + (*(c + 1) << 14) + (*(c + 2) << 7) + (*(c + 3)); + /* read more header */ + if(size + lus > MAX) { + lus += fread(buffer + lus, 1, MAX - lus, fic); + fprintf(stderr, + "Warning >> ID3 header is huge (%d bytes) ! trying anyway : %s\n", + size, file); + } else + lus += fread(buffer + lus, 1, size, fic); + if(size > lus) + size = lus; + c += 4; + if(version == 2) + while(c < buffer + size) { + int size = (*(c + 3) << 16) + (*(c + 4) << 8) + (*(c + 5)); + if(*c == 0) + break; + if(strncmp(c, "TT2", 3) == 0) { + strncpy(title, c + 7, size - 1); + title[size - 1] = '\0'; + } + if(strncmp(c, "TP1", 3) == 0) { + strncpy(artist, c + 7, size - 1); + artist[size - 1] = '\0'; + } + if(strncmp(c, "TCO", 3) == 0) { + /* strncpy(genrebuf,c+7,size-1); */ + /* genrebuf[size-1]='\0'; */ + /* genre=atoi(&genrebuf[1]); */ + genre = atoi(c + 8); + } + c += size + 6; + } + if(version == 3 || version == 4) + while(c < buffer + size) { + int size = + (*(c + 4) << 24) + (*(c + 5) << 16) + (*(c + 6) << 8) + + (*(c + 7)); + if(*c == 0) + break; + if(strncmp(c, "TIT2", 4) == 0) { + strncpy(title, c + 11, size - 1); + title[size - 1] = '\0'; + } + if(strncmp(c, "TPE1", 4) == 0) { + strncpy(artist, c + 11, size - 1); + artist[size - 1] = '\0'; + } + if(strncmp(c, "TCON", 4) == 0) { + /* strncpy(genrebuf,c+11,size-1); */ + /* genrebuf[size-1]='\0'; */ + /* genre=atoi(&genrebuf[1]); */ + genre = atoi(c + 12); + } + if(strncmp(c, "TLEN", 4) == 0) { + duration = atoi(c + 11) / 1000; + } + c += size + 10; + } + } + + while(c < buffer + lus - 10) { + if(*c == 0xFF && (*(c + 1) & 0xF0) == 0xF0) { + int version; + int lay; + int bitrate_index; + int bitrate; + version = 2 - (*(c + 1) >> 3 & 1); + lay = 4 - (*(c + 1) >> 1 & 3); + bitrate_index = *(c + 2) >> 4 & 0xF; + if(version >= 1 && version <= 2 && lay - 1 >= 0 && lay - 1 <= 2 + && bitrate_index >= 0 && bitrate_index <= 14) + bitrate = bitrates[version - 1][lay - 1][bitrate_index]; + else + bitrate = 0; + if(bitrate != 0) { + fseek(fic, 0, SEEK_END); + duration = (ftell(fic) + buffer - c) / 125 / bitrate; + } else + duration = 0; + break; } - if (i==ID3_NR_OF_V1_GENRES) genre=0; - } + c++; } - c++; - } - - fseek(fic,-OGG_BASE,SEEK_END); - lus=fread(buffer,1,OGG_BASE,fic); - c=buffer+lus-1; - while (strncmp(c,"OggS",4)!=0 && c>buffer) c--; - if (c!=buffer) - { - c+=6; - samples=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24); - duration=samples/sample_rate; - } - - fclose(fic); + + /* try ID3v1 */ + if(strlen(artist) == 0 && strlen(title) == 0) { + fseek(fic, -128, SEEK_END); + lus = fread(buffer, 1, 128, fic); + if(lus == 128 && buffer[0] == 'T' && buffer[1] == 'A' + && buffer[2] == 'G') { + strncpy(title, buffer + 3, 30); + title[30] = '\0'; + c = title + 29; + while(c > title && *c == ' ') + *(c--) = '\0'; + strncpy(artist, buffer + 33, 30); + artist[30] = '\0'; + c = artist + 29; + while(c > artist && *c == ' ') + *(c--) = '\0'; + /* strncpy(album,buffer+65,30); */ + /* strncpy(year,buffer+97,4); */ + /* strncpy(comment,buffer+101,30); */ + /* strncpy(genrebuf,buffer+127,1); genre[1]=0; */ + genre = buffer[127]; + } + } + + fclose(fic); } -void parse_mpc(unsigned char *file) +void parse_ogg(unsigned char *file) { - FILE *fic; - unsigned char *c; - int lus; - int sample_rates[4]={44100,48000,37800,32000}; - int frame_count; - int size,items; - int i; - - if (debug) fprintf(stderr,"Debug >> parsing mpc : %s\n",file); - - /* read header */ - if ((fic=fopen(file,"r"))==NULL) { fprintf(stderr,"Warning >> can't open file : %s\n",file); return; } - lus=fread(buffer,1,12,fic); - - /* try Musepack */ - if (buffer[0]!='M' && buffer[1]!='P' && buffer[2]!='+') - { - fprintf(stderr,"Warning >> not a Musepack header : %s\n",file); - return; - } - - /* only version 7 */ - if (buffer[3]!=7) - { - fprintf(stderr,"Warning >> only Musepack SV7 supported : %s\n",file); - return; - } - - /* duration */ - c=buffer+4; - frame_count=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24); - c+=5; - duration=frame_count*1152/sample_rates[*c&3]; - - /* try APETAGEX footer */ - fseek(fic,-32,SEEK_END); - lus=fread(buffer,1,32,fic); - if (lus==32 && strncmp(buffer,"APETAGEX",8)==0) - { - c=buffer+12; - size=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24); - size+=32; - c+=4; - items=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24); - fseek(fic,-size,SEEK_END); - lus=fread(buffer,1,size,fic); - if (lus==size && strncmp(buffer,"APETAGEX",8)==0) - { - c=buffer+32; - while (items--) - { - size=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24); - c+=8; - if (strcasecmp(c,"TITLE")==0) - { - strncpy(title,c+6,size); - title[size]='\0'; + FILE *fic; + unsigned char *c; + int lus; + int sample_rate; + int samples; + + if(debug) + fprintf(stderr, "Debug >> parsing ogg : %s\n", file); + + /* read header */ + if((fic = fopen(file, "r")) == NULL) { + fprintf(stderr, "Warning >> can't open file : %s\n", file); + return; + } + lus = fread(buffer, 1, OGG_BASE, fic); + + /* try Ogg */ + if(strncmp(buffer, "Ogg", 3) != 0) { + fprintf(stderr, "Warning >> not a Ogg header : %s\n", file); + return; + } + + c = buffer + 0x28; + sample_rate = + (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24); + + while(c < buffer + lus - 10) { + int size; + if(strncasecmp(c, "TITLE=", 6) == 0) { + size = + *(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) + + (*(c - 1) << 24); + strncpy(title, c + 6, size - 6); + title[size - 6] = '\0'; + c += size; } - if (strcasecmp(c,"ARTIST")==0) - { - strncpy(artist,c+7,size); - artist[size]='\0'; + if(strncasecmp(c, "ALBUM ARTIST=", 13) == 0) { + // ignore tag + size = + *(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) + + (*(c - 1) << 24); + c += size; } - if (strcasecmp(c,"GENRE")==0) - { - for(i=0;i buffer) + c--; + if(c != buffer) { + c += 6; + samples = + (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24); + duration = samples / sample_rate; + } + + fclose(fic); +} + +void parse_mpc(unsigned char *file) +{ + FILE *fic; + unsigned char *c; + int lus; + int sample_rates[4] = { 44100, 48000, 37800, 32000 }; + int frame_count; + int size, items; + int i; + + if(debug) + fprintf(stderr, "Debug >> parsing mpc : %s\n", file); + + /* read header */ + if((fic = fopen(file, "r")) == NULL) { + fprintf(stderr, "Warning >> can't open file : %s\n", file); + return; + } + lus = fread(buffer, 1, 12, fic); + + /* try Musepack */ + if (strncmp(buffer, "MP+", 3) != 0) { + fprintf(stderr, "Warning >> not a Musepack header : %s\n", file); + return; + } + + /* only version 7 */ + if(buffer[3] != 7) { + fprintf(stderr, "Warning >> only Musepack SV7 supported : %s\n", + file); + return; + } + + /* duration */ + c = buffer + 4; + frame_count = + (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24); + c += 5; + duration = frame_count * 1152 / sample_rates[*c & 3]; + + /* try APETAGEX footer */ + fseek(fic, -32, SEEK_END); + lus = fread(buffer, 1, 32, fic); + if(lus == 32 && strncmp(buffer, "APETAGEX", 8) == 0) { + c = buffer + 12; + size = + (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24); + size += 32; + c += 4; + items = + (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24); + fseek(fic, -size, SEEK_END); + lus = fread(buffer, 1, size, fic); + if(lus == size && strncmp(buffer, "APETAGEX", 8) == 0) { + c = buffer + 32; + while(items--) { + size = + (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + + (*(c + 3) << 24); + c += 8; + if(strcasecmp(c, "TITLE") == 0) { + strncpy(title, c + 6, size); + title[size] = '\0'; + } + if(strcasecmp(c, "ARTIST") == 0) { + strncpy(artist, c + 7, size); + artist[size] = '\0'; + } + if(strcasecmp(c, "GENRE") == 0) { + for(i = 0; i < ID3_NR_OF_V1_GENRES; i++) { + strncpy(genrebuf, c + 6, size); + genrebuf[size] = '\0'; + if(strcasecmp + (ID3_v1_genre_description[i], genrebuf) == 0) { + genre = i; + break; + } + if(i == ID3_NR_OF_V1_GENRES) + genre = 0; + } + } + c += strlen(c) + 1 + size; } - if (i==ID3_NR_OF_V1_GENRES) genre=0; - } } - c+=strlen(c)+1+size; - } } - } - fclose(fic); + fclose(fic); } -#define FSN 8 -#define MAXINO (1<<22) +#define FSN 32 +#define MAXINO (1<<24) #define INOTYP unsigned long #define regbit_qry(x,y) ( x[( (y) / sizeof(INOTYP) )] & 1<<( (y) % sizeof(INOTYP) ) ) #define regbit_set(x,y) ( x[( (y) / sizeof(INOTYP) )] |= 1<<( (y) % sizeof(INOTYP) ) ) -int hlink_check(struct stat*info) +int hlink_check(struct stat *info) { - /* - * for speed this subroutine should only be called - * - if the file has more than one hardlink - * - if the file is a resolved softlink - */ - /* the persistent variables */ - static INOTYP *list[FSN]; - static dev_t name[FSN]; - /* some temporary variables */ - int fsn, is_registered=0; - - /* assertions - in case parameters are lowered for less memory usage */ - assert(fsnst_ino)/sizeof(INOTYP)st_dev)) && (name[fsn]!=0) ; fsn++); - - /* if file system is not registered yet, do it and leave */ - if( name[fsn] == 0 ) - { - name[fsn] = (info->st_dev); - /* provide space for the bitmap that maps the inodes of this file system */ - list[fsn] = (INOTYP*)calloc(MAXINO,sizeof(INOTYP)); - /* no comparison is needed in empty lists ... return */ - if(debug) fprintf(stderr, "Debug >> Linked >> Init List %04x @mem %04lx\n", (int)name[fsn], (long)&list[fsn] ); - } else - { - /* this looks more complicated than it really is */ - /* the idea is very simple: - * provide a bitmap that maps all inodes of a file system - * to mark all files that have already been visited. - * If it is already visited, do not add it to the playlist - */ - /* - * The difficulty is as follows: - * struct inode_bitmap { char registered:1; } bitmap[1<st_ino) ) ) is_registered=1; - else regbit_set( list[fsn], (info->st_ino) ); /* - * the debug expression is more complicated then the working stuff + * for speed this subroutine should only be called + * - if the file has more than one hardlink + * - if the file is a resolved softlink */ - if(debug) - fprintf(stderr, "Debug >> Linked >> DEV %04x INO %06x => " - "list[%02x][%04x] = %04x & %04x --> %s registered\n", - (int)info->st_dev, (int)info->st_ino, fsn, (int)((info->st_ino)/sizeof(INOTYP)), - (int)list[fsn][(info->st_ino)/sizeof(INOTYP)], - 1<<((info->st_ino)%sizeof(INOTYP)), is_registered?"Already":"Not" ); - } - return is_registered; + /* the persistent variables */ + static INOTYP *list[FSN]; + static dev_t name[FSN]; + /* some temporary variables */ + int fsn, is_registered = 0; + + /* assertions - in case parameters are lowered for less memory usage */ + assert(fsn < FSN); + assert((info->st_ino) / sizeof(INOTYP) < MAXINO); + + /* search which internal registration number is used for this filesystem */ + for(fsn = 0; (name[fsn] != (info->st_dev)) && (name[fsn] != 0); fsn++); + + /* if file system is not registered yet, do it and leave */ + if(name[fsn] == 0) { + name[fsn] = (info->st_dev); + /* provide space for the bitmap that maps the inodes of this file system */ + list[fsn] = (INOTYP *) calloc(MAXINO, sizeof(INOTYP)); + /* no comparison is needed in empty lists ... return */ + if(debug) + fprintf(stderr, + "Debug >> Linked >> Init List %04x @mem %04lx\n", + (int)name[fsn], (long)&list[fsn]); + } else { + /* this looks more complicated than it really is */ + /* the idea is very simple: + * provide a bitmap that maps all inodes of a file system + * to mark all files that have already been visited. + * If it is already visited, do not add it to the playlist + */ + /* + * The difficulty is as follows: + * struct inode_bitmap { char registered:1; } bitmap[1<st_ino))) + is_registered = 1; + else + regbit_set(list[fsn], (info->st_ino)); + /* + * the debug expression is more complicated then the working stuff + */ + if(debug) + fprintf(stderr, "Debug >> Linked >> DEV %04x INO %06x => " + "list[%02x][%04x] = %04x & %04x --> %s registered\n", + (int)info->st_dev, (int)info->st_ino, fsn, + (int)((info->st_ino) / sizeof(INOTYP)), + (int)list[fsn][(info->st_ino) / sizeof(INOTYP)], + 1 << ((info->st_ino) % sizeof(INOTYP)), + is_registered ? "Already" : "Not"); + } + return is_registered; } -void parse_directory(unsigned char *path) +#ifdef HAVE_LIBURIPARSER +char * relative_uri_malloc(const char * unixFilename, const char * baseDir) { - int i,n; - struct dirent **namelist; - unsigned char newpath[PATH_MAX]; - unsigned char *c; - struct stat infos; - - void print_faketitle() - { - c=newpath+strlen(newpath); - while (c>newpath && *c!='/') c--; - while (c> parsing directory : %s\n",path); - if ((n=scandir(path,&namelist,0,alphasort))<0) { fprintf(stderr,"Warning >> can't open directory : %s\n",path); return; } - for (i=0;id_name); - if (stat(newpath,&infos)!=0) { fprintf(stderr,"Warning >> can't stat file : %s\n",newpath); continue; } - if (recursive && S_ISDIR(infos.st_mode) && strcmp(namelist[i]->d_name,".")!=0 && strcmp(namelist[i]->d_name,"..")!=0) parse_directory(newpath); - /* hlink_check() might be applied more selective ... avoidhlink is only a simple prereq */ - if (S_ISREG(infos.st_mode) && ! ( avoidhlinked && hlink_check(&infos) ) ) - { - unsigned char ext[5]; - int j; - for (j=0;j<5;j++) ext[j]=tolower(namelist[i]->d_name[strlen(namelist[i]->d_name)-4+j]); - artist[0]='\0'; - title[0]='\0'; - duration=-2; - if (strcmp(".mp2",ext)==0) { duration=-1; parse_mp3(newpath); } - if (strcmp(".mp3",ext)==0) { duration=-1; parse_mp3(newpath); } - if (strcmp(".mpc",ext)==0) { duration=-1; parse_mpc(newpath); } - if (strcmp(".mp+",ext)==0) { duration=-1; parse_mpc(newpath); } - if (strcmp(".ogg",ext)==0) { duration=-1; parse_ogg(newpath); } - if (strcmp(".wav",ext)==0) { duration=-1; /* parse_wav(newpath); */ } - - if (duration!=-2 && genrelist[genre]) /* is it an audio file ? */ - { + /* checks */ + if ((unixFilename == NULL) || (baseDir == NULL)) { + return NULL; + } + + /* base URI */ + baseUriString = malloc((7 + 3 * strlen(baseDir) + 1) * sizeof(char)); + if (baseUriString == NULL) { + return NULL; + } + if (uriUnixFilenameToUriStringA(baseDir, baseUriString) != 0) { + free(baseUriString); + return NULL; + } + state.uri = &baseUri; + if (uriParseUriA(&state, baseUriString) != 0) { + free(baseUriString); + uriFreeUriMembersA(&baseUri); + return NULL; + } + + /* source URI */ + if (unixFilename[0] != '/') { + const int baseDirLen = strlen(baseDir); + const int sourceFileLen = strlen(unixFilename); + absSourceLen = baseDirLen + sourceFileLen; + absSourceFile = malloc((absSourceLen + 1) * sizeof(char)); + sprintf(absSourceFile, "%s%s", baseDir, unixFilename); + } else { + absSourceLen = strlen(unixFilename); + absSourceFile = (char *)unixFilename; + } + sourceUriString = malloc((7 + 3 * absSourceLen + 1) * sizeof(char)); + if (sourceUriString == NULL) { + free(baseUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + uriFreeUriMembersA(&baseUri); + return NULL; + } + if (uriUnixFilenameToUriStringA(absSourceFile, sourceUriString) != 0) { + free(baseUriString); + free(sourceUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + uriFreeUriMembersA(&baseUri); + return NULL; + } + state.uri = &sourceUri; + if (uriParseUriA(&state, sourceUriString) != 0) { + free(baseUriString); + free(sourceUriString); + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&sourceUri); + return NULL; + } + if (uriNormalizeSyntaxA(&sourceUri) != 0) { + free(baseUriString); + free(sourceUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&sourceUri); + return NULL; + } + + /* make relative (or keep absolute if necessary) */ + if (uriRemoveBaseUriA(&relativeUri, &sourceUri, &baseUri, URI_FALSE) != 0) { + free(baseUriString); + free(sourceUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&sourceUri); + uriFreeUriMembersA(&relativeUri); + return NULL; + } + + /* back to string */ + if (uriToStringCharsRequiredA(&relativeUri, &charsRequired) != 0) { + free(baseUriString); + free(sourceUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&sourceUri); + uriFreeUriMembersA(&relativeUri); + return NULL; + } + output = malloc((charsRequired + 1) * sizeof(char)); + if (uriToStringA(output, &relativeUri, charsRequired + 1, NULL) != 0) { + free(baseUriString); + free(sourceUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + free(output); + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&sourceUri); + uriFreeUriMembersA(&relativeUri); + return NULL; + } + + free(baseUriString); + free(sourceUriString); + if (unixFilename[0] != '/') { + free(absSourceFile); + } + uriFreeUriMembersA(&baseUri); + uriFreeUriMembersA(&sourceUri); + uriFreeUriMembersA(&relativeUri); + + return output; +} + +char * xml_escape_malloc(const char * input) +{ + const char * read = input; + char * output; + char * write; + + if (input == NULL) { + return NULL; + } + + output = malloc((6 * strlen(input) + 1) * sizeof(char)); + if (output == NULL) { + return NULL; + } + write = output; + + for (;;) { + if (*read == '\0') { + *write = '\0'; + return output; + } + + switch ((unsigned char)*read) { + case '&': + strcpy(write, "&"); + write += 5; + break; + case '<': + strcpy(write, "<"); + write += 4; + break; + case '>': + strcpy(write, ">"); + write += 4; + break; + case '\'': + strcpy(write, "'"); + write += 6; + break; + case '"': + strcpy(write, """); + write += 6; + break; + default: + *(write++) = *read; + } + read++; + } +} +#endif + +void parse_file(unsigned char *newpath, unsigned char * original_path) +{ + unsigned char ext[5]; + int j, encoding = 0; + + for(j = 0; j < 5; j++) + ext[j] = tolower(newpath[strlen(newpath) - 4 + j]); + artist[0] = '\0'; + title[0] = '\0'; + duration = -2; + if(strcmp(".mp2", ext) == 0) { + duration = -1; + parse_mp3(newpath); + encoding = MP2ENC; + } + if(strcmp(".mp3", ext) == 0) { + duration = -1; + parse_mp3(newpath); + encoding = MP3ENC; + } + if(strcmp(".mpc", ext) == 0) { + duration = -1; + parse_mpc(newpath); + encoding = MPCENC; + } + if(strcmp(".mp+", ext) == 0) { + duration = -1; + parse_mpc(newpath); + encoding = MPPENC; + } + if(strcmp(".ogg", ext) == 0) { + duration = -1; + parse_ogg(newpath); + encoding = OGGENC; + } + if(strcmp(".wav", ext) == 0) { + duration = -1; + /* parse_wav(newpath); */ + encoding = WAVENC; + } + if(strcmp(".wma", ext) == 0) { + duration = -1; + /* parse_wma(newpath); */ + encoding = WMAENC; + } + /* guesstitle() */ + if((strlen(artist) == 0) && (strlen(title) == 0)) { + // there are no tag infos read + // use file name to state substitute it + char *c = strrchr(newpath, separator); + if(c == NULL) + c = newpath; + strcpy(artist, ++c); + // arbitrarily use the first '-' + // to separate artist and title + c = strchr(artist, '-'); + if(c != NULL) { // if trenner found, divide file name + *c = '\0'; + strcpy(title, ++c); + c = strrchr(title, '.'); + if(c != NULL) + *c = '\0'; + } else { // no trenner found, assume + // no artist, only title + strcpy(title, artist); + artist[0] = '\0'; + } + // replace underscores by spaces + for(c = artist; (c = strchr(c, '_')) != NULL; c++) + *c = ' '; + for(c = title; (c = strchr(c, '_')) != NULL; c++) + *c = ' '; + // trim spaces + trim(artist); + trim(title); + } + /* guesstitle() end */ + + if(duration != -2 && genrelist[genre]) { /* is it an audio file ? */ counter++; - switch (format) - { - case 0: - if (duration!=-1) - { - printf("#EXTINF:%d,",duration); - if (strlen(artist)==0 && strlen(title)==0) print_faketitle(); - else printf("%s - %s",artist,title); - printf("%s",eol); + switch (format) { + case FORMAT_M3U: + printf("#EXTINF:%d,", duration); + if(strlen(artist) != 0) + printf("%s - ", artist); + printf("%s%s", title, eol); + print_path(newpath); + printf("%s", eol); + break; + case FORMAT_PLS: + printf("File%d=", counter); + print_path(newpath); + printf("%sTitle%d=", eol, counter); + if(strlen(artist) != 0) + printf("%s - ", artist); + printf("%s%s", title, eol); + if(duration != -1) + printf("Length%d=%d%s", counter, duration, eol); + break; + case FORMAT_HTML: + printf("%d%s%s", counter, + artist, title); + if(duration == -1) + printf("?%s", eol); + else + printf("%d:%s%d%s", duration / 60, + duration % 60 < 10 ? "0" : "", duration % 60, eol); + break; + case FORMAT_RSS: + if(duration != -1) { + struct stat infos; + char timebuffer[256]; + + if(stat(newpath, &infos) != 0) { + fprintf(stderr, "Warning >> can't stat entry : %s\n", + newpath); + return; + } + strftime(timebuffer, 255, "%a %d %b %Y %T %z", localtime(&(infos.st_mtime))); /* ctime() had a trailing CR */ + printf("\t%s", eol); + printf("\t\t"); + myputstr(artist); + printf("%s\t\t", eol); + myputstr(title); + printf("%s", eol); + + if(referal == NULL) { + noreferal(newpath, artist, title); + } else + reference(newpath); + printf("\t\t%s%s\t\t%s\t\t", + (int)infos.st_size, magic[encoding], eol); + print_pathtail(newpath); + printf("%s", eol); + if(duration > 3599) + printf + ("\t\t%d:%02d:%02d%s", + duration / 3600, (duration / 60) % 60, + duration % 60, eol); + else + printf + ("\t\t%d:%02d%s", + duration / 60, duration % 60, eol); + if(strlen(artist) != 0) { + printf("\t\t"); + myputstr(artist); + printf("%s", eol); + } + printf("\t%s", eol); } - print_path(); - printf("%s",eol); break; - case 1: - printf("File%d=",counter); - print_path(); - printf("%s",eol); - printf("Title%d=",counter); - if (strlen(artist)==0 && strlen(title)==0) print_faketitle(); - else printf("%s - %s",artist,title); - printf("%s",eol); - if (duration!=-1) printf("Length%d=%d%s",counter,duration,eol); + case FORMAT_PLP: + myplaputstr("HARP, "); + myplaputstr(newpath); + myplaputstr(eol); break; - case 2: - printf("%d%s%s",counter,artist,title); - if (duration==-1) printf("?"); else printf("%d:%s%d",duration/60,duration%60<10?"0":"",duration%60); - printf("%s",eol); + case FORMAT_UMS: + txxputstr(newpath); break; +#ifdef HAVE_LIBURIPARSER + case FORMAT_XSPF: + printf("\n"); + if (strlen(title) > 0) { + char * escaped_title = xml_escape_malloc(title); + if (escaped_title != NULL) { + printf(" %s\n", escaped_title); + free(escaped_title); + } + } + if (strlen(artist) > 0) { + char * escaped_artist = xml_escape_malloc(artist); + if (escaped_artist != NULL) { + printf(" %s\n", escaped_artist); + free(escaped_artist); + } + } + if (duration > 0) { + printf(" %d\n", duration); + } + { + char * relative_location; + char * escaped_location; + relative_location = relative_uri_malloc(newpath, original_path); + if (relative_location != NULL) { + escaped_location = xml_escape_malloc(relative_location); + if (escaped_location != NULL) { + printf(" %s\n", escaped_location); + free(escaped_location); + } + free(relative_location); + } + } + printf("\n"); + break; +#endif + } + } +} + +void parse_directory(unsigned char *path, unsigned char * original_path) +{ + int i, n; + struct dirent **namelist; + unsigned char newpath[PATH_MAX]; + struct stat infos; + + if(debug) + fprintf(stderr, "Debug >> parsing directory : %s\n", path); + if(stat(path, &infos) != 0) { + fprintf(stderr, "Warning >> can't stat entry : %s\n", path); + return; + } + /* check if it is a filename */ + if(S_ISREG(infos.st_mode) || S_ISLNK(infos.st_mode)) { + parse_file(path, original_path); + return; + } + /* must be a directory - or something unusable like pipe, socket, etc */ + if((n = scandir(path, &namelist, 0, alphasort)) < 0) { + fprintf(stderr, "Warning >> can't open directory : %s\n", path); + return; + } + for(i = 0; i < n; i++) { + snprintf(newpath, PATH_MAX, "%s/%s", path, namelist[i]->d_name); + + if(stat(newpath, &infos) != 0) { + fprintf(stderr, "Warning >> can't stat entry : %s\n", newpath); + continue; + } + if(recursive && S_ISDIR(infos.st_mode) + && strcmp(namelist[i]->d_name, ".") != 0 + && strcmp(namelist[i]->d_name, "..") != 0) + parse_directory(newpath, original_path); + /* hlink_check() might be applied more selective ... avoidhlink is only a simple prereq */ + if(S_ISREG(infos.st_mode) + && !(avoidhlinked && hlink_check(&infos))) { + parse_file(newpath, original_path); } - } + free(namelist[i]); } - free(namelist[i]); - } - free(namelist); + free(namelist); } -int main(int argc,char **argv) +int main(int argc, char **argv) { - parse_options(argc,argv); - if (optind==argc) usage(); - switch (format) - { - case 0: - printf("#EXTM3U%s",eol); - break; - case 1: - printf("[playlist]%s",eol); - break; - case 2: - printf("%s%s%s%s%sPlaylist generated by FAPG 0.31%s%s%s%s%s%s%s

Playlist

%s%s%s%s",eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol); - break; - } - for (;optind%s%s

Playlist generated by FAPG 0.31

%s%s%s%s",eol,eol,eol,eol,eol,eol); - break; - } - if (genrelist) free(genrelist); - exit(0); + winorunix = one2one; + basemap = one2one; + parse_options(argc, argv); + + if(optind == argc && !fromstdin) + usage(); + + /* print header */ + switch (format) { + case FORMAT_M3U: + printf("#EXTM3U%s", eol); + break; + case FORMAT_PLS: + printf("[playlist]%s", eol); + break; + case FORMAT_HTML: + printf + ("%s%s%s%s%sPlaylist generated by FAPG " + VERSION + "%s%s%s%s%s%s%s

Playlist

%s%s
EntryArtistTitleLength
%s%s", + eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, + eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, + eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, + eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, + eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, + eol, eol, eol); + break; + case FORMAT_RSS: + { + time_t zeit; + char timebuffer[256]; + time(&zeit); + strftime(timebuffer, 255, "%a %d %b %Y %T %z", + localtime(&zeit)); + printf + ("%s%s%s %s\t%s - %s - %s%s\tDirectory Tree %s%s\t%s%s\t%s\t%s%s\tFAPG " + VERSION + "%s\t%s\t\t%s/podcast.jpg%s\t\tServer Logo%s\t\t%s%s\t\tFeed provided by FAPG. Click to visit.%s\t%s\t%s\t\tAdmin %s%s\t\tpodcast@%s%s\t%s\tVarious%s\tDirectory Tree %s%s\t%s%s\tunknown%s\t%s%s\tNo%s\t1800%s", + eol, eol, eol, eol, hostname, dir, argv[optind], eol, + prefix, eol, base, eol, prefix, eol, timebuffer, eol, eol, + eol, base, eol, eol, base, eol, eol, eol, eol, base, eol, + hostname, eol, eol, eol, dir, eol, getenv("LOGNAME"), eol, + eol, getenv("LANG"), eol, eol, eol); + unix2dos[38] = 43; // I never made an rss feed work with '&' in it + basemap = noand; + } + break; + case FORMAT_PLP: + { + eol = "\r\n"; + myplaputstr("PLP PLAYLIST\r\nVERSION 1.20\r\n\r\n"); + } + break; + case FORMAT_UMS: + { + txxputheader(" iriver UMS PLA"); + } + break; +#ifdef HAVE_LIBURIPARSER + case FORMAT_XSPF: + printf("\n" + "\n" + "\n" + "\n"); + break; +#endif + } + + /* iterate through files */ + { + const char * const pwd_source = getenv("PWD"); + const int pwdlen = strlen(pwd_source); + char * const pwd = malloc((pwdlen + 1 + 1) * sizeof(char)); + sprintf(pwd, "%s/", pwd_source); + + if(fromstdin) { + unsigned char path[PATH_MAX]; + int i; + while(fgets(path, PATH_MAX, stdin)) { + for(i = 0; i < PATH_MAX; i++) + if(path[i] == '\r' || path[i] == '\n') + path[i] = '\0'; + if (i <= 0) { + continue; + } + + /* strip trailing slash */ + if (path[i - 1] == '/') { + path[i - 1] = '\0'; + } + + parse_directory(path, pwd); + } + } else + for(; optind < argc; optind++) { + /* strip trailing slash */ + char * dup = strdup(argv[optind]); + const int len = strlen(dup); + if ((len > 0) && (dup[len - 1] == '/')) { + dup[len - 1] = '\0'; + } + + parse_directory(dup, pwd); + } + + free(pwd); + } + + /* print footer */ + switch (format) { + case FORMAT_PLS: + printf("NumberOfEntries=%d%sVersion=2%s", counter, eol, eol); + break; + case FORMAT_HTML: + printf + ("
EntryArtistTitleLength
%s%s

Playlist generated by FAPG " + VERSION "

%s%s%s%s", eol, eol, eol, eol, + eol, eol); + break; + case FORMAT_RSS: + printf(" %s%s", eol, eol); + break; + case FORMAT_UMS: + txxputcounter(counter); + break; +#ifdef HAVE_LIBURIPARSER + case FORMAT_XSPF: + printf("\n" + "\n"); + break; +#endif + } + + if(genrelist) + free(genrelist); + + exit(0); } +