diff options
author | Simon Howard | 2008-05-02 17:32:09 +0000 |
---|---|---|
committer | Simon Howard | 2008-05-02 17:32:09 +0000 |
commit | 6b1ac97d99599ed5e8d8557313237f3ebb102ead (patch) | |
tree | ad70f70e87671fbf17ffa379de843dc3c4bc2b63 | |
parent | 05ad516a0cc829416b270f7c49aba579171a6da7 (diff) | |
download | chocolate-doom-6b1ac97d99599ed5e8d8557313237f3ebb102ead.tar.gz chocolate-doom-6b1ac97d99599ed5e8d8557313237f3ebb102ead.tar.bz2 chocolate-doom-6b1ac97d99599ed5e8d8557313237f3ebb102ead.zip |
Add WAD I/O abstraction layer - first step for mmapped WAD access.
Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 1133
-rw-r--r-- | configure.in | 1 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/w_checksum.c | 8 | ||||
-rw-r--r-- | src/w_file.c | 80 | ||||
-rw-r--r-- | src/w_file.h | 88 | ||||
-rw-r--r-- | src/w_file_posix.c | 176 | ||||
-rw-r--r-- | src/w_file_stdc.c | 104 | ||||
-rw-r--r-- | src/w_merge.c | 11 | ||||
-rw-r--r-- | src/w_wad.c | 111 | ||||
-rw-r--r-- | src/w_wad.h | 6 |
10 files changed, 529 insertions, 59 deletions
diff --git a/configure.in b/configure.in index 6f490dad..bf2a2c75 100644 --- a/configure.in +++ b/configure.in @@ -7,6 +7,7 @@ orig_CFLAGS="$CFLAGS" AC_PROG_CC AC_PROG_RANLIB AC_CHECK_PROG(HAVE_PYTHON, python, true, false) +AC_CHECK_FUNCS(mmap) OPT_LEVEL=2 diff --git a/src/Makefile.am b/src/Makefile.am index f4565395..8757d351 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,6 +105,9 @@ v_video.c v_video.h \ wi_stuff.c wi_stuff.h \ w_checksum.c w_checksum.h \ w_wad.c w_wad.h \ +w_file.c w_file.h \ +w_file_stdc.c \ +w_file_posix.c \ z_zone.c z_zone.h # source files needed for FEATURE_DEHACKED diff --git a/src/w_checksum.c b/src/w_checksum.c index 339c4eb9..ceda95d8 100644 --- a/src/w_checksum.c +++ b/src/w_checksum.c @@ -31,10 +31,10 @@ #include "w_checksum.h" #include "w_wad.h" -static FILE **open_wadfiles = NULL; +static wad_file_t **open_wadfiles = NULL; static int num_open_wadfiles = 0; -static int GetFileNumber(FILE *handle) +static int GetFileNumber(wad_file_t *handle) { int i; int result; @@ -51,7 +51,7 @@ static int GetFileNumber(FILE *handle) // Allocate another slot for this file. open_wadfiles = realloc(open_wadfiles, - sizeof(FILE *) * (num_open_wadfiles + 1)); + sizeof(wad_file_t *) * (num_open_wadfiles + 1)); open_wadfiles[num_open_wadfiles] = handle; result = num_open_wadfiles; @@ -67,7 +67,7 @@ static void ChecksumAddLump(md5_context_t *md5_context, lumpinfo_t *lump) strncpy(buf, lump->name, 8); buf[8] = '\0'; MD5_UpdateString(md5_context, buf); - MD5_UpdateInt32(md5_context, GetFileNumber(lump->handle)); + MD5_UpdateInt32(md5_context, GetFileNumber(lump->wad_file)); MD5_UpdateInt32(md5_context, lump->position); MD5_UpdateInt32(md5_context, lump->size); } diff --git a/src/w_file.c b/src/w_file.c new file mode 100644 index 00000000..eed68230 --- /dev/null +++ b/src/w_file.c @@ -0,0 +1,80 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// WAD I/O functions. +// +//----------------------------------------------------------------------------- + +#include "config.h" + +#include "doomdef.h" +#include "doomtype.h" + +#include "w_file.h" + +extern wad_file_class_t stdc_wad_file; + +#ifdef HAVE_MMAP +extern wad_file_class_t posix_wad_file; +#endif + +static wad_file_class_t *wad_file_classes[] = +{ +#ifdef HAVE_MMAP + &posix_wad_file, +#endif + &stdc_wad_file, +}; + +wad_file_t *W_OpenFile(char *path) +{ + wad_file_t *result; + int i; + + // Try all classes in order until we find one that works + + result = NULL; + + for (i=0; i<arrlen(wad_file_classes); ++i) + { + result = wad_file_classes[i]->OpenFile(path); + + if (result != NULL) + { + break; + } + } + + return result; +} + +void W_CloseFile(wad_file_t *wad) +{ + wad->file_class->CloseFile(wad); +} + +size_t W_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len) +{ + return wad->file_class->Read(wad, offset, buffer, buffer_len); +} + diff --git a/src/w_file.h b/src/w_file.h new file mode 100644 index 00000000..2eb0d492 --- /dev/null +++ b/src/w_file.h @@ -0,0 +1,88 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// WAD I/O functions. +// +//----------------------------------------------------------------------------- + + +#ifndef __W_FILE__ +#define __W_FILE__ + +#include <stdio.h> +#include "doomtype.h" + +typedef struct _wad_file_s wad_file_t; + +typedef struct +{ + // Open a file for reading. + + wad_file_t *(*OpenFile)(char *path); + + // Close the specified file. + + void (*CloseFile)(wad_file_t *file); + + // Read data from the specified position in the file into the + // provided buffer. Returns the number of bytes read. + + size_t (*Read)(wad_file_t *file, unsigned int offset, + void *buffer, size_t buffer_len); + +} wad_file_class_t; + +struct _wad_file_s +{ + // Class of this file. + + wad_file_class_t *file_class; + + // If this is NULL, the file cannot be mapped into memory. If this + // is non-NULL, it is a pointer to the mapped file. + + byte *mapped; + + // Length of the file, in bytes. + + unsigned int length; +}; + +// Open the specified file. Returns a pointer to a new wad_file_t +// handle for the WAD file, or NULL if it could not be opened. + +wad_file_t *W_OpenFile(char *path); + +// Close the specified WAD file. + +void W_CloseFile(wad_file_t *wad); + +// Read data from the specified file into the provided buffer. The +// data is read from the specified offset from the start of the file. +// Returns the number of bytes read. + +size_t W_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len); + +#endif /* #ifndef __W_FILE__ */ + + diff --git a/src/w_file_posix.c b/src/w_file_posix.c new file mode 100644 index 00000000..600d917d --- /dev/null +++ b/src/w_file_posix.c @@ -0,0 +1,176 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// WAD I/O functions. +// +//----------------------------------------------------------------------------- + +#include "config.h" + +#ifdef HAVE_MMAP + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <string.h> + +#include "w_file.h" +#include "z_zone.h" + +typedef struct +{ + wad_file_t wad; + int handle; +} posix_wad_file_t; + +extern wad_file_class_t posix_wad_file; + +static void MapFile(posix_wad_file_t *wad, char *filename) +{ + void *result; + int protection; + int flags; + + // Mapped area can be read and written to. Ideally + // this should be read-only, as none of the Doom code should + // change the WAD files after being read. However, there may + // be code lurking in the source that does. + + protection = PROT_READ|PROT_WRITE; + + // Writes to the mapped area result in private changes that are + // *not* written to disk. + + flags = MAP_PRIVATE; + + result = mmap(NULL, wad->wad.length, + protection, flags, + wad->handle, 0); + + wad->wad.mapped = result; + + if (result == NULL) + { + fprintf(stderr, "W_POSIX_OpenFile: Unable to mmap() %s - %s\n", + filename, strerror(errno)); + } +} + +unsigned int GetFileLength(int handle) +{ + return lseek(handle, 0, SEEK_END); +} + +static wad_file_t *W_POSIX_OpenFile(char *path) +{ + posix_wad_file_t *result; + int handle; + + handle = open(path, 0); + + if (handle < 0) + { + return NULL; + } + + // Create a new posix_wad_file_t to hold the file handle. + + result = Z_Malloc(sizeof(posix_wad_file_t), PU_STATIC, 0); + result->wad.file_class = &posix_wad_file; + result->wad.length = GetFileLength(handle); + result->handle = handle; + + // Try to map the file into memory with mmap: + + MapFile(result, path); + + return &result->wad; +} + +static void W_POSIX_CloseFile(wad_file_t *wad) +{ + posix_wad_file_t *posix_wad; + + posix_wad = (posix_wad_file_t *) wad; + + // If mapped, unmap it. + + // Close the file + + close(posix_wad->handle); + Z_Free(posix_wad); +} + +// Read data from the specified position in the file into the +// provided buffer. Returns the number of bytes read. + +size_t W_POSIX_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len) +{ + posix_wad_file_t *posix_wad; + byte *byte_buffer; + size_t bytes_read; + int result; + + posix_wad = (posix_wad_file_t *) wad; + + // Jump to the specified position in the file. + + lseek(posix_wad->handle, offset, SEEK_SET); + + // Read into the buffer. + + bytes_read = 0; + byte_buffer = buffer; + + while (buffer_len > 0) { + result = read(posix_wad->handle, byte_buffer, buffer_len); + + if (result < 0) { + perror("W_POSIX_Read"); + break; + } else if (result == 0) { + break; + } + + // Successfully read some bytes + + byte_buffer += result; + buffer_len -= result; + bytes_read += result; + } + + return bytes_read; +} + + +wad_file_class_t posix_wad_file = +{ + W_POSIX_OpenFile, + W_POSIX_CloseFile, + W_POSIX_Read, +}; + + +#endif /* #ifdef HAVE_MMAP */ + diff --git a/src/w_file_stdc.c b/src/w_file_stdc.c new file mode 100644 index 00000000..04450e8b --- /dev/null +++ b/src/w_file_stdc.c @@ -0,0 +1,104 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// WAD I/O functions. +// +//----------------------------------------------------------------------------- + +#include <stdio.h> + +#include "m_misc.h" +#include "w_file.h" +#include "z_zone.h" + +typedef struct +{ + wad_file_t wad; + FILE *fstream; +} stdc_wad_file_t; + +extern wad_file_class_t stdc_wad_file; + +static wad_file_t *W_StdC_OpenFile(char *path) +{ + stdc_wad_file_t *result; + FILE *fstream; + + fstream = fopen(path, "rb"); + + if (fstream == NULL) + { + return NULL; + } + + // Create a new stdc_wad_file_t to hold the file handle. + + result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0); + result->wad.file_class = &stdc_wad_file; + result->wad.mapped = NULL; + result->wad.length = M_FileLength(fstream); + result->fstream = fstream; + + return &result->wad; +} + +static void W_StdC_CloseFile(wad_file_t *wad) +{ + stdc_wad_file_t *stdc_wad; + + stdc_wad = (stdc_wad_file_t *) wad; + + fclose(stdc_wad->fstream); + Z_Free(stdc_wad); +} + +// Read data from the specified position in the file into the +// provided buffer. Returns the number of bytes read. + +size_t W_StdC_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len) +{ + stdc_wad_file_t *stdc_wad; + size_t result; + + stdc_wad = (stdc_wad_file_t *) wad; + + // Jump to the specified position in the file. + + fseek(stdc_wad->fstream, offset, SEEK_SET); + + // Read into the buffer. + + result = fread(buffer, 1, buffer_len, stdc_wad->fstream); + + return result; +} + + +wad_file_class_t stdc_wad_file = +{ + W_StdC_OpenFile, + W_StdC_CloseFile, + W_StdC_Read, +}; + + diff --git a/src/w_merge.c b/src/w_merge.c index ff240e0c..372b3583 100644 --- a/src/w_merge.c +++ b/src/w_merge.c @@ -645,7 +645,7 @@ void W_NWTMergeFile(char *filename, int flags) void W_NWTDashMerge(char *filename) { - FILE *handle; + wad_file_t *wad_file; int old_numlumps; int i; @@ -653,10 +653,12 @@ void W_NWTDashMerge(char *filename) // Load PWAD - handle = W_AddFile(filename); + wad_file = W_AddFile(filename); - if (handle == NULL) + if (wad_file == NULL) + { return; + } // iwad is at the start, pwad was appended to the end @@ -687,6 +689,7 @@ void W_NWTDashMerge(char *filename) // The PWAD must now be added in again with -file. numlumps = old_numlumps; - fclose(handle); + + W_CloseFile(wad_file); } diff --git a/src/w_wad.c b/src/w_wad.c index a93ae377..becdcf71 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -137,17 +137,17 @@ unsigned int reloadlump; char* reloadname; -FILE *W_AddFile (char *filename) +wad_file_t *W_AddFile (char *filename) { wadinfo_t header; lumpinfo_t* lump_p; unsigned int i; - FILE *handle; + wad_file_t *wad_file; int length; int startlump; filelump_t* fileinfo; filelump_t* filerover; - FILE *storehandle; + wad_file_t *storehandle; // open the file and add to directory @@ -158,10 +158,12 @@ FILE *W_AddFile (char *filename) reloadname = filename; reloadlump = numlumps; } + + wad_file = W_OpenFile(filename); - if ( (handle = fopen(filename,"rb")) == NULL) + if (wad_file == NULL) { - printf (" couldn't open %s\n",filename); + printf (" couldn't open %s\n", filename); return NULL; } @@ -178,7 +180,7 @@ FILE *W_AddFile (char *filename) fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, 0); fileinfo->filepos = LONG(0); - fileinfo->size = LONG(M_FileLength(handle)); + fileinfo->size = LONG(wad_file->length); // Name the lump after the base of the filename (without the // extension). @@ -189,7 +191,8 @@ FILE *W_AddFile (char *filename) else { // WAD file - fread (&header, sizeof(header), 1, handle); + W_Read(wad_file, 0, &header, sizeof(header)); + if (strncmp(header.identification,"IWAD",4)) { // Homebrew levels? @@ -201,16 +204,16 @@ FILE *W_AddFile (char *filename) // ???modifiedgame = true; } + header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps*sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, 0); - fseek(handle, header.infotableofs, SEEK_SET); - fread(fileinfo, length, 1, handle); + + W_Read(wad_file, header.infotableofs, fileinfo, length); numlumps += header.numlumps; } - // Fill in lumpinfo lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); @@ -219,19 +222,21 @@ FILE *W_AddFile (char *filename) lump_p = &lumpinfo[startlump]; - storehandle = reloadname ? NULL : handle; + storehandle = reloadname ? NULL : wad_file; for (i=startlump,filerover=fileinfo ; i<numlumps ; i++,lump_p++, filerover++) { - lump_p->handle = storehandle; + lump_p->wad_file = storehandle; lump_p->position = LONG(filerover->filepos); lump_p->size = LONG(filerover->size); lump_p->cache = NULL; - strncpy (lump_p->name, filerover->name, 8); + strncpy(lump_p->name, filerover->name, 8); } if (reloadname) - fclose (handle); + { + W_CloseFile(wad_file); + } Z_Free(fileinfo); @@ -241,7 +246,7 @@ FILE *W_AddFile (char *filename) lumphash = NULL; } - return handle; + return wad_file; } @@ -258,39 +263,44 @@ void W_Reload (void) int lumpcount; lumpinfo_t* lump_p; unsigned int i; - FILE *handle; + wad_file_t* wad_file; int length; filelump_t* fileinfo; - if (!reloadname) + if (reloadname == NULL) + { return; + } - if ( (handle = fopen(reloadname,"rb")) == NULL) - I_Error ("W_Reload: couldn't open %s",reloadname); + wad_file = W_OpenFile(reloadname); + + if (wad_file == NULL) + { + I_Error ("W_Reload: couldn't open %s", reloadname); + } - fread(&header, sizeof(header), 1, handle); + W_Read(wad_file, 0, &header, sizeof(header)); lumpcount = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = lumpcount*sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, 0); - fseek(handle, header.infotableofs, SEEK_SET); - fread(fileinfo, length, 1, handle); + W_Read(wad_file, header.infotableofs, fileinfo, length); // Fill in lumpinfo lump_p = &lumpinfo[reloadlump]; - for (i=reloadlump ; - i<reloadlump+lumpcount ; - i++,lump_p++, fileinfo++) + for (i=reloadlump; i<reloadlump+lumpcount; i++, lump_p++, fileinfo++) { if (lumpinfo[i].cache) + { Z_Free (lumpinfo[i].cache); + } lump_p->position = LONG(fileinfo->filepos); lump_p->size = LONG(fileinfo->size); } - fclose(handle); + W_CloseFile(wad_file); Z_Free(fileinfo); } @@ -394,40 +404,49 @@ int W_LumpLength (unsigned int lump) // Loads the lump into the given buffer, // which must be >= W_LumpLength(). // -void -W_ReadLump -( unsigned int lump, - void* dest ) +void W_ReadLump(unsigned int lump, void *dest) { int c; lumpinfo_t* l; - FILE *handle; + wad_file_t* wad_file; if (lump >= numlumps) + { I_Error ("W_ReadLump: %i >= numlumps",lump); + } l = lumpinfo+lump; I_BeginRead (); - if (l->handle == NULL) + if (l->wad_file == NULL) { // reloadable file, so use open / read / close - if ( (handle = fopen(reloadname,"rb")) == NULL) + + wad_file = W_OpenFile(reloadname); + + if (wad_file == NULL) + { I_Error ("W_ReadLump: couldn't open %s",reloadname); + } } else - handle = l->handle; + { + wad_file = l->wad_file; + } - fseek(handle, l->position, SEEK_SET); - c = fread (dest, 1, l->size, handle); + c = W_Read(wad_file, l->position, dest, l->size); if (c < l->size) + { I_Error ("W_ReadLump: only read %i of %i on lump %i", - c,l->size,lump); + c, l->size, lump); + } - if (l->handle == NULL) - fclose (handle); + if (l->wad_file == NULL) + { + W_CloseFile(wad_file); + } I_EndRead (); } @@ -438,10 +457,7 @@ W_ReadLump // // W_CacheLumpNum // -void* -W_CacheLumpNum -( int lump, - int tag ) +void *W_CacheLumpNum(int lump, int tag) { byte* ptr; @@ -459,7 +475,7 @@ W_CacheLumpNum else { //printf ("cache hit on lump %i\n",lump); - Z_ChangeTag (lumpinfo[lump].cache,tag); + Z_ChangeTag (lumpinfo[lump].cache, tag); } return lumpinfo[lump].cache; @@ -470,12 +486,9 @@ W_CacheLumpNum // // W_CacheLumpName // -void* -W_CacheLumpName -( char* name, - int tag ) +void *W_CacheLumpName(char *name, int tag) { - return W_CacheLumpNum (W_GetNumForName(name), tag); + return W_CacheLumpNum(W_GetNumForName(name), tag); } #if 0 diff --git a/src/w_wad.h b/src/w_wad.h index cb267dd3..85a42db8 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -32,6 +32,8 @@ #include "doomtype.h" +#include "w_file.h" + // // TYPES @@ -46,7 +48,7 @@ typedef struct lumpinfo_s lumpinfo_t; struct lumpinfo_s { char name[8]; - FILE *handle; + wad_file_t *wad_file; int position; int size; void *cache; @@ -61,7 +63,7 @@ extern void** lumpcache; extern lumpinfo_t* lumpinfo; extern unsigned int numlumps; -FILE *W_AddFile (char *filename); +wad_file_t *W_AddFile (char *filename); void W_Reload (void); int W_CheckNumForName (char* name); |