static int64 MojoInput_uz2_read(MojoInput *io, void *_buf, uint32 bufsize) { uint8 *buf = (uint8 *) _buf; UZ2input *input = (UZ2input *) io->opaque; int64 retval = 0; while (bufsize > 0) { const uint32 available = input->uncompsize - input->uncompindex; const uint32 cpy = (available < bufsize) ? available : bufsize; if (available == 0) { if (input->position == input->fsize) return 0; else if (!MojoInput_readui32(input->io, &input->compsize)) return (retval == 0) ? -1 : retval; else if (!MojoInput_readui32(input->io, &input->uncompsize)) return (retval == 0) ? -1 : retval; else if (!unpack(input)) return (retval == 0) ? -1 : retval; continue; // try again. } // if memcpy(buf, input->uncompbuf + input->uncompindex, cpy); buf += cpy; bufsize -= cpy; retval += cpy; input->uncompindex += cpy; input->position += cpy; } // while return retval; } // MojoInput_uz2_read
// Unfortunately, we have to walk the whole file, but we don't have to actually // do any decompression work here. Just seek, read 8 bytes, repeat until EOF. static int64 calculate_uz2_outsize(MojoInput *io) { int64 retval = 0; uint32 compsize = 0; uint32 uncompsize = 0; int64 pos = 0; if (!io->seek(io, 0)) return -1; while (MojoInput_readui32(io, &compsize)) { if (!MojoInput_readui32(io, &uncompsize)) return -1; else if ((compsize > MAXCOMPSIZE) || (uncompsize > MAXUNCOMPSIZE)) return -1; else if ((compsize == 0) || (uncompsize == 0)) return -1; retval += uncompsize; pos += (sizeof (uint32) * 2) + compsize; if (!io->seek(io, pos)) return -1; } // while if (!io->seek(io, 0)) // make sure we're back to the start. return -1; return retval; } // calculate_uz2_outsize
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
static boolean MojoInput_uz2_seek(MojoInput *io, uint64 pos) { UZ2input *input = (UZ2input *) io->opaque; int64 seekpos = 0; // in a perfect world, this wouldn't seek from the start if moving // forward. But oh well. input->position = 0; while (input->position < pos) { if (!input->io->seek(input->io, seekpos)) return false; else if (!MojoInput_readui32(io, &input->compsize)) return false; else if (!MojoInput_readui32(io, &input->uncompsize)) return false; // we checked these formally elsewhere. assert(input->compsize > 0); assert(input->uncompsize > 0); assert(input->compsize <= MAXCOMPSIZE); assert(input->uncompsize <= MAXUNCOMPSIZE); input->position += input->uncompsize; seekpos += (sizeof (uint32) * 2) + input->compsize; } // while // we are positioned on the compressed block that contains the seek target. if (!unpack(input)) return false; input->position -= input->uncompsize; input->uncompindex = (uint32) (pos - input->position); input->position += input->uncompindex; return true; } // MojoInput_uz2_seek
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