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. */
7 #if defined(VERSION_IN_DLB_FILENAME)
8 #include "patchlevel.h"
18 #define STATIC_DCL extern
21 #define STATIC_DCL static
22 #define STATIC_OVL static
27 * Data librarian. Present a STDIO-like interface to NetHack while
28 * multiplexing on one or more "data libraries". If a file is not found
29 * in a given library, look for it outside the libraries.
32 typedef struct dlb_procs {
33 boolean NDECL((*dlb_init_proc));
34 void NDECL((*dlb_cleanup_proc));
35 boolean FDECL((*dlb_fopen_proc), (DLB_P, const char *, const char *));
36 int FDECL((*dlb_fclose_proc), (DLB_P));
37 int FDECL((*dlb_fread_proc), (char *, int, int, DLB_P));
38 int FDECL((*dlb_fseek_proc), (DLB_P, long, int));
39 char *FDECL((*dlb_fgets_proc), (char *, int, DLB_P));
40 int FDECL((*dlb_fgetc_proc), (DLB_P));
41 long FDECL((*dlb_ftell_proc), (DLB_P));
44 #if defined(VERSION_IN_DLB_FILENAME)
45 char dlbfilename[MAX_DLB_FILENAME];
48 /* without extern.h via hack.h, these haven't been declared for us */
49 extern FILE *FDECL(fopen_datafile, (const char *, const char *, int));
53 * Library Implementation:
55 * When initialized, we open all library files and read in their tables
56 * of contents. The library files stay open all the time. When
57 * a open is requested, the libraries' directories are searched. If
58 * successful, we return a descriptor that contains the library, file
59 * size, and current file mark. This descriptor is used for all
62 * The ability to open more than one library is supported but used
63 * only in the Amiga port (the second library holds the sound files).
64 * For Unix, the idea would be to split the NetHack library
65 * into text and binary parts, where the text version could be shared.
69 static library dlb_libs[MAX_LIBS];
71 STATIC_DCL boolean FDECL(readlibdir, (library * lp));
72 STATIC_DCL boolean FDECL(find_file, (const char *name, library **lib,
73 long *startp, long *sizep));
74 STATIC_DCL boolean NDECL(lib_dlb_init);
75 STATIC_DCL void NDECL(lib_dlb_cleanup);
76 STATIC_DCL boolean FDECL(lib_dlb_fopen, (dlb *, const char *, const char *));
77 STATIC_DCL int FDECL(lib_dlb_fclose, (dlb *));
78 STATIC_DCL int FDECL(lib_dlb_fread, (char *, int, int, dlb *));
79 STATIC_DCL int FDECL(lib_dlb_fseek, (dlb *, long, int));
80 STATIC_DCL char *FDECL(lib_dlb_fgets, (char *, int, dlb *));
81 STATIC_DCL int FDECL(lib_dlb_fgetc, (dlb *));
82 STATIC_DCL long FDECL(lib_dlb_ftell, (dlb *));
84 /* not static because shared with dlb_main.c */
85 boolean FDECL(open_library, (const char *lib_name, library *lp));
86 void FDECL(close_library, (library * lp));
88 /* without extern.h via hack.h, these haven't been declared for us */
89 extern char *FDECL(eos, (char *));
92 * Read the directory out of the library. Return 1 if successful,
95 * NOTE: An improvement of the file structure should be the file
96 * size as part of the directory entry or perhaps in place of the
97 * offset -- the offset can be calculated by a running tally of
100 * Library file structure:
103 * %3ld library FORMAT revision (currently rev 1)
105 * %8ld # of files in archive (includes 1 for directory)
107 * %8ld size of allocation for string space for directory names
109 * %8ld library offset - sanity check - lseek target for start of first file
111 * %8ld size - sanity check - byte size of complete archive file
113 * followed by one DIRECTORY entry for each file in the archive, including
114 * the directory itself:
115 * %1c handling information (compression, etc.) Always ' ' in rev 1.
118 * %8ld offset in archive file of start of this file
121 * followed by the contents of the files
123 #define DLB_MIN_VERS 1 /* min library version readable by this code */
124 #define DLB_MAX_VERS 1 /* max library version readable by this code */
127 * Read the directory from the library file. This will allocate and
128 * fill in our globals. The file pointer is reset back to position
129 * zero. If any part fails, leave nothing that needs to be deallocated.
131 * Return TRUE on success, FALSE on failure.
135 library *lp; /* library pointer to fill in */
139 long liboffset, totalsize;
141 if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n", &lp->rev, &lp->nentries,
142 &lp->strsize, &liboffset, &totalsize) != 5)
144 if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS)
147 lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir));
148 lp->sspace = (char *) alloc(lp->strsize);
150 /* read in each directory entry */
151 for (i = 0, sp = lp->sspace; i < lp->nentries; i++) {
152 lp->dir[i].fname = sp;
153 if (fscanf(lp->fdata, "%c%s %ld\n", &lp->dir[i].handling, sp,
154 &lp->dir[i].foffset) != 3) {
155 free((genericptr_t) lp->dir);
156 free((genericptr_t) lp->sspace);
157 lp->dir = (libdir *) 0;
158 lp->sspace = (char *) 0;
164 /* calculate file sizes using offset information */
165 for (i = 0; i < lp->nentries; i++) {
166 if (i == lp->nentries - 1)
167 lp->dir[i].fsize = totalsize - lp->dir[i].foffset;
169 lp->dir[i].fsize = lp->dir[i + 1].foffset - lp->dir[i].foffset;
172 (void) fseek(lp->fdata, 0L, SEEK_SET); /* reset back to zero */
179 * Look for the file in our directory structure. Return 1 if successful,
180 * 0 if not found. Fill in the size and starting position.
183 find_file(name, lib, startp, sizep)
186 long *startp, *sizep;
191 for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) {
193 for (j = 0; j < lp->nentries; j++) {
194 if (FILENAME_CMP(name, lp->dir[j].fname) == 0) {
196 *startp = lp->dir[j].foffset;
197 *sizep = lp->dir[j].fsize;
202 *lib = (library *) 0;
203 *startp = *sizep = 0;
208 * Open the library of the given name and fill in the given library
209 * structure. Return TRUE if successful, FALSE otherwise.
212 open_library(lib_name, lp)
213 const char *lib_name;
216 boolean status = FALSE;
218 lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX);
220 if (readlibdir(lp)) {
223 (void) fclose(lp->fdata);
224 lp->fdata = (FILE *) 0;
234 (void) fclose(lp->fdata);
235 free((genericptr_t) lp->dir);
236 free((genericptr_t) lp->sspace);
238 (void) memset((char *) lp, 0, sizeof(library));
242 * Open the library file once using stdio. Keep it open, but
243 * keep track of the file position.
246 lib_dlb_init(VOID_ARGS)
249 (void) memset((char *) &dlb_libs[0], 0, sizeof(dlb_libs));
250 #ifdef VERSION_IN_DLB_FILENAME
251 build_dlb_filename((const char *) 0);
253 /* To open more than one library, add open library calls here. */
254 if (!open_library(DLBFILE, &dlb_libs[0]))
257 if (!open_library(DLBFILE2, &dlb_libs[1])) {
258 close_library(&dlb_libs[0]);
266 lib_dlb_cleanup(VOID_ARGS)
270 /* close the data file(s) */
271 for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++)
272 close_library(&dlb_libs[i]);
275 #ifdef VERSION_IN_DLB_FILENAME
277 build_dlb_filename(lf)
280 Sprintf(dlbfilename, "%s%d%d%d",
281 lf ? lf : DLBBASENAME, VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
288 lib_dlb_fopen(dp, name, mode)
291 const char *mode UNUSED;
296 /* look up file in directory */
297 if (find_file(name, &lp, &start, &size)) {
305 return FALSE; /* failed */
313 /* nothing needs to be done */
318 lib_dlb_fread(buf, size, quan, dp)
323 long pos, nread, nbytes;
325 /* make sure we don't read into the next file */
326 if ((dp->size - dp->mark) < (size * quan))
327 quan = (dp->size - dp->mark) / size;
331 pos = dp->start + dp->mark;
332 if (dp->lib->fmark != pos) {
333 fseek(dp->lib->fdata, pos, SEEK_SET); /* check for error??? */
334 dp->lib->fmark = pos;
337 nread = fread(buf, size, quan, dp->lib->fdata);
338 nbytes = nread * size;
340 dp->lib->fmark += nbytes;
346 lib_dlb_fseek(dp, pos, whence)
355 curpos = dp->mark + pos;
358 curpos = dp->size - pos;
366 if (curpos > dp->size)
374 lib_dlb_fgets(buf, len, dp)
383 return buf; /* sanity check */
385 /* return NULL on EOF */
386 if (dp->mark >= dp->size)
389 len--; /* save room for null */
390 for (i = 0, bp = buf; i < len && dp->mark < dp->size && c != '\n';
392 if (dlb_fread(bp, 1, 1, dp) <= 0)
393 break; /* EOF or error */
398 #if defined(MSDOS) || defined(WIN32)
399 if ((bp = index(buf, '\r')) != 0) {
414 if (lib_dlb_fread(&c, 1, 1, dp) != 1)
426 const dlb_procs_t lib_dlb_procs = { lib_dlb_init, lib_dlb_cleanup,
427 lib_dlb_fopen, lib_dlb_fclose,
428 lib_dlb_fread, lib_dlb_fseek,
429 lib_dlb_fgets, lib_dlb_fgetc,
435 const dlb_procs_t rsrc_dlb_procs = { rsrc_dlb_init, rsrc_dlb_cleanup,
436 rsrc_dlb_fopen, rsrc_dlb_fclose,
437 rsrc_dlb_fread, rsrc_dlb_fseek,
438 rsrc_dlb_fgets, rsrc_dlb_fgetc,
442 /* Global wrapper functions ------------------------------------------------
445 #define do_dlb_init (*dlb_procs->dlb_init_proc)
446 #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc)
447 #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc)
448 #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc)
449 #define do_dlb_fread (*dlb_procs->dlb_fread_proc)
450 #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc)
451 #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc)
452 #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc)
453 #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc)
455 static const dlb_procs_t *dlb_procs;
456 static boolean dlb_initialized = FALSE;
461 if (!dlb_initialized) {
463 dlb_procs = &lib_dlb_procs;
466 dlb_procs = &rsrc_dlb_procs;
470 dlb_initialized = do_dlb_init();
473 return dlb_initialized;
479 if (dlb_initialized) {
481 dlb_initialized = FALSE;
486 dlb_fopen(name, mode)
487 const char *name, *mode;
492 if (!dlb_initialized)
495 /* only support reading; ignore possible binary flag */
496 if (!mode || mode[0] != 'r')
499 dp = (dlb *) alloc(sizeof(dlb));
500 if (do_dlb_fopen(dp, name, mode))
502 else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0)
505 /* can't find anything */
506 free((genericptr_t) dp);
519 if (dlb_initialized) {
521 ret = fclose(dp->fp);
523 ret = do_dlb_fclose(dp);
525 free((genericptr_t) dp);
531 dlb_fread(buf, size, quan, dp)
536 if (!dlb_initialized || size <= 0 || quan <= 0)
539 return (int) fread(buf, size, quan, dp->fp);
540 return do_dlb_fread(buf, size, quan, dp);
544 dlb_fseek(dp, pos, whence)
549 if (!dlb_initialized)
552 return fseek(dp->fp, pos, whence);
553 return do_dlb_fseek(dp, pos, whence);
557 dlb_fgets(buf, len, dp)
562 if (!dlb_initialized)
565 return fgets(buf, len, dp->fp);
566 return do_dlb_fgets(buf, len, dp);
573 if (!dlb_initialized)
576 return fgetc(dp->fp);
577 return do_dlb_fgetc(dp);
584 if (!dlb_initialized)
587 return ftell(dp->fp);
588 return do_dlb_ftell(dp);