1 //-----------------------------------------------------------------------------
2 // Files
3 //-----------------------------------------------------------------------------
4 
5 #include "vars.h"
6 #include "files.h"
7 #include "commands.h"
8 #include "console.h"
9 #include "logfile.h"
10 #include "parser.h"
11 #include "mem.h"
12 #include "texture.h"
13 #include "system.h"
14 #include "definitions.h"
15 #include <string.h>
16 
17 #ifdef WIN32
18   #include <direct.h>
19 #else
20   #include <sys/types.h>
21   #include <dirent.h>
22   #include <errno.h>
23   #include <unistd.h>
24   #include <sys/types.h>
25   #include <ctype.h>
26 
27   #include <fnmatch.h>
28   #include <sys/stat.h>
29   #define _getcwd getcwd
30 
31   #pragma pack(1)
32 
33   typedef struct tagBITMAPFILEHEADER
34   {
35     WORD bfType;
36     DWORD bfSize;
37     WORD bfReserved1;
38     WORD bfReserved2;
39     DWORD bfOffBits;
40   } BITMAPFILEHEADER;
41 
42   typedef struct tagBITMAPINFOHEADER
43   {
44     DWORD biSize;
45     LONG biWidth;
46     LONG biHeight;
47     WORD biPlanes;
48     WORD biBitCount;
49     DWORD biCompression;
50     DWORD biSizeImage;
51     LONG biXPelsPerMeter;
52     LONG biYPelsPerMeter;
53     DWORD biClrUsed;
54     DWORD biClrImportant;
55   } BITMAPINFOHEADER;
56 
57   #pragma pack()
58 
lstrlwr(char * s)59   char *lstrlwr(char *s)
60   {
61     int i = 0;
62 
63     while (s[i] != '\0')
64     {
65       if (isupper(s[i]))
66       s[i] = tolower(s[i]);
67       ++i;
68     }
69 
70     return s;
71   }
72 
73   #define strlwr lstrlwr
74   #define _strlwr lstrlwr
75 
76   #define BI_RGB    0L
77 #endif
78 
79 search_path *FileEnvironment::Search = NULL;
80 char FileEnvironment::main_path[];
81 
82 static Pack *packets  = NULL;
83 int nPackedFiles    = 0;
84 int nPAKFiles     = 0;
85 
86 //-----------------------------------------------------------------------------
87 // Global functions
88 //-----------------------------------------------------------------------------
89 
f_StripName(char * path)90 void f_StripName(char *path)
91 {
92   int length = (int) strlen(path)-1;
93 
94   while (length > 0 && path[length] != '/' && path[length] != '\\')
95   {
96     --length;
97   }
98   if (length)
99     path[length+1] = 0;
100   else
101     path[0] = 0;
102 }
103 
f_StripExtension(char * path)104 void f_StripExtension(char *path)
105 {
106   int length = (int) strlen(path)-1;  // �?
107   while (length > 0 && path[length] != '.')
108   {
109     --length;
110     if (path[length] == '/')
111       return;   // no extension
112   }
113   if (length)
114     path[length] = 0;
115 }
116 
f_Name(char * path)117 char * f_Name(char *path)
118 {
119   int length, l;
120   l = length = (int) strlen(path)-1;
121   while (length > 0 && path[length] != '\\' && path[length] != '/') --length;
122   return &path[length+1];
123 }
124 
f_Extension(char * name)125 char * f_Extension(char *name)
126 {
127   int length, l;
128   l = length = (int) strlen(name)-1;  // �?
129   while (length > 0 && name[length] != '.')
130   {
131     --length;
132     if (name[length] == '/')
133       return &name[l];    // no extension
134   }
135   if(length==0) return &name[l];
136   return &name[length];
137 
138   //while(*name!='.'&&*name!=0) ++name;
139   //return name;
140 }
141 
142 // CAUTION: string must be well formated ('\0' at the end)
f_CorrectSlashInName(char * name)143 inline void f_CorrectSlashInName(char *name)
144 {
145   int i = 0;
146   do
147   {
148     if(name[i] == '\0') break;
149     else if(name[i] == '\\') name[i] = '/';
150   } while(++i);
151 }
152 
153 //-----------------------------------------------------------------------------
154 
getPAKContent(char * pak_name,char * file_type,char * grep)155 void getPAKContent(char *pak_name, char *file_type, char *grep)
156 {
157   int nfounds = 0;
158 
159   // Search for local files
160   char strpath[MAX_FILEPATH] = { '\0' };
161   char path[MAX_FILEPATH];
162   strncpy(path, gVars->StringForKey("r_mapsubdir"), MAX_FILEPATH);
163   int l = (int) strlen(path);
164 
165   if (path[l-1] == '\\' || path[l-1] == '/')
166     sprintf(strpath, "%s*%s", path, file_type);
167   else
168     sprintf(strpath, "%s/*%s", path, file_type);
169 
170   SearchFile files(strpath);
171 
172   gLogFile->OpenFile();
173 
174   for (char *name = files.FirstFile(); name; name = files.NextFile())
175   {
176     if (!grep || (grep && strstr(strlwr(name), strlwr(grep))))
177     {
178       gConsole->Insertln("^2%s", name);
179       ++nfounds;
180     }
181   }
182 
183   // Search for packed files
184   for (Pack* packlist = packets; packlist; packlist = packlist->next)
185   {
186     if (pak_name == NULL || strstr(strlwr(packlist->name), strlwr(pak_name)))
187     {
188       for (int i = 0; i < packlist->nFiles; ++i)
189       {
190         if (file_type == ".*" || strstr(strlwr(packlist->files[i].name), strlwr(file_type)))
191         {
192           if (!grep || (grep && strstr(strlwr(packlist->files[i].name), strlwr(grep))))
193           {
194             gConsole->Insertln("^2%s ^0(%s)", packlist->files[i].name, packlist->name);
195             ++nfounds;
196           }
197         }
198       }
199     }
200   }
201   gLogFile->CloseFile();
202   gConsole->Insertln("%d file%s found", nfounds, nfounds>1?"s":"");
203 }
204 
logPreviews(void)205 void logPreviews(void)
206 {
207   char levelshot_name[256] = { '\0' };
208   int levelshot_found = 0;
209 
210   // Search for local files
211   char strpath[MAX_FILEPATH] = { '\0' };
212   char path[MAX_FILEPATH];
213   strncpy(path, gVars->StringForKey("r_mapsubdir"), MAX_FILEPATH);
214   int l = (int) strlen(path);
215 
216   if (path[l-1] == '\\' || path[l-1] == '/')
217     sprintf(strpath, "%s*%s", path, ".bsp");
218   else
219     sprintf(strpath, "%s/*%s", path, ".bsp");
220 
221   SearchFile files(strpath);
222 
223   gLogFile->OpenFile();
224 
225   for (char *name = files.FirstFile(); name; name = files.NextFile())
226   {
227     gLogFile->Insert("^2%s", name);
228     // searh levelshot having TGA or JPG extension
229     bool extistga = false;
230     char nname[256] = { '\0' };
231     int lname = (int) strlen(name)-1;
232     while (lname >= 0 && name[lname] != '/' && name[lname] != '\\') --lname;
233     strcpy(nname, &name[lname+1]);
234     f_StripExtension(nname);
235     sprintf(levelshot_name, "levelshots/%s.jpg", nname);
236     levelshot_found = FileExist(levelshot_name, 1, 0);
237     if (!levelshot_found)
238     {
239       sprintf(levelshot_name, "levelshots/%s.tga", nname);
240       levelshot_found = FileExist(levelshot_name, 1, 0);
241       if (levelshot_found) extistga = true;
242     }
243 
244     if (!levelshot_found)
245       strcpy(levelshot_name, "menu/art/unknownmap.jpg");
246 
247     VFile levelshotfile(levelshot_name);
248     texinfo info;
249     if (levelshotfile.mem)
250     {
251       if (extistga) TGA_Decode(&levelshotfile, &info);
252       else JPG_Decode(&levelshotfile, &info);
253       FlipTexture(&info);
254     }
255 
256     char dstfilename[256] = { '\0' };
257     sprintf(dstfilename, "shots/%s.bmp", nname);
258     WriteBitmapFile(dstfilename, info.width, info.height, info.bpp, info.mem);
259     gLogFile->Insert("<br><img src=\"%s\" width=\"%d\" height=\"%d\"><br><br>", dstfilename, info.width, info.height);
260   }
261 
262   // Search for packed files
263   for (Pack* packlist = packets; packlist; packlist = packlist->next)
264   {
265     for (int i = 0; i < packlist->nFiles; ++i)
266     {
267       if (strstr(strlwr(packlist->files[i].name), ".bsp"))
268       {
269         char nname[256] = { '\0' };
270         int lname = (int) strlen(packlist->files[i].name)-1;
271         while (lname >= 0 && packlist->files[i].name[lname] != '/' && packlist->files[i].name[lname] != '\\') --lname;
272         strcpy(nname, &packlist->files[i].name[lname+1]);
273         f_StripExtension(nname);
274 
275         gLogFile->Insert("^2%s ^0(%s)", packlist->files[i].name, packlist->name);
276 
277         // searh levelshot having TGA or JPG extension
278         bool extistga = false;
279         sprintf(levelshot_name, "levelshots/%s.jpg", nname);
280         levelshot_found = FileExist(levelshot_name, 1, 0);
281         if (!levelshot_found)
282         {
283           sprintf(levelshot_name, "levelshots/%s.tga", nname);
284           levelshot_found = FileExist(levelshot_name, 1, 0);
285           if (levelshot_found) extistga = true;
286         }
287 
288         if (!levelshot_found)
289           strcpy(levelshot_name, "menu/art/unknownmap.jpg");
290 
291         VFile levelshotfile(levelshot_name);
292         texinfo info;
293         if (levelshotfile.mem)
294         {
295           if (extistga) TGA_Decode(&levelshotfile, &info);
296           else JPG_Decode(&levelshotfile, &info);
297           FlipTexture(&info);
298         }
299 
300         char dstfilename[256] = { '\0' };
301         sprintf(dstfilename, "shots/%s.bmp", nname);
302         WriteBitmapFile(dstfilename, info.width, info.height, info.bpp, info.mem);
303         gLogFile->Insert("<br><img src=\"%s\" width=\"%d\" height=\"%d\"><br><br>", dstfilename, info.width, info.height);
304       }
305     }
306   }
307 
308   gLogFile->CloseFile();
309 }
310 
FileExist(char * file_name,int pak_search,int strip_extension)311 int FileExist(char *file_name, int pak_search, int strip_extension)
312 {
313   FILE * fp;
314   char fname[FILE_NAME], sname[FILE_NAME];
315 
316   for (search_path *p = FileEnvironment::Search; p; p = p->next)
317   {
318     sprintf(fname, "%s%s", p->path, file_name);
319     if (strip_extension) f_StripExtension(fname);
320 
321     f_CorrectSlashInName(fname);
322 
323     fp = fopen(fname, "rb");
324     if (fp)
325     {
326       fclose(fp);
327       return 1;
328     }
329   }
330 
331   // Si on ne trouve pas le fichier tel quel, on cherche dans les fichiers pak
332   if (pak_search)
333   {
334     for (Pack *p = packets; p; p = p->next)
335     {
336       for (int i = 0; i < p->nFiles; ++i)
337       {
338         strcpy(fname, file_name);
339         strcpy(sname, p->files[i].name);
340         if (strip_extension)
341         {
342           f_StripExtension(fname);
343           f_StripExtension(sname);
344         }
345         if (stricmp(fname, sname) == 0)
346         {
347           return 1;
348         }
349       }
350     }
351   }
352 
353   return 0;
354 }
355 
356 //-----------------------------------------------------------------------------
357 // VFile
358 //-----------------------------------------------------------------------------
359 
VFile(const char * name,bool pak_search,const char * pakname)360 VFile::VFile(const char *name, bool pak_search, const char *pakname)
361 {
362   FILE * fp;
363     mem = NULL;
364   error = 0;
365   char _name[FILE_NAME];
366 
367   int lenpak = 0;
368   if (pakname) lenpak = (int) strlen(pakname);
369 
370   // change all '\\' to '/'
371   strcpy(_name, name);
372 
373   f_CorrectSlashInName(_name);
374 
375   // suppress initial '/' or '\\'
376   while ((_name[0] == '/' || _name[0] == '\\') && strlen(_name) > 0) strcpy(_name, &(_name[1]));
377 
378   // Let's search in pak files
379   if (pak_search)
380   {
381     Pack *p;
382     for (p = packets; p; p = p->next)
383     {
384       if (!lenpak || (lenpak && !stricmp(p->name, pakname)))
385       {
386         for (int i = 0; i < p->nFiles; ++i)
387         {
388           if (!stricmp(_name, p->files[i].name))
389           {
390             if ((fp = fopen(p->name, "rb")) == NULL)
391             {
392               gConsole->Insertln("^1ERROR: Cannot open %s", p->name);
393               return;
394             }
395             fseek(fp, p->files[i].offset, SEEK_SET);
396 
397             mem = (BYTE *) UnZip(fp);
398             size = p->files[i].size;
399             fclose(fp);
400             return;
401           }
402         }
403       }
404     }
405     if (p) return;
406   }
407 
408   // The file couldn't be found in pak files, let's search in local folders
409   for (search_path *p = FileEnvironment::Search; p; p = p->next)
410   {
411     sprintf(fname, "%s%s", p->path, _name);
412 
413     f_CorrectSlashInName(fname);
414 
415     if ((fp = fopen(fname,"rb")) == NULL) continue; // cannot find the file... continue with another path
416 
417     // see the size
418     fseek(fp, 0L, SEEK_END);
419     size = ftell(fp);
420     rewind(fp);
421 
422     // allocate memory
423     mem = new BYTE[size];
424     if (mem == NULL)
425     {
426       fclose(fp);
427       gConsole->Insertln("^1ERROR: VFile: Cannot allocate required size");
428       // FIXME: critical error!
429       return;
430     }
431 
432     // copy archive to memory
433     fread(mem, size, sizeof(BYTE), fp);
434     fclose(fp);
435 
436     return;
437   }
438 
439   // display error!! : file not found!
440   //gConsole->Insertln("^1ERROR: Error occured while loading file %s", name);
441 }
442 
~VFile(void)443 VFile::~VFile(void)
444 {
445   // delete memory archive
446   if (mem) delete [] mem;
447   mem = NULL;
448 }
449 
450 //-----------------------------------------------------------------------------
451 // LumpFile
452 //-----------------------------------------------------------------------------
453 
LumpFile(const char * name,const int id,const int ver,const int num_lumps)454 LumpFile::LumpFile(const char *name, const int id, const int ver, const int num_lumps):VFile(name)
455 {
456   head = (header *) mem;
457 
458   if (!head)
459   {
460     gConsole->Insertln("^1ERROR: Couldn't read file header");
461     return;
462   }
463 
464     if (head->id != id)
465   {
466     gConsole->Insertln("^1ERROR: Bad file id in %s; found: %d, expected: %d",
467       name, head->id, id);
468     delete [] mem; mem = NULL;
469     return;
470   }
471     if (head->ver != ver)
472   {
473     gConsole->Insertln("^1ERROR: Bad file version in %s; found: %d, expected: %d",
474       name, head->ver, ver);
475     delete [] mem; mem = NULL;
476     return;
477   }
478 }
479 
~LumpFile(void)480 LumpFile::~LumpFile(void)
481 {
482   // FIXME: como hacer que �ste destructor no llame al destructor padre ?
483   //      �lo llama?
484   // en todo caso se deber�a eliminar mem si es que a�n no ha sido eliminada.
485 }
486 
487 // TODO: test errors...
ReadLump(int lump,void ** dest,size_t elem)488 int LumpFile::ReadLump(int lump, void** dest, size_t elem)
489 {
490   if (!mem) return 0;
491   int len = head->lump[lump].filelen;
492 
493   // test if size is valid (should stop loading if not, but try anyway)
494   if (len % elem) gConsole->Insertln("^1LumpFile::ReadLump: Funny lump size ! Trying to open anyway :\\");
495 
496   int num = len / (int) elem;
497 
498   *dest = cake_malloc(len, "LumpFile::ReadLump");
499   if (!(*dest)) ThrowException(ALLOCATION_ERROR, "LumpFile::ReadLump.(*dest)");
500 
501   memcpy(*dest, mem + head->lump[lump].fileofs, num * elem);
502   return num;
503 }
504 
505 //-----------------------------------------------------------------------------
506 // FileEnvironment
507 //-----------------------------------------------------------------------------
508 
Init(void)509 void FileEnvironment::Init(void)
510 {
511   char pth[MAX_FILEPATH];
512 
513   _getcwd(pth, MAX_FILEPATH); // get current path
514   #ifdef WIN32
515     if (pth[strlen(pth)-1] != '\\') strcat(pth, "\\");
516     #else
517     if (pth[strlen(pth)-1] != '/') strcat(pth, "/");
518     #endif
519 
520   // change all '\\' to '/'
521   for (int i = 0; i < (int) strlen(pth); ++i) if (pth[i] == '\\') pth[i] = '/';
522 
523   strncpy(FileEnvironment::main_path, pth, MAX_FILEPATH);
524 }
525 
AddPath(const char * path)526 void FileEnvironment::AddPath(const char *path)
527 {
528   search_path *tmp = new search_path;
529   int i = 0;
530 
531   if (path[0] == '/' ||                               // linux case
532     (strlen(path) > 2 && path[1] == ':' && (path[2] == '\\' || path[2] == '/')))  // windows case
533   {
534     // path use driver letter
535     strcpy(tmp->path, path);
536   }
537   else
538   {
539     // path is relative to main path
540     strncpy(tmp->path, main_path, MAX_FILEPATH);
541 
542     // adapt path to "../" and "./" elements
543     int l = (int) strlen(path), s = 0;
544     while (l > 0 && i < l)
545     {
546       if (i <= l - 3 && path[i] == '.' && path[i+1] == '.' && (path[i+2] == '/' || path[i+2] == '\\'))
547       {
548         i += 2;
549         // remove last dir of the main_path
550         int ml = (int) strlen(tmp->path) - 1;
551         if (tmp->path[ml] == '\\' || tmp->path[ml] == '/') --ml;
552         while (ml >= 0 && (tmp->path[ml] != '\\' && tmp->path[ml] != '/'))
553         {
554           tmp->path[ml] = '\0';
555           --ml;
556         }
557         s += 3;
558       }
559       else if (i <= l - 2 && path[i] == '.' && (path[i+1] == '/' || path[i+1] == '\\'))
560       {
561         ++i;
562         s += 2;
563       }
564       ++i;
565     }
566     strcat(tmp->path, &(path[s]));
567   }
568 
569   f_CorrectSlashInName(tmp->path);
570 
571   tmp->next = FileEnvironment::Search;
572   FileEnvironment::Search = tmp;
573 }
574 
575 // Search for all pk3 files and add the filenames contained
576 // in each pk3 file to the "packets" list
LoadPacks(void)577 void FileEnvironment::LoadPacks(void)
578 {
579   char *      name = NULL;
580   FILE *      fp;
581   ZIPEnd      End;
582   ZIPCtrlHeader File;
583   Pack      *packet;
584   int       i;
585 
586   nPackedFiles = 0;
587   nPAKFiles = 0;
588 
589   char fname[512];          // FIXME: static allocation
590 
591   // we put the supported extensions files in a table
592   #define SUPPORTED_EXT 3
593   char exts[SUPPORTED_EXT][10];
594   for (i = 0; i < SUPPORTED_EXT; ++i) memset(exts[i], 0, 10);
595 
596   strcpy(exts[0], "*.pk3");
597   strcpy(exts[1], "*.pak");
598   strcpy(exts[2], "*.zip");
599 
600   gConsole->Insertln("<br/><b>^6----- Reading Packs -------------------------------------------</b>");
601   gLogFile->OpenFile();
602 
603   for (i = 0; i < SUPPORTED_EXT; ++i)
604   {
605     SearchFile packs(exts[i]);
606 
607     // for each file with supported extensions, open it and add its files to the index
608     for (search_path *p = FileEnvironment::Search; p; p = p->next)
609     {
610       for (name = packs.FirstFile(p->path); name; name = packs.NextFile(p->path))
611       {
612         memset(fname, '\0', 512*sizeof(char));
613         sprintf(fname, "%s%s", p->path, name);
614 
615         if ((fp = fopen(fname, "rb")))
616         {
617           // Read the final header
618           fseek(fp, -22, SEEK_END);
619           fread(&End,  sizeof(End), 1, fp);
620           if (End.Signature != ZIPEndSig)
621           {
622             gConsole->Insertln("^5WARNING: Corrupted pak file %s", name);
623             fclose(fp);
624             continue;
625           }
626 
627           gConsole->Insertln("...reading \"%s\" (%d file%s)", fname, End.FilesOnDisk, End.FilesOnDisk>1?"s":"");
628 
629           ++nPAKFiles;
630 
631           packet = new Pack;  // Add the packet to packets list
632           if (!packet) ThrowException(ALLOCATION_ERROR, "Files::LoadPacks.packet");
633 
634           packet->name = new char[strlen(fname)+1];
635           if (!packet->name) ThrowException(ALLOCATION_ERROR, "Files::LoadPacks.packet->name");
636           memset(packet->name, '\0', (strlen(fname)+1)*sizeof(char));
637           strcpy(packet->name, fname);
638           packet->nFiles = End.FilesOnDisk;
639           packet->files = new PackedFile[End.FilesOnDisk];
640           if (!packet->files) ThrowException(ALLOCATION_ERROR, "Files::LoadPacks.packet->files");
641           packet->next = packets;
642           packets = packet;
643 
644           // Read the header of each file
645           fseek(fp, End.Offset, SEEK_SET);
646           for (int n = 0; n < End.FilesOnDisk; ++n)
647           {
648             fread(&File, sizeof(File), 1, fp);
649             if (File.Signature != ZIPCtrlHeaderSig)
650             {
651               gConsole->Insertln("^5WARNING: Corrupted file %s", name);
652               fclose(fp);
653               break;      // continue with next pak
654             }
655 
656             packet->files[n].size = File.UnCompressedSize;
657             packet->files[n].offset = File.Offset;
658             memset(packet->files[n].name, '\0', 1024); // FIXME: hack???
659             fread(packet->files[n].name, 1, File.FileNameLength, fp);
660 
661             fseek(fp, File.ExtraLength+File.CommentLength, SEEK_CUR);
662           }
663           nPackedFiles += End.FilesOnDisk;
664 
665           fclose(fp);
666         }
667       }
668     }
669   }
670   gLogFile->CloseFile();
671   gConsole->Insertln("Reading finished - %d packed files in %d packages",
672     nPackedFiles, nPAKFiles);
673 }
674 
Shut(void)675 void FileEnvironment::Shut(void)
676 {
677   search_path *s, *snext = NULL;
678 
679   for (s = FileEnvironment::Search; s; s = snext)
680   {
681     snext = s->next;
682     delete s;
683   }
684 
685   Pack *p, *pnext = NULL;
686   for (p = packets; p; p = pnext)
687   {
688     delete [] p->name;
689     delete [] p->files;
690     pnext = p->next;
691     delete p;
692   }
693 }
694 
dumpEnvironment(void)695 void FileEnvironment::dumpEnvironment(void)
696 {
697   gConsole->Insertln("<b>File environment :</b>");
698   gConsole->Insertln("\tmain path : %s", FileEnvironment::main_path);
699   search_path *s = FileEnvironment::Search;
700   if (s) gConsole->Insertln("\tsearch path :");
701   gLogFile->OpenFile();
702   while (s)
703   {
704     gConsole->Insertln("\t\t%s", s->path);
705     s = s->next;
706   }
707   gLogFile->CloseFile();
708   gConsole->Insertln("\tmap path : %s", gVars->StringForKey("r_mapsubdir"));
709 }
710 
711 //-----------------------------------------------------------------------------
712 // SearchFile
713 //-----------------------------------------------------------------------------
714 
SearchFile(char * pattern)715 SearchFile::SearchFile(char *pattern)
716 {
717   this->pattern = pattern;
718   last = FileEnvironment::Search;
719   temp_pat = NULL;
720 }
721 
~SearchFile(void)722 SearchFile::~SearchFile(void)
723 {
724   if (temp_pat) delete temp_pat;
725 }
726 
FirstFile(void)727 char *SearchFile::FirstFile(void)
728 {
729   #ifdef WIN32
730     struct _finddata_t fileinfo;
731   #else
732     struct stat buf;
733     struct dirent* fileinfo;
734     char* temp = new char[1024];
735   #endif
736 
737   if (last == NULL)   // end of the list, reset and return
738   {
739     last = FileEnvironment::Search;
740     return NULL;
741   }
742 
743   if (temp_pat) delete [] temp_pat;
744   temp_pat = new char[strlen(last->path) + strlen(pattern) + 1];
745   strcpy(temp_pat, last->path);
746   strcat(temp_pat, pattern);
747 
748   f_CorrectSlashInName(temp_pat);
749 
750   #ifdef WIN32
751     handle = (int) _findfirst(temp_pat, &fileinfo);
752     if (handle == -1)
753     {
754       _findclose(handle);
755       if (temp_pat) delete [] temp_pat;
756       temp_pat = NULL;
757       last = last->next;
758       return FirstFile();
759     }
760 
761     // skip non-valid filenames
762     while ((fileinfo.attrib & _A_SUBDIR) || fileinfo.name[0] == '.')
763     {
764       if (_findnext(handle, &fileinfo) == -1)
765       {
766         _findclose(handle);
767         return NULL;
768       }
769     }
770   #else
771     handle = opendir(last->path);
772 
773     if (handle == NULL)
774     {
775       gConsole->Insertln("^1handle == NULL: %d - %s", errno, strerror(errno));
776       if (temp_pat) delete [] temp_pat;
777       temp_pat = NULL;
778       last = last->next;
779       return FirstFile();
780     }
781 
782     while ((fileinfo = readdir(handle)) != NULL)
783     {
784       memset(&buf, 0, sizeof(buf));
785       memset(temp, 0, sizeof(temp));
786 
787       strcpy(temp, last->path );
788       strcat(temp, fileinfo->d_name);
789 
790       if (stat(temp, &buf ) < 0)
791         gConsole->Insertln("^6stat: %d - %s", errno, strerror(errno));
792 
793       if (!S_ISDIR(buf.st_mode))
794         if (!fnmatch(pattern, fileinfo->d_name, FNM_PERIOD))
795           break;
796     }
797 
798     if (fileinfo == NULL)
799     {
800       gConsole->Insertln("^1readdir handle == NULL: %d - %s", errno, strerror(errno));
801       closedir(handle);
802       return NULL;
803     }
804   #endif
805 
806   strcpy(lastpath, pattern);
807   f_StripName(lastpath);
808   #ifdef WIN32
809     strcat(lastpath, fileinfo.name);
810   #else
811     strcat(lastpath, fileinfo->d_name);
812   #endif
813   return lastpath;
814 }
815 
FirstFile(const char * path)816 char *SearchFile::FirstFile(const char *path)
817 {
818   #ifdef WIN32
819     struct _finddata_t fileinfo;
820   #else
821     struct stat buf;
822     struct dirent* fileinfo;
823     char* temp = new char[1024];
824   #endif
825 
826   if (path == NULL)   // end of the list, reset and return
827   {
828     return NULL;
829   }
830 
831   if (temp_pat) delete [] temp_pat;
832   temp_pat = new char[strlen(path) + strlen(pattern) + 1];
833   strcpy(temp_pat, path);
834   strcat(temp_pat, pattern);
835 
836   f_CorrectSlashInName(temp_pat);
837 
838   #ifdef WIN32
839     handle = (int) _findfirst(temp_pat, &fileinfo);
840     if (handle == -1)
841     {
842       _findclose(handle);
843       if (temp_pat) delete [] temp_pat;
844       temp_pat = NULL;
845       return NULL;
846     }
847 
848     // skip non-valid filenames
849     while ((fileinfo.attrib & _A_SUBDIR) || fileinfo.name[0] == '.')
850     {
851       if (_findnext(handle, &fileinfo) == -1)
852       {
853         _findclose(handle);
854         return NULL;
855       }
856     }
857   #else
858     handle = opendir(path);
859 
860     if (handle == NULL)
861     {
862       gConsole->Insertln("^1handle == NULL: %d - %s", errno, strerror(errno));
863       if (temp_pat) delete [] temp_pat;
864       temp_pat = NULL;
865       return NULL;
866     }
867 
868     while ((fileinfo = readdir(handle)) != NULL)
869     {
870       memset(&buf, 0, sizeof(buf));
871       memset(temp, 0, sizeof(temp));
872 
873       strcpy(temp, path);
874       strcat(temp, fileinfo->d_name);
875 
876       if (stat(temp, &buf) < 0)
877         gConsole->Insertln("^6stat: %d - %s", errno, strerror(errno));
878 
879       if (!S_ISDIR(buf.st_mode))
880         if (!fnmatch( pattern, fileinfo->d_name, FNM_PERIOD))
881           break;
882     }
883 
884     if (fileinfo == NULL)
885     {
886       gConsole->Insertln("^1readdir handle == NULL: %d - %s", errno, strerror(errno));
887       closedir(handle);
888       return NULL;
889     }
890   #endif
891 
892   strcpy(lastpath, pattern);
893   f_StripName(lastpath);
894   #ifdef WIN32
895     strcat(lastpath, fileinfo.name);
896   #else
897     strcat(lastpath, fileinfo->d_name);
898   #endif
899   return lastpath;
900 }
901 
NextFile(void)902 char *SearchFile::NextFile(void)
903 {
904   #ifdef WIN32
905     struct _finddata_t fileinfo;
906 
907     while (_findnext(handle, &fileinfo) != -1)
908     {
909       if ((fileinfo.attrib & _A_SUBDIR)) continue;
910       if (fileinfo.name[0] == '.') continue;
911 
912       strcpy(lastpath, pattern);
913       f_StripName(lastpath);
914       strcat(lastpath, fileinfo.name);
915       return lastpath;
916     }
917     _findclose(handle);
918   #else
919     struct stat buf;
920     struct dirent* fileinfo;
921     char* temp = new char[1024];
922 
923     while ((fileinfo = readdir(handle)) != NULL)
924     {
925       memset(temp, 0, sizeof(temp));
926       strcpy(temp, last->path);
927       strcat(temp, fileinfo->d_name);
928 
929       if( stat(temp, &buf) < 0 )
930         gConsole->Insertln("^6stat: %d - %s", errno, strerror(errno));
931 
932       if (S_ISDIR(buf.st_mode) || (fnmatch(pattern, fileinfo->d_name, FNM_PERIOD) == FNM_NOMATCH))
933         continue;
934 
935       strcpy(lastpath, pattern);
936       f_StripName(lastpath);
937       strcat(lastpath, fileinfo->d_name);
938       return lastpath;
939     }
940     closedir(handle);
941   #endif
942 
943   if (temp_pat) delete [] temp_pat;
944   temp_pat = NULL;
945   last = last->next;
946   return FirstFile();
947 }
948 
NextFile(const char * path)949 char *SearchFile::NextFile(const char *path)
950 {
951   #ifdef WIN32
952     struct _finddata_t fileinfo;
953 
954     while (_findnext(handle, &fileinfo) != -1)
955     {
956       if ((fileinfo.attrib & _A_SUBDIR)) continue;
957       if (fileinfo.name[0] == '.') continue;
958 
959       strcpy(lastpath, pattern);
960       f_StripName(lastpath);
961       strcat(lastpath, fileinfo.name);
962       return lastpath;
963     }
964     _findclose(handle);
965   #else
966     struct stat buf;
967     struct dirent* fileinfo;
968     char* temp = new char[1024];
969 
970     while ((fileinfo = readdir(handle)) != NULL)
971     {
972       memset(temp, 0, sizeof(temp));
973       strcpy(temp, last->path);
974       strcat(temp, fileinfo->d_name);
975 
976       if (stat(temp, &buf) < 0)
977         gConsole->Insertln("^6stat: %d - %s", errno, strerror(errno));
978 
979       if (S_ISDIR(buf.st_mode) || (fnmatch(pattern, fileinfo->d_name, FNM_PERIOD) == FNM_NOMATCH))
980         continue;
981 
982       strcpy(lastpath, pattern);
983       f_StripName(lastpath);
984       strcat(lastpath, fileinfo->d_name);
985       return lastpath;
986     }
987     closedir(handle);
988   #endif
989 
990   if (temp_pat) delete [] temp_pat;
991   temp_pat = NULL;
992   return NULL;
993 }
994 
995 //-----------------------------------------------------------------------------
996 // Config File
997 //-----------------------------------------------------------------------------
998 
ConfigFile(char * name)999 ConfigFile::ConfigFile(char *name):VFile(name)
1000 {
1001   char buffer[256];
1002   if (mem)
1003   {
1004     gCommands->AddToConsole = false;
1005 
1006     gLogFile->Insert("<b>Loading config file...</b> (%s)\n", name);
1007 
1008     Parser::StartParseBuffer(mem, size);
1009 
1010     gLogFile->OpenFile();
1011     while (Parser::GetToken(true))
1012     {
1013       memset(buffer, 0, 256*sizeof(char));
1014       strcat(buffer, Parser::token);
1015       while (Parser::GetToken(false))
1016       {
1017         strcat(buffer, " ");
1018         strcat(buffer, Parser::token);
1019       }
1020       gLogFile->Insert("\t%d:\t%s\n", Parser::scriptline, buffer);
1021       if (!gCommands->ExecuteCommand(buffer))
1022         gLogFile->Insert("\t\t^5WARNING, Command not found: %s\n", buffer);
1023     }
1024     gLogFile->CloseFile();
1025     Parser::StopParseFile();
1026 
1027     gCommands->AddToConsole = true;
1028   }
1029   else
1030   {
1031     gConsole->Insertln("^5WARNING: Unable to read configuration file. Using default settings.");
1032   }
1033 }
1034 
1035 //-----------------------------------------------------------------------------
1036 // Shader initialization
1037 //-----------------------------------------------------------------------------
1038 
1039 #if SHADER_USE_REFERENCES
1040   static shader_ref_list *shader_refs = NULL; // Shader references
1041 
AddShaderToList(ShaderFile * fp,const char * shader,const char * file,const char * pak)1042   int AddShaderToList(ShaderFile *fp, const char *shader, const char *file, const char *pak)
1043   {
1044     shader_ref_list *ref;
1045 
1046     #if !SHADER_ALLOWDUPLICATE
1047       for (ref = shader_refs; ref; ref = ref->next)
1048         if (!strnicmp(shader, ref->shader_name, SHADER_NAME_MAX_LENGTH)) return 0;
1049     #endif
1050 
1051     ref = (shader_ref_list*) cake_malloc(sizeof(shader_ref_list), "Files::AddShaderToList.ref");
1052     if (!ref) ThrowException(ALLOCATION_ERROR, "Files::AddShaderToList.ref");
1053 
1054     strncpy(ref->shader_name, shader, SHADER_NAME_MAX_LENGTH);
1055 
1056     memset(ref->file_name, '\0', SHADER_NAME_MAX_LENGTH);
1057     if (file) strncpy(ref->file_name, file, SHADER_NAME_MAX_LENGTH);
1058 
1059     memset(ref->pak_name, '\0', SHADER_NAME_MAX_LENGTH);
1060     if (pak) strncpy(ref->pak_name, pak, SHADER_NAME_MAX_LENGTH);
1061 
1062     ref->offset = fp->GetShaderPos();
1063     ref->next = shader_refs;
1064     shader_refs = ref;
1065 
1066     return 1;
1067   }
1068 #else
1069   static shaders_file_list *shaders_files = NULL;
1070   static shaders_file_list *curr= NULL;
1071 
AddShadersFileToList(const char * file)1072   int AddShadersFileToList(const char *file)
1073   {
1074     shaders_file_list *ref;
1075 
1076     #if !SHADER_ALLOWDUPLICATE
1077       for (ref = shaders_files; ref; ref = ref->next)
1078         if (!strnicmp(file, ref->file_name, SHADER_NAME_MAX_LENGTH)) return 0;
1079     #endif
1080 
1081     ref = (shaders_file_list*) cake_malloc(sizeof(shaders_file_list), "Files::AddShadersFileToList.ref");
1082     if (!ref) ThrowException(ALLOCATION_ERROR, "AddShadersFileToList.ref");
1083 
1084     strncpy(ref->file_name, file, SHADER_NAME_MAX_LENGTH);
1085     ref->next = shaders_files;
1086     shaders_files = ref;
1087 
1088     return 1;
1089   }
1090 #endif
1091 
InitializeShaders(void)1092 void InitializeShaders(void)
1093 {
1094   gConsole->Insertln("<br/><b>^6----- Initializing shaders ------------------------------------</b>");
1095   int numshaderrefs = 0, numfiles = 0, numskippedfile = 0;
1096 
1097   DestroyShaderList();
1098 
1099   // PAK files
1100   int l;
1101   char *name;
1102 
1103   gLogFile->OpenFile();
1104   for (Pack *p = packets; p; p = p->next)
1105   {
1106     for (int i = 0; i < p->nFiles; ++i)
1107     {
1108       l = (int) strlen(p->files[i].name);
1109       if (l > 7 &&
1110         !strnicmp(&p->files[i].name[l-7], ".shader", 7) &&
1111         (!strnicmp(p->files[i].name, "scripts/", 8) || !strnicmp(p->files[i].name, "scripts\\", 8)))
1112       {
1113         ++numfiles;
1114         gConsole->Insertln("...loading \"%s\" (from \"%s\")", (char *) p->files[i].name, p->name);
1115         #if SHADER_USE_REFERENCES
1116         {
1117           char *shadername;
1118           ShaderFile file((char *) p->files[i].name, p->name);
1119 
1120           // parse each shader
1121           while ((shadername = file.GetShaderName()))
1122           {
1123             if (AddShaderToList(&file, shadername, (char *) p->files[i].name, p->name)) ++numshaderrefs;
1124             file.Skip();
1125           }
1126         }
1127         #else
1128           if (!AddShadersFileToList((char *) p->files[i].name)) ++numskippedfile;
1129         #endif
1130       }
1131     }
1132   }
1133 
1134   // Local files
1135   SearchFile search("scripts/*.shader");
1136 
1137   // for each .shader file
1138   for (name = search.FirstFile(); name; name = search.NextFile(), ++numfiles)
1139   {
1140     // opens the file:
1141     gConsole->Insertln("...loading \"%s\" (local file)", name);
1142     #if SHADER_USE_REFERENCES
1143     {
1144       char *shadername;
1145       ShaderFile file((char *) name);
1146 
1147       // parse each shader
1148       while ((shadername = file.GetShaderName()))
1149       {
1150         if (AddShaderToList(&file, shadername, name, NULL)) ++numshaderrefs;
1151         file.Skip();
1152       }
1153     }
1154     #else
1155       if (!AddShadersFileToList(name)) ++numskippedfile;
1156     #endif
1157   }
1158   gLogFile->CloseFile();
1159 
1160   gConsole->Insert("Initialization finished - ");
1161   #if SHADER_USE_REFERENCES
1162     gConsole->Insertln("%d shaders referenced in %d files (%d skipped)", numshaderrefs, numfiles, numskippedfile);
1163   #else
1164     gConsole->Insertln("found %d files containing shaders (%d skipped)", numfiles, numskippedfile);
1165   #endif
1166 }
1167 
DestroyShaderList(void)1168 void DestroyShaderList(void)
1169 {
1170   #if SHADER_USE_REFERENCES
1171     // Unallocation of completion list
1172     if (shader_refs)
1173     {
1174       for (; shader_refs;)
1175       {
1176         shader_ref_list *back = shader_refs->next;
1177         shader_refs->next = NULL;
1178         cake_free(shader_refs);
1179         shader_refs = back;
1180         back = NULL;
1181       }
1182       shader_refs = NULL;
1183     }
1184   #else
1185     curr = NULL;
1186 
1187     // Unallocation of completion list
1188     if (shaders_files)
1189     {
1190       for (; shaders_files;)
1191       {
1192         shaders_file_list *back = shaders_files->next;
1193         shaders_files->next = NULL;
1194         cake_free(shaders_files);
1195         shaders_files = back;
1196         back = NULL;
1197       }
1198       shaders_files = NULL;
1199     }
1200   #endif
1201 }
1202 
1203 #if SHADER_USE_REFERENCES
RefForShader(const char * shader)1204   shader_ref_list *RefForShader(const char *shader)
1205   {
1206     for (shader_ref_list *ref = shader_refs; ref; ref = ref->next)
1207     {
1208       if (!strnicmp(shader, (const char*) ref->shader_name, SHADER_NAME_MAX_LENGTH))
1209       {
1210         return ref;
1211       }
1212     }
1213 
1214     return NULL;
1215   }
1216 #else
GetFirstShadersFile(void)1217   char *GetFirstShadersFile(void)
1218   {
1219     curr = shaders_files;
1220     return curr->file_name;
1221   }
1222 
NextShadersFile(void)1223   char *NextShadersFile(void)
1224   {
1225     curr = curr->next;
1226     if (curr) return curr->file_name;
1227     else return NULL;
1228   }
1229 #endif
1230 
1231 //-----------------------------------------------------------------------------
1232 // Bitmap file writer
1233 //-----------------------------------------------------------------------------
WriteBitmapFile(char * filename,int width,int height,int bpp,unsigned char * imageData)1234 int WriteBitmapFile(char *filename, int width, int height, int bpp, unsigned char *imageData)
1235 {
1236   FILE       *filePtr;      // file pointer
1237   BITMAPFILEHEADER bitmapFileHeader;  // bitmap file header
1238   BITMAPINFOHEADER bitmapInfoHeader;  // bitmap info header
1239   int        imageIdx;      // used for swapping RGB->BGR
1240   unsigned char  tempRGB;     // used for swapping
1241 
1242   // open file for writing binary mode
1243   filePtr = fopen(filename, "wb");
1244   if (!filePtr) return 0;
1245 
1246   // define the bitmap file header
1247   bitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER);
1248   bitmapFileHeader.bfType = 0x4D42;
1249   bitmapFileHeader.bfReserved1 = 0;
1250   bitmapFileHeader.bfReserved2 = 0;
1251   bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
1252 
1253   // define the bitmap information header
1254   bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
1255   bitmapInfoHeader.biPlanes = 1;
1256   bitmapInfoHeader.biBitCount = bpp*8;
1257   bitmapInfoHeader.biCompression = BI_RGB;          // no compression
1258   bitmapInfoHeader.biSizeImage = width * abs(height) * bpp; // width * height * bpp
1259   bitmapInfoHeader.biXPelsPerMeter = 0;
1260   bitmapInfoHeader.biYPelsPerMeter = 0;
1261   bitmapInfoHeader.biClrUsed = 0;
1262   bitmapInfoHeader.biClrImportant = 0;
1263   bitmapInfoHeader.biWidth = width;             // bitmap width
1264   bitmapInfoHeader.biHeight = height;             // bitmap height
1265 
1266   // switch the image data from RGB to BGR
1267   for (imageIdx = 0; imageIdx < (int) bitmapInfoHeader.biSizeImage; imageIdx+=bpp)
1268   {
1269     tempRGB = imageData[imageIdx];
1270     imageData[imageIdx] = imageData[imageIdx + 2];
1271     imageData[imageIdx + 2] = tempRGB;
1272   }
1273 
1274   // write the bitmap file header
1275   fwrite(&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), filePtr);
1276 
1277   // write the bitmap info header
1278   fwrite(&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), filePtr);
1279 
1280   // write the image data
1281   fwrite(imageData, 1, bitmapInfoHeader.biSizeImage, filePtr);
1282 
1283   // close our file
1284   fclose(filePtr);
1285 
1286   return 1;
1287 }
1288