annotate src/win32/7zip/OpenArchive.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
rev   line source
rlm@1 1 #include "../stdafx.h"
rlm@1 2 #include "../resource.h"
rlm@1 3 #include <windows.h>
rlm@1 4 #include <mmsystem.h>
rlm@1 5 #include <cstdio>
rlm@1 6 #include <cerrno>
rlm@1 7 #include <cassert>
rlm@1 8 #include <cstring>
rlm@1 9 #include <map>
rlm@1 10 #include <vector>
rlm@1 11 #include <algorithm>
rlm@1 12 #include "7zip.h"
rlm@1 13 //#include "G_main.h"
rlm@1 14 //#include "G_dsound.h"
rlm@1 15 #include "OpenArchive.h"
rlm@1 16
rlm@1 17 LRESULT CALLBACK ArchiveFileChooser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
rlm@1 18 static int s_archiveFileChooserResult = -1;
rlm@1 19
rlm@1 20 static HWND s_parentHWND = NULL;
rlm@1 21 void SetArchiveParentHWND(void* hwnd) { s_parentHWND = (HWND)hwnd; }
rlm@1 22 static HWND GetArchiveParentHWND() { return s_parentHWND ? s_parentHWND : AfxGetApp()->m_pMainWnd->GetSafeHwnd(); }
rlm@1 23
rlm@1 24 static char Str_Tmp [2048];
rlm@1 25
rlm@1 26 struct ArchiveFileChooserInfo
rlm@1 27 {
rlm@1 28 ArchiveFileChooserInfo(ArchiveFile& theArchive, const char** ignoreExtensions, int& numIgnoreExtensions) : archive(theArchive)
rlm@1 29 {
rlm@1 30 tryagain:
rlm@1 31 int numItems = archive.GetNumItems();
rlm@1 32 for(int i = 0; i < numItems; i++)
rlm@1 33 {
rlm@1 34 if(archive.GetItemSize(i))
rlm@1 35 {
rlm@1 36 const char* name = archive.GetItemName(i);
rlm@1 37 const char* ext = strrchr(name, '.');
rlm@1 38 bool ok = true;
rlm@1 39 if(ext++)
rlm@1 40 {
rlm@1 41 for(int j = 0; j < numIgnoreExtensions; j++)
rlm@1 42 {
rlm@1 43 const char* ext2 = ignoreExtensions[j];
rlm@1 44 const char* wild = strchr(ext2, '*');
rlm@1 45 if(!wild)
rlm@1 46 {
rlm@1 47 if(!_stricmp(ext, ext2))
rlm@1 48 {
rlm@1 49 ok = false;
rlm@1 50 break;
rlm@1 51 }
rlm@1 52 }
rlm@1 53 else // very limited (end only) wildcard support
rlm@1 54 {
rlm@1 55 if(!_strnicmp(ext, ext2, wild - ext2))
rlm@1 56 {
rlm@1 57 ok = false;
rlm@1 58 break;
rlm@1 59 }
rlm@1 60 }
rlm@1 61 }
rlm@1 62 }
rlm@1 63 if(ok)
rlm@1 64 {
rlm@1 65 ArchiveFileChooserInfo::FileInfo fi = { name, i };
rlm@1 66 files.push_back(fi);
rlm@1 67 }
rlm@1 68 }
rlm@1 69 }
rlm@1 70
rlm@1 71 if(files.empty() && numIgnoreExtensions)
rlm@1 72 {
rlm@1 73 // try again without any exclusions if we excluded everything in the archive
rlm@1 74 numIgnoreExtensions = 0;
rlm@1 75 goto tryagain;
rlm@1 76 }
rlm@1 77
rlm@1 78 // strip away prefix paths that are common to all the files
rlm@1 79 bool stripping = !files.empty();
rlm@1 80 while(stripping)
rlm@1 81 {
rlm@1 82 const char* firstName = files[0].name.c_str();
rlm@1 83 const char* slash = strchr(firstName, '\\');
rlm@1 84 const char* slash2 = strchr(firstName, '/');
rlm@1 85 slash = max(slash, slash2);
rlm@1 86 if(!slash++)
rlm@1 87 break;
rlm@1 88 for(size_t i = 1; i < files.size(); i++)
rlm@1 89 if(strncmp(firstName, files[i].name.c_str(), slash - firstName))
rlm@1 90 stripping = false;
rlm@1 91 if(stripping)
rlm@1 92 for(size_t i = 0; i < files.size(); i++)
rlm@1 93 files[i].name = files[i].name.substr(slash - firstName, files[i].name.length() - (slash - firstName));
rlm@1 94 }
rlm@1 95
rlm@1 96 // sort by filename
rlm@1 97 std::sort(files.begin(), files.end(), FileInfo::Sort);
rlm@1 98 }
rlm@1 99
rlm@1 100 //protected:
rlm@1 101
rlm@1 102 struct FileInfo
rlm@1 103 {
rlm@1 104 std::string name;
rlm@1 105 int itemIndex;
rlm@1 106
rlm@1 107 static bool Sort(const FileInfo& elem1, const FileInfo& elem2)
rlm@1 108 {
rlm@1 109 int comp = elem1.name.compare(elem2.name);
rlm@1 110 return comp ? (comp < 0) : (elem1.itemIndex < elem2.itemIndex);
rlm@1 111 }
rlm@1 112 };
rlm@1 113
rlm@1 114 ArchiveFile& archive;
rlm@1 115 std::vector<FileInfo> files;
rlm@1 116 };
rlm@1 117
rlm@1 118 static void ClearLayoutStates();
rlm@1 119
rlm@1 120 int ChooseItemFromArchive(ArchiveFile& archive, bool autoChooseIfOnly1, const char** ignoreExtensions, int numIgnoreExtensions)
rlm@1 121 {
rlm@1 122 int prevNumIgnoreExtensions = numIgnoreExtensions;
rlm@1 123 archive.m_userMadeSelection = false;
rlm@1 124
rlm@1 125 // prepare a list of files to choose from the archive
rlm@1 126 ArchiveFileChooserInfo info (archive, ignoreExtensions, numIgnoreExtensions);
rlm@1 127
rlm@1 128 // based on our list, decide which item in the archive to choose
rlm@1 129
rlm@1 130 // check if there's nothing
rlm@1 131 if(info.files.size() < 1)
rlm@1 132 {
rlm@1 133 MessageBox(GetArchiveParentHWND(), "The archive is either empty or encrypted.", "Nothing to load!", MB_OK | MB_ICONWARNING);
rlm@1 134 return -1;
rlm@1 135 }
rlm@1 136
rlm@1 137 // warn if all the files in the archive have extensions we should ignore
rlm@1 138 if(numIgnoreExtensions != prevNumIgnoreExtensions)
rlm@1 139 {
rlm@1 140 CString msg;
rlm@1 141 msg.Format("The archive appears to only contain the wrong type of files.\n\n(in \"%s\")", archive.GetArchiveFileName());
rlm@1 142 int answer = MessageBox(GetArchiveParentHWND(), msg, "Warning", MB_OKCANCEL | MB_ICONWARNING | MB_DEFBUTTON2);
rlm@1 143 if(answer == IDCANCEL)
rlm@1 144 return -1;
rlm@1 145 }
rlm@1 146
rlm@1 147 // if there's only 1 item, choose it
rlm@1 148 if(info.files.size() == 1 && autoChooseIfOnly1 && numIgnoreExtensions == prevNumIgnoreExtensions)
rlm@1 149 return info.files[0].itemIndex;
rlm@1 150
rlm@1 151 // bring up a dialog to choose the index if there's more than 1
rlm@1 152 DialogBoxParam(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_ARCHIVEFILECHOOSER), GetArchiveParentHWND(), (DLGPROC) ArchiveFileChooser,(LPARAM) &info);
rlm@1 153 archive.m_userMadeSelection = (s_archiveFileChooserResult != -1);
rlm@1 154 return s_archiveFileChooserResult;
rlm@1 155 }
rlm@1 156
rlm@1 157
rlm@1 158
rlm@1 159
rlm@1 160 #define DEFAULT_EXTENSION ".tmp"
rlm@1 161 #define DEFAULT_CATEGORY "vba"
rlm@1 162
rlm@1 163 static struct TempFiles
rlm@1 164 {
rlm@1 165 struct TemporaryFile
rlm@1 166 {
rlm@1 167 TemporaryFile(const char* cat, const char* ext)
rlm@1 168 {
rlm@1 169 if(!ext || !*ext) ext = DEFAULT_EXTENSION;
rlm@1 170 if(!cat || !*cat) cat = DEFAULT_CATEGORY;
rlm@1 171 category = cat;
rlm@1 172
rlm@1 173 char tempPath [2048];
rlm@1 174 GetTempPath(2048, tempPath);
rlm@1 175 //GetTempFileName(tempPath, cat, 0, filename, ext); // alas
rlm@1 176
rlm@1 177 char*const fname = tempPath + strlen(tempPath);
rlm@1 178 unsigned short start = (unsigned short)(timeGetTime() & 0xFFFF);
rlm@1 179 unsigned short n = start + 1;
rlm@1 180 while(n != start)
rlm@1 181 {
rlm@1 182 _snprintf(fname, 2048 - (fname - tempPath), "%s%04X%s", cat, n, ext);
rlm@1 183 FILE* file = fopen(tempPath, "wb");
rlm@1 184 if(file)
rlm@1 185 {
rlm@1 186 // mark the temporary file as read-only and (whatever this does) temporary
rlm@1 187 DWORD attributes = GetFileAttributes(tempPath);
rlm@1 188 attributes |= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_TEMPORARY;
rlm@1 189 SetFileAttributes(tempPath, attributes);
rlm@1 190
rlm@1 191 fclose(file);
rlm@1 192
rlm@1 193 // add it to our registry of files that need to be deleted, in case we fail to terminate properly
rlm@1 194 TempFiles::AddEntryToGarbageRegistry(tempPath);
rlm@1 195
rlm@1 196 break;
rlm@1 197 }
rlm@1 198 n++;
rlm@1 199 }
rlm@1 200 strcpy(filename, tempPath);
rlm@1 201 }
rlm@1 202 TemporaryFile(const TemporaryFile& copy)
rlm@1 203 {
rlm@1 204 strcpy(filename, copy.filename);
rlm@1 205 category = copy.category;
rlm@1 206 }
rlm@1 207 TemporaryFile()
rlm@1 208 {
rlm@1 209 filename[0] = 0;
rlm@1 210 // category[0] = 0; // error
rlm@1 211 }
rlm@1 212 bool Delete(bool returnFalseOnRegistryRemovalFailure=false)
rlm@1 213 {
rlm@1 214 if(!*filename)
rlm@1 215 return true; // guess it already didn't exist
rlm@1 216
rlm@1 217 // remove read-only attribute so Windows will let us delete it
rlm@1 218 // (our temporary files are read-only to discourage other apps from tampering)
rlm@1 219 DWORD attributes = GetFileAttributes(filename);
rlm@1 220 if(attributes & FILE_ATTRIBUTE_READONLY)
rlm@1 221 SetFileAttributes(filename, attributes & ~FILE_ATTRIBUTE_READONLY);
rlm@1 222
rlm@1 223 if(_unlink(filename) == 0 || errno != EACCES)
rlm@1 224 {
rlm@1 225 // remove it from our registry of files that need to be deleted, to reduce accumulation
rlm@1 226 bool removed = TempFiles::RemoveEntryFromGarbageRegistry(filename);
rlm@1 227
rlm@1 228 *filename = '\0';
rlm@1 229 return removed || !returnFalseOnRegistryRemovalFailure; // successfully deleted or already didn't exist, return true unless registry removal failure notification was requested and that failed
rlm@1 230 }
rlm@1 231
rlm@1 232 // restore read-only if we couldn't delete it (not sure if this ever succeeds or matters though)
rlm@1 233 if(attributes & FILE_ATTRIBUTE_READONLY)
rlm@1 234 SetFileAttributes(filename, attributes);
rlm@1 235
rlm@1 236 return false; // failed to delete read-only or in-use file
rlm@1 237 }
rlm@1 238 char filename [MAX_PATH];
rlm@1 239 std::string category;
rlm@1 240 };
rlm@1 241
rlm@1 242 std::vector<TemporaryFile> tempFiles;
rlm@1 243
rlm@1 244 const char* GetFile(const char* category, const char* extension)
rlm@1 245 {
rlm@1 246 tempFiles.push_back(TemporaryFile(category, extension));
rlm@1 247 return tempFiles.back().filename;
rlm@1 248 }
rlm@1 249
rlm@1 250 void ReleaseFile(const char* filename)
rlm@1 251 {
rlm@1 252 for(int i = (int)tempFiles.size()-1; i >= 0; i--)
rlm@1 253 {
rlm@1 254 if(!strcmp(filename, tempFiles[i].filename))
rlm@1 255 {
rlm@1 256 if(tempFiles[i].Delete())
rlm@1 257 tempFiles.erase(tempFiles.begin() + i);
rlm@1 258 }
rlm@1 259 }
rlm@1 260 }
rlm@1 261
rlm@1 262 void ReleaseCategory(const char* cat, const char* exceptionFilename)
rlm@1 263 {
rlm@1 264 for(int i = (int)tempFiles.size()-1; i >= 0; i--)
rlm@1 265 {
rlm@1 266 if(!strcmp(cat, tempFiles[i].category.c_str()) &&
rlm@1 267 (!exceptionFilename ||
rlm@1 268 strcmp(exceptionFilename, tempFiles[i].filename)))
rlm@1 269 {
rlm@1 270 if(tempFiles[i].Delete())
rlm@1 271 tempFiles.erase(tempFiles.begin() + i);
rlm@1 272 }
rlm@1 273 }
rlm@1 274 }
rlm@1 275
rlm@1 276 // delete all temporary files on shutdown
rlm@1 277 ~TempFiles()
rlm@1 278 {
rlm@1 279 for(size_t i = 0; i < tempFiles.size(); i++)
rlm@1 280 {
rlm@1 281 tempFiles[i].Delete();
rlm@1 282 }
rlm@1 283
rlm@1 284 TempFiles::CleanOutGarbageRegistry();
rlm@1 285 }
rlm@1 286
rlm@1 287 // run this on startup to delete any files that we failed to delete last time
rlm@1 288 // in case we crashed or were forcefully terminated
rlm@1 289 TempFiles()
rlm@1 290 {
rlm@1 291 TempFiles::CleanOutGarbageRegistry();
rlm@1 292 }
rlm@1 293
rlm@1 294 static void AddEntryToGarbageRegistry(const char* filename)
rlm@1 295 {
rlm@1 296 char gbgFile[2048];
rlm@1 297 GetTempPath(2048, gbgFile);
rlm@1 298 strcat(gbgFile, "VBATempFileRecords");
rlm@1 299 char key[64];
rlm@1 300 int i = 0;
rlm@1 301 while(true)
rlm@1 302 {
rlm@1 303 sprintf(key, "File%d", i);
rlm@1 304 GetPrivateProfileString("Files", key, "", Str_Tmp, 2048, gbgFile);
rlm@1 305 if(!*Str_Tmp)
rlm@1 306 break;
rlm@1 307 i++;
rlm@1 308 }
rlm@1 309 WritePrivateProfileString("Files", key, filename, gbgFile);
rlm@1 310 }
rlm@1 311 static bool RemoveEntryFromGarbageRegistry(const char* filename)
rlm@1 312 {
rlm@1 313 char gbgFile[2048];
rlm@1 314 GetTempPath(2048, gbgFile);
rlm@1 315 strcat(gbgFile, "VBATempFileRecords");
rlm@1 316 char key[64];
rlm@1 317 int i = 0;
rlm@1 318 int deleteSlot = -1;
rlm@1 319 while(true)
rlm@1 320 {
rlm@1 321 sprintf(key, "File%d", i);
rlm@1 322 GetPrivateProfileString("Files", key, "", Str_Tmp, 2048, gbgFile);
rlm@1 323 if(!*Str_Tmp)
rlm@1 324 break;
rlm@1 325 if(!strcmp(Str_Tmp, filename))
rlm@1 326 deleteSlot = i;
rlm@1 327 i++;
rlm@1 328 }
rlm@1 329 --i;
rlm@1 330 if(i >= 0 && deleteSlot >= 0)
rlm@1 331 {
rlm@1 332 if(i != deleteSlot)
rlm@1 333 {
rlm@1 334 sprintf(key, "File%d", i);
rlm@1 335 GetPrivateProfileString("Files", key, "", Str_Tmp, 2048, gbgFile);
rlm@1 336 sprintf(key, "File%d", deleteSlot);
rlm@1 337 WritePrivateProfileString("Files", key, Str_Tmp, gbgFile);
rlm@1 338 }
rlm@1 339 sprintf(key, "File%d", i);
rlm@1 340 if(0 == WritePrivateProfileString("Files", key, NULL, gbgFile))
rlm@1 341 return false;
rlm@1 342 }
rlm@1 343 if(i <= 0 && deleteSlot == 0)
rlm@1 344 _unlink(gbgFile);
rlm@1 345 return true;
rlm@1 346 }
rlm@1 347
rlm@1 348 private:
rlm@1 349 static void CleanOutGarbageRegistry()
rlm@1 350 {
rlm@1 351 char gbgFile[2048];
rlm@1 352 GetTempPath(2048, gbgFile);
rlm@1 353 strcat(gbgFile, "VBATempFileRecords");
rlm@1 354
rlm@1 355 char key[64];
rlm@1 356 int i = 0;
rlm@1 357 while(true)
rlm@1 358 {
rlm@1 359 sprintf(key, "File%d", i);
rlm@1 360 GetPrivateProfileString("Files", key, "", Str_Tmp, 2048, gbgFile);
rlm@1 361 if(!*Str_Tmp)
rlm@1 362 break;
rlm@1 363 TemporaryFile temp;
rlm@1 364 strcpy(temp.filename, Str_Tmp);
rlm@1 365 if(!temp.Delete(true))
rlm@1 366 i++;
rlm@1 367 }
rlm@1 368 }
rlm@1 369
rlm@1 370 } s_tempFiles;
rlm@1 371
rlm@1 372
rlm@1 373 const char* GetTempFile(const char* category, const char* extension)
rlm@1 374 {
rlm@1 375 return s_tempFiles.GetFile(category, extension);
rlm@1 376 }
rlm@1 377 void ReleaseTempFile(const char* filename)
rlm@1 378 {
rlm@1 379 s_tempFiles.ReleaseFile(filename);
rlm@1 380 }
rlm@1 381 void ReleaseTempFileCategory(const char* cat, const char* exceptionFilename)
rlm@1 382 {
rlm@1 383 if(!cat || !*cat) cat = DEFAULT_CATEGORY;
rlm@1 384 s_tempFiles.ReleaseCategory(cat, exceptionFilename);
rlm@1 385 }
rlm@1 386
rlm@1 387
rlm@1 388
rlm@1 389 // example input Name: "C:\games.zip"
rlm@1 390 // example output LogicalName: "C:\games.zip|Metroid.gba"
rlm@1 391 // example output PhysicalName: "C:\Documents and Settings\User\Local Settings\Temp\VBA\rom7A37.gba"
rlm@1 392 // assumes arguments are character buffers with 2048 bytes each
rlm@1 393 bool ObtainFile(const char* Name, char *const & LogicalName, char *const & PhysicalName, const char* category, const char** ignoreExtensions, int numIgnoreExtensions)
rlm@1 394 {
rlm@1 395 restart:
rlm@1 396 char ArchivePaths [2048];
rlm@1 397 strcpy(LogicalName, Name);
rlm@1 398 strcpy(PhysicalName, Name);
rlm@1 399 strcpy(ArchivePaths, Name);
rlm@1 400 char* bar = strchr(ArchivePaths, '|');
rlm@1 401 if(bar)
rlm@1 402 {
rlm@1 403 PhysicalName[bar - ArchivePaths] = 0; // doesn't belong in the physical name
rlm@1 404 LogicalName[bar - ArchivePaths] = 0; // we'll reconstruct the logical name as we go
rlm@1 405 *bar++ = 0; // bar becomes the next logical archive path component
rlm@1 406 }
rlm@1 407
rlm@1 408 bool userSelected = false;
rlm@1 409
rlm@1 410 while(true)
rlm@1 411 {
rlm@1 412 ArchiveFile archive (PhysicalName, LogicalName);
rlm@1 413 if(!archive.IsCompressed())
rlm@1 414 {
rlm@1 415 if(archive.GetNumItems() > 0)
rlm@1 416 return true;
rlm@1 417 else
rlm@1 418 {
rlm@1 419 // failed or cancelled... backtrack to outermost archive if not already there
rlm@1 420 char* div = NULL;
rlm@1 421 if(LogicalName[strlen(LogicalName)-1] == '|')
rlm@1 422 {
rlm@1 423 LogicalName[strlen(LogicalName)-1] = '\0';
rlm@1 424 div = strrchr(LogicalName, '|');
rlm@1 425 }
rlm@1 426 if(div && userSelected)
rlm@1 427 goto restart;
rlm@1 428 else
rlm@1 429 return false;
rlm@1 430 }
rlm@1 431 }
rlm@1 432 else
rlm@1 433 {
rlm@1 434 int item = -1;
rlm@1 435 bool forceManual = false;
rlm@1 436 if(bar && *bar) // try following the in-archive part of the logical path
rlm@1 437 {
rlm@1 438 char* bar2 = strchr(bar, '|');
rlm@1 439 if(bar2) *bar2++ = 0;
rlm@1 440 int numItems = archive.GetNumItems();
rlm@1 441 for(int i = 0; i < numItems; i++)
rlm@1 442 {
rlm@1 443 if(archive.GetItemSize(i))
rlm@1 444 {
rlm@1 445 const char* itemName = archive.GetItemName(i);
rlm@1 446 if(!_stricmp(itemName, bar))
rlm@1 447 {
rlm@1 448 item = i; // match found, now we'll auto-follow the path
rlm@1 449 break;
rlm@1 450 }
rlm@1 451 }
rlm@1 452 }
rlm@1 453 if(item < 0)
rlm@1 454 {
rlm@1 455 forceManual = true; // we don't want it choosing something else without user permission
rlm@1 456 bar = NULL; // remaining archive path is invalid
rlm@1 457 }
rlm@1 458 else
rlm@1 459 bar = bar2; // advance to next archive path part
rlm@1 460 }
rlm@1 461 if(item < 0)
rlm@1 462 item = ChooseItemFromArchive(archive, !forceManual, ignoreExtensions, numIgnoreExtensions);
rlm@1 463
rlm@1 464 userSelected |= archive.m_userMadeSelection;
rlm@1 465
rlm@1 466 const char* TempFileName = s_tempFiles.GetFile(category, strrchr(archive.GetItemName(item), '.'));
rlm@1 467 if(!archive.ExtractItem(item, TempFileName))
rlm@1 468 s_tempFiles.ReleaseFile(TempFileName);
rlm@1 469 s_tempFiles.ReleaseFile(PhysicalName);
rlm@1 470 strcpy(PhysicalName, TempFileName);
rlm@1 471 _snprintf(LogicalName + strlen(LogicalName), 2048 - (strlen(LogicalName)+1), "|%s", archive.GetItemName(item));
rlm@1 472 }
rlm@1 473 }
rlm@1 474 }
rlm@1 475
rlm@1 476
rlm@1 477
rlm@1 478 struct ControlLayoutInfo
rlm@1 479 {
rlm@1 480 int controlID;
rlm@1 481
rlm@1 482 enum LayoutType // what to do when the containing window resizes
rlm@1 483 {
rlm@1 484 NONE, // leave the control where it was
rlm@1 485 RESIZE_END, // resize the control
rlm@1 486 MOVE_START, // move the control
rlm@1 487 };
rlm@1 488 LayoutType horizontalLayout;
rlm@1 489 LayoutType verticalLayout;
rlm@1 490 };
rlm@1 491 struct ControlLayoutState
rlm@1 492 {
rlm@1 493 int x,y,width,height;
rlm@1 494 bool valid;
rlm@1 495 ControlLayoutState() : valid(false) {}
rlm@1 496 };
rlm@1 497
rlm@1 498 static ControlLayoutInfo controlLayoutInfos [] = {
rlm@1 499 {IDC_LIST1, ControlLayoutInfo::RESIZE_END, ControlLayoutInfo::RESIZE_END},
rlm@1 500 {IDOK, ControlLayoutInfo::MOVE_START, ControlLayoutInfo::MOVE_START},
rlm@1 501 {ID_CANCEL, ControlLayoutInfo::MOVE_START, ControlLayoutInfo::MOVE_START},
rlm@1 502 };
rlm@1 503 static const int numControlLayoutInfos = sizeof(controlLayoutInfos)/sizeof(*controlLayoutInfos);
rlm@1 504
rlm@1 505 static ControlLayoutState s_layoutState [numControlLayoutInfos];
rlm@1 506 static int s_windowWidth = 182, s_windowHeight = 113;
rlm@1 507
rlm@1 508
rlm@1 509 LRESULT CALLBACK ArchiveFileChooser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
rlm@1 510 {
rlm@1 511 RECT r, r2;
rlm@1 512 int dx1, dy1, dx2, dy2;
rlm@1 513 static std::map<int,int> s_listToItemsMap;
rlm@1 514
rlm@1 515 switch(uMsg)
rlm@1 516 {
rlm@1 517 case WM_INITDIALOG:
rlm@1 518 {
rlm@1 519 //Clear_Sound_Buffer();
rlm@1 520
rlm@1 521 //if(Full_Screen)
rlm@1 522 //{
rlm@1 523 // while (ShowCursor(false) >= 0);
rlm@1 524 // while (ShowCursor(true) < 0);
rlm@1 525 //}
rlm@1 526
rlm@1 527 for(int i = 0; i < numControlLayoutInfos; i++)
rlm@1 528 s_layoutState[i].valid = false;
rlm@1 529
rlm@1 530 GetWindowRect(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), &r);
rlm@1 531 dx1 = (r.right - r.left) / 2;
rlm@1 532 dy1 = (r.bottom - r.top) / 2;
rlm@1 533
rlm@1 534 GetWindowRect(hDlg, &r2);
rlm@1 535 dx2 = (r2.right - r2.left) / 2;
rlm@1 536 dy2 = (r2.bottom - r2.top) / 2;
rlm@1 537
rlm@1 538 //SetWindowPos(hDlg, NULL, max(0, r.left + (dx1 - dx2)), max(0, r.top + (dy1 - dy2)), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
rlm@1 539 SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
rlm@1 540
rlm@1 541 ArchiveFileChooserInfo& info = *(ArchiveFileChooserInfo*)lParam;
rlm@1 542 std::vector<ArchiveFileChooserInfo::FileInfo>& files = info.files;
rlm@1 543 ArchiveFile& archive = info.archive;
rlm@1 544
rlm@1 545 std::string title = "Choose File in ";
rlm@1 546 title += archive.GetArchiveTypeName();
rlm@1 547 title += " Archive";
rlm@1 548 SetWindowText(hDlg, title.c_str());
rlm@1 549
rlm@1 550 // populate list
rlm@1 551 for(size_t i = 0; i < files.size(); i++)
rlm@1 552 {
rlm@1 553 int listIndex = SendDlgItemMessage(hDlg, IDC_LIST1, LB_ADDSTRING, (WPARAM) 0, (LONG) (LPTSTR) files[i].name.c_str());
rlm@1 554 s_listToItemsMap[listIndex] = files[i].itemIndex;
rlm@1 555 }
rlm@1 556
rlm@1 557 SendDlgItemMessage(hDlg, IDC_LIST1, LB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
rlm@1 558
rlm@1 559 {
rlm@1 560 RECT r3;
rlm@1 561 GetClientRect(hDlg, &r3);
rlm@1 562 s_windowWidth = r3.right - r3.left;
rlm@1 563 s_windowHeight = r3.bottom - r3.top;
rlm@1 564 }
rlm@1 565
rlm@1 566 return true;
rlm@1 567 } break;
rlm@1 568
rlm@1 569 case WM_SIZING:
rlm@1 570 {
rlm@1 571 // enforce a minimum window size
rlm@1 572
rlm@1 573 LPRECT r = (LPRECT) lParam;
rlm@1 574 int minimumWidth = 281;
rlm@1 575 int minimumHeight = 117;
rlm@1 576 if(r->right - r->left < minimumWidth)
rlm@1 577 if(wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT)
rlm@1 578 r->left = r->right - minimumWidth;
rlm@1 579 else
rlm@1 580 r->right = r->left + minimumWidth;
rlm@1 581 if(r->bottom - r->top < minimumHeight)
rlm@1 582 if(wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT)
rlm@1 583 r->top = r->bottom - minimumHeight;
rlm@1 584 else
rlm@1 585 r->bottom = r->top + minimumHeight;
rlm@1 586 return TRUE;
rlm@1 587 }
rlm@1 588
rlm@1 589 case WM_SIZE:
rlm@1 590 {
rlm@1 591 // resize or move controls in the window as necessary when the window is resized
rlm@1 592
rlm@1 593 int prevDlgWidth = s_windowWidth;
rlm@1 594 int prevDlgHeight = s_windowHeight;
rlm@1 595
rlm@1 596 int dlgWidth = LOWORD(lParam);
rlm@1 597 int dlgHeight = HIWORD(lParam);
rlm@1 598
rlm@1 599 int deltaWidth = dlgWidth - prevDlgWidth;
rlm@1 600 int deltaHeight = dlgHeight - prevDlgHeight;
rlm@1 601
rlm@1 602 for(int i = 0; i < numControlLayoutInfos; i++)
rlm@1 603 {
rlm@1 604 ControlLayoutInfo layoutInfo = controlLayoutInfos[i];
rlm@1 605 ControlLayoutState& layoutState = s_layoutState[i];
rlm@1 606
rlm@1 607 HWND hCtrl = GetDlgItem(hDlg,layoutInfo.controlID);
rlm@1 608
rlm@1 609 int x,y,width,height;
rlm@1 610 if(layoutState.valid)
rlm@1 611 {
rlm@1 612 x = layoutState.x;
rlm@1 613 y = layoutState.y;
rlm@1 614 width = layoutState.width;
rlm@1 615 height = layoutState.height;
rlm@1 616 }
rlm@1 617 else
rlm@1 618 {
rlm@1 619 RECT r;
rlm@1 620 GetWindowRect(hCtrl, &r);
rlm@1 621 POINT p = {r.left, r.top};
rlm@1 622 ScreenToClient(hDlg, &p);
rlm@1 623 x = p.x;
rlm@1 624 y = p.y;
rlm@1 625 width = r.right - r.left;
rlm@1 626 height = r.bottom - r.top;
rlm@1 627 }
rlm@1 628
rlm@1 629 switch(layoutInfo.horizontalLayout)
rlm@1 630 {
rlm@1 631 case ControlLayoutInfo::RESIZE_END: width += deltaWidth; break;
rlm@1 632 case ControlLayoutInfo::MOVE_START: x += deltaWidth; break;
rlm@1 633 default: break;
rlm@1 634 }
rlm@1 635 switch(layoutInfo.verticalLayout)
rlm@1 636 {
rlm@1 637 case ControlLayoutInfo::RESIZE_END: height += deltaHeight; break;
rlm@1 638 case ControlLayoutInfo::MOVE_START: y += deltaHeight; break;
rlm@1 639 default: break;
rlm@1 640 }
rlm@1 641
rlm@1 642 SetWindowPos(hCtrl, 0, x,y, width,height, 0);
rlm@1 643
rlm@1 644 layoutState.x = x;
rlm@1 645 layoutState.y = y;
rlm@1 646 layoutState.width = width;
rlm@1 647 layoutState.height = height;
rlm@1 648 layoutState.valid = true;
rlm@1 649 }
rlm@1 650
rlm@1 651 s_windowWidth = dlgWidth;
rlm@1 652 s_windowHeight = dlgHeight;
rlm@1 653
rlm@1 654 RedrawWindow(hDlg, NULL, NULL, RDW_INVALIDATE);
rlm@1 655 }
rlm@1 656 break;
rlm@1 657
rlm@1 658 case WM_COMMAND:
rlm@1 659 switch(LOWORD(wParam))
rlm@1 660 {
rlm@1 661 case IDC_LIST1:
rlm@1 662 if(HIWORD(wParam) == LBN_DBLCLK)
rlm@1 663 {
rlm@1 664 POINT pos;
rlm@1 665 GetCursorPos(&pos);
rlm@1 666 int clickedItem = LBItemFromPt(GetDlgItem(hDlg, IDC_LIST1), pos, FALSE);
rlm@1 667 if(clickedItem != -1)
rlm@1 668 {
rlm@1 669 SendMessage(hDlg, WM_COMMAND, IDOK, 0);
rlm@1 670 }
rlm@1 671 }
rlm@1 672 return TRUE;
rlm@1 673
rlm@1 674 case IDOK:
rlm@1 675 {
rlm@1 676 int listIndex = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
rlm@1 677 s_archiveFileChooserResult = s_listToItemsMap[listIndex];
rlm@1 678 s_listToItemsMap.clear();
rlm@1 679 //if(Full_Screen)
rlm@1 680 //{
rlm@1 681 // while (ShowCursor(true) < 0);
rlm@1 682 // while (ShowCursor(false) >= 0);
rlm@1 683 //}
rlm@1 684 EndDialog(hDlg, false);
rlm@1 685 } return TRUE;
rlm@1 686
rlm@1 687 case ID_CANCEL:
rlm@1 688 case IDCANCEL:
rlm@1 689 s_archiveFileChooserResult = -1;
rlm@1 690 s_listToItemsMap.clear();
rlm@1 691 //if(Full_Screen)
rlm@1 692 //{
rlm@1 693 // while (ShowCursor(true) < 0);
rlm@1 694 // while (ShowCursor(false) >= 0);
rlm@1 695 //}
rlm@1 696 EndDialog(hDlg, false);
rlm@1 697 return TRUE;
rlm@1 698 }
rlm@1 699
rlm@1 700 case WM_CLOSE:
rlm@1 701 s_archiveFileChooserResult = -1;
rlm@1 702 s_listToItemsMap.clear();
rlm@1 703 //if(Full_Screen)
rlm@1 704 //{
rlm@1 705 // while (ShowCursor(true) < 0);
rlm@1 706 // while (ShowCursor(false) >= 0);
rlm@1 707 //}
rlm@1 708 EndDialog(hDlg, false);
rlm@1 709 return TRUE;
rlm@1 710 }
rlm@1 711
rlm@1 712 return false;
rlm@1 713 }