misc/libphysfs/archiver_slb.c
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     1 /*
       
     2  * SLB support routines for PhysicsFS.
       
     3  *
       
     4  * This driver handles SLB archives ("slab files"). This uncompressed format
       
     5  * is used in I-War / Independence War and Independence War: Defiance.
       
     6  *
       
     7  * The format begins with four zero bytes (version?), the file count and the
       
     8  * location of the table of contents. Each ToC entry contains a 64-byte buffer
       
     9  * containing a zero-terminated filename, the offset of the data, and its size.
       
    10  * All the filenames begin with the separator character '\'. 
       
    11  *
       
    12  * Please see the file LICENSE.txt in the source's root directory.
       
    13  *
       
    14  * This file written by Aleksi Nurmi, based on the GRP archiver by
       
    15  * Ryan C. Gordon.
       
    16  */
       
    17 
       
    18 #define __PHYSICSFS_INTERNAL__
       
    19 #include "physfs_internal.h"
       
    20 
       
    21 #if PHYSFS_SUPPORTS_SLB
       
    22 
       
    23 static UNPKentry *slbLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
       
    24 {
       
    25     UNPKentry *entries = NULL;
       
    26     UNPKentry *entry = NULL;
       
    27 
       
    28     entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
       
    29     BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
    30 
       
    31     for (entry = entries; fileCount > 0; fileCount--, entry++)
       
    32     {
       
    33         char *ptr;
       
    34 
       
    35         /* don't include the '\' in the beginning */
       
    36         char backslash;
       
    37         GOTO_IF_MACRO(!__PHYSFS_readAll(io, &backslash, 1), ERRPASS, failed);
       
    38         GOTO_IF_MACRO(backslash != '\\', ERRPASS, failed);
       
    39 
       
    40         /* read the rest of the buffer, 63 bytes */
       
    41         GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 63), ERRPASS, failed);
       
    42         entry->name[63] = '\0'; /* in case the name lacks the null terminator */
       
    43 
       
    44         /* convert backslashes */
       
    45         for (ptr = entry->name; *ptr; ptr++)
       
    46         {
       
    47             if (*ptr == '\\')
       
    48                 *ptr = '/';
       
    49         } /* for */
       
    50 
       
    51         GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->startPos, 4),
       
    52                       ERRPASS, failed);
       
    53         entry->startPos = PHYSFS_swapULE32(entry->startPos);
       
    54 
       
    55         GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed);
       
    56         entry->size = PHYSFS_swapULE32(entry->size);
       
    57     } /* for */
       
    58     
       
    59     return entries;
       
    60 
       
    61 failed:
       
    62     allocator.Free(entries);
       
    63     return NULL;
       
    64 
       
    65 } /* slbLoadEntries */
       
    66 
       
    67 
       
    68 static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
       
    69 {
       
    70     PHYSFS_uint32 version;
       
    71     PHYSFS_uint32 count = 0;
       
    72     PHYSFS_uint32 tocPos = 0;
       
    73     UNPKentry *entries = NULL;
       
    74 
       
    75     assert(io != NULL);  /* shouldn't ever happen. */
       
    76 
       
    77     BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
       
    78 
       
    79     BAIL_IF_MACRO(!__PHYSFS_readAll(io, &version, sizeof(version)),
       
    80                   ERRPASS, NULL);
       
    81     version = PHYSFS_swapULE32(version);
       
    82     BAIL_IF_MACRO(version != 0, ERRPASS, NULL);
       
    83 
       
    84     BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
       
    85     count = PHYSFS_swapULE32(count);
       
    86 
       
    87     /* offset of the table of contents */
       
    88     BAIL_IF_MACRO(!__PHYSFS_readAll(io, &tocPos, sizeof(tocPos)),
       
    89                   ERRPASS, NULL);
       
    90     tocPos = PHYSFS_swapULE32(tocPos);
       
    91     
       
    92     /* seek to the table of contents */
       
    93     BAIL_IF_MACRO(!io->seek(io, tocPos), ERRPASS, NULL);
       
    94 
       
    95     entries = slbLoadEntries(io, count);
       
    96     BAIL_IF_MACRO(!entries, ERRPASS, NULL);
       
    97 
       
    98     return UNPK_openArchive(io, entries, count);
       
    99 } /* SLB_openArchive */
       
   100 
       
   101 
       
   102 const PHYSFS_Archiver __PHYSFS_Archiver_SLB =
       
   103 {
       
   104     CURRENT_PHYSFS_ARCHIVER_API_VERSION,
       
   105     {
       
   106         "SLB",
       
   107         "I-War / Independence War Slab file",
       
   108         "Aleksi Nurmi <aleksi.nurmi@gmail.com>",
       
   109         "https://bitbucket.org/ahnurmi/",
       
   110         0,  /* supportsSymlinks */
       
   111     },
       
   112     SLB_openArchive,
       
   113     UNPK_enumerateFiles,
       
   114     UNPK_openRead,
       
   115     UNPK_openWrite,
       
   116     UNPK_openAppend,
       
   117     UNPK_remove,
       
   118     UNPK_mkdir,
       
   119     UNPK_stat,
       
   120     UNPK_closeArchive
       
   121 };
       
   122 
       
   123 #endif  /* defined PHYSFS_SUPPORTS_SLB */
       
   124 
       
   125 /* end of archiver_slb.c ... */
       
   126