[4057] added: Line of sight (vmaps) [part 2] (last part)
[mangos-git.git] / contrib / vmap_extractor_v2 / stormlib / SFileOpenFileEx.cpp
blobcc9a7d735857167b3d3eeb60568ea36e6a3159dd
1 /*****************************************************************************/
2 /* SFileOpenFileEx.cpp Copyright (c) Ladislav Zezula 2003 */
3 /*---------------------------------------------------------------------------*/
4 /* Description : */
5 /*---------------------------------------------------------------------------*/
6 /* Date Ver Who Comment */
7 /* -------- ---- --- ------- */
8 /* xx.xx.99 1.00 Lad The first version of SFileOpenFileEx.cpp */
9 /*****************************************************************************/
11 #define __STORMLIB_SELF__
12 #include "StormLib.h"
13 #include "SCommon.h"
15 /*****************************************************************************/
16 /* Local functions */
17 /*****************************************************************************/
19 // TODO: Test for archives > 4GB
20 static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile)
22 TMPQFile * hf = NULL;
23 HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
25 if(hFile != INVALID_HANDLE_VALUE)
27 // Allocate and initialize file handle
28 size_t nHandleSize = sizeof(TMPQFile) + strlen(szFileName);
29 if((hf = (TMPQFile *)ALLOCMEM(char, nHandleSize)) != NULL)
31 memset(hf, 0, nHandleSize);
32 strcpy(hf->szFileName, szFileName);
33 hf->hFile = hFile;
34 *phFile = hf;
35 return TRUE;
37 else
38 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
40 *phFile = NULL;
41 return FALSE;
44 // TODO: Test for archives > 4GB
45 static void FreeMPQFile(TMPQFile *& hf)
47 if(hf != NULL)
49 if(hf->hFile != INVALID_HANDLE_VALUE)
50 CloseHandle(hf->hFile);
51 if(hf->pdwBlockPos != NULL)
52 FREEMEM(hf->pdwBlockPos);
53 if(hf->pbFileBuffer != NULL)
54 FREEMEM(hf->pbFileBuffer);
55 FREEMEM(hf);
56 hf = NULL;
60 /*****************************************************************************/
61 /* Public functions */
62 /*****************************************************************************/
64 //-----------------------------------------------------------------------------
65 // SFileEnumLocales enums all locale versions within MPQ.
66 // Functions fills all available language identifiers on a file into the buffer
67 // pointed by plcLocales. There must be enough entries to copy the localed,
68 // otherwise the function returns ERROR_INSUFFICIENT_BUFFER.
70 // TODO: Test for archives > 4GB
71 int WINAPI SFileEnumLocales(
72 HANDLE hMPQ,
73 const char * szFileName,
74 LCID * plcLocales,
75 DWORD * pdwMaxLocales,
76 DWORD dwSearchScope)
78 TMPQArchive * ha = (TMPQArchive *)hMPQ;
79 TMPQHash * pHash = NULL;
80 TMPQHash * pHashEnd = NULL;
81 DWORD dwLocales = 0;
82 int nError = ERROR_SUCCESS;
84 // Test the parameters
85 if(nError == ERROR_SUCCESS)
87 if(!IsValidMpqHandle(ha) || pdwMaxLocales == NULL)
88 nError = ERROR_INVALID_PARAMETER;
89 if(dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
90 nError = ERROR_INVALID_PARAMETER;
91 if(dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0)
92 nError = ERROR_INVALID_PARAMETER;
95 // Retrieve the hash entry for the required file
96 if(nError == ERROR_SUCCESS)
98 pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
100 if(dwSearchScope == SFILE_OPEN_BY_INDEX)
102 for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
104 if(pHash->dwBlockIndex == (DWORD_PTR)szFileName)
105 break;
107 if(pHash == pHashEnd)
108 pHash = NULL;
110 else
111 pHash = GetHashEntry(ha, szFileName);
114 // If the file was not found, sorry
115 if(nError == ERROR_SUCCESS)
117 if(pHash == NULL)
118 nError = ERROR_FILE_NOT_FOUND;
121 // Count the entries which correspond to the same file name
122 if(nError == ERROR_SUCCESS)
124 TMPQHash * pSaveHash = pHash;
125 DWORD dwName1 = pHash->dwName1;
126 DWORD dwName2 = pHash->dwName2;
128 // For nameless access, return 1 locale always
129 if(dwSearchScope == SFILE_OPEN_BY_INDEX)
130 dwLocales++;
131 else
133 while(pHash < pHashEnd && pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2)
135 dwLocales++;
136 pHash++;
140 pHash = pSaveHash;
143 // Test if there is enough space to copy the locales
144 if(nError == ERROR_SUCCESS)
146 DWORD dwMaxLocales = *pdwMaxLocales;
148 *pdwMaxLocales = dwLocales;
149 if(dwMaxLocales < dwLocales)
150 nError = ERROR_INSUFFICIENT_BUFFER;
153 // Fill all the locales
154 if(nError == ERROR_SUCCESS)
156 for(DWORD i = 0; i < dwLocales; i++, pHash++)
157 *plcLocales++ = (LCID)pHash->lcLocale;
159 return nError;
162 //-----------------------------------------------------------------------------
163 // SFileHasFile
165 // hMPQ - Handle of opened MPQ archive
166 // szFileName - Name of file to look for
168 // TODO: Test for archives > 4GB
169 BOOL WINAPI SFileHasFile(HANDLE hMPQ, char * szFileName)
171 TMPQArchive * ha = (TMPQArchive *)hMPQ;
172 int nError = ERROR_SUCCESS;
174 if(nError == ERROR_SUCCESS)
176 if(ha == NULL)
177 nError = ERROR_INVALID_PARAMETER;
178 if(*szFileName == 0)
179 nError = ERROR_INVALID_PARAMETER;
182 // Prepare the file opening
183 if(nError == ERROR_SUCCESS)
185 if(GetHashEntryEx(ha, szFileName, lcLocale) == NULL)
187 nError = ERROR_FILE_NOT_FOUND;
191 // Cleanup
192 if(nError != ERROR_SUCCESS)
194 SetLastError(nError);
197 return (nError == ERROR_SUCCESS);
201 //-----------------------------------------------------------------------------
202 // SFileOpenFileEx
204 // hMPQ - Handle of opened MPQ archive
205 // szFileName - Name of file to open
206 // dwSearchScope - Where to search
207 // phFile - Pointer to store opened file handle
209 // TODO: Test for archives > 4GB
210 BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
212 LARGE_INTEGER FilePos;
213 TMPQArchive * ha = (TMPQArchive *)hMPQ;
214 TMPQFile * hf = NULL;
215 TMPQHash * pHash = NULL; // Hash table index
216 TMPQBlock * pBlock = NULL; // File block
217 TMPQBlockEx * pBlockEx = NULL;
218 DWORD dwHashIndex = 0; // Hash table index
219 DWORD dwBlockIndex = (DWORD)-1; // Found table index
220 size_t nHandleSize = 0; // Memory space necessary to allocate TMPQHandle
221 int nError = ERROR_SUCCESS;
223 #ifdef _DEBUG
224 // Due to increasing numbers of files in MPQs, I had to change the behavior
225 // of opening by file index. Now, the SFILE_OPEN_BY_INDEX value of dwSearchScope
226 // must be entered. This check will allow to find code places that are incompatible
227 // with the new behavior.
228 if(dwSearchScope != SFILE_OPEN_BY_INDEX && szFileName != NULL)
230 assert((DWORD_PTR)szFileName > 0x10000);
232 #endif
234 if(nError == ERROR_SUCCESS)
236 if(ha == NULL && dwSearchScope == SFILE_OPEN_FROM_MPQ)
237 nError = ERROR_INVALID_PARAMETER;
238 if(phFile == NULL)
239 nError = ERROR_INVALID_PARAMETER;
240 if(dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
241 nError = ERROR_INVALID_PARAMETER;
242 if(dwSearchScope != SFILE_OPEN_BY_INDEX && (szFileName == NULL || *szFileName == 0))
243 nError = ERROR_INVALID_PARAMETER;
246 // Prepare the file opening
247 if(nError == ERROR_SUCCESS)
249 // When the file is given by number, ...
250 if(dwSearchScope == SFILE_OPEN_BY_INDEX)
252 TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
254 // Set handle size to be sizeof(TMPQFile) + length of FileXXXXXXXX.xxx
255 nHandleSize = sizeof(TMPQFile) + 20;
256 for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
258 if((DWORD_PTR)szFileName == pHash->dwBlockIndex)
260 dwHashIndex = (DWORD)(pHash - ha->pHashTable);
261 dwBlockIndex = pHash->dwBlockIndex;
262 break;
266 else
268 // If we have to open a disk file
269 if(dwSearchScope == SFILE_OPEN_LOCAL_FILE)
270 return OpenLocalFile(szFileName, phFile);
272 nHandleSize = sizeof(TMPQFile) + strlen(szFileName);
273 if((pHash = GetHashEntryEx(ha, szFileName, lcLocale)) != NULL)
275 dwHashIndex = (DWORD)(pHash - ha->pHashTable);
276 dwBlockIndex = pHash->dwBlockIndex;
281 // Get block index from file name and test it
282 if(nError == ERROR_SUCCESS)
284 // If index was not found, or is greater than number of files, exit.
285 if(dwBlockIndex == (DWORD)-1 || dwBlockIndex > ha->pHeader->dwBlockTableSize)
286 nError = ERROR_FILE_NOT_FOUND;
289 // Get block and test if the file was not already deleted.
290 if(nError == ERROR_SUCCESS)
292 // Get both block tables and file position
293 pBlockEx = ha->pExtBlockTable + dwBlockIndex;
294 pBlock = ha->pBlockTable + dwBlockIndex;
295 FilePos.HighPart = pBlockEx->wFilePosHigh;
296 FilePos.LowPart = pBlock->dwFilePos;
298 if(FilePos.QuadPart > ha->MpqSize.QuadPart ||
299 pBlock->dwCSize > ha->MpqSize.QuadPart)
300 nError = ERROR_FILE_CORRUPT;
301 if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0)
302 nError = ERROR_FILE_NOT_FOUND;
303 if(pBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS)
304 nError = ERROR_NOT_SUPPORTED;
307 // Allocate file handle
308 if(nError == ERROR_SUCCESS)
310 if((hf = (TMPQFile *)ALLOCMEM(char, nHandleSize)) == NULL)
311 nError = ERROR_NOT_ENOUGH_MEMORY;
314 // Initialize file handle
315 if(nError == ERROR_SUCCESS)
317 memset(hf, 0, nHandleSize);
318 hf->hFile = INVALID_HANDLE_VALUE;
319 hf->ha = ha;
320 hf->pBlockEx = pBlockEx;
321 hf->pBlock = pBlock;
322 hf->nBlocks = (hf->pBlock->dwFSize + ha->dwBlockSize - 1) / ha->dwBlockSize;
323 hf->pHash = pHash;
325 hf->MpqFilePos.HighPart = pBlockEx->wFilePosHigh;
326 hf->MpqFilePos.LowPart = pBlock->dwFilePos;
327 hf->MpqFilePos.QuadPart += ha->MpqPos.QuadPart;
329 hf->dwHashIndex = dwHashIndex;
330 hf->dwFileIndex = dwBlockIndex;
332 // Allocate buffers for decompression.
333 if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
335 // Allocate buffer for block positions. At the begin of file are stored
336 // DWORDs holding positions of each block relative from begin of file in the archive
337 // As for newer MPQs, there may be one additional entry in the block table
338 // (if the MPQ_FILE_HAS_EXTRA flag is set).
339 // Allocate the buffer to include this DWORD as well
341 if((hf->pdwBlockPos = ALLOCMEM(DWORD, hf->nBlocks + 2)) == NULL)
342 nError = ERROR_NOT_ENOUGH_MEMORY;
345 // Decrypt file seed. Cannot be used if the file is given by index
346 if(dwSearchScope != SFILE_OPEN_BY_INDEX)
348 if(hf->pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
350 const char * szTemp = strrchr(szFileName, '\\');
352 strcpy(hf->szFileName, szFileName);
353 if(szTemp != NULL)
354 szFileName = szTemp + 1;
355 hf->dwSeed1 = DecryptFileSeed((char *)szFileName);
357 if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
359 hf->dwSeed1 = (hf->dwSeed1 + hf->pBlock->dwFilePos) ^ hf->pBlock->dwFSize;
363 else
365 // If the file is encrypted and not compressed, we cannot detect the file seed
366 if(SFileGetFileName(hf, hf->szFileName) == FALSE)
367 nError = GetLastError();
371 // Cleanup
372 if(nError != ERROR_SUCCESS)
374 FreeMPQFile(hf);
375 SetLastError(nError);
378 *phFile = hf;
379 return (nError == ERROR_SUCCESS);
382 //-----------------------------------------------------------------------------
383 // BOOL SFileCloseFile(HANDLE hFile);
385 // TODO: Test for archives > 4GB
386 BOOL WINAPI SFileCloseFile(HANDLE hFile)
388 TMPQFile * hf = (TMPQFile *)hFile;
390 if(!IsValidFileHandle(hf))
392 SetLastError(ERROR_INVALID_PARAMETER);
393 return FALSE;
396 // Set the last accessed file in the archive
397 if(hf->ha != NULL)
398 hf->ha->pLastFile = NULL;
400 // Free the structure
401 FreeMPQFile(hf);
402 return TRUE;