misc/physfs/src/archiver_wad.c
branchphysfslayer
changeset 7768 13e2037ebc79
equal deleted inserted replaced
7767:d1ea9b3f543e 7768:13e2037ebc79
       
     1 /*
       
     2  * WAD support routines for PhysicsFS.
       
     3  *
       
     4  * This driver handles DOOM engine archives ("wads"). 
       
     5  * This format (but not this driver) was designed by id Software for use
       
     6  *  with the DOOM engine.
       
     7  * The specs of the format are from the unofficial doom specs v1.666
       
     8  * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
       
     9  * The format of the archive: (from the specs)
       
    10  *
       
    11  *  A WAD file has three parts:
       
    12  *  (1) a twelve-byte header
       
    13  *  (2) one or more "lumps"
       
    14  *  (3) a directory or "info table" that contains the names, offsets, and
       
    15  *      sizes of all the lumps in the WAD
       
    16  *
       
    17  *  The header consists of three four-byte parts:
       
    18  *    (a) an ASCII string which must be either "IWAD" or "PWAD"
       
    19  *    (b) a 4-byte (long) integer which is the number of lumps in the wad
       
    20  *    (c) a long integer which is the file offset to the start of
       
    21  *    the directory
       
    22  *
       
    23  *  The directory has one 16-byte entry for every lump. Each entry consists
       
    24  *  of three parts:
       
    25  *
       
    26  *    (a) a long integer, the file offset to the start of the lump
       
    27  *    (b) a long integer, the size of the lump in bytes
       
    28  *    (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
       
    29  *        For example, the "DEMO1" entry in hexadecimal would be
       
    30  *        (44 45 4D 4F 31 00 00 00)
       
    31  * 
       
    32  * Note that there is no way to tell if an opened WAD archive is a
       
    33  *  IWAD or PWAD with this archiver.
       
    34  * I couldn't think of a way to provide that information, without being too
       
    35  *  hacky.
       
    36  * I don't think it's really that important though.
       
    37  *
       
    38  *
       
    39  * Please see the file LICENSE.txt in the source's root directory.
       
    40  *
       
    41  * This file written by Travis Wells, based on the GRP archiver by
       
    42  *  Ryan C. Gordon.
       
    43  */
       
    44 
       
    45 #define __PHYSICSFS_INTERNAL__
       
    46 #include "physfs_internal.h"
       
    47 
       
    48 #if PHYSFS_SUPPORTS_WAD
       
    49 
       
    50 static UNPKentry *wadLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
       
    51 {
       
    52     PHYSFS_uint32 directoryOffset;
       
    53     UNPKentry *entries = NULL;
       
    54     UNPKentry *entry = NULL;
       
    55 
       
    56     BAIL_IF_MACRO(!__PHYSFS_readAll(io, &directoryOffset, 4), ERRPASS, 0);
       
    57     directoryOffset = PHYSFS_swapULE32(directoryOffset);
       
    58 
       
    59     BAIL_IF_MACRO(!io->seek(io, directoryOffset), ERRPASS, 0);
       
    60 
       
    61     entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
       
    62     BAIL_IF_MACRO(!entries, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
    63 
       
    64     for (entry = entries; fileCount > 0; fileCount--, entry++)
       
    65     {
       
    66         if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
       
    67         if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
       
    68         if (!__PHYSFS_readAll(io, &entry->name, 8)) goto failed;
       
    69 
       
    70         entry->name[8] = '\0'; /* name might not be null-terminated in file. */
       
    71         entry->size = PHYSFS_swapULE32(entry->size);
       
    72         entry->startPos = PHYSFS_swapULE32(entry->startPos);
       
    73     } /* for */
       
    74 
       
    75     return entries;
       
    76 
       
    77 failed:
       
    78     allocator.Free(entries);
       
    79     return NULL;
       
    80 } /* wadLoadEntries */
       
    81 
       
    82 
       
    83 static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
       
    84 {
       
    85     PHYSFS_uint8 buf[4];
       
    86     UNPKentry *entries = NULL;
       
    87     PHYSFS_uint32 count = 0;
       
    88 
       
    89     assert(io != NULL);  /* shouldn't ever happen. */
       
    90 
       
    91     BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
       
    92     BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
       
    93     if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
       
    94         BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
       
    95 
       
    96     BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof (count)), ERRPASS, NULL);
       
    97     count = PHYSFS_swapULE32(count);
       
    98 
       
    99     entries = wadLoadEntries(io, count);
       
   100     BAIL_IF_MACRO(!entries, ERRPASS, NULL);
       
   101     return UNPK_openArchive(io, entries, count);
       
   102 } /* WAD_openArchive */
       
   103 
       
   104 
       
   105 const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
       
   106 {
       
   107     {
       
   108         "WAD",
       
   109         "DOOM engine format",
       
   110         "Travis Wells <traviswells@mchsi.com>",
       
   111         "http://www.3dmm2.com/doom/",
       
   112     },
       
   113     WAD_openArchive,        /* openArchive() method    */
       
   114     UNPK_enumerateFiles,     /* enumerateFiles() method */
       
   115     UNPK_openRead,           /* openRead() method       */
       
   116     UNPK_openWrite,          /* openWrite() method      */
       
   117     UNPK_openAppend,         /* openAppend() method     */
       
   118     UNPK_remove,             /* remove() method         */
       
   119     UNPK_mkdir,              /* mkdir() method          */
       
   120     UNPK_closeArchive,       /* closeArchive() method   */
       
   121     UNPK_stat                /* stat() method           */
       
   122 };
       
   123 
       
   124 #endif  /* defined PHYSFS_SUPPORTS_WAD */
       
   125 
       
   126 /* end of wad.c ... */
       
   127