shithub: choc

Download patch

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);