ExtendedInfo.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #include "main.h"
  2. #include "api.h"
  3. #include "../nu/AutoWide.h"
  4. #include "../nu/AutoWideFn.h"
  5. #include "../nu/AutoChar.h"
  6. #include "../nu/AutoCharFn.h"
  7. #include "../nu/AutoLock.h"
  8. #include "../nu/ns_wc.h"
  9. #include <malloc.h>
  10. using namespace Nullsoft::Utility;
  11. /* Get Extended File Info */
  12. typedef int (__cdecl *GetANSIInfo)(const char *fn, const char *data, char *dest, size_t destlen);
  13. typedef int (__cdecl *GetUnicodeInfo)(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen);
  14. int ConvertGetExtendedFileInfo(GetUnicodeInfo getter, const char *fn, const char *data, char *dest, size_t destlen)
  15. {
  16. wchar_t *destW = 0;
  17. if (dest && destlen)
  18. {
  19. destW = (wchar_t *)_malloca(destlen * sizeof(wchar_t));
  20. memset(destW, 0, destlen * sizeof(wchar_t));
  21. }
  22. int retVal = getter(AutoWideFn(fn), data, destW, destlen);
  23. if (retVal && dest && destlen)
  24. WideCharToMultiByteSZ(CP_ACP, 0, destW, -1, dest, (int)destlen, 0, 0);
  25. if (destW) _freea(destW);
  26. return retVal;
  27. }
  28. int ConvertGetExtendedFileInfo(GetANSIInfo getter, const char *fn, const char *data, wchar_t *dest, size_t destlen)
  29. {
  30. char *destA = 0;
  31. if (dest && destlen)
  32. {
  33. destA = (char *)_malloca(destlen * sizeof(char));
  34. memset(destA, 0, destlen * sizeof(char));
  35. }
  36. int retVal = getter(fn, data, destA, destlen);
  37. if (retVal && dest && destlen)
  38. MultiByteToWideCharSZ(CP_ACP, 0, destA, -1, dest, (int)destlen);
  39. if (destA) _freea(destA);
  40. return retVal;
  41. }
  42. static GetANSIInfo gefi;
  43. static GetUnicodeInfo gefiW;
  44. static char cachedExt[16];
  45. LockGuard getMetadataGuard;
  46. int in_get_extended_fileinfo(const char *fn, const char *metadata, char *dest, size_t destlen)
  47. {
  48. AutoLock lock(getMetadataGuard);
  49. In_Module *i=0;
  50. char ext[16] = {0};
  51. int a = 0;
  52. // do some extra checks on the params as quite a few clients crash when accessing here
  53. try {
  54. if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
  55. fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
  56. metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
  57. return 0;
  58. } catch (...) {
  59. return 0;
  60. }
  61. if (dest)
  62. memset(dest, 0, destlen);
  63. extension_ex(fn, ext, sizeof(ext));
  64. if (!_stricmp(cachedExt, ext) && *ext)
  65. {
  66. if (gefi)
  67. return gefi(fn, metadata, dest, destlen);
  68. else if (gefiW) // should always be true if we got this far
  69. return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
  70. else
  71. return 0;
  72. }
  73. while (a >= 0)
  74. {
  75. i = in_setmod_noplay(AutoWideFn(fn), &a);
  76. if (!i)
  77. break;
  78. if (a >= 0) a++;
  79. lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
  80. gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
  81. gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
  82. if (gefi || gefiW)
  83. break;
  84. }
  85. // if no one claimed it, then check if it's the currently playing track
  86. // benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
  87. if (!i && !lstrcmpiW(FileName, AutoWide(fn)))
  88. {
  89. i=in_mod;
  90. if (i)
  91. {
  92. cachedExt[0]=0;
  93. gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
  94. gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
  95. }
  96. }
  97. if (!i)
  98. return 0;
  99. if (gefi)
  100. return gefi(fn, metadata, dest, destlen);
  101. else if (gefiW)
  102. return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
  103. else
  104. return 0;
  105. }
  106. int in_get_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *dest, size_t destlen)
  107. {
  108. AutoLock lock(getMetadataGuard);
  109. In_Module *i=0;
  110. char ext[16] = {0};
  111. int a = 0;
  112. // do some extra checks on the params as quite a few clients crash when accessing here
  113. try {
  114. if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
  115. fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
  116. metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
  117. return 0;
  118. } catch (...) {
  119. return 0;
  120. }
  121. if (dest)
  122. memset(dest, 0, destlen);
  123. AutoCharFn charFn(fn);
  124. extension_ex(charFn, ext, sizeof(ext));
  125. if (!_stricmp(cachedExt, ext) && *ext)
  126. {
  127. if (gefiW) // should always be true if we got this far
  128. return gefiW(fn, AutoChar(metadata), dest, destlen);
  129. if (gefi)
  130. return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
  131. else
  132. return 0;
  133. }
  134. while (a >= 0)
  135. {
  136. i = in_setmod_noplay(fn, &a);
  137. if (!i)
  138. break;
  139. if (a >= 0) a++;
  140. lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
  141. gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
  142. gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
  143. if (gefi || gefiW)
  144. break;
  145. }
  146. // if no one claimed it, then check if it's the currently playing track
  147. // benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
  148. if (!i && !lstrcmpiW(FileName, fn)) // currently playing file?
  149. {
  150. i=in_mod;
  151. if (i)
  152. {
  153. cachedExt[0]=0;
  154. gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
  155. gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
  156. }
  157. }
  158. if (!i)
  159. return 0;
  160. if (gefiW)
  161. return gefiW(fn, AutoChar(metadata), dest, destlen);
  162. else if (gefi)
  163. return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
  164. else
  165. return 0;
  166. }
  167. /* Set Extended File Info */
  168. typedef int (__cdecl *SetANSIInfo)(const char *fn, const char *metadata, const char *data);
  169. typedef int (__cdecl *SetUnicodeInfo)(const wchar_t *fn, const char *metadata, const wchar_t *data);
  170. static SetANSIInfo sefi;
  171. static SetUnicodeInfo sefiW;
  172. static int (*wefi)();
  173. static char cachedExtSet[16];
  174. static int ConvertSetExtendedFileInfo(SetUnicodeInfo setter, const char *fn, const char *metadata, const char *data)
  175. {
  176. return setter(AutoWide(fn), metadata, AutoWide(data));
  177. }
  178. static int ConvertSetExtendedFileInfo(SetANSIInfo setter, const char *fn, const char *metadata, const wchar_t *data)
  179. {
  180. return setter(fn, metadata, AutoChar(data));
  181. }
  182. int in_set_extended_fileinfo(const char *fn, const char *metadata, char *data)
  183. {
  184. AutoLock lock(getMetadataGuard);
  185. char ext[16] = {0};
  186. int a = 0;
  187. extension_ex(fn, ext, sizeof(ext));
  188. if (!_stricmp(cachedExtSet, ext) && *ext)
  189. {
  190. if (sefi)
  191. return sefi(fn, metadata, data);
  192. else if (sefiW)
  193. return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
  194. else
  195. return 0;
  196. }
  197. while (a >= 0)
  198. {
  199. wefi = NULL;
  200. sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
  201. sefiW = NULL;
  202. In_Module *i = in_setmod_noplay(AutoWideFn(fn), &a);
  203. if (a >= 0) a++;
  204. cachedExtSet[0] = 0;
  205. if (!i) return 0;
  206. lstrcpynA(cachedExtSet, ext, 16);
  207. sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
  208. sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
  209. wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
  210. if (sefi || sefiW) break;
  211. }
  212. if (sefi)
  213. return sefi(fn, metadata, data);
  214. else if (sefiW)
  215. return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
  216. else
  217. return 0;
  218. }
  219. int in_set_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *data)
  220. {
  221. AutoLock lock(getMetadataGuard);
  222. char ext[16] = {0};
  223. int a = 0;
  224. AutoCharFn charFn(fn);
  225. extension_ex(charFn, ext, sizeof(ext));
  226. if (!_stricmp(cachedExtSet, ext) && *ext)
  227. {
  228. if (sefiW)
  229. return sefiW(fn, AutoChar(metadata), data);
  230. else if (sefi)
  231. return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
  232. else
  233. return 0;
  234. }
  235. while (a >= 0)
  236. {
  237. wefi = NULL;
  238. sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
  239. sefiW = NULL;
  240. In_Module *i = in_setmod_noplay(fn, &a);
  241. if (a >= 0) a++;
  242. cachedExtSet[0] = 0;
  243. if (!i) return 0;
  244. lstrcpynA(cachedExtSet, ext, 16);
  245. sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
  246. sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
  247. wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
  248. if (sefi || sefiW) break;
  249. }
  250. if (sefiW)
  251. return sefiW(fn, AutoChar(metadata), data);
  252. else if (sefi)
  253. return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
  254. else
  255. return 0;
  256. }
  257. int in_write_extended_fileinfo()
  258. {
  259. AutoLock lock(getMetadataGuard);
  260. if (!wefi)
  261. return 0;
  262. return
  263. wefi();
  264. }
  265. inline void COPY_METADATA(const wchar_t *src, const wchar_t *dest, const wchar_t *item, wchar_t *buf, size_t buflen)
  266. {
  267. if (NULL != src && NULL != item && NULL != buf)
  268. {
  269. buf[0]=0;
  270. extendedFileInfoStructW efis=
  271. {
  272. src,
  273. item,
  274. buf,
  275. buflen,
  276. };
  277. if (SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)&efis,IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
  278. in_set_extended_fileinfoW(dest, item, buf);
  279. }
  280. }
  281. //#define COPY_METADATA(src, dest, item, buf, buflen) { buf[0]=0; if (in_get_extended_fileinfoW(src, item, buf, buflen)) in_set_extended_fileinfoW(dest, item, buf); }
  282. void CopyExtendedFileInfo(const wchar_t *source, const wchar_t *destination)
  283. {
  284. wchar_t bigData[32768] = {0}; // hopefully big enough for all reasonable metadata
  285. COPY_METADATA(source, destination, L"title", bigData, 32768);
  286. COPY_METADATA(source, destination, L"artist", bigData, 32768);
  287. COPY_METADATA(source, destination, L"albumartist", bigData, 32768);
  288. COPY_METADATA(source, destination, L"album", bigData, 32768);
  289. COPY_METADATA(source, destination, L"genre", bigData, 32768);
  290. COPY_METADATA(source, destination, L"year", bigData, 32768);
  291. COPY_METADATA(source, destination, L"disc", bigData, 32768);
  292. COPY_METADATA(source, destination, L"publisher", bigData, 32768);
  293. COPY_METADATA(source, destination, L"comment", bigData, 32768);
  294. COPY_METADATA(source, destination, L"track", bigData, 32768);
  295. COPY_METADATA(source, destination, L"tool", bigData, 32768);
  296. COPY_METADATA(source, destination, L"composer", bigData, 32768);
  297. COPY_METADATA(source, destination, L"conductor", bigData, 32768);
  298. COPY_METADATA(source, destination, L"bpm", bigData, 32768);
  299. COPY_METADATA(source, destination, L"GracenoteFileID", bigData, 32768);
  300. COPY_METADATA(source, destination, L"GracenoteExtData", bigData, 32768);
  301. in_write_extended_fileinfo();
  302. //albumArt->CopyAlbumArt(source, destination);
  303. }