334 lines
8.4 KiB
C++
334 lines
8.4 KiB
C++
#include <windows.h>
|
|
#include "../../General/gen_ml/ml.h"
|
|
#include "../../Library/ml_pmp/pmp.h"
|
|
#include "AndroidDevice.h"
|
|
#include <strsafe.h>
|
|
#include <shlwapi.h>
|
|
|
|
BOOL RecursiveCreateDirectory(wchar_t* buf1);
|
|
__int64 fileSize(wchar_t * filename);
|
|
bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
|
|
DeviceType detectDeviceType(wchar_t drive);
|
|
void removebadchars(wchar_t *s);
|
|
wchar_t * FixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
|
|
|
|
void removebadchars(wchar_t *s) {
|
|
while (s && *s)
|
|
{
|
|
if (*s == L'?' || *s == L'/' || *s == L'\\' || *s == L':' || *s == L'*' || *s == L'\"' || *s == L'<' || *s == L'>' || *s == L'|')
|
|
*s = L'_';
|
|
s = CharNextW(s);
|
|
}
|
|
}
|
|
|
|
__int64 fileSize(wchar_t * filename)
|
|
{
|
|
WIN32_FIND_DATA f={0};
|
|
HANDLE h = FindFirstFileW(filename,&f);
|
|
if(h == INVALID_HANDLE_VALUE) return -1;
|
|
FindClose(h);
|
|
ULARGE_INTEGER i;
|
|
i.HighPart = f.nFileSizeHigh;
|
|
i.LowPart = f.nFileSizeLow;
|
|
return i.QuadPart;
|
|
}
|
|
|
|
// RecursiveCreateDirectory: creates all non-existent folders in a path
|
|
BOOL RecursiveCreateDirectory(wchar_t* buf1) {
|
|
wchar_t *p=buf1;
|
|
int errors = 0;
|
|
if (*p) {
|
|
p = PathSkipRoot(buf1);
|
|
if (!p) return true ;
|
|
|
|
wchar_t ch='c';
|
|
while (ch) {
|
|
while (p && *p != '\\' && *p) p = CharNext(p);
|
|
ch = (p ? *p : 0);
|
|
if (p) *p = 0;
|
|
int pp = (int)wcslen(buf1)-1;
|
|
|
|
while(buf1[pp] == '.' || buf1[pp] == ' ' ||
|
|
(buf1[pp] == '\\' && (buf1[pp-1] == '.' || buf1[pp-1] == ' ' || buf1[pp-1] == '/')) ||
|
|
buf1[pp] == '/' && buf1)
|
|
{
|
|
if(buf1[pp] == '\\')
|
|
{
|
|
buf1[pp-1] = '_';
|
|
pp -= 2;
|
|
} else {
|
|
buf1[pp] = '_';
|
|
pp--;
|
|
}
|
|
}
|
|
|
|
WIN32_FIND_DATA fd = {0};
|
|
// Avoid a "There is no disk in the drive" error box on empty removable drives
|
|
UINT prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
|
HANDLE h = FindFirstFile(buf1,&fd);
|
|
SetErrorMode(prevErrorMode);
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!CreateDirectory(buf1,NULL)) errors++;
|
|
} else {
|
|
FindClose(h);
|
|
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) errors++;
|
|
}
|
|
if (p) *p++ = ch;
|
|
}
|
|
}
|
|
|
|
return errors != 0;
|
|
}
|
|
|
|
bool supportedFormat(wchar_t * file, wchar_t * supportedFormats) {
|
|
wchar_t * ext = wcsrchr(file,'.');
|
|
if(!ext) return false;
|
|
ext++;
|
|
wchar_t * p = supportedFormats;
|
|
while(p && *p) {
|
|
bool ret=false;
|
|
wchar_t * np = wcschr(p,L';');
|
|
if(np) *np = 0;
|
|
if(!_wcsicmp(ext,p)) ret=true;
|
|
if(np) { *np = L';'; p=np+1; }
|
|
else return ret;
|
|
if(ret) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// FixReplacementVars: replaces <Artist>, <Title>, <Album>, and #, ##, ##, with appropriate data
|
|
// DOES NOT add a file extention!!
|
|
wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song)
|
|
{
|
|
#define ADD_STR(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) outp++; }
|
|
#define ADD_STR_U(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towupper(*outp); outp++; } }
|
|
#define ADD_STR_L(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towlower(*outp); outp++; } }
|
|
|
|
wchar_t tmpsrc[4096] = {0};
|
|
lstrcpyn(tmpsrc,str,sizeof(tmpsrc)/sizeof(wchar_t)); //lstrcpyn is nice enough to make sure it's null terminated.
|
|
|
|
wchar_t *inp = tmpsrc;
|
|
wchar_t *outp = str;
|
|
int slash = 0;
|
|
|
|
while (inp && *inp && outp-str < str_size-2)
|
|
{
|
|
if (*inp == L'<')
|
|
{
|
|
if (!wcsncmp(inp,L"<TITLE>",7))
|
|
{
|
|
ADD_STR_U(dev->getTrackTitle);
|
|
inp+=7;
|
|
}
|
|
else if (!wcsncmp(inp,L"<title>",7))
|
|
{
|
|
ADD_STR_L(dev->getTrackTitle);
|
|
inp+=7;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<Title>",7))
|
|
{
|
|
ADD_STR(dev->getTrackTitle);
|
|
inp+=7;
|
|
}
|
|
else if (!wcsncmp(inp,L"<ALBUM>",7))
|
|
{
|
|
ADD_STR_U(dev->getTrackAlbum);
|
|
inp+=7;
|
|
}
|
|
else if (!wcsncmp(inp,L"<album>",7))
|
|
{
|
|
ADD_STR_L(dev->getTrackAlbum);
|
|
inp+=7;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<Album>",7))
|
|
{
|
|
ADD_STR(dev->getTrackAlbum);
|
|
inp+=7;
|
|
}
|
|
else if (!wcsncmp(inp,L"<GENRE>",7))
|
|
{
|
|
ADD_STR_U(dev->getTrackGenre);
|
|
inp+=7;
|
|
}
|
|
else if (!wcsncmp(inp,L"<genre>",7))
|
|
{
|
|
ADD_STR_L(dev->getTrackGenre);
|
|
inp+=7;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<Genre>",7))
|
|
{
|
|
ADD_STR(dev->getTrackGenre);
|
|
inp+=7;
|
|
}
|
|
else if (!wcsncmp(inp,L"<ARTIST>",8))
|
|
{
|
|
ADD_STR_U(dev->getTrackArtist);
|
|
inp+=8;
|
|
}
|
|
else if (!wcsncmp(inp,L"<artist>",8))
|
|
{
|
|
ADD_STR_L(dev->getTrackArtist);
|
|
inp+=8;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<Artist>",8))
|
|
{
|
|
ADD_STR(dev->getTrackArtist);
|
|
inp+=8;
|
|
}
|
|
else if (!wcsncmp(inp,L"<ALBUMARTIST>",13))
|
|
{
|
|
wchar_t temp[128] = {0};
|
|
|
|
dev->getTrackAlbumArtist(song, temp, 128);
|
|
if (temp[0] == 0)
|
|
dev->getTrackArtist(song, temp, 128);
|
|
|
|
lstrcpyn(outp,temp,str_size-1-(outp-str));
|
|
removebadchars(outp);
|
|
while (outp && *outp) { *outp=towupper(*outp); outp++; }
|
|
|
|
inp+=13;
|
|
}
|
|
else if (!wcsncmp(inp,L"<albumartist>",13))
|
|
{
|
|
wchar_t temp[128] = {0};
|
|
|
|
dev->getTrackAlbumArtist(song, temp, 128);
|
|
if (temp[0] == 0)
|
|
dev->getTrackArtist(song, temp, 128);
|
|
|
|
lstrcpyn(outp,temp,str_size-1-(outp-str));
|
|
removebadchars(outp);
|
|
while (outp && *outp) { *outp=towlower(*outp); outp++; }
|
|
inp+=13;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<Albumartist>",13))
|
|
{
|
|
wchar_t temp[128] = {0};
|
|
|
|
dev->getTrackAlbumArtist(song, temp, 128);
|
|
if (temp[0] == 0)
|
|
dev->getTrackArtist(song, temp, 128);
|
|
|
|
lstrcpyn(outp,temp, (int)str_size-1-(outp-str));
|
|
removebadchars(outp);
|
|
while (outp && *outp) outp++;
|
|
inp+=13;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<year>",6))
|
|
{
|
|
wchar_t year[64] = {0};
|
|
int y = dev->getTrackYear(song);
|
|
if (y) StringCchPrintf(year, ARRAYSIZE(year), L"%d", y);
|
|
lstrcpyn(outp,year, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
|
|
inp+=6;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<disc>",6))
|
|
{
|
|
wchar_t disc[16] = {0};
|
|
int d = dev->getTrackDiscNum(song);
|
|
if (d) StringCchPrintf(disc, ARRAYSIZE(disc), L"%d", d);
|
|
lstrcpyn(outp,disc, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
|
|
inp+=6;
|
|
}
|
|
else if (!_wcsnicmp(inp,L"<filename>",10))
|
|
{
|
|
wchar_t tfn[MAX_PATH], *ext, *fn;
|
|
StringCchCopy(tfn,MAX_PATH,((AndroidSong*)song)->filename);
|
|
ext = wcsrchr(tfn, L'.');
|
|
*ext = 0; //kill extension since its added later
|
|
fn = wcsrchr(tfn, L'\\');
|
|
fn++;
|
|
lstrcpyn(outp,fn, (int)str_size-1-(outp-str));
|
|
while (outp && *outp) outp++;
|
|
inp+=10;
|
|
}
|
|
else
|
|
{
|
|
// use this to skip over unknown tags
|
|
while (inp && *inp && *inp != L'>') inp++;
|
|
if (inp) inp++;
|
|
}
|
|
}
|
|
else if (*inp == L'#')
|
|
{
|
|
int nd=0;
|
|
wchar_t tmp[64] = {0};
|
|
while (inp && *inp == L'#') nd++,inp++;
|
|
int track = dev->getTrackTrackNum(song);
|
|
if (!track)
|
|
{
|
|
while (inp && *inp == L' ') inp++;
|
|
while (inp && *inp == L'\\') inp++;
|
|
if (inp && (*inp == L'-' || *inp == L'.' || *inp == L'_')) // separator
|
|
{
|
|
inp++;
|
|
while (inp && *inp == L' ') inp++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nd > 1)
|
|
{
|
|
wchar_t tmp2[32] = {0};
|
|
if (nd > 5) nd=5;
|
|
StringCchPrintf(tmp2, ARRAYSIZE(tmp2), L"%%%02dd",nd);
|
|
StringCchPrintf(tmp, ARRAYSIZE(tmp), tmp2,track);
|
|
}
|
|
else StringCchPrintf(tmp, ARRAYSIZE(tmp), L"%d",track);
|
|
}
|
|
lstrcpyn(outp,tmp, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
|
|
}
|
|
else
|
|
{
|
|
if (*inp == L'\\') slash += 1;
|
|
*outp++=*inp++;
|
|
}
|
|
}
|
|
|
|
if (outp) *outp = 0;
|
|
|
|
// if we end up with something like U:\\\ then this
|
|
// will set it to be just <filename> so it'll not
|
|
// end up making a load of bad files e.g. U:\.mp3
|
|
int out_len = lstrlen(str);
|
|
if (out_len)
|
|
{
|
|
if (out_len - 2 == slash)
|
|
{
|
|
outp = str + 3;
|
|
wchar_t tfn[MAX_PATH], *ext, *fn;
|
|
StringCchCopy(tfn,MAX_PATH,((AndroidSong*)song)->filename);
|
|
ext = wcsrchr(tfn, L'.');
|
|
*ext = 0; //kill extension since its added later
|
|
fn = wcsrchr(tfn, L'\\');
|
|
fn++;
|
|
lstrcpyn(outp,fn, (int)str_size-1-(outp-str));
|
|
while (outp && *outp) outp++;
|
|
if (outp) *outp = 0;
|
|
}
|
|
}
|
|
|
|
inp=str;
|
|
outp=str;
|
|
wchar_t lastc=0;
|
|
while (inp && *inp)
|
|
{
|
|
wchar_t ch=*inp++;
|
|
if (ch == L'\t') ch=L' ';
|
|
|
|
if (ch == L' ' && (lastc == L' ' || lastc == L'\\' || lastc == L'/')) continue; // ignore space after slash, or another space
|
|
|
|
if ((ch == L'\\' || ch == L'/') && lastc == L' ') outp--; // if we have a space then slash, back up to write the slash where the space was
|
|
*outp++=ch;
|
|
lastc=ch;
|
|
}
|
|
if (outp) *outp=0;
|
|
#undef ADD_STR
|
|
#undef ADD_STR_L
|
|
#undef ADD_STR_U
|
|
|
|
return str;
|
|
} |