diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_local/LocalMediaCOM.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_local/LocalMediaCOM.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_local/LocalMediaCOM.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_local/LocalMediaCOM.cpp b/Src/Plugins/Library/ml_local/LocalMediaCOM.cpp new file mode 100644 index 00000000..3600b349 --- /dev/null +++ b/Src/Plugins/Library/ml_local/LocalMediaCOM.cpp @@ -0,0 +1,307 @@ +#include "main.h" +#include "LocalMediaCOM.h" + + +void sortResults(int column, int dir, itemRecordListW *obj); + +static void saveQueryToList(nde_scanner_t s, itemRecordListW *obj, int sortColumn, int sortDir) +{ + emptyRecordList(obj); + + EnterCriticalSection(&g_db_cs); + NDE_Scanner_First(s); + + int r; + do + { + nde_field_t f = NDE_Scanner_GetFieldByID(s, MAINTABLE_ID_FILENAME); + if (f) + { + allocRecordList(obj, obj->Size + 1); + if (!obj->Alloc) break; + + obj->Items[obj->Size].filename = NDE_StringField_GetString(f); + ndestring_retain(obj->Items[obj->Size].filename); + ScannerRefToObjCacheNFNW(s, obj, true); + } + + r = NDE_Scanner_Next(s); + } + while (r && !NDE_Scanner_EOF(s)); + + if (((Table *)g_table)->HasErrors()) // TODO: don't use C++ NDE API + { + wchar_t *last_query = NULL; + if (m_media_scanner) + { + const wchar_t *lq = NDE_Scanner_GetLastQuery(m_media_scanner); + if (lq) last_query = _wcsdup(lq); + NDE_Table_DestroyScanner(g_table, m_media_scanner); + } + NDE_Table_Compact(g_table); + if (m_media_scanner) + { + m_media_scanner = NDE_Table_CreateScanner(g_table); + if (last_query != NULL) + { + NDE_Scanner_Query(m_media_scanner, last_query); + free(last_query); + } + } + } + LeaveCriticalSection(&g_db_cs); + + compactRecordList(obj); + + sortResults(sortColumn, sortDir, obj); +} + +void WriteEscaped(FILE *fp, const wchar_t *str) +{ + // TODO: for speed optimization, + // we should wait until we hit a special character + // and write out everything else so before it, + // like how ASX loader does it + while (str && *str) + { + switch(*str) + { + case L'&': + fputws(L"&", fp); + break; + case L'>': + fputws(L">", fp); + break; + case L'<': + fputws(L"<", fp); + break; + case L'\'': + fputws(L"'", fp); + break; + case L'\"': + fputws(L""", fp); + break; + default: + fputwc(*str, fp); + break; + } + // write out the whole character + wchar_t *next = CharNextW(str); + while (++str != next) + fputwc(*str, fp); + + } +} + +bool SaveListToXML(const itemRecordListW *const obj, const wchar_t *filename, int limit) +{ + int i=0; + FILE *fp = _wfopen(filename, L"wb"); + if (!fp) + return false; + wchar_t BOM = 0xFEFF; + fwrite(&BOM, sizeof(BOM), 1, fp); + fwprintf(fp, L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>"); + fputws(L"<itemlist>\r\n", fp); + + while (i < obj->Size) + { + fputws(L"<item ", fp); + + if (obj->Items[i].filename) + { + fputws(L"filename=\"", fp); + WriteEscaped(fp, obj->Items[i].filename); + fputws(L"\" ", fp); + } + + if (obj->Items[i].title) + { + fputws(L"title=\"", fp); + WriteEscaped(fp, obj->Items[i].title); + fputws(L"\" ", fp); + } + + if (obj->Items[i].album) + { + fputws(L"album=\"", fp); + WriteEscaped(fp, obj->Items[i].album); + fputws(L"\" ", fp); + } + + if (obj->Items[i].artist) + { + fputws(L"artist=\"", fp); + WriteEscaped(fp, obj->Items[i].artist); + fputws(L"\" ", fp); + } + + if (obj->Items[i].comment) + { + fputws(L"comment=\"", fp); + WriteEscaped(fp, obj->Items[i].comment); + fputws(L"\" ", fp); + } + + if (obj->Items[i].genre) + { + fputws(L"genre=\"", fp); + WriteEscaped(fp, obj->Items[i].genre); + fputws(L"\" ", fp); + } + + if (obj->Items[i].year > 0) + fwprintf(fp, L"year=\"%d\" ",obj->Items[i].year); + + if (obj->Items[i].track > 0) + fwprintf(fp, L"track=\"%d\" ",obj->Items[i].track); + + if (obj->Items[i].length > 0) + fwprintf(fp, L"length=\"%d\" ",obj->Items[i].length); + + // TODO: extended info fields + fputws(L"/>", fp); + if (++i == limit) + break; + } + fputws(L"</itemlist>", fp); + fclose(fp); + + return true; +} + +enum +{ + DISP_LOCALMEDIA_XMLQUERY = 777, + +}; + +#define CHECK_ID(str, id) if (_wcsicmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; } +HRESULT LocalMediaCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + bool unknowns = false; + for (unsigned int i = 0;i != cNames;i++) + { + CHECK_ID("XMLQuery", DISP_LOCALMEDIA_XMLQUERY) + rgdispid[i] = DISPID_UNKNOWN; + unknowns = true; + } + if (unknowns) + return DISP_E_UNKNOWNNAME; + else + return S_OK; +} + +HRESULT LocalMediaCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +HRESULT LocalMediaCOM::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +void Bookmark_WriteAsXML(const wchar_t *filename, int max); + +HRESULT LocalMediaCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + switch (dispid) + { + case DISP_LOCALMEDIA_XMLQUERY: + if (pdispparams->cArgs == 4) + { + openDb(); + int max,dir,column; + + // Strict-ish type checking + if ( pdispparams->rgvarg[0].vt == VT_BSTR ) + max = _wtoi(pdispparams->rgvarg[0].bstrVal); + else + max = pdispparams->rgvarg[0].uiVal; + + if ( pdispparams->rgvarg[1].vt == VT_BSTR ) + dir = _wtoi(pdispparams->rgvarg[2].bstrVal); + else + dir = pdispparams->rgvarg[1].uiVal; + + if ( pdispparams->rgvarg[2].vt == VT_BSTR ) + column = _wtoi(pdispparams->rgvarg[2].bstrVal); + else + column = pdispparams->rgvarg[2].uiVal; + + // run query + EnterCriticalSection(&g_db_cs); + nde_scanner_t s=NDE_Table_CreateScanner(g_table); + NDE_Scanner_Query(s, pdispparams->rgvarg[3].bstrVal); + +// create itemRecordList (necessary because NDE doesn't sort) + itemRecordListW obj; + obj.Alloc = 0; + obj.Items = NULL; + obj.Size = 0; + saveQueryToList(s, &obj, column, dir); + NDE_Table_DestroyScanner(g_table, s); + LeaveCriticalSection(&g_db_cs); + + // write to a temporary XML file + wchar_t tempPath[MAX_PATH] = {0}; + GetTempPathW(MAX_PATH, tempPath); + wchar_t tempFile[MAX_PATH] = {0}; + GetTempFileNameW(tempPath, L"lmx", 0, tempFile); + SaveListToXML(&obj, tempFile, max); + freeRecordList(&obj); + + // open the resultant file to read into a buffer + // (we're basically using the filesystem as an automatically growing buffer) + HANDLE plFile = CreateFileW(tempFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + size_t flen = SetFilePointer(plFile, 0, NULL, FILE_END); + SetFilePointer(plFile, 0, NULL, FILE_BEGIN); + + SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, flen); + void *data; + SafeArrayAccessData(bufferArray, &data); + DWORD bytesRead = 0; + ReadFile(plFile, data, flen, &bytesRead, 0); + SafeArrayUnaccessData(bufferArray); + CloseHandle(plFile); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_ARRAY|VT_UI1; + V_ARRAY(pvarResult) = bufferArray; + DeleteFileW(tempFile); + } + return S_OK; + } + return DISP_E_MEMBERNOTFOUND; +} + + +STDMETHODIMP LocalMediaCOM::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (!ppvObject) + return E_POINTER; + + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = (IDispatch *)this; + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = this; + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +ULONG LocalMediaCOM::AddRef(void) +{ + return 0; +} + + +ULONG LocalMediaCOM::Release(void) +{ + return 0; +} |