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