00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #if defined(WIN32)|defined(_WIN32)
00024 #include <windows.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #else
00028 #include <glob.h>
00029 #include <sys/stat.h>
00030 #include <unistd.h>
00031 #endif
00032
00033 #include "qbsp.h"
00034
00035
00036 typedef struct qfile_exttype_s
00037 {
00038 char *extension;
00039 int type;
00040 } qfile_exttyp_t;
00041
00042 qfile_exttyp_t quakefiletypes[] =
00043 {
00044 {QFILEEXT_UNKNOWN, QFILETYPE_UNKNOWN},
00045 {QFILEEXT_PAK, QFILETYPE_PAK},
00046 {QFILEEXT_PK3, QFILETYPE_PK3},
00047 {QFILEEXT_SIN, QFILETYPE_PAK},
00048 {QFILEEXT_BSP, QFILETYPE_BSP},
00049 {QFILEEXT_MAP, QFILETYPE_MAP},
00050 {QFILEEXT_MDL, QFILETYPE_MDL},
00051 {QFILEEXT_MD2, QFILETYPE_MD2},
00052 {QFILEEXT_MD3, QFILETYPE_MD3},
00053 {QFILEEXT_WAL, QFILETYPE_WAL},
00054 {QFILEEXT_WAV, QFILETYPE_WAV},
00055 {QFILEEXT_AAS, QFILETYPE_AAS},
00056 {NULL, 0}
00057 };
00058
00059
00060
00061
00062
00063
00064
00065 int QuakeFileExtensionType(char *extension)
00066 {
00067 int i;
00068
00069 for (i = 0; quakefiletypes[i].extension; i++)
00070 {
00071 if (!stricmp(extension, quakefiletypes[i].extension))
00072 {
00073 return quakefiletypes[i].type;
00074 }
00075 }
00076 return QFILETYPE_UNKNOWN;
00077 }
00078
00079
00080
00081
00082
00083
00084 char *QuakeFileTypeExtension(int type)
00085 {
00086 int i;
00087
00088 for (i = 0; quakefiletypes[i].extension; i++)
00089 {
00090 if (quakefiletypes[i].type == type)
00091 {
00092 return quakefiletypes[i].extension;
00093 }
00094 }
00095 return QFILEEXT_UNKNOWN;
00096 }
00097
00098
00099
00100
00101
00102
00103 int QuakeFileType(char *filename)
00104 {
00105 char ext[_MAX_PATH] = ".";
00106
00107 ExtractFileExtension(filename, ext+1);
00108 return QuakeFileExtensionType(ext);
00109 }
00110
00111
00112
00113
00114
00115
00116 char *StringContains(char *str1, char *str2, int casesensitive)
00117 {
00118 int len, i, j;
00119
00120 len = strlen(str1) - strlen(str2);
00121 for (i = 0; i <= len; i++, str1++)
00122 {
00123 for (j = 0; str2[j]; j++)
00124 {
00125 if (casesensitive)
00126 {
00127 if (str1[j] != str2[j]) break;
00128 }
00129 else
00130 {
00131 if (toupper(str1[j]) != toupper(str2[j])) break;
00132 }
00133 }
00134 if (!str2[j]) return str1;
00135 }
00136 return NULL;
00137 }
00138
00139
00140
00141
00142
00143
00144 int FileFilter(char *filter, char *filename, int casesensitive)
00145 {
00146 char buf[1024];
00147 char *ptr;
00148 int i, found;
00149
00150 while(*filter)
00151 {
00152 if (*filter == '*')
00153 {
00154 filter++;
00155 for (i = 0; *filter; i++)
00156 {
00157 if (*filter == '*' || *filter == '?') break;
00158 buf[i] = *filter;
00159 filter++;
00160 }
00161 buf[i] = '\0';
00162 if (strlen(buf))
00163 {
00164 ptr = StringContains(filename, buf, casesensitive);
00165 if (!ptr) return false;
00166 filename = ptr + strlen(buf);
00167 }
00168 }
00169 else if (*filter == '?')
00170 {
00171 filter++;
00172 filename++;
00173 }
00174 else if (*filter == '[' && *(filter+1) == '[')
00175 {
00176 filter++;
00177 }
00178 else if (*filter == '[')
00179 {
00180 filter++;
00181 found = false;
00182 while(*filter && !found)
00183 {
00184 if (*filter == ']' && *(filter+1) != ']') break;
00185 if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']'))
00186 {
00187 if (casesensitive)
00188 {
00189 if (*filename >= *filter && *filename <= *(filter+2)) found = true;
00190 }
00191 else
00192 {
00193 if (toupper(*filename) >= toupper(*filter) &&
00194 toupper(*filename) <= toupper(*(filter+2))) found = true;
00195 }
00196 filter += 3;
00197 }
00198 else
00199 {
00200 if (casesensitive)
00201 {
00202 if (*filter == *filename) found = true;
00203 }
00204 else
00205 {
00206 if (toupper(*filter) == toupper(*filename)) found = true;
00207 }
00208 filter++;
00209 }
00210 }
00211 if (!found) return false;
00212 while(*filter)
00213 {
00214 if (*filter == ']' && *(filter+1) != ']') break;
00215 filter++;
00216 }
00217 filter++;
00218 filename++;
00219 }
00220 else
00221 {
00222 if (casesensitive)
00223 {
00224 if (*filter != *filename) return false;
00225 }
00226 else
00227 {
00228 if (toupper(*filter) != toupper(*filename)) return false;
00229 }
00230 filter++;
00231 filename++;
00232 }
00233 }
00234 return true;
00235 }
00236
00237
00238
00239
00240
00241
00242 quakefile_t *FindQuakeFilesInZip(char *zipfile, char *filter)
00243 {
00244 unzFile uf;
00245 int err;
00246 unz_global_info gi;
00247 char filename_inzip[MAX_PATH];
00248 unz_file_info file_info;
00249 int i;
00250 quakefile_t *qfiles, *lastqf, *qf;
00251
00252 uf = unzOpen(zipfile);
00253 err = unzGetGlobalInfo(uf, &gi);
00254
00255 if (err != UNZ_OK) return NULL;
00256
00257 unzGoToFirstFile(uf);
00258
00259 qfiles = NULL;
00260 lastqf = NULL;
00261 for (i = 0; i < gi.number_entry; i++)
00262 {
00263 err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL,0,NULL,0);
00264 if (err != UNZ_OK) break;
00265
00266 ConvertPath(filename_inzip);
00267 if (FileFilter(filter, filename_inzip, false))
00268 {
00269 qf = malloc(sizeof(quakefile_t));
00270 if (!qf) Error("out of memory");
00271 memset(qf, 0, sizeof(quakefile_t));
00272 strcpy(qf->pakfile, zipfile);
00273 strcpy(qf->filename, zipfile);
00274 strcpy(qf->origname, filename_inzip);
00275 qf->zipfile = true;
00276
00277 memcpy(&qf->zipinfo, (unz_s*)uf, sizeof(unz_s));
00278 qf->offset = 0;
00279 qf->length = file_info.uncompressed_size;
00280 qf->type = QuakeFileType(filename_inzip);
00281
00282 qf->next = NULL;
00283 if (lastqf) lastqf->next = qf;
00284 else qfiles = qf;
00285 lastqf = qf;
00286 }
00287 unzGoToNextFile(uf);
00288 }
00289
00290 unzClose(uf);
00291
00292 return qfiles;
00293 }
00294
00295
00296
00297
00298
00299
00300 quakefile_t *FindQuakeFilesInPak(char *pakfile, char *filter)
00301 {
00302 FILE *fp;
00303 dpackheader_t packheader;
00304 dsinpackfile_t *packfiles;
00305 dpackfile_t *idpackfiles;
00306 quakefile_t *qfiles, *lastqf, *qf;
00307 int numpackdirs, i;
00308
00309 qfiles = NULL;
00310 lastqf = NULL;
00311
00312 fp = fopen(pakfile, "rb");
00313 if (!fp)
00314 {
00315 Warning("can't open pak file %s", pakfile);
00316 return NULL;
00317 }
00318
00319 if ((fread(&packheader, 1, sizeof(dpackheader_t), fp) != sizeof(dpackheader_t))
00320 || (packheader.ident != IDPAKHEADER && packheader.ident != SINPAKHEADER)
00321 || (fseek(fp, LittleLong(packheader.dirofs), SEEK_SET))
00322 )
00323 {
00324 fclose(fp);
00325 Warning("invalid pak file %s", pakfile);
00326 return NULL;
00327 }
00328
00329 if (packheader.ident == IDPAKHEADER)
00330 {
00331
00332 numpackdirs = LittleLong(packheader.dirlen) / sizeof(dpackfile_t);
00333 idpackfiles = (dpackfile_t *) malloc(numpackdirs * sizeof(dpackfile_t));
00334 if (!idpackfiles) Error("out of memory");
00335
00336 if (fread(idpackfiles, sizeof(dpackfile_t), numpackdirs, fp) != numpackdirs)
00337 {
00338 fclose(fp);
00339 free(idpackfiles);
00340 Warning("can't read the Quake pak file dir entries from %s", pakfile);
00341 return NULL;
00342 }
00343 fclose(fp);
00344
00345 packfiles = (dsinpackfile_t *) malloc(numpackdirs * sizeof(dsinpackfile_t));
00346 if (!packfiles) Error("out of memory");
00347 for (i = 0; i < numpackdirs; i++)
00348 {
00349 strcpy(packfiles[i].name, idpackfiles[i].name);
00350 packfiles[i].filepos = LittleLong(idpackfiles[i].filepos);
00351 packfiles[i].filelen = LittleLong(idpackfiles[i].filelen);
00352 }
00353 free(idpackfiles);
00354 }
00355 else
00356 {
00357
00358 numpackdirs = LittleLong(packheader.dirlen) / sizeof(dsinpackfile_t);
00359 packfiles = (dsinpackfile_t *) malloc(numpackdirs * sizeof(dsinpackfile_t));
00360 if (!packfiles) Error("out of memory");
00361
00362 if (fread(packfiles, sizeof(dsinpackfile_t), numpackdirs, fp) != numpackdirs)
00363 {
00364 fclose(fp);
00365 free(packfiles);
00366 Warning("can't read the Sin pak file dir entries from %s", pakfile);
00367 return NULL;
00368 }
00369 fclose(fp);
00370 for (i = 0; i < numpackdirs; i++)
00371 {
00372 packfiles[i].filepos = LittleLong(packfiles[i].filepos);
00373 packfiles[i].filelen = LittleLong(packfiles[i].filelen);
00374 }
00375 }
00376
00377 for (i = 0; i < numpackdirs; i++)
00378 {
00379 ConvertPath(packfiles[i].name);
00380 if (FileFilter(filter, packfiles[i].name, false))
00381 {
00382 qf = malloc(sizeof(quakefile_t));
00383 if (!qf) Error("out of memory");
00384 memset(qf, 0, sizeof(quakefile_t));
00385 strcpy(qf->pakfile, pakfile);
00386 strcpy(qf->filename, pakfile);
00387 strcpy(qf->origname, packfiles[i].name);
00388 qf->zipfile = false;
00389 qf->offset = packfiles[i].filepos;
00390 qf->length = packfiles[i].filelen;
00391 qf->type = QuakeFileType(packfiles[i].name);
00392
00393 qf->next = NULL;
00394 if (lastqf) lastqf->next = qf;
00395 else qfiles = qf;
00396 lastqf = qf;
00397 }
00398 }
00399 free(packfiles);
00400 return qfiles;
00401 }
00402
00403
00404
00405
00406
00407
00408 quakefile_t *FindQuakeFilesWithPakFilter(char *pakfilter, char *filter)
00409 {
00410 #if defined(WIN32)|defined(_WIN32)
00411 WIN32_FIND_DATA filedata;
00412 HWND handle;
00413 struct _stat statbuf;
00414 #else
00415 glob_t globbuf;
00416 struct stat statbuf;
00417 int j;
00418 #endif
00419 quakefile_t *qfiles, *lastqf, *qf;
00420 char pakfile[_MAX_PATH], filename[_MAX_PATH], *str;
00421 int done;
00422
00423 qfiles = NULL;
00424 lastqf = NULL;
00425 if (pakfilter && strlen(pakfilter))
00426 {
00427 #if defined(WIN32)|defined(_WIN32)
00428 handle = FindFirstFile(pakfilter, &filedata);
00429 done = (handle == INVALID_HANDLE_VALUE);
00430 while(!done)
00431 {
00432 _splitpath(pakfilter, pakfile, NULL, NULL, NULL);
00433 _splitpath(pakfilter, NULL, &pakfile[strlen(pakfile)], NULL, NULL);
00434 AppendPathSeperator(pakfile, _MAX_PATH);
00435 strcat(pakfile, filedata.cFileName);
00436 _stat(pakfile, &statbuf);
00437 #else
00438 glob(pakfilter, 0, NULL, &globbuf);
00439 for (j = 0; j < globbuf.gl_pathc; j++)
00440 {
00441 strcpy(pakfile, globbuf.gl_pathv[j]);
00442 stat(pakfile, &statbuf);
00443 #endif
00444
00445 if (statbuf.st_mode & S_IFDIR)
00446 {
00447 strcpy(filename, pakfilter);
00448 AppendPathSeperator(filename, _MAX_PATH);
00449 strcat(filename, filter);
00450 qf = FindQuakeFilesWithPakFilter(NULL, filename);
00451 if (lastqf) lastqf->next = qf;
00452 else qfiles = qf;
00453 lastqf = qf;
00454 while(lastqf->next) lastqf = lastqf->next;
00455 }
00456 else
00457 {
00458 #if defined(WIN32)|defined(_WIN32)
00459 str = StringContains(pakfile, ".pk3", false);
00460 #else
00461 str = StringContains(pakfile, ".pk3", true);
00462 #endif
00463 if (str && str == pakfile + strlen(pakfile) - strlen(".pk3"))
00464 {
00465 qf = FindQuakeFilesInZip(pakfile, filter);
00466 }
00467 else
00468 {
00469 qf = FindQuakeFilesInPak(pakfile, filter);
00470 }
00471
00472 if (qf)
00473 {
00474 if (lastqf) lastqf->next = qf;
00475 else qfiles = qf;
00476 lastqf = qf;
00477 while(lastqf->next) lastqf = lastqf->next;
00478 }
00479 }
00480
00481 #if defined(WIN32)|defined(_WIN32)
00482
00483 done = !FindNextFile(handle, &filedata);
00484 }
00485 #else
00486 }
00487 globfree(&globbuf);
00488 #endif
00489 }
00490 else
00491 {
00492 #if defined(WIN32)|defined(_WIN32)
00493 handle = FindFirstFile(filter, &filedata);
00494 done = (handle == INVALID_HANDLE_VALUE);
00495 while(!done)
00496 {
00497 _splitpath(filter, filename, NULL, NULL, NULL);
00498 _splitpath(filter, NULL, &filename[strlen(filename)], NULL, NULL);
00499 AppendPathSeperator(filename, _MAX_PATH);
00500 strcat(filename, filedata.cFileName);
00501 #else
00502 glob(filter, 0, NULL, &globbuf);
00503 for (j = 0; j < globbuf.gl_pathc; j++)
00504 {
00505 strcpy(filename, globbuf.gl_pathv[j]);
00506 #endif
00507
00508 qf = malloc(sizeof(quakefile_t));
00509 if (!qf) Error("out of memory");
00510 memset(qf, 0, sizeof(quakefile_t));
00511 strcpy(qf->pakfile, "");
00512 strcpy(qf->filename, filename);
00513 strcpy(qf->origname, filename);
00514 qf->offset = 0;
00515 qf->length = 0;
00516 qf->type = QuakeFileType(filename);
00517
00518 qf->next = NULL;
00519 if (lastqf) lastqf->next = qf;
00520 else qfiles = qf;
00521 lastqf = qf;
00522 #if defined(WIN32)|defined(_WIN32)
00523
00524 done = !FindNextFile(handle, &filedata);
00525 }
00526 #else
00527 }
00528 globfree(&globbuf);
00529 #endif
00530 }
00531 return qfiles;
00532 }
00533
00534
00535
00536
00537
00538
00539 quakefile_t *FindQuakeFiles(char *filter)
00540 {
00541 char *str;
00542 char newfilter[_MAX_PATH];
00543 char pakfilter[_MAX_PATH];
00544 char filefilter[_MAX_PATH];
00545
00546 strcpy(newfilter, filter);
00547 ConvertPath(newfilter);
00548 strcpy(pakfilter, newfilter);
00549
00550 str = StringContains(pakfilter, ".pak", false);
00551 if (!str) str = StringContains(pakfilter, ".pk3", false);
00552
00553 if (str)
00554 {
00555 str += strlen(".pak");
00556 if (*str)
00557 {
00558 *str++ = '\0';
00559 while(*str == '\\' || *str == '/') str++;
00560 strcpy(filefilter, str);
00561 return FindQuakeFilesWithPakFilter(pakfilter, filefilter);
00562 }
00563 }
00564 return FindQuakeFilesWithPakFilter(NULL, newfilter);
00565 }
00566
00567
00568
00569
00570
00571
00572 int LoadQuakeFile(quakefile_t *qf, void **bufferptr)
00573 {
00574 FILE *fp;
00575 void *buffer;
00576 int length;
00577 unzFile zf;
00578
00579 if (qf->zipfile)
00580 {
00581
00582 zf = unzOpen(qf->pakfile);
00583
00584 qf->zipinfo.file = ((unz_s *) zf)->file;
00585
00586 unzOpenCurrentFile(&qf->zipinfo);
00587
00588 length = qf->length;
00589 buffer = GetMemory(length+1);
00590
00591 length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
00592
00593 unzCloseCurrentFile(&qf->zipinfo);
00594
00595 unzClose(zf);
00596
00597 *bufferptr = buffer;
00598 return length;
00599 }
00600 else
00601 {
00602 fp = SafeOpenRead(qf->filename);
00603 if (qf->offset) fseek(fp, qf->offset, SEEK_SET);
00604 length = qf->length;
00605 if (!length) length = Q_filelength(fp);
00606 buffer = GetMemory(length+1);
00607 ((char *)buffer)[length] = 0;
00608 SafeRead(fp, buffer, length);
00609 fclose(fp);
00610
00611 *bufferptr = buffer;
00612 return length;
00613 }
00614 }
00615
00616
00617
00618
00619
00620
00621 int ReadQuakeFile(quakefile_t *qf, void *buffer, int offset, int length)
00622 {
00623 FILE *fp;
00624 int read;
00625 unzFile zf;
00626 char tmpbuf[1024];
00627
00628 if (qf->zipfile)
00629 {
00630
00631 zf = unzOpen(qf->pakfile);
00632
00633 qf->zipinfo.file = ((unz_s *) zf)->file;
00634
00635 unzOpenCurrentFile(&qf->zipinfo);
00636
00637 while(offset > 0)
00638 {
00639 read = offset;
00640 if (read > sizeof(tmpbuf)) read = sizeof(tmpbuf);
00641 unzReadCurrentFile(&qf->zipinfo, tmpbuf, read);
00642 offset -= read;
00643 }
00644
00645 length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
00646
00647 unzCloseCurrentFile(&qf->zipinfo);
00648
00649 unzClose(zf);
00650
00651 return length;
00652 }
00653 else
00654 {
00655 fp = SafeOpenRead(qf->filename);
00656 if (qf->offset) fseek(fp, qf->offset, SEEK_SET);
00657 if (offset) fseek(fp, offset, SEEK_CUR);
00658 SafeRead(fp, buffer, length);
00659 fclose(fp);
00660
00661 return length;
00662 }
00663 }