/* * WADFILE.C * * Version 1.0.0 * * Abstract: * This module contains all the WADFILE processing routines for the * WadLib library. * * History: * 1.0.0 (March 31, 1994) * * Author: * Michael McMahon * **************************************************************************** * Wadfile Function Directory *--------------------------------------------------------------------------- *Index: Name : Description *--------------------------------------------------------------------------- * #1 : WadfileAddLump : Add a lump to a Wadfile being created. * #2 : WadfileClose : Close file, flush cache, update WAD directory * #3 : WadfileCopyEntry : Copies a lump from one Wadfile to another. * #4 : WadfileCopyMap : Copies a map from one Wadfile to another. * #5 : WadfileCreate : Create WAD file and initialize Wadfile struct. * #6 : WadfileGetDirInfo : Read directory info into Wadfile structure. * #7 : WadfileGetNextDirInfo : Move to next directory entry and read it in. * #8 : WadfileGetPrevDirInfo : Move to last directory entry and read it in. * #9 : WadfileInitialize : One-time call, set up memory allocators. * #10 : WadfileLumpClose : Close lump inside WAD file, free its memory. * #11 : WadfileLumpCopy : Copy lump file from one Wadfile to another. * #12 : WadfileLumpOpen : Open lump at current directory position. * #13 : WadfileOpen : Open a WAD file and initialize Wadfile struct. * #14 : WadfileSeek : Find first dir entry with a search string. * #15 : WadfileSeekMap : Find map given episode and map. ExMy **************************************************************************** * * WADLIB SOFTWARE LICENSE AGREEMENT * * 1. GRANT OF LICENSE. Michael McMahon and his affiliations (collectively * the "AUTHOR") grant you (either an individual or an entity) the * non-exclusive, royalty-free right to use this library source code, * documentation, and sample code (collectively, the "SOFTWARE") for * any lawful purpose subject to the terms of this license. By using the * SOFTWARE you are agreeing to be bound to all the terms of this license. * * 2. COPYRIGHT. The SOFTWARE is Copyright (c) 1994, Michael McMahon, * PO Box 14807, San Luis Nabisco, CA 93406-4807 USA. All Rights Reserved * Worldwide. You may not use, modify, or distribute the SOFTWARE except * as otherwise provided herein. * * 3. DECLARATION OF PUBLIC DOMAIN DISTRIBUTION AND USE. The distribution * and use of the SOFTWARE is hereby designated PUBLIC DOMAIN by the * the AUTHOR. You may not sell, rent, or lease this SOFTWARE. The * SOFTWARE may be reproduced verbatim in part or in full by any * reproduction means for any lawful purpose, and may also be subject to * the following agreement. * * 4. AGREEMENT FOR USE OF SOFTWARE. The AUTHOR grants you a non-exclusive, * royalty-free right to incorporate the SOFTWARE into any production for * any legal purpose as long as you agree * (a) to indemnify, hold harmless, and defend the AUTHOR from and against * any claims or lawsuits, including attorneys' fees, that arise or * result from the use or distribution of your software production; and * (b) no matter how much the SOFTWARE is modified, the AUTHOR owns the * copyright and this original, unmodified copyright notice remains * intact in the source code; and, * (c) the AUTHOR is not held responsible for fixing bugs or making * enhancements or changes to the SOFTWARE for any reason; and, * (d) the SOFTWARE is not redistributed if it is modified in any way; and, * (e) otherwise comply with the terms of this agreement; and, * (f) the AUTHOR is forgiven for making so many demands. * * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. THE * AUTHOR FURTHER DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WITHOUT * LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR OF FITNESS * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK ARISING OUT OF THE USE * OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. * * The author can be reached at: * Michael McMahon * P.O. Box 14807 * San Luis Nabisco, CA 93406-4807 USA * Internet: mmcmahon@oboe.calpoly.edu * [Bug reports, suggestions, success stories, etc. are welcome; tech * support, and other unnecessary two-way mail, is not] */ #include #include #include #include #include "general.h" #include "wadfile.h" /* Private wadfile variables */ static int wadfileInitialized=FALSE; /* Module doesn't work unless TRUE */ static WadfileMalloc wadfileMalloc; /* User's allocate memory routine */ static WadfileFree wadfileFree; /* User's free memory routine */ static int wadfileNumAllocations; /* Keeps track of the malloc's */ /*------------------------- Private routines ------------------------------*/ /**[ Internal 1 of 2 ]**************************************************** * * * wf_malloc * * * * Desc: * * This calls the user's memory allocation routine and updates * * the 'wadfileNumAllocations' variable. * * * * Def: * * static void * wf_malloc(unsigned long size); * * * * Parm: * * size Number of bytes to allocate. * * * * Retn: * * Pointer to allocated memory, or NULL if not enough memory. * * * * Notes: * * This is the gateway for the WADFILE routines to access the user's * * memory allocation routine. Don't call 'wadfileMalloc()' directly. * * * *************************************************************************/ static void * wf_malloc(unsigned long size) { void * result; /* Sanity check */ assert(wadfileMalloc != NULL); /* Allocate memory and bump wadfileNumAllocations if successful */ result = wadfileMalloc(size); if (result != NULL) wadfileNumAllocations++; return result; } /**[ Internal 2 of 2 ]**************************************************** * * * wf_free * * * * Desc: * * This calls the user's memory de-allocation routine and updates * * the 'wadfileNumAllocations' variable. * * * * Def: * * static void wf_free(void * ptr); * * * * Parm: * * ptr Valid memory pointer that was allocated with wf_malloc. * * * * Retn: * * None * * * * Notes: * * This is the gateway for the WADFILE routines to access the user's * * memory deallocation routine. Don't call 'wadfileFree()' directly. * * * *************************************************************************/ static void wf_free(void * ptr) { /* Sanity check */ assert(wadfileFree != NULL); /* Bounds check -- wf_malloc doesn't change wadfileNumAllocations with a NULL value, so wf_free behaves the same way with NULL. */ if (ptr == NULL) return; /* Free the memory and update counter */ wadfileFree(ptr); wadfileNumAllocations--; } /*-------------------------- Public routines ------------------------------*/ /**[ #1 ]***************************************************************** * * * WadfileAddLump * * * * Desc: * * This writes a lump to a Wadfile being created, and adds a * * directory entry associated with the lump. * * * * Def: * * int WadfileAddLump(Wadfile * wad, unsigned long size, * * char * name, char * data); * * * * Parm: * * wad Wadfile to add the lump data to. * * size Size of lump data in bytes. * * name Directory name of lump. IT MUST BE 8 CHARACTERS! * * data Pointer to lump data. * * * * Retn: * * TRUE if the data is added successfully, FALSE otherwise. * * * * Notes: * * If compiling for a 16-bit target, the maximum lump size is 64k. * * * * 'name' should consist of capital letters, numbers, and the under- * * score character. If the text is less than eight characters, it * * must be padded with zeroes. For example: "E1M1\0\0\0\0" is correct.* * * *************************************************************************/ int WadfileAddLump(Wadfile * wad, unsigned long size, char * name, char * data) { unsigned long location; char * ptr; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds check */ if (!(wad->flags & FLAG_WADFILE_OPEN)) return FALSE; if (!(wad->flags & FLAG_WADFILE_WRITEONLY)) return FALSE; /* Bump up 'entryIndex' */ if (wad->entryIndex == INVALID_ENTRY) wad->entryIndex = 0; else wad->entryIndex++; if (wad->entryIndex >= wad->dirNumEntries) return FALSE; /* Copy data to 'dirCache' */ location = ftell(wad->wf); ptr = &wad->dirCache[wad->entryIndex*SIZEOF_WAD_DIR_ENTRY]; memcpy(ptr, &location, SIZEOF_WAD_DIR_LOCATION); ptr += SIZEOF_WAD_DIR_LOCATION; memcpy(ptr, &size, SIZEOF_WAD_DIR_SIZE); ptr += SIZEOF_WAD_DIR_SIZE; memcpy(ptr, name, SIZEOF_WAD_DIR_NAME); /* Write data to Wadfile on disk */ if (size != 0) fwrite(data, size, 1, wad->wf); return TRUE; } /**[ #2 ]***************************************************************** * * * WadfileClose * * * * Desc: * * This closes a Wadfile and flushes its disk cache. If the lump is * * open, it is closed and the lump memory is released. If the * * Wadfile is being created, the directory is written to disk and * * the file header is updated before the Wadfile is closed. * * * * Def: * * void WadfileClose(Wadfile * wad); * * * * Parm: * * wad The Wadfile to close. * * * * Retn: * * None. * * * *************************************************************************/ void WadfileClose(Wadfile * wad) { uint32 size, location; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* If the file is open, flush caches, close file and clear the open flag */ if (wad->flags & FLAG_WADFILE_OPEN) { /* If creating a file, write directory entries and fix header */ if (wad->flags & FLAG_WADFILE_WRITEONLY) { if (wad->entryIndex != INVALID_ENTRY) { /* Initialize variables */ size = wad->entryIndex + 1; location = ftell(wad->wf); /* Write directory to disk */ fwrite(wad->dirCache, SIZEOF_WAD_DIR_ENTRY, size, wad->wf); /* Fix WAD header */ fseek(wad->wf, SIZEOF_WAD_SIGNATURE, SEEK_SET); fwrite(&size, sizeof(size), 1, wad->wf); fwrite(&location, sizeof(location), 1, wad->wf); } else { /* Invalid Wad file, so destroy WAD Signature */ fseek(wad->wf, 0L, SEEK_SET); size = 0; fwrite(&size, SIZEOF_WAD_SIGNATURE, 1, wad->wf); } } /* Flush 'dirCache' */ if (wad->flags & FLAG_WADFILE_DIRCACHED) { wf_free(wad->dirCache); wad->flags ^= FLAG_WADFILE_DIRCACHED; } if (wad->flags & FLAG_LUMP_OPEN) WadfileLumpClose(wad); /* Close file */ fclose(wad->wf); wad->flags ^= FLAG_WADFILE_OPEN; } } /**[ #3 ]***************************************************************** * * * WadfileCopyEntry * * * * Desc: * * This copies an arbitrary lump from an open Wadfile to a Wadfile * * that is being created. Do not use 'WadfileLumpOpen' or * * 'WadfileLumpClose' to initialize and release the lump data; this * * routine is self-contained and opens, copies, and closes the lump * * data in one fell swoop. * * * * Def: * * int WadfileCopyEntry(Wadfile * dest, char * destName, * * Wadfile * src, char * srcName) * * * * Parm: * * dest A Wadfile that is being created. * * destName The directory entry name for the new lump. * * src An existing Wadfile. * * srcName The directory entry name to search for and copy. * * * * Retn: * * TRUE if lump is copied succesfully; FALSE otherwise. * * * * Notes: * * On a 16-bit platform, this successfully copies lumps larger * * than 64k. * * * *************************************************************************/ int WadfileCopyEntry(Wadfile * dest, char * destName, Wadfile * src, char * srcName) { /* Sequentially search WAD directory for 'srcName' */ if (!WadfileSeek(src, srcName)) return FALSE; /* Copy lump from source to destination */ if (!WadfileLumpCopy(dest, destName, src)) return FALSE; return TRUE; } /**[ #4 ]***************************************************************** * * * WadfileCopyMap * * * * Desc: * * This copies an arbitrary map from an open Wadfile to a Wadfile * * that is being created. Do not use 'WadfileLumpOpen' or * * 'WadfileLumpClose' to initialize and release the lump data; this * * routine is self-contained and opens, copies, and closes the lump * * data in one fell swoop. * * * * Def: * * int WadfileCopyMap(Wadfile * dest, int destEpisode, int destMap, * * Wadfile * src, int srcEpisode, int srcMap) * * * * Parm: * * dest A Wadfile that is being created. * * destEpisode The new episode number for the map data. * * destMap The new map number for the map data. * * src An existing Wadfile. * * srcEpisode The old episode number for the map data. * * srcMap The old map number for the map data. * * * * Retn: * * TRUE if map is copied succesfully; FALSE otherwise. * * * * Notes: * * On a 16-bit platform, this successfully copies lumps larger * * than 64k. * * * *************************************************************************/ int WadfileCopyMap(Wadfile * dest, int destEpisode, int destMap, Wadfile * src, int srcEpisode, int srcMap) { int i; char targetName[SIZEOF_WAD_DIR_NAME]; /* Seek to map location, if possible */ if (!WadfileSeekMap(src, srcEpisode, srcMap)) return FALSE; /* Copy the source map to destination map */ if (!WadfileLumpOpen(src)) return FALSE; sprintf(targetName, "E%dM%d\0\0\0\0", destEpisode, destMap); if (!WadfileAddLump(dest, src->lumpSize, targetName, src->lumpData)) return FALSE; if (!WadfileLumpClose(src)) return FALSE; /* Now that this is copied, go to next entry */ WadfileGetNextDirInfo(src); /* Write out all other sections of the map */ for (i=0; ientryName, src)) return FALSE; /* Go to next entry in the directory */ WadfileGetNextDirInfo(src); } return TRUE; } /**[ #5 ]***************************************************************** * * * WadfileCreate * * * * Desc: * * This initializes a Wadfile structure, and creates a WAD file on * * disk. This file can be either an IWAD or a PWAD file. * * * * Def: * * int WadfileCreate(Wadfile * wad, char * filename, * * int type, int maxEntries); * * * * Parm: * * wad The Wadfile to create. * * filename The filename (with path) to use. * * type The file type, either IWAD or PWAD: * * TYPE_IWAD Create an IWAD file. * * TYPE_PWAD Create a PWAD file. * * maxEntries The maximum number of directory entries that can be * * used in this Wadfile. * * * * Retn: * * TRUE if the Wadfile is created successfully, FALSE otherwise. * * * * Notes: * * If 'filename' exists on disk, the function fails. YOU must delete * * the file before calling this function. * * * * 'filename' should have a ".WAD" extension. * * * * There is no reason to create an IWAD file. You should always * * create a PWAD file. * * * * Be liberal when choosing 'maxEntries'. You have less RAM is you * * choose too high, the program crashes if you choose too low. Each * * entry takes 16 bytes of RAM. The registered DOOM has just over * * 2000 entries. * * * *************************************************************************/ int WadfileCreate(Wadfile * wad, char * filename, int type, int maxEntries) { uint32 longint; char s[SIZEOF_WAD_SIGNATURE+1]; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds check */ if (filename == NULL) return FALSE; if ((type != TYPE_IWAD) && (type != TYPE_PWAD)) return FALSE; if (maxEntries <= 0) return FALSE; /* Make sure the memory allocation routines exist */ if (wadfileMalloc == NULL) return FALSE; /* Initialize WAD structure */ wad->flags = 0; wad->dirNumEntries = maxEntries; wad->entryIndex = INVALID_ENTRY; wad->entryName[SIZEOF_WAD_DIR_NAME] = 0; /* Permanent end of string mark */ wad->dirCache = NULL; /* Make sure the file doesn't already exist */ wad->wf = fopen(filename, "rb"); if (wad->wf!=NULL) return FALSE; /* Create the file, return if error */ wad->wf = fopen(filename, "wb"); if (wad->wf==NULL) return FALSE; wad->flags ^= FLAG_WADFILE_OPEN; wad->flags ^= FLAG_WADFILE_WRITEONLY; /* Write signature to the Wadfile */ if (type==TYPE_IWAD) strcpy(s, IWAD_SIGNATURE); else strcpy(s, PWAD_SIGNATURE); s[SIZEOF_WAD_SIGNATURE] = 0; fwrite(s, SIZEOF_WAD_SIGNATURE, 1, wad->wf); /* Write out dummy values for dir location and size as placeholders */ longint=0; fwrite(&longint, sizeof(longint), 1, wad->wf); fwrite(&longint, sizeof(longint), 1, wad->wf); /* Create the directory with 'maxEntries' number of entries */ wad->dirCache = wf_malloc(maxEntries*SIZEOF_WAD_DIR_ENTRY); if (wad->dirCache == NULL) { WadfileClose(wad); return FALSE; } wad->flags |= FLAG_WADFILE_DIRCACHED; return TRUE; } /**[ #6 ]***************************************************************** * * * WadfileGetDirInfo * * * * Desc: * * This loads a specific Wadfile directory entry into a Wadfile * * structure. * * * * Def: * * int WadfileGetDirInfo(Wadfile * wad, int entryIndex); * * * * Parm: * * wad The Wadfile structure to process. * * entryIndex Directory index to load in. * * * * Retn: * * TRUE if entry found and loaded succesfully; FALSE otherwise. * * * *************************************************************************/ int WadfileGetDirInfo(Wadfile * wad, int entryIndex) { /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds check */ if (entryIndex < 0) return FALSE; if (!(wad->flags & FLAG_WADFILE_OPEN)) return FALSE; if (entryIndex > wad->dirNumEntries) return FALSE; /* Copy info from memory or disk */ if (wad->flags & FLAG_WADFILE_DIRCACHED) { /* From memory cache */ memcpy(&wad->entryLocation, &wad->dirCache[entryIndex*SIZEOF_WAD_DIR_ENTRY], SIZEOF_WAD_DIR_ENTRY); } else { /* Seek to the correct directory entry and read it in from disk */ fseek(wad->wf, wad->dirLocation + SIZEOF_WAD_DIR_ENTRY*entryIndex, SEEK_SET); fread(&wad->entryLocation, SIZEOF_WAD_DIR_ENTRY, 1, wad->wf); } /* Update WAD structure */ wad->entryIndex = entryIndex; return TRUE; } /**[ #7 ]***************************************************************** * * * WadfileGetNextDirInfo * * * * Desc: * * This loads the next Wadfile directory entry into a Wadfile * * structure. * * * * Def: * * int WadfileGetNextDirInfo(Wadfile * wad); * * * * Parm: * * wad The Wadfile structure to process. * * * * Retn: * * TRUE if entry loaded succesfully; FALSE otherwise. * * * * Notes: * * This routine fails if you haven't called 'WadfileGetDirInfo' at * * least once with this Wadfile variable. * * * *************************************************************************/ int WadfileGetNextDirInfo(Wadfile * wad) { /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); return WadfileGetDirInfo(wad, wad->entryIndex+1); } /**[ #8 ]***************************************************************** * * * WadfileGetPrevDirInfo * * * * Desc: * * This loads the previous Wadfile directory entry into a Wadfile * * structure. * * * * Def: * * int WadfileGetPrevDirInfo(Wadfile * wad); * * * * Parm: * * wad The Wadfile structure to process. * * * * Retn: * * TRUE if entry loaded succesfully; FALSE otherwise. * * * * Notes: * * This routine fails if you haven't called 'WadfileGetDirInfo' at * * least once with this Wadfile variable. * * * *************************************************************************/ int WadfileGetPrevDirInfo(Wadfile * wad) { /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); return WadfileGetDirInfo(wad, wad->entryIndex-1); } /**[ #9 ]***************************************************************** * * * WadfileInitialize * * * * Desc: * * This initializes the Wadfile support and must be called before * * any other Wadfile routines are called. * * * * Def: * * int WadfileInitialize(WadfileMalloc * wfm, WadfileFree * wff); * * * * Parm: * * wfm Malloc routine for Wadfile routines (can be NULL) * * wff Free memory routine for Wadfile routines (can be NULL) * * * * Retn: * * TRUE if the memory routines are operational, FALSE otherwise. * * * * Notes: * * Either both of the parameters are NULL or not. It is a fatal error * * to specify one routine and not the other. * * * * Any time you want to specify different memory allocation routines * * for the Wadfile library, just call this routine again. If there * * are lingering allocations, the function will fail. * * * *************************************************************************/ int WadfileInitialize(WadfileMalloc wfm, WadfileFree wff) { /* Bounds check--vital enough to be asserts */ assert(((wfm==NULL) && (wff==NULL))|| ((wfm!=NULL) && (wff!=NULL))); /* See if we're getting re-initialized */ if (wadfileInitialized) { /* Any lingering allocations? */ if (wadfileNumAllocations) wadfileInitialized = FALSE; else { /* No? Re-initialize. */ wadfileMalloc = wfm; wadfileFree = wff; } } else { /* Make sure the compiler understands the code */ assert(sizeof(int16) == 2); assert(sizeof(uint16) == 2); assert(sizeof(int32) == 4); assert(sizeof(uint32) == 4); /* Initialize the memory handlers */ wadfileNumAllocations = 0; wadfileMalloc = wfm; wadfileFree = wff; wadfileInitialized = TRUE; } return wadfileInitialized; } /**[ #10 ]**************************************************************** * * * WadfileLumpClose * * * * Desc: * * This releases the memory allocated to the lump that is stored * * in a Wadfile structure. This memory is allocated and filled * * by the 'WadfileLumpOpen' routine. * * * * Def: * * int WadfileLumpClose(Wadfile * wad); * * * * Parm: * * wad The Wadfile structure to process. * * * * Retn: * * TRUE if lump memory freed succesfully; FALSE otherwise. * * * *************************************************************************/ int WadfileLumpClose(Wadfile * wad) { /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds check */ if (wadfileMalloc==NULL) return FALSE; if (!(wad->flags & FLAG_LUMP_OPEN)) return FALSE; /* Deallocate the LUMP data */ if (wad->lumpSize != 0) wf_free(wad->lumpData); /* Update Wadfile structure */ wad->flags ^= FLAG_LUMP_OPEN; return TRUE; } /**[ #11 ]**************************************************************** * * * WadfileLumpCopy * * * * Desc: * * This copies the lump data from an open Wadfile to a Wadfile that * * is being created. Do not use 'WadfileLumpOpen' or * * 'WadfileLumpClose' to initialize and release the lump data; this * * routine is self-contained and opens, copies, and closes the lump * * data in one fell swoop. * * * * Def: * * int WadfileLumpCopy(Wadfile * dest, char * destName, Wadfile * src); * * * * Parm: * * dest A Wadfile that is being created. * * destName The directory entry name for the new lump. * * src An existing Wadfile. * * * * Retn: * * TRUE if lump is copied succesfully; FALSE otherwise. * * * * Notes: * * On a 16-bit platform, this successfully copies lumps larger * * than 64k. * * * *************************************************************************/ int WadfileLumpCopy(Wadfile * dest, char * destName, Wadfile * src) { unsigned long allocSize; unsigned long lumpCopySize; unsigned long location; char * ptr; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds check */ if (wadfileMalloc==NULL) return FALSE; if (!(dest->flags & FLAG_WADFILE_OPEN)) return FALSE; if (!(src->flags & FLAG_WADFILE_OPEN)) return FALSE; if (!(dest->flags & FLAG_WADFILE_WRITEONLY)) return FALSE; if (src->flags & FLAG_WADFILE_WRITEONLY) return FALSE; if (dest->flags & FLAG_LUMP_OPEN) return FALSE; if (src->entryIndex == INVALID_ENTRY) return FALSE; if (destName == NULL) return FALSE; /* Set LUMP variables */ dest->lumpLocation = src->entryLocation; dest->lumpSize = src->entrySize; memcpy(dest->lumpName, destName, SIZEOF_WAD_DIR_NAME); location = ftell(dest->wf); /* Seek to start of data to be read */ fseek(src->wf, src->entryLocation, SEEK_SET); /* Set up loop control variable */ lumpCopySize = dest->lumpSize; /* Do the copy */ while (lumpCopySize != 0) { /* Allocate a buffer */ if (lumpCopySize >= MALLOC_MAX) allocSize = MALLOC_MAX; else allocSize = lumpCopySize; dest->lumpData = wf_malloc(allocSize); if (dest->lumpData == NULL) return FALSE; /* Read LUMP data from 'src' and write to 'dest' */ fread(dest->lumpData, allocSize, 1, src->wf); fwrite(dest->lumpData, allocSize, 1, dest->wf); /* Free the buffer */ wf_free(dest->lumpData); /* Update our byte count */ lumpCopySize -= allocSize; } /* while */ /* Bump up 'entryIndex' */ if (dest->entryIndex == INVALID_ENTRY) dest->entryIndex = 0; else dest->entryIndex++; if (dest->entryIndex >= dest->dirNumEntries) return FALSE; /* Copy data to 'dirCache' */ ptr = &dest->dirCache[dest->entryIndex*SIZEOF_WAD_DIR_ENTRY]; memcpy(ptr, &location, SIZEOF_WAD_DIR_LOCATION); ptr += SIZEOF_WAD_DIR_LOCATION; memcpy(ptr, &dest->lumpSize, SIZEOF_WAD_DIR_SIZE); ptr += SIZEOF_WAD_DIR_SIZE; memcpy(ptr, dest->lumpName, SIZEOF_WAD_DIR_NAME); return TRUE; } /**[ #12 ]**************************************************************** * * * WadfileLumpOpen * * * * Desc: * * This allocates memory and reads in the lump associated with the * * current directory entry in the Wadfile structure. The memory * * is released later on by using the 'WadfileLumpClose' routine. * * * * Def: * * int WadfileLumpOpen(Wadfile * wad); * * * * Parm: * * wad The Wadfile structure to process. * * * * Retn: * * TRUE if lump allocated and read in succesfully; FALSE otherwise. * * * * Notes: * * This routine fails if you haven't called 'WadfileGetDirInfo' at * * least once with this Wadfile variable. * * * * If you're using a 16-bit compiler, the maximum lump size is 64k. * * This function fails if the lump is too big. Only 1 lump out of * * 2045 in the registered version of DOOM is >64kb. (E2M7 SIDEDEFS) * * Use 'WadfileLumpCopy' to work around the 64k limitation. * * * *************************************************************************/ int WadfileLumpOpen(Wadfile * wad) { /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds check */ if (wadfileMalloc==NULL) return FALSE; if (!(wad->flags & FLAG_WADFILE_OPEN)) return FALSE; if (wad->flags & FLAG_WADFILE_WRITEONLY) return FALSE; if (wad->flags & FLAG_LUMP_OPEN) return FALSE; if (wad->entryIndex == INVALID_ENTRY) return FALSE; /* Allocate memory for LUMP */ if (wad->entrySize != 0) { wad->lumpData = wf_malloc(wad->entrySize); if (wad->lumpData == NULL) return FALSE; } /* Set LUMP variables */ wad->lumpLocation = wad->entryLocation; wad->lumpSize = wad->entrySize; memcpy(wad->lumpName, wad->entryName, SIZEOF_WAD_DIR_NAME); /* Read LUMP data from disk */ if (wad->lumpSize != 0) { fseek(wad->wf, wad->entryLocation, SEEK_SET); fread(wad->lumpData, wad->lumpSize, 1, wad->wf); } /* Update Wadfile structure */ wad->flags |= FLAG_LUMP_OPEN; return TRUE; } /**[ #13 ]**************************************************************** * * * WadfileOpen * * * * Desc: * * This opens a WAD file and initializes a Wadfile context. * * * * Def: * * int WadfileOpen(Wadfile * wad, char * filename, int type); * * * * Parm: * * wad The Wadfile context * * filename The file name (including path) of the WAD file. * * type The type of WAD file to open: * * WANTIWAD accept only IWAD files. * * WANTPWAD accept only PWAD files. * * IWADPWAD accept either IWAD or PWAD files. * * * * Retn: * * TRUE if the file exists and is open, FALSE otherwise. * * * *************************************************************************/ int WadfileOpen(Wadfile * wad, char * filename, int type) { uint32 longint; char s[SIZEOF_WAD_SIGNATURE+1]; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Initialize WAD structure */ wad->flags = 0; wad->entryIndex = INVALID_ENTRY; wad->entryName[SIZEOF_WAD_DIR_NAME] = 0; /* Permanent end of string mark */ wad->dirCache = NULL; /* Open the file, return if error */ wad->wf = fopen(filename, "rb"); if (wad->wf==NULL) return FALSE; wad->flags ^= FLAG_WADFILE_OPEN; /* Read in and check the WAD file signature */ fread(s, SIZEOF_WAD_SIGNATURE, 1, wad->wf); s[SIZEOF_WAD_SIGNATURE] = 0; if (strcmp(s, IWAD_SIGNATURE) == 0) wad->flags |= FLAG_WADFILE_IWAD; else if (strcmp(s, PWAD_SIGNATURE) != 0) goto Exit_Error; /* Read in directory location and size */ fread(&longint, sizeof(longint), 1, wad->wf); wad->dirNumEntries = longint; fread(&longint, sizeof(longint), 1, wad->wf); wad->dirLocation = longint; /* Make sure the file type matches what the caller is asking for */ if (((type == WANTPWAD)&&(wad->flags & FLAG_WADFILE_IWAD)) || ((type == WANTIWAD)&&(!(wad->flags & FLAG_WADFILE_IWAD)))) { Exit_Error: WadfileClose(wad); return FALSE; } /* If memory allocation is available, try to cache the directory */ if (wadfileMalloc != NULL) { wad->dirCache = wf_malloc(wad->dirNumEntries*SIZEOF_WAD_DIR_ENTRY); if (wad->dirCache != NULL) { wad->flags |= FLAG_WADFILE_DIRCACHED; fseek(wad->wf, wad->dirLocation, SEEK_SET); fread(wad->dirCache, wad->dirNumEntries*SIZEOF_WAD_DIR_ENTRY, 1,wad->wf); } } return TRUE; } /**[ #14 ]**************************************************************** * * * WadfileSeek * * * * Desc: * * This routine does a linear search through the Wadfile's directory * * starting with the first directory entry and searching until it * * finds its target or hits the end of the directory. * * * * Def: * * int WadfileSeek(Wadfile * wad, char * targetName); * * * * Parm: * * wad The Wadfile structure to process. * * targetName The name of the target directory entry. * * * * Retn: * * TRUE if target was found succesfully; FALSE otherwise. * * If TRUE, then the Wadfile's 'entryIndex', 'entryName', * * 'entrySize', and 'entryLocation' contain meaningful values. * * * * Notes: * * 'targetName' can be less than 8 characters; that is, you do not * * have to pad it with zeroes, like in 'WadfileAddLump'. * * * * See also 'WadfileSeekMap' if you are looking for a specific map. * * * *************************************************************************/ int WadfileSeek(Wadfile * wad, char * targetName) { int i; char targetString[SIZEOF_WAD_DIR_NAME+1]; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Convert target name to a null-terminated string */ strncpy(targetString, targetName, SIZEOF_WAD_DIR_NAME); targetString[SIZEOF_WAD_DIR_NAME] = '\0'; /* Bounds Check */ if (!(wad->flags & FLAG_WADFILE_OPEN)) return FALSE; if (targetString == NULL) return FALSE; /* Too small */ if (strlen(targetString)>SIZEOF_WAD_DIR_NAME) return FALSE; /* Too big */ /* Begin linear search of the WAD directory */ i=0; while ((idirNumEntries)&&(strcmp(wad->entryName, targetString) !=0)) { WadfileGetDirInfo(wad, i); i++; } return (idirNumEntries); } /**[ #15 ]**************************************************************** * * * WadfileSeekMap * * * * Desc: * * This routine does a linear search through the Wadfile's directory * * starting with the first directory entry and searching until it * * finds its target map or hits the end of the directory. * * * * Def: * * int WadfileSeekMap(Wadfile * wad, int episodeNum, int mapNum); * * * * Parm: * * wad The Wadfile structure to process. * * episodeNum Episode to find. Valid range is 1...DOOM_LASTEPISODE. * * mapNum Map to find. Valid range is 1...DOOM_LASTMAP. * * * * Retn: * * TRUE if target was found succesfully; FALSE otherwise. * * If TRUE, then the Wadfile's 'entryIndex', 'entryName', * * 'entrySize', and 'entryLocation' contain meaningful values. * * * * Notes: * * This routine uses 'WadfileSeek' as its search engine. When you * * aren't looking for maps, use 'WadfileSeek'. * * * *************************************************************************/ int WadfileSeekMap(Wadfile * wad, int episodeNum, int mapNum) { char targetName[5]; /* Make sure WadfileInitialize has been called */ assert(wadfileInitialized); /* Bounds Check */ if ((episodeNum < 0) || (episodeNum > DOOM_LASTEPISODE)) return FALSE; if ((mapNum < 0) || (mapNum > DOOM_LASTMAP)) return FALSE; /* Compose directory name */ sprintf(targetName, "E%dM%d",episodeNum, mapNum); /* Sequentially search WAD directory for ExMy */ return WadfileSeek(wad, targetName); }