MegaGlest/mk/linux/mojosetup/archive_pkg.c

251 lines
7.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.
*
Copyright (c) 2006-2010 Ryan C. Gordon and others.
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>
*
*/
#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 ...