blob: a4a80c40f435e178465244fef561f1bdb974db77 [file] [log] [blame]
//===----------------- Zip.cpp - Interface with zlib ----------------------===//
//
// JnJVM
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <zlib.h>
#include "JavaArray.h"
#include "LockedMap.h"
#include "Reader.h"
#include "Zip.h"
using namespace jnjvm;
ZipArchive* ZipArchive::hashedArchive(char* archname) {
assert(0 && "implement hashedArchive");
return 0;
}
ZipArchive* ZipArchive::singleArchive(char* archname) {
ZipArchive* ar = gc_new(ZipArchive)();
ar->name = archname;
ArrayUInt8* bytes = Reader::openFile(archname);
if (bytes != 0) {
ar->reader = Reader::allocateReader(bytes);
ar->findOfscd();
if (ar->ofscd > -1) {
ar->filetable = ZipFileMap::allocate();
ar->addFiles();
return ar;
}
}
return 0;
}
ZipFile* ZipArchive::getFile(char* filename) {
ZipFile* res = filetable->lookup(filename);
return res;
}
void ZipArchive::remove() {}
#define END_CENTRAL_DIRECTORY_FILE_HEADER_SIZE 18
#define CENTRAL_DIRECTORY_FILE_HEADER_SIZE 42
#define LOCAL_FILE_HEADER_SIZE 26
#define C_FILENAME_LENGTH 24
#define C_UCSIZE 20
#define C_CSIZE 16
#define C_EXTRA_FIELD_LENGTH 26
#define C_FILE_COMMENT_LENGTH 28
#define C_ROLH 38
#define C_COMPRESSION_METHOD 6
#define L_FILENAME_LENGTH 22
#define L_EXTRA_FIELD_LENGTH 24
#define E_OFFSET_START_CENTRAL_DIRECTORY 12
#define HDR_ENDCENTRAL "PK\005\006"
#define HDR_CENTRAL "PK\001\002"
#define HDR_LOCAL "PK\003\004"
#define PATH_SEPARATOR '/'
#define ZIP_STORE 0
#define ZIP_DEFLATE 8
#define DEF_WBITS 15
static uint32 readEndianDep4(Reader* reader) {
uint8 one = reader->readU1();
uint8 two = reader->readU1();
uint8 three = reader->readU1();
uint8 four = reader->readU1();
return (one + (two << 8) + (three << 16) + (four << 24));
}
static uint16 readEndianDep2(Reader* reader) {
uint8 one = reader->readU1();
uint8 two = reader->readU1();
return (one + (two << 8));
}
void ZipArchive::findOfscd() {
sint32 curOffs = 0;
sint32 minOffs = 0;
sint32 st = END_CENTRAL_DIRECTORY_FILE_HEADER_SIZE + 4;
curOffs = reader->max;
if (curOffs >= (65535 + END_CENTRAL_DIRECTORY_FILE_HEADER_SIZE + 4)) {
minOffs = curOffs - (65535 + END_CENTRAL_DIRECTORY_FILE_HEADER_SIZE + 4);
} else {
minOffs = 0;
}
while (curOffs > minOffs) {
sint32 searchPos = 0;
if (curOffs >= (1024 - st)) {
curOffs = curOffs - (1024 - st);
} else {
curOffs = 0;
}
reader->cursor += curOffs;
sint32 diff = reader->max - reader->cursor;
sint32 temp = reader->cursor;
if (diff > 1024) {
searchPos = 1024;
reader->cursor += 1024;
} else {
searchPos = diff;
reader->cursor = reader->max;
}
if (searchPos >= st) {
sint32 searchPtr = temp + (searchPos - st);
while (searchPtr > temp) {
if (reader->bytes->elements[searchPtr] == 'P' && !(memcmp(&(reader->bytes->elements[searchPtr]), HDR_ENDCENTRAL, 4))) {
sint32 offset = searchPtr + 4 + E_OFFSET_START_CENTRAL_DIRECTORY;
reader->cursor = offset;
this->ofscd = readEndianDep4(reader);
return;
}
}
}
}
this->ofscd = -1;
}
void ZipArchive::addFiles() {
sint32 temp = ofscd;
reader->cursor = temp;
while (true) {
if (memcmp(&(reader->bytes->elements[temp]), HDR_CENTRAL, 4)) return;
ZipFile* ptr = gc_new(ZipFile)();
reader->cursor = temp + 4 + C_COMPRESSION_METHOD;
ptr->compressionMethod = readEndianDep2(reader);
reader->cursor = temp + 4 + C_CSIZE;
ptr->csize = readEndianDep4(reader);
ptr->ucsize = readEndianDep4(reader);
ptr->filenameLength = readEndianDep2(reader);
ptr->extraFieldLength = readEndianDep2(reader);
ptr->fileCommentLength = readEndianDep2(reader);
reader->cursor = temp + 4 + C_ROLH;
ptr->rolh = readEndianDep4(reader);
temp = temp + 4 + CENTRAL_DIRECTORY_FILE_HEADER_SIZE;
if ((ptr->filenameLength > 1024) || (reader->max - temp) < ptr->filenameLength)
return;
ptr->filename = (char*)malloc(ptr->filenameLength + 1);
memcpy(ptr->filename, &(reader->bytes->elements[temp]), ptr->filenameLength);
ptr->filename[ptr->filenameLength] = 0;
if (ptr->filename[ptr->filenameLength - 1] != PATH_SEPARATOR) {
filetable->hash(ptr->filename, ptr);
}
temp = temp + ptr->filenameLength + ptr->extraFieldLength + ptr->fileCommentLength;
}
}
sint32 ZipArchive::readFile(ArrayUInt8* array, const ZipFile* file) {
uint32 bytesLeft = 0;
uint32 filenameLength = 0;
uint32 extraFieldLength = 0;
char* ptr = (char*)array->elements;
uint32 temp = 0;
reader->cursor = file->rolh;
if (!(memcmp(&(reader->bytes->elements[file->rolh]), HDR_LOCAL, 4))) {
reader->cursor += 4;
temp = reader->cursor;
reader->cursor += L_FILENAME_LENGTH;
filenameLength = readEndianDep2(reader);
extraFieldLength = readEndianDep2(reader);
reader->cursor = temp + extraFieldLength + filenameLength + LOCAL_FILE_HEADER_SIZE;
if (file->compressionMethod == ZIP_STORE) {
memcpy(ptr, &(reader->bytes->elements[reader->cursor]), file->ucsize);
} else if (file->compressionMethod == ZIP_DEFLATE) {
z_stream stre;
sint32 err = 0;
bytesLeft = file->csize;
stre.next_out = (Bytef*)ptr;
stre.avail_out = file->ucsize;
stre.zalloc = 0;
stre.zfree = 0;
err = inflateInit2_(&stre, - DEF_WBITS, zlib_version, sizeof(z_stream));
if (err != Z_OK) {
return 0;
}
while (bytesLeft) {
uint32 size = 0;
stre.next_in = &(reader->bytes->elements[reader->cursor]);
if (bytesLeft > 1024) size = 1024;
else size = bytesLeft;
uint32 diff = reader->max - reader->cursor;
if (diff < size) {
stre.avail_in = diff;
reader->cursor = reader->max;
} else {
stre.avail_in = size;
reader->cursor += size;
}
if (bytesLeft > size) {
err = inflate(&stre, Z_PARTIAL_FLUSH);
} else {
err = inflate(&stre, Z_FINISH);
}
bytesLeft = bytesLeft - size;
}
inflateEnd(&stre);
if ((err != Z_STREAM_END) && (bytesLeft || err != Z_BUF_ERROR || stre.avail_out)) {
return 0;
} else {
return 1;
}
} else {
return 0;
}
} else {
return 0;
}
return 0;
}