MegaGlest/mk/linux/mojosetup/archive_pck.c

296 lines
8.5 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_PCK
MojoArchive *MojoArchive_createPCK(MojoInput *io) { return NULL; }
#else
#define PCK_MAGIC 0x534c4850
typedef struct
{
uint32 Magic; // 4 bytes, has to be PCK_MAGIC (0x534c4850)
uint32 StartOfBinaryData; // 4 bytes, offset to the data
} PCKheader;
typedef struct
{
int8 filename[60]; // 60 bytes, null terminated
uint32 filesize; // 4 bytes
} PCKentry;
typedef struct
{
uint64 fileCount;
uint64 dataStart;
uint64 nextFileStart;
int64 nextEnumPos;
MojoArchiveEntry *archiveEntries;
} PCKinfo;
static boolean MojoInput_pck_ready(MojoInput *io)
{
return true; // !!! FIXME?
} // MojoInput_pck_ready
static int64 MojoInput_pck_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_pck_read
static boolean MojoInput_pck_seek(MojoInput *io, uint64 pos)
{
MojoArchive *ar = (MojoArchive *) io->opaque;
const PCKinfo *info = (PCKinfo *) 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_pck_seek
static int64 MojoInput_pck_tell(MojoInput *io)
{
MojoArchive *ar = (MojoArchive *) io->opaque;
const PCKinfo *info = (PCKinfo *) ar->opaque;
const MojoArchiveEntry *entry = &ar->prevEnum;
return ar->io->tell(ar->io) - (info->nextFileStart - entry->filesize);
} // MojoInput_pck_tell
static int64 MojoInput_pck_length(MojoInput *io)
{
MojoArchive *ar = (MojoArchive *) io->opaque;
const MojoArchiveEntry *entry = &ar->prevEnum;
return entry->filesize;
} // MojoInput_pck_length
static MojoInput *MojoInput_pck_duplicate(MojoInput *io)
{
MojoInput *retval = NULL;
fatal(_("BUG: Can't duplicate pck inputs")); // !!! FIXME: why not?
return retval;
} // MojoInput_pck_duplicate
static void MojoInput_pck_close(MojoInput *io)
{
free(io);
} // MojoInput_pck_close
// MojoArchive implementation...
static boolean MojoArchive_pck_enumerate(MojoArchive *ar)
{
MojoArchiveEntry *archiveEntries = NULL;
PCKinfo *info = (PCKinfo *) ar->opaque;
const int dataStart = info->dataStart;
const int fileCount = dataStart / sizeof (PCKentry);
const size_t len = fileCount * sizeof (MojoArchiveEntry);
PCKentry fileEntry;
uint64 i, realFileCount = 0;
char directory[256] = {'\0'};
MojoInput *io = ar->io;
MojoArchive_resetEntry(&ar->prevEnum);
archiveEntries = (MojoArchiveEntry *) xmalloc(len);
for (i = 0; i < fileCount; i++)
{
int dotdot;
int64 br;
br = io->read(io, fileEntry.filename, sizeof (fileEntry.filename));
if (br != sizeof (fileEntry.filename))
return false;
else if (!MojoInput_readui32(io, &fileEntry.filesize))
return false;
dotdot = (strcmp(fileEntry.filename, "..") == 0);
if ((!dotdot) && (fileEntry.filesize == 0x80000000))
{
MojoArchiveEntry *entry = &archiveEntries[realFileCount];
strcat(directory, fileEntry.filename);
strcat(directory, "/");
entry->filename = xstrdup(directory);
entry->type = MOJOARCHIVE_ENTRY_DIR;
entry->perms = MojoPlatform_defaultDirPerms();
entry->filesize = 0;
realFileCount++;
} // if
else if ((dotdot) && (fileEntry.filesize == 0x80000000))
{
// remove trailing path separator
char *pathSep;
const size_t strLength = strlen(directory);
directory[strLength - 1] = '\0';
pathSep = strrchr(directory, '/');
if(pathSep != NULL)
{
pathSep++;
*pathSep = '\0';
} // if
} // else if
else
{
MojoArchiveEntry *entry = &archiveEntries[realFileCount];
if (directory[0] == '\0')
entry->filename = xstrdup(fileEntry.filename);
else
{
const size_t len = sizeof (char) * strlen(directory) +
strlen(fileEntry.filename) + 1;
entry->filename = (char *) xmalloc(len);
strcat(entry->filename, directory);
strcat(entry->filename, fileEntry.filename);
} // else
entry->perms = MojoPlatform_defaultFilePerms();
entry->type = MOJOARCHIVE_ENTRY_FILE;
entry->filesize = fileEntry.filesize;
realFileCount++;
} // else
} // for
info->fileCount = realFileCount;
info->archiveEntries = archiveEntries;
info->nextEnumPos = 0;
info->nextFileStart = dataStart;
return true;
} // MojoArchive_pck_enumerate
static const MojoArchiveEntry *MojoArchive_pck_enumNext(MojoArchive *ar)
{
PCKinfo *info = (PCKinfo *) ar->opaque;
const MojoArchiveEntry *entry = &info->archiveEntries[info->nextEnumPos];
if (info->nextEnumPos >= info->fileCount)
return NULL;
if (!ar->io->seek(ar->io, info->nextFileStart))
return NULL;
info->nextEnumPos++;
info->nextFileStart += entry->filesize;
memcpy(&ar->prevEnum, entry, sizeof (ar->prevEnum));
return &ar->prevEnum;
} // MojoArchive_pck_enumNext
static MojoInput *MojoArchive_pck_openCurrentEntry(MojoArchive *ar)
{
MojoInput *io = NULL;
io = (MojoInput *) xmalloc(sizeof (MojoInput));
io->ready = MojoInput_pck_ready;
io->read = MojoInput_pck_read;
io->seek = MojoInput_pck_seek;
io->tell = MojoInput_pck_tell;
io->length = MojoInput_pck_length;
io->duplicate = MojoInput_pck_duplicate;
io->close = MojoInput_pck_close;
io->opaque = ar;
return io;
} // MojoArchive_pck_openCurrentEntry
static void MojoArchive_pck_close(MojoArchive *ar)
{
int i;
PCKinfo *info = (PCKinfo *) ar->opaque;
ar->io->close(ar->io);
for (i = 0; i < info->fileCount; i++)
{
MojoArchiveEntry *entry = &info->archiveEntries[i];
free(entry->filename);
} // for
free(info->archiveEntries);
free(info);
free(ar);
} // MojoArchive_pck_close
MojoArchive *MojoArchive_createPCK(MojoInput *io)
{
MojoArchive *ar = NULL;
PCKinfo *pckInfo = NULL;
PCKheader pckHeader;
if (!MojoInput_readui32(io, &pckHeader.Magic))
return NULL;
else if (!MojoInput_readui32(io, &pckHeader.StartOfBinaryData))
return NULL;
// Check if this is a *.pck file.
if (pckHeader.Magic != PCK_MAGIC)
return NULL;
pckInfo = (PCKinfo *) xmalloc(sizeof (PCKinfo));
pckInfo->dataStart = pckHeader.StartOfBinaryData + sizeof (PCKheader);
ar = (MojoArchive *) xmalloc(sizeof (MojoArchive));
ar->opaque = pckInfo;
ar->enumerate = MojoArchive_pck_enumerate;
ar->enumNext = MojoArchive_pck_enumNext;
ar->openCurrentEntry = MojoArchive_pck_openCurrentEntry;
ar->close = MojoArchive_pck_close;
ar->io = io;
return ar;
} // MojoArchive_createPCK
#endif // SUPPORT_PCK
// end of archive_pck.c ...