ref: 6b1ac97d99599ed5e8d8557313237f3ebb102ead
parent: 05ad516a0cc829416b270f7c49aba579171a6da7
author: Simon Howard <fraggle@gmail.com>
date: Fri May 2 13:32:09 EDT 2008
Add WAD I/O abstraction layer - first step for mmapped WAD access. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1133
--- a/configure.in
+++ b/configure.in
@@ -7,6 +7,7 @@
AC_PROG_CC
AC_PROG_RANLIB
AC_CHECK_PROG(HAVE_PYTHON, python, true, false)
+AC_CHECK_FUNCS(mmap)
OPT_LEVEL=2
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -105,6 +105,9 @@
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
--- 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 @@
// 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 @@
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);
}
--- /dev/null
+++ b/src/w_file.c
@@ -1,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);
+}
+
--- /dev/null
+++ b/src/w_file.h
@@ -1,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__ */
+
+
--- /dev/null
+++ b/src/w_file_posix.c
@@ -1,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 */
+
--- /dev/null
+++ b/src/w_file_stdc.c
@@ -1,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,
+};
+
+
--- a/src/w_merge.c
+++ b/src/w_merge.c
@@ -645,7 +645,7 @@
void W_NWTDashMerge(char *filename)
{
- FILE *handle;
+ wad_file_t *wad_file;
int old_numlumps;
int i;
@@ -653,10 +653,12 @@
// 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 @@
// The PWAD must now be added in again with -file.
numlumps = old_numlumps;
- fclose(handle);
+
+ W_CloseFile(wad_file);
}
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -137,17 +137,17 @@
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 @@
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 @@
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 @@
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 @@
// ???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 @@
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 @@
lumphash = NULL;
}
- return handle;
+ return wad_file;
}
@@ -258,39 +263,44 @@
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);
- fread(&header, sizeof(header), 1, handle);
+ if (wad_file == NULL)
+ {
+ I_Error ("W_Reload: couldn't open %s", reloadname);
+ }
+
+ 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 @@
// 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_CacheLumpNum
//
-void*
-W_CacheLumpNum
-( int lump,
- int tag )
+void *W_CacheLumpNum(int lump, int tag)
{
byte* ptr;
@@ -459,7 +475,7 @@
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_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
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -32,7 +32,9 @@
#include "doomtype.h"
+#include "w_file.h"
+
//
// TYPES
//
@@ -46,7 +48,7 @@
struct lumpinfo_s
{
char name[8];
- FILE *handle;
+ wad_file_t *wad_file;
int position;
int size;
void *cache;
@@ -61,7 +63,7 @@
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);