diff options
Diffstat (limited to '3rdparty/libflac/src/plugin_winamp2/tagz.cpp')
-rw-r--r-- | 3rdparty/libflac/src/plugin_winamp2/tagz.cpp | 921 |
1 files changed, 921 insertions, 0 deletions
diff --git a/3rdparty/libflac/src/plugin_winamp2/tagz.cpp b/3rdparty/libflac/src/plugin_winamp2/tagz.cpp new file mode 100644 index 00000000000..a2c5a4857e5 --- /dev/null +++ b/3rdparty/libflac/src/plugin_winamp2/tagz.cpp @@ -0,0 +1,921 @@ +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include "tagz.h" + +#ifdef TAGZ_UNICODE + +#define _TX(X) L##X +#define t_strdup wcsdup +#define t_strlen wcslen +#define t_strnicmp wcsnicmp +#define t_atoi(x) wcstol(x,0,10) +#define t_stricmp wcsicmp +#define t_strstr wcsstr +#define sprintf swprintf + +#else + +#define _TX(X) X +#define t_strdup strdup +#define t_strlen strlen +#define t_strnicmp strnicmp +#define t_atoi atoi +#define t_stricmp stricmp +#define t_strstr strstr + +#endif + +#define TABSIZE(x) (sizeof(x)/sizeof(x[0])) + + +class T_String +{ +private: + T_CHAR * data; + UINT size,used; +public: + T_String() {data=0;size=0;used=0;} + void AddChar(T_CHAR c) + { + if (!data) + { + data=(T_CHAR*)malloc((size=512)*sizeof(T_CHAR)); + used=0; + } + else if (size==used) + { + size<<=1; + data=(T_CHAR*)realloc((char*)data,size*sizeof(T_CHAR)); + } + if (data) data[used++]=c; + } + void AddInt(int i) + { + T_CHAR foo[16]; + sprintf(foo,_TX("%i"),i); + AddString(foo); + } + void AddString(const T_CHAR * z) + { + while(*z) {AddChar(*z);z++;} + } + void AddString(T_String & s) + { + AddString(s.Peek()); + } + ~T_String() + { + if (data) free(data); + } + T_CHAR * GetBuf() + { + if (!data) return ::t_strdup(_TX("")); + T_CHAR * r=(T_CHAR*)realloc(data,(used+1)*sizeof(T_CHAR)); + r[used]=0; + data=0; + return r; + } + T_CHAR operator[](UINT i) + { + if (!data || i>=used) return 0; + else return data[i]; + } + UINT Len() {return data ? used : 0;} + void Reset() + { + if (data) {free(data);data=0;} + } + const T_CHAR * Peek() + { + AddChar(0); + used--; + return data; + } + T_CHAR * strdup() + { + return ::t_strdup(Peek()); + } +}; + + + + +static int separator(T_CHAR x) +{ + if (!x || x==' ') return 1; + if (x=='\'' || x=='_') return 0; +#ifdef TAGZ_UNICODE + return !iswalnum(x); +#else + return !isalnum(x); +#endif +} + +static int sepcmp(T_CHAR* src,T_CHAR* val) +{ + UINT l=t_strlen(val); + return !t_strnicmp(src,val,l) && separator(src[l]); +} + +static char roman_num[]= +{ + 'I','V','X','L','C','D','M' +}; + + +static int is_roman(T_CHAR * ptr)/* could be more smart i think */ +{ + if (ptr[0]==']' && ptr[1]=='[' && separator(ptr[2])) return 1; + while(!separator(*ptr)) + { + UINT n; + bool found=0; + for(n=0;n<TABSIZE(roman_num);n++) + { + if (*ptr==roman_num[n]) {found=1;break;} + } + if (!found) return 0; + ptr++; + } + return 1; +} + +static int need_full(T_CHAR* ptr) +{ + if (is_roman(ptr)) return 1; + if (sepcmp(ptr,_TX("RPG"))) return 1; + while(!separator(*ptr)) + { + if (*ptr<'0' || *ptr>'9') return 0; + ptr++; + } + return 1; +} + +typedef bool (*TEXTFUNC)(UINT n_src,T_CHAR **src,UINT*,T_String &out); + +#define MAKEFUNC(X) static bool X(UINT n_src,T_CHAR ** src,UINT *found_src,T_String &out) + + +MAKEFUNC(If) +{ + if (n_src!=3) return false; + + out.AddString(src[found_src[0] ? 1 : 2]); + return true; +} + +MAKEFUNC(If2) +{ + if (n_src!=2) return false; + + out.AddString(src[found_src[0] ? 0 : 1]); + return true; +} + + +MAKEFUNC(Iflonger) +{ + if (n_src!=4) return false; + + out.AddString(src[(int)t_strlen(src[0])>t_atoi(src[1]) ? 2 : 3]); + return true; +} + +MAKEFUNC(Ifgreater) +{ + if (n_src!=4) return false; + + out.AddString(src[t_atoi(src[0])>t_atoi(src[1]) ? 2 : 3]); + return true; +} + +MAKEFUNC(Upper) +{ + if (n_src!=1) return false; + + T_CHAR * s=src[0]; + + while(*s) + out.AddChar(toupper(*(s++))); + + return true; +} + +MAKEFUNC(Lower) +{ + if (n_src!=1) return false; + + T_CHAR * s=src[0]; + + while(*s) + out.AddChar(tolower(*(s++))); + + return true; +} + +MAKEFUNC(Pad) +{ + if (n_src<2 || n_src>3) return false; + + T_CHAR *fill=_TX(" "); + if (n_src==3 && src[2][0]) + fill = src[2]; + + int num = t_atoi(src[1]); + T_CHAR *p = src[0]; + + while (*p) { out.AddChar(*(p++)); num--; } + + UINT fl = t_strlen(fill); + while (num>0) + out.AddChar(fill[(--num)%fl]); + + return true; +} + +MAKEFUNC(Cut) +{ + if (n_src!=2) return false; + + UINT num = t_atoi(src[1]); + T_CHAR *p = src[0]; + + while (*p && num>0) {out.AddChar(*(p++));num--;} + + return true; +} + +MAKEFUNC(PadCut) +{ + if (n_src<2 || n_src>3) return false; + + T_CHAR *fill = _TX(" "); + if (n_src==3 && src[2][0]) + fill = src[2]; + + int num = t_atoi(src[1]); + T_CHAR *p = src[0]; + + while(*p && num>0) {out.AddChar(*(p++));num--;} + + UINT fl=t_strlen(fill); + while (num>0) + out.AddChar(fill[(--num)%fl]); + + return true; +} + +/* abbr(string) */ +/* abbr(string,len) */ +MAKEFUNC(Abbr) +{ + if (n_src==0 || n_src>2) return false; + + + if (n_src==2 && (int)t_strlen(src[0])<t_atoi(src[1])) + { + out.AddString(src[0]); + return true; + } + + T_CHAR * meta=src[0]; + bool w=0, r=0; + + while(*meta) + { + bool an=!separator(*meta) || *meta==']' || *meta=='['; + + if (w && !an) + w=0; + else if (!w && an) + { + w=1; + r=need_full(meta)?1:0; + out.AddChar(*meta); + } + else if (w && r) + out.AddChar(*meta); + meta++; + } + + return true; +} + + + +MAKEFUNC(Caps) +{ + if (n_src!=1) return false; + + T_CHAR* sp=src[0]; + int sep = 1; + + while(*sp) + { + T_CHAR c=*(sp++); + int s = separator(c); + if (!s && sep) + c=toupper(c); + else if (!sep) c=tolower(c); + sep=s; + out.AddChar(c); + } + + return true; +} + +MAKEFUNC(Caps2) +{ + if (n_src!=1) return false; + + T_CHAR* sp=src[0]; + int sep=1; + + while(*sp) + { + T_CHAR c=*(sp++); + int s = separator(c); + if (!s && sep) + c=toupper(c); + sep=s; + out.AddChar(c); + } + + return true; +} + +MAKEFUNC(Longest) +{ + T_CHAR *ptr=0; + UINT n, m=0; + + for(n=0;n<n_src;n++) + { + UINT l=t_strlen(src[n]); + if (l>m) {m=l;ptr=src[n];} + } + + if (ptr) out.AddString(ptr); + return true; +} + +MAKEFUNC(Shortest) +{ + T_CHAR * ptr=0; + UINT n,m=(UINT)(-1); + + for(n=0;n<n_src;n++) + { + UINT l=t_strlen(src[n]); + if (l<m) {m=l;ptr=src[n];} + } + + if (ptr) out.AddString(ptr); + return true; +} + +MAKEFUNC(Num) +{ + if (n_src!=2) return false; + + T_CHAR tmp[16]; + T_CHAR tmp1[16]; + sprintf(tmp1,_TX("%%0%uu"),t_atoi(src[1])); + sprintf(tmp,tmp1,t_atoi(src[0])); + out.AddString(tmp); + + return true; +} + +MAKEFUNC(Hex) +{ + if (n_src!=2) return false; + + T_CHAR tmp[16]; + T_CHAR tmp1[16]; + sprintf(tmp1,_TX("%%0%ux"),t_atoi(src[1])); + sprintf(tmp,tmp1,t_atoi(src[0])); + out.AddString(tmp); + + return true; +} + +MAKEFUNC(StrChr) +{ + if (n_src!=2) return false; + + T_CHAR * p=src[0]; + T_CHAR s=src[1][0]; + + while (*p && *p!=s) p++; + if (*p==s) + out.AddInt(1+p-src[0]); + else out.AddChar('0'); + + return true; +} + +MAKEFUNC(StrRChr) +{ + if (n_src!=2) return false; + + T_CHAR * p=src[0],*p1=0; + T_CHAR s=src[1][0]; + + while(*p) + { + if (*p==s) p1=p; + p++; + } + + if (p1) + out.AddInt(1+p1-src[0]); + else out.AddChar('0'); + + return true; +} + +MAKEFUNC(StrStr) +{ + if (n_src!=2) return false; + + T_CHAR * p = t_strstr(src[0],src[1]); + + if (p) + out.AddInt(1+p-src[0]); + else out.AddChar('0'); + + return true; +} + +/* substr(string, index) */ +/* substr(string, index, length) */ +MAKEFUNC(SubStr) +{ + if (n_src<2 || n_src>3) return false; + + int n1 = t_atoi(src[1]), n2; + + if (n_src == 3) + n2 = t_atoi(src[2]); + else n2 = n1; + + if (n1 < 1) n1=1; + if (n2 >= n1) + { + n1--; + n2--; + while(n1<=n2 && src[0][n1]) + out.AddChar(src[0][n1++]); + } + + return true; +} + +MAKEFUNC(Len) +{ + if (n_src!=1) return false; + + out.AddInt(t_strlen(src[0])); + return true; +} + +MAKEFUNC(Add) +{ + UINT n; + int s=0; + + for (n=0;n<n_src;n++) + s+=t_atoi(src[n]); + + out.AddInt(s); + + return true; +} + +MAKEFUNC(Sub) +{ + if (n_src==0) return false; + + UINT n; + int s=t_atoi(src[0]); + + for (n=1;n<n_src;n++) + s-=t_atoi(src[n]); + + out.AddInt(s); + + return true; +} + +MAKEFUNC(Mul) +{ + UINT n; + int s=1; + + for(n=0;n<n_src;n++) + s*=t_atoi(src[n]); + + out.AddInt(s); + + return true; +} + +MAKEFUNC(Div) +{ + if (n_src==0) return false; + + UINT n; + int s=t_atoi(src[0]); + + for(n=1;n<n_src;n++) + { + int t=t_atoi(src[n]); + if (t) s/=t; + else t=0; + } + + out.AddInt(s); + + return true; +} + +MAKEFUNC(Mod) +{ + if (n_src==0) return false; + + UINT n; + int s=t_atoi(src[0]); + + for(n=1;n<n_src;n++) + { + int t=t_atoi(src[n]); + if (t) s%=t; + else t=0; + } + + out.AddInt(s); + + return true; +} + +MAKEFUNC(Max) +{ + if (!n_src) return false; + + int m = t_atoi(src[0]); + UINT n; + + for (n=1; n<n_src; n++) + { + int t = t_atoi(src[n]); + if (t > m) m = t; + } + out.AddInt(m); + + return true; +} + +MAKEFUNC(Min) +{ + if (!n_src) return false; + + int m=t_atoi(src[0]); + UINT n; + + for(n=1;n<n_src;n++) + { + int t=t_atoi(src[n]); + if (t<m) m=t; + } + out.AddInt(m); + + return true; +} + +/* replace(string, what_to_replace, replacement) */ +MAKEFUNC(Replace) +{ + if (n_src!=3) return false; + T_CHAR *p = src[0]; + + while (*p) + { + UINT n=0; + + while (src[1][n] && p[n]==src[1][n]) n++; + + if (!src[1][n]) + { + out.AddString(src[2]); + p += n; + } + else out.AddChar(*p++); + } + + return true; +} + +struct +{ + TEXTFUNC func; + const T_CHAR * name; +} +FUNCS[] = +{ + If,_TX("if"), + If2,_TX("if2"), + Upper,_TX("upper"), + Lower,_TX("lower"), + Pad,_TX("pad"), + Cut,_TX("cut"), + PadCut,_TX("padcut"), + Abbr,_TX("abbr"), + Caps,_TX("caps"), + Caps2,_TX("caps2"), + Longest,_TX("longest"), + Shortest,_TX("shortest"), + Iflonger,_TX("iflonger"), + Ifgreater,_TX("ifgreater"), + Num,_TX("num"),Num,_TX("dec"), + Hex,_TX("hex"), + StrChr,_TX("strchr"), + StrChr,_TX("strlchr"), + StrRChr,_TX("strrchr"), + StrStr,_TX("strstr"), + SubStr,_TX("substr"), + Len,_TX("len"), + Add,_TX("add"), + Sub,_TX("sub"), + Mul,_TX("mul"), + Div,_TX("div"), + Mod,_TX("mod"), + Min,_TX("min"), + Max,_TX("max"), + Replace,_TX("replace"), +}; + + +class FMT +{ +private: + T_String str; + T_CHAR * spec; + TAGFUNC f; + TAGFREEFUNC ff; + void * fp; + T_CHAR * org_spec; + int found; + + void Error(T_CHAR *e=0) + { + str.Reset(); + str.AddString(e ? e : _TX("[SYNTAX ERROR IN FORMATTING STRING]")); + found++; /* force displaying */ + } + + T_CHAR * _FMT(T_CHAR * s,UINT *f=0) + { + FMT fmt(this,s); + T_CHAR * c=(T_CHAR*)fmt; + if (f) *f=fmt.found; + found+=fmt.found; + return c; + } + + static bool skipshit(T_CHAR** _p,T_CHAR *bl) + { + T_CHAR * p=*_p; + int bc1=0,bc2=0; + while(*p) + { + if (!bc1 && !bc2 && bl) + { + T_CHAR *z=bl; + while(*z) + { + if (*z==*p) break; + z++; + } + if (*z) break; + } + if (*p=='\'') + { + p++; + while(*p && *p!='\'') p++; + if (!*p) return 0; + } + else if (*p=='(') bc1++; + else if (*p==')') + { + if (--bc1<0) return 0; + } + else if (*p=='[') bc2++; + else if (*p==']') + { + if (--bc2<0) return 0; + } + p++; + } + *_p=p; + return *p && !bc1 && !bc2; + } + + void run() + { + if (!spec) {Error();return;} + while(*spec) + { + if (*spec=='%') + { + spec++; + if (*spec=='%') {str.AddChar('%');spec++;continue;} + T_CHAR* s1=spec+1; + while(*s1 && *s1!='%') s1++; + if (!*s1) {Error();break;} + *s1=0; + T_CHAR * tag=f(spec,fp); + *s1='%'; + /*if (!tag) tag=tag_unknown; */ + if (tag && tag[0]) + { + found++; + str.AddString(tag); + } + else + { + str.AddString(_TX("?")); + } + if (tag && ff) ff(tag,fp); + spec=s1+1; + } + else if (*spec=='$') + { + spec++; + if (*spec=='$') {str.AddChar('$');spec++;continue;} + T_CHAR * s1=spec+1; + while(*s1 && *s1!='(') s1++; + if (!*s1) {Error();break;} + T_CHAR * s2=s1+1; + if (!skipshit(&s2,_TX(")"))) {Error();break;} + if (!*s2) {Error();break;}; + T_CHAR * p=s1+1; + T_CHAR* temp[64]; + UINT temp_f[64]; + UINT nt=0; + T_CHAR * p1=s1+1; + while(p<=s2 && nt<64) + { + if (!skipshit(&p,_TX(",)"))) {Error();return;} + if (p>s2 || (*p!=',' && *p!=')')) {Error(_TX("internal error"));return;} + T_CHAR bk=*p; + *p=0; + temp[nt]=_FMT(p1,&temp_f[nt]); + nt++; + *p=bk;; + p1=p+1; + p++; + } + *s1=0; + UINT n; + + for (n=0; n<TABSIZE(FUNCS); n++) + if (!t_stricmp(spec, FUNCS[n].name)) + break; + + *s1='('; + + if (n != TABSIZE(FUNCS)) + { + if (!FUNCS[n].func(nt, temp, temp_f, str)) + { + Error(_TX("[INVALID $")); + str.AddString(FUNCS[n].name); + str.AddString(_TX(" SYNTAX]")); + return; + } + } + else + { + Error(_TX("[UNKNOWN FUNCTION]")); + return; + } + + for(n=0;n<nt;n++) free(temp[n]); + spec=s2+1; + } + else if (*spec=='\'') + { + spec++; + if (*spec=='\'') {str.AddChar('\'');spec++;continue;} + T_CHAR * s1=spec+1; + while(*s1 && *s1!='\'') s1++; + if (!*s1) {Error();break;} + *s1=0; + str.AddString(spec); + *s1='\''; + spec=s1+1; + } + else if (*spec=='[') + { + spec++; + T_CHAR * s1=spec; + UINT bc=0; + if (!skipshit(&s1,_TX("]"))) {Error();break;} + T_CHAR bk=*s1; + *s1=0; + FMT fmt(this,spec); + fmt.run(); + if (fmt.found) + { + str.AddString(fmt.str); + found+=fmt.found; + } + *s1=bk; + spec=s1+1; + } + else if (*spec == ']') {Error();break;} + else + { + str.AddChar(*spec); + spec++; + } + } + } + + FMT(FMT* base,T_CHAR * _spec) + { + found=0; + org_spec=0; + f=base->f; + ff=base->ff; + fp=base->fp; + spec=_spec; + } +public: + FMT(const T_CHAR * p_spec,TAGFUNC _f,TAGFREEFUNC _ff,void * _fp) + { + found=0; + org_spec=spec=t_strdup(p_spec); + f=_f; + ff=_ff; + fp=_fp; + } + operator T_CHAR*() + { + run(); + return str.GetBuf(); + } + ~FMT() + { + if (org_spec) free(org_spec); + } +}; + +extern "C" +{ + +UINT tagz_format(const T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void *fp,T_CHAR* out,UINT max) +{ + T_CHAR * zz=tagz_format_r(spec,f,ff,fp); + UINT r=0; + while(r<max-1 && zz[r]) + { + out[r]=zz[r]; + r++; + } + out[r]=0; + free(zz); + return r; +} + +T_CHAR * tagz_format_r(const T_CHAR* spec,TAGFUNC f,TAGFREEFUNC ff,void * fp) +{ + return FMT(spec,f,ff,fp); +} + +const char tagz_manual[]="Syntax reference: \n" + "\n" + "* %tagname% - inserts field named <tagname>, eg. \"%artist%\"\n" + "* $abbr(x) - inserts abbreviation of x, eg. \"$abbr(%album%)\" - will convert album name of \"Final Fantasy VI\" to \"FFVI\"\n" + "* $abbr(x,y) - inserts abbreviation of x if x is longer than y characters; otherwise inserts full value of x, eg. \"$abbr(%album%,10)\"\n" + "* $lower(x), $upper(x) - converts x to in lower/uppercase, eg. \"$upper(%title%)\"\n" + "* $num(x,y) - displays x number and pads with zeros up to y characters (useful for track numbers), eg. $num(%tracknumber%,2)\n" + "* $caps(x) - converts first letter in every word of x to uppercase, and all other letters to lowercase, eg. \"blah BLAH\" -> \"Blah Blah\"\n" + "* $caps2(x) - similar to $caps, but leaves uppercase letters as they are, eg. \"blah BLAH\" -> \"Blah BLAH\"\n" + "* $if(A,B,C) - if A contains at least one valid tag, displays B, otherwise displays C; eg. \"$if(%artist%,%artist%,unknown artist)\" will display artist name if present; otherwise will display \"unknown artist\"; note that \"$if(A,A,)\" is equivalent to \"[A]\" (see below)\n" + "* $if2(A,B) - equals to $if(A,A,B)\n" + "* $longest(A,B,C,....) - compares lengths of output strings produced by A,B,C... and displays the longest one, eg. \"$longest(%title%,%comment%)\" will display either title if it's longer than comment; otherwise it will display comment\n" + "* $pad(x,y) - pads x with spaces up to y characters\n" + "* $cut(x,y) - truncates x to y characters\n" + "* $padcut(x,y) - pads x to y characters and truncates to y if longer\n" + "* [ .... ] - displays contents of brackets only if at least one of fields referenced inside has been found, eg. \"%artist% - [%album% / ]%title%\" will hide [] block if album field is not present\n" + "* \' (single quotation mark) - outputs raw text without parsing, eg, \'blah$blah%blah[][]\' will output the contained string and ignore all reserved characters (%,$,[,]) in it; you can use this feature to insert square brackets for an example.\n" + "\n" + "eg. \"[%artist% - ][$abbr(%album%,10)[ %tracknumber%] / ]%title%[ %streamtitle%]\"\n"; + + +} |