287c71ca84
fastboot passes the *uncompressed* length of the file as the length of the input to the inflate() call, which happens to work unless the compressed data is actually larger than the uncompressed data (which it can be for very small files). Fix this to pass the correct compressed length down to the inflate call.
160 lines
3.4 KiB
C
160 lines
3.4 KiB
C
#include <zipfile/zipfile.h>
|
|
|
|
#include "private.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <zlib.h>
|
|
#define DEF_MEM_LEVEL 8 // normally in zutil.h?
|
|
|
|
zipfile_t
|
|
init_zipfile(const void* data, size_t size)
|
|
{
|
|
int err;
|
|
|
|
Zipfile *file = malloc(sizeof(Zipfile));
|
|
if (file == NULL) return NULL;
|
|
memset(file, 0, sizeof(Zipfile));
|
|
file->buf = data;
|
|
file->bufsize = size;
|
|
|
|
err = read_central_dir(file);
|
|
if (err != 0) goto fail;
|
|
|
|
return file;
|
|
fail:
|
|
free(file);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
release_zipfile(zipfile_t f)
|
|
{
|
|
Zipfile* file = (Zipfile*)f;
|
|
Zipentry* entry = file->entries;
|
|
while (entry) {
|
|
Zipentry* next = entry->next;
|
|
free(entry);
|
|
entry = next;
|
|
}
|
|
free(file);
|
|
}
|
|
|
|
zipentry_t
|
|
lookup_zipentry(zipfile_t f, const char* entryName)
|
|
{
|
|
Zipfile* file = (Zipfile*)f;
|
|
Zipentry* entry = file->entries;
|
|
while (entry) {
|
|
if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) {
|
|
return entry;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
size_t
|
|
get_zipentry_size(zipentry_t entry)
|
|
{
|
|
return ((Zipentry*)entry)->uncompressedSize;
|
|
}
|
|
|
|
char*
|
|
get_zipentry_name(zipentry_t entry)
|
|
{
|
|
Zipentry* e = (Zipentry*)entry;
|
|
int l = e->fileNameLength;
|
|
char* s = malloc(l+1);
|
|
memcpy(s, e->fileName, l);
|
|
s[l] = '\0';
|
|
return s;
|
|
}
|
|
|
|
enum {
|
|
STORED = 0,
|
|
DEFLATED = 8
|
|
};
|
|
|
|
static int
|
|
uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
|
|
{
|
|
z_stream zstream;
|
|
unsigned long crc;
|
|
int err = 0;
|
|
int zerr;
|
|
|
|
memset(&zstream, 0, sizeof(zstream));
|
|
zstream.zalloc = Z_NULL;
|
|
zstream.zfree = Z_NULL;
|
|
zstream.opaque = Z_NULL;
|
|
zstream.next_in = (void*)in;
|
|
zstream.avail_in = clen;
|
|
zstream.next_out = (Bytef*) out;
|
|
zstream.avail_out = unlen;
|
|
zstream.data_type = Z_UNKNOWN;
|
|
|
|
// Use the undocumented "negative window bits" feature to tell zlib
|
|
// that there's no zlib header waiting for it.
|
|
zerr = inflateInit2(&zstream, -MAX_WBITS);
|
|
if (zerr != Z_OK) {
|
|
return -1;
|
|
}
|
|
|
|
// uncompress the data
|
|
zerr = inflate(&zstream, Z_FINISH);
|
|
if (zerr != Z_STREAM_END) {
|
|
fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END,
|
|
zstream.total_out);
|
|
err = -1;
|
|
}
|
|
|
|
inflateEnd(&zstream);
|
|
return err;
|
|
}
|
|
|
|
int
|
|
decompress_zipentry(zipentry_t e, void* buf, int bufsize)
|
|
{
|
|
Zipentry* entry = (Zipentry*)e;
|
|
switch (entry->compressionMethod)
|
|
{
|
|
case STORED:
|
|
memcpy(buf, entry->data, entry->uncompressedSize);
|
|
return 0;
|
|
case DEFLATED:
|
|
return uninflate(buf, bufsize, entry->data, entry->compressedSize);
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void
|
|
dump_zipfile(FILE* to, zipfile_t file)
|
|
{
|
|
Zipfile* zip = (Zipfile*)file;
|
|
Zipentry* entry = zip->entries;
|
|
int i;
|
|
|
|
fprintf(to, "entryCount=%d\n", zip->entryCount);
|
|
for (i=0; i<zip->entryCount; i++) {
|
|
fprintf(to, " file \"");
|
|
fwrite(entry->fileName, entry->fileNameLength, 1, to);
|
|
fprintf(to, "\"\n");
|
|
entry = entry->next;
|
|
}
|
|
}
|
|
|
|
zipentry_t
|
|
iterate_zipfile(zipfile_t file, void** cookie)
|
|
{
|
|
Zipentry* entry = (Zipentry*)*cookie;
|
|
if (entry == NULL) {
|
|
Zipfile* zip = (Zipfile*)file;
|
|
*cookie = zip->entries;
|
|
return *cookie;
|
|
} else {
|
|
entry = entry->next;
|
|
*cookie = entry;
|
|
return entry;
|
|
}
|
|
}
|