1 /*
2 * wads2.cc
3 * Wads functions that are not needed during editing.
4 * AYM 1998-08-09
5 */
6
7
8 /*
9 This file is part of Yadex.
10
11 Yadex incorporates code from DEU 5.21 that was put in the public domain in
12 1994 by Rapha�l Quinet and Brendon Wyber.
13
14 The rest of Yadex is Copyright � 1997-2003 Andr� Majorel and others.
15
16 This program is free software; you can redistribute it and/or modify it under
17 the terms of the GNU General Public License as published by the Free Software
18 Foundation; either version 2 of the License, or (at your option) any later
19 version.
20
21 This program is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License along with
26 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
27 Place, Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30
31 #include "yadex.h"
32 #include "game.h" /* yg_picture_format */
33 #include "serialnum.h"
34 #include "wadfile.h"
35 #include "wadlist.h"
36 #include "wads.h"
37 #include "wads2.h"
38
39
40 static char *locate_pwad (const char *filename);
41 static int level_name_order (const void *p1, const void *p2);
42
43
44 /*
45 * OpenMainWad - open the iwad
46 *
47 * Open the main wad file, read in its directory and create
48 * the master directory.
49 *
50 * Return 0 on success, non-zero on failure.
51 */
OpenMainWad(const char * filename)52 int OpenMainWad (const char *filename)
53 {
54 MDirPtr lastp, newp;
55 long n;
56 Wad_file *wf;
57
58 /* open the wad file */
59 printf ("Loading iwad: %s...\n", filename);
60 wf = BasicWadOpen (filename, yg_picture_format);
61 if (wf == 0)
62 return 1;
63 if (strncmp (wf->type, "IWAD", 4))
64 warn ("%.128s: is a pwad, not an iwad. Will use it anyway.\n", filename);
65
66 /* create the master directory */
67 lastp = NULL;
68 for (n = 0; n < wf->dirsize; n++)
69 {
70 newp = (MDirPtr) GetMemory (sizeof (struct MasterDirectory));
71 newp->next = NULL;
72 newp->wadfile = wf;
73 memcpy (&(newp->dir), &(wf->directory[n]), sizeof (struct Directory));
74 if (MasterDir)
75 lastp->next = newp;
76 else
77 MasterDir = newp;
78 lastp = newp;
79 }
80 master_dir_serial.bump ();
81
82 /* check if registered version */
83 if (FindMasterDir (MasterDir, "E2M1") == NULL
84 && FindMasterDir (MasterDir, "MAP01") == NULL
85 && FindMasterDir (MasterDir, "MAP33") == NULL
86 && strcmp (Game, "doom02")
87 && strcmp (Game, "doom04")
88 && strcmp (Game, "doom05")
89 && strcmp (Game, "doompr"))
90 {
91 printf (" *-----------------------------------------------------*\n");
92 printf (" | Warning: this is the shareware version of the game. |\n");
93 printf (" | You won't be allowed to save your changes. |\n");
94 printf (" | PLEASE REGISTER YOUR COPY OF THE GAME. |\n");
95 printf (" *-----------------------------------------------------*\n");
96 Registered = false; // If you remove this, bad things will happen to you...
97 }
98 else
99 Registered = true;
100 return 0;
101 }
102
103
104 /*
105 * OpenPatchWad - add a pwad
106 *
107 * Open a patch wad file, read in its directory and alter
108 * the master directory.
109 *
110 * Return 0 on success, non-zero on failure.
111 */
OpenPatchWad(const char * filename)112 int OpenPatchWad (const char *filename)
113 {
114 Wad_file * wad;
115 MDirPtr mdir = 0;
116 long n;
117 char entryname[WAD_NAME + 1];
118 const char *entry_type = 0;
119 char *real_name;
120 int nitems = 0; // Number of items in group of flats/patches/sprites
121
122 // Look for the file and ignore it if it doesn't exist
123 real_name = locate_pwad (filename);
124 if (real_name == NULL)
125 {
126 warn ("%.128s: not found.\n", filename);
127 return 1;
128 }
129
130 /* open the wad file */
131 printf ("Loading pwad: %s...\n", real_name);
132 // By default, assume pwads use the normal picture format.
133 wad = BasicWadOpen (real_name, YGPF_NORMAL);
134 FreeMemory (real_name);
135 if (! wad)
136 return 1;
137 if (strncmp (wad->type, "PWAD", 4))
138 warn ("%.128s: is an iwad, not a pwad. Will use it anyway.\n", filename);
139
140 /* alter the master directory */
141
142 /* AYM: now, while the directory is scanned, a state variable is
143 updated. its values are :
144 0 no special state
145 1-11 reading level lumps */
146 /* AYM 1998-11-15: FIXME: to be on the safe side, should consider
147 FF_END to end a group of flats if the following entry is neither
148 F_END nor F?_START. */
149
150 int state = 0;
151 int replaces = 0;
152 int state_prev;
153 int replaces_prev;
154 int names = 0; // Number of names already printed on current line
155 const char *entry_type_prev;
156 typedef char level_list_item_t[WAD_NAME];
157 level_list_item_t *level_list = 0;
158 size_t nlevels = 0;
159 for (n = 0; n < wad->dirsize; n++)
160 {
161 strncpy (entryname, wad->directory[n].name, WAD_NAME);
162 entryname[WAD_NAME] = '\0';
163 state_prev = state;
164 replaces_prev = replaces;
165 entry_type_prev = entry_type;
166 if (state == 0)
167 {
168 if (! strcmp (entryname, "F_START")
169 || ! strcmp (entryname, "P_START")
170 || ! strcmp (entryname, "S_START"))
171 {
172 entry_type = "label";
173 replaces = 0;
174 }
175 // DeuTex puts flats between FF_START and FF_END/F_END.
176 // All lumps between those markers are assumed
177 // to be flats.
178 else if (! strncmp (entryname, "FF_START", WAD_NAME))
179 {
180 state = 'f';
181 entry_type = "group of flats";
182 replaces = 0;
183 nitems = 0;
184 }
185 // DeuTex puts patches between PP_START and PP_END.
186 // All lumps between those markers are assumed
187 // to be patches.
188 else if (! strncmp (entryname, "PP_START", WAD_NAME))
189 {
190 state = 'p';
191 entry_type = "group of patches";
192 replaces = 0;
193 nitems = 0;
194 }
195 // DeuTex puts patches between SS_START and SS_END/S_END.
196 // All lumps between those markers are assumed
197 // to be sprites.
198 else if (! strncmp (entryname, "SS_START", WAD_NAME))
199 {
200 state = 's';
201 entry_type = "group of sprites";
202 replaces = 0;
203 nitems = 0;
204 }
205 else
206 {
207 mdir = FindMasterDir (MasterDir, entryname);
208 replaces = mdir != NULL;
209 /* if it is a level, do the same thing for the next 10 entries too */
210 if (levelname2levelno (entryname))
211 {
212 state = 11;
213 entry_type = "level";
214 // Add to list of level names
215 {
216 level_list_item_t *new_list;
217 new_list = (level_list_item_t *)
218 realloc (level_list, (nlevels + 1) * sizeof *level_list);
219 if (new_list != 0)
220 {
221 level_list = new_list;
222 strncpy (level_list[nlevels], entryname, sizeof *level_list);
223 nlevels++;
224 }
225 }
226 }
227 else
228 entry_type = "entry";
229 }
230 if (n == 0
231 || state_prev != state
232 || replaces_prev != replaces
233 || entry_type_prev != entry_type)
234 {
235 if (n > 0)
236 verbmsg ("\n");
237 names = 0;
238 verbmsg (" %s %s", replaces ? "Updating" : "Adding new", entry_type);
239 }
240 if (names >= 6)
241 {
242 verbmsg ("\n %-*s %-*s",
243 strlen (replaces ? "Updating" : "Adding new"), "",
244 strlen (entry_type), "");
245 names = 0;
246 }
247 verbmsg (" %-*s", WAD_NAME, entryname);
248 names++;
249 if ((*entry_type == 'm' || *entry_type == 'l') && wad->directory[n].size)
250 verbmsg (" warning: non-zero length (%ld)", wad->directory[n].size);
251 }
252 // Either F_END or FF_END mark the end of a
253 // DeuTex-generated group of flats.
254 else if (state == 'f')
255 {
256 if (! strncmp (entryname, "F_END", WAD_NAME)
257 || ! strncmp (entryname, "FF_END", WAD_NAME))
258 {
259 state = 0;
260 verbmsg ("/%.*s (%d flats)", WAD_NAME, entryname, nitems);
261 }
262 // Of course, F?_START and F?_END don't count
263 // toward the number of flats in the group.
264 else if (! (*entryname == 'F'
265 && (! strncmp (entryname + 2, "_START", 6)
266 || ! strcmp (entryname + 2, "_END"))))
267 nitems++;
268 }
269 // PP_END marks the end of a DeuTex-generated group of patches.
270 else if (state == 'p')
271 {
272 if (! strncmp (entryname, "PP_END", WAD_NAME))
273 {
274 state = 0;
275 verbmsg ("/PP_END (%d patches)", nitems);
276 }
277 // Of course, P?_START and P?_END don't count
278 // toward the number of flats in the group.
279 else if (! (*entryname == 'P'
280 && (! strncmp (entryname + 2, "_START", 6)
281 || ! strcmp (entryname + 2, "_END"))))
282 nitems++;
283 }
284 // Either S_END or SS_END mark the end of a
285 // DeuTex-generated group of sprites.
286 else if (state == 's')
287 {
288 if (! strncmp (entryname, "S_END", WAD_NAME)
289 || ! strncmp (entryname, "SS_END", WAD_NAME))
290 {
291 state = 0;
292 verbmsg ("/%.*s (%d sprites)", WAD_NAME, entryname, nitems);
293 }
294 // Of course, S?_START and S?_END don't count
295 // toward the number of sprites in the group.
296 else if (! (*entryname == 'S'
297 && (! strncmp (entryname + 2, "_START", 6)
298 || ! strcmp (entryname + 2, "_END"))))
299 nitems++;
300 }
301
302 /* if this entry is not in the master directory, then add it */
303 if (!replaces)
304 {
305 mdir = MasterDir;
306 while (mdir->next)
307 mdir = mdir->next;
308 mdir->next = (MDirPtr) GetMemory (sizeof (struct MasterDirectory));
309 mdir = mdir->next;
310 mdir->next = NULL;
311 }
312 /* else, simply replace it */
313 mdir->wadfile = wad;
314 memcpy (&(mdir->dir), &(wad->directory[n]), sizeof (struct Directory));
315 mdir = mdir->next;
316
317 if (state > 0 && state <= 11)
318 state--;
319 }
320 verbmsg ("\n");
321 master_dir_serial.bump ();
322
323 // Print list of levels found in this pwad
324 if (level_list != 0)
325 {
326 printf (" Levels: ");
327 qsort (level_list, nlevels, sizeof *level_list, level_name_order);
328 for (size_t n = 0; n < nlevels; n++)
329 {
330 int prev = n > 0 ? levelname2rank (level_list[n - 1]) : INT_MIN;
331 int cur = levelname2rank (level_list[n ]);
332 int next = n + 1 < nlevels ? levelname2rank (level_list[n + 1]) : INT_MAX;
333 if (cur != prev + 1 || cur != next - 1)
334 {
335 if (cur == prev + 1)
336 putchar ('-');
337 else if (n > 0)
338 putchar (' ');
339 printf ("%.*s", (int) sizeof *level_list, level_list[n]);
340 }
341 }
342 putchar ('\n');
343 free (level_list);
344 }
345 return 0;
346 }
347
348
349 /*
350 * level_name_order - -cmp-style comparison of two level names
351 */
level_name_order(const void * p1,const void * p2)352 static int level_name_order (const void *p1, const void *p2)
353 {
354 return levelname2rank ((const char *) p1)
355 - levelname2rank ((const char *) p2);
356 }
357
358
359 /*
360 * CloseWadFiles - close all wads
361 *
362 * Close all the wad, deallocating the wad file structures.
363 */
CloseWadFiles()364 void CloseWadFiles ()
365 {
366 MDirPtr curd, nextd;
367
368 // Close the wad files
369 Wad_file *wf;
370 wad_list.rewind ();
371 while (wad_list.get (wf))
372 wad_list.del ();
373
374 // Delete the master directory
375 curd = MasterDir;
376 MasterDir = NULL;
377 while (curd)
378 {
379 nextd = curd->next;
380 FreeMemory (curd);
381 curd = nextd;
382 }
383 master_dir_serial.bump ();
384 }
385
386
387 /*
388 * CloseUnusedWadFiles - forget unused patch wad files
389 */
CloseUnusedWadFiles()390 void CloseUnusedWadFiles ()
391 {
392 Wad_file *wf;
393 wad_list.rewind ();
394 while (wad_list.get (wf))
395 {
396 // Check if the wad file is used by a directory entry
397 MDirPtr mdir = MasterDir;
398 while (mdir && mdir->wadfile != wf)
399 mdir = mdir->next;
400 if (mdir == 0)
401 wad_list.del ();
402 }
403 }
404
405
406 /*
407 * BasicWadOpen - open a wad
408 *
409 * Basic opening of wad file and creation of node in Wad
410 * linked list.
411 *
412 * Return a null pointer on error.
413 */
BasicWadOpen(const char * filename,ygpf_t pic_format)414 Wad_file *BasicWadOpen (const char *filename, ygpf_t pic_format)
415 {
416 bool fail = false;
417
418 /* If this wad is already open, close it first (it's not always
419 possible to open the same file twice). Also position the
420 wad_list pointer on the old wad (or at the end of the list if
421 this is a new wad) so that the reopening a wad doesn't change
422 it's relative position in the list.
423
424 FIXME if reopening fails, we're left in the cold. I'm not
425 sure how to avoid that, though. */
426 {
427 Wad_file *dummy;
428 wad_list.rewind ();
429 while (wad_list.get (dummy))
430 if (fncmp (filename, dummy->filename) == 0)
431 {
432 wad_list.del ();
433 break;
434 }
435 }
436
437 // Create a new Wad_file
438 Wad_file *wf = new Wad_file;
439 wf->pic_format_ = pic_format;
440 wf->directory = 0;
441 wf->filename = (char *) GetMemory (strlen (filename) + 1);
442 strcpy (wf->filename, filename);
443
444 // Open the wad and read its header.
445 wf->fp = fopen (filename, "rb");
446 if (wf->fp == 0)
447 {
448 printf ("%.128s: %s\n", filename, strerror (errno));
449 fail = true;
450 goto byebye;
451 }
452 {
453 bool e = file_read_bytes (wf->fp, wf->type, 4);
454 e |= file_read_i32 (wf->fp, &wf->dirsize);
455 e |= file_read_i32 (wf->fp, &wf->dirstart);
456 if (e || memcmp (wf->type, "IWAD", 4) != 0 && memcmp (wf->type, "PWAD", 4) != 0)
457 {
458 printf ("%.128s: not a wad (bad header)\n", filename);
459 fail = true;
460 goto byebye;
461 }
462 }
463 verbmsg (" Type %.4s, directory has %ld entries at offset %08lXh\n",
464 wf->type, (long) wf->dirsize, (long) wf->dirstart);
465
466 // Load the directory of the wad
467 wf->directory = (DirPtr) GetMemory ((long) sizeof (struct Directory)
468 * wf->dirsize);
469 if (fseek (wf->fp, wf->dirstart, SEEK_SET) != 0)
470 {
471 printf ("%.128s: can't seek to directory at %08lXh\n",
472 filename, wf->dirstart);
473 fail = true;
474 goto byebye;
475 }
476 for (i32 n = 0; n < wf->dirsize; n++)
477 {
478 bool e = file_read_i32 (wf->fp, &wf->directory[n].start);
479 e |= file_read_i32 (wf->fp, &wf->directory[n].size);
480 e |= file_read_bytes (wf->fp, wf->directory[n].name, WAD_NAME);
481 if (e)
482 {
483 printf ("%.128s: read error on directory entry %ld\n", filename, (long)n);
484 fail = true;
485 goto byebye;
486 }
487 }
488
489 // Insert the new wad in the list
490 wad_list.insert (wf);
491
492 byebye:
493 if (fail)
494 {
495 delete wf;
496 return 0;
497 }
498 return wf;
499 }
500
501
502 /*
503 * ListMasterDirectory - list the master directory
504 */
ListMasterDirectory(FILE * file)505 void ListMasterDirectory (FILE *file)
506 {
507 char dataname[WAD_NAME + 1];
508 MDirPtr dir;
509 char key;
510 int lines = 3;
511
512 dataname[WAD_NAME] = '\0';
513 fprintf (file, "The Master Directory\n");
514 fprintf (file, "====================\n\n");
515 fprintf (file, "NAME____ FILE______________________________________________"
516 " SIZE__ START____\n");
517 for (dir = MasterDir; dir; dir = dir->next)
518 {
519 strncpy (dataname, dir->dir.name, WAD_NAME);
520 fprintf (file, "%-*s %-50s %6ld x%08lx\n",
521 WAD_NAME, dataname, dir->wadfile->pathname (),
522 dir->dir.size, dir->dir.start);
523 if (file == stdout && lines++ > screen_lines - 4)
524 {
525 lines = 0;
526 printf ("['Q' followed by Return to abort, Return only to continue]");
527 key = getchar ();
528 printf ("\r%57s\r", "");
529 if (key == 'Q' || key == 'q')
530 {
531 getchar (); // Read the '\n'
532 break;
533 }
534 }
535 }
536 }
537
538
539 /*
540 * ListFileDirectory - list the directory of a wad
541 */
ListFileDirectory(FILE * file,const Wad_file * wad)542 void ListFileDirectory (FILE *file, const Wad_file *wad)
543 {
544 char dataname[WAD_NAME + 1];
545 char key;
546 int lines = 5;
547 long n;
548
549 dataname[WAD_NAME] = '\0';
550 fprintf (file, "Wad File Directory\n");
551 fprintf (file, "==================\n\n");
552 fprintf (file, "Wad File: %s\n\n", wad->pathname ());
553 fprintf (file, "NAME____ SIZE__ START____ END______\n");
554 for (n = 0; n < wad->dirsize; n++)
555 {
556 strncpy (dataname, wad->directory[n].name, WAD_NAME);
557 fprintf (file, "%-*s %6ld x%08lx x%08lx\n",
558 WAD_NAME, dataname,
559 wad->directory[n].size,
560 wad->directory[n].start,
561 wad->directory[n].size + wad->directory[n].start - 1);
562 if (file == stdout && lines++ > screen_lines - 4)
563 {
564 lines = 0;
565 printf ("['Q' followed by Return to abort, Return only to continue]");
566 key = getchar ();
567 printf ("\r%57s\r", "");
568 if (key == 'Q' || key == 'q')
569 {
570 getchar (); // Read the '\n'
571 break;
572 }
573 }
574 }
575 }
576
577
578 /*
579 * BuildNewMainWad - build a new iwad (or pwad)
580 *
581 * Build a new wad file from master directory.
582 */
BuildNewMainWad(const char * filename,bool patchonly)583 void BuildNewMainWad (const char *filename, bool patchonly)
584 {
585 FILE *file;
586 long counter = 12;
587 MDirPtr cur;
588 long size;
589 long dirstart;
590 long dirnum;
591
592 /* open the file and store signatures */
593 if (patchonly)
594 printf ("Building a compound Patch Wad file \"%s\".\n", filename);
595 else
596 printf ("Building a new Main Wad file \"%s\" (size approx 10 MB)\n",
597 filename);
598 if (FindMasterDir (MasterDir, "E2M4") == NULL
599 && FindMasterDir (MasterDir, "MAP01") == NULL
600 && FindMasterDir (MasterDir, "MAP33") == NULL
601 && strcmp (Game, "doom02")
602 && strcmp (Game, "doom04")
603 && strcmp (Game, "doom05")
604 && strcmp (Game, "doompr"))
605 fatal_error ("You were warned: you are not allowed to do this.");
606 if ((file = fopen (filename, "wb")) == NULL)
607 fatal_error ("unable to open file \"%s\"", filename);
608 if (patchonly)
609 WriteBytes (file, "PWAD", 4);
610 else
611 WriteBytes (file, "IWAD", 4);
612 file_write_i32 (file, 0xdeadbeef); /* put true value in later */
613 file_write_i32 (file, 0xdeadbeef); /* put true value in later */
614
615 /* output the directory data chunks */
616 const Wad_file *iwad = 0; // FIXME unreliable way of knowing the iwad
617 wad_list.rewind (); // got to look into this
618 wad_list.get (iwad);
619 for (cur = MasterDir; cur; cur = cur->next)
620 {
621 if (patchonly && cur->wadfile == iwad)
622 continue;
623 size = cur->dir.size;
624 counter += size;
625 cur->wadfile->seek (cur->dir.start);
626 if (cur->wadfile->error ())
627 ; // FIXME
628 if (copy_bytes (file, cur->wadfile->fp, size) != 0)
629 ; // FIXME
630 printf ("Size: %luK\r", counter / 1024);
631 }
632
633 /* output the directory */
634 dirstart = counter;
635 counter = 12;
636 dirnum = 0;
637 for (cur = MasterDir; cur; cur = cur->next)
638 {
639 if (patchonly && cur->wadfile == iwad)
640 continue;
641 if (dirnum % 100 == 0)
642 printf ("Outputting directory %04ld...\r", dirnum);
643 if (cur->dir.start)
644 file_write_i32 (file, counter);
645 else
646 file_write_i32 (file, 0);
647 file_write_i32 (file, cur->dir.size);
648 file_write_name (file, cur->dir.name);
649 counter += cur->dir.size;
650 dirnum++;
651 }
652
653 /* fix up the number of entries and directory start information */
654 if (fseek (file, 4L, 0))
655 fatal_error ("error writing to file");
656 file_write_i32 (file, dirnum);
657 file_write_i32 (file, dirstart);
658
659 /* close the file */
660 printf (" \r");
661 fclose (file);
662 }
663
664
665 /*
666 * DumpDirectoryEntry - hexadecimal dump of a lump
667 *
668 * Dump a directory entry in hex
669 */
DumpDirectoryEntry(FILE * file,const char * entryname)670 void DumpDirectoryEntry (FILE *file, const char *entryname)
671 {
672 char dataname[WAD_NAME + 1];
673 char key;
674 int lines = 5;
675 long n = 0;
676 unsigned char buf[16];
677 const int bytes_per_line = 16;
678
679 for (MDirPtr entry = MasterDir; entry != 0; entry = entry->next)
680 {
681 if (y_strnicmp (entry->dir.name, entryname, WAD_NAME) != 0)
682 continue;
683 strncpy (dataname, entry->dir.name, WAD_NAME);
684 dataname[WAD_NAME] = '\0';
685 fprintf (file, "Contents of entry %s (size = %ld bytes):\n",
686 dataname, entry->dir.size);
687 const Wad_file *wf = entry->wadfile;
688 wf->seek (entry->dir.start);
689 for (n = 0; n < entry->dir.size;)
690 {
691 int i;
692 fprintf (file, "%04lX: ", n);
693
694 // Nb of bytes to read for this line
695 long bytes_to_read = entry->dir.size - n;
696 if (bytes_to_read > bytes_per_line)
697 bytes_to_read = bytes_per_line;
698 long nbytes = wf->read_vbytes (buf, bytes_to_read);
699 if (wf->error ())
700 break;
701 n += nbytes;
702
703 for (i = 0; i < nbytes; i++)
704 fprintf (file, " %02X", buf[i]);
705 for (; i < bytes_per_line; i++)
706 fputs (" ", file);
707 fprintf (file, " ");
708
709 for (i = 0; i < nbytes; i++)
710 {
711 if (buf[i] >= 0x20
712 && buf[i] != 0x7f
713 #ifdef Y_UNIX
714 && ! (buf[i] >= 0x80 && buf[i] <= 0xa0) // ISO 8859-1
715 #endif
716 )
717 putc (buf[i], file);
718 else
719 putc ('.', file);
720 }
721 putc ('\n', file);
722
723 if (file == stdout && lines++ > screen_lines - 4)
724 {
725 lines = 0;
726 printf ("[%d%% - Q + Return to abort,"
727 " S + Return to skip this entry,"
728 " Return to continue]", (int) (n * 100 / entry->dir.size));
729 key = getchar ();
730 printf ("\r%68s\r", "");
731 if (key == 'S' || key == 's')
732 {
733 getchar (); // Read the '\n'
734 break;
735 }
736 if (key == 'Q' || key == 'q')
737 {
738 getchar (); // Read the '\n'
739 return;
740 }
741 }
742 }
743 }
744 if (! n)
745 {
746 printf ("Entry not in master directory.\n");
747 return;
748 }
749 }
750
751
752
753 /*
754 * SaveDirectoryEntry - write the contents of a lump to a new pwad
755 *
756 * Save a directory entry to disk
757 */
SaveDirectoryEntry(FILE * file,const char * entryname)758 void SaveDirectoryEntry (FILE *file, const char *entryname)
759 {
760 MDirPtr entry;
761
762 for (entry = MasterDir; entry; entry = entry->next)
763 if (!y_strnicmp (entry->dir.name, entryname, WAD_NAME))
764 break;
765 if (entry)
766 {
767 // Write the header
768 WriteBytes (file, "PWAD", 4); // Type = PWAD
769 file_write_i32 (file, 1); // 1 entry in the directory
770 file_write_i32 (file, 12); // The directory starts at offset 12
771
772 // Write the directory
773 file_write_i32 (file, 28); // First entry starts at offset 28
774 file_write_i32 (file, entry->dir.size); // Size of first entry
775 file_write_name (file, entry->dir.name); // Name of first entry
776
777 // Write the lump data
778 entry->wadfile->seek (entry->dir.start);
779 if (entry->wadfile->error ())
780 {
781 err ("%s: seek error", entryname);
782 return;
783 }
784 int r = copy_bytes (file, entry->wadfile->fp, entry->dir.size);
785 if (r != 0)
786 {
787 if (r == 1)
788 err ("%s: error reading from source wad", entryname);
789 else if (r == 2)
790 err ("%s: error writing to destination wad", entryname);
791 else
792 nf_bug ("%s: copy_bytes() returned %d", entryname, r);
793 return;
794 }
795 }
796 else
797 {
798 printf ("Entry not in master directory.\n");
799 return;
800 }
801 }
802
803
804 /*
805 * SaveEntryToRawFile - write the contents of a lump to a new file
806 *
807 * Save a directory entry to disk, without a pwad header
808 */
SaveEntryToRawFile(FILE * file,const char * entryname)809 void SaveEntryToRawFile (FILE *file, const char *entryname)
810 {
811 MDirPtr entry;
812
813 for (entry = MasterDir; entry; entry = entry->next)
814 if (!y_strnicmp (entry->dir.name, entryname, WAD_NAME))
815 break;
816 if (entry)
817 {
818 verbmsg ("Writing %ld bytes starting from offset %lX...\n",
819 (long) entry->dir.size, (unsigned long) entry->dir.start);
820 entry->wadfile->seek (entry->dir.start);
821 if (entry->wadfile->error ())
822 {
823 err ("%s: seek error", entryname);
824 return;
825 }
826 int r = copy_bytes (file, entry->wadfile->fp, entry->dir.size);
827 if (r != 0)
828 {
829 if (r == 1)
830 err ("%s: error reading from source wad", entryname);
831 else if (r == 2)
832 err ("%s: error writing to destination file", entryname);
833 else
834 nf_bug ("%s: copy_bytes() returned %d", entryname, r);
835 return;
836 }
837 }
838 else
839 {
840 printf ("[Entry not in master directory]\n");
841 return;
842 }
843 }
844
845
846 /*
847 * SaveEntryFromRawFile - encapsulate a raw file in a pwad
848 *
849 * Encapsulate a raw file in a pwad file
850 */
SaveEntryFromRawFile(FILE * file,FILE * raw,const char * entryname)851 void SaveEntryFromRawFile (FILE *file, FILE *raw, const char *entryname)
852 {
853 long size;
854 char name8[WAD_NAME];
855
856 // Write the header
857 WriteBytes (file, "PWAD", 4); // Type = PWAD
858 file_write_i32 (file, 1); // 1 entry in the directory
859 file_write_i32 (file, 12); // The directory starts at offset 12
860
861 // Write the directory
862 file_write_i32 (file, 28); // First entry starts at offset 28
863
864 if (fseek (raw, 0L, SEEK_END) != 0)
865 fatal_error ("error reading from raw file");
866 size = ftell (raw);
867 if (size < 0)
868 fatal_error ("error reading from raw file");
869 if (fseek (raw, 0L, SEEK_SET) != 0)
870 fatal_error ("error reading from raw file");
871 file_write_i32 (file, size); // Size of first entry
872
873 memset (name8, '\0', WAD_NAME);
874 strncpy (name8, entryname, WAD_NAME);
875 file_write_name (file, name8); // Name of first entry
876
877 // Write the lump data
878 int r = copy_bytes (file, raw, size);
879 if (r != 0)
880 {
881 if (r == 1)
882 err ("%s: error reading from source file", entryname);
883 else if (r == 2)
884 err ("%s: error writing to destination wad", entryname);
885 else
886 nf_bug ("%s: copy_bytes() returned %d", entryname, r);
887 return;
888 }
889 }
890
891
892 /*
893 * locate_pwad
894 * Look for a PWAD in the standard directories
895 * and returns its name in a GetMemory'd buffer
896 * (or NULL if not found). It's up to the caller
897 * to free the buffer after use.
898 */
899
900
901 /* Directories that are searched for PWADs */
902 static const char *standard_directories[] =
903 {
904 "",
905 "~/", // "~" means "the user's home directory"
906 "/usr/local/share/games/%s/", // %s is replaced by <Game>
907 "/usr/share/games/%s/", // %s is replaced by <Game>
908 "/usr/local/share/games/wads/",
909 "/usr/share/games/wads/",
910 0
911 };
912
913
locate_pwad(const char * filename)914 static char *locate_pwad (const char *filename)
915 {
916 al_fext_t ext;
917 const char **dirname;
918 char *real_basename;
919 char *real_name;
920
921 // Get the extension in <ext>
922 al_fana (filename, NULL, NULL, NULL, ext);
923
924 // If it's an absolute name, stop there.
925 if (is_absolute (filename))
926 {
927 real_name = (char *) GetMemory (strlen (filename) + 1 + (*ext ? 0 : 4));
928 strcpy (real_name, filename);
929 if (! *ext)
930 strcat (real_name, ".wad");
931 bool r = file_exists (real_name);
932 if (! r)
933 {
934 FreeMemory (real_name);
935 return 0;
936 }
937 return real_name;
938 }
939
940 // It's a relative name. If no extension given, append ".wad"
941 real_basename = (char *) GetMemory (strlen (filename) + 1 + (*ext ? 0 : 4));
942 strcpy (real_basename, filename);
943 if (! *ext)
944 strcat (real_basename, ".wad");
945
946 // Then search for a file of that name in the standard directories.
947 real_name = (char *) GetMemory (Y_FILE_NAME + 1);
948 for (dirname = standard_directories; *dirname; dirname++)
949 {
950 if (! strcmp (*dirname, "~/"))
951 if (getenv ("HOME"))
952 {
953 al_scps (real_name, getenv ("HOME"), Y_FILE_NAME);
954 al_sapc (real_name, '/', Y_FILE_NAME);
955 }
956 else
957 continue;
958 else
959 y_snprintf (real_name, Y_FILE_NAME + 1, *dirname, Game ? Game : "");
960 al_saps (real_name, real_basename, Y_FILE_NAME);
961 verbmsg (" Trying \"%s\"... ", real_name);
962 if (file_exists (real_name))
963 {
964 verbmsg ("right on !\n");
965 FreeMemory (real_basename);
966 return real_name;
967 }
968 verbmsg ("nuts\n");
969 }
970 FreeMemory (real_name);
971 FreeMemory (real_basename);
972 return NULL;
973 }
974
975
976 /* end of file */
977
978