diff options
Diffstat (limited to 'Src/xspf')
-rw-r--r-- | Src/xspf/XSPFHandler.cpp | 74 | ||||
-rw-r--r-- | Src/xspf/XSPFHandler.h | 23 | ||||
-rw-r--r-- | Src/xspf/XSPFHandlerFactory.cpp | 56 | ||||
-rw-r--r-- | Src/xspf/XSPFHandlerFactory.h | 19 | ||||
-rw-r--r-- | Src/xspf/XSPFLoader.cpp | 461 | ||||
-rw-r--r-- | Src/xspf/XSPFLoader.h | 16 | ||||
-rw-r--r-- | Src/xspf/api__xspf.h | 21 | ||||
-rw-r--r-- | Src/xspf/main.cpp | 71 | ||||
-rw-r--r-- | Src/xspf/resource.h | 16 | ||||
-rw-r--r-- | Src/xspf/version.rc2 | 39 | ||||
-rw-r--r-- | Src/xspf/xspf.rc | 86 | ||||
-rw-r--r-- | Src/xspf/xspf.sln | 30 | ||||
-rw-r--r-- | Src/xspf/xspf.vcxproj | 278 | ||||
-rw-r--r-- | Src/xspf/xspf.vcxproj.filters | 53 |
14 files changed, 1243 insertions, 0 deletions
diff --git a/Src/xspf/XSPFHandler.cpp b/Src/xspf/XSPFHandler.cpp new file mode 100644 index 00000000..72c0927e --- /dev/null +++ b/Src/xspf/XSPFHandler.cpp @@ -0,0 +1,74 @@ +#include "XSPFHandler.h" +#include "XSPFLoader.h" +#include "api__xspf.h" +#include "resource.h" + +const wchar_t *XSPFHandler::EnumerateExtensions(size_t n) +{ + switch(n) + { + case 0: + return L"xspf"; + default: + return 0; + } +} + +const char *XSPFHandler::EnumerateMIMETypes(size_t n) +{ + switch(n) + { + case 0: + return "application/xspf+xml"; + default: + return 0; + } +} + +const wchar_t *XSPFHandler::GetName() +{ + static wchar_t xspfpl[64]; + // no point re-loading this all of the time since it won't change once we've been loaded + return (!xspfpl[0]?WASABI_API_LNGSTRINGW_BUF(IDS_XSPF_PLAYLIST,xspfpl,64):xspfpl); +} + +// returns SUCCESS and FAILED, so be careful ... +int XSPFHandler::SupportedFilename(const wchar_t *filename) +{ + size_t filenameLength = wcslen(filename); + size_t extensionLength = wcslen(L".xspf"); + if (filenameLength < extensionLength) return SVC_PLAYLISTHANDLER_FAILED; // too short + if (!_wcsicmp(filename + filenameLength - extensionLength, L".xspf")) + return SVC_PLAYLISTHANDLER_SUCCESS; + else + return SVC_PLAYLISTHANDLER_FAILED; +} + +int XSPFHandler::SupportedMIMEType(const char *type) +{ + if (!strcmp(type, "application/xspf+xml")) + return SVC_PLAYLISTHANDLER_SUCCESS; + else + return SVC_PLAYLISTHANDLER_FAILED; +} + +ifc_playlistloader *XSPFHandler::CreateLoader(const wchar_t *filename) +{ + return new XSPFLoader; +} + +void XSPFHandler::ReleaseLoader(ifc_playlistloader *loader) +{ + delete static_cast<XSPFLoader *>(loader); +} + +// Define the dispatch table +#define CBCLASS XSPFHandler +START_DISPATCH; +CB(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, EnumerateExtensions) +CB(SVC_PLAYLISTHANDLER_ENUMMIMETYPES, EnumerateMIMETypes) +CB(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, SupportedFilename) +CB(SVC_PLAYLISTHANDLER_CREATELOADER, CreateLoader) +VCB(SVC_PLAYLISTHANDLER_RELEASELOADER, ReleaseLoader) +CB(SVC_PLAYLISTHANDLER_GETNAME, GetName) +END_DISPATCH;
\ No newline at end of file diff --git a/Src/xspf/XSPFHandler.h b/Src/xspf/XSPFHandler.h new file mode 100644 index 00000000..bcfa949b --- /dev/null +++ b/Src/xspf/XSPFHandler.h @@ -0,0 +1,23 @@ +#ifndef NULLSOFT_XSPF_XSPFHANDLER_H +#define NULLSOFT_XSPF_XSPFHANDLER_H + +#include "../playlist/svc_playlisthandler.h" +// the "Playlist Handler" is responsible for describing all the capabilities of the playlist format to Winamp +// It is a singleton class (for each playlist type) +// besides informational functions, it contains factory methods for creating playlist loaders and writers + +class XSPFHandler : public svc_playlisthandler +{ +public: + const wchar_t *EnumerateExtensions(size_t n); // returns 0 when it's done + const char *EnumerateMIMETypes(size_t n); // returns 0 when it's done, returns char * to match HTTP specs + const wchar_t *GetName(); // returns a name suitable for display to user of this playlist form (e.g. PLS Playlist) + int SupportedFilename(const wchar_t *filename); // returns SUCCESS and FAILED, so be careful ... + int SupportedMIMEType(const char *filename); // returns SUCCESS and FAILED, so be careful ... + ifc_playlistloader *CreateLoader(const wchar_t *filename); + void ReleaseLoader(ifc_playlistloader *loader); + +protected: + RECVS_DISPATCH; // boiler-plate code for the dispatch-table +}; +#endif
\ No newline at end of file diff --git a/Src/xspf/XSPFHandlerFactory.cpp b/Src/xspf/XSPFHandlerFactory.cpp new file mode 100644 index 00000000..f1a17d3a --- /dev/null +++ b/Src/xspf/XSPFHandlerFactory.cpp @@ -0,0 +1,56 @@ +#include "XSPFHandlerFactory.h" +#include "XSPFHandler.h" +/* + This is the GUID for our service factory + don't re-use this. + make your own guid with guidgen.exe + lives somewhere like C:\program files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin +*/ + +// {51D17273-566F-4fa9-AFE0-1345C65B8B1B} +static const GUID XSPFHandlerGUID = +{ 0x51d17273, 0x566f, 0x4fa9, { 0xaf, 0xe0, 0x13, 0x45, 0xc6, 0x5b, 0x8b, 0x1b } }; + + +// our playlist handler. +static XSPFHandler xspfHandler; + +FOURCC XSPFHandlerFactory::GetServiceType() +{ + return svc_playlisthandler::getServiceType(); +} + +const char *XSPFHandlerFactory::GetServiceName() +{ + return "XSPF Playlist Loader"; +} + +GUID XSPFHandlerFactory::GetGuid() +{ + return XSPFHandlerGUID; +} + +void *XSPFHandlerFactory::GetInterface(int global_lock) +{ + // xspfHandler is a singleton object, so we can just return a pointer to it + // depending on what kind of service you are making, you might have to + // 'new' an object and return that instead (and then free it in ReleaseInterface) + return &xspfHandler; +} + +int XSPFHandlerFactory::ReleaseInterface(void *ifc) +{ + // no-op because we returned a singleton (see above) + return 1; +} + +// Define the dispatch table +#define CBCLASS XSPFHandlerFactory +START_DISPATCH; +CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType) +CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName) +CB(WASERVICEFACTORY_GETGUID, GetGuid) +CB(WASERVICEFACTORY_GETINTERFACE, GetInterface) +CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/xspf/XSPFHandlerFactory.h b/Src/xspf/XSPFHandlerFactory.h new file mode 100644 index 00000000..e65332e2 --- /dev/null +++ b/Src/xspf/XSPFHandlerFactory.h @@ -0,0 +1,19 @@ +#ifndef NULLSOFT_XSPF_XSPFHANDLERFACTORY_H +#define NULLSOFT_XSPF_XSPFHANDLERFACTORY_H + +#include <api/service/waservicefactory.h> + +class XSPFHandlerFactory : public waServiceFactory +{ +public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGuid(); + void *GetInterface(int global_lock = TRUE); + int ReleaseInterface(void *ifc); + +protected: + RECVS_DISPATCH; // all Wasabi objects implementing a Dispatchable interface require this +}; + +#endif
\ No newline at end of file diff --git a/Src/xspf/XSPFLoader.cpp b/Src/xspf/XSPFLoader.cpp new file mode 100644 index 00000000..5caad890 --- /dev/null +++ b/Src/xspf/XSPFLoader.cpp @@ -0,0 +1,461 @@ +#include "XSPFLoader.h" +#include "../xml/obj_xml.h" +#include "../xml/ifc_xmlreadercallback.h" +#include "api__xspf.h" +#include "../winamp/wa_ipc.h" +#include <api/service/waservicefactory.h> +#include <shlwapi.h> +#include <strsafe.h> + +// tries to retrieve the media library API (if it's not already retrieved +bool HasMediaLibraryAPI() +{ + // TODO: should critical section this + if (!AGAVE_API_MLDB) + { + waServiceFactory *mldbFactory = WASABI_API_SVC->service_getServiceByGuid(mldbApiGuid); + if (mldbFactory) + AGAVE_API_MLDB = (api_mldb *)mldbFactory->getInterface(); // retrieve a pointer to the API object + } + return !!AGAVE_API_MLDB; +} + +static bool HasTagzAPI() +{ + // TODO: should critical section this + if (!AGAVE_API_TAGZ) + { + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(tagzGUID); + if (sf) + AGAVE_API_TAGZ = (api_tagz *)sf->getInterface(); // retrieve a pointer to the API object + } + return !!AGAVE_API_TAGZ; +} + +const wchar_t* ATFString() +{ + // TODO: should critical section this + if (!WASABI_API_APP) + { + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid); + if (sf) + WASABI_API_APP = (api_application *)sf->getInterface(); // retrieve a pointer to the API object + } + if (WASABI_API_APP) + { + const wchar_t *atf = WASABI_API_APP->getATFString(); + if (atf && *atf) return atf; + } + return L"%artist% - %title%"; +} + +// go check out XSPFLoader::Load before decyphering this class +class XSPFLoaderCallback : public ifc_xmlreadercallback +{ +public: + XSPFLoaderCallback(ifc_playlistloadercallback *_playlist); + ~XSPFLoaderCallback(); + void xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); + void xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag); + void xmlReaderOnCharacterDataCallback(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str); + +protected: + RECVS_DISPATCH; + +private: + enum + { + ELEMENT_NONE=-1, + ELEMENT_LOCATION=0, + ELEMENT_IDENTIFIER, + ELEMENT_TITLE, + ELEMENT_CREATOR, + ELEMENT_ALBUM, + ELEMENT_TRACKNUM, + NUM_ELEMENTS, + }; + wchar_t *elements[NUM_ELEMENTS]; + int element; + ifc_playlistloadercallback *playlist; +}; + +XSPFLoaderCallback::XSPFLoaderCallback(ifc_playlistloadercallback *_playlist) +{ + element = ELEMENT_NONE; + for (int i=0;i<NUM_ELEMENTS;i++) + elements[i]=0; + + playlist = _playlist; +} + +XSPFLoaderCallback::~XSPFLoaderCallback() +{ + for (int i=0;i<NUM_ELEMENTS;i++) + { + free(elements[i]); + elements[i]=0; + } +} + +// this gets called for every opening tag +// xmlpath is the full XML path up to this point, delimited with \f (form feed) +// xmltag is the actual opening tag +// params is an object which lets you query for the attribtues in the tag +void XSPFLoaderCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) +{ + if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\flocation")) + element=ELEMENT_LOCATION; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\fidentifier")) + element=ELEMENT_IDENTIFIER; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\ftitle")) + element=ELEMENT_TITLE; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\fcreator")) + element=ELEMENT_CREATOR; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\falbum")) + element=ELEMENT_ALBUM; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\ftracknum")) + element=ELEMENT_TRACKNUM; + else + element=ELEMENT_NONE; +} + +static void QueryStringAdd(const wchar_t *value, wchar_t *&query, size_t &query_len) +{ + if (!value || !*value) return; + while (value && *value && query_len > 3) { + if (*value == L'%') { *query++ = L'%'; *query++ = L'%'; query_len-=2;} + else if (*value == L'\"') { *query++ = L'%'; *query++ = L'2'; *query++ = L'2'; query_len-=3;} + else if (*value == L'\'') { *query++ = L'%'; *query++ = L'2'; *query++ = L'7'; query_len-=3;} + else if (*value == L'[') { *query++ = L'%'; *query++ = L'5'; *query++ = L'B'; query_len-=3;} + else if (*value == L']') { *query++ = L'%'; *query++ = L'5'; *query++ = L'D'; query_len-=3;} + else if (*value == L'(') { *query++ = L'%'; *query++ = L'2'; *query++ = L'8'; query_len-=3;} + else if (*value == L')') { *query++ = L'%'; *query++ = L'2'; *query++ = L'9'; query_len-=3;} + else if (*value == L'#') { *query++ = L'%'; *query++ = L'2'; *query++ = L'3'; query_len-=3;} + else { *query++ = *value; query_len--; } + value++; + } + *query = 0; +} + +class ItemRecordTagProvider : public ifc_tagprovider +{ +public: + ItemRecordTagProvider(itemRecordW *item) : t(item) {} + wchar_t *GetTag(const wchar_t *name, ifc_tagparams *parameters); + void FreeTag(wchar_t *Tag); +protected: + RECVS_DISPATCH; +private: + itemRecordW *t; +}; + +#define CBCLASS ItemRecordTagProvider +START_DISPATCH; +CB(IFC_TAGPROVIDER_GET_TAG, GetTag); +VCB(IFC_TAGPROVIDER_FREE_TAG, FreeTag); +END_DISPATCH; +#undef CBCLASS + +wchar_t *ItemRecordTagProvider::GetTag(const wchar_t *tag, ifc_tagparams *parameters) +{ + bool copy=false; + wchar_t buf[128]={0}; + wchar_t *value = NULL; + + if (!_wcsicmp(tag, L"artist")) value = t->artist; + else if (!_wcsicmp(tag, L"album")) value = t->album; + else if (!_wcsicmp(tag, L"filename")) value = t->filename; + else if (!_wcsicmp(tag, L"title")) value = t->title; + else if (!_wcsicmp(tag, L"year")) + { + if (t->year > 0) + { + StringCchPrintfW(buf, 128, L"%04d", t->year); + value = buf; + } + } + else if (!_wcsicmp(tag, L"genre")) value = t->genre; + else if (!_wcsicmp(tag, L"comment")) value = t->comment; + else if (!_wcsicmp(tag, L"tracknumber") || !_wcsicmp(tag, L"track")) + { + if (t->track > 0) + { + if (t->tracks > 0) + StringCchPrintfW(buf, 128, L"%02d/%02d", t->track, t->tracks); + else + StringCchPrintfW(buf, 128, L"%02d", t->track); + value = buf; + } + } + else if (!_wcsicmp(tag, L"disc")) + { + if (t->disc > 0) + { + if (t->discs > 0) + StringCchPrintfW(buf, 128, L"%d/%d", t->disc, t->discs); + else + StringCchPrintfW(buf, 128, L"%d", t->disc); + + value = buf; + } + } + else if (!_wcsicmp(tag, L"rating")) + { + if (t->rating > 0) + { + StringCchPrintfW(buf, 128, L"%d", t->rating); + value = buf; + } + } + else if (!_wcsicmp(tag, L"playcount")) + { + if (t->playcount > 0) + { + StringCchPrintfW(buf, 128, L"%d", t->playcount); + value = buf; + } + } + else if (!_wcsicmp(tag, L"bitrate")) + { + if (t->bitrate > 0) + { + StringCchPrintfW(buf, 128, L"%d", t->bitrate); + value = buf; + } + } + else if (!_wcsicmp(tag, L"bpm")) + { + if (t->bpm > 0) + { + StringCchPrintfW(buf, 128, L"%d", t->bpm); + value = buf; + } + } + else if (!_wcsicmp(tag, L"albumartist")) value = t->albumartist; + else if (!_wcsicmp(tag, L"publisher")) value = t->publisher; + else if (!_wcsicmp(tag, L"composer")) value = t->composer; + else if (!_wcsicmp(tag, L"replaygain_album_gain")) value = t->replaygain_album_gain; + else if (!_wcsicmp(tag, L"replaygain_track_gain")) value = t->replaygain_track_gain; + else if (!_wcsicmp(tag, L"GracenoteFileID")) + { + copy=true; + value = getRecordExtendedItem(t, L"GracenoteFileID"); + } + else if (!_wcsicmp(tag, L"GracenoteExtData")) + { + copy=true; + value = getRecordExtendedItem(t, L"GracenoteExtData"); + } + else + return 0; + + if (!value) + return 0; + else + { + if (copy || value == buf) + return AGAVE_API_MLDB->DuplicateString(value); + else + { + AGAVE_API_MLDB->RetainString(value); + return value; + } + } +} + +void ItemRecordTagProvider::FreeTag(wchar_t *tag) +{ + AGAVE_API_MLDB->ReleaseString(tag); +} + +// this gets called for every closing tag +void XSPFLoaderCallback::xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag) +{ + if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack")) + { + // end of track info + if (elements[ELEMENT_LOCATION] // if we have a location + && (PathIsURL(elements[ELEMENT_LOCATION]) // and it's a URL + || GetFileAttributes(elements[ELEMENT_LOCATION]) != INVALID_FILE_ATTRIBUTES)) // or a file that exists + { + // location field seemed OK so go ahead and add + // TODO try using the length if available... + playlist->OnFile(elements[ELEMENT_LOCATION], 0, -1, 0); + } + else if (HasMediaLibraryAPI()) // we don't have a good location so let's hit the media library + { + // let's build a query out of what we have + bool needs_and=false; + wchar_t query[2048]={0}; + wchar_t *query_end=query; + size_t query_size=2048; + + struct { + const wchar_t *field_name; + int field_value; + } fields[] = + { + {L"artist", ELEMENT_CREATOR}, + {L"title", ELEMENT_TITLE}, + }; + for(size_t i=0;i!=sizeof(fields)/sizeof(fields[0]);i++) + { + if (elements[fields[i].field_value]) + { + if (needs_and) + StringCchCopyEx(query_end, query_size, L" AND ", &query_end, &query_size, 0); + StringCchPrintfEx(query_end, query_size, &query_end, &query_size, 0, L"(%s == \"", fields[i].field_name); + QueryStringAdd(elements[fields[i].field_value], query_end, query_size); + StringCchCopyEx(query_end, query_size, L"\")", &query_end, &query_size, 0); + needs_and=true; + } + } + + if (query[0]) + { + itemRecordListW *results = AGAVE_API_MLDB->QueryLimit(query, 1); + if (results && results->Size >= 1 && results->Items[0].filename) + { + if (HasTagzAPI()) + { + wchar_t title[2048]={0}; + ItemRecordTagProvider provider(&results->Items[0]); + AGAVE_API_TAGZ->format(ATFString(), title, 2048, &provider, 0); + int length = -1; + if (results->Items[0].length > 0) + length=results->Items[0].length*1000; + playlist->OnFile(results->Items[0].filename, title, length, 0); + } + else + { + int length = -1; + if (results->Items[0].length > 0) + length=results->Items[0].length*1000; + playlist->OnFile(results->Items[0].filename, 0, length, 0); + } + } + AGAVE_API_MLDB->FreeRecordList(results); + } + } + for (int i=0;i<NUM_ELEMENTS;i++) + { + free(elements[i]); + elements[i]=0; + } + } + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\flocation")) + element=ELEMENT_NONE; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\fidentifier")) + element=ELEMENT_NONE; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\ftitle")) + element=ELEMENT_NONE; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\fcreator")) + element=ELEMENT_NONE; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\falbum")) + element=ELEMENT_NONE; + else if (!wcscmp(xmlpath, L"playlist\ftrackList\ftrack\ftracknum")) + element=ELEMENT_NONE; +} + +void XSPFLoaderCallback::xmlReaderOnCharacterDataCallback(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str) +{ + if (element!=ELEMENT_NONE) + { + // this certainly isn't the most memory efficient way to do this but it'll work for now :) + if (elements[element] == 0) + { + elements[element] = wcsdup(str); + } + else + { + size_t elementlen = wcslen(elements[element]); + size_t incominglen = wcslen(str); + + wchar_t *&newstr = elements[element], *oldstr = newstr; + newstr = (wchar_t *)realloc(newstr, sizeof(wchar_t)*(elementlen+incominglen+1)); + if (newstr != NULL) + { + memcpy(newstr+elementlen, str, incominglen*sizeof(wchar_t)); + newstr[elementlen+incominglen] = 0; + } + } + } +} + +#define CBCLASS XSPFLoaderCallback +START_DISPATCH; +VCB(ONSTARTELEMENT, xmlReaderOnStartElementCallback) +VCB(ONENDELEMENT, xmlReaderOnEndElementCallback) +VCB(ONCHARDATA, xmlReaderOnCharacterDataCallback) +END_DISPATCH; +#undef CBCLASS + +/* ---------------------------- */ +static int LoadFile(obj_xml *parser, const wchar_t *filename) +{ + HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); + + if (file == INVALID_HANDLE_VALUE) + return IFC_PLAYLISTLOADER_FAILED; + + while (true) + { + char data[1024] = {0}; + DWORD bytesRead = 0; + if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead) + { + if (parser->xmlreader_feed(data, bytesRead) != API_XML_SUCCESS) + { + CloseHandle(file); + return IFC_PLAYLISTLOADER_FAILED; + } + } + else + break; + } + + CloseHandle(file); + if (parser->xmlreader_feed(0, 0) != API_XML_SUCCESS) + return IFC_PLAYLISTLOADER_FAILED; + + return IFC_PLAYLISTLOADER_SUCCESS; +} + +// this get called by Winamp +// you a method in the passed playlist loader callback object +// for each item in the playlist +int XSPFLoader::Load(const wchar_t *filename, ifc_playlistloadercallback *playlist) +{ + // first thing we'll need is an XML parser + // we'll have to do the wasabi dance to get it + + // first, get the service factory for creating XML objects + waServiceFactory *xmlFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); + if (xmlFactory) + { + obj_xml *parser = (obj_xml *)xmlFactory->getInterface(); // create an XML parser + if (parser) + { + // ok now we can get down to biz'nes + XSPFLoaderCallback xmlCallback(playlist); + parser->xmlreader_registerCallback(L"*", &xmlCallback); + parser->xmlreader_setCaseSensitive(); + parser->xmlreader_open(); + int ret = LoadFile(parser, filename); + parser->xmlreader_unregisterCallback(&xmlCallback); + parser->xmlreader_close(); + xmlFactory->releaseInterface(parser); // destroy the XML parser via the service factory + + return ret; + } + } + + return IFC_PLAYLISTLOADER_FAILED; +} + +// Define the dispatch table +#define CBCLASS XSPFLoader +START_DISPATCH; +CB(IFC_PLAYLISTLOADER_LOAD, Load) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/xspf/XSPFLoader.h b/Src/xspf/XSPFLoader.h new file mode 100644 index 00000000..04e2230f --- /dev/null +++ b/Src/xspf/XSPFLoader.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_XSPF_XSPFLOADER_H +#define NULLSOFT_XSPF_XSPFLOADER_H + +#include "../playlist/ifc_playlistloader.h" + +// this is the class that actually loads the playlist. +// everything up to this point (component, handler, handler factory) was just administrative +class XSPFLoader : public ifc_playlistloader +{ +public: + int Load(const wchar_t *filename, ifc_playlistloadercallback *playlist); + +protected: + RECVS_DISPATCH; // boiler-plate code for our dispatch table +}; +#endif
\ No newline at end of file diff --git a/Src/xspf/api__xspf.h b/Src/xspf/api__xspf.h new file mode 100644 index 00000000..8fa5cb6f --- /dev/null +++ b/Src/xspf/api__xspf.h @@ -0,0 +1,21 @@ +#ifndef NULLSOFT_XSPF_API_H +#define NULLSOFT_XSPF_API_H + +// Service Manager +#include "api/service/api_service.h" + +// Media Library API +#include "../Plugins/Library/ml_local/api_mldb.h" +extern api_mldb *mldbApi; +#define AGAVE_API_MLDB mldbApi + +#include "../Agave/Language/api_language.h" + +#include "../tagz/api_tagz.h" +extern api_tagz *tagzApi; +#define AGAVE_API_TAGZ tagzApi + +#include <api/application/api_application.h> +#define WASABI_API_APP applicationApi + +#endif
\ No newline at end of file diff --git a/Src/xspf/main.cpp b/Src/xspf/main.cpp new file mode 100644 index 00000000..ab0001f5 --- /dev/null +++ b/Src/xspf/main.cpp @@ -0,0 +1,71 @@ +#include "../Agave/Component/ifc_wa5component.h" +#include "api__xspf.h" // services we'll used are extern'd here +#include "XSPFHandlerFactory.h" + +// declarations for the pointers to services we'll need +// by convention, these follow the format WASABI_API_* or AGAVE_API_* +// you are free to name it however you want, but this provides good consistency +api_service *WASABI_API_SVC = 0; // the wasabi service manager (our gateway to other services) +api_mldb *AGAVE_API_MLDB = 0; // media library API. we'll retrieve this the first time we need it, because it will load after us +api_tagz *AGAVE_API_TAGZ = 0; +api_application *WASABI_API_APP = 0; +// wasabi based services for localisation support +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; + +// our service factories that we're going to register +static XSPFHandlerFactory xspfHandlerFactory; + +// here is the implementation of our component +// this class contains the methods called during initialization and shutdown +// to register/deregister our component's services +class XSPFComponent : public ifc_wa5component +{ +public: + void RegisterServices(api_service *service); // this is where the party is + void DeregisterServices(api_service *service); + +protected: + RECVS_DISPATCH; // some boiler-plate code to implement our dispatch table +}; + +static HINSTANCE GetMyInstance() +{ + MEMORY_BASIC_INFORMATION mbi = {0}; + if(VirtualQuery(GetMyInstance, &mbi, sizeof(mbi))) + return (HINSTANCE)mbi.AllocationBase; + return NULL; +} + +void XSPFComponent::RegisterServices(api_service *service) +{ + WASABI_API_SVC = service; // we get passed the service manager and we need to save the pointer + WASABI_API_SVC->service_register(&xspfHandlerFactory); + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID); + if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface()); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(GetMyInstance(),playlistLangGUID); +} + +void XSPFComponent::DeregisterServices(api_service *service) +{ + WASABI_API_SVC->service_deregister(&xspfHandlerFactory); +} + +static XSPFComponent xspfComponent; +// Winamp calls this function after it LoadLibrary's your W5S +// you need to turn a pointer to your component. +extern "C" __declspec(dllexport) ifc_wa5component *GetWinamp5SystemComponent() +{ + return &xspfComponent; +} + +// some boiler-plate code to implement the dispatch table for our component +#define CBCLASS XSPFComponent +START_DISPATCH; +VCB(API_WA5COMPONENT_REGISTERSERVICES, RegisterServices) +VCB(API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/xspf/resource.h b/Src/xspf/resource.h new file mode 100644 index 00000000..1249067c --- /dev/null +++ b/Src/xspf/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by xspf.rc +// +#define IDS_XSPF_PLAYLIST 8 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/xspf/version.rc2 b/Src/xspf/version.rc2 new file mode 100644 index 00000000..f27fc594 --- /dev/null +++ b/Src/xspf/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", "xspf.w5s" + VALUE "LegalCopyright", "Copyright © 2007-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "xspf.w5s" + VALUE "ProductName", "Winamp XML Shareable Playlist Format Support" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/xspf/xspf.rc b/Src/xspf/xspf.rc new file mode 100644 index 00000000..967c05c4 --- /dev/null +++ b/Src/xspf/xspf.rc @@ -0,0 +1,86 @@ +// 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 + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_XSPF_PLAYLIST "XML Shareable Playlist Format" +END + +#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/xspf/xspf.sln b/Src/xspf/xspf.sln new file mode 100644 index 00000000..6d3f3b58 --- /dev/null +++ b/Src/xspf/xspf.sln @@ -0,0 +1,30 @@ +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}") = "xspf", "xspf.vcxproj", "{3FDDC715-EC20-4FD6-B723-92795736BDD5}" +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 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Debug|Win32.Build.0 = Debug|Win32 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Debug|x64.ActiveCfg = Debug|x64 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Debug|x64.Build.0 = Debug|x64 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Release|Win32.ActiveCfg = Release|Win32 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Release|Win32.Build.0 = Release|Win32 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Release|x64.ActiveCfg = Release|x64 + {3FDDC715-EC20-4FD6-B723-92795736BDD5}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F492E8CB-F967-49DF-9CBE-D69862846DD6} + EndGlobalSection +EndGlobal diff --git a/Src/xspf/xspf.vcxproj b/Src/xspf/xspf.vcxproj new file mode 100644 index 00000000..14b3e137 --- /dev/null +++ b/Src/xspf/xspf.vcxproj @@ -0,0 +1,278 @@ +<?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>{3FDDC715-EC20-4FD6-B723-92795736BDD5}</ProjectGuid> + <RootNamespace>xspf</RootNamespace> + <Keyword>Win32Proj</Keyword> + <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"> + <VcpkgEnabled>false</VcpkgEnabled> + </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)'=='Debug|x64'"> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </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> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>../replicant;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;XSPF_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(ProjectDir)x86_Debug\$(ProjectName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <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>../replicant;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;XSPF_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(ProjectDir)x64_Debug\$(ProjectName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <ProfileGuidedDatabase>$(ProjectDir)x64_Debug\$(TargetName).pgd</ProfileGuidedDatabase> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <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> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>../replicant;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;XSPF_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <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> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <ProfileGuidedDatabase>$(ProjectDir)x86_Release\$(TargetName).pgd</ProfileGuidedDatabase> + <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <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> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>../replicant;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;XSPF_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <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> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <ManifestFile>$(ProjectDir)x64_Release\$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile> + <ProfileGuidedDatabase>$(ProjectDir)x64_Release\$(TargetName).pgd</ProfileGuidedDatabase> + <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <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="..\Plugins\General\gen_ml\ml_lib.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="XSPFHandler.cpp" /> + <ClCompile Include="XSPFHandlerFactory.cpp" /> + <ClCompile Include="XSPFLoader.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__xspf.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="XSPFHandler.h" /> + <ClInclude Include="XSPFHandlerFactory.h" /> + <ClInclude Include="XSPFLoader.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="xspf.rc" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/xspf/xspf.vcxproj.filters b/Src/xspf/xspf.vcxproj.filters new file mode 100644 index 00000000..b5aea129 --- /dev/null +++ b/Src/xspf/xspf.vcxproj.filters @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="XSPFHandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="XSPFHandlerFactory.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="XSPFLoader.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Plugins\General\gen_ml\ml_lib.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="XSPFLoader.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="XSPFHandlerFactory.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="XSPFHandler.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="api__xspf.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{85782fd0-d621-46ed-84af-21d7dc5cbb60}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{4d951680-f48e-4040-9d03-dbafac1e7cb1}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{0a439138-f363-4152-aaaf-5e20c98a37cd}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="xspf.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file |