363 lines
10 KiB
C++
363 lines
10 KiB
C++
#include "main.h"
|
|
#include "api.h"
|
|
#include "../nu/AutoWide.h"
|
|
#include "../nu/AutoWideFn.h"
|
|
#include "../nu/AutoChar.h"
|
|
#include "../nu/AutoCharFn.h"
|
|
#include "../nu/AutoLock.h"
|
|
#include "../nu/ns_wc.h"
|
|
#include <malloc.h>
|
|
|
|
using namespace Nullsoft::Utility;
|
|
/* Get Extended File Info */
|
|
|
|
typedef int (__cdecl *GetANSIInfo)(const char *fn, const char *data, char *dest, size_t destlen);
|
|
typedef int (__cdecl *GetUnicodeInfo)(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen);
|
|
|
|
int ConvertGetExtendedFileInfo(GetUnicodeInfo getter, const char *fn, const char *data, char *dest, size_t destlen)
|
|
{
|
|
wchar_t *destW = 0;
|
|
|
|
if (dest && destlen)
|
|
{
|
|
destW = (wchar_t *)_malloca(destlen * sizeof(wchar_t));
|
|
memset(destW, 0, destlen * sizeof(wchar_t));
|
|
}
|
|
|
|
int retVal = getter(AutoWideFn(fn), data, destW, destlen);
|
|
if (retVal && dest && destlen)
|
|
WideCharToMultiByteSZ(CP_ACP, 0, destW, -1, dest, (int)destlen, 0, 0);
|
|
|
|
if (destW) _freea(destW);
|
|
return retVal;
|
|
}
|
|
|
|
int ConvertGetExtendedFileInfo(GetANSIInfo getter, const char *fn, const char *data, wchar_t *dest, size_t destlen)
|
|
{
|
|
char *destA = 0;
|
|
|
|
if (dest && destlen)
|
|
{
|
|
destA = (char *)_malloca(destlen * sizeof(char));
|
|
memset(destA, 0, destlen * sizeof(char));
|
|
}
|
|
|
|
int retVal = getter(fn, data, destA, destlen);
|
|
if (retVal && dest && destlen)
|
|
MultiByteToWideCharSZ(CP_ACP, 0, destA, -1, dest, (int)destlen);
|
|
|
|
if (destA) _freea(destA);
|
|
return retVal;
|
|
}
|
|
|
|
static GetANSIInfo gefi;
|
|
static GetUnicodeInfo gefiW;
|
|
static char cachedExt[16];
|
|
LockGuard getMetadataGuard;
|
|
|
|
int in_get_extended_fileinfo(const char *fn, const char *metadata, char *dest, size_t destlen)
|
|
{
|
|
AutoLock lock(getMetadataGuard);
|
|
|
|
In_Module *i=0;
|
|
char ext[16] = {0};
|
|
int a = 0;
|
|
|
|
// do some extra checks on the params as quite a few clients crash when accessing here
|
|
try {
|
|
if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
|
|
fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
|
|
metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
|
|
return 0;
|
|
} catch (...) {
|
|
return 0;
|
|
}
|
|
|
|
if (dest)
|
|
memset(dest, 0, destlen);
|
|
|
|
extension_ex(fn, ext, sizeof(ext));
|
|
|
|
if (!_stricmp(cachedExt, ext) && *ext)
|
|
{
|
|
if (gefi)
|
|
return gefi(fn, metadata, dest, destlen);
|
|
else if (gefiW) // should always be true if we got this far
|
|
return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
while (a >= 0)
|
|
{
|
|
i = in_setmod_noplay(AutoWideFn(fn), &a);
|
|
if (!i)
|
|
break;
|
|
|
|
if (a >= 0) a++;
|
|
|
|
lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
|
|
|
|
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
|
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
|
if (gefi || gefiW)
|
|
break;
|
|
}
|
|
|
|
// if no one claimed it, then check if it's the currently playing track
|
|
// benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
|
|
if (!i && !lstrcmpiW(FileName, AutoWide(fn)))
|
|
{
|
|
i=in_mod;
|
|
if (i)
|
|
{
|
|
cachedExt[0]=0;
|
|
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
|
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
|
}
|
|
}
|
|
|
|
if (!i)
|
|
return 0;
|
|
|
|
if (gefi)
|
|
return gefi(fn, metadata, dest, destlen);
|
|
else if (gefiW)
|
|
return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int in_get_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *dest, size_t destlen)
|
|
{
|
|
AutoLock lock(getMetadataGuard);
|
|
|
|
In_Module *i=0;
|
|
char ext[16] = {0};
|
|
int a = 0;
|
|
|
|
// do some extra checks on the params as quite a few clients crash when accessing here
|
|
try {
|
|
if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
|
|
fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
|
|
metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
|
|
return 0;
|
|
} catch (...) {
|
|
return 0;
|
|
}
|
|
|
|
if (dest)
|
|
memset(dest, 0, destlen);
|
|
|
|
AutoCharFn charFn(fn);
|
|
extension_ex(charFn, ext, sizeof(ext));
|
|
|
|
if (!_stricmp(cachedExt, ext) && *ext)
|
|
{
|
|
if (gefiW) // should always be true if we got this far
|
|
return gefiW(fn, AutoChar(metadata), dest, destlen);
|
|
if (gefi)
|
|
return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
while (a >= 0)
|
|
{
|
|
i = in_setmod_noplay(fn, &a);
|
|
if (!i)
|
|
break;
|
|
|
|
if (a >= 0) a++;
|
|
|
|
lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
|
|
|
|
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
|
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
|
if (gefi || gefiW)
|
|
break;
|
|
}
|
|
|
|
// if no one claimed it, then check if it's the currently playing track
|
|
// benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
|
|
if (!i && !lstrcmpiW(FileName, fn)) // currently playing file?
|
|
{
|
|
i=in_mod;
|
|
if (i)
|
|
{
|
|
cachedExt[0]=0;
|
|
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
|
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
|
}
|
|
}
|
|
|
|
if (!i)
|
|
return 0;
|
|
|
|
if (gefiW)
|
|
return gefiW(fn, AutoChar(metadata), dest, destlen);
|
|
else if (gefi)
|
|
return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* Set Extended File Info */
|
|
|
|
typedef int (__cdecl *SetANSIInfo)(const char *fn, const char *metadata, const char *data);
|
|
typedef int (__cdecl *SetUnicodeInfo)(const wchar_t *fn, const char *metadata, const wchar_t *data);
|
|
|
|
static SetANSIInfo sefi;
|
|
static SetUnicodeInfo sefiW;
|
|
static int (*wefi)();
|
|
static char cachedExtSet[16];
|
|
|
|
static int ConvertSetExtendedFileInfo(SetUnicodeInfo setter, const char *fn, const char *metadata, const char *data)
|
|
{
|
|
return setter(AutoWide(fn), metadata, AutoWide(data));
|
|
}
|
|
|
|
static int ConvertSetExtendedFileInfo(SetANSIInfo setter, const char *fn, const char *metadata, const wchar_t *data)
|
|
{
|
|
return setter(fn, metadata, AutoChar(data));
|
|
}
|
|
|
|
int in_set_extended_fileinfo(const char *fn, const char *metadata, char *data)
|
|
{
|
|
AutoLock lock(getMetadataGuard);
|
|
char ext[16] = {0};
|
|
int a = 0;
|
|
|
|
extension_ex(fn, ext, sizeof(ext));
|
|
if (!_stricmp(cachedExtSet, ext) && *ext)
|
|
{
|
|
if (sefi)
|
|
return sefi(fn, metadata, data);
|
|
else if (sefiW)
|
|
return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
while (a >= 0)
|
|
{
|
|
wefi = NULL;
|
|
sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
|
|
sefiW = NULL;
|
|
In_Module *i = in_setmod_noplay(AutoWideFn(fn), &a);
|
|
if (a >= 0) a++;
|
|
cachedExtSet[0] = 0;
|
|
if (!i) return 0;
|
|
lstrcpynA(cachedExtSet, ext, 16);
|
|
|
|
sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
|
|
sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
|
|
wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
|
|
if (sefi || sefiW) break;
|
|
}
|
|
|
|
if (sefi)
|
|
return sefi(fn, metadata, data);
|
|
else if (sefiW)
|
|
return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int in_set_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *data)
|
|
{
|
|
AutoLock lock(getMetadataGuard);
|
|
|
|
char ext[16] = {0};
|
|
int a = 0;
|
|
|
|
AutoCharFn charFn(fn);
|
|
extension_ex(charFn, ext, sizeof(ext));
|
|
if (!_stricmp(cachedExtSet, ext) && *ext)
|
|
{
|
|
if (sefiW)
|
|
return sefiW(fn, AutoChar(metadata), data);
|
|
else if (sefi)
|
|
return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
while (a >= 0)
|
|
{
|
|
wefi = NULL;
|
|
sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
|
|
sefiW = NULL;
|
|
In_Module *i = in_setmod_noplay(fn, &a);
|
|
if (a >= 0) a++;
|
|
cachedExtSet[0] = 0;
|
|
if (!i) return 0;
|
|
lstrcpynA(cachedExtSet, ext, 16);
|
|
|
|
sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
|
|
sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
|
|
wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
|
|
if (sefi || sefiW) break;
|
|
}
|
|
if (sefiW)
|
|
return sefiW(fn, AutoChar(metadata), data);
|
|
else if (sefi)
|
|
return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int in_write_extended_fileinfo()
|
|
{
|
|
AutoLock lock(getMetadataGuard);
|
|
if (!wefi)
|
|
return 0;
|
|
return
|
|
wefi();
|
|
}
|
|
|
|
inline void COPY_METADATA(const wchar_t *src, const wchar_t *dest, const wchar_t *item, wchar_t *buf, size_t buflen)
|
|
{
|
|
if (NULL != src && NULL != item && NULL != buf)
|
|
{
|
|
buf[0]=0;
|
|
extendedFileInfoStructW efis=
|
|
{
|
|
src,
|
|
item,
|
|
buf,
|
|
buflen,
|
|
};
|
|
|
|
if (SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)&efis,IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
|
|
in_set_extended_fileinfoW(dest, item, buf);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//#define COPY_METADATA(src, dest, item, buf, buflen) { buf[0]=0; if (in_get_extended_fileinfoW(src, item, buf, buflen)) in_set_extended_fileinfoW(dest, item, buf); }
|
|
void CopyExtendedFileInfo(const wchar_t *source, const wchar_t *destination)
|
|
{
|
|
wchar_t bigData[32768] = {0}; // hopefully big enough for all reasonable metadata
|
|
|
|
COPY_METADATA(source, destination, L"title", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"artist", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"albumartist", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"album", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"genre", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"year", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"disc", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"publisher", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"comment", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"track", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"tool", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"composer", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"conductor", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"bpm", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"GracenoteFileID", bigData, 32768);
|
|
COPY_METADATA(source, destination, L"GracenoteExtData", bigData, 32768);
|
|
in_write_extended_fileinfo();
|
|
|
|
//albumArt->CopyAlbumArt(source, destination);
|
|
} |