diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/ExtendedInfo.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Winamp/ExtendedInfo.cpp')
-rw-r--r-- | Src/Winamp/ExtendedInfo.cpp | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/Src/Winamp/ExtendedInfo.cpp b/Src/Winamp/ExtendedInfo.cpp new file mode 100644 index 00000000..4c743583 --- /dev/null +++ b/Src/Winamp/ExtendedInfo.cpp @@ -0,0 +1,363 @@ +#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); +}
\ No newline at end of file |