| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 | 
							- #include "main.h"
 
- #include "api.h"
 
- #include "ASXLoader.h"
 
- #include <stdio.h>
 
- #include "../nu/AutoWide.h"
 
- #include "../xml/ifc_xmlreadercallback.h"
 
- #include "../xml/obj_xml.h"
 
- #include "api.h"
 
- #include <api/service/waservicefactory.h>
 
- #include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
 
- #include "../nu/AutoChar.h"
 
- #include "../Winamp/strutil.h"
 
- #include <strsafe.h>
 
- #include "XMLString.h"
 
- void SetUserAgent(api_httpreceiver *http)
 
- {
 
- 	char agent[256] = {0};
 
- 	StringCchPrintfA(agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString());
 
- 	http->addheader(agent);
 
- }
 
- class ASXInfo : public ifc_plentryinfo
 
- {
 
- public:
 
- 	ASXInfo()
 
- 	{
 
- 		memset( returnTemp, 0, sizeof( returnTemp ) );
 
- 	}
 
- 	const wchar_t *GetExtendedInfo( const wchar_t *parameter )
 
- 	{
 
- 		if ( !_wcsicmp( parameter, L"context" ) )
 
- 		{
 
- 			if ( isRadio )
 
- 				return L"radio";
 
- 		}
 
- 		else if ( !_wcsicmp( parameter, L"repeat" ) )
 
- 		{
 
- 			if ( repeat )
 
- 			{
 
- 				StringCchPrintfW( returnTemp, 20, L"%d", repeat );
 
- 				return returnTemp;
 
- 			}
 
- 		}
 
- 		return 0;
 
- 	}
 
- 	bool isRadio = false;
 
- 	int  repeat  = 0;
 
- protected:
 
- 	RECVS_DISPATCH;
 
- 	wchar_t returnTemp[ 20 ];
 
- };
 
- #define CBCLASS ASXInfo
 
- START_DISPATCH;
 
- CB( IFC_PLENTRYINFO_GETEXTENDEDINFO, GetExtendedInfo )
 
- END_DISPATCH;
 
- #undef CBCLASS
 
- class ASXXML : public ifc_xmlreadercallback
 
- {
 
- public:
 
- 	ASXXML(ifc_playlistloadercallback *_playlist, const wchar_t *_root, obj_xml *_parser) : playlist(_playlist), rootPath(_root), parser(_parser)
 
- 	{
 
- 	}
 
- 	void OnFileHelper(ifc_playlistloadercallback *playlist, const wchar_t *filename, const wchar_t *title, int length, ifc_plentryinfo *extraInfo)
 
- 	{
 
- 		if (wcsstr(filename, L"://") || PathIsRootW(filename))
 
- 		{
 
- 			playlist->OnFile(filename, title, length, extraInfo);
 
- 		}
 
- 		else
 
- 		{
 
- 			wchar_t fullPath[MAX_PATH] = {0}, canonicalizedPath[MAX_PATH] = {0};
 
- 			PathCombineW(fullPath, rootPath, filename);
 
- 			PathCanonicalizeW(canonicalizedPath, fullPath);
 
- 			playlist->OnFile(canonicalizedPath, title, length, extraInfo);
 
- 		}
 
- 	}
 
- 	void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
 
- 	{
 
- 		if (!_wcsicmp(xmltag, L"ENTRYREF"))
 
- 		{
 
- 			const wchar_t *url = params->getItemValue(L"HREF");
 
- 			const wchar_t *titleHack = params->getItemValue(L"CLIENTBIND");
 
- 			int lengthHack = -1;
 
- 			wchar_t titleBuf[256] = L"";
 
- 			if (titleHack)
 
- 			{
 
- 				// get the length out of the parantheses
 
- 				StringCchCopyW(titleBuf, 256, titleHack);
 
- 				wchar_t *end = titleBuf + lstrlenW(titleBuf);
 
- 				while (end && *end && *end != '(' && end != titleBuf)
 
- 					end = CharPrevW(titleBuf, end);
 
- 				*end = 0;
 
- 				end++;
 
- 				lengthHack = _wtoi(end);
 
- 			}
 
- 			wchar_t filename[FILENAME_SIZE] = {0};
 
- 			if (wcschr(url, L'?'))
 
- 				StringCchPrintfW(filename, FILENAME_SIZE, L"%s&=.asx", url);
 
- 			else
 
- 				StringCchPrintfW(filename, FILENAME_SIZE, L"%s?.asx", url);
 
- 			OnFileHelper(playlist, filename, titleBuf, lengthHack*1000, &info);
 
- 		}
 
- 		else if (!_wcsicmp(xmlpath, L"ASX\fENTRY\fREF") || !_wcsicmp(xmlpath, L"ASX\fREPEAT\fENTRY\fREF"))
 
- 		{
 
- 			const wchar_t *track = params->getItemValue(L"HREF");
 
- 			wchar_t fullTitle[128] = {0}, fullFilename[FILENAME_SIZE] = {0};
 
- 			// if there is no extension given, we need to add ?.wma or &=.wma to the end of the URL
 
- 			// this could be 2 lines of code if that wasn't the case :(
 
- 			if (track)
 
- 			{
 
- 				const wchar_t *trackTitle = 0;
 
- 				if (title.GetString()[0] && artist.GetString()[0])
 
- 				{
 
- 					StringCchPrintfW(fullTitle, 128, L"%s - %s", artist.GetString(), title.GetString());
 
- 					trackTitle = fullTitle;
 
- 				}
 
- 				if (!_wcsnicmp(track, L"http://", 7))
 
- 				{
 
- 					const wchar_t *end = scanstr_backcW(track, L"/.", 0);
 
- 					if (!end || *end == L'/')
 
- 					{
 
- 						if (wcschr(track, L'?'))
 
- 							StringCchPrintfW(fullFilename, FILENAME_SIZE, L"%s&=.wma", track);
 
- 						else
 
- 							StringCchPrintfW(fullFilename, FILENAME_SIZE, L"%s?.wma", track);
 
- 						track = fullFilename;
 
- 					}
 
- 				}
 
- 				
 
- 				OnFileHelper(playlist, track, trackTitle, -1, &info);
 
- 			}
 
- 		}
 
- 		else if (!_wcsicmp(xmltag, L"REPEAT"))
 
- 		{
 
- 			const wchar_t *param;
 
- 			if (param = params->getItemValue(L"count"))
 
- 			{
 
- 				info.repeat = _wtoi(param);
 
- 			}
 
- 			else
 
- 				info.repeat = -1;
 
- 		}
 
- 		else if (!_wcsicmp(xmltag, L"PARAM"))
 
- 		{
 
- 			const wchar_t *param;
 
- 			if (param = params->getItemValue(L"name"))
 
- 			{
 
- 				if (!_wcsicmp(param, L"context"))
 
- 				{
 
- 					const wchar_t * value = params->getItemValue(L"value");
 
- 					if (!_wcsicmp(value, L"station"))
 
- 						info.isRadio = true;
 
- 				} 
 
- 				else if (!_wcsicmp(param, L"encoding"))
 
- 				{
 
- 					const wchar_t *value=params->getItemValue(L"value");
 
- 					if (value)
 
- 						parser->xmlreader_setEncoding(value); // I hope we can set it on the fly like this!
 
- 				}
 
- 			}
 
- 		}
 
- 	}
 
- 	void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag)
 
- 	{
 
- 		if (!_wcsicmp(xmltag, L"REPEAT"))
 
- 		{
 
- 			info.repeat = 0;
 
- 		}
 
- 	}
 
- 	ifc_playlistloadercallback *playlist;
 
- 	XMLString title, artist;
 
- 	ASXInfo info;
 
- 	const wchar_t *rootPath;
 
- 	obj_xml *parser;
 
- protected:
 
- 	RECVS_DISPATCH;
 
- };
 
- #define CBCLASS ASXXML
 
- START_DISPATCH;
 
- VCB(ONSTARTELEMENT, StartTag)
 
- VCB(ONENDELEMENT, EndTag)
 
- END_DISPATCH;
 
- #undef CBCLASS
 
- /*
 
- TODO:
 
-  
 
- don't add tracks until all parts of the "ENTRY" tag are processed.  There are some ASX playlists where the title comes AFTER the ref's
 
-  
 
- maybe have separate XML callbacks for metadata (title, author, shit like that) so that logic can be separated from the main ASX logic
 
- */
 
- // ASX isn't really XML.  That means we need to URL-encode the text so our XML parser doesn't choke
 
- // if microsoft followed standards, the world would be a better place.
 
- int ASXLoader::GayASX_to_XML_converter(obj_xml *parser, char *buffer, int len)
 
- {
 
- 	// benski> I have no idea if ASX is always ASCII, or if it's UTF-8 or what.
 
- 	// but really I can't be bothered with Microsoft's lameness right now, so we'll assume it's local code page for the time being
 
- 	char *start = buffer;
 
- 	int sofar = 0;
 
- 	for (int i = 0;i < len;i++)
 
- 	{
 
- 		if (buffer[i] == '&')
 
- 		{
 
- 			if (sofar)
 
- 			{
 
- 				if (parser->xmlreader_feed(start, sofar) != API_XML_SUCCESS)
 
- 					return API_XML_FAILURE;
 
- 			}
 
- 			if (parser->xmlreader_feed("&", 5) != API_XML_SUCCESS) // no null terminator
 
- 				return API_XML_FAILURE;
 
- 			start = &buffer[i + 1];
 
- 			sofar = 0;
 
- 		}
 
- 		else 
 
- 		{
 
- 			/**
 
- 			  * ok, this might look really weird
 
- 			  * but ASX doesn't have case sensitivity
 
- 				* so lots of playlists have things like
 
- 				* <title>This is the title</Title>
 
- 				* and so we have to accomodate
 
- 				* for this nonsense
 
- 				*/
 
- 			if (inTag && !inQuotes)
 
- 				buffer[i] = toupper(buffer[i]);
 
- 			if (buffer[i] == '>')
 
- 			{
 
- 				inTag=false;
 
- 			}
 
- 			else if (buffer[i] == '<')
 
- 			{
 
- 				inTag=true;
 
- 			}
 
- 			// dro> only do uppercase handling on parts of the tag not inbetween quotes
 
- 			// (some servers just don't like having the urls case messed with, the swines)
 
- 			if (buffer[i] == '"')
 
- 			{
 
- 				if(!inQuotes)
 
- 					inQuotes=true;
 
- 				else
 
- 					inQuotes=false;
 
- 			}
 
- 			sofar++;
 
- 		}
 
- 	}
 
- 	if (sofar && parser->xmlreader_feed(start, sofar) != API_XML_SUCCESS)
 
- 		return API_XML_FAILURE;
 
- 	OutputDebugStringA(buffer);
 
- 	return API_XML_SUCCESS;
 
- }
 
- #define HTTP_BUFFER_SIZE 16384
 
- int ASXLoader::FeedXMLHTTP(api_httpreceiver *http, obj_xml *parser, bool *noData)
 
- {
 
- 	char downloadedData[HTTP_BUFFER_SIZE] = {0};
 
- 	int xmlResult = API_XML_SUCCESS; 
 
- 	int downloadSize = http->get_bytes(downloadedData, HTTP_BUFFER_SIZE);
 
- 	if (downloadSize)
 
- 	{
 
- 		xmlResult = GayASX_to_XML_converter(parser, downloadedData, downloadSize);
 
- 		*noData=false;
 
- 	}
 
- 	else	
 
- 		*noData = true;
 
- 	return xmlResult;
 
- }
 
- void ASXLoader::RunXMLDownload(api_httpreceiver *http, obj_xml *parser)
 
- {
 
- int ret;
 
- 	bool noData;
 
- 	do
 
- 	{
 
- 		Sleep(50);
 
- 		ret = http->run();
 
- 		if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
 
- 			return ;
 
- 	}
 
- 	while (ret == HTTPRECEIVER_RUN_OK);
 
- 	// finish off the data
 
- 	do
 
- 	{
 
- 		if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
 
- 			return ;
 
-   } while (!noData);
 
- 	parser->xmlreader_feed(0, 0);
 
- }
 
- int ASXLoader::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 (GayASX_to_XML_converter(parser, 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;
 
- }
 
- int ASXLoader::LoadURL(obj_xml *parser, const wchar_t *url)
 
- {
 
- 	api_httpreceiver *http = 0;
 
- 	waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
 
- 	if (sf) http = (api_httpreceiver *)sf->getInterface();
 
- 	if (!http)
 
- 		return IFC_PLAYLISTLOADER_FAILED;
 
- 	http->AllowCompression();
 
- 	http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, winamp.GetProxy()); 
 
- 	SetUserAgent(http);
 
- 	http->connect(AutoChar(url));
 
- 	int ret;
 
- 	do
 
- 	{
 
- 		Sleep(10);
 
- 		ret = http->run();
 
- 		if (ret == -1) // connection failed
 
- 			break;
 
- 		// ---- check our reply code ----
 
- 		int replycode = http->getreplycode();
 
- 		switch (replycode)
 
- 		{
 
- 		case 0:
 
- 		case 100:
 
- 			break;
 
- 		case 200:
 
- 			{
 
- 				RunXMLDownload(http, parser);
 
- 				sf->releaseInterface(http);
 
- 				return IFC_PLAYLISTLOADER_SUCCESS;
 
- 			}
 
- 			break;
 
- 		default:
 
- 			sf->releaseInterface(http);
 
- 			return IFC_PLAYLISTLOADER_FAILED;
 
- 		}
 
- 	}
 
- 	while (ret == HTTPRECEIVER_RUN_OK);
 
- 	//const char *er = http->geterrorstr();
 
- 	sf->releaseInterface(http);
 
- 	return IFC_PLAYLISTLOADER_FAILED;
 
- }
 
- static int loadasxv2fn(const wchar_t *filename, ifc_playlistloadercallback *playlist)
 
- {
 
- 	int i=1;
 
- 	wchar_t ref[FILENAME_SIZE] = {0};
 
- 	wchar_t key[100] = {0};
 
- 	while (1)
 
- 	{
 
- 		StringCchPrintfW(key, 100, L"Ref%d", i++);
 
- 		GetPrivateProfileStringW(L"Reference", key, L"?", ref, FILENAME_SIZE, filename);
 
- 		if (!lstrcmpiW(ref, L"?"))
 
- 		break;
 
- 		else
 
- 		{
 
- 				if (!_wcsnicmp(ref, L"http://", 7))
 
- 				{
 
- 					const wchar_t *end = scanstr_backcW(ref, L"/.", 0);
 
- 					if (!end || *end == L'/')
 
- 					{
 
- 						if (wcschr(ref, L'?'))
 
- 							StringCchCatW(ref, FILENAME_SIZE, L"&=.wma");
 
- 						else
 
- 								StringCchCatW(ref, FILENAME_SIZE, L"?.wma");
 
- 					}
 
- 				}
 
- 				playlist->OnFile(ref, 0, 0, 0);
 
- 		}
 
- 	}
 
- 	return IFC_PLAYLISTLOADER_SUCCESS;
 
- }
 
- int ASXLoader::Load(const wchar_t *filename, ifc_playlistloadercallback *playlist)
 
- {
 
- 	obj_xml *parser = 0;
 
- 	waServiceFactory *parserFactory = 0;
 
- 	HANDLE quickTest = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
 
- 	if (quickTest != INVALID_HANDLE_VALUE)
 
- 	{
 
- 		char reference[11] = {0};
 
- 		DWORD bytesRead=0;
 
- 		ReadFile(quickTest, reference, 11, &bytesRead, 0);
 
- 		CloseHandle(quickTest);
 
- 		if (bytesRead == 11 && !_strnicmp(reference, "[Reference]", 11))
 
- 			return loadasxv2fn(filename, playlist);		
 
- 	}
 
- 	parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
 
- 	if (parserFactory)
 
- 		parser = (obj_xml *)parserFactory->getInterface();
 
- 	if (parser)
 
- 	{
 
- 		wchar_t rootPath[MAX_PATH] = {0};
 
- 		const wchar_t *callbackPath = playlist->GetBasePath();
 
- 		if (callbackPath)
 
- 			lstrcpynW(rootPath, callbackPath, MAX_PATH);
 
- 		else
 
- 		{
 
- 			lstrcpynW(rootPath, filename, MAX_PATH);
 
- 			PathRemoveFileSpecW(rootPath);
 
- 		}
 
- 		ASXXML asxXml(playlist, rootPath, parser);
 
- 		parser->xmlreader_registerCallback(L"ASX\f*", &asxXml);
 
- 		parser->xmlreader_registerCallback(L"ASX\fENTRY\fTITLE", &asxXml.title);
 
- 		parser->xmlreader_registerCallback(L"ASX\fENTRY\fAUTHOR", &asxXml.artist);
 
- 		parser->xmlreader_open();
 
- 		parser->xmlreader_setEncoding(L"windows-1252");
 
- 		
 
- 		int ret;
 
- 		if (wcsstr(filename, L"://"))
 
- 			ret = LoadURL(parser, filename);
 
- 		else
 
- 			ret = LoadFile(parser, filename);
 
- 		parser->xmlreader_unregisterCallback(&asxXml);
 
- 		parser->xmlreader_unregisterCallback(&asxXml.title);
 
- 		parser->xmlreader_unregisterCallback(&asxXml.artist);
 
- 		parser->xmlreader_close();
 
- 		parserFactory->releaseInterface(parser);
 
- 		return ret;
 
- 	}
 
- 	return IFC_PLAYLISTLOADER_FAILED;
 
- }
 
- #define CBCLASS ASXLoader
 
- START_DISPATCH;
 
- CB(IFC_PLAYLISTLOADER_LOAD, Load)
 
- END_DISPATCH;
 
- #undef CBCLASS
 
 
  |