MegaGlest/mk/linux/mojosetup/archive_pkg.c

228 lines
6.1 KiB
C

/**
* 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, number of files in the archive
} 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 ...