1 /*****************************************************************************/
2 /* SFileFindFile.cpp Copyright (c) Ladislav Zezula 2003 */
3 /*---------------------------------------------------------------------------*/
4 /* A module for file searching within MPQs */
5 /*---------------------------------------------------------------------------*/
6 /* Date Ver Who Comment */
7 /* -------- ---- --- ------- */
8 /* 25.03.03 1.00 Lad The first version of SFileFindFile.cpp */
9 /*****************************************************************************/
11 #define __STORMLIB_SELF__
15 //-----------------------------------------------------------------------------
18 #define LISTFILE_CACHE_SIZE 0x1000
20 //-----------------------------------------------------------------------------
23 static BOOL
IsValidSearchHandle(TMPQSearch
* hs
)
25 if(hs
== NULL
|| IsBadReadPtr(hs
, sizeof(TMPQSearch
)))
28 if(!IsValidMpqHandle(hs
->ha
))
34 // This function compares a string with a wildcard search string.
35 // returns TRUE, when the string matches with the wildcard.
36 BOOL
CheckWildCard(const char * szString
, const char * szWildCard
)
38 char * szTemp
; // Temporary helper pointer
39 int nResult
= 0; // For memcmp return values
40 int nMustNotMatch
= 0; // Number of following chars int szString,
41 // which must not match with szWildCard
42 int nMustMatch
= 0; // Number of the following characters,
45 // When the string is empty, it does not match with every wildcard
49 // When the mask is empty, it matches to every wildcard
50 if(szWildCard
== NULL
|| *szWildCard
== 0)
58 case '*': // Means "every number of characters"
60 while(*szWildCard
== '*')
63 // When no more characters in wildcard, it means that the strings match
67 // The next N characters must not agree
68 nMustNotMatch
|= 0x70000000;
71 case '?': // Means "One or no character"
72 while(*szWildCard
== '?')
80 // If the two characters match
81 if(toupper(*szString
) == toupper(*szWildCard
))
83 // When end of string, they agree
93 // If the next character must match, the string does not match
94 if(nMustNotMatch
== 0)
97 // Count the characters which must match after characters
98 // that must not match
99 szTemp
= (char *)szWildCard
;
101 while(*szTemp
!= 0 && *szTemp
!= '*' && *szTemp
!= '?')
107 // Now skip characters from szString up to number of chars
108 // that must not match
110 while(nMustNotMatch
> 0 && *szString
!= 0)
112 if((nResult
= _strnicmp(szString
, szWildCard
, nMustMatch
)) == 0)
119 // Make one more comparison
120 if(nMustNotMatch
== 0)
121 nResult
= _strnicmp(szString
, szWildCard
, nMustMatch
);
123 // If a match has been found, continue the search
127 szWildCard
+= nMustMatch
;
128 szString
+= nMustMatch
;
136 // Performs one MPQ search
137 // TODO: Test for archives > 4GB
138 static int DoMPQSearch(TMPQSearch
* hs
, SFILE_FIND_DATA
* lpFindFileData
)
140 TMPQArchive
* ha
= hs
->ha
;
142 TMPQHash
* pHashEnd
= ha
->pHashTable
+ ha
->pHeader
->dwHashTableSize
;
143 TMPQHash
* pHash
= ha
->pHashTable
+ hs
->dwNextIndex
;
145 // Do until some file found or no more files
146 while(pHash
< pHashEnd
)
148 pNode
= ha
->pListFile
[hs
->dwNextIndex
++];
150 // If this entry is free, do nothing
151 if(pHash
->dwBlockIndex
< HASH_ENTRY_FREE
&& (DWORD_PTR
)pNode
< HASH_ENTRY_FREE
)
153 // Check the file name.
154 if(CheckWildCard(pNode
->szFileName
, hs
->szSearchMask
))
156 TMPQBlock
* pBlock
= ha
->pBlockTable
+ pHash
->dwBlockIndex
;
158 lpFindFileData
->lcLocale
= pHash
->lcLocale
;
159 lpFindFileData
->dwFileSize
= pBlock
->dwFSize
;
160 lpFindFileData
->dwFileFlags
= pBlock
->dwFlags
;
161 lpFindFileData
->dwBlockIndex
= pHash
->dwBlockIndex
;
162 lpFindFileData
->dwCompSize
= pBlock
->dwCSize
;
164 // Fill the file name and plain file name
165 strcpy(lpFindFileData
->cFileName
, pNode
->szFileName
);
166 lpFindFileData
->szPlainName
= strrchr(lpFindFileData
->cFileName
, '\\');
167 if(lpFindFileData
->szPlainName
== NULL
)
168 lpFindFileData
->szPlainName
= lpFindFileData
->cFileName
;
170 lpFindFileData
->szPlainName
++;
172 // Fill the next entry
173 return ERROR_SUCCESS
;
180 // No more files found, return error
181 return ERROR_NO_MORE_FILES
;
184 // TODO: Test for archives > 4GB
185 static void FreeMPQSearch(TMPQSearch
*& hs
)
194 //-----------------------------------------------------------------------------
197 // TODO: Test for archives > 4GB
198 HANDLE WINAPI
SFileFindFirstFile(HANDLE hMPQ
, const char * szMask
, SFILE_FIND_DATA
* lpFindFileData
, const char * szListFile
)
200 TMPQArchive
* ha
= (TMPQArchive
*)hMPQ
;
201 TMPQSearch
* hs
= NULL
; // Search object handle
203 int nError
= ERROR_SUCCESS
;
205 // Check for the valid parameters
206 if(nError
== ERROR_SUCCESS
)
208 if(!IsValidMpqHandle(ha
))
209 nError
= ERROR_INVALID_PARAMETER
;
211 if(szMask
== NULL
|| lpFindFileData
== NULL
)
212 nError
= ERROR_INVALID_PARAMETER
;
214 if(szListFile
== NULL
&& !IsValidMpqHandle(ha
))
215 nError
= ERROR_INVALID_PARAMETER
;
218 // Include the listfile into the MPQ's internal listfile
219 // Note that if the listfile name is NULL, do nothing because the
220 // internal listfile is always included.
221 if(nError
== ERROR_SUCCESS
&& szListFile
!= NULL
)
222 nError
= SFileAddListFile((HANDLE
)ha
, szListFile
);
224 // Allocate the structure for MPQ search
225 if(nError
== ERROR_SUCCESS
)
227 nSize
= sizeof(TMPQSearch
) + strlen(szMask
) + 1;
228 if((hs
= (TMPQSearch
*)ALLOCMEM(char, nSize
)) == NULL
)
229 nError
= ERROR_NOT_ENOUGH_MEMORY
;
232 // Perform the first search
233 if(nError
== ERROR_SUCCESS
)
235 memset(hs
, 0, sizeof(TMPQSearch
));
238 strcpy(hs
->szSearchMask
, szMask
);
239 nError
= DoMPQSearch(hs
, lpFindFileData
);
243 if(nError
!= ERROR_SUCCESS
)
246 SetLastError(nError
);
249 // Return the result value
253 // TODO: Test for archives > 4GB
254 BOOL WINAPI
SFileFindNextFile(HANDLE hFind
, SFILE_FIND_DATA
* lpFindFileData
)
256 TMPQSearch
* hs
= (TMPQSearch
*)hFind
;
257 int nError
= ERROR_SUCCESS
;
259 // Check the parameters
260 if(nError
== ERROR_SUCCESS
)
262 if(!IsValidSearchHandle(hs
) || lpFindFileData
== NULL
)
263 nError
= ERROR_INVALID_PARAMETER
;
266 if(nError
== ERROR_SUCCESS
)
267 nError
= DoMPQSearch(hs
, lpFindFileData
);
269 if(nError
!= ERROR_SUCCESS
)
271 SetLastError(nError
);
277 // TODO: Test for archives > 4GB
278 BOOL WINAPI
SFileFindClose(HANDLE hFind
)
280 TMPQSearch
* hs
= (TMPQSearch
*)hFind
;
282 // Check the parameters
283 if(!IsValidSearchHandle(hs
))
285 SetLastError(ERROR_INVALID_PARAMETER
);