view src/win32/MovieOpen.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 // MovieOpen.cpp : implementation file
2 //
4 #include "stdafx.h"
5 #include "resource.h"
6 #include "MovieOpen.h"
7 #include "MainWnd.h"
8 #include "FileDlg.h"
9 #include "WinResUtil.h"
10 #include "WinMiscUtil.h"
11 #include "VBA.h"
13 #include "../gba/GBA.h"
14 #include "../gb/gbGlobals.h"
15 #include "../common/Util.h"
16 #include "7zip/OpenArchive.h"
18 // MovieOpen dialog
20 IMPLEMENT_DYNAMIC(MovieOpen, CDialog)
21 MovieOpen::MovieOpen(CWnd *pParent /*=NULL*/)
22 : CDialog(MovieOpen::IDD, pParent)
23 {}
25 MovieOpen::~MovieOpen()
26 {
27 SetArchiveParentHWND(NULL);
28 }
30 BOOL MovieOpen::OnInitDialog()
31 {
32 CDialog::OnInitDialog();
34 pauseFrame = 0;
35 ZeroMemory(&movieInfo, sizeof SMovie);
37 SetArchiveParentHWND(GetSafeHwnd());
39 GetDlgItem(IDC_CHECK_HIDEBORDER)->ShowWindow(FALSE);
40 GetDlgItem(IDC_LABEL_WARNING1)->SetWindowText("");
41 GetDlgItem(IDC_LABEL_WARNING2)->SetWindowText("");
42 GetDlgItem(IDC_EDIT_PAUSEFRAME)->SetWindowText("");
43 GetDlgItem(IDC_EDIT_PAUSEFRAME)->EnableWindow(FALSE);
44 GetDlgItem(IDC_CHECK_PAUSEFRAME)->EnableWindow(FALSE);
46 CheckDlgButton(IDC_READONLY, TRUE);
47 m_editDescription.SetReadOnly(theApp.movieReadOnly);
49 m_editFilename.LimitText(_MAX_PATH);
50 m_editAuthor.LimitText(MOVIE_METADATA_AUTHOR_SIZE);
51 m_editDescription.LimitText(MOVIE_METADATA_SIZE - MOVIE_METADATA_AUTHOR_SIZE);
52 m_editPauseFrame.LimitText(8);
54 // convert the ROM filename into a default movie name
55 CString movieName = winGetDestFilename(theApp.gameFilename, IDS_MOVIE_DIR, ".vbm");
57 GetDlgItem(IDC_MOVIE_FILENAME)->SetWindowText(movieName);
59 // scroll to show the rightmost side of the movie filename
60 ((CEdit *)GetDlgItem(IDC_MOVIE_FILENAME))->SetSel((DWORD)(movieName.GetLength() - 1), FALSE);
62 OnBnClickedMovieRefresh();
64 return TRUE; // return TRUE unless you set the focus to a control
65 // EXCEPTION: OCX Property Pages should return FALSE
66 }
68 void MovieOpen::DoDataExchange(CDataExchange *pDX)
69 {
70 CDialog::DoDataExchange(pDX);
71 //{{AFX_DATA_MAP(MovieCreate)
72 DDX_Control(pDX, IDC_EDIT_AUTHOR, m_editAuthor);
73 DDX_Control(pDX, IDC_EDIT_DESCRIPTION, m_editDescription);
74 DDX_Control(pDX, IDC_MOVIE_FILENAME, m_editFilename);
75 DDX_Control(pDX, IDC_EDIT_PAUSEFRAME, m_editPauseFrame);
76 //}}AFX_DATA_MAP
77 }
79 BEGIN_MESSAGE_MAP(MovieOpen, CDialog)
80 ON_BN_CLICKED(IDC_BROWSE, OnBnClickedBrowse)
81 ON_BN_CLICKED(IDOK, OnBnClickedOk)
82 ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel)
83 ON_BN_CLICKED(IDC_MOVIE_REFRESH, OnBnClickedMovieRefresh)
84 ON_BN_CLICKED(IDC_READONLY, OnBnClickedReadonly)
85 ON_BN_CLICKED(IDC_CHECK_PAUSEFRAME, OnBnClickedCheckPauseframe)
86 ON_BN_CLICKED(IDC_CHECK_HIDEBORDER, OnBnClickedHideborder)
87 ON_EN_CHANGE(IDC_MOVIE_FILENAME, OnEnChangeMovieFilename)
88 END_MESSAGE_MAP()
90 // MovieOpen message handlers
92 // FIXME: file-scope-global
93 static bool shouldReopenBrowse = false;
95 void MovieOpen::OnBnClickedBrowse()
96 {
97 theApp.winCheckFullscreen(); // FIXME: necessary or not?
99 LPCTSTR exts[] = { ".vbm", NULL };
101 CString filter = winResLoadFilter(IDS_FILTER_MOVIE);
102 CString title = winResLoadString(IDS_SELECT_MOVIE_NAME);
104 CString movieName = winGetDestFilename(theApp.gameFilename, IDS_MOVIE_DIR, exts[0]);
105 CString movieDir = winGetDestDir(IDS_MOVIE_DIR);
107 FileDlg dlg(this, movieName, filter, 1, "VBM", exts, movieDir, title, false, true);
109 do
110 {
111 shouldReopenBrowse = false;
113 if (dlg.DoModal() == IDCANCEL)
114 {
115 return;
116 }
118 movieName = dlg.GetPathName();
120 GetDlgItem(IDC_MOVIE_FILENAME)->SetWindowText(movieName);
122 // SetWindowText calls OnEnChangeMovieFilename which calls OnBnClickedMovieRefresh
123 // so this extra call to OnBnClickedMovieRefresh is bad
124 //OnBnClickedMovieRefresh();
125 }
126 while (shouldReopenBrowse);
128 // scroll to show the rightmost side of the movie filename
129 ((CEdit *)GetDlgItem(IDC_MOVIE_FILENAME))->SetSel((DWORD)(movieName.GetLength() - 1), FALSE);
130 }
132 // some extensions that might commonly be near emulation-related files that we almost certainly can't open, or at least not
133 // directly.
134 // also includes definitely non-movie extensions we know about, since we only use this variable in a movie opening function.
135 // we do this by exclusion instead of inclusion because we don't want to exclude extensions used for any archive files, even
136 // extensionless or unusually-named archives.
137 static const char *s_movieIgnoreExtensions [] = {
138 "gba", "gbc", "gb", "sgb", "cgb", "bin", "agb", "bios", "mb", "elf", "sgm", "clt", "dat", "gbs", "gcf", "spc",
139 "xpc", "pal", "act", "dmp", "avi", "ini", "txt", "nfo", "htm", "html", "jpg", "jpeg", "png", "bmp", "gif", "mp3",
140 "wav", "lnk", "exe", "bat", "sav", "luasav"
141 };
143 void MovieOpen::OnBnClickedMovieRefresh()
144 {
145 static int recursionDepth = 0;
146 if (recursionDepth > 0)
147 return;
148 struct Scope {Scope(){ ++ recursionDepth; } ~Scope(){ --recursionDepth; }} scope;
150 CString tempName;
151 GetDlgItem(IDC_MOVIE_FILENAME)->GetWindowText(tempName);
153 #if 1
154 // use ObtainFile to support opening files within archives (.7z, .rar, .zip, .zip.rar.7z, etc.)
156 if (movieLogicalName.GetLength() > 2048) movieLogicalName.Truncate(2048);
158 char LogicalName[2048], PhysicalName[2048];
159 if (ObtainFile(tempName, LogicalName, PhysicalName, "mov", s_movieIgnoreExtensions,
160 sizeof(s_movieIgnoreExtensions) / sizeof(*s_movieIgnoreExtensions)))
161 {
162 if (tempName != LogicalName)
163 {
164 int selStart = 0, selEnd = 0;
165 ((CEdit *)GetDlgItem(IDC_MOVIE_FILENAME))->GetSel(selStart, selEnd);
167 GetDlgItem(IDC_MOVIE_FILENAME)->SetWindowText(LogicalName);
169 ((CEdit *)GetDlgItem(IDC_MOVIE_FILENAME))->SetSel(selStart, selEnd, FALSE);
170 }
171 moviePhysicalName = PhysicalName;
172 movieLogicalName = LogicalName;
173 ReleaseTempFileCategory("mov", PhysicalName);
174 }
175 else
176 {
177 shouldReopenBrowse = true;
178 return;
179 }
180 #else
181 // old version that only supports uncompressed movies
182 moviePhysicalName = tempName;
183 movieLogicalName = tempName;
184 #endif
186 if (VBAMovieGetInfo(moviePhysicalName, &movieInfo) == MOVIE_SUCCESS)
187 {
188 if (movieInfo.readOnly)
189 {
190 CheckDlgButton(IDC_READONLY, TRUE);
191 m_editDescription.SetReadOnly(TRUE);
192 }
194 char buffer[MOVIE_METADATA_SIZE];
196 strncpy(buffer, movieInfo.authorInfo, MOVIE_METADATA_AUTHOR_SIZE);
197 buffer[MOVIE_METADATA_AUTHOR_SIZE - 1] = '\0';
198 GetDlgItem(IDC_EDIT_AUTHOR)->SetWindowText(buffer);
200 strncpy(buffer, movieInfo.authorInfo + MOVIE_METADATA_AUTHOR_SIZE, MOVIE_METADATA_SIZE - MOVIE_METADATA_AUTHOR_SIZE);
201 buffer[MOVIE_METADATA_SIZE - MOVIE_METADATA_AUTHOR_SIZE - 1] = '\0';
202 GetDlgItem(IDC_EDIT_DESCRIPTION)->SetWindowText(buffer);
204 int option = 2;
205 if (movieInfo.header.startFlags & MOVIE_START_FROM_SRAM)
206 option = 1;
207 if (movieInfo.header.startFlags & MOVIE_START_FROM_SNAPSHOT)
208 option = 0;
209 CheckRadioButton(IDC_RECNOW, IDC_RECSTART, IDC_RECNOW + option);
211 option = 3;
212 if (movieInfo.header.typeFlags & MOVIE_TYPE_SGB)
213 option = 2;
214 if (movieInfo.header.typeFlags & MOVIE_TYPE_GBC)
215 option = 1;
216 if (movieInfo.header.typeFlags & MOVIE_TYPE_GBA)
217 option = 0;
218 CheckRadioButton(IDC_REC_GBA, IDC_REC_GB, IDC_REC_GBA + option);
220 GetDlgItem(IDC_CHECK_HIDEBORDER)->ShowWindow(option == 2 ? TRUE : FALSE);
222 if (movieInfo.header.typeFlags & MOVIE_TYPE_GBA)
223 {
224 if (movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE)
225 {
226 if (movieInfo.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE)
227 option = 2;
228 else
229 option = 3;
230 }
231 else
232 option = 1;
233 }
234 else
235 option = 0;
237 CheckRadioButton(IDC_REC_NOBIOS, IDC_REC_GBABIOSINTRO, IDC_REC_NOBIOS + option);
239 {
240 char * p;
241 time_t ttime = (time_t)movieInfo.header.uid;
242 strncpy(buffer, ctime(&ttime), 127);
243 buffer[127] = '\0';
244 if ((p = strrchr(buffer, '\n')))
245 *p = '\0';
246 GetDlgItem(IDC_LABEL_DATE)->SetWindowText(buffer);
248 uint32 div = 60;
249 uint32 l = (movieInfo.header.length_frames + (div >> 1)) / div;
250 uint32 seconds = l % 60;
251 l /= 60;
252 uint32 minutes = l % 60;
253 l /= 60;
254 uint32 hours = l % 60;
255 sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
256 GetDlgItem(IDC_LABEL_LENGTH)->SetWindowText(buffer);
257 sprintf(buffer, "%ld", movieInfo.header.length_frames);
258 GetDlgItem(IDC_LABEL_FRAMES)->SetWindowText(buffer);
259 sprintf(buffer, "%ld", movieInfo.header.rerecord_count);
260 GetDlgItem(IDC_LABEL_RERECORD)->SetWindowText(buffer);
261 }
263 {
264 char warning1 [1024], warning2 [1024], buffer [1024];
266 strcpy(warning1, "");
267 strcpy(warning2, "");
269 char romTitle [12];
270 uint32 romGameCode;
271 uint16 checksum;
272 uint8 crc;
274 VBAMovieGetRomInfo(movieInfo, romTitle, romGameCode, checksum, crc);
276 // rather than treat these as warnings, might as well always show the info in the dialog (it's probably more
277 // informative and reassuring)
278 /// if (strncmp(movieInfo.header.romTitle,romTitle,12) != 0)
279 {
280 char str [13];
281 strncpy(str, movieInfo.header.romTitle, 12);
282 str[12] = '\0';
283 sprintf(buffer, "title=%s ", str);
284 strcat(warning1, buffer);
286 strncpy(str, romTitle, 12);
287 str[12] = '\0';
288 sprintf(buffer, "title=%s ", str);
289 strcat(warning2, buffer);
290 }
291 /// if (((movieInfo.header.typeFlags & MOVIE_TYPE_GBA)!=0) != (systemCartridgeType == 0))
292 {
293 sprintf(buffer, "type=%s ",
294 (movieInfo.header.typeFlags & MOVIE_TYPE_GBA) ? "GBA" : (movieInfo.header.typeFlags &
295 MOVIE_TYPE_GBC) ? "GBC" : (movieInfo.header.
296 typeFlags &
297 MOVIE_TYPE_SGB) ? "SGB" : "GB");
298 strcat(warning1, buffer);
300 sprintf(buffer, "type=%s ", systemCartridgeType ==
301 0 ? "GBA" : (gbRom[0x143] & 0x80 ? "GBC" : (gbRom[0x146] == 0x03 ? "SGB" : "GB")));
302 strcat(warning2, buffer);
303 }
304 /// if (movieInfo.header.romCRC != crc)
305 {
306 sprintf(buffer, "crc=%02x ", movieInfo.header.romCRC);
307 strcat(warning1, buffer);
309 sprintf(buffer, "crc=%02x ", crc);
310 strcat(warning2, buffer);
311 }
312 /// if (movieInfo.header.romGameCode != romGameCode)
313 {
314 char code [5];
315 if (movieInfo.header.typeFlags & MOVIE_TYPE_GBA)
316 {
317 memcpy(code, &movieInfo.header.romGameCode, 4);
318 code[4] = '\0';
319 sprintf(buffer, "code=%s ", code);
320 strcat(warning1, buffer);
321 }
323 if (systemCartridgeType == 0)
324 {
325 memcpy(code, &romGameCode, 4);
326 code[4] = '\0';
327 sprintf(buffer, "code=%s ", code);
328 strcat(warning2, buffer);
329 }
330 }
331 /// if (movieInfo.header.romOrBiosChecksum != checksum && !((movieInfo.header.optionFlags &
332 // MOVIE_SETTING_USEBIOSFILE)==0
333 // && checksum==0))
334 {
335 sprintf(buffer,
336 movieInfo.header.typeFlags &
337 MOVIE_TYPE_GBA ? ((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) ==
338 0 ? "(bios=none) " : "(bios=%04x) ") : "check=%04x ",
339 movieInfo.header.romOrBiosChecksum);
340 strcat(warning1, buffer);
342 sprintf(buffer,
343 checksum == 0 ? "(bios=none) " : systemCartridgeType == 0 ? "(bios=%04x) " : "check=%04x ",
344 checksum);
345 strcat(warning2, buffer);
346 }
348 if (strlen(warning1) > 0)
349 {
350 sprintf(buffer, "Movie ROM: %s", warning1);
351 GetDlgItem(IDC_LABEL_WARNING1)->SetWindowText(buffer);
353 sprintf(buffer, "Your ROM: %s", warning2);
355 //if(movieInfo.header.romCRC != crc
356 //|| strncmp(movieInfo.header.romTitle,romTitle,12) != 0
357 //|| movieInfo.header.romOrBiosChecksum != checksum && !((movieInfo.header.optionFlags &
358 // MOVIE_SETTING_USEBIOSFILE)==0 && checksum==0))
359 // strcat(buffer, "<-- MISMATCH");
361 GetDlgItem(IDC_LABEL_WARNING2)->SetWindowText(buffer);
362 }
363 else
364 {
365 GetDlgItem(IDC_LABEL_WARNING1)->SetWindowText("(No problems detected)");
366 GetDlgItem(IDC_LABEL_WARNING2)->SetWindowText(" ");
367 }
368 }
369 GetDlgItem(IDC_CHECK_PAUSEFRAME)->EnableWindow(TRUE);
370 }
371 else
372 {
373 GetDlgItem(IDC_LABEL_DATE)->SetWindowText(" ");
374 GetDlgItem(IDC_LABEL_LENGTH)->SetWindowText(" ");
375 GetDlgItem(IDC_LABEL_FRAMES)->SetWindowText(" ");
376 GetDlgItem(IDC_LABEL_RERECORD)->SetWindowText(" ");
377 GetDlgItem(IDC_EDIT_AUTHOR)->SetWindowText(" ");
378 GetDlgItem(IDC_EDIT_DESCRIPTION)->SetWindowText(" ");
379 GetDlgItem(IDC_LABEL_WARNING1)->SetWindowText(" ");
380 GetDlgItem(IDC_LABEL_WARNING2)->SetWindowText(" ");
382 GetDlgItem(IDC_EDIT_PAUSEFRAME)->SetWindowText("");
383 GetDlgItem(IDC_EDIT_PAUSEFRAME)->EnableWindow(FALSE);
384 GetDlgItem(IDC_CHECK_PAUSEFRAME)->EnableWindow(FALSE);
385 CheckDlgButton(IDC_CHECK_PAUSEFRAME, FALSE);
386 /*
387 /// FIXME: how to un-check all the radio buttons?
388 CheckRadioButton(IDC_RECNOW, IDC_RECSTART, -1);
389 CheckRadioButton(IDC_REC_GBA, IDC_REC_GB, -1);
390 CheckRadioButton(IDC_REC_NOBIOS, IDC_REC_GBABIOSINTRO, -1);*/
391 }
392 }
394 BOOL MovieOpen::OnWndMsg(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *res)
395 {
396 switch (msg)
397 {
398 case WM_CTLCOLORSTATIC:
399 {
400 //HWND hwndDlg = GetSafeHwnd();
401 HWND warnDlg = NULL;
402 GetDlgItem(IDC_LABEL_WARNING2, &warnDlg);
404 if ((HWND)lParam == warnDlg)
405 {
406 char romTitle [12];
407 uint32 romGameCode;
408 uint16 checksum;
409 uint8 crc;
411 VBAMovieGetRomInfo(movieInfo, romTitle, romGameCode, checksum, crc);
413 if (movieInfo.header.romCRC != crc
414 || strncmp(movieInfo.header.romTitle, romTitle, 12) != 0
415 || movieInfo.header.romOrBiosChecksum != checksum
416 && !((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) == 0 && checksum == 0))
417 {
418 // draw the md5 sum in red if it's different from the md5 of the rom used in the replay
419 HDC hdcStatic = (HDC)wParam;
420 SetTextColor(hdcStatic, RGB(255, 0, 0)); // use red for a mismatch
422 // I'm not sure why this doesn't work to make the background transparent... it turns white anyway
423 SetBkMode(hdcStatic, TRANSPARENT);
424 return (LONG)GetStockObject(NULL_BRUSH);
425 }
426 }
427 return FALSE;
428 }
429 }
430 return CDialog::OnWndMsg(msg, wParam, lParam, res);
431 }
433 void MovieOpen::OnBnClickedOk()
434 {
435 bool useBIOSFile = (movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0;
436 if (useBIOSFile)
437 {
438 extern bool systemLoadBIOS(const char *biosFileName, bool useBiosFile);
439 if (!systemLoadBIOS(theApp.biosFileName, useBIOSFile))
440 {
441 systemMessage(0, "This movie requires a valid GBA BIOS file to play.\nPlease locate a BIOS file.");
442 ((MainWnd *)theApp.m_pMainWnd)->OnOptionsEmulatorSelectbiosfile();
443 if (!systemLoadBIOS(theApp.biosFileName, useBIOSFile))
444 {
445 systemMessage(0, "\"%s\" is not a valid BIOS file; cannot play movie without one.", theApp.biosFileName);
446 return;
447 }
448 }
449 }
451 int code = VBAMovieOpen(moviePhysicalName, IsDlgButtonChecked(IDC_READONLY) != FALSE);
453 if (code != MOVIE_SUCCESS)
454 {
455 if (code == MOVIE_FILE_NOT_FOUND)
456 systemMessage(0, "Could not find movie file \"%s\".", (const char *)movieLogicalName);
457 else if (code == MOVIE_WRONG_FORMAT)
458 systemMessage(0, "Movie file \"%s\" is not in proper VBM format.", (const char *)movieLogicalName);
459 else if (code == MOVIE_WRONG_VERSION)
460 systemMessage(0, "Movie file \"%s\" is not a supported version.", (const char *)movieLogicalName);
461 else
462 systemMessage(0, "Failed to open movie \"%s\".", (const char *)movieLogicalName);
463 return;
464 }
465 else
466 {
467 // get author and movie info from the edit fields (the description might change):
468 char info[MOVIE_METADATA_SIZE], buffer[MOVIE_METADATA_SIZE];
470 GetDlgItem(IDC_EDIT_AUTHOR)->GetWindowText(buffer, MOVIE_METADATA_AUTHOR_SIZE);
471 strncpy(info, buffer, MOVIE_METADATA_AUTHOR_SIZE);
472 info[MOVIE_METADATA_AUTHOR_SIZE - 1] = '\0';
474 GetDlgItem(IDC_EDIT_DESCRIPTION)->GetWindowText(buffer, MOVIE_METADATA_SIZE - MOVIE_METADATA_AUTHOR_SIZE);
475 strncpy(info + MOVIE_METADATA_AUTHOR_SIZE, buffer, MOVIE_METADATA_SIZE - MOVIE_METADATA_AUTHOR_SIZE);
476 info[MOVIE_METADATA_SIZE - 1] = '\0';
478 VBAMovieSetMetadata(info);
479 }
481 if (IsDlgButtonChecked(IDC_CHECK_PAUSEFRAME))
482 {
483 char buffer [9];
484 GetDlgItem(IDC_EDIT_PAUSEFRAME)->GetWindowText(buffer, 8);
485 buffer[8] = '\0';
487 int pauseFrame = atoi(buffer);
488 if (pauseFrame >= 0)
489 VBAMovieSetPauseAt(pauseFrame);
490 }
492 OnOK();
493 }
495 void MovieOpen::OnBnClickedCancel()
496 {
497 OnCancel();
498 }
500 void MovieOpen::OnBnClickedReadonly()
501 {
502 theApp.movieReadOnly = IsDlgButtonChecked(IDC_READONLY) != 0;
503 m_editDescription.SetReadOnly(theApp.movieReadOnly);
504 OnBnClickedMovieRefresh();
505 }
507 void MovieOpen::OnBnClickedCheckPauseframe()
508 {
509 if (IsDlgButtonChecked(IDC_CHECK_PAUSEFRAME))
510 {
511 char buffer [8];
512 _itoa(movieInfo.header.length_frames, buffer, 10);
513 GetDlgItem(IDC_EDIT_PAUSEFRAME)->SetWindowText(buffer);
514 GetDlgItem(IDC_EDIT_PAUSEFRAME)->EnableWindow(TRUE);
515 }
516 else
517 {
518 GetDlgItem(IDC_EDIT_PAUSEFRAME)->SetWindowText("");
519 GetDlgItem(IDC_EDIT_PAUSEFRAME)->EnableWindow(FALSE);
520 }
521 }
523 void MovieOpen::OnBnClickedHideborder()
524 {
525 theApp.hideMovieBorder = IsDlgButtonChecked(IDC_CHECK_HIDEBORDER) != 0;
526 }
528 void MovieOpen::OnEnChangeMovieFilename()
529 {
530 OnBnClickedMovieRefresh();
531 }