1
0

info.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. #include "main.h"
  2. #include "resource.h"
  3. #include <shlwapi.h>
  4. #include <commdlg.h>
  5. #include <strsafe.h>
  6. #include "../nu/AutoWide.h"
  7. #include "../nu/AutoCharFn.h"
  8. #include "CompressionUtility.h"
  9. extern In_Module mod;
  10. extern "C"
  11. {
  12. #include "genres.h"
  13. }
  14. #define HAVE_BMPVIEW
  15. #ifdef HAVE_BMPVIEW
  16. static LRESULT CALLBACK BmpViewProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
  17. {
  18. switch (msg)
  19. {
  20. case WM_PAINT:
  21. {
  22. RECT r;
  23. GetClientRect(wnd, &r);
  24. HDC wdc = GetDC(wnd);
  25. HDC dc = (HDC)GetWindowLongPtr(wnd, 4);
  26. DrawEdge(wdc, &r, EDGE_SUNKEN, BF_RECT);
  27. if (dc) BitBlt(wdc, 2, 2, r.right - 4, r.bottom - 4, dc, 0, 0, SRCCOPY);
  28. ReleaseDC(wnd, wdc);
  29. ValidateRect(wnd, 0);
  30. return 0;
  31. }
  32. break;
  33. case WM_USER:
  34. {
  35. HDC dc = CreateCompatibleDC(0);
  36. SelectObject(dc, (HBITMAP)lp);
  37. SetWindowLongPtr(wnd, 0, lp);
  38. SetWindowLongPtr(wnd, 4, (LONG_PTR)dc);
  39. //RedrawWindow(wnd,0,0,RDW_INVALIDATE);
  40. }
  41. return 0;
  42. case WM_DESTROY:
  43. {
  44. HBITMAP bmp = (HBITMAP)GetWindowLongPtr(wnd, 0);
  45. HDC dc = (HDC)GetWindowLongPtr(wnd, 4);
  46. if (dc) DeleteDC(dc);
  47. if (bmp) DeleteObject(bmp);
  48. }
  49. break;
  50. }
  51. return DefWindowProc(wnd, msg, wp, lp);
  52. }
  53. void bmpview_init()
  54. {
  55. static bool got_class;
  56. if (!got_class)
  57. {
  58. got_class = 1;
  59. WNDCLASS wc =
  60. {
  61. 0,
  62. BmpViewProc,
  63. 0, 8,
  64. MIDI_callback::GetInstance(), 0, LoadCursor(0, IDC_ARROW), 0,
  65. 0,
  66. L"BitmapView"
  67. };
  68. RegisterClassW(&wc);
  69. }
  70. }
  71. #endif
  72. BOOL SaveFile(HWND w, MIDI_file* mf, BOOL info);
  73. int SaveAsGZip(string filename, const void* buffer, size_t size);
  74. UINT align(UINT x, UINT a)
  75. {
  76. a--;
  77. return (x + a) & ~a;
  78. }
  79. typedef struct
  80. {
  81. UINT ctrl_id;
  82. DWORD riff_id;
  83. // char * name;
  84. }
  85. RMI_TAG;
  86. static void _swap_ptrs(void** a, void* b)
  87. {
  88. void* _a = *a;
  89. *a = b;
  90. if (_a) free(_a);
  91. }
  92. #define swap_ptrs(x,y) _swap_ptrs((void**)&x,(void*)(y))
  93. static RMI_TAG rmi_tagz[] =
  94. {
  95. {IDC_DISP, _rv('DISP')},
  96. {IDC_NAME, _rv('INAM')},
  97. {IDC_ARTIST, _rv('IART')},
  98. {IDC_ALBUM, _rv('IALB')},
  99. {IDC_TRACK, _rv('ITRK')},
  100. {IDC_GENRE, _rv('IGNR')},
  101. {IDC_COMPOSER, _rv('ICMP')},
  102. {IDC_COPYRIGHT, _rv('ICOP')},
  103. {IDC_COMMENT, _rv('ICMT')},
  104. {IDC_DATE, _rv('ICRD')},
  105. {IDC_SOFTWARE, _rv('ISFT')},
  106. {IDC_ENGINEER, _rv('IENG')},
  107. {IDC_SUBJECT, _rv('ISBJ')},
  108. };
  109. void SetDlgItemTextSiz(HWND wnd, UINT id, char* text, UINT siz)
  110. {
  111. if (!text[siz - 1]) SetDlgItemTextA(wnd, id, text);
  112. else
  113. {
  114. char* foo = (char*)alloca(siz + 1);
  115. memcpy(foo, text, siz);
  116. foo[siz] = 0;
  117. SetDlgItemTextA(wnd, id, foo);
  118. }
  119. }
  120. #define N_RMI_TAGZ (sizeof(rmi_tagz)/sizeof(rmi_tagz[0]))
  121. static void set_rmi_dlg_title(HWND wnd, MIDI_file* mf)
  122. {
  123. char t[MAX_PATH + 100] = { 0 };
  124. StringCbPrintfA(t, sizeof(t), WASABI_API_LNGSTRING(STRING_RMI_INFO_FMT), (const char*)mf->path);
  125. SetWindowTextA(wnd, t);
  126. }
  127. static BOOL CALLBACK rmiproc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
  128. {
  129. switch (msg)
  130. {
  131. case WM_INITDIALOG:
  132. #if defined(_WIN64)
  133. SetWindowLong(wnd, DWLP_USER, lp);
  134. #else
  135. SetWindowLong(wnd, DWL_USER, lp);
  136. #endif
  137. {
  138. MIDI_file* mf = (MIDI_file*)lp;
  139. set_rmi_dlg_title(wnd, mf);
  140. if (mf->title && *mf->title)
  141. {
  142. SetDlgItemTextA(wnd, IDC_DISP, mf->title);
  143. }
  144. if (mf->rmi_data)
  145. {
  146. BYTE* rmi = (BYTE*)mf->rmi_data;
  147. int p = 4;
  148. while (p < mf->rmi_size)
  149. {
  150. DWORD id = *(DWORD*)(rmi + p);
  151. UINT n;
  152. for (n = 0; n < N_RMI_TAGZ; n++)
  153. {
  154. if (id == rmi_tagz[n].riff_id)
  155. {
  156. SetDlgItemTextSiz(wnd, rmi_tagz[n].ctrl_id, (char*)(rmi + p + 8), *(DWORD*)(rmi + p + 4));
  157. break;
  158. }
  159. }
  160. p += 8 + align(*(DWORD*)(rmi + p + 4), 2);
  161. }
  162. }
  163. #ifdef HAVE_BMPVIEW
  164. if (mf->bmp_data)
  165. {
  166. void* pixels;
  167. BITMAPINFOHEADER* foo = (BITMAPINFOHEADER*)mf->bmp_data;
  168. HBITMAP bmp = CreateDIBSection(0, (BITMAPINFO*)foo, DIB_RGB_COLORS, &pixels, 0, 0);
  169. if (bmp)
  170. {
  171. UINT clr_used = foo->biClrUsed;
  172. if (!clr_used) clr_used = 1 << foo->biBitCount;
  173. BYTE* ptr = (BYTE*)foo + foo->biSize + (clr_used << 2);
  174. int max = (BYTE*)mf->bmp_data + mf->bmp_size - ptr;
  175. BITMAP b;
  176. GetObject(bmp, sizeof(b), &b);
  177. int siz = b.bmWidthBytes * b.bmHeight;
  178. if (siz < 0) siz = -siz;
  179. if (siz > max) siz = max;
  180. memcpy(pixels, ptr, siz);
  181. SendDlgItemMessage(wnd, IDC_BMPVIEW, WM_USER, 0, (long)bmp);
  182. }
  183. }
  184. #endif
  185. }
  186. genres_read(GetDlgItem(wnd, IDC_GENRE));
  187. return 1;
  188. case WM_COMMAND:
  189. switch (wp)
  190. {
  191. case IDOK:
  192. {
  193. #if defined(_WIN64)
  194. MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWLP_USER);
  195. #else
  196. MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWL_USER);
  197. #endif
  198. char* title = 0;
  199. HWND w = GetDlgItem(wnd, IDC_DISP);
  200. UINT sz = GetWindowTextLength(w);
  201. if (sz)
  202. {
  203. sz++;
  204. title = (char*)malloc(sz);
  205. GetWindowTextA(w, title, sz);
  206. }
  207. swap_ptrs(mf->title, title);
  208. BYTE* rmi_info = 0;
  209. UINT rmi_siz = 0;
  210. UINT n;
  211. for (n = 0; n < N_RMI_TAGZ; n++)
  212. {
  213. UINT d = GetWindowTextLength(GetDlgItem(wnd, rmi_tagz[n].ctrl_id));
  214. if (d) rmi_siz += align(d + 1, 2) + 8;
  215. }
  216. if (rmi_siz)
  217. {
  218. rmi_siz += 4; //'INFO'
  219. rmi_info = (BYTE*)malloc(rmi_siz);
  220. UINT ptr = 4;
  221. *(DWORD*)rmi_info = _rv('INFO');
  222. for (n = 0; n < N_RMI_TAGZ; n++)
  223. {
  224. w = GetDlgItem(wnd, rmi_tagz[n].ctrl_id);
  225. if (GetWindowTextLength(w))
  226. {
  227. *(DWORD*)(rmi_info + ptr) = rmi_tagz[n].riff_id;
  228. ptr += 4;
  229. char* foo = (char*)(rmi_info + ptr + 4);
  230. GetWindowTextA(w, foo, rmi_siz - (ptr + 4));
  231. UINT s = strlen(foo) + 1;
  232. *(DWORD*)(rmi_info + ptr) = s;
  233. ptr += 4 + align(s, 2);
  234. }
  235. }
  236. rmi_siz = ptr;
  237. }
  238. mf->rmi_size = rmi_siz;
  239. swap_ptrs(mf->rmi_data, rmi_info);
  240. genres_write(GetDlgItem(wnd, IDC_GENRE));
  241. if (SaveFile(wnd, mf, 1)) EndDialog(wnd, 0);
  242. }
  243. break;
  244. case IDCANCEL:
  245. genres_write(GetDlgItem(wnd, IDC_GENRE));
  246. EndDialog(wnd, 1);
  247. break;
  248. }
  249. break;
  250. }
  251. return 0;
  252. }
  253. int show_rmi_info(HWND w, MIDI_file* mf)
  254. {
  255. #ifdef HAVE_BMPVIEW
  256. bmpview_init();
  257. #endif
  258. return WASABI_API_DIALOGBOXPARAM(IDD_RMI_SHIZ, w, rmiproc, (long)mf);
  259. }
  260. static bool is_local(const char* url)
  261. {
  262. if (!_strnicmp(url, "file://", 7) || !strnicmp(url, "partial://", 10)) return 1;
  263. if (url[1] == ':' && url[2] == '\\') return 1;
  264. return strstr(url, "://") ? 0 : 1;
  265. }
  266. static char* fmt_names[] = { "MIDI", "RIFF MIDI", "HMP", "HMI", "XMIDI", "MUS", "CMF", "GMD", "MIDS", "GMF", "MIDI(?)" };
  267. const char* find_tag(MIDI_file* mf, DWORD id, UINT* siz);
  268. char* getfmtstring(MIDI_file* f, char* s)
  269. {
  270. const char* z = fmt_names[f->format];
  271. while (z && *z) *(s++) = *(z++);
  272. if (f->format <= 1) //MID/RMI
  273. {
  274. char foo[32] = { 0 };
  275. StringCbPrintfA(foo, sizeof(foo), WASABI_API_LNGSTRING(STRING_INFO_FORMAT_FMT), f->data[4 + 4 + 1]);
  276. z = foo;
  277. while (z && *z) *(s++) = *(z++);
  278. }
  279. if (f->info.e_type)
  280. {
  281. *(s++) = ' ';
  282. *(s++) = '(';
  283. z = f->info.e_type;
  284. while (z && *z) *(s++) = *(z++);
  285. *(s++) = ')';
  286. }
  287. *s = 0;
  288. return s;
  289. }
  290. void file2title(const char* f, string& t);
  291. static const char* find_tag(MIDI_file* mf, DWORD id, UINT* siz)
  292. {
  293. if (!mf->rmi_data) return 0;
  294. char* rmi = (char*)mf->rmi_data;
  295. int ptr = 4;
  296. while (ptr < mf->rmi_size)
  297. {
  298. if (*(DWORD*)(rmi + ptr) == id)
  299. {
  300. UINT s = *(DWORD*)(rmi + ptr + 4);
  301. UINT s1 = 0;
  302. ptr += 8;
  303. while (rmi[ptr + s1] && s1 < s) s1++;
  304. if (siz) *siz = s1;
  305. return rmi + ptr;
  306. }
  307. ptr += align(*(DWORD*)(rmi + ptr + 4), 2) + 8;
  308. }
  309. return 0;
  310. }
  311. bool KeywordMatch(const char* mainString, const char* keyword)
  312. {
  313. return !_stricmp(mainString, keyword);
  314. }
  315. static const wchar_t* pExtList[] = { L"MID",L"MIDI",L"RMI",L"KAR",L"HMP",L"HMI",L"XMI",L"MSS",L"MUS",L"CMF",L"GMD",L"MIDS",L"MIZ",L"HMZ" };
  316. static const int pExtDescIdList[] = { 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 0, 8, 9 };
  317. static const int pExtDescList[] =
  318. {
  319. IDS_FAMILY_STRING_MIDI,
  320. IDS_FAMILY_STRING_KARAOKE_MIDI,
  321. IDS_FAMILY_STRING_HMI_MIDI,
  322. IDS_FAMILY_STRING_EXTENDED_MIDI,
  323. IDS_FAMILY_STRING_MSS_MIDI,
  324. IDS_FAMILY_STRING_FINALE_MIDI,
  325. IDS_FAMILY_STRING_CREATIVE_MIDI,
  326. IDS_FAMILY_STRING_GENERAL_MIDI_DUMP,
  327. IDS_FAMILY_STRING_COMPRESSED_MIDI,
  328. IDS_FAMILY_STRING_COMPRESSED_HMI_MIDI
  329. };
  330. MIDI_file* wa2_open_file(const char* url);
  331. extern "C" __declspec(dllexport) int winampGetExtendedFileInfoW(const wchar_t* fn, const char* data, wchar_t* dest, int destlen)
  332. {
  333. MIDI_file* file = 0;
  334. if (KeywordMatch(data, "type"))
  335. {
  336. dest[0] = L'0';
  337. dest[1] = 0;
  338. return 1;
  339. }
  340. if (KeywordMatch(data, "BURNABLE"))
  341. {
  342. dest[0] = L'0';
  343. dest[1] = 0;
  344. return 1;
  345. }
  346. if (KeywordMatch(data, "noburnreason")) // note: this isn't supposed to be any kind of protection - just keeps the burner from misbehaving on protected tracks
  347. {
  348. WASABI_API_LNGSTRINGW_BUF(IDS_MIDIS_ARE_NOT_BURNABLE, dest, destlen);
  349. return 1;
  350. }
  351. if (KeywordMatch(data, "family"))
  352. {
  353. INT index;
  354. LPCWSTR e;
  355. DWORD lcid;
  356. e = PathFindExtensionW(fn);
  357. if (L'.' != *e || 0x00 == *(++e)) return 0;
  358. lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  359. for (index = sizeof(pExtList) / sizeof(wchar_t*) - 1; index >= 0 && CSTR_EQUAL != CompareStringW(lcid, NORM_IGNORECASE, e, -1, pExtList[index], -1); index--);
  360. if (index >= 0 && S_OK == StringCchCopyW(dest, destlen, WASABI_API_LNGSTRINGW(pExtDescList[pExtDescIdList[index]]))) return 1;
  361. return 0;
  362. }
  363. file = wa2_open_file(AutoCharFn(fn));
  364. if (!file)
  365. {
  366. return 0;
  367. }
  368. const char* ret = 0;
  369. //else if (!_stricmp(tag,"FILEPATH") || !_stricmp(tag,"PATH")) ret=file->path;
  370. //else if (!_stricmp(tag,"DISPLAY")) ret=file->title;
  371. //else if (!_stricmp(tag,"FIRSTTRACK")) ret=file->info.traxnames[0];
  372. if (KeywordMatch(data, "LENGTH"))
  373. {
  374. _itow(file->GetLength(), dest, 10);
  375. file->Free();
  376. return 1;
  377. }
  378. else if (file->rmi_data)
  379. {
  380. if (KeywordMatch(data, "TITLE")) ret = find_tag(file, _rv('INAM'), 0);
  381. else if (KeywordMatch(data, "ARTIST")) ret = find_tag(file, _rv('IART'), 0);
  382. else if (KeywordMatch(data, "COMPOSER")) ret = find_tag(file, _rv('ICMP'), 0);
  383. else if (KeywordMatch(data, "GENRE")) ret = find_tag(file, _rv('IGNR'), 0);
  384. else if (KeywordMatch(data, "ALBUM")) ret = find_tag(file, _rv('IALB'), 0);
  385. else if (KeywordMatch(data, "COPYRIGHT")) ret = find_tag(file, _rv('ICOP'), 0);
  386. else if (KeywordMatch(data, "COMMENT")) ret = find_tag(file, _rv('ICMT'), 0);
  387. else if (KeywordMatch(data, "TRACK")) ret = find_tag(file, _rv('ITRK'), 0);
  388. else if (KeywordMatch(data, "DATE")) ret = find_tag(file, _rv('ICRD'), 0);
  389. else
  390. {
  391. file->Free();
  392. return 0;
  393. }
  394. }
  395. else
  396. {
  397. file->Free();
  398. return 0;
  399. }
  400. if (ret)
  401. {
  402. lstrcpynW(dest, AutoWide(ret), destlen);
  403. }
  404. file->Free();
  405. return !!ret;
  406. }
  407. void MIDI_file::GetTitle(char* buf, int maxlen)
  408. {
  409. string file_title;
  410. file2title(path, file_title);
  411. lstrcpynA(buf, file_title, maxlen);
  412. }
  413. //int save_gzip(MIDI_file* mf, char* path);
  414. static void do_ext(string& s, const char* ext)
  415. {
  416. const char* p = strrchr(s, '.');
  417. if (p) s.truncate(p - (const char*)s);
  418. s += ext;
  419. }
  420. void* build_rmi(MIDI_file* mf, UINT* siz)
  421. {
  422. UINT sz = 0x14 + align(mf->size, 2);
  423. UINT t_sz = 0;
  424. if (mf->title)
  425. {
  426. t_sz = strlen(mf->title);
  427. if (t_sz)
  428. {
  429. t_sz++; //add null;
  430. sz += 12 + align(t_sz, 2);
  431. }
  432. }
  433. if (mf->rmi_data)
  434. {
  435. sz += align(mf->rmi_size + 8, 2);
  436. }
  437. if (mf->bmp_data)
  438. {
  439. sz += align(mf->bmp_size + 12, 2);
  440. }
  441. if (mf->pDLSdata) sz += align(mf->DLSsize, 2);
  442. BYTE* block = (BYTE*)malloc(sz);
  443. BYTE* b_ptr = block;
  444. *(DWORD*)b_ptr = _rv('RIFF');
  445. b_ptr += 4;
  446. *(DWORD*)b_ptr = sz - 8;
  447. b_ptr += 4;
  448. *(DWORD*)b_ptr = _rv('RMID');
  449. b_ptr += 4;
  450. *(DWORD*)b_ptr = _rv('data');
  451. b_ptr += 4;
  452. *(DWORD*)b_ptr = mf->size;
  453. b_ptr += 4;
  454. memcpy(b_ptr, mf->data, mf->size);
  455. b_ptr += align(mf->size, 2);
  456. if (t_sz)
  457. {
  458. *(DWORD*)b_ptr = _rv('DISP');
  459. b_ptr += 4;
  460. *(DWORD*)b_ptr = t_sz + 4;
  461. b_ptr += 4;
  462. *(DWORD*)b_ptr = 1;
  463. b_ptr += 4;
  464. memcpy(b_ptr, mf->title, t_sz);
  465. b_ptr += align(t_sz, 2);
  466. }
  467. if (mf->rmi_data)
  468. {
  469. *(DWORD*)b_ptr = _rv('LIST');
  470. b_ptr += 4;
  471. *(DWORD*)b_ptr = mf->rmi_size;
  472. b_ptr += 4;
  473. memcpy(b_ptr, mf->rmi_data, mf->rmi_size);
  474. b_ptr += align(mf->rmi_size, 2);
  475. }
  476. if (mf->bmp_data)
  477. {
  478. *(DWORD*)b_ptr = _rv('DISP');
  479. b_ptr += 4;
  480. *(DWORD*)b_ptr = mf->bmp_size + 4;
  481. b_ptr += 4;
  482. *(DWORD*)b_ptr = 8;
  483. b_ptr += 4;
  484. memcpy(b_ptr, mf->bmp_data, mf->bmp_size);
  485. b_ptr += align(mf->bmp_size, 2);
  486. }
  487. if (mf->pDLSdata)
  488. {
  489. memcpy(b_ptr, mf->pDLSdata, mf->DLSsize);
  490. b_ptr += align(mf->DLSsize, 2);
  491. }
  492. *siz = sz;
  493. return block;
  494. }
  495. BOOL SaveFile(HWND w, MIDI_file* mf, BOOL info)
  496. {
  497. BOOL rmi_only = info;
  498. string tmp;
  499. if (is_local(mf->path) && _strnicmp(mf->path, "partial://", 10))
  500. {
  501. tmp = mf->path;
  502. if (!info) do_ext(tmp, ".mid");
  503. }
  504. else
  505. {
  506. info = 0;
  507. file2title(mf->path, tmp);
  508. tmp += ".mid";
  509. }
  510. if (mf->format > 1) info = 0; //not MID/RMI
  511. UINT fmt = 0;
  512. BOOL do_gzip = 0;
  513. if (!info)
  514. {
  515. char filter[512] = { 0 };
  516. OPENFILENAMEA ofn = { sizeof(ofn),0 };
  517. ofn.hwndOwner = w;
  518. ofn.lpstrFile = tmp.buffer_get(MAX_PATH + 1);
  519. ofn.nMaxFile = MAX_PATH;
  520. ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  521. ofn.lpstrDefExt = "";
  522. ofn.lpstrFilter = filter;
  523. char* pf = filter, * sf = 0;
  524. int len = 0;
  525. #define APPEND(x) {memcpy(pf,x,len);pf+=len;}
  526. if (!rmi_only)
  527. {
  528. sf = BuildFilterString(IDS_MIDI_FILES, "MID", &len);
  529. APPEND(sf);
  530. sf = BuildFilterString(IDS_COMPRESSED_MIDI_FILES, "MIZ", &len);
  531. APPEND(sf);
  532. }
  533. sf = BuildFilterString(IDS_RMI_FILES, "RMI", &len);
  534. APPEND(sf);
  535. sf = BuildFilterString(IDS_COMPRESSED_RMI_FILES, "MIZ", &len);
  536. APPEND(sf);
  537. #undef APPEND
  538. * pf = 0;
  539. if (!GetSaveFileNameA(&ofn)) return 0;
  540. tmp.buffer_done();
  541. fmt = ofn.nFilterIndex - 1;
  542. do_gzip = fmt & 1;
  543. fmt >>= 1;
  544. if (rmi_only) fmt = 1;
  545. if (do_gzip) do_ext(tmp, ".miz");
  546. else if (fmt == 1) do_ext(tmp, ".rmi");
  547. else do_ext(tmp, ".mid");
  548. }
  549. else
  550. {
  551. fmt = 1;
  552. const char* p = strrchr(tmp, '.');
  553. if (p && !_stricmp(p, ".miz")) do_gzip = 1;
  554. }
  555. {
  556. if (fmt > 1) fmt = 0;
  557. BOOL local = 0;
  558. const void* buf = 0;
  559. UINT buf_size = 0;
  560. if (fmt == 0)
  561. {
  562. buf = mf->data;
  563. buf_size = mf->size;
  564. }
  565. else //if (fmt==1)
  566. {
  567. local = 1;
  568. buf = build_rmi(mf, &buf_size);
  569. }
  570. int rv;
  571. if (do_gzip)
  572. {
  573. rv = SaveAsGZip(tmp, buf, buf_size);
  574. }
  575. else
  576. {
  577. HANDLE f = CreateFileA(tmp, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
  578. if (f != INVALID_HANDLE_VALUE)
  579. {
  580. DWORD bw = 0;
  581. WriteFile(f, buf, buf_size, &bw, 0);
  582. CloseHandle(f);
  583. rv = 1;
  584. }
  585. else rv = 0;
  586. }
  587. if (local) free((void*)buf);
  588. if (!_stricmp(mf->path, tmp))
  589. {
  590. mf->format = fmt;
  591. }
  592. if (!rv)
  593. {
  594. char _m[320] = { 0 };
  595. StringCbPrintfA(_m, sizeof(_m), WASABI_API_LNGSTRING(STRING_WRITE_ERROR_FMT), (const char*)tmp);
  596. MessageBoxA(w, _m, ERROR, MB_ICONERROR);
  597. }
  598. return rv;
  599. }
  600. }
  601. /// <summary>
  602. /// Compress given buffer with GZIP format and saves to given filename
  603. /// </summary>
  604. /// <param name="filename"></param>
  605. /// <param name="buffer"></param>
  606. /// <param name="size"></param>
  607. /// <returns></returns>
  608. int SaveAsGZip(string filename, const void* buffer, size_t size)
  609. {
  610. void* data;
  611. size_t data_len = size;
  612. int ret = CompressionUtility::CompressAsGZip(buffer, size, &data, data_len);
  613. if (ret >= 0)
  614. {
  615. try
  616. {
  617. HANDLE f = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
  618. if (f != INVALID_HANDLE_VALUE)
  619. {
  620. DWORD bw = 0;
  621. WriteFile(f, data, data_len, &bw, 0);
  622. CloseHandle(f);
  623. return 1;
  624. }
  625. }
  626. catch (...)
  627. {
  628. DWORD i = GetLastError();
  629. return 0;
  630. }
  631. }
  632. return 0;
  633. }
  634. #define _pr ((MIDI_file*)(lp))
  635. static cfg_struct_t<RECT> cfg_infpos("infpos", -1);
  636. static UINT inf_x_min = 0x80000000, inf_y_min, inf_c_x, inf_c_y;
  637. static RECT r_trax, r_text;
  638. static void SetWindowRect(HWND w, RECT* r)
  639. {
  640. SetWindowPos(w, 0, r->left, r->top, r->right - r->left, r->bottom - r->top, SWP_NOZORDER);
  641. }
  642. void cGetWindowRect(HWND w, RECT* r)
  643. {
  644. RECT tr, tr1;
  645. GetWindowRect(w, &tr);
  646. SetWindowPos(w, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  647. GetWindowRect(w, &tr1);
  648. r->left = tr.left - tr1.left;
  649. r->right = tr.right - tr1.left;
  650. r->top = tr.top - tr1.top;
  651. r->bottom = tr.bottom - tr1.top;
  652. SetWindowRect(w, r);
  653. }
  654. #define RB_NUM 3
  655. static struct
  656. {
  657. UINT id, dx, dy;
  658. }
  659. rb_dat[RB_NUM] =
  660. {
  661. {IDC_SAVE, 0, 0},
  662. {IDOK, 0, 0},
  663. {IDC_RMI_CRAP, 0, 0},
  664. };
  665. #define BOTTOM_NUM 8
  666. static struct
  667. {
  668. UINT id;
  669. UINT x, dy;
  670. }
  671. b_dat[BOTTOM_NUM] =
  672. {
  673. {IDC_STATIC1, 0, 0},
  674. {IDC_STATIC2, 0, 0},
  675. {IDC_STATIC3, 0, 0},
  676. {IDC_TIX, 0, 0},
  677. {IDC_MS, 0, 0},
  678. {IDC_FSIZE, 0, 0},
  679. {IDC_DLS, 0, 0},
  680. {IDC_LOOP, 0, 0}
  681. };
  682. static void OnSize(HWND wnd)
  683. {
  684. RECT cl, t;
  685. GetClientRect(wnd, &cl);
  686. t.left = r_text.left;
  687. t.right = r_text.right;
  688. t.top = r_text.top;
  689. t.bottom = cl.bottom - (inf_c_y - r_text.bottom);
  690. SetWindowRect(GetDlgItem(wnd, IDC_COPYRIGHT), &t);
  691. t.left = r_trax.left;
  692. t.right = cl.right - (inf_c_x - r_trax.right);
  693. t.top = r_trax.top;
  694. t.bottom = cl.bottom - (inf_c_y - r_trax.bottom);
  695. SetWindowRect(GetDlgItem(wnd, IDC_TRAX), &t);
  696. UINT n;
  697. for (n = 0; n < BOTTOM_NUM; n++)
  698. {
  699. SetWindowPos(GetDlgItem(wnd, b_dat[n].id), 0, b_dat[n].x, cl.bottom - b_dat[n].dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  700. }
  701. for (n = 0; n < RB_NUM; n++)
  702. {
  703. SetWindowPos(GetDlgItem(wnd, rb_dat[n].id), 0, cl.right - rb_dat[n].dx, cl.bottom - rb_dat[n].dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  704. }
  705. }
  706. BOOL WINAPI InfoProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
  707. {
  708. switch (msg)
  709. {
  710. case WM_INITDIALOG:
  711. if (inf_x_min == 0x80000000)
  712. {
  713. RECT r;
  714. GetWindowRect(wnd, &r);
  715. inf_x_min = r.right - r.left;
  716. inf_y_min = r.bottom - r.top;
  717. GetClientRect(wnd, &r);
  718. inf_c_x = r.right;
  719. inf_c_y = r.bottom;
  720. cGetWindowRect(GetDlgItem(wnd, IDC_COPYRIGHT), &r_text);
  721. cGetWindowRect(GetDlgItem(wnd, IDC_TRAX), &r_trax);
  722. UINT n;
  723. for (n = 0; n < BOTTOM_NUM; n++)
  724. {
  725. cGetWindowRect(GetDlgItem(wnd, b_dat[n].id), &r);
  726. b_dat[n].x = r.left;
  727. b_dat[n].dy = inf_c_y - r.top;
  728. }
  729. for (n = 0; n < RB_NUM; n++)
  730. {
  731. cGetWindowRect(GetDlgItem(wnd, rb_dat[n].id), &r);
  732. rb_dat[n].dx = inf_c_x - r.left;
  733. rb_dat[n].dy = inf_c_y - r.top;
  734. }
  735. }
  736. if (cfg_infpos.get_val().left != -1)
  737. {
  738. int sx = GetSystemMetrics(SM_CXSCREEN), sy = GetSystemMetrics(SM_CYSCREEN);
  739. if (cfg_infpos.get_val().right > sx)
  740. {
  741. cfg_infpos.get_val().left -= cfg_infpos.get_val().right - sx;
  742. cfg_infpos.get_val().right = sx;
  743. }
  744. if (cfg_infpos.get_val().bottom > sy)
  745. {
  746. cfg_infpos.get_val().top -= cfg_infpos.get_val().bottom - sy;
  747. cfg_infpos.get_val().bottom = sy;
  748. }
  749. if (cfg_infpos.get_val().left < 0)
  750. {
  751. cfg_infpos.get_val().right -= cfg_infpos.get_val().left;
  752. cfg_infpos.get_val().left = 0;
  753. }
  754. if (cfg_infpos.get_val().top < 0)
  755. {
  756. cfg_infpos.get_val().bottom -= cfg_infpos.get_val().top;
  757. cfg_infpos.get_val().top = 0;
  758. }
  759. SetWindowRect(wnd, &cfg_infpos.get_val());
  760. OnSize(wnd);
  761. }
  762. #if defined(_WIN64)
  763. SetWindowLong(wnd, DWLP_USER, lp);
  764. #else
  765. SetWindowLong(wnd, DWL_USER, lp);
  766. #endif
  767. SetDlgItemTextA(wnd, IDC_COPYRIGHT, _pr->info.copyright);
  768. SetDlgItemInt(wnd, IDC_MS, _pr->len, 0);
  769. SetDlgItemInt(wnd, IDC_TIX, _pr->info.tix, 0);
  770. {
  771. char tmp[128] = { 0 };
  772. getfmtstring(_pr, tmp);
  773. SetDlgItemTextA(wnd, IDC_FORMAT, tmp);
  774. HANDLE f = CreateFileA(_pr->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
  775. if (f != INVALID_HANDLE_VALUE)
  776. {
  777. StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_BYTES_FMT), GetFileSize(f, 0));
  778. CloseHandle(f);
  779. SetDlgItemTextA(wnd, IDC_FSIZE, tmp);
  780. }
  781. }
  782. {
  783. char tmp[1024] = { 0 };
  784. if (_pr->info.traxnames)
  785. {
  786. HWND lb = GetDlgItem(wnd, IDC_TRAX);
  787. UINT n;
  788. for (n = 0; n < _pr->info.ntrax; n++)
  789. {
  790. StringCbPrintfA(tmp, sizeof(tmp), "(%u) %s", n, (const char*)(_pr->info.traxnames[n]));
  791. SendMessageA(lb, LB_ADDSTRING, 0, (LPARAM)tmp);
  792. }
  793. }
  794. StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_TRACKS_FMT), _pr->info.ntrax);
  795. SetDlgItemTextA(wnd, IDC_NTRAX, tmp);
  796. if (_pr->title)
  797. {
  798. StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_MIDI_INFO_FMT1), (const char*)_pr->title, (const char*)_pr->path);
  799. }
  800. else
  801. {
  802. StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_MIDI_INFO_FMT2), (const char*)_pr->path);
  803. }
  804. if (_pr->flags & FLAG_INCOMPLETE) StringCbCatA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_INCOMPLETE));
  805. SetWindowTextA(wnd, tmp);
  806. }
  807. if (_pr->pDLSdata) EnableWindow(GetDlgItem(wnd, IDC_DLS), 1);
  808. if (_pr->loopstart) EnableWindow(GetDlgItem(wnd, IDC_LOOP), 1);
  809. //if (_pr->rmi_data) EnableWindow(GetDlgItem(wnd,IDC_RMI_CRAP),1);
  810. return 1;
  811. case WM_SIZE:
  812. OnSize(wnd);
  813. break;
  814. case WM_SIZING:
  815. if (lp)
  816. {
  817. RECT* r = (RECT*)lp;
  818. if ((UINT)(r->right - r->left) < inf_x_min)
  819. {
  820. if (wp != WMSZ_LEFT && wp != WMSZ_TOPLEFT && wp != WMSZ_BOTTOMLEFT)
  821. r->right = r->left + inf_x_min;
  822. else r->left = r->right - inf_x_min;
  823. }
  824. if ((UINT)(r->bottom - r->top) < inf_y_min)
  825. {
  826. if (wp != WMSZ_TOP && wp != WMSZ_TOPLEFT && wp != WMSZ_TOPRIGHT)
  827. r->bottom = r->top + inf_y_min;
  828. else r->top = r->bottom - inf_y_min;
  829. }
  830. }
  831. break;
  832. case WM_COMMAND:
  833. if (wp == IDOK || wp == IDCANCEL)
  834. {
  835. EndDialog(wnd, /*changed ? 0 : 1*/0);
  836. }
  837. else if (wp == IDC_SAVE)
  838. {
  839. #if defined(_WIN64)
  840. SaveFile(wnd, (MIDI_file*)GetWindowLong(wnd, DWLP_USER), 0);
  841. #else
  842. SaveFile(wnd, (MIDI_file*)GetWindowLong(wnd, DWL_USER), 0);
  843. #endif
  844. }
  845. else if (wp == IDC_RMI_CRAP)
  846. {
  847. #if defined(_WIN64)
  848. MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWLP_USER);
  849. #else
  850. MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWL_USER);
  851. #endif
  852. show_rmi_info(wnd, mf);
  853. }
  854. break;
  855. case WM_CLOSE:
  856. EndDialog(wnd, /*changed ? 0 : 1*/0);
  857. break;
  858. case WM_DESTROY:
  859. GetWindowRect(wnd, &cfg_infpos.get_val());
  860. break;
  861. }
  862. return 0;
  863. }
  864. #undef _pr