1 /*
2 * Abuse - dark 2D side-scrolling platform game
3 * Copyright (c) 1995 Crack dot Com
4 * Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 * This software was released into the Public Domain. As with most public
7 * domain software, no warranty is made or implied by Crack dot Com, by
8 * Jonathan Clark, or by Sam Hocevar.
9 */
10
11 #if defined HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdint.h>
18 #include <ctype.h>
19 #include <fcntl.h>
20 #include <math.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include "common.h"
26
27 #include "image.h"
28 #include "palette.h"
29 #include "specs.h"
30 #include "dprint.h"
31
32 char const *spec_types[] =
33 {
34 "Invalid type", // 0
35 "Color table", // 1
36 "Palette", // 2
37 "Invalid Type", // 3
38 "Image", // 4
39 "Fore Tile",
40 "Back Tile",
41 "Character",
42 "8 Morph",
43 "16 Morph",
44 "Grue objs",
45 "Extern WAV",
46 "DMX MUS",
47 "Patched morph",
48 "Normal file",
49 "Compress1 file",
50 "Vector Image",
51 "Light list",
52 "Grue fgmap",
53 "Grue bgmap",
54 "Data array",
55 "Character2",
56 "Particle",
57 "Extern lcache"
58 };
59
60
61 int total_files_open=0;
62 char spec_main_file[100];
63
64 static char *spec_prefix=NULL;
65 static char *save_spec_prefix=NULL;
66
67 static jFILE spec_main_jfile((FILE*)0);
68 static int spec_main_fd = -1;
69 static long spec_main_offset = -1;
70 static spec_directory spec_main_sd;
71
set_filename_prefix(char const * prefix)72 void set_filename_prefix(char const *prefix)
73 {
74 if( spec_prefix )
75 {
76 free( spec_prefix );
77 }
78
79 if( prefix )
80 {
81 spec_prefix = strcpy( (char *)malloc( strlen( prefix ) + 2 ), prefix );
82 int len = strlen( prefix );
83 if( prefix[len - 1] != '\\' && prefix[len - 1] != '/')
84 {
85 spec_prefix[len] = '/';
86 spec_prefix[len + 1] = 0;
87 }
88 }
89 else
90 {
91 spec_prefix = NULL;
92 }
93 }
94
get_filename_prefix()95 char *get_filename_prefix()
96 {
97 return spec_prefix;
98 }
99
100
set_save_filename_prefix(char const * save_prefix)101 void set_save_filename_prefix(char const *save_prefix)
102 {
103 if( save_spec_prefix )
104 {
105 free( save_spec_prefix );
106 }
107
108 if( save_prefix )
109 {
110 int len = strlen( save_prefix );
111 save_spec_prefix = (char *)malloc( len + 1 );
112 strcpy( save_spec_prefix, save_prefix );
113 /* AK - Commented this out as it may cause problems
114 if( save_prefix[len - 1] != '\\' && save_prefix[len - 1] != '/' )
115 {
116 save_spec_prefix[len] = '/';
117 save_spec_prefix[len + 1] = '\0';
118 } */
119 }
120 else
121 {
122 save_spec_prefix = NULL;
123 }
124 }
125
get_save_filename_prefix()126 char *get_save_filename_prefix()
127 {
128 return save_spec_prefix;
129 }
130
131 int search_order=SPEC_SEARCH_OUTSIDE_INSIDE;
132
133 static void (*no_space_handle_fun)()=NULL;
134
set_no_space_handler(void (* handle_fun)())135 void set_no_space_handler(void (*handle_fun)())
136 {
137 no_space_handle_fun=handle_fun;
138 }
139
140
bFILE()141 bFILE::bFILE()
142 {
143 rbuf_size=8192;
144 rbuf=(unsigned char *)malloc(rbuf_size);
145 rbuf_start=rbuf_end=0;
146
147 wbuf_size=8192;
148 wbuf=(unsigned char *)malloc(wbuf_size);
149 wbuf_end=0;
150 }
151
~bFILE()152 bFILE::~bFILE()
153 {
154 if (rbuf) free(rbuf);
155 flush_writes();
156 if (wbuf) free(wbuf);
157 }
158
flush_writes()159 int bFILE::flush_writes()
160 {
161 if (wbuf_end!=0)
162 {
163 unsigned long ret=unbuffered_write(wbuf,wbuf_end);
164 if (ret!=wbuf_end && no_space_handle_fun)
165 no_space_handle_fun();
166
167 wbuf_end=0;
168 return ret;
169 }
170 return 0;
171 }
172
read(void * buf,size_t count)173 int bFILE::read(void *buf, size_t count) // returns number of bytes read, calls unbuffer_read
174 {
175 if (!allow_read_buffering())
176 return unbuffered_read(buf,count);
177
178 int total_read=0,error=0;
179 if (!count) return 0;
180 while (count && !error)
181 {
182 if (rbuf_start<rbuf_end)
183 {
184 unsigned int avail_size=rbuf_end-rbuf_start;
185 int copy_size=avail_size>count ? count : avail_size;
186 memcpy(buf,rbuf+rbuf_start,copy_size);
187 buf=(void *)(((unsigned char *)buf)+copy_size);
188 rbuf_start+=copy_size;
189 if (rbuf_start>=rbuf_end)
190 {
191 if (rbuf_end!=rbuf_size) // buffer wasn't full before so there is no way we can complete read
192 error=1;
193 rbuf_start=rbuf_end=0;
194 }
195 total_read+=copy_size;
196 count-=copy_size;
197 } else
198 {
199 rbuf_end=unbuffered_read(rbuf,rbuf_size);
200 if (rbuf_end==0) error=1;
201 rbuf_start=0;
202 }
203 }
204 return total_read;
205 }
206
207
write(void const * buf,size_t count)208 int bFILE::write(void const *buf, size_t count) // returns number of bytes written
209 {
210 if (allow_write_buffering())
211 {
212 int total_written=0;
213 while (count)
214 {
215 int copy_size=wbuf_end+count<=wbuf_size ? count : wbuf_size-wbuf_end;
216 memcpy(wbuf+wbuf_end,buf,copy_size);
217 wbuf_end+=copy_size;
218 count-=copy_size;
219 buf=(void *)(((char *)buf)+copy_size);
220 if (wbuf_end==wbuf_size)
221 if ((unsigned int)flush_writes()!=wbuf_size)
222 return total_written;
223
224 total_written+=copy_size;
225 }
226 return total_written;
227 } else
228 {
229 unsigned long ret=unbuffered_write(buf,count);
230 if (ret!=count && no_space_handle_fun)
231 no_space_handle_fun();
232 }
233 return 0;
234 }
235
seek(long offset,int whence)236 int bFILE::seek(long offset, int whence) // whence=SEEK_SET, SEEK_CUR, SEEK_END, ret=0=success
237 {
238 // rbuf_start=rbuf_end=0;
239 // unbuffered_seek(offset,SEEK_SET);
240
241 long realpos=unbuffered_tell();
242 long curpos=realpos-rbuf_end+rbuf_start;
243 if (whence==SEEK_CUR) offset+=curpos;
244 else if (whence==SEEK_END) offset=file_size()-offset;
245
246 if (offset<realpos-(long)rbuf_end || offset>=realpos)
247 {
248 rbuf_start=rbuf_end=0;
249 unbuffered_seek(offset,SEEK_SET);
250 } else
251 rbuf_start=rbuf_end-(realpos-offset);
252 return 1;
253 }
254
tell()255 int bFILE::tell()
256 {
257 return unbuffered_tell()-rbuf_end+rbuf_start+
258 wbuf_end; // if this a write file, add on how much we've written
259 }
260
allow_read_buffering()261 int bFILE::allow_read_buffering() { return 1; }
allow_write_buffering()262 int bFILE::allow_write_buffering() { return 1; }
263
set_spec_main_file(char const * filename,int Search_order)264 void set_spec_main_file(char const *filename, int Search_order)
265 {
266 dprintf("Specs : main file set to %s\n",filename);
267 strcpy(spec_main_file,filename);
268 search_order=Search_order;
269
270 #if (defined(__APPLE__) && !defined(__MACH__))
271 spec_main_jfile.open_external(filename,"rb",O_BINARY|O_RDONLY);
272 #else
273 spec_main_jfile.open_external(filename,"rb",O_RDONLY);
274 #endif
275 spec_main_fd = spec_main_jfile.get_fd();
276 if (spec_main_fd==-1)
277 return;
278 spec_main_sd.startup(&spec_main_jfile);
279 }
280
jFILE(FILE * file_pointer)281 jFILE::jFILE(FILE *file_pointer) // assumes fp is at begining of file
282 {
283 access=0;
284 fd=-1;
285 file_length=0;
286 start_offset=0;
287 flags=JFILE_CLONED;
288 }
289
open_external(char const * filename,char const * mode,int flags)290 void jFILE::open_external(char const *filename, char const *mode, int flags)
291 {
292 int skip_size=0;
293 char tmp_name[200];
294 if (spec_prefix && filename[0] != '/')
295 sprintf(tmp_name,"%s%s",spec_prefix,filename);
296 else strcpy(tmp_name,filename);
297
298 // int old_mask=umask(S_IRWXU | S_IRWXG | S_IRWXO);
299 if (flags&O_WRONLY)
300 {
301 if ((flags&O_APPEND)==0)
302 {
303 skip_size=1;
304 //int errval = unlink(tmp_name);
305 }
306
307 flags-=O_WRONLY;
308 flags|=O_CREAT|O_RDWR;
309
310 fd=open(tmp_name,flags,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
311 } else
312 fd=open(tmp_name,flags);
313
314 // umask(old_mask);
315 if (fd>=0 && !skip_size)
316 {
317 file_length=lseek(fd,0,SEEK_END);
318 if ((flags&O_APPEND)==0)
319 lseek(fd,0,SEEK_SET);
320 else
321 current_offset = file_length;
322 start_offset=0;
323 } else
324 {
325 file_length=0;
326 start_offset=0;
327 }
328 }
329
330
331 class null_file : public bFILE // this file type will use virtual opens inside of a spe
332 {
333 public :
open_failure()334 virtual int open_failure() { return 1; }
unbuffered_read(void * buf,size_t count)335 virtual int unbuffered_read(void *buf, size_t count) { return 0; }
unbuffered_write(void const * buf,size_t count)336 virtual int unbuffered_write(void const *buf, size_t count) { return 0; }
unbuffered_seek(long offset,int whence)337 virtual int unbuffered_seek(long offset, int whence) { return 0; }
338
unbuffered_tell()339 virtual int unbuffered_tell() { return 0; }
file_size()340 virtual int file_size() { return 0; }
~null_file()341 virtual ~null_file() { ; }
342 } ;
343
344
345 static bFILE *(*open_file_fun)(char const *,char const *)=NULL;
346 int (*verify_file_fun)(char const *,char const *)=NULL;
347
set_file_opener(bFILE * (* open_fun)(char const *,char const *))348 void set_file_opener(bFILE *(*open_fun)(char const *, char const *))
349 {
350 open_file_fun=open_fun;
351 }
352
open_file(char const * filename,char const * mode)353 bFILE *open_file(char const *filename, char const *mode)
354 {
355 if (!verify_file_fun || verify_file_fun(filename,mode))
356 {
357 if (open_file_fun)
358 return open_file_fun(filename,mode);
359 else return new jFILE(filename,mode);
360 } else return new null_file;
361 }
362
open_internal(char const * filename,char const * mode,int flags)363 void jFILE::open_internal(char const *filename, char const *mode, int flags)
364 {
365 int wr=0;
366 for (char const *s=mode; *s; s++)
367 if (toupper(*s)=='A' || toupper(*s)=='W')
368 wr=1;
369
370 if (wr)
371 fd=-1; // only allow extern file openings for writing
372 else
373 {
374 fd = spec_main_fd;
375 if (fd>=0) // if we were able to open the main file, see if it's in there
376 {
377 start_offset=0;
378 spec_entry *se=spec_main_sd.find(filename);
379 if (se)
380 {
381 start_offset=se->offset;
382 current_offset = 0;
383 file_length=se->size;
384 rbuf_start=rbuf_end=0;
385 } else
386 {
387 close(fd);
388 fd=-1;
389 }
390 }
391 }
392 }
393
jFILE(char const * filename,char const * access_string)394 jFILE::jFILE(char const *filename, char const *access_string) // same as fopen parameters
395 {
396 flags=access=0;
397 char const *s=access_string;
398 for (; *s; s++)
399 if (toupper(*s)=='R') access=O_RDONLY;
400
401 for (s=access_string; *s; s++)
402 if (toupper(*s)=='W')
403 {
404 if (access)
405 access=O_RDWR;
406 else access=O_WRONLY;
407 }
408
409 for (s=access_string; *s; s++)
410 if (toupper(*s)=='A')
411 access|=O_APPEND|O_WRONLY;
412
413 file_length=start_offset=-1;
414 current_offset = 0;
415
416 fd=-1;
417 if (search_order==SPEC_SEARCH_OUTSIDE_INSIDE)
418 open_external(filename,access_string,access);
419
420 if (fd<0)
421 open_internal(filename,access_string,access);
422
423 if (fd<0 && search_order==SPEC_SEARCH_INSIDE_OUTSIDE)
424 open_external(filename,access_string,access);
425
426 total_files_open++;
427 }
428
~jFILE()429 jFILE::~jFILE()
430 {
431 flush_writes();
432 if (fd>=0 && !(flags&JFILE_CLONED))
433 {
434 total_files_open--;
435 if (fd != spec_main_fd)
436 close(fd);
437 }
438 }
439
unbuffered_tell()440 int jFILE::unbuffered_tell()
441 {
442 // int ret = ::lseek(fd,0,SEEK_CUR) - start_offset;
443 // if (ret != current_offset)
444 // fprintf(stderr,"Bad tell %d\n",current_offset);
445 return current_offset;
446 }
447
unbuffered_read(void * buf,size_t count)448 int jFILE::unbuffered_read(void *buf, size_t count)
449 {
450 unsigned long len;
451
452 if (fd == spec_main_fd)
453 {
454 if (current_offset+start_offset != spec_main_offset)
455 spec_main_offset = lseek(fd, start_offset+current_offset, SEEK_SET);
456
457 len = ::read(fd,(char*)buf,count);
458 spec_main_offset += len;
459 }
460 else
461 {
462 len = ::read(fd,(char*)buf,count);
463 }
464 current_offset += len;
465 return len;
466 }
467
unbuffered_write(void const * buf,size_t count)468 int jFILE::unbuffered_write(void const *buf, size_t count)
469 {
470 long ret = ::write(fd,(char*)buf,count);
471 current_offset += ret;
472 return ret;
473 }
474
unbuffered_seek(long offset,int whence)475 int jFILE::unbuffered_seek(long offset, int whence) // whence=SEEK_SET, SEEK_CUR, SEEK_END, ret=0=success
476 {
477 long ret;
478
479 switch (whence)
480 {
481 case SEEK_SET :
482 { ret = lseek(fd,start_offset+offset,SEEK_SET); } break;
483 case SEEK_END :
484 { ret = lseek(fd,start_offset+file_length-offset,SEEK_SET); } break;
485 case SEEK_CUR :
486 { ret = lseek(fd,offset,SEEK_CUR); } break;
487 default:
488 ret = -1;
489 break;
490 }
491 if (ret>=0)
492 {
493 current_offset = ret - start_offset;
494 if (spec_main_fd == fd)
495 spec_main_offset = ret;
496 return ret;
497 }
498 else
499 return -1; // if a bad whence, then failure
500 }
501
502
read_uint8()503 uint8_t bFILE::read_uint8()
504 { uint8_t x;
505 read(&x,1);
506 return x;
507 }
508
read_uint16()509 uint16_t bFILE::read_uint16()
510 {
511 uint16_t x;
512 read(&x,2);
513 return lstl(x);
514 }
515
516
read_uint32()517 uint32_t bFILE::read_uint32()
518 {
519 uint32_t x;
520 read(&x,4);
521 return lltl(x);
522 }
523
write_uint8(uint8_t x)524 void bFILE::write_uint8(uint8_t x)
525 {
526 write(&x,1);
527 }
528
write_uint16(uint16_t x)529 void bFILE::write_uint16(uint16_t x)
530 {
531 x=lstl(x);
532 write(&x,2);
533 }
534
535
write_uint32(uint32_t x)536 void bFILE::write_uint32(uint32_t x)
537 {
538 x=lltl(x);
539 write(&x,4);
540 }
541
write_double(double x)542 void bFILE::write_double(double x)
543 {
544 double a;
545 write_uint32((long)(modf(x,&a)*(double)(1<<31)));
546 write_uint32((long)a);
547 }
548
read_double()549 double bFILE::read_double()
550 {
551 long a,b;
552 a=read_uint32();
553 b=read_uint32();
554 return (double)b+a/(double)(1<<31);
555 }
556
~spec_directory()557 spec_directory::~spec_directory()
558 {
559
560 if (total)
561 {
562 free(data);
563 free(entries);
564 }
565 }
566
FullyLoad(bFILE * fp)567 void spec_directory::FullyLoad(bFILE *fp)
568 {
569 for (int i = 0; i < total; i++)
570 {
571 spec_entry *se = entries[i];
572 free(se->data);
573 se->data = malloc(se->size);
574 fp->seek(se->offset, SEEK_SET);
575 fp->read(se->data, se->size);
576 }
577 }
578
spec_entry(uint8_t spec_type,char const * object_name,char const * link_filename,unsigned long data_size,unsigned long data_offset)579 spec_entry::spec_entry(uint8_t spec_type, char const *object_name,
580 char const *link_filename,
581 unsigned long data_size, unsigned long data_offset)
582 {
583 type = spec_type;
584 name = strdup(object_name);
585 data = NULL;
586 size = data_size;
587 offset = data_offset;
588 }
589
~spec_entry()590 spec_entry::~spec_entry()
591 {
592 free(name);
593 free(data);
594 }
595
Print()596 void spec_entry::Print()
597 {
598 printf("%15s%25s%8ld%8ld\n", spec_types[type], name, size, offset);
599 }
600
calc_offsets()601 void spec_directory::calc_offsets()
602 {
603 size_t o = SPEC_SIG_SIZE + 2;
604
605 // calculate the size of directory info
606 for (int i = 0; i < total; i++)
607 o += 1 + 1 + strlen(entries[i]->name) + 1 + 1 + 8;
608
609 // calculate offset for each entry
610 for (int i = 0; i < total; i++)
611 {
612 entries[i]->offset = o;
613 o += entries[i]->size;
614 }
615 }
616
find(char const * name,int type)617 spec_entry *spec_directory::find(char const *name, int type)
618 {
619 int i;
620 spec_entry **e;
621 for (i=0,e=entries; i<total; i++,e++)
622 if (!strcmp((*e)->name,name) && (*e)->type==type)
623 return (*e);
624 return NULL;
625 }
626
find(char const * name)627 spec_entry *spec_directory::find(char const *name)
628 {
629 int i;
630 spec_entry **e;
631 for (i=0,e=entries; i<total; i++,e++)
632 if (!strcmp((*e)->name,name))
633 return (*e);
634 return NULL;
635 }
636
find_number(char const * name)637 long spec_directory::find_number(char const *name)
638 {
639 int i;
640 spec_entry **e;
641 for (i=0,e=entries; i<total; i++,e++)
642 if (!strcmp((*e)->name,name))
643 return i;
644 return -1;
645 }
646
find(int type)647 spec_entry *spec_directory::find(int type)
648 {
649 int i;
650 spec_entry **e;
651 for (i=0,e=entries; i<total; i++,e++)
652 if ((*e)->type==type)
653 return (*e);
654 return NULL;
655 }
656
type_total(int type)657 long spec_directory::type_total(int type)
658 {
659 int i,x=0;
660 spec_entry **e;
661 for (i=0,e=entries; i<total; i++,e++)
662 if ((*e)->type==type) x++;
663 return x;
664 }
665
find_number(int type)666 long spec_directory::find_number(int type)
667 {
668 int i;
669 spec_entry **e;
670 for (i=0,e=entries; i<total; i++,e++)
671 if ((*e)->type==type)
672 return i;
673 return -1;
674 }
675
print()676 void spec_directory::print()
677 {
678 spec_entry **se;
679 int i;
680 printf("[ Entry type ][ Entry name ][ Size ][ Offset ]\n");
681 for (i=0,se=entries; i<total; i++,se++)
682 (*se)->Print();
683 }
684
685
startup(bFILE * fp)686 void spec_directory::startup(bFILE *fp)
687 {
688 char buf[256];
689 memset(buf,0,256);
690 fp->read(buf,8);
691 buf[9]=0;
692 size=0;
693 if (!strcmp(buf,SPEC_SIGNATURE))
694 {
695 total=fp->read_uint16();
696 entries=(spec_entry **)malloc(sizeof(spec_entry *)*total);
697 long start=fp->tell();
698
699 int i;
700 for (i=0; i<total; i++)
701 {
702 fp->read(buf,2);
703 long entry_size=sizeof(spec_entry)+(unsigned char)buf[1];
704 entry_size=(entry_size+3)&(~3);
705 fp->read(buf,(unsigned char)buf[1]);
706 fp->read(buf,9);
707
708 size+=entry_size;
709 }
710 data=malloc(size);
711 char *dp=(char *)data;
712 fp->seek(start,SEEK_SET);
713 for (i=0; i<total; i++)
714 {
715 spec_entry *se=(spec_entry *)dp;
716 entries[i]=se;
717
718 unsigned char len,flags,type;
719 fp->read(&type,1);
720 fp->read(&len,1);
721 se->type=type;
722 se->data = NULL;
723 se->name=dp+sizeof(spec_entry);
724 fp->read(se->name,len);
725 fp->read(&flags,1);
726
727 se->size=fp->read_uint32();
728 se->offset=fp->read_uint32();
729 dp+=((sizeof(spec_entry)+len)+3)&(~3);
730 }
731 }
732 else
733 {
734 total=0;
735 data=NULL;
736 entries=NULL;
737 }
738 }
739
740
spec_directory(bFILE * fp)741 spec_directory::spec_directory(bFILE *fp)
742 { startup(fp); }
743
spec_directory(FILE * fp)744 spec_directory::spec_directory(FILE *fp)
745 {
746 jFILE jfp(fp);
747 startup(&jfp);
748 }
749
spec_directory()750 spec_directory::spec_directory()
751 {
752 size=0;
753 total=0;
754 data=NULL;
755 entries=NULL;
756 }
757
758 /*
759 spec_directory::spec_directory(char *filename)
760 {
761 jFILE *fp;
762 if (filename)
763 {
764 fp=new jFILE(filename,"rb");
765 if (!fp->open_failure())
766 startup(fp);
767 else
768 {
769 total=0;
770 entries=NULL;
771 }
772 delete fp;
773 } else printf("NULL filename to spec_directory::spec_directory\n");
774 }*/
775
write_string(bFILE * fp,char const * st)776 int write_string(bFILE *fp, char const *st)
777 {
778 unsigned char length=strlen(st)+1;
779 if (fp->write(&length,1)!=1) return 0;
780 if (fp->write(st,length)!=length) return 0;
781 return 1;
782 }
783
data_start_offset()784 long spec_directory::data_start_offset()
785 {
786 /* FIXME: no need for a for loop here! */
787 long i;
788 for(i = 0; i < total; i++)
789 return entries[i]->offset;
790
791 // If no entries, then no data, but return where it would start anyway
792 return SPEC_SIG_SIZE + 2;
793 }
794
data_end_offset()795 long spec_directory::data_end_offset()
796 {
797 /* FIXME: no need for a for loop here! */
798 spec_entry **e;
799 long i;
800 for (i=total-1,e=entries; i>=0; i--,e++)
801 return (*e)->offset+(*e)->size;
802
803 return SPEC_SIG_SIZE+2;
804 }
805
write(bFILE * fp)806 int spec_directory::write(bFILE *fp)
807 {
808
809 char sig[SPEC_SIG_SIZE];
810 unsigned char flags=0;
811 unsigned long offset,data_size;
812 spec_entry **e;
813 strcpy(sig,SPEC_SIGNATURE);
814
815 if (fp->write(sig,sizeof(sig))!=sizeof(sig)) return 0;
816 fp->write_uint16(total);
817
818
819 int i;
820 for (i=0,e=entries; i<total; i++,e++)
821 {
822 if (fp->write(&(*e)->type,1)!=1) return 0;
823 if (!write_string(fp,(*e)->name)) return 0;
824 flags=0;
825 if (fp->write(&flags,1)!=1) return 0;
826
827 data_size=lltl((*e)->size);
828 if (fp->write((char *)&data_size,4)!=4) return 0;
829 offset=lltl((*e)->offset);
830 if (fp->write((char *)&offset,4)!=4) return 0;
831
832 }
833 return 1;
834 }
835
write(char const * filename)836 jFILE *spec_directory::write(char const *filename)
837 {
838 jFILE *fp;
839 fp=new jFILE(filename,"wb");
840 if (fp->open_failure()) { delete fp; return NULL; }
841 if (!write(fp))
842 {
843 delete fp;
844 return NULL;
845 } else return fp;
846
847 }
848
read_uint16(FILE * fp)849 uint16_t read_uint16(FILE *fp)
850 {
851 uint16_t x;
852 fread(&x,1,2,fp);
853 return lstl(x);
854 }
855
read_uint32(FILE * fp)856 uint32_t read_uint32(FILE *fp)
857 {
858 uint32_t x;
859 fread(&x,1,4,fp);
860 return lltl(x);
861 }
write_uint16(FILE * fp,uint16_t x)862 void write_uint16(FILE *fp, uint16_t x)
863 {
864 x=lstl(x);
865 fwrite(&x,1,2,fp);
866 }
867
write_uint32(FILE * fp,uint32_t x)868 void write_uint32(FILE *fp, uint32_t x)
869 {
870 x=lltl(x);
871 fwrite(&x,1,4,fp);
872 }
873
read_uint8(FILE * fp)874 uint8_t read_uint8(FILE *fp) { return fgetc(fp)&0xff; }
write_uint8(FILE * fp,uint8_t x)875 void write_uint8(FILE *fp, uint8_t x) { fputc((unsigned char)x,fp); }
876
remove(spec_entry * e)877 void spec_directory::remove(spec_entry *e)
878 {
879 int i;
880 for (i=0; i<total && entries[i]!=e; i++); // find the entry in the array first
881
882 if (entries[i]==e) // make sre it was found
883 {
884 delete e;
885 total--;
886 for (; i<total; i++) // compact the pointer array
887 entries[i]=entries[i+1];
888 entries=(spec_entry **)realloc(entries,sizeof(spec_entry *)*total);
889 }
890 else
891 printf("Spec_directory::remove bad entry pointer\n");
892 }
893
894
895
add_by_hand(spec_entry * e)896 void spec_directory::add_by_hand(spec_entry *e)
897 {
898 total++;
899 entries=(spec_entry **)realloc(entries,sizeof(spec_entry *)*total);
900 entries[total-1]=e;
901 }
902
delete_entries()903 void spec_directory::delete_entries() // if the directory was created by hand instead of by file
904 {
905 int i;
906 for (i=0; i<total; i++)
907 delete entries[i];
908
909 if (total)
910 free(entries);
911 }
912
note_open_fd(int fd,char const * str)913 void note_open_fd(int fd, char const *str)
914 {
915 total_files_open++;
916 }
917
note_close_fd(int fd)918 void note_close_fd(int fd)
919 {
920 total_files_open--;
921 }
922
list_open_fds()923 void list_open_fds()
924 {
925 printf("Total open file descriptors: %d\n", total_files_open);
926 }
927
928