aboutsummaryrefslogtreecommitdiff
path: root/Src/albumart
diff options
context:
space:
mode:
Diffstat (limited to 'Src/albumart')
-rw-r--r--Src/albumart/AlbumArt.cpp1095
-rw-r--r--Src/albumart/AlbumArt.h26
-rw-r--r--Src/albumart/ParamList.cpp113
-rw-r--r--Src/albumart/ParamList.h43
-rw-r--r--Src/albumart/albumart.rc76
-rw-r--r--Src/albumart/albumart.sln31
-rw-r--r--Src/albumart/albumart.vcxproj256
-rw-r--r--Src/albumart/albumart.vcxproj.filters44
-rw-r--r--Src/albumart/api__albumart.h15
-rw-r--r--Src/albumart/main.cpp84
-rw-r--r--Src/albumart/resource.h14
-rw-r--r--Src/albumart/version.rc239
12 files changed, 1836 insertions, 0 deletions
diff --git a/Src/albumart/AlbumArt.cpp b/Src/albumart/AlbumArt.cpp
new file mode 100644
index 00000000..3cf3432d
--- /dev/null
+++ b/Src/albumart/AlbumArt.cpp
@@ -0,0 +1,1095 @@
+#include "AlbumArt.h"
+#include "api__albumart.h"
+#include "ParamList.h"
+#include <api/service/svcs/svc_imgload.h>
+#include <api/service/svcs/svc_imgwrite.h>
+#include <shlwapi.h>
+#include <api/service/waservicefactory.h>
+#include "../Agave/AlbumArt/svc_albumArtProvider.h"
+#include <api/syscb/callbacks/metacb.h>
+#include <strsafe.h>
+
+static svc_imageLoader *FindImageLoader(const wchar_t *filespec, waServiceFactory **factory)
+{
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int)WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ if (l->isMine(filespec))
+ {
+ *factory = sf;
+ return l;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return NULL;
+}
+
+static svc_imageLoader *FindImageLoader(void *data, size_t datalen, waServiceFactory **factory)
+{
+ FOURCC imgload = svc_imageLoader::getServiceType();
+ int n = (int)WASABI_API_SVC->service_getNumServices(imgload);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
+ if (sf)
+ {
+ svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
+ if (l)
+ {
+ if (l->testData(data, (int)datalen))
+ {
+ *factory = sf;
+ return l;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return NULL;
+}
+
+static svc_albumArtProvider *FindProvider(const wchar_t *filename, int providerType, waServiceFactory **factory)
+{
+ FOURCC albumartprovider = svc_albumArtProvider::getServiceType();
+ int n = (int)WASABI_API_SVC->service_getNumServices(albumartprovider);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(albumartprovider,i);
+ if (sf)
+ {
+ svc_albumArtProvider * provider = (svc_albumArtProvider*)sf->getInterface();
+ if (provider)
+ {
+ if (provider->ProviderType() == providerType && provider->IsMine(filename))
+ {
+ *factory = sf;
+ return provider;
+ }
+ sf->releaseInterface(provider);
+ }
+ }
+ }
+ return NULL;
+}
+
+static ARGB32 *loadImgFromFile(const wchar_t *file, int *w, int *h)
+{
+ waServiceFactory *sf = 0;
+ svc_imageLoader *loader = FindImageLoader(file, &sf);
+ if (loader)
+ {
+ HANDLE hf = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (hf != INVALID_HANDLE_VALUE)
+ {
+ int len = GetFileSize(hf, 0);
+ HANDLE hmap = CreateFileMapping(hf, 0, PAGE_READONLY, 0, 0, 0);
+ if (hmap)
+ {
+ void *data = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
+ if (data)
+ {
+ if (loader->testData(data,len))
+ {
+ ARGB32* im = loader->loadImage(data,len,w,h);
+ UnmapViewOfFile(data);
+ CloseHandle(hmap);
+ CloseHandle(hf);
+ sf->releaseInterface(loader);
+ return im;
+ }
+ UnmapViewOfFile(data);
+ }
+
+ CloseHandle(hmap);
+ }
+ CloseHandle(hf);
+ }
+ sf->releaseInterface(loader);
+ }
+ return 0;
+}
+
+static ARGB32 *loadImgFromFile(const wchar_t *path, const wchar_t *filespec, int *w, int *h, bool test=false, ifc_xmlreaderparams *params = NULL)
+{
+ waServiceFactory *sf = 0;
+ svc_imageLoader *loader = FindImageLoader(filespec, &sf);
+ if (loader)
+ {
+ if (test)
+ {
+ sf->releaseInterface(loader);
+ return (ARGB32*)1;
+ }
+ wchar_t file[MAX_PATH] = {0};
+ PathCombineW(file, path, filespec);
+ HANDLE hf = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (hf != INVALID_HANDLE_VALUE)
+ {
+ int len = GetFileSize(hf, 0);
+ HANDLE hmap = CreateFileMapping(hf, 0, PAGE_READONLY, 0, 0, 0);
+ if (hmap)
+ {
+ void *data = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
+ if (data)
+ {
+ if (loader->testData(data,len))
+ {
+ ARGB32* im = loader->loadImage(data,len,w,h, params);
+ UnmapViewOfFile(data);
+ CloseHandle(hmap);
+ CloseHandle(hf);
+ sf->releaseInterface(loader);
+ return im;
+ }
+ UnmapViewOfFile(data);
+ }
+
+ CloseHandle(hmap);
+ }
+ CloseHandle(hf);
+ }
+
+ sf->releaseInterface(loader);
+ }
+ return 0;
+}
+
+static bool loadImgDataFromFile(const wchar_t *path, const wchar_t *filespec, void **bits, size_t *len, wchar_t **mimeType, bool originTest = false)
+{
+ waServiceFactory *sf = 0;
+ svc_imageLoader *loader = FindImageLoader(filespec, &sf);
+ if (loader)
+ {
+ wchar_t file[MAX_PATH] = {0};
+ PathCombineW(file, path, filespec);
+ HANDLE hf = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (hf != INVALID_HANDLE_VALUE)
+ {
+ if(!originTest)
+ {
+ int flen = GetFileSize(hf, 0);
+ *bits = WASABI_API_MEMMGR->sysMalloc(flen);
+ DWORD bytes_read = 0;
+ ReadFile(hf, *bits, flen, &bytes_read, 0);
+ *len = bytes_read;
+ }
+ if (mimeType)
+ {
+ *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(12 * sizeof(wchar_t));
+ wcsncpy(*mimeType, loader->mimeType(), 12);
+ }
+ CloseHandle(hf);
+ sf->releaseInterface(loader);
+ return true;
+ }
+ sf->releaseInterface(loader);
+ }
+ return false;
+}
+
+static ARGB32 *FindImage(const wchar_t *path, const wchar_t *mask, int *w, int *h, bool test=false, ifc_xmlreaderparams *params = NULL)
+{
+ wchar_t dirmask[MAX_PATH] = {0};
+ PathCombineW(dirmask, path, mask);
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(dirmask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ ARGB32 *bits = loadImgFromFile(path, find.cFileName, w, h, test, params);
+ if (bits)
+ {
+ FindClose(hFind);
+ return bits;
+ }
+ }
+ while (FindNextFileW(hFind, &find));
+ FindClose(hFind);
+ }
+ return 0;
+}
+
+static bool FindImageData(const wchar_t *path, const wchar_t *mask, void **bits, size_t *len, wchar_t **mimeType)
+{
+ wchar_t dirmask[MAX_PATH] = {0};
+ PathCombineW(dirmask, path, mask);
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(dirmask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (loadImgDataFromFile(path, find.cFileName, bits, len, mimeType))
+ {
+ return true;
+ }
+ }
+ while (FindNextFileW(hFind, &find));
+ FindClose(hFind);
+ }
+ return false;
+}
+
+static bool FindImageOrigin(const wchar_t *path, const wchar_t *mask, wchar_t **mimeType)
+{
+ wchar_t dirmask[MAX_PATH] = {0};
+ PathCombineW(dirmask, path, mask);
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(dirmask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (loadImgDataFromFile(path, find.cFileName, NULL, NULL, mimeType, true))
+ {
+ FindClose(hFind);
+ return true;
+ }
+ }
+ while (FindNextFileW(hFind, &find));
+ FindClose(hFind);
+ }
+ return false;
+}
+
+static bool DeleteImage(const wchar_t *path, const wchar_t *mask)
+{
+ wchar_t dirmask[MAX_PATH] = {0};
+ PathCombineW(dirmask, path, mask);
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(dirmask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ // i know this seems stupid, but we need to load the image
+ // since this is supposed to delete the image that would show up
+ // from a GetAlbumArt call
+ int w = 0, h = 0;
+ ARGB32 *bits = loadImgFromFile(path, find.cFileName, &w, &h);
+ if (bits)
+ {
+ FindClose(hFind);
+ WASABI_API_MEMMGR->sysFree(bits);
+ wchar_t fullpath[MAX_PATH] = {0};
+ PathCombineW(fullpath, path, find.cFileName);
+ DeleteFileW(fullpath);
+ return true;
+ }
+ }
+ while (FindNextFileW(hFind, &find));
+ FindClose(hFind);
+ }
+ return false;
+}
+
+static ARGB32 *FindAlbumArtByProvider(int providertype, const wchar_t *filename, const wchar_t *type, int *w, int *h, ifc_xmlreaderparams *params = NULL)
+{
+ waServiceFactory *factory = 0;
+ svc_albumArtProvider *provider = FindProvider(filename, providertype, &factory);
+ if (provider)
+ {
+ void *data = 0;
+ size_t datalen = 0;
+ wchar_t *mimeType=0;
+ if (provider->GetAlbumArtData(filename, type, &data, &datalen, &mimeType) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
+ {
+ waServiceFactory *sf;
+ svc_imageLoader *loader = 0;
+ if (mimeType)
+ {
+ wchar_t mask[MAX_PATH] = {0};
+ StringCchPrintfW(mask, MAX_PATH, L"hi.%s", mimeType);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ loader = FindImageLoader(mask, &sf);
+ }
+ else
+ {
+ loader = FindImageLoader(data, datalen, &sf);
+ }
+
+ if (loader)
+ {
+ if (loader->testData(data, (int)datalen))
+ {
+ ARGB32* im = loader->loadImage(data, (int)datalen,w,h,params);
+ WASABI_API_MEMMGR->sysFree(data);
+ sf->releaseInterface(loader);
+ factory->releaseInterface(provider);
+ return im;
+ }
+ sf->releaseInterface(loader);
+ }
+ WASABI_API_MEMMGR->sysFree(data);
+ }
+ factory->releaseInterface(provider);
+ }
+ return 0;
+}
+
+static int DeleteAlbumArtByProvider(int providertype, const wchar_t *filename, const wchar_t *type)
+{
+ waServiceFactory *factory = 0;
+ svc_albumArtProvider *provider = FindProvider(filename, providertype, &factory);
+ if (provider)
+ {
+ int ret = provider->DeleteAlbumArt(filename, type);
+ factory->releaseInterface(provider);
+ return ret == ALBUMARTPROVIDER_SUCCESS;
+ }
+ return false;
+}
+
+static bool FindSceneNFO(const wchar_t *path, wchar_t *mask)
+{
+ wchar_t nfo_mask[MAX_PATH] = {0};
+ PathCombineW(nfo_mask, path, L"*.nfo");
+
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(nfo_mask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ StringCchCopyW(mask, MAX_PATH, find.cFileName);
+ PathRemoveExtensionW(mask);
+ StringCchCatW(mask, MAX_PATH, L".*");
+ FindClose(hFind);
+ return true;
+ }
+ return false;
+}
+
+static void CleanNameForPath(wchar_t *name)
+{
+ while (name && *name)
+ {
+ switch(*name)
+ {
+ case L'?':
+ case L'*':
+ case L'|':
+ *name = L'_';
+ break;
+ case '/':
+ case L'\\':
+ case L':':
+ *name = L'-';
+ break;
+ case L'\"':
+ *name = L'\'';
+ break;
+ case L'<':
+ *name = L'(';
+ break;
+ case L'>': *name = L')';
+ break;
+ }
+ name++;
+ }
+}
+
+
+int AlbumArt::GetAlbumArt(const wchar_t *filename, const wchar_t *type, int *w, int *h, ARGB32 **bits)
+{
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+
+ /* First, look for embedded album art */
+ if (*bits = FindAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_EMBEDDED, filename, type, w,h))
+ return ALBUMART_SUCCESS;
+
+ /* moved to allow for SHOUTcast 2 in-stream metadata which is best classed as embedded */
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ /* Next, Search the albumart in a cover library dir */
+ if (*bits = FindAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_DATABASE, filename, type, w,h))
+ return ALBUMART_SUCCESS;
+
+ bool isCover = !_wcsicmp(type,L"cover");
+ /* Get the folder of the file */
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t mask[MAX_PATH] = {0};
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ /* Next, look for a file with the same name as the album name */
+ wchar_t albumname[MAX_PATH] = {0};
+ if (isCover && AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ if (*bits = FindImage(path, mask, w, h))
+ return ALBUMART_SUCCESS;
+ }
+
+ // look for 'scene' artwork (*.jpg with the same filename as *.nfo)
+ if (isCover && FindSceneNFO(path, mask))
+ {
+ if (*bits = FindImage(path, mask, w, h))
+ return ALBUMART_SUCCESS;
+ }
+
+ /* Next, let's look in the folder for some art */
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", type);
+ if (*bits = FindImage(path, mask, w, h))
+ return ALBUMART_SUCCESS;
+
+ /* Look for folder.jpg if the type is "cover" */
+ if (isCover && (*bits = FindImage(path, L"folder.*", w, h)))
+ return ALBUMART_SUCCESS;
+
+ /* Look for front.jpg if the type is "cover" */
+ if (isCover && (*bits = FindImage(path, L"front.*", w, h)))
+ return ALBUMART_SUCCESS;
+
+ /* Look for albumart.jpg if the type is "cover" */
+ if (isCover && (*bits = FindImage(path, L"albumart.*", w, h)))
+ return ALBUMART_SUCCESS;
+
+ return ALBUMART_FAILURE;
+}
+
+int AlbumArt::GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType)
+{
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ /* First, look for embedded album art */
+ waServiceFactory *sourceFactory = 0;
+ svc_albumArtProvider *sourceProvider = FindProvider(filename, ALBUMARTPROVIDER_TYPE_EMBEDDED, &sourceFactory);
+ if (sourceProvider)
+ {
+ void *data = 0;
+ size_t datalen = 0;
+ wchar_t *mime_type = 0;
+ if (sourceProvider->GetAlbumArtData(filename, type, &data, &datalen, &mime_type) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
+ {
+ if (bits)
+ *bits = data;
+ if (len)
+ *len = datalen;
+ if (mimeType)
+ *mimeType = mime_type;
+ sourceFactory->releaseInterface(sourceProvider);
+ return ALBUMART_SUCCESS;
+ }
+ sourceFactory->releaseInterface(sourceProvider);
+ }
+
+#if 0 // TODO
+ /* Next, Search the albumart in a cover library dir */
+ if (*bits = FindAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_DATABASE, filename, type, w,h))
+ return ALBUMART_SUCCESS;
+#endif
+
+ bool isCover = !_wcsicmp(type,L"cover");
+ /* Get the folder of the file */
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t mask[MAX_PATH] = {0};
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ /* Next, look for a file with the same name as the album name */
+ wchar_t albumname[MAX_PATH] = {0};
+ if (isCover && AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ if (FindImageData(path, mask, bits, len, mimeType))
+ return ALBUMART_SUCCESS;
+ }
+
+ // look for 'scene' artwork (*.jpg with the same filename as *.nfo)
+ if (isCover && FindSceneNFO(path, mask))
+ {
+ if (FindImageData(path, mask, bits, len, mimeType))
+ return ALBUMART_SUCCESS;
+ }
+
+ /* Next, let's look in the folder for some art */
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", type);
+ if (FindImageData(path, mask, bits, len, mimeType))
+ return ALBUMART_SUCCESS;
+
+ /* Look for folder.jpg if the type is "cover" */
+ if (isCover && FindImageData(path, L"folder.*", bits, len, mimeType))
+ return ALBUMART_SUCCESS;
+
+ /* Look for front.jpg if the type is "cover" */
+ if (isCover && FindImageData(path, L"front.*", bits, len, mimeType))
+ return ALBUMART_SUCCESS;
+
+ /* Look for albumart.jpg if the type is "cover" */
+ if (isCover && FindImageData(path, L"albumart.*", bits, len, mimeType))
+ return ALBUMART_SUCCESS;
+
+ return ALBUMART_FAILURE;
+}
+
+int AlbumArt::GetAlbumArt_NoAMG(const wchar_t *filename, const wchar_t *type, int *w, int *h, ARGB32 **bits)
+{
+ ParamList params;
+ params.addItem(L"AMG", L"1");
+
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ /* First, look for embedded album art */
+ if (*bits = FindAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_EMBEDDED, filename, type, w,h, &params))
+ return ALBUMART_SUCCESS;
+
+ /* Next, Search the albumart in a cover library dir */
+ if (*bits = FindAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_DATABASE, filename, type, w,h, &params))
+ return ALBUMART_SUCCESS;
+
+ bool isCover = !_wcsicmp(type,L"cover");
+ /* Get the folder of the file */
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t mask[MAX_PATH] = {0};
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ /* Next, look for a file with the same name as the album name */
+ wchar_t albumname[MAX_PATH] = {0};
+ if (isCover && AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ if (*bits = FindImage(path, mask, w, h, false, &params))
+ return ALBUMART_SUCCESS;
+ }
+
+ // look for 'scene' artwork (*.jpg with the same filename as *.nfo)
+ if (isCover && FindSceneNFO(path, mask))
+ {
+ if (*bits = FindImage(path, mask, w, h, false, &params))
+ return ALBUMART_SUCCESS;
+ }
+
+ /* Next, let's look in the folder for some art */
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", type);
+ if (*bits = FindImage(path, mask, w, h, false, &params))
+ return ALBUMART_SUCCESS;
+
+ /* Look for folder.jpg if the type is "cover" */
+ if (isCover && (*bits = FindImage(path, L"folder.*", w, h, false, &params)))
+ return ALBUMART_SUCCESS;
+
+ /* Look for front.jpg if the type is "cover" */
+ if (isCover && (*bits = FindImage(path, L"front.*", w, h, false, &params)))
+ return ALBUMART_SUCCESS;
+
+ /* Look for albumart.jpg if the type is "cover" */
+ if (isCover && (*bits = FindImage(path, L"albumart.*", w, h, false, &params)))
+ return ALBUMART_SUCCESS;
+
+ return ALBUMART_FAILURE;
+}
+
+int AlbumArt::GetAlbumArtOrigin(const wchar_t *filename, const wchar_t *type, wchar_t **mimeType)
+{
+ if (!filename || !*filename)
+ return ALBUMART_NONE;
+ if (PathIsURLW(filename))
+ return ALBUMART_NONE;
+
+ /* First, look for embedded album art */
+ waServiceFactory *sourceFactory = 0;
+ svc_albumArtProvider *sourceProvider = FindProvider(filename, ALBUMARTPROVIDER_TYPE_EMBEDDED, &sourceFactory);
+ if (sourceProvider)
+ {
+ void *data = 0;
+ size_t datalen = 0;
+ wchar_t *mime_type = 0;
+ if (sourceProvider->GetAlbumArtData(filename, type, &data, &datalen, &mime_type) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
+ {
+ if (mimeType)
+ {
+ *mimeType = mime_type;
+ if(!mime_type)
+ {
+ waServiceFactory *sf = 0;
+ svc_imageLoader *loader = 0;
+ loader = FindImageLoader(data, datalen, &sf);
+ if (loader)
+ {
+ *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(16 * sizeof(wchar_t));
+ wcsncpy(*mimeType, loader->mimeType(), 11);
+ sf->releaseInterface(loader);
+ }
+ else
+ {
+ *mimeType = 0;
+ }
+ }
+ }
+
+ sourceFactory->releaseInterface(sourceProvider);
+ WASABI_API_MEMMGR->sysFree(data);
+ return ALBUMART_EMBEDDED;
+ }
+ sourceFactory->releaseInterface(sourceProvider);
+ }
+
+#if 0 // TODO
+ /* Next, Search the albumart in a cover library dir */
+ if (*bits = FindAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_DATABASE, filename, type, w,h))
+ return ALBUMART_SUCCESS;
+#endif
+
+ bool isCover = !_wcsicmp(type,L"cover");
+ /* Get the folder of the file */
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t mask[MAX_PATH] = {0};
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ /* Next, look for a file with the same name as the album name */
+ wchar_t albumname[MAX_PATH] = {0};
+ if (isCover && AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ if (FindImageOrigin(path, mask, mimeType))
+ return ALBUMART_ALBUM;
+ }
+
+ // look for 'scene' artwork (*.jpg with the same filename as *.nfo)
+ if (isCover && FindSceneNFO(path, mask))
+ {
+ if (FindImageOrigin(path, mask, mimeType))
+ return ALBUMART_NFO;
+ }
+
+ /* Next, let's look in the folder for some art */
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", type);
+ if (FindImageOrigin(path, mask, mimeType))
+ return ALBUMART_FILENAME;
+
+ /* Look for folder.jpg if the type is "cover" */
+ if (isCover && FindImageOrigin(path, L"folder.*", mimeType))
+ return ALBUMART_FOLDER;
+
+ /* Look for front.jpg if the type is "cover" */
+ if (isCover && FindImageOrigin(path, L"front.*", mimeType))
+ return ALBUMART_FRONT;
+
+ /* Look for albumart.jpg if the type is "cover" */
+ if (isCover && FindImageOrigin(path, L"albumart.*", mimeType))
+ return ALBUMART_ARTWORK;
+
+ return ALBUMART_NONE;
+}
+
+// benski> TODO, i really don't like duplicating this logic from GetAlbumArt, maybe we can find a way
+int AlbumArt::DeleteAlbumArt(const wchar_t *filename, const wchar_t *type)
+{
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ /* First, look for embedded album art */
+ if (DeleteAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_EMBEDDED, filename, type))
+ return ALBUMART_SUCCESS;
+
+ /* Next, Search the albumart in a cover library dir */
+ if (DeleteAlbumArtByProvider(ALBUMARTPROVIDER_TYPE_DATABASE, filename, type))
+ return ALBUMART_SUCCESS;
+
+ bool isCover = !_wcsicmp(type,L"cover");
+ /* Get the folder of the file */
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t mask[MAX_PATH] = {0};
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ /* Next, look for a file with the same name as the album name */
+ wchar_t albumname[MAX_PATH] = {0};
+ if (AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ if (DeleteImage(path, mask))
+ return ALBUMART_SUCCESS;
+ }
+
+ // look for 'scene' artwork (*.jpg with the same filename as *.nfo)
+ if (isCover && FindSceneNFO(path, mask))
+ {
+ if (DeleteImage(path, mask))
+ return ALBUMART_SUCCESS;
+ }
+
+ /* Next, let's look in the folder for some art */
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", type);
+ if (DeleteImage(path, mask))
+ return ALBUMART_SUCCESS;
+
+ /* Look for folder.jpg if the type is "cover" */
+ if (isCover && DeleteImage(path, L"folder.*"))
+ return ALBUMART_SUCCESS;
+
+ /* Look for folder.jpg if the type is "cover" */
+ if (isCover && DeleteImage(path, L"front.*"))
+ return ALBUMART_SUCCESS;
+
+ /* Look for albumart.jpg if the type is "cover" */
+ if (isCover && DeleteImage(path, L"albumart.*"))
+ return ALBUMART_SUCCESS;
+
+ return ALBUMART_FAILURE;
+}
+
+class strbuilder
+{
+public:
+ wchar_t *str;
+ wchar_t *end;
+ size_t alloc;
+ strbuilder()
+ {
+ alloc = 512;
+ end = str = (wchar_t*)WASABI_API_MEMMGR->sysMalloc(alloc);
+ str[0]=str[1]=0;
+ }
+ void append(const wchar_t *s)
+ {
+ size_t oldlen = end - str;
+ size_t l = wcslen(s) + 1;
+ while (alloc < l + oldlen + 1)
+ {
+ alloc += 512;
+ str = (wchar_t*)WASABI_API_MEMMGR->sysRealloc(str,alloc);
+ end = str+oldlen;
+ }
+ lstrcpynW(end,s, (int)l);
+ end += l;
+ *end=0;
+ }
+ wchar_t *get()
+ {
+ return str;
+ }
+};
+
+int AlbumArt::GetAlbumArtTypes(const wchar_t *filename, wchar_t **types)
+{
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t mask[MAX_PATH] = {0};
+ strbuilder str;
+
+ /* First, let's look in the folder for some art */
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ // TODO (mpdeimos) Make the stuff here configurable, add wildcards *front* / *cover* ...
+ StringCchPrintfW(mask, MAX_PATH, L"cover.*");
+ if (FindImage(path, mask, 0, 0,true))
+ str.append(L"cover");
+ else // mpdeimos> front.jpg is much more common than cover.jpg
+ {
+ StringCchPrintfW(mask, MAX_PATH, L"front.*");
+ if (FindImage(path, mask, 0, 0,true))
+ str.append(L"cover");
+ else
+ {
+ StringCchPrintfW(mask, MAX_PATH, L"folder.*");
+ if (FindImage(path, mask, 0, 0,true))
+ str.append(L"cover");
+ else
+ {
+ StringCchPrintfW(mask, MAX_PATH, L"albumart.*");
+ if (FindImage(path, mask, 0, 0,true))
+ str.append(L"cover");
+ else
+ {
+ wchar_t albumname[MAX_PATH]=L"";
+ if (AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ if (FindImage(path, mask, 0, 0))
+ str.append(L"cover");
+ }
+ }
+ }
+ }
+ }
+ // add other shit to str
+
+ //str.append(L"foo");
+ //str.append(L"bar");
+
+ *types = str.get();
+ return ALBUMART_SUCCESS;
+}
+
+int AlbumArt::GetValidAlbumArtTypes(const wchar_t *filename, wchar_t **type)
+{
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ strbuilder str;
+ str.append(L"cover");
+
+ // add other shit to str
+ //str.append(L"foo");
+ //str.append(L"bar");
+
+ *type = str.get();
+ return ALBUMART_SUCCESS;
+}
+
+static void * writeImg(const ARGB32 *data, int w, int h, int *length, const wchar_t *ext)
+{
+ if (!ext || (ext && !*ext)) return NULL;
+ if (*ext == L'.') ext++;
+ FOURCC imgwrite = svc_imageWriter::getServiceType();
+ int n = (int)WASABI_API_SVC->service_getNumServices(imgwrite);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgwrite,i);
+ if (sf)
+ {
+ svc_imageWriter * l = (svc_imageWriter*)sf->getInterface();
+ if (l)
+ {
+ if (wcsstr(l->getExtensions(),ext))
+ {
+ void* ret = l->convert(data,32,w,h,length);
+ sf->releaseInterface(l);
+ return ret;
+ }
+ sf->releaseInterface(l);
+ }
+ }
+ }
+ return NULL;
+}
+
+static int writeFile(const wchar_t *file, const void * data, int length)
+{
+ FILE *f=_wfopen(file,L"wb");
+ if (!f) return ALBUMART_FAILURE;
+ if (fwrite(data,length,1,f) != 1)
+ {
+ fclose(f);
+ return ALBUMART_FAILURE;
+ }
+ fclose(f);
+ return ALBUMART_SUCCESS;
+}
+
+static void writeImageToFile(ARGB32 * img, int w, int h, const wchar_t *file)
+{
+ int length = 0;
+ void * data = writeImg(img,w,h,&length,wcsrchr(file,L'.'));
+ if (data)
+ {
+ writeFile(file,data,length);
+ WASABI_API_MEMMGR->sysFree(data);
+ }
+}
+
+int AlbumArt::SetAlbumArt(const wchar_t *filename, const wchar_t *type, int w, int h, const void *bits, size_t len, const wchar_t *mimeType)
+{
+ if (!bits)
+ return ALBUMART_FAILURE;
+
+ if (!filename || !*filename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(filename))
+ return ALBUMART_FAILURE;
+
+ if (!type) type = L"cover";
+
+ bool freebits = false;
+ if (!mimeType)
+ {
+ mimeType = L"jpg"; // TODO: read from ini?
+ int l = 0;
+ bits = writeImg((ARGB32*)bits,w,h,&l,mimeType);
+ if (!bits) return ALBUMART_FAILURE;
+ freebits = true;
+ len = l;
+ }
+
+ wchar_t path[MAX_PATH] = {0};
+ wchar_t fn[MAX_PATH] = {0};
+
+ StringCchCopyW(path, MAX_PATH, filename);
+ PathRemoveFileSpecW(path);
+
+ wchar_t albumname[MAX_PATH] = {0};
+ if (!_wcsicmp(type,L"cover") && AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ type = albumname;
+ }
+
+ StringCchPrintfW(fn, MAX_PATH, L"%s\\%s.%s", path, type, mimeType);
+
+ int ret = ALBUMART_SUCCESS;
+ if (bits)
+ ret = writeFile(fn,bits, (int)len);
+
+ if (ret == ALBUMART_SUCCESS)
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::META, MetadataCallback::ART_UPDATED, (intptr_t)fn);
+
+ /*
+ else //bits == NULL, so delete!
+ _wunlink(fn);
+ */
+
+ if (freebits) WASABI_API_MEMMGR->sysFree((void*)bits);
+ return ret;
+}
+
+static bool CopySceneNFO(const wchar_t *sourcePath, const wchar_t *destinationPath)
+{
+ wchar_t nfo_mask[MAX_PATH] = {0};
+ PathCombineW(nfo_mask, sourcePath, L"*.nfo");
+
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(nfo_mask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ wchar_t sourceFile[MAX_PATH] = {0};
+ wchar_t destinationFile[MAX_PATH] = {0};
+ PathCombineW(sourceFile, sourcePath, find.cFileName);
+ PathCombineW(destinationFile, destinationPath, find.cFileName);
+ CopyFileW(sourceFile, destinationFile, TRUE);
+ FindClose(hFind);
+ return true;
+ }
+ return false;
+}
+
+static void CopyMask(const wchar_t *sourcePath, const wchar_t *destinationPath, const wchar_t *mask)
+{
+ wchar_t findMask[MAX_PATH] = {0};
+ PathCombineW(findMask, sourcePath, mask);
+
+ WIN32_FIND_DATAW find = {0};
+ HANDLE hFind = FindFirstFileW(findMask, &find);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ // make sure it's an actual loadable image
+ waServiceFactory *factory = 0;
+ svc_imageLoader *loader = FindImageLoader(find.cFileName, &factory);
+
+ if (loader)
+ {
+ wchar_t sourceFile[MAX_PATH] = {0};
+ wchar_t destinationFile[MAX_PATH] = {0};
+ PathCombineW(sourceFile, sourcePath, find.cFileName);
+ PathCombineW(destinationFile, destinationPath, find.cFileName);
+ CopyFileW(sourceFile, destinationFile, TRUE);
+ factory->releaseInterface(loader);
+ }
+ }
+ while (FindNextFileW(hFind, &find));
+ FindClose(hFind);
+ }
+}
+
+int AlbumArt::CopyAlbumArt(const wchar_t *sourceFilename, const wchar_t *destinationFilename)
+{
+ if (!sourceFilename || !*sourceFilename || !destinationFilename || !*destinationFilename)
+ return ALBUMART_FAILURE;
+ if (PathIsURLW(sourceFilename) || PathIsURLW(destinationFilename))
+ return ALBUMART_FAILURE;
+
+ // first, copy embedded album art
+ waServiceFactory *sourceFactory = 0;
+ svc_albumArtProvider *sourceProvider = FindProvider(sourceFilename, ALBUMARTPROVIDER_TYPE_EMBEDDED, &sourceFactory);
+ if (sourceProvider)
+ {
+ waServiceFactory *destinationFactory = 0;
+ svc_albumArtProvider *destinationProvider = FindProvider(destinationFilename, ALBUMARTPROVIDER_TYPE_EMBEDDED, &destinationFactory);
+
+ if (destinationProvider)
+ {
+ // TODO: iterate through all the different types
+ void *data = 0;
+ size_t datalen = 0;
+ wchar_t *mimeType = 0;
+ if (sourceProvider->GetAlbumArtData(sourceFilename, L"cover", &data, &datalen, &mimeType) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
+ {
+ destinationProvider->SetAlbumArtData(destinationFilename, L"cover", data, datalen, mimeType);
+ WASABI_API_MEMMGR->sysFree(data);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ }
+ destinationFactory->releaseInterface(destinationProvider);
+ }
+ sourceFactory->releaseInterface(sourceProvider);
+ }
+
+ // now, if they're in different directories, copy folder.jpg, cover.jpg, front.jpg and %album%.jpg
+ wchar_t sourcePath[MAX_PATH] = {0}, destinationPath[MAX_PATH] = {0};
+ StringCchCopyW(sourcePath, MAX_PATH, sourceFilename);
+ PathRemoveFileSpecW(sourcePath);
+ StringCchCopyW(destinationPath, MAX_PATH, destinationFilename);
+ PathRemoveFileSpecW(destinationPath);
+
+ if (_wcsicmp(sourcePath, destinationPath) != 0) // if they're different
+ {
+ CopyMask(sourcePath, destinationPath, L"cover.*");
+ CopyMask(sourcePath, destinationPath, L"folder.*");
+ CopyMask(sourcePath, destinationPath, L"front.*");
+ CopyMask(sourcePath, destinationPath, L"albumart.*");
+ wchar_t mask[MAX_PATH] = {0};
+ if (FindSceneNFO(sourcePath, mask))
+ {
+ CopyMask(sourcePath, destinationPath, mask);
+ CopySceneNFO(sourcePath, destinationPath);
+ }
+
+ wchar_t albumname[MAX_PATH] = {0};
+ if (AGAVE_API_METADATA->GetExtendedFileInfo(sourceFilename, L"album", albumname, MAX_PATH) && albumname[0])
+ {
+ CleanNameForPath(albumname);
+ StringCchPrintfW(mask, MAX_PATH, L"%s.*", albumname);
+ CopyMask(sourcePath, destinationPath, mask);
+ }
+ }
+ return 0;
+}
+
+#define CBCLASS AlbumArt
+START_DISPATCH;
+CB(API_ALBUMART_GETALBUMART, GetAlbumArt);
+CB(API_ALBUMART_GETALBUMART_NOAMG, GetAlbumArt_NoAMG);
+CB(API_ALBUMART_GETALBUMARTDATA, GetAlbumArtData);
+CB(API_ALBUMART_GETALBUMARTORIGIN, GetAlbumArtOrigin);
+CB(API_ALBUMART_GETALBUMARTTYPES, GetAlbumArtTypes);
+CB(API_ALBUMART_GETVALIDALBUMARTTYPES, GetValidAlbumArtTypes);
+CB(API_ALBUMART_SETALBUMART, SetAlbumArt);
+CB(API_ALBUMART_DELETEALBUMART, DeleteAlbumArt);
+CB(API_ALBUMART_COPYALBUMART, CopyAlbumArt);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/albumart/AlbumArt.h b/Src/albumart/AlbumArt.h
new file mode 100644
index 00000000..68e8ab9d
--- /dev/null
+++ b/Src/albumart/AlbumArt.h
@@ -0,0 +1,26 @@
+#ifndef NULLSOFT_WINAMP_ALBUMART_H
+#define NULLSOFT_WINAMP_ALBUMART_H
+
+#include "../Agave/AlbumArt/api_albumart.h"
+
+class AlbumArt : public api_albumart
+{
+public:
+ static const char *getServiceName() { return "Album Art API"; }
+ static const GUID getServiceGuid() { return albumArtGUID; }
+
+public:
+ int GetAlbumArt(const wchar_t *filename, const wchar_t *type, int *w, int *h, ARGB32 **bits);
+ int GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType);
+ int GetAlbumArt_NoAMG(const wchar_t *filename, const wchar_t *type, int *w, int *h, ARGB32 **bits);
+ int GetAlbumArtOrigin(const wchar_t *filename, const wchar_t *type, wchar_t **mimeType);
+
+ int GetAlbumArtTypes(const wchar_t *filename, wchar_t **types);
+ int GetValidAlbumArtTypes(const wchar_t *filename, wchar_t **type);
+ int SetAlbumArt(const wchar_t *filename, const wchar_t *type, int w, int h, const void *bits, size_t len, const wchar_t *mimeType);
+ int DeleteAlbumArt(const wchar_t *filename, const wchar_t *type);
+ int CopyAlbumArt(const wchar_t *sourceFilename, const wchar_t *destinationFilename);
+protected:
+ RECVS_DISPATCH;
+};
+#endif \ No newline at end of file
diff --git a/Src/albumart/ParamList.cpp b/Src/albumart/ParamList.cpp
new file mode 100644
index 00000000..9585fa10
--- /dev/null
+++ b/Src/albumart/ParamList.cpp
@@ -0,0 +1,113 @@
+#include "ParamList.h"
+
+ParamList::~ParamList()
+{
+ for (auto v : parms_list)
+ {
+ delete v;
+ }
+ parms_list.clear();
+}
+
+const wchar_t *ParamList::getItemName(int i)
+{
+ if(((size_t)i)>=getNbItems())
+ return L"";
+ return
+ parms_list[i]->parm;
+}
+
+const wchar_t *ParamList::getItemValueIndex(int i)
+{
+ if(((size_t)i)>=getNbItems())
+ return L"";
+ return
+ parms_list[i]->value;
+}
+
+const wchar_t *ParamList::getItemValue(const wchar_t *name)
+{
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!_wcsicmp(parms_list[i]->parm, name))
+ return parms_list[i]->value;
+ return NULL;
+}
+
+const wchar_t *ParamList::enumItemValues(const wchar_t *name, int nb)
+{
+ int f=0;
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!_wcsicmp(parms_list[i]->parm, name))
+ if(f==nb)
+ return parms_list[i]->value;
+ else f++;
+ return NULL;
+}
+
+int ParamList::getItemValueInt(const wchar_t *name, int def)
+{
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!_wcsicmp(parms_list[i]->parm, name))
+ {
+ return (parms_list[i]->value ? _wtoi(parms_list[i]->value) : def);
+ }
+ return def;
+}
+
+size_t ParamList::getNbItems()
+{
+ return parms_list.size();
+}
+
+void ParamList::addItem(const wchar_t *parm, const wchar_t *value)
+{
+ parms_struct *p= new parms_struct;
+ p->parm = _wcsdup(parm);
+ p->ownValue = true;
+ p->value = _wcsdup(value);
+ parms_list.push_back(p);
+}
+
+void ParamList::removeItem(const wchar_t *parm)
+{
+ //for (size_t i=0;i!=parms_list.size();i++)
+ //{
+ // parms_struct *s = parms_list[i];
+ // if (!_wcsicmp(parm, s->parm))
+ // {
+ // delete s;
+ // parms_list.eraseindex(i);
+ // i--;
+ // }
+ //}
+
+ for (auto it = parms_list.begin(); it != parms_list.end(); it++)
+ {
+ parms_struct* s = *it;
+ if (!_wcsicmp(parm, s->parm))
+ {
+ delete s;
+ it = parms_list.erase(it);
+ }
+ }
+
+}
+
+int ParamList::findItem(const wchar_t *parm)
+{
+ for(size_t i=0;i!=getNbItems();i++)
+ if(!_wcsicmp(parms_list[i]->parm, parm))
+ return (int)i;
+ return -1;
+}
+
+#define CBCLASS ParamList
+START_DISPATCH;
+CB(XMLREADERPARAMS_GETITEMNAME, getItemName)
+CB(XMLREADERPARAMS_GETITEMVALUE, getItemValueIndex)
+CB(XMLREADERPARAMS_GETITEMVALUE2, getItemValue)
+CB(XMLREADERPARAMS_ENUMITEMVALUES, enumItemValues)
+CB(XMLREADERPARAMS_GETITEMVALUEINT, getItemValueInt)
+CB(XMLREADERPARAMS_GETNBITEMS, getNbItems)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/albumart/ParamList.h b/Src/albumart/ParamList.h
new file mode 100644
index 00000000..971623a8
--- /dev/null
+++ b/Src/albumart/ParamList.h
@@ -0,0 +1,43 @@
+#pragma once
+#include "../xml/ifc_xmlreaderparams.h"
+#include <vector>
+
+class ParamList : public ifc_xmlreaderparams
+{
+public:
+ ParamList() {}
+ ~ParamList();
+
+ const wchar_t *getItemName(int i);
+ const wchar_t *getItemValueIndex(int i);
+ const wchar_t *getItemValue(const wchar_t *name);
+ const wchar_t *enumItemValues(const wchar_t *name, int nb);
+ int getItemValueInt(const wchar_t *name, int def = 0);
+ size_t getNbItems();
+
+ void addItem(const wchar_t *parm, const wchar_t *value);
+ void removeItem(const wchar_t *parm);
+ int findItem(const wchar_t *parm);
+
+protected:
+ RECVS_DISPATCH;
+private:
+ struct parms_struct
+ {
+ parms_struct() : parm(0), ownValue(false)
+ {
+ value=0;
+ }
+
+ ~parms_struct()
+ {
+ if (ownValue)
+ free((wchar_t *)parm);
+ free(value);
+ }
+ const wchar_t *parm;
+ wchar_t *value;
+ bool ownValue;
+ };
+ std::vector<parms_struct*> parms_list;
+}; \ No newline at end of file
diff --git a/Src/albumart/albumart.rc b/Src/albumart/albumart.rc
new file mode 100644
index 00000000..fcff7711
--- /dev/null
+++ b/Src/albumart/albumart.rc
@@ -0,0 +1,76 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/albumart/albumart.sln b/Src/albumart/albumart.sln
new file mode 100644
index 00000000..99a4b1d7
--- /dev/null
+++ b/Src/albumart/albumart.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "albumart", "albumart.vcxproj", "{388476B7-C0A1-4853-B6F4-9A64CA346BA9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|Win32.Build.0 = Debug|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|Win32.ActiveCfg = Release|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|Win32.Build.0 = Release|Win32
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|x64.ActiveCfg = Debug|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Debug|x64.Build.0 = Debug|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|x64.ActiveCfg = Release|x64
+ {388476B7-C0A1-4853-B6F4-9A64CA346BA9}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {92B093B6-3585-4F4A-93CF-5F7AB10E54EC}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/albumart/albumart.vcxproj b/Src/albumart/albumart.vcxproj
new file mode 100644
index 00000000..f5205e97
--- /dev/null
+++ b/Src/albumart/albumart.vcxproj
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{388476B7-C0A1-4853-B6F4-9A64CA346BA9}</ProjectGuid>
+ <RootNamespace>albumart</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ALBUMART_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ImportLibrary>$(ProjectDir)x86_Debug\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ALBUMART_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ImportLibrary>$(ProjectDir)x64_Debug\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ALBUMART_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x86_Release\$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ALBUMART_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x64_Release\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="AlbumArt.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="ParamList.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AlbumArt.h" />
+ <ClInclude Include="api__albumart.h" />
+ <ClInclude Include="ParamList.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="albumart.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\WAT\WAT.vcxproj">
+ <Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/albumart/albumart.vcxproj.filters b/Src/albumart/albumart.vcxproj.filters
new file mode 100644
index 00000000..e1896a25
--- /dev/null
+++ b/Src/albumart/albumart.vcxproj.filters
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="AlbumArt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ParamList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AlbumArt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="api__albumart.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ParamList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{53508be3-d188-4fe9-a80f-9378f206b5c7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{ba06c2c5-3fd5-4833-b54e-5510f086502e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{97dcdbfa-92da-4a1f-8d1e-29c49d975774}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="albumart.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/albumart/api__albumart.h b/Src/albumart/api__albumart.h
new file mode 100644
index 00000000..6c3d5950
--- /dev/null
+++ b/Src/albumart/api__albumart.h
@@ -0,0 +1,15 @@
+#pragma once
+#include <api/service/api_service.h>
+extern api_service *serviceManager;
+#define WASABI_API_SVC serviceManager
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memmgrApi;
+#define WASABI_API_MEMMGR memmgrApi
+
+#include "../Agave/Metadata/api_metadata.h"
+extern api_metadata *metadataApi;
+#define AGAVE_API_METADATA metadataApi
+
+#include <api/syscb/api_syscb.h>
+#define WASABI_API_SYSCB sysCallbackApi \ No newline at end of file
diff --git a/Src/albumart/main.cpp b/Src/albumart/main.cpp
new file mode 100644
index 00000000..c1d60b7e
--- /dev/null
+++ b/Src/albumart/main.cpp
@@ -0,0 +1,84 @@
+#define WIN32_LEAN_AND_MEAN
+#include "api__albumart.h"
+#include <bfc/platform/export.h>
+#include "../Agave/Component/ifc_wa5component.h"
+#include "../nu/Singleton.h"
+#include "AlbumArt.h"
+
+api_service *WASABI_API_SVC=0;
+api_memmgr *WASABI_API_MEMMGR=0;
+api_metadata *AGAVE_API_METADATA=0;
+api_syscb *WASABI_API_SYSCB=0;
+
+static AlbumArt album_art;
+static SingletonServiceFactory<api_albumart, AlbumArt> album_art_factory;
+
+class AlbumArtComponent : public ifc_wa5component
+{
+public:
+ void RegisterServices(api_service *service);
+ int RegisterServicesSafeModeOk();
+ void DeregisterServices(api_service *service);
+protected:
+ RECVS_DISPATCH;
+};
+
+template <class api_T>
+void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
+{
+ if (WASABI_API_SVC)
+ {
+ waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
+{
+ if (WASABI_API_SVC && api_t)
+ {
+ waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ factory->releaseInterface(api_t);
+ }
+ api_t = NULL;
+}
+
+void AlbumArtComponent::RegisterServices(api_service *service)
+{
+ WASABI_API_SVC = service;
+
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceBuild(WASABI_API_SYSCB, syscbApiServiceGuid);
+ album_art_factory.Register(WASABI_API_SVC, &album_art);
+}
+
+int AlbumArtComponent::RegisterServicesSafeModeOk()
+{
+ return 1;
+}
+
+void AlbumArtComponent::DeregisterServices(api_service *service)
+{
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceRelease(WASABI_API_SYSCB, syscbApiServiceGuid);
+ album_art_factory.Deregister(WASABI_API_SVC);
+}
+
+static AlbumArtComponent component;
+extern "C" DLLEXPORT ifc_wa5component *GetWinamp5SystemComponent()
+{
+ return &component;
+}
+
+#define CBCLASS AlbumArtComponent
+START_DISPATCH;
+VCB(API_WA5COMPONENT_REGISTERSERVICES, RegisterServices)
+CB(15, RegisterServicesSafeModeOk)
+VCB(API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/albumart/resource.h b/Src/albumart/resource.h
new file mode 100644
index 00000000..b9b57407
--- /dev/null
+++ b/Src/albumart/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by albumart.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/albumart/version.rc2 b/Src/albumart/version.rc2
new file mode 100644
index 00000000..07b5ca1c
--- /dev/null
+++ b/Src/albumart/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION WINAMP_PRODUCTVER
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp 5.x System Component"
+ VALUE "FileVersion", STR_WINAMP_PRODUCTVER
+ VALUE "InternalName", "albumart.w5s"
+ VALUE "LegalCopyright", "Copyright © 2005-2019 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "albumart.w5s"
+ VALUE "ProductName", "Winamp Album Artwork Management Service"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END