#define MPP_ENCODER #include "mppdec.h" #include typedef struct { unsigned char Artist [512]; unsigned char Title [512]; unsigned char Album [512]; unsigned char Year [ 5]; unsigned int Number; } taginfo_t; static int xdigit ( char c ) { if ( (unsigned int )(c-'0') < 10 ) return c-'0'; if ( (unsigned int )(c-'A') < 6 ) return c-'A'+10; return -1; } static void percent ( char* p ) { char* q = p; for (; *p; ) { if ( p[0] == '%' && xdigit(p[1]) >= 0 && xdigit(p[2]) >= 0 ) *q++ = 16*xdigit(p[1]) + xdigit(p[2]), p += 3; else if (p[0] == '_') *q++ = ' ', p++; else *q++ = *p++; } *q = '\0'; } static char* separator ( char* s ) { while (*s) { if ( s[0] == PATH_SEP ) { s[0] = '\0'; return s+1; } if ( (s[0]==' ' || s[0]=='_') && s[1]=='-' && s[2]=='-' && (s[3]==' ' || s[3]=='_') ) { s[0] = '\0'; return s+4; } s++; } return NULL; } static int IsIndexType1 ( const char* s ) { if ( s[0]=='[' && isdigit(s[1]) && isdigit(s[2]) && s[3]==']' && (s[4]==' ' || s[4]=='_') ) return 10*s[1]+s[2]-11*'0'; if ( 0 == strcmp (s, "[00]") ) return 0; return -1; } static int IsIndexType2 ( const char* s ) { if ( isdigit(s[0]) && isdigit(s[1]) && s[2] == '\0' ) return 10*s[0]+s[1]-11*'0'; return -1; } typedef int (*idxfn) (const char*); int ParseName ( const char* filename, taginfo_t* const T ) { unsigned char* Components [64]; idxfn fn [2] = { IsIndexType1, IsIndexType2 }; int Ci = 0; char Path [PATHLEN_MAX] = ""; char Name [PATHLEN_MAX]; char* p; int i; int j; #if DRIVE_SEP != '\0' char Drive = '@'; #endif #if DRIVE_SEP != '\0' // drive specified? if ( isalpha (filename[0]) && filename[1] == DRIVE_SEP ) { Drive = filename[0]; filename += 2; } #endif if ( filename[0] != PATH_SEP ) { // no absolute path, so get the current folder for this drive p = Path; #if DRIVE_SEP != '\0' # if defined _WIN32 _getdcwd ( Drive & 0x1F, Path, sizeof Path ); # else getcurdir ( Drive & 0x1F, Path ); # endif if ( isalpha (p[0]) && p[1] == DRIVE_SEP ) p += 2; #else getcwd ( Path, sizeof Path ); #endif // parse the current folder while ( p != NULL && *p != '\0' ) { Components [Ci++] = p; p = separator ( p ); } } // parse the filename strcpy ( Name, filename ); p = Name; while ( p != NULL && *p != '\0' ) { Components [Ci++] = p; p = separator ( p ); } // remove ".", ".." and names from file formats for ( i = j = 0; i < Ci; i++ ) if ( 0 == strcmp (Components [i], "" ) ) ; else if ( 0 == strcmp (Components [i], "." ) ) ; else if ( 0 == strcmp (Components [i], "wav") ) ; else if ( 0 == strcmp (Components [i], "pac") ) ; else if ( 0 == strcmp (Components [i], "mpc") ) ; else if ( 0 == strcmp (Components [i], "mpp") ) ; else if ( 0 == strcmp (Components [i], "mp+") ) ; else if ( 0 == strcmp (Components [i], "mp3") ) ; else if ( 0 == strcmp (Components [i], ".." ) ) j -= j ? 1 : 0; else Components [j++] = Components [i]; Ci = j; // remove file extension p = strrchr ( Components [Ci-1], '.'); if ( p != NULL ) *p = '\0'; // Merging of (CD 1), (CD 1/7), (CD 1/12) is still missing // Decoding of %XX and "_" is still missing T->Year [0] = '\0'; T->Artist[0] = '\0'; T->Album [0] = '\0'; T->Title [0] = '\0'; T->Number = -1; if ( fn[0] ( Components [Ci-1]) >= 0 ) { strcpy ( T->Album , Components [Ci-2] ); strcpy ( T->Artist, Components [Ci-3] ); strcpy ( T->Title , strlen (Components [Ci-1]) >= 5 ? Components [Ci-1]+5 : (unsigned char*)"" ); T->Number = fn[0] ( Components [Ci-1]); goto okay; } if ( fn[0] ( Components [Ci-2]) >= 0 ) { strcpy ( T->Album , Components [Ci-3] ); strcpy ( T->Artist, Components [Ci-2]+5 ); strcpy ( T->Title , Components [Ci-1] ); T->Number = fn[0] ( Components [Ci-2]); goto okay; } if ( fn[1] ( Components [Ci-1]) == 0 ) { strcpy ( T->Album , Components [Ci-2] ); strcpy ( T->Artist, Components [Ci-3] ); strcpy ( T->Title , "" ); T->Number = 0; goto okay; } if ( fn[1] ( Components [Ci-2]) >= 0 ) { strcpy ( T->Album , Components [Ci-3] ); strcpy ( T->Artist, Components [Ci-4] ); strcpy ( T->Title , Components [Ci-1] ); T->Number = fn[1] ( Components [Ci-2]); goto okay; } if ( fn[1] ( Components [Ci-3]) >= 0 ) { strcpy ( T->Album , Components [Ci-4] ); strcpy ( T->Artist, Components [Ci-2] ); strcpy ( T->Title , Components [Ci-1] ); T->Number = fn[1] ( Components [Ci-3]); goto okay; } for ( i = 0; i < Ci; i++) printf ( "'%s' ", Components [i] ); printf ( "\n" ); return 1; okay: T->Year[0] = '\0'; if ( strlen (T->Album) >= 8 ) { p = T->Album + strlen (T->Album) - 7; if (p[0] == ' ' && p[1]=='(' && p[6]=='1') { i = atoi (p+2); if ( i >= 1900 && i <= 2019 ) { sprintf (T->Year, "%4u", i); p[0] = '\0'; } } } percent (T->Album); percent (T->Artist); percent (T->Title); return 0; } int main ( int argc, char** argv ) { taginfo_t T; const char* extentions [] = { ".mpc", ".mp+", ".mpp", ".wav", ".ape", ".pac", NULL }; mysetargv ( &argc, &argv, extentions ); while ( *++argv ) { fprintf ( stderr, "%s\n", *argv ); ParseName (*argv, &T); printf ( "%-40.40s %-40.40s %4.4s [%02d] %s\n", T.Artist, T.Album, T.Year, T.Number, T.Title ); } return 0; }