123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- #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;
- }
|