| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- /*
- * LucasArts 1990s-era shooters container files
- * GOB (Dark Forces 1994, Jedi Knight 1997)
- * LAB (Outlaws 1996)
- * LFD (XWing, Tie Fighter, Dark Forces, probably others)
- *
- * Written by Manuel Lauss <manuel.lauss@gmail.com>
- */
- #define __PHYSICSFS_INTERNAL__
- #include "physfs_internal.h"
- #if PHYSFS_SUPPORTS_LECARCHIVES
- /* GOB1: WAD-Style */
- static int gob1LoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 offset, void *arc)
- {
- PHYSFS_uint32 i, entries, dofs, dlen;
- char name[13];
- if (!io->seek(io, offset))
- return 0;
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &entries, 4), 0);
- entries = PHYSFS_swapULE32(entries);
- for (i = 0; i < entries; i++)
- {
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dofs, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dlen, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 13), 0);
- name[12] = '\0';
- dofs = PHYSFS_swapULE32(dofs);
- dlen = PHYSFS_swapULE32(dlen);
- BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, dofs, dlen), 0);
- }
- return 1;
- }
- /* GOB2: GOB1 with 127 byte filepath hierarchy */
- static int gob2LoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 offset, void *arc)
- {
- PHYSFS_uint32 i, entries, dofs, dlen;
- char name[128], *c;
- if (!io->seek(io, offset))
- return 0;
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &entries, 4), 0);
- entries = PHYSFS_swapULE32(entries);
- for (i = 0; i < entries; i++)
- {
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dofs, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dlen, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 128), 0);
- name[127] = '\0';
- /* replace backslashes */
- c = name;
- while (*c)
- {
- if (*c == '\\')
- *c = '/';
- ++c;
- }
- dofs = PHYSFS_swapULE32(dofs);
- dlen = PHYSFS_swapULE32(dlen);
- BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, dofs, dlen), 0);
- }
- return 1;
- }
- static void *GOB_openArchive(PHYSFS_Io *io, const char *name,
- int forWriting, int *claimed)
- {
- PHYSFS_uint8 buf[12];
- PHYSFS_uint32 catofs = 0;
- void *unpkarc = NULL;
- int ret, gob;
- assert(io != NULL); /* shouldn't ever happen. */
- BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 4), NULL);
- if (memcmp(buf, "GOB\x0a", 4) == 0)
- {
- gob = 1;
- }
- else if (memcmp(buf, "GOB\x20", 4) == 0)
- {
- /* Version */
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &catofs, 4), NULL);
- catofs = PHYSFS_swapULE32(catofs);
- if (catofs != 0x14)
- BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
- gob = 2;
- }
- else
- {
- BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
- gob = 0;
- }
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &catofs, 4), NULL);
- catofs = PHYSFS_swapULE32(catofs);
- *claimed = 1;
- unpkarc = UNPK_openArchive(io, 0, 1);
- BAIL_IF_ERRPASS(!unpkarc, NULL);
- switch (gob)
- {
- case 1: ret = gob1LoadEntries(io, catofs, unpkarc); break;
- case 2: ret = gob2LoadEntries(io, catofs, unpkarc); break;
- default: ret = 0;
- }
- if (ret == 0)
- {
- UNPK_abandonArchive(unpkarc);
- return NULL;
- }
- return unpkarc;
- }
- const PHYSFS_Archiver __PHYSFS_Archiver_GOB =
- {
- CURRENT_PHYSFS_ARCHIVER_API_VERSION,
- {
- "GOB",
- "LucasArts GOB container",
- "Manuel Lauss <manuel.lauss@gmail.com>",
- "https://icculus.org/physfs/",
- 0, /* supportsSymlinks */
- },
- GOB_openArchive,
- UNPK_enumerate,
- UNPK_openRead,
- UNPK_openWrite,
- UNPK_openAppend,
- UNPK_remove,
- UNPK_mkdir,
- UNPK_stat,
- UNPK_closeArchive
- };
- /** LFD **/
- static int lfdLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 skip, void *arc)
- {
- char ext[5], finalname[16];
- PHYSFS_uint32 dlen, pos;
- PHYSFS_sint64 len;
- int i;
- len = io->length(io);
- if (len < 4)
- {
- PHYSFS_setErrorCode(PHYSFS_ERR_PAST_EOF);
- return 0;
- }
- pos = skip;
- while (pos < len)
- {
- if (!io->seek(io, pos))
- return 0;
- memset(finalname, 0, 16);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, ext, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, finalname, 8), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dlen, 4), 0);
- dlen = PHYSFS_swapULE32(dlen);
- ext[4] = 0;
- i = strlen(finalname);
- finalname[i] = '.';
- strcpy(finalname + i + 1, ext);
- pos += 16; /* step over file meta info */
- BAIL_IF_ERRPASS(!UNPK_addEntry(arc, finalname, 0, -1, -1, pos, dlen), 0);
- pos += dlen; /* step over file contents */
- }
- return 1;
- }
- static void *LFD_openArchive(PHYSFS_Io *io, const char *name,
- int forWriting, int *claimed)
- {
- PHYSFS_uint8 buf[16];
- PHYSFS_uint32 catsize;
- void *unpkarc = NULL;
- assert(io != NULL); /* shouldn't ever happen. */
- BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 12), NULL);
- if (memcmp(buf, "RMAPresource", 12) == 0)
- {
- /* has a content directory */
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &catsize, 4), NULL);
- catsize = PHYSFS_swapULE32(catsize);
- if ((catsize & 15) || (catsize == 0))
- BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
- catsize += 16; /* include header */
- }
- else
- {
- catsize = 0;
- }
- if (!io->seek(io, 0))
- return NULL;
- *claimed = 1;
- unpkarc = UNPK_openArchive(io, 0, 1);
- BAIL_IF_ERRPASS(!unpkarc, NULL);
- if (!lfdLoadEntries(io, catsize, unpkarc))
- {
- UNPK_abandonArchive(unpkarc);
- return NULL;
- }
- return unpkarc;
- }
- const PHYSFS_Archiver __PHYSFS_Archiver_LFD =
- {
- CURRENT_PHYSFS_ARCHIVER_API_VERSION,
- {
- "LFD",
- "LucasArts LFD container",
- "Manuel Lauss <manuel.lauss@gmail.com>",
- "https://icculus.org/physfs/",
- 0, /* supportsSymlinks */
- },
- LFD_openArchive,
- UNPK_enumerate,
- UNPK_openRead,
- UNPK_openWrite,
- UNPK_openAppend,
- UNPK_remove,
- UNPK_mkdir,
- UNPK_stat,
- UNPK_closeArchive
- };
- /** LAB **/
- /* read characters until \0 is found */
- static PHYSFS_sint32 readstring(PHYSFS_Io *io, char *dest, unsigned max)
- {
- PHYSFS_uint32 bytes = 0;
- PHYSFS_sint64 ret;
- char c;
- while (bytes < max)
- {
- ret = io->read(io, &c, 1);
- if (ret == 0)
- return 0; /* file ended prematurely */
- else if (ret < 0)
- return -1;
- else if (c == 0)
- return bytes;
- *dest++ = c;
- bytes++;
- }
- return bytes;
- }
- static int labLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 cnt, void *arc)
- {
- const PHYSFS_uint32 lab_name_table_start = 16 + (cnt * 16);
- PHYSFS_uint32 nofs, dofs, dlen, fcc;
- PHYSFS_sint32 readlen;
- PHYSFS_sint64 savepos;
- char fn[32];
- PHYSFS_uint32 i;
- for (i = 0; i < cnt; i++)
- {
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &nofs, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dofs, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &dlen, 4), 0);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &fcc, 4), 0);
- nofs = PHYSFS_swapULE32(nofs);
- dofs = PHYSFS_swapULE32(dofs);
- dlen = PHYSFS_swapULE32(dlen);
- fcc = PHYSFS_swapULE32(fcc);
- /* remember where we parked */
- savepos = io->tell(io);
- if (savepos < 0)
- return 0;
- /* go to the filename table entry and read it */
- if (!io->seek(io, lab_name_table_start + nofs))
- return 0;
- memset(fn, 0, 32);
- readlen = readstring(io, fn, 31);
- if (readlen > 0)
- {
- BAIL_IF_ERRPASS(!UNPK_addEntry(arc, fn, 0, -1, -1, dofs, dlen), 0);
- }
- else
- {
- if (readlen == 0)
- PHYSFS_setErrorCode(PHYSFS_ERR_PAST_EOF);
- return 0;
- }
- /* ah that's the spot */
- if (!io->seek(io, savepos))
- return 0;
- }
- return 1;
- }
- static void *LAB_openArchive(PHYSFS_Io *io, const char *name,
- int forWriting, int *claimed)
- {
- PHYSFS_uint8 buf[16];
- PHYSFS_uint32 catsize, entries, i;
- void *unpkarc = NULL;
- assert(io != NULL); /* shouldn't ever happen. */
- BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 4), NULL);
- if (memcmp(buf, "LABN", 4) != 0)
- BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
- /* Container Format version, always 0x00010000 */
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &i, 4), NULL);
- i = PHYSFS_swapULE32(i);
- if (i != 0x00010000)
- BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &entries, 4), NULL);
- BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &catsize, 4), NULL);
- entries = PHYSFS_swapULE32(entries);
- catsize = PHYSFS_swapULE32(catsize);
- *claimed = 1;
- unpkarc = UNPK_openArchive(io, 0, 1);
- BAIL_IF_ERRPASS(!unpkarc, NULL);
- if (!labLoadEntries(io, entries, unpkarc))
- {
- UNPK_abandonArchive(unpkarc);
- return NULL;
- }
- return unpkarc;
- }
- const PHYSFS_Archiver __PHYSFS_Archiver_LAB =
- {
- CURRENT_PHYSFS_ARCHIVER_API_VERSION,
- {
- "LAB",
- "LucasArts LAB container",
- "Manuel Lauss <manuel.lauss@gmail.com>",
- "https://icculus.org/physfs/",
- 0, /* supportsSymlinks */
- },
- LAB_openArchive,
- UNPK_enumerate,
- UNPK_openRead,
- UNPK_openWrite,
- UNPK_openAppend,
- UNPK_remove,
- UNPK_mkdir,
- UNPK_stat,
- UNPK_closeArchive
- };
- #endif
|