269 lines
8.2 KiB
C++
269 lines
8.2 KiB
C++
|
#include "main.h"
|
||
|
#include "../nu/ns_wc.h"
|
||
|
#include "../winamp/wa_ipc.h"
|
||
|
#include <shlwapi.h>
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
#define TID_UNKNOWN 0
|
||
|
#define TID_ARTIST 1
|
||
|
#define TID_ALBUM 2
|
||
|
#define TID_TITLE 3
|
||
|
#define TID_GENRE 4
|
||
|
#define TID_YEAR 5
|
||
|
#define TID_TRACKARTIST 6
|
||
|
#define TID_FILENAME 7
|
||
|
#define TID_EXTENSION 8
|
||
|
#define TID_DISC 9
|
||
|
#define TID_DISCS 10
|
||
|
|
||
|
#define TOKEN_ARTIST TEXT("<artist>")
|
||
|
#define TOKEN_ALBUM TEXT("<album>")
|
||
|
#define TOKEN_TITLE TEXT("<title>")
|
||
|
#define TOKEN_GENRE TEXT("<genre>")
|
||
|
#define TOKEN_YEAR TEXT("<year>")
|
||
|
#define TOKEN_TRACKARTIST TEXT("<trackartist>")
|
||
|
#define TOKEN_FILENAME TEXT("<filename>")
|
||
|
#define TOKEN_EXTENSION TEXT("<extension>")
|
||
|
#define TOKEN_DISC TEXT("<disc>")
|
||
|
#define TOKEN_DISCS TEXT("<discs>")
|
||
|
|
||
|
#define TOKEN_LEN_ARTIST 8
|
||
|
#define TOKEN_LEN_ALBUM 7
|
||
|
#define TOKEN_LEN_TITLE 7
|
||
|
#define TOKEN_LEN_GENRE 7
|
||
|
#define TOKEN_LEN_YEAR 6
|
||
|
#define TOKEN_LEN_TRACKARTIST 13
|
||
|
#define TOKEN_LEN_FILENAME 10
|
||
|
#define TOKEN_LEN_EXTENSION 11
|
||
|
#define TOKEN_LEN_DISC 6
|
||
|
#define TOKEN_LEN_DISCS 7
|
||
|
|
||
|
#define STRCOMP_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
|
||
|
|
||
|
#define CHECK_TOKEN(token, format) (CSTR_EQUAL == CompareString(STRCOMP_INVARIANT, NORM_IGNORECASE, TOKEN_##token##, TOKEN_LEN_##token##, format, TOKEN_LEN_##token##))
|
||
|
|
||
|
|
||
|
static TCHAR PathValidateChar(TCHAR cVal, BOOL bAllowBackSlash)
|
||
|
{
|
||
|
switch(cVal)
|
||
|
{
|
||
|
case TEXT('\\'): if (!bAllowBackSlash) return TEXT('-');
|
||
|
break;
|
||
|
case TEXT('/'): if (!bAllowBackSlash) return TEXT('-');
|
||
|
return TEXT('\\');
|
||
|
|
||
|
case TEXT(':'): return TEXT('-');
|
||
|
case TEXT('*'): return TEXT('_');
|
||
|
case TEXT('?'): return TEXT('_');
|
||
|
case TEXT('\"'): return TEXT('\'');
|
||
|
case TEXT('<'): return TEXT('(');
|
||
|
case TEXT('>'): return TEXT(')');
|
||
|
case TEXT('|'): return TEXT('_');
|
||
|
}
|
||
|
return cVal;
|
||
|
}
|
||
|
|
||
|
void CleanupDirectoryString(LPTSTR pszDirectory)
|
||
|
{
|
||
|
PathUnquoteSpaces(pszDirectory);
|
||
|
PathRemoveBlanks(pszDirectory);
|
||
|
|
||
|
LPTSTR pc = pszDirectory;
|
||
|
while (TEXT('\0') != *pc) { if (TEXT('/') == *pc) *pc = TEXT('\\'); pc++; }
|
||
|
|
||
|
if (pc > pszDirectory)
|
||
|
{
|
||
|
pc--;
|
||
|
while (pszDirectory != pc &&
|
||
|
(TEXT('.') == *pc || TEXT(' ') == *pc || TEXT('\\') == *pc))
|
||
|
{
|
||
|
*pc = TEXT('\0');
|
||
|
pc--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LPWSTR GetExtensionString(LPWSTR pszBuffer, INT cchBufferMax, DWORD fourcc)
|
||
|
{
|
||
|
char configExt[10] = { '\0', };
|
||
|
pszBuffer[0] = L'\0';
|
||
|
convertConfigItem cfi;
|
||
|
cfi.configfile = 0;
|
||
|
cfi.data = configExt;
|
||
|
cfi.format = fourcc;
|
||
|
cfi.item = "extension";
|
||
|
cfi.len = 10;
|
||
|
SENDWAIPC(plugin.hwndWinampParent, IPC_CONVERT_CONFIG_GET_ITEM, (WPARAM)&cfi);
|
||
|
if ('\0' != *configExt)
|
||
|
{
|
||
|
if (!MultiByteToWideCharSZ(CP_ACP, 0, configExt, -1, pszBuffer, cchBufferMax))
|
||
|
return NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (cchBufferMax < 5) return NULL;
|
||
|
pszBuffer[0] = (TCHAR)((fourcc) & 0xff);
|
||
|
pszBuffer[1] = (TCHAR)((fourcc >> 8) & 0xff);
|
||
|
pszBuffer[2] = (TCHAR)((fourcc >> 16) & 0xff);
|
||
|
pszBuffer[3] = TEXT('\0');
|
||
|
for (LPTSTR p = &pszBuffer[2]; p >= pszBuffer && TEXT(' ') == *p; p--) *p = TEXT('\0');
|
||
|
}
|
||
|
return pszBuffer;
|
||
|
}
|
||
|
|
||
|
// if trackno is 0xdeadbeef, or title is 0, they are both ignored
|
||
|
// TODO: use ATF instead
|
||
|
HRESULT FormatFileName(LPTSTR pszTextOut, INT cchTextMax, LPCTSTR pszFormat,
|
||
|
INT nTrackNo, LPCTSTR pszArtist,
|
||
|
LPCTSTR pszAlbum, LPCTSTR pszTitle,
|
||
|
LPCTSTR pszGenre, LPCTSTR pszYear,
|
||
|
LPCTSTR pszTrackArtist,
|
||
|
LPCTSTR pszFileName, LPCTSTR pszDisc)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
TCHAR szBuffer[MAX_PATH] = {0};
|
||
|
LPTSTR pszStart = pszTextOut + lstrlen(pszTextOut);
|
||
|
|
||
|
while (pszFormat && TEXT('\0') != *pszFormat)
|
||
|
{
|
||
|
int whichstr = TID_UNKNOWN;
|
||
|
if (*pszFormat == TEXT('#') && nTrackNo != 0xdeadbeef)
|
||
|
{
|
||
|
int cnt = 0;
|
||
|
while (pszFormat && *pszFormat == TEXT('#')) { pszFormat++; cnt++; }
|
||
|
if (cnt > 8) cnt = 8;
|
||
|
|
||
|
TCHAR szFormat[32] = {0};
|
||
|
hr = StringCchPrintf(szFormat, ARRAYSIZE(szFormat), TEXT("%%%02dd"), cnt);
|
||
|
if (S_OK == hr) StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, nTrackNo);
|
||
|
if (S_OK == hr) StringCchCat(pszTextOut, cchTextMax, szBuffer);
|
||
|
if (S_OK != hr) return hr;
|
||
|
}
|
||
|
else if (pszArtist && CHECK_TOKEN(ARTIST, pszFormat)) whichstr = TID_ARTIST;
|
||
|
else if (pszAlbum && CHECK_TOKEN(ALBUM, pszFormat)) whichstr = TID_ALBUM;
|
||
|
else if (pszTitle && CHECK_TOKEN(TITLE, pszFormat)) whichstr = TID_TITLE;
|
||
|
else if (pszGenre && CHECK_TOKEN(GENRE, pszFormat)) whichstr = TID_GENRE;
|
||
|
else if (pszYear && CHECK_TOKEN(YEAR, pszFormat)) whichstr = TID_YEAR;
|
||
|
else if (pszTrackArtist && CHECK_TOKEN(TRACKARTIST, pszFormat)) whichstr = TID_TRACKARTIST;
|
||
|
else if (pszFileName && CHECK_TOKEN(FILENAME, pszFormat)) whichstr = TID_FILENAME;
|
||
|
else if (pszFileName && CHECK_TOKEN(EXTENSION, pszFormat)) whichstr = TID_EXTENSION;
|
||
|
else if (pszDisc && CHECK_TOKEN(DISC, pszFormat)) whichstr = TID_DISC;
|
||
|
else if (pszDisc && CHECK_TOKEN(DISCS, pszFormat)) whichstr = TID_DISCS;
|
||
|
else
|
||
|
{
|
||
|
INT l = lstrlen(pszTextOut);
|
||
|
pszTextOut += l;
|
||
|
cchTextMax -= l;
|
||
|
pszTextOut[0] = *pszFormat++;
|
||
|
if (cchTextMax < 2) return STRSAFE_E_INSUFFICIENT_BUFFER;
|
||
|
pszTextOut[0] = PathValidateChar(pszTextOut[0], TRUE);
|
||
|
if (TEXT('\\') == *pszTextOut)
|
||
|
{
|
||
|
// remove end spaces and dots
|
||
|
while (pszTextOut > pszStart &&
|
||
|
(TEXT('\\') == *(pszTextOut - 1) || TEXT(' ') == *(pszTextOut - 1) || TEXT('.') == *(pszTextOut - 1)))
|
||
|
{
|
||
|
pszTextOut--;
|
||
|
cchTextMax--;
|
||
|
}
|
||
|
|
||
|
if (pszTextOut == pszStart)
|
||
|
{
|
||
|
pszTextOut--;
|
||
|
cchTextMax--;
|
||
|
}
|
||
|
else *pszTextOut = TEXT('\\');
|
||
|
}
|
||
|
pszTextOut++;
|
||
|
cchTextMax--;
|
||
|
*pszTextOut = TEXT('\0');
|
||
|
if (S_OK != hr) return hr;
|
||
|
}
|
||
|
if (whichstr != TID_UNKNOWN)
|
||
|
{
|
||
|
LPCTSTR pszSrc = NULL;
|
||
|
int islow = IsCharLower(pszFormat[1]) && IsCharLower(pszFormat[2]);
|
||
|
int ishi = IsCharUpper(pszFormat[1]) && IsCharUpper(pszFormat[2]);
|
||
|
switch(whichstr)
|
||
|
{
|
||
|
case TID_ARTIST: pszSrc = pszArtist; pszFormat += TOKEN_LEN_ARTIST; break;
|
||
|
case TID_ALBUM: pszSrc = pszAlbum; pszFormat += TOKEN_LEN_ALBUM; break;
|
||
|
case TID_TITLE: pszSrc = pszTitle; pszFormat += TOKEN_LEN_TITLE; break;
|
||
|
case TID_GENRE: pszSrc = pszGenre; pszFormat += TOKEN_LEN_GENRE; break;
|
||
|
case TID_YEAR: pszSrc = pszYear; pszFormat += TOKEN_LEN_YEAR; break;
|
||
|
case TID_TRACKARTIST: pszSrc = pszTrackArtist; pszFormat += TOKEN_LEN_TRACKARTIST; break;
|
||
|
case TID_DISC:
|
||
|
if (pszDisc && *pszDisc && TEXT('\0') == *pszDisc) pszSrc = L"1";
|
||
|
else
|
||
|
{
|
||
|
// default to 1 when we've not got a proper value passed to us
|
||
|
int disc = _wtoi(pszDisc);
|
||
|
if(disc <= 0) disc = 1;
|
||
|
StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%d", disc);
|
||
|
pszSrc = szBuffer;
|
||
|
}
|
||
|
pszFormat += TOKEN_LEN_DISC;
|
||
|
break;
|
||
|
case TID_DISCS:
|
||
|
if (pszDisc && *pszDisc && TEXT('\0') == *pszDisc) pszSrc = L"1";
|
||
|
else
|
||
|
{
|
||
|
LPTSTR pszTemp = wcschr((LPTSTR)pszDisc, L'/');
|
||
|
if(pszTemp == NULL) pszTemp = wcschr((LPTSTR)pszDisc, L'\\');
|
||
|
if(pszTemp == NULL)
|
||
|
{
|
||
|
pszTemp = (LPTSTR)pszDisc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszTemp = CharNext(pszTemp);
|
||
|
}
|
||
|
int disc = _wtoi(pszTemp);
|
||
|
if(disc <= 0) disc = 1;
|
||
|
StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%d", disc);
|
||
|
pszSrc = szBuffer;
|
||
|
}
|
||
|
pszFormat += TOKEN_LEN_DISCS;
|
||
|
break;
|
||
|
case TID_FILENAME:
|
||
|
pszSrc = PathFindExtension(pszFileName);
|
||
|
if (TEXT('\0') == *pszSrc) pszSrc = pszFileName;
|
||
|
else
|
||
|
{
|
||
|
StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszFileName);
|
||
|
PathRemoveExtension(szBuffer);
|
||
|
pszSrc = szBuffer;
|
||
|
}
|
||
|
pszFormat += TOKEN_LEN_FILENAME;
|
||
|
break;
|
||
|
case TID_EXTENSION:
|
||
|
pszSrc = PathFindExtension(pszFileName); pszFormat += TOKEN_LEN_EXTENSION;
|
||
|
while (pszTextOut > pszStart && TEXT('.') == *(pszTextOut - 1))
|
||
|
{
|
||
|
pszTextOut--;
|
||
|
*pszTextOut = TEXT('\0');
|
||
|
cchTextMax++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
INT l = lstrlen(pszTextOut);
|
||
|
pszTextOut += l;
|
||
|
cchTextMax -= l;
|
||
|
|
||
|
while (pszSrc && TEXT('\0') != *pszSrc && cchTextMax > 0)
|
||
|
{
|
||
|
pszTextOut[0] = pszSrc[0];
|
||
|
if (ishi) CharUpperBuffW(pszTextOut, 1);
|
||
|
else if (islow) CharLowerBuffW(pszTextOut, 1);
|
||
|
pszTextOut[0] = PathValidateChar(pszTextOut[0], FALSE);
|
||
|
cchTextMax--;
|
||
|
if (cchTextMax) pszTextOut++;
|
||
|
pszSrc++;
|
||
|
}
|
||
|
pszTextOut[0] = TEXT('\0');
|
||
|
if (0 == cchTextMax) return STRSAFE_E_INSUFFICIENT_BUFFER;
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|