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 }
|