ToISO.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include "main.h"
  2. #include "api__ml_iso.h"
  3. #include <api/service/waservicefactory.h>
  4. #include "../burner/obj_isocreator.h"
  5. #include "../playlist/ifc_playlistloadercallback.h"
  6. #include <shlwapi.h>
  7. #include <strsafe.h>
  8. /**
  9. ** Playlist Loader callback class
  10. ** Used when this plugin loads a playlist file
  11. ** the playlist loader will call the OnFile() function
  12. ** for each playlist item
  13. */
  14. class ISOPlaylistLoader : public ifc_playlistloadercallback
  15. {
  16. public:
  17. ISOPlaylistLoader(obj_isocreator *_creator);
  18. protected:
  19. RECVS_DISPATCH;
  20. private:
  21. void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
  22. obj_isocreator *creator;
  23. };
  24. /**
  25. ** helper function
  26. ** for getting a filename location
  27. ** of where to save the ISO file
  28. **/
  29. static bool PromptForFilename(wchar_t *filename, size_t filenameCch)
  30. {
  31. wchar_t oldCurPath[MAX_PATH], newCurPath[MAX_PATH];
  32. OPENFILENAMEW openfilename;
  33. // null terminate the string or else we'll get a garbage filename as the 'default' filename
  34. filename[0]=0;
  35. // GetSaveFileName changes Window's working directory
  36. // which locks that folder from being deleted until Winamp closes
  37. // so we save the old working directory name
  38. // and restore it on complete
  39. // Winamp maintains its own concept of a working directory
  40. // to help us avoid this problem
  41. GetCurrentDirectoryW(MAX_PATH, oldCurPath);
  42. // initialize the open file name struct
  43. openfilename.lStructSize = sizeof(openfilename);
  44. openfilename.hwndOwner = plugin.hwndLibraryParent;
  45. openfilename.hInstance = plugin.hDllInstance;
  46. openfilename.lpstrFilter = L"ISO Files\0*.iso\0";
  47. openfilename.lpstrCustomFilter = 0;
  48. openfilename.nMaxCustFilter = 0;
  49. openfilename.nFilterIndex = 0;
  50. openfilename.lpstrFile = filename;
  51. openfilename.nMaxFile = filenameCch;
  52. openfilename.lpstrFileTitle = 0;
  53. openfilename.nMaxFileTitle = 0;
  54. // we set the initial directory based on winamp's working path
  55. openfilename.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
  56. openfilename.lpstrTitle = 0;
  57. // despite the big note about working directory
  58. // we don't want to use OFN_NOCHANGEDIR
  59. // because we're going to manually sync Winamp's working path
  60. openfilename.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_LONGNAMES;
  61. openfilename.nFileOffset = 0;
  62. openfilename.nFileExtension = 0;
  63. openfilename.lpstrDefExt = L".iso";
  64. openfilename.lCustData = 0;
  65. openfilename.lpfnHook = 0;
  66. openfilename.lpTemplateName = 0;
  67. if (GetSaveFileNameW(&openfilename))
  68. {
  69. // let's re-synch Winamp's working directory
  70. GetCurrentDirectoryW(MAX_PATH, newCurPath);
  71. WASABI_API_APP->path_setWorkingPath(newCurPath);
  72. // set the old path back
  73. SetCurrentDirectoryW(oldCurPath);
  74. return true; // success!
  75. }
  76. else
  77. {
  78. // set the old path back
  79. SetCurrentDirectoryW(oldCurPath);
  80. return false; // user hit cancel or something else happened
  81. }
  82. }
  83. /**
  84. ** helper functions
  85. ** for creating and deleting
  86. ** an iso creator object
  87. ** through the wasabi service manager
  88. **/
  89. static obj_isocreator *CreateISOCreator()
  90. {
  91. waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(obj_isocreatorGUID);
  92. if (factory)
  93. return (obj_isocreator *)factory->getInterface();
  94. else
  95. return 0;
  96. }
  97. static void ReleaseISOCreator(obj_isocreator *creator)
  98. {
  99. if (creator)
  100. {
  101. waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(obj_isocreatorGUID);
  102. if (factory)
  103. factory->releaseInterface(creator);
  104. }
  105. }
  106. void ConvertItemRecordListToISO(const itemRecordList *list)
  107. {
  108. obj_isocreator *isocreator = CreateISOCreator();
  109. if (isocreator)
  110. {
  111. wchar_t destination[MAX_PATH];
  112. if (PromptForFilename(destination, MAX_PATH))
  113. {
  114. // these values are hardcoded for this example.
  115. isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
  116. char destinationPath[MAX_PATH];
  117. // loop through the files and add them
  118. for (int i=0;i<list->Size;i++)
  119. {
  120. itemRecord &item = list->Items[i];
  121. // since we have metadata, we're going to auto-generate folders based on the album name
  122. const char *album = item.album;
  123. if (!album || !*album)
  124. album = "Unknown Album";
  125. // isocreator requires a preceding backslash
  126. StringCbPrintfA(destinationPath, sizeof(destinationPath), "\\%s\\%s", album, PathFindFileNameA(item.filename));
  127. // convert to unicode since that's what obj_isocreator requires
  128. wchar_t unicodeSource[MAX_PATH];
  129. wchar_t unicodeDest[MAX_PATH];
  130. MultiByteToWideChar(CP_ACP, 0, item.filename, -1, unicodeSource, MAX_PATH);
  131. MultiByteToWideChar(CP_ACP, 0, destinationPath, -1, unicodeDest, MAX_PATH);
  132. isocreator->AddFile(unicodeSource, unicodeDest);
  133. }
  134. isocreator->Write(destination, 0);
  135. }
  136. ReleaseISOCreator(isocreator);
  137. }
  138. }
  139. void ConvertFilenamesToISO(const char *filenames)
  140. {
  141. obj_isocreator *isocreator = CreateISOCreator();
  142. if (isocreator)
  143. {
  144. wchar_t destination[MAX_PATH];
  145. if (PromptForFilename(destination, MAX_PATH))
  146. {
  147. // these values are hardcoded for this example.
  148. isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
  149. wchar_t destinationPath[MAX_PATH];
  150. // loop through the files and add them
  151. while (*filenames)
  152. {
  153. /**
  154. ** both playlist loader and iso creator want unicode filenames
  155. ** so we'll convert it first
  156. */
  157. wchar_t unicodeFilename[MAX_PATH];
  158. MultiByteToWideChar(CP_ACP, 0, filenames, -1, unicodeFilename, MAX_PATH);
  159. /**
  160. ** see if this file is a playlist file
  161. ** we'll do that by trying to load it
  162. ** the Load() function will fail gracefully if it's not a playlist file
  163. ** if it succeeds, it will call loader.OnFile() which adds it to the iso file
  164. **/
  165. ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
  166. if (AGAVE_API_PLAYLISTMANAGER->Load(unicodeFilename, &loader) == PLAYLISTMANAGER_LOAD_NO_LOADER)
  167. {
  168. // not a playlist file, so load it normally
  169. // isocreator requires a preceding backslash
  170. StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s", PathFindFileNameW(unicodeFilename));
  171. isocreator->AddFile(unicodeFilename, destinationPath);
  172. }
  173. filenames+=strlen(filenames)+1;
  174. }
  175. isocreator->Write(destination, 0);
  176. }
  177. ReleaseISOCreator(isocreator);
  178. }
  179. }
  180. /**
  181. ** Load Playlist and write it to the ISO file
  182. ** this function is a bit complex, since we have to load the playlist
  183. ** through api_playlistmanager. This involves creating an playlist loader callback
  184. ** (ifc_playlistloadercallback) which gets called for each playlist item
  185. **/
  186. void ConvertPlaylistToISO(const mlPlaylist *playlist)
  187. {
  188. obj_isocreator *isocreator = CreateISOCreator();
  189. if (isocreator)
  190. {
  191. wchar_t destination[MAX_PATH];
  192. if (PromptForFilename(destination, MAX_PATH))
  193. {
  194. // these values are hardcoded for this example.
  195. const wchar_t *title=L"WinampISO";
  196. if (playlist->title) // if there's a playlist title, use it as the volume name
  197. title = playlist->title;
  198. isocreator->Open(title, obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
  199. ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
  200. AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
  201. isocreator->Write(destination, 0);
  202. }
  203. ReleaseISOCreator(isocreator);
  204. }
  205. }
  206. /** Load all playlists and write them to the ISO file
  207. ** this function is a bit complex, since we have to load the playlist
  208. ** through api_playlistmanager. This involves creating an playlist loader callback
  209. ** (ifc_playlistloadercallback) which gets called for each playlist item
  210. **/
  211. void ConvertPlaylistsToISO(const mlPlaylist **playlists)
  212. {
  213. obj_isocreator *isocreator = CreateISOCreator();
  214. if (isocreator)
  215. {
  216. wchar_t destination[MAX_PATH];
  217. if (PromptForFilename(destination, MAX_PATH))
  218. {
  219. // these values are hardcoded for this example.
  220. isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
  221. while (*playlists)
  222. {
  223. const mlPlaylist *playlist = *playlists;
  224. ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
  225. AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
  226. playlists++;
  227. }
  228. isocreator->Write(destination, 0);
  229. }
  230. ReleaseISOCreator(isocreator);
  231. }
  232. }
  233. void ConvertUnicodeItemRecordListToISO(const itemRecordListW *list)
  234. {
  235. obj_isocreator *isocreator = CreateISOCreator();
  236. if (isocreator)
  237. {
  238. wchar_t destination[MAX_PATH];
  239. if (PromptForFilename(destination, MAX_PATH))
  240. {
  241. // these values are hardcoded for this example.
  242. isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
  243. wchar_t destinationPath[MAX_PATH];
  244. // loop through the files and add them
  245. for (int i=0;i<list->Size;i++)
  246. {
  247. itemRecordW &item = list->Items[i];
  248. // since we have metadata, we're going to auto-generate folders based on the album name
  249. const wchar_t *album = item.album;
  250. if (!album || !*album)
  251. album = L"Unknown Album";
  252. // isocreator requires a preceding backslash
  253. StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s\\%s", album, PathFindFileNameW(item.filename));
  254. isocreator->AddFile(item.filename, destinationPath);
  255. }
  256. isocreator->Write(destination, 0);
  257. }
  258. ReleaseISOCreator(isocreator);
  259. }
  260. }
  261. void ConvertUnicodeFilenamesToISO(const wchar_t *filenames)
  262. {
  263. obj_isocreator *isocreator = CreateISOCreator();
  264. if (isocreator)
  265. {
  266. wchar_t destination[MAX_PATH];
  267. if (PromptForFilename(destination, MAX_PATH))
  268. {
  269. // these values are hardcoded for this example.
  270. isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
  271. wchar_t destinationPath[MAX_PATH];
  272. // loop through the files and add them
  273. while (*filenames)
  274. {
  275. /**
  276. ** see if this file is a playlist file
  277. ** we'll do that by trying to load it
  278. ** the Load() function will fail gracefully if it's not a playlist file
  279. ** if it succeeds, it will call loader.OnFile() which adds it to the iso file
  280. **/
  281. ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
  282. if (AGAVE_API_PLAYLISTMANAGER->Load(filenames, &loader) == PLAYLISTMANAGER_LOAD_NO_LOADER)
  283. {
  284. // not a playlist file, so load it normally
  285. // isocreator requires a preceding backslash
  286. StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s", PathFindFileNameW(filenames));
  287. isocreator->AddFile(filenames, destinationPath);
  288. }
  289. filenames+=wcslen(filenames)+1;
  290. }
  291. isocreator->Write(destination, 0);
  292. }
  293. ReleaseISOCreator(isocreator);
  294. }
  295. }
  296. /* --- Playlist Loader definition --- */
  297. ISOPlaylistLoader::ISOPlaylistLoader(obj_isocreator *_creator)
  298. {
  299. creator=_creator;
  300. }
  301. void ISOPlaylistLoader::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info)
  302. {
  303. // isocreator requires a preceding backslash
  304. wchar_t destinationPath[MAX_PATH];
  305. StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s", PathFindFileNameW(filename));
  306. // add file to .iso image
  307. creator->AddFile(filename, destinationPath);
  308. }
  309. #define CBCLASS ISOPlaylistLoader
  310. START_DISPATCH;
  311. VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
  312. //VCB(IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO, OnPlaylistInfo)
  313. END_DISPATCH;