/** * 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 * */ #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 ...