Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added support for Descent 3 Mercenary archives
- Loading branch information
Showing
3 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
/** | ||
* MojoSetup; a portable, flexible installation application. | ||
* | ||
* Please see the file LICENSE.txt in the source's root directory. | ||
* | ||
* This file written by Steffen Pankratz. | ||
*/ | ||
|
||
#include "fileio.h" | ||
#include "platform.h" | ||
|
||
#if !SUPPORT_PKG | ||
MojoArchive *MojoArchive_createPKG(MojoInput *io) { return NULL; } | ||
#else | ||
|
||
#define PKG_MAGIC 0x4f504b47 | ||
|
||
typedef struct | ||
{ | ||
uint32 magic; // 4 bytes, has to be PKG_MAGIC (0x4f504b47) | ||
uint32 fileCount; // 4 bytes, offset to the data | ||
} PKGheader; | ||
|
||
typedef struct | ||
{ | ||
uint64 nextFileStart; | ||
} PKGinfo; | ||
|
||
static boolean MojoInput_pkg_ready(MojoInput *io) | ||
{ | ||
return true; | ||
} // MojoInput_pkg_ready | ||
|
||
static int64 MojoInput_pkg_read(MojoInput *io, void *buf, uint32 bufsize) | ||
{ | ||
MojoArchive *ar = (MojoArchive *) io->opaque; | ||
const MojoArchiveEntry *entry = &ar->prevEnum; | ||
int64 pos = io->tell(io); | ||
if ((pos + bufsize) > entry->filesize) | ||
bufsize = (uint32) (entry->filesize - pos); | ||
return ar->io->read(ar->io, buf, bufsize); | ||
} // MojoInput_pkg_read | ||
|
||
static boolean MojoInput_pkg_seek(MojoInput *io, uint64 pos) | ||
{ | ||
MojoArchive *ar = (MojoArchive *) io->opaque; | ||
const PKGinfo *info = (PKGinfo *) ar->opaque; | ||
const MojoArchiveEntry *entry = &ar->prevEnum; | ||
boolean retval = false; | ||
if (pos < ((uint64) entry->filesize)) | ||
{ | ||
const uint64 newpos = (info->nextFileStart - entry->filesize) + pos; | ||
retval = ar->io->seek(ar->io, newpos); | ||
} // if | ||
return retval; | ||
} // MojoInput_pkg_seek | ||
|
||
static int64 MojoInput_pkg_tell(MojoInput *io) | ||
{ | ||
MojoArchive *ar = (MojoArchive *) io->opaque; | ||
const PKGinfo *info = (PKGinfo *) ar->opaque; | ||
const MojoArchiveEntry *entry = &ar->prevEnum; | ||
return ar->io->tell(ar->io) - (info->nextFileStart - entry->filesize); | ||
} // MojoInput_pkg_tell | ||
|
||
static int64 MojoInput_pkg_length(MojoInput *io) | ||
{ | ||
MojoArchive *ar = (MojoArchive *) io->opaque; | ||
const MojoArchiveEntry *entry = &ar->prevEnum; | ||
return entry->filesize; | ||
} // MojoInput_pkg_length | ||
|
||
static MojoInput *MojoInput_pkg_duplicate(MojoInput *io) | ||
{ | ||
MojoInput *retval = NULL; | ||
fatal(_("BUG: Can't duplicate pkg inputs")); // !!! FIXME: why not? | ||
return retval; | ||
} // MojoInput_pkg_duplicate | ||
|
||
static void MojoInput_pkg_close(MojoInput *io) | ||
{ | ||
free(io); | ||
} // MojoInput_pkg_close | ||
|
||
// MojoArchive implementation... | ||
|
||
static boolean MojoArchive_pkg_enumerate(MojoArchive *ar) | ||
{ | ||
PKGinfo *info = (PKGinfo *) ar->opaque; | ||
MojoArchive_resetEntry(&ar->prevEnum); | ||
|
||
info->nextFileStart = sizeof (PKGheader); | ||
return true; | ||
} // MojoArchive_pkg_enumerate | ||
|
||
|
||
static const MojoArchiveEntry *MojoArchive_pkg_enumNext(MojoArchive *ar) | ||
{ | ||
PKGinfo *info = (PKGinfo *) ar->opaque; | ||
MojoInput *io = ar->io; | ||
int64 ret = 0; | ||
uint32 pathNameLength = 0; | ||
uint64 pathNameStart = 0; | ||
uint32 fileNameLength = 0; | ||
uint64 fileNameStart = 0; | ||
uint32 fileSize = 0; | ||
char* backSlash = NULL; | ||
|
||
if (!ar->io->seek(ar->io, info->nextFileStart)) | ||
return NULL; | ||
|
||
// read the path name length | ||
if (!MojoInput_readui32(io, &pathNameLength)) | ||
return NULL; | ||
|
||
pathNameStart = ar->io->tell(ar->io); | ||
|
||
// skip reading the path name for now | ||
if (!ar->io->seek(ar->io, pathNameStart + pathNameLength)) | ||
return NULL; | ||
|
||
// read the file name length | ||
if (!MojoInput_readui32(io, &fileNameLength)) | ||
return NULL; | ||
|
||
fileNameStart = ar->io->tell(ar->io); | ||
|
||
// as both strings are null terminated, we need one byte less | ||
ar->prevEnum.filename = (char *) xmalloc(pathNameLength + fileNameLength -1); | ||
|
||
// go to the start of the path name | ||
if (!ar->io->seek(ar->io, pathNameStart)) | ||
return NULL; | ||
|
||
// read the path name | ||
ret = io->read(io, ar->prevEnum.filename, pathNameLength); | ||
if (ret != pathNameLength) | ||
return false; | ||
|
||
// replace backslashes with slashes in the path name | ||
while((backSlash = strchr(ar->prevEnum.filename, '\\'))) | ||
*backSlash = '/'; | ||
|
||
// go the start of the file name | ||
if (!ar->io->seek(ar->io, fileNameStart)) | ||
return NULL; | ||
|
||
// read the file name | ||
ret = io->read(io, ar->prevEnum.filename + pathNameLength - 1, fileNameLength); | ||
if (ret != fileNameLength) | ||
return false; | ||
|
||
// read the file size | ||
if (!MojoInput_readui32(io, &fileSize)) | ||
return NULL; | ||
|
||
// skip the next 8 bytes, probably some kind of check sum | ||
if (!ar->io->seek(ar->io, ar->io->tell(ar->io) + 8)) | ||
return NULL; | ||
|
||
ar->prevEnum.filesize = fileSize; | ||
ar->prevEnum.perms = MojoPlatform_defaultFilePerms(); | ||
ar->prevEnum.type = MOJOARCHIVE_ENTRY_FILE; | ||
|
||
info->nextFileStart = ar->io->tell(ar->io) + ar->prevEnum.filesize; | ||
|
||
return &ar->prevEnum; | ||
} // MojoArchive_pkg_enumNext | ||
|
||
|
||
static MojoInput *MojoArchive_pkg_openCurrentEntry(MojoArchive *ar) | ||
{ | ||
MojoInput *io = NULL; | ||
io = (MojoInput *) xmalloc(sizeof (MojoInput)); | ||
io->ready = MojoInput_pkg_ready; | ||
io->read = MojoInput_pkg_read; | ||
io->seek = MojoInput_pkg_seek; | ||
io->tell = MojoInput_pkg_tell; | ||
io->length = MojoInput_pkg_length; | ||
io->duplicate = MojoInput_pkg_duplicate; | ||
io->close = MojoInput_pkg_close; | ||
io->opaque = ar; | ||
return io; | ||
} // MojoArchive_pkg_openCurrentEntry | ||
|
||
|
||
static void MojoArchive_pkg_close(MojoArchive *ar) | ||
{ | ||
PKGinfo *info = (PKGinfo *) ar->opaque; | ||
ar->io->close(ar->io); | ||
|
||
free(info); | ||
free(ar); | ||
} // MojoArchive_pkg_close | ||
|
||
|
||
MojoArchive *MojoArchive_createPKG(MojoInput *io) | ||
{ | ||
MojoArchive *ar = NULL; | ||
PKGinfo *pkgInfo = NULL; | ||
PKGheader pkgHeader; | ||
|
||
if (!MojoInput_readui32(io, &pkgHeader.magic)) | ||
return NULL; | ||
else if (!MojoInput_readui32(io, &pkgHeader.fileCount)) | ||
return NULL; | ||
|
||
// Check if this is a *.pkg file. | ||
if (pkgHeader.magic != PKG_MAGIC) | ||
return NULL; | ||
|
||
pkgInfo = (PKGinfo *) xmalloc(sizeof (PKGinfo)); | ||
|
||
ar = (MojoArchive *) xmalloc(sizeof (MojoArchive)); | ||
ar->opaque = pkgInfo; | ||
ar->enumerate = MojoArchive_pkg_enumerate; | ||
ar->enumNext = MojoArchive_pkg_enumNext; | ||
ar->openCurrentEntry = MojoArchive_pkg_openCurrentEntry; | ||
ar->close = MojoArchive_pkg_close; | ||
ar->io = io; | ||
|
||
return ar; | ||
} // MojoArchive_createPKG | ||
|
||
#endif // SUPPORT_PKG | ||
|
||
// end of archive_pkg.c ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters