LocalMediaCOM.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #include "main.h"
  2. #include "LocalMediaCOM.h"
  3. void sortResults(int column, int dir, itemRecordListW *obj);
  4. static void saveQueryToList(nde_scanner_t s, itemRecordListW *obj, int sortColumn, int sortDir)
  5. {
  6. emptyRecordList(obj);
  7. EnterCriticalSection(&g_db_cs);
  8. NDE_Scanner_First(s);
  9. int r;
  10. do
  11. {
  12. nde_field_t f = NDE_Scanner_GetFieldByID(s, MAINTABLE_ID_FILENAME);
  13. if (f)
  14. {
  15. allocRecordList(obj, obj->Size + 1);
  16. if (!obj->Alloc) break;
  17. obj->Items[obj->Size].filename = NDE_StringField_GetString(f);
  18. ndestring_retain(obj->Items[obj->Size].filename);
  19. ScannerRefToObjCacheNFNW(s, obj, true);
  20. }
  21. r = NDE_Scanner_Next(s);
  22. }
  23. while (r && !NDE_Scanner_EOF(s));
  24. if (((Table *)g_table)->HasErrors()) // TODO: don't use C++ NDE API
  25. {
  26. wchar_t *last_query = NULL;
  27. if (m_media_scanner)
  28. {
  29. const wchar_t *lq = NDE_Scanner_GetLastQuery(m_media_scanner);
  30. if (lq) last_query = _wcsdup(lq);
  31. NDE_Table_DestroyScanner(g_table, m_media_scanner);
  32. }
  33. NDE_Table_Compact(g_table);
  34. if (m_media_scanner)
  35. {
  36. m_media_scanner = NDE_Table_CreateScanner(g_table);
  37. if (last_query != NULL)
  38. {
  39. NDE_Scanner_Query(m_media_scanner, last_query);
  40. free(last_query);
  41. }
  42. }
  43. }
  44. LeaveCriticalSection(&g_db_cs);
  45. compactRecordList(obj);
  46. sortResults(sortColumn, sortDir, obj);
  47. }
  48. void WriteEscaped(FILE *fp, const wchar_t *str)
  49. {
  50. // TODO: for speed optimization,
  51. // we should wait until we hit a special character
  52. // and write out everything else so before it,
  53. // like how ASX loader does it
  54. while (str && *str)
  55. {
  56. switch(*str)
  57. {
  58. case L'&':
  59. fputws(L"&", fp);
  60. break;
  61. case L'>':
  62. fputws(L">", fp);
  63. break;
  64. case L'<':
  65. fputws(L"&lt;", fp);
  66. break;
  67. case L'\'':
  68. fputws(L"&apos;", fp);
  69. break;
  70. case L'\"':
  71. fputws(L"&quot;", fp);
  72. break;
  73. default:
  74. fputwc(*str, fp);
  75. break;
  76. }
  77. // write out the whole character
  78. wchar_t *next = CharNextW(str);
  79. while (++str != next)
  80. fputwc(*str, fp);
  81. }
  82. }
  83. bool SaveListToXML(const itemRecordListW *const obj, const wchar_t *filename, int limit)
  84. {
  85. int i=0;
  86. FILE *fp = _wfopen(filename, L"wb");
  87. if (!fp)
  88. return false;
  89. wchar_t BOM = 0xFEFF;
  90. fwrite(&BOM, sizeof(BOM), 1, fp);
  91. fwprintf(fp, L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>");
  92. fputws(L"<itemlist>\r\n", fp);
  93. while (i < obj->Size)
  94. {
  95. fputws(L"<item ", fp);
  96. if (obj->Items[i].filename)
  97. {
  98. fputws(L"filename=\"", fp);
  99. WriteEscaped(fp, obj->Items[i].filename);
  100. fputws(L"\" ", fp);
  101. }
  102. if (obj->Items[i].title)
  103. {
  104. fputws(L"title=\"", fp);
  105. WriteEscaped(fp, obj->Items[i].title);
  106. fputws(L"\" ", fp);
  107. }
  108. if (obj->Items[i].album)
  109. {
  110. fputws(L"album=\"", fp);
  111. WriteEscaped(fp, obj->Items[i].album);
  112. fputws(L"\" ", fp);
  113. }
  114. if (obj->Items[i].artist)
  115. {
  116. fputws(L"artist=\"", fp);
  117. WriteEscaped(fp, obj->Items[i].artist);
  118. fputws(L"\" ", fp);
  119. }
  120. if (obj->Items[i].comment)
  121. {
  122. fputws(L"comment=\"", fp);
  123. WriteEscaped(fp, obj->Items[i].comment);
  124. fputws(L"\" ", fp);
  125. }
  126. if (obj->Items[i].genre)
  127. {
  128. fputws(L"genre=\"", fp);
  129. WriteEscaped(fp, obj->Items[i].genre);
  130. fputws(L"\" ", fp);
  131. }
  132. if (obj->Items[i].year > 0)
  133. fwprintf(fp, L"year=\"%d\" ",obj->Items[i].year);
  134. if (obj->Items[i].track > 0)
  135. fwprintf(fp, L"track=\"%d\" ",obj->Items[i].track);
  136. if (obj->Items[i].length > 0)
  137. fwprintf(fp, L"length=\"%d\" ",obj->Items[i].length);
  138. // TODO: extended info fields
  139. fputws(L"/>", fp);
  140. if (++i == limit)
  141. break;
  142. }
  143. fputws(L"</itemlist>", fp);
  144. fclose(fp);
  145. return true;
  146. }
  147. enum
  148. {
  149. DISP_LOCALMEDIA_XMLQUERY = 777,
  150. };
  151. #define CHECK_ID(str, id) if (_wcsicmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; }
  152. HRESULT LocalMediaCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  153. {
  154. bool unknowns = false;
  155. for (unsigned int i = 0;i != cNames;i++)
  156. {
  157. CHECK_ID("XMLQuery", DISP_LOCALMEDIA_XMLQUERY)
  158. rgdispid[i] = DISPID_UNKNOWN;
  159. unknowns = true;
  160. }
  161. if (unknowns)
  162. return DISP_E_UNKNOWNNAME;
  163. else
  164. return S_OK;
  165. }
  166. HRESULT LocalMediaCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  167. {
  168. return E_NOTIMPL;
  169. }
  170. HRESULT LocalMediaCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
  171. {
  172. return E_NOTIMPL;
  173. }
  174. void Bookmark_WriteAsXML(const wchar_t *filename, int max);
  175. HRESULT LocalMediaCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  176. {
  177. switch (dispid)
  178. {
  179. case DISP_LOCALMEDIA_XMLQUERY:
  180. if (pdispparams->cArgs == 4)
  181. {
  182. openDb();
  183. int max,dir,column;
  184. // Strict-ish type checking
  185. if ( pdispparams->rgvarg[0].vt == VT_BSTR )
  186. max = _wtoi(pdispparams->rgvarg[0].bstrVal);
  187. else
  188. max = pdispparams->rgvarg[0].uiVal;
  189. if ( pdispparams->rgvarg[1].vt == VT_BSTR )
  190. dir = _wtoi(pdispparams->rgvarg[2].bstrVal);
  191. else
  192. dir = pdispparams->rgvarg[1].uiVal;
  193. if ( pdispparams->rgvarg[2].vt == VT_BSTR )
  194. column = _wtoi(pdispparams->rgvarg[2].bstrVal);
  195. else
  196. column = pdispparams->rgvarg[2].uiVal;
  197. // run query
  198. EnterCriticalSection(&g_db_cs);
  199. nde_scanner_t s=NDE_Table_CreateScanner(g_table);
  200. NDE_Scanner_Query(s, pdispparams->rgvarg[3].bstrVal);
  201. // create itemRecordList (necessary because NDE doesn't sort)
  202. itemRecordListW obj;
  203. obj.Alloc = 0;
  204. obj.Items = NULL;
  205. obj.Size = 0;
  206. saveQueryToList(s, &obj, column, dir);
  207. NDE_Table_DestroyScanner(g_table, s);
  208. LeaveCriticalSection(&g_db_cs);
  209. // write to a temporary XML file
  210. wchar_t tempPath[MAX_PATH] = {0};
  211. GetTempPathW(MAX_PATH, tempPath);
  212. wchar_t tempFile[MAX_PATH] = {0};
  213. GetTempFileNameW(tempPath, L"lmx", 0, tempFile);
  214. SaveListToXML(&obj, tempFile, max);
  215. freeRecordList(&obj);
  216. // open the resultant file to read into a buffer
  217. // (we're basically using the filesystem as an automatically growing buffer)
  218. HANDLE plFile = CreateFileW(tempFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  219. size_t flen = SetFilePointer(plFile, 0, NULL, FILE_END);
  220. SetFilePointer(plFile, 0, NULL, FILE_BEGIN);
  221. SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, flen);
  222. void *data;
  223. SafeArrayAccessData(bufferArray, &data);
  224. DWORD bytesRead = 0;
  225. ReadFile(plFile, data, flen, &bytesRead, 0);
  226. SafeArrayUnaccessData(bufferArray);
  227. CloseHandle(plFile);
  228. VariantInit(pvarResult);
  229. V_VT(pvarResult) = VT_ARRAY|VT_UI1;
  230. V_ARRAY(pvarResult) = bufferArray;
  231. DeleteFileW(tempFile);
  232. }
  233. return S_OK;
  234. }
  235. return DISP_E_MEMBERNOTFOUND;
  236. }
  237. STDMETHODIMP LocalMediaCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
  238. {
  239. if (!ppvObject)
  240. return E_POINTER;
  241. else if (IsEqualIID(riid, IID_IDispatch))
  242. *ppvObject = (IDispatch *)this;
  243. else if (IsEqualIID(riid, IID_IUnknown))
  244. *ppvObject = this;
  245. else
  246. {
  247. *ppvObject = NULL;
  248. return E_NOINTERFACE;
  249. }
  250. AddRef();
  251. return S_OK;
  252. }
  253. ULONG LocalMediaCOM::AddRef(void)
  254. {
  255. return 0;
  256. }
  257. ULONG LocalMediaCOM::Release(void)
  258. {
  259. return 0;
  260. }