remove RSA's md4.c, replace by DP's
[xonotic/netradiant.git] / tools / quake2 / qdata / qdata.c
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "qdata.h"
23 #include "inout.h"
24 #include "md4.h"
25
26 qboolean        g_compress_pak;
27 qboolean        g_release;                      // don't grab, copy output data to new tree
28 qboolean        g_pak;                          // if true, copy to pak instead of release
29 char            g_releasedir[1024];     // c:\quake2\baseq2, etc
30 qboolean        g_archive;                      // don't grab, copy source data to new tree
31 qboolean        do3ds;
32 char            g_only[256];            // if set, only grab this cd
33 qboolean        g_skipmodel;            // set true when a cd is not g_only
34
35 char            *ext_3ds = "3ds";
36 char            *ext_tri= "tri";
37 char            *trifileext;
38
39 char            game[64] = "quake2";
40
41 void InitPaths( int *argc, char **argv );
42
43 /*
44 =======================================================
45
46   PAK FILES
47
48 =======================================================
49 */
50
51 typedef struct
52 {
53         char    name[56];
54         int             filepos, filelen;
55 } packfile_t;
56
57 typedef struct
58 {
59         char    id[4];
60         int             dirofs;
61         int             dirlen;
62 } packheader_t;
63
64 packfile_t              pfiles[16384];
65 FILE                    *pakfile;
66 packfile_t              *pf;
67 packheader_t    pakheader;
68
69
70
71 /*
72 ==============
73 BeginPak
74 ==============
75 */
76 void BeginPak (char *outname)
77 {
78         if (!g_pak)
79                 return;
80
81         pakfile = SafeOpenWrite (outname);
82
83         // leave space for header
84         SafeWrite (pakfile, &pakheader, sizeof(pakheader));
85         
86         pf = pfiles;
87 }
88
89
90 /*
91 ==============
92 ReleaseFile
93
94 Filename should be gamedir reletive.
95 Either copies the file to the release dir, or adds it to
96 the pak file.
97 ==============
98 */
99 void ReleaseFile (char *filename)
100 {
101         int             len;
102         byte    *buf;
103         char    source[1024];
104         char    dest[1024];
105
106         if (!g_release)
107                 return;
108
109         sprintf (source, "%s%s", gamedir, filename);
110
111         if (!g_pak)
112         {       // copy it
113                 sprintf (dest, "%s/%s", g_releasedir, filename);
114                 printf ("copying to %s\n", dest);
115                 QCopyFile (source, dest);
116                 return;
117         }
118
119         // pak it
120         printf ("paking %s\n", filename);
121         if (strlen(filename) >= sizeof(pf->name))
122                 Error ("Filename too long for pak: %s", filename);
123
124         len = LoadFile (source, (void **)&buf);
125
126         if (g_compress_pak && len < 4096*1024 )
127         {
128                 cblock_t        in, out;
129                 cblock_t Huffman (cblock_t in);
130
131                 in.count = len;
132                 in.data = buf;
133
134                 out = Huffman (in);
135
136                 if (out.count < in.count)
137                 {
138                         printf ("   compressed from %i to %i\n", in.count, out.count);
139                         free (in.data);
140                         buf = out.data;
141                         len = out.count;
142                 }
143                 else
144                         free (out.data);
145         }
146
147         strcpy (pf->name, filename);
148         pf->filepos = LittleLong(ftell(pakfile));
149         pf->filelen = LittleLong(len);
150         pf++;
151
152         SafeWrite (pakfile, buf, len);
153
154         free (buf);
155 }
156
157
158 /*
159 ==============
160 FinishPak
161 ==============
162 */
163 void FinishPak (void)
164 {
165         int             dirlen;
166         int             d;
167         int             i;
168         unsigned        checksum;
169
170         if (!g_pak)
171                 return;
172
173         pakheader.id[0] = 'P';
174         pakheader.id[1] = 'A';
175         pakheader.id[2] = 'C';
176         pakheader.id[3] = 'K';
177         dirlen = (byte *)pf - (byte *)pfiles;
178         pakheader.dirofs = LittleLong(ftell(pakfile));
179         pakheader.dirlen = LittleLong(dirlen);
180         
181         checksum = Com_BlockChecksum ( (void *)pfiles, dirlen );
182
183         SafeWrite (pakfile, pfiles, dirlen);
184
185         i = ftell (pakfile);
186          
187         fseek (pakfile, 0, SEEK_SET);
188         SafeWrite (pakfile, &pakheader, sizeof(pakheader));
189         fclose (pakfile);       
190         
191         d = pf - pfiles;
192         printf ("%i files packed in %i bytes\n",d, i);
193         printf ("checksum: 0x%x\n", checksum);
194 }
195
196
197 /*
198 ===============
199 Cmd_File
200
201 This is only used to cause a file to be copied during a release
202 build (default.cfg, maps, etc)
203 ===============
204 */
205 void Cmd_File (void)
206 {
207         GetToken (false);
208         ReleaseFile (token);
209 }
210
211 /*
212 ===============
213 PackDirectory_r
214
215 ===============
216 */
217 #ifdef _WIN32
218 #include "io.h"
219 void PackDirectory_r (char *dir)
220 {
221         struct _finddata_t fileinfo;
222         int             handle;
223         char    dirstring[1024];
224         char    filename[1024];
225
226         sprintf (dirstring, "%s%s/*.*", gamedir, dir);
227
228         handle = _findfirst (dirstring, &fileinfo);
229         if (handle == -1)
230                 return;
231
232         do
233         {
234                 sprintf (filename, "%s/%s", dir, fileinfo.name);
235                 if (fileinfo.attrib & _A_SUBDIR)
236                 {       // directory
237                         if (fileinfo.name[0] != '.')    // don't pak . and ..
238                                 PackDirectory_r (filename);
239                         continue;
240                 }
241                 // copy or pack the file
242                 ReleaseFile (filename);         
243         } while (_findnext( handle, &fileinfo ) != -1);
244
245         _findclose (handle);
246 }
247 #else
248
249 #include <sys/types.h>
250 #include <sys/dir.h>
251
252 void PackDirectory_r (char *dir)
253 {
254 #ifdef NeXT
255         struct direct **namelist, *ent;
256 #else
257         struct dirent **namelist, *ent;
258 #endif
259         int             count;
260         struct stat st;
261         int                     i;
262         int                     len;
263         char            fullname[1024];
264         char            dirstring[1024];
265         char            *name;
266         
267         sprintf (dirstring, "%s%s", gamedir, dir);
268         count = scandir(dirstring, &namelist, NULL, NULL);
269         
270         for (i=0 ; i<count ; i++)
271         {
272                 ent = namelist[i];      
273                 name = ent->d_name;
274
275                 if (name[0] == '.')
276                         continue;
277         
278                 sprintf (fullname, "%s/%s", dir, name);
279                 sprintf (dirstring, "%s%s/%s", gamedir, dir, name);
280                 
281                 if (stat (dirstring, &st) == -1)
282                         Error ("fstating %s", pf->name);
283                 if (st.st_mode & S_IFDIR)
284                 {       // directory
285                         PackDirectory_r (fullname);
286                         continue;
287                 }
288
289                 // copy or pack the file
290                 ReleaseFile (fullname);         
291         }
292 }
293 #endif
294
295
296 /*
297 ===============
298 Cmd_Dir
299
300 This is only used to cause a directory to be copied during a
301 release build (sounds, etc)
302 ===============
303 */
304 void Cmd_Dir (void)
305 {
306         GetToken (false);
307         PackDirectory_r (token);        
308 }
309
310 //========================================================================
311
312 #define MAX_RTEX        16384
313 int             numrtex;
314 char    rtex[MAX_RTEX][64];
315
316 void ReleaseTexture (char *name)
317 {
318         int             i;
319         char    path[1024];
320
321         for (i=0 ; i<numrtex ; i++)
322                 if (!Q_strncasecmp(name, rtex[i], strlen(name)))
323                         return;
324
325         if (numrtex == MAX_RTEX)
326                 Error ("numrtex == MAX_RTEX");
327
328         strcpy (rtex[i], name);
329         numrtex++;
330
331         sprintf (path, "textures/%s.wal", name);
332         ReleaseFile (path);
333 }
334
335 /*
336 ===============
337 Cmd_Maps
338
339 Only relevent for release and pak files.
340 Releases the .bsp files for the maps, and scans all of the files to
341 build a list of all textures used, which are then released.
342 ===============
343 */
344 void Cmd_Maps (void)
345 {
346         char    map[1024];
347         int             i;
348
349         while (TokenAvailable ())
350         {
351                 GetToken (false);
352                 sprintf (map, "maps/%s.bsp", token);
353                 ReleaseFile (map);
354
355                 if (!g_release)
356                         continue;
357
358                 // get all the texture references
359                 sprintf (map, "%smaps/%s.bsp", gamedir, token);
360                 LoadBSPFileTexinfo (map);
361                 for (i=0 ; i<numtexinfo ; i++)
362                         ReleaseTexture (texinfo[i].texture);
363         }
364 }
365
366
367 //==============================================================
368
369 /*
370 ===============
371 ParseScript
372 ===============
373 */
374 void ParseScript (void)
375 {
376         while (1)
377         {
378                 do
379                 {       // look for a line starting with a $ command
380                         GetToken (true);
381                         if (endofscript)
382                                 return;
383                         if (token[0] == '$')
384                                 break;                          
385                         while (TokenAvailable())
386                                 GetToken (false);
387                 } while (1);
388         
389                 //
390                 // model commands
391                 //
392                 if (!strcmp (token, "$modelname"))
393                         Cmd_Modelname ();
394                 else if (!strcmp (token, "$base"))
395                         Cmd_Base ();
396                 else if (!strcmp (token, "$cd"))
397                         Cmd_Cd ();
398                 else if (!strcmp (token, "$origin"))
399                         Cmd_Origin ();
400                 else if (!strcmp (token, "$scale"))
401                         Cmd_ScaleUp ();
402                 else if (!strcmp (token, "$frame"))
403                         Cmd_Frame ();
404                 else if (!strcmp (token, "$skin"))
405                         Cmd_Skin ();
406                 else if (!strcmp (token, "$skinsize"))
407                         Cmd_Skinsize ();
408                 //
409                 // sprite commands
410                 //
411                 else if (!strcmp (token, "$spritename"))
412                         Cmd_SpriteName ();
413                 else if (!strcmp (token, "$load"))
414                         Cmd_Load ();
415                 else if (!strcmp (token, "$spriteframe"))
416                         Cmd_SpriteFrame ();
417                 //
418                 // image commands
419                 //
420                 else if (!strcmp (token, "$grab"))
421                         Cmd_Grab ();
422                 else if (!strcmp (token, "$raw"))
423                         Cmd_Raw ();
424                 else if (!strcmp (token, "$colormap"))
425                         Cmd_Colormap ();
426                 else if (!strcmp (token, "$mippal"))
427                         Cmd_Mippal ();
428                 else if (!strcmp (token, "$mipdir"))
429                         Cmd_Mipdir ();
430                 else if (!strcmp (token, "$mip"))
431                         Cmd_Mip ();
432                 else if (!strcmp (token, "$environment"))
433                         Cmd_Environment ();
434                 //
435                 // video
436                 //
437                 else if (!strcmp (token, "$video"))
438                         Cmd_Video ();
439                 //
440                 // misc
441                 //
442                 else if (!strcmp (token, "$file"))
443                         Cmd_File ();
444                 else if (!strcmp (token, "$dir"))
445                         Cmd_Dir ();
446                 else if (!strcmp (token, "$maps"))
447                         Cmd_Maps ();
448                 else if (!strcmp (token, "$alphalight"))
449                         Cmd_Alphalight ();
450                 else if (!strcmp (token, "$inverse16table" ))
451                         Cmd_Inverse16Table();
452                 else
453                         Error ("bad command %s\n", token);
454         }
455 }
456
457 //=======================================================
458
459 /*
460 ==============
461 main
462 ==============
463 */
464 int main (int argc, char **argv)
465 {
466         static  int             i;              // VC4.2 compiler bug if auto...
467         char    path[1024];
468
469         ExpandWildcards (&argc, &argv);
470
471   InitPaths( &argc, argv );
472
473         for (i=1 ; i<argc ; i++)
474         {
475                 if (!strcmp(argv[i], "-archive"))
476                 {
477                         // -archive f:/quake2/release/dump_11_30
478                         archive = true;
479                         strcpy (archivedir, argv[i+1]);
480                         printf ("Archiving source to: %s\n", archivedir);
481                         i++;
482                 }
483                 else if (!strcmp(argv[i], "-release"))
484                 {
485                         g_release = true;
486                         strcpy (g_releasedir, argv[i+1]);
487                         printf ("Copy output to: %s\n", g_releasedir);
488                         i++;
489                 }
490                 else if (!strcmp(argv[i], "-compress"))
491                 {
492                         g_compress_pak = true;
493                         printf ("Compressing pakfile\n");
494                 }
495                 else if (!strcmp(argv[i], "-pak"))
496                 {
497                         g_release = true;
498                         g_pak = true;
499                         printf ("Building pakfile: %s\n", argv[i+1]);
500                         BeginPak (argv[i+1]);
501                         i++;
502                 }
503                 else if (!strcmp(argv[i], "-only"))
504                 {
505                         strcpy (g_only, argv[i+1]);
506                         printf ("Only grabbing %s\n", g_only);
507                         i++;
508                 }
509                 else if (!strcmp(argv[i], "-3ds"))
510                 {
511                         do3ds = true;
512                         printf ("loading .3ds files\n");
513                 }
514                 else if (argv[i][0] == '-')
515                         Error ("Unknown option \"%s\"", argv[i]);
516                 else
517                         break;
518         }
519
520         if (i >= argc)
521                 Error ("usage: %s [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr", argv[ 0 ] );
522
523         if (do3ds)
524                 trifileext = ext_3ds;
525         else
526                 trifileext = ext_tri;
527
528         for ( ; i<argc ; i++)
529         {
530                 printf ("--------------- %s ---------------\n", argv[i]);
531                 // load the script
532                 strcpy (path, argv[i]);
533                 DefaultExtension (path, ".qdt");
534                 SetQdirFromPath (path);
535                 LoadScriptFile (ExpandArg(path));
536                 
537                 //
538                 // parse it
539                 //
540                 ParseScript ();
541
542                 // write out the last model
543                 FinishModel ();
544                 FinishSprite ();
545         }
546
547         if (g_pak)
548                 FinishPak ();
549
550         return 0;
551 }
552