Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

l_qfiles.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
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 //file extensions with their type
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 // Parameter:           -
00062 // Returns:             -
00063 // Changes Globals:     -
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         } //end if
00075     } //end for
00076     return QFILETYPE_UNKNOWN;
00077 } //end of the function QuakeFileExtensionType
00078 //===========================================================================
00079 //
00080 // Parameter:           -
00081 // Returns:             -
00082 // Changes Globals:     -
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         } //end if
00094     } //end for
00095     return QFILEEXT_UNKNOWN;
00096 } //end of the function QuakeFileExtension
00097 //===========================================================================
00098 //
00099 // Parameter:           -
00100 // Returns:             -
00101 // Changes Globals:     -
00102 //===========================================================================
00103 int QuakeFileType(char *filename)
00104 {
00105     char ext[_MAX_PATH] = ".";
00106 
00107     ExtractFileExtension(filename, ext+1);
00108     return QuakeFileExtensionType(ext);
00109 } //end of the function QuakeFileTypeFromFileName
00110 //===========================================================================
00111 //
00112 // Parameter:               -
00113 // Returns:                 -
00114 // Changes Globals:     -
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             } //end if
00129             else
00130             {
00131                 if (toupper(str1[j]) != toupper(str2[j])) break;
00132             } //end else
00133         } //end for
00134         if (!str2[j]) return str1;
00135     } //end for
00136     return NULL;
00137 } //end of the function StringContains
00138 //===========================================================================
00139 //
00140 // Parameter:           -
00141 // Returns:             -
00142 // Changes Globals:     -
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             } //end for
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             } //end if
00168         } //end if
00169         else if (*filter == '?')
00170         {
00171             filter++;
00172             filename++;
00173         } //end else if
00174         else if (*filter == '[' && *(filter+1) == '[')
00175         {
00176             filter++;
00177         } //end if
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                     } //end if
00191                     else
00192                     {
00193                         if (toupper(*filename) >= toupper(*filter) &&
00194                             toupper(*filename) <= toupper(*(filter+2))) found = true;
00195                     } //end else
00196                     filter += 3;
00197                 } //end if
00198                 else
00199                 {
00200                     if (casesensitive)
00201                     {
00202                         if (*filter == *filename) found = true;
00203                     } //end if
00204                     else
00205                     {
00206                         if (toupper(*filter) == toupper(*filename)) found = true;
00207                     } //end else
00208                     filter++;
00209                 } //end else
00210             } //end while
00211             if (!found) return false;
00212             while(*filter)
00213             {
00214                 if (*filter == ']' && *(filter+1) != ']') break;
00215                 filter++;
00216             } //end while
00217             filter++;
00218             filename++;
00219         } //end else if
00220         else
00221         {
00222             if (casesensitive)
00223             {
00224                 if (*filter != *filename) return false;
00225             } //end if
00226             else
00227             {
00228                 if (toupper(*filter) != toupper(*filename)) return false;
00229             } //end else
00230             filter++;
00231             filename++;
00232         } //end else
00233     } //end while
00234     return true;
00235 } //end of the function FileFilter
00236 //===========================================================================
00237 //
00238 // Parameter:           -
00239 // Returns:             -
00240 // Changes Globals:     -
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             //memcpy( &buildBuffer[i].zipfileinfo, (unz_s*)uf, sizeof(unz_s));
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             //add the file ot the list
00282             qf->next = NULL;
00283             if (lastqf) lastqf->next = qf;
00284             else qfiles = qf;
00285             lastqf = qf;
00286         } //end if
00287         unzGoToNextFile(uf);
00288     } //end for
00289 
00290     unzClose(uf);
00291 
00292     return qfiles;
00293 } //end of the function FindQuakeFilesInZip
00294 //===========================================================================
00295 //
00296 // Parameter:           -
00297 // Returns:             -
00298 // Changes Globals:     -
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     //open the pak file
00312     fp = fopen(pakfile, "rb");
00313     if (!fp)
00314     {
00315         Warning("can't open pak file %s", pakfile);
00316         return NULL;
00317     } //end if
00318     //read pak header, check for valid pak id and seek to the dir entries
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     } //end if
00328     //if it is a pak file from id software
00329     if (packheader.ident == IDPAKHEADER)
00330     {
00331         //number of dir entries in the pak file
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         //read the dir entry
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         } //end if
00343         fclose(fp);
00344         //convert to sin pack files
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         } //end for
00353         free(idpackfiles);
00354     } //end if
00355     else //its a Sin pack file
00356     {
00357         //number of dir entries in the pak file
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         //read the dir entry
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         } //end if
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         } //end for
00375     } //end else
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             //add the file ot the list
00393             qf->next = NULL;
00394             if (lastqf) lastqf->next = qf;
00395             else qfiles = qf;
00396             lastqf = qf;
00397         } //end if
00398     } //end for
00399     free(packfiles);
00400     return qfiles;
00401 } //end of the function FindQuakeFilesInPak
00402 //===========================================================================
00403 //
00404 // Parameter:           -
00405 // Returns:             -
00406 // Changes Globals:     -
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             //if the file with .pak or .pk3 is a folder
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             } //end if
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                 } //end if
00467                 else
00468                 {
00469                     qf = FindQuakeFilesInPak(pakfile, filter);
00470                 } //end else
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                 } //end if
00479             } //end else
00480             //
00481 #if defined(WIN32)|defined(_WIN32)
00482             //find the next file
00483             done = !FindNextFile(handle, &filedata);
00484         } //end while
00485 #else
00486         } //end for
00487         globfree(&globbuf);
00488 #endif
00489     } //end if
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             //add the file ot the list
00518             qf->next = NULL;
00519             if (lastqf) lastqf->next = qf;
00520             else qfiles = qf;
00521             lastqf = qf;
00522 #if defined(WIN32)|defined(_WIN32)
00523             //find the next file
00524             done = !FindNextFile(handle, &filedata);
00525         } //end while
00526 #else
00527         } //end for
00528         globfree(&globbuf);
00529 #endif
00530     } //end else
00531     return qfiles;
00532 } //end of the function FindQuakeFilesWithPakFilter
00533 //===========================================================================
00534 //
00535 // Parameter:           -
00536 // Returns:             -
00537 // Changes Globals:     -
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         } //end if
00563     } //end else
00564     return FindQuakeFilesWithPakFilter(NULL, newfilter);
00565 } //end of the function FindQuakeFiles
00566 //===========================================================================
00567 //
00568 // Parameter:           -
00569 // Returns:             -
00570 // Changes Globals:     -
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         //open the zip file
00582         zf = unzOpen(qf->pakfile);
00583         //set the file pointer
00584         qf->zipinfo.file = ((unz_s *) zf)->file;
00585         //open the Quake file in the zip file
00586         unzOpenCurrentFile(&qf->zipinfo);
00587         //allocate memory for the buffer
00588         length = qf->length;
00589         buffer = GetMemory(length+1);
00590         //read the Quake file from the zip file
00591         length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
00592         //close the Quake file in the zip file
00593         unzCloseCurrentFile(&qf->zipinfo);
00594         //close the zip file
00595         unzClose(zf);
00596 
00597         *bufferptr = buffer;
00598         return length;
00599     } //end if
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     } //end else
00614 } //end of the function LoadQuakeFile
00615 //===========================================================================
00616 //
00617 // Parameter:           -
00618 // Returns:             -
00619 // Changes Globals:     -
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         //open the zip file
00631         zf = unzOpen(qf->pakfile);
00632         //set the file pointer
00633         qf->zipinfo.file = ((unz_s *) zf)->file;
00634         //open the Quake file in the zip file
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         } //end while
00644         //read the Quake file from the zip file
00645         length = unzReadCurrentFile(&qf->zipinfo, buffer, length);
00646         //close the Quake file in the zip file
00647         unzCloseCurrentFile(&qf->zipinfo);
00648         //close the zip file
00649         unzClose(zf);
00650 
00651         return length;
00652     } //end if
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     } //end else
00663 } //end of the function ReadQuakeFile

Generated on Thu Aug 25 12:37:17 2005 for Quake III Arena by  doxygen 1.3.9.1