1 /* NetHack 3.6 dlb.c $NHDT-Date: 1446975464 2015/11/08 09:37:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */
2 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
3 /* NetHack may be freely redistributed. See license for details. */
15 #define STATIC_DCL extern
18 #define STATIC_DCL static
19 #define STATIC_OVL static
24 * Data librarian. Present a STDIO-like interface to NetHack while
25 * multiplexing on one or more "data libraries". If a file is not found
26 * in a given library, look for it outside the libraries.
29 typedef struct dlb_procs
{
30 boolean
NDECL((*dlb_init_proc
));
31 void NDECL((*dlb_cleanup_proc
));
32 boolean
FDECL((*dlb_fopen_proc
), (DLB_P
, const char *, const char *));
33 int FDECL((*dlb_fclose_proc
), (DLB_P
));
34 int FDECL((*dlb_fread_proc
), (char *, int, int, DLB_P
));
35 int FDECL((*dlb_fseek_proc
), (DLB_P
, long, int));
36 char *FDECL((*dlb_fgets_proc
), (char *, int, DLB_P
));
37 int FDECL((*dlb_fgetc_proc
), (DLB_P
));
38 long FDECL((*dlb_ftell_proc
), (DLB_P
));
41 /* without extern.h via hack.h, these haven't been declared for us */
42 extern FILE *FDECL(fopen_datafile
, (const char *, const char *, int));
46 * Library Implementation:
48 * When initialized, we open all library files and read in their tables
49 * of contents. The library files stay open all the time. When
50 * a open is requested, the libraries' directories are searched. If
51 * successful, we return a descriptor that contains the library, file
52 * size, and current file mark. This descriptor is used for all
55 * The ability to open more than one library is supported but used
56 * only in the Amiga port (the second library holds the sound files).
57 * For Unix, the idea would be to split the NetHack library
58 * into text and binary parts, where the text version could be shared.
62 static library dlb_libs
[MAX_LIBS
];
64 STATIC_DCL boolean
FDECL(readlibdir
, (library
* lp
));
65 STATIC_DCL boolean
FDECL(find_file
, (const char *name
, library
**lib
,
66 long *startp
, long *sizep
));
67 STATIC_DCL boolean
NDECL(lib_dlb_init
);
68 STATIC_DCL
void NDECL(lib_dlb_cleanup
);
69 STATIC_DCL boolean
FDECL(lib_dlb_fopen
, (dlb
*, const char *, const char *));
70 STATIC_DCL
int FDECL(lib_dlb_fclose
, (dlb
*));
71 STATIC_DCL
int FDECL(lib_dlb_fread
, (char *, int, int, dlb
*));
72 STATIC_DCL
int FDECL(lib_dlb_fseek
, (dlb
*, long, int));
73 STATIC_DCL
char *FDECL(lib_dlb_fgets
, (char *, int, dlb
*));
74 STATIC_DCL
int FDECL(lib_dlb_fgetc
, (dlb
*));
75 STATIC_DCL
long FDECL(lib_dlb_ftell
, (dlb
*));
77 /* not static because shared with dlb_main.c */
78 boolean
FDECL(open_library
, (const char *lib_name
, library
*lp
));
79 void FDECL(close_library
, (library
* lp
));
81 /* without extern.h via hack.h, these haven't been declared for us */
82 extern char *FDECL(eos
, (char *));
85 * Read the directory out of the library. Return 1 if successful,
88 * NOTE: An improvement of the file structure should be the file
89 * size as part of the directory entry or perhaps in place of the
90 * offset -- the offset can be calculated by a running tally of
93 * Library file structure:
96 * %3ld library FORMAT revision (currently rev 1)
98 * %8ld # of files in archive (includes 1 for directory)
100 * %8ld size of allocation for string space for directory names
102 * %8ld library offset - sanity check - lseek target for start of first file
104 * %8ld size - sanity check - byte size of complete archive file
106 * followed by one DIRECTORY entry for each file in the archive, including
107 * the directory itself:
108 * %1c handling information (compression, etc.) Always ' ' in rev 1.
111 * %8ld offset in archive file of start of this file
114 * followed by the contents of the files
116 #define DLB_MIN_VERS 1 /* min library version readable by this code */
117 #define DLB_MAX_VERS 1 /* max library version readable by this code */
120 * Read the directory from the library file. This will allocate and
121 * fill in our globals. The file pointer is reset back to position
122 * zero. If any part fails, leave nothing that needs to be deallocated.
124 * Return TRUE on success, FALSE on failure.
128 library
*lp
; /* library pointer to fill in */
132 long liboffset
, totalsize
;
134 if (fscanf(lp
->fdata
, "%ld %ld %ld %ld %ld\n", &lp
->rev
, &lp
->nentries
,
135 &lp
->strsize
, &liboffset
, &totalsize
) != 5)
137 if (lp
->rev
> DLB_MAX_VERS
|| lp
->rev
< DLB_MIN_VERS
)
140 lp
->dir
= (libdir
*) alloc(lp
->nentries
* sizeof(libdir
));
141 lp
->sspace
= (char *) alloc(lp
->strsize
);
143 /* read in each directory entry */
144 for (i
= 0, sp
= lp
->sspace
; i
< lp
->nentries
; i
++) {
145 lp
->dir
[i
].fname
= sp
;
146 if (fscanf(lp
->fdata
, "%c%s %ld\n", &lp
->dir
[i
].handling
, sp
,
147 &lp
->dir
[i
].foffset
) != 3) {
148 free((genericptr_t
) lp
->dir
);
149 free((genericptr_t
) lp
->sspace
);
150 lp
->dir
= (libdir
*) 0;
151 lp
->sspace
= (char *) 0;
157 /* calculate file sizes using offset information */
158 for (i
= 0; i
< lp
->nentries
; i
++) {
159 if (i
== lp
->nentries
- 1)
160 lp
->dir
[i
].fsize
= totalsize
- lp
->dir
[i
].foffset
;
162 lp
->dir
[i
].fsize
= lp
->dir
[i
+ 1].foffset
- lp
->dir
[i
].foffset
;
165 (void) fseek(lp
->fdata
, 0L, SEEK_SET
); /* reset back to zero */
172 * Look for the file in our directory structure. Return 1 if successful,
173 * 0 if not found. Fill in the size and starting position.
176 find_file(name
, lib
, startp
, sizep
)
179 long *startp
, *sizep
;
184 for (i
= 0; i
< MAX_LIBS
&& dlb_libs
[i
].fdata
; i
++) {
186 for (j
= 0; j
< lp
->nentries
; j
++) {
187 if (FILENAME_CMP(name
, lp
->dir
[j
].fname
) == 0) {
189 *startp
= lp
->dir
[j
].foffset
;
190 *sizep
= lp
->dir
[j
].fsize
;
195 *lib
= (library
*) 0;
196 *startp
= *sizep
= 0;
201 * Open the library of the given name and fill in the given library
202 * structure. Return TRUE if successful, FALSE otherwise.
205 open_library(lib_name
, lp
)
206 const char *lib_name
;
209 boolean status
= FALSE
;
211 lp
->fdata
= fopen_datafile(lib_name
, RDBMODE
, DATAPREFIX
);
213 if (readlibdir(lp
)) {
216 (void) fclose(lp
->fdata
);
217 lp
->fdata
= (FILE *) 0;
227 (void) fclose(lp
->fdata
);
228 free((genericptr_t
) lp
->dir
);
229 free((genericptr_t
) lp
->sspace
);
231 (void) memset((char *) lp
, 0, sizeof(library
));
235 * Open the library file once using stdio. Keep it open, but
236 * keep track of the file position.
239 lib_dlb_init(VOID_ARGS
)
242 (void) memset((char *) &dlb_libs
[0], 0, sizeof(dlb_libs
));
244 /* To open more than one library, add open library calls here. */
245 if (!open_library(DLBFILE
, &dlb_libs
[0]))
248 if (!open_library(DLBFILE2
, &dlb_libs
[1])) {
249 close_library(&dlb_libs
[0]);
257 lib_dlb_cleanup(VOID_ARGS
)
261 /* close the data file(s) */
262 for (i
= 0; i
< MAX_LIBS
&& dlb_libs
[i
].fdata
; i
++)
263 close_library(&dlb_libs
[i
]);
268 lib_dlb_fopen(dp
, name
, mode
)
271 const char *mode UNUSED
;
276 /* look up file in directory */
277 if (find_file(name
, &lp
, &start
, &size
)) {
285 return FALSE
; /* failed */
293 /* nothing needs to be done */
298 lib_dlb_fread(buf
, size
, quan
, dp
)
303 long pos
, nread
, nbytes
;
305 /* make sure we don't read into the next file */
306 if ((dp
->size
- dp
->mark
) < (size
* quan
))
307 quan
= (dp
->size
- dp
->mark
) / size
;
311 pos
= dp
->start
+ dp
->mark
;
312 if (dp
->lib
->fmark
!= pos
) {
313 fseek(dp
->lib
->fdata
, pos
, SEEK_SET
); /* check for error??? */
314 dp
->lib
->fmark
= pos
;
317 nread
= fread(buf
, size
, quan
, dp
->lib
->fdata
);
318 nbytes
= nread
* size
;
320 dp
->lib
->fmark
+= nbytes
;
326 lib_dlb_fseek(dp
, pos
, whence
)
335 curpos
= dp
->mark
+ pos
;
338 curpos
= dp
->size
- pos
;
346 if (curpos
> dp
->size
)
354 lib_dlb_fgets(buf
, len
, dp
)
363 return buf
; /* sanity check */
365 /* return NULL on EOF */
366 if (dp
->mark
>= dp
->size
)
369 len
--; /* save room for null */
370 for (i
= 0, bp
= buf
; i
< len
&& dp
->mark
< dp
->size
&& c
!= '\n';
372 if (dlb_fread(bp
, 1, 1, dp
) <= 0)
373 break; /* EOF or error */
378 #if defined(MSDOS) || defined(WIN32)
379 if ((bp
= index(buf
, '\r')) != 0) {
394 if (lib_dlb_fread(&c
, 1, 1, dp
) != 1)
406 const dlb_procs_t lib_dlb_procs
= { lib_dlb_init
, lib_dlb_cleanup
,
407 lib_dlb_fopen
, lib_dlb_fclose
,
408 lib_dlb_fread
, lib_dlb_fseek
,
409 lib_dlb_fgets
, lib_dlb_fgetc
,
415 const dlb_procs_t rsrc_dlb_procs
= { rsrc_dlb_init
, rsrc_dlb_cleanup
,
416 rsrc_dlb_fopen
, rsrc_dlb_fclose
,
417 rsrc_dlb_fread
, rsrc_dlb_fseek
,
418 rsrc_dlb_fgets
, rsrc_dlb_fgetc
,
422 /* Global wrapper functions ------------------------------------------------
425 #define do_dlb_init (*dlb_procs->dlb_init_proc)
426 #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc)
427 #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc)
428 #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc)
429 #define do_dlb_fread (*dlb_procs->dlb_fread_proc)
430 #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc)
431 #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc)
432 #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc)
433 #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc)
435 static const dlb_procs_t
*dlb_procs
;
436 static boolean dlb_initialized
= FALSE
;
441 if (!dlb_initialized
) {
443 dlb_procs
= &lib_dlb_procs
;
446 dlb_procs
= &rsrc_dlb_procs
;
450 dlb_initialized
= do_dlb_init();
453 return dlb_initialized
;
459 if (dlb_initialized
) {
461 dlb_initialized
= FALSE
;
466 dlb_fopen(name
, mode
)
467 const char *name
, *mode
;
472 if (!dlb_initialized
)
475 /* only support reading; ignore possible binary flag */
476 if (!mode
|| mode
[0] != 'r')
479 dp
= (dlb
*) alloc(sizeof(dlb
));
480 if (do_dlb_fopen(dp
, name
, mode
))
482 else if ((fp
= fopen_datafile(name
, mode
, DATAPREFIX
)) != 0)
485 /* can't find anything */
486 free((genericptr_t
) dp
);
499 if (dlb_initialized
) {
501 ret
= fclose(dp
->fp
);
503 ret
= do_dlb_fclose(dp
);
505 free((genericptr_t
) dp
);
511 dlb_fread(buf
, size
, quan
, dp
)
516 if (!dlb_initialized
|| size
<= 0 || quan
<= 0)
519 return (int) fread(buf
, size
, quan
, dp
->fp
);
520 return do_dlb_fread(buf
, size
, quan
, dp
);
524 dlb_fseek(dp
, pos
, whence
)
529 if (!dlb_initialized
)
532 return fseek(dp
->fp
, pos
, whence
);
533 return do_dlb_fseek(dp
, pos
, whence
);
537 dlb_fgets(buf
, len
, dp
)
542 if (!dlb_initialized
)
545 return fgets(buf
, len
, dp
->fp
);
546 return do_dlb_fgets(buf
, len
, dp
);
553 if (!dlb_initialized
)
556 return fgetc(dp
->fp
);
557 return do_dlb_fgetc(dp
);
564 if (!dlb_initialized
)
567 return ftell(dp
->fp
);
568 return do_dlb_ftell(dp
);