177 lines
5.1 KiB
C++
177 lines
5.1 KiB
C++
#include <precomp.h>
|
|
#define REAL_STDIO
|
|
#include "zipread.h"
|
|
#include <zlib/unzip.h>
|
|
#include <bfc/parse/pathparse.h>
|
|
#include <api/skin/api_skin.h>
|
|
|
|
#define UNZIPBUFSIZE 65536
|
|
|
|
int ZipRead::open(const char *filename, int mode) {
|
|
unzFile f=NULL;
|
|
int success=0;
|
|
|
|
if (WASABI_API_SKIN == NULL) return 0;
|
|
PathParser pp1(WASABI_API_SKIN->getSkinsPath());
|
|
PathParser pp2(filename);
|
|
int v;
|
|
for (v=0;v<pp1.getNumStrings();v++)
|
|
if (!STRCASEEQLSAFE(pp1.enumString(v), pp2.enumString(v))) return 0;
|
|
String walName = pp2.enumString(v);
|
|
String file;
|
|
for (v=v+1;v<pp2.getNumStrings();v++) {
|
|
if (!file.isempty()) file.cat(DIRCHARSTR);
|
|
file += pp2.enumString(v);
|
|
}
|
|
|
|
// is there a zip file?
|
|
String zipName;
|
|
Std::fileInfoStruct zipFi;
|
|
if(!Std::getFileInfos(zipName=StringPrintf("%s%s.wal",WASABI_API_SKIN->getSkinsPath(),walName.getValue()),&zipFi) &&
|
|
!Std::getFileInfos(zipName=StringPrintf("%s%s.wsz",WASABI_API_SKIN->getSkinsPath(),walName.getValue()),&zipFi) &&
|
|
!Std::getFileInfos(zipName=StringPrintf("%s%s.zip",WASABI_API_SKIN->getSkinsPath(),walName.getValue()),&zipFi))
|
|
return 0; // zip not found
|
|
|
|
if(zipTmpDir.isempty()) {
|
|
char tmpPath[WA_MAX_PATH];
|
|
Std::getTempPath(sizeof(tmpPath)-1,tmpPath);
|
|
zipTmpDir=StringPrintf("%s_wa3sktmp",tmpPath);
|
|
Std::createDirectory(zipTmpDir);
|
|
}
|
|
|
|
// check in cached opened zip dirs
|
|
int badcrc=0;
|
|
for(int i=0;i<openedZipHandles.getNumItems();i++) {
|
|
if(!STRICMP(openedZipHandles[i].name->getValue(), walName)) {
|
|
if(!MEMCMP(&openedZipHandles[i].checksum,&zipFi,sizeof(zipFi))) {
|
|
// try to find it in the dezipped temp dir
|
|
handle=openInTempDir(walName,file);
|
|
if(handle) return 1;
|
|
else return 0;
|
|
} else {
|
|
// bad checksum
|
|
badcrc=1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// is the dezipped dir is here?
|
|
if(!badcrc) {
|
|
StringPrintf tmpf("%s%s%s%s_wa3chksum",zipTmpDir.getValue(),DIRCHARSTR,walName.getValue(),DIRCHARSTR);
|
|
FILE *fh=fopen(tmpf,"rb");
|
|
if(fh) {
|
|
Std::fileInfoStruct tmpFi={0,};
|
|
fread(&tmpFi,1,sizeof(tmpFi),fh);
|
|
fclose(fh);
|
|
if(!MEMCMP(&tmpFi,&zipFi,sizeof(tmpFi))) {
|
|
// checksum correct
|
|
openedZipEntry ze={new String(walName), new String(zipName)};
|
|
ze.checksum=tmpFi;
|
|
openedZipHandles.addItem(ze);
|
|
handle=openInTempDir(walName,file);
|
|
if(handle) return 1;
|
|
else return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// not found, so try to find it in a zip file
|
|
f = unzOpen(zipName);
|
|
if(!f) return 0;
|
|
|
|
StringPrintf zDir("%s%s%s",zipTmpDir.getValue(),DIRCHARSTR,walName.getValue());
|
|
Std::removeDirectory(zDir,1);
|
|
|
|
// unpack the zip in temp folder
|
|
String dirmask;
|
|
unzGoToFirstFile(f);
|
|
Std::createDirectory(zDir);
|
|
do {
|
|
char filename[MAX_PATH];
|
|
unzGetCurrentFileInfo(f,NULL,filename,sizeof(filename),NULL,0,NULL,0);
|
|
if (unzOpenCurrentFile(f) == UNZ_OK) {
|
|
int l;
|
|
dirmask.printf("%s%s%s",zDir.getValue(),DIRCHARSTR,filename);
|
|
if (Std::isDirChar(dirmask.lastChar())) {
|
|
// create dir
|
|
Std::createDirectory(dirmask);
|
|
} else {
|
|
// create file
|
|
FILE *fp = fopen(dirmask,"wb");
|
|
if(!fp) {
|
|
String dir=dirmask;
|
|
char *p=(char *)Std::filename(dir);
|
|
if(p) {
|
|
*p=0;
|
|
Std::createDirectory(dir);
|
|
fp = fopen(dirmask,"wb");
|
|
}
|
|
}
|
|
if (fp) {
|
|
do {
|
|
MemBlock<char> buf(UNZIPBUFSIZE);
|
|
l=unzReadCurrentFile(f,buf.getMemory(),buf.getSizeInBytes());
|
|
if (l > 0) fwrite(buf.getMemory(),1,l,fp);
|
|
} while (l > 0);
|
|
fclose(fp);
|
|
success=1;
|
|
}
|
|
}
|
|
if (unzCloseCurrentFile(f) == UNZ_CRCERROR) success=0;
|
|
}
|
|
} while (unzGoToNextFile(f) == UNZ_OK);
|
|
unzClose(f);
|
|
|
|
// write the checksum file
|
|
Std::fileInfoStruct fi;
|
|
Std::getFileInfos(zipName, &fi);
|
|
FILE *fh=fopen(StringPrintf("%s%s_wa3chksum",zDir.getValue(),DIRCHARSTR),"wt");
|
|
fwrite(&fi,1,sizeof(fi),fh);
|
|
fclose(fh);
|
|
|
|
openedZipEntry ze={new String(walName), new String(zipName)};
|
|
ze.checksum=fi;
|
|
openedZipHandles.addItem(ze);
|
|
|
|
// try to find it (again) in the dezipped temp dir
|
|
handle=openInTempDir(walName,file);
|
|
if(handle) return 1;
|
|
return 0;
|
|
}
|
|
|
|
FILE *ZipRead::openInTempDir(const char *walName, const char *file) {
|
|
StringPrintf tmpf("%s%s%s%s%s",zipTmpDir.getValue(),DIRCHARSTR,walName,DIRCHARSTR,file);
|
|
FILE *fh=fopen(tmpf,"rb");
|
|
if(fh) return fh;
|
|
// okay maybe the file isn't in the root dir of the zip file
|
|
fh=fopen(StringPrintf("%s%s%s%s%s%s%s",zipTmpDir.getValue(),DIRCHARSTR,walName,DIRCHARSTR,walName,DIRCHARSTR,file),"rb");
|
|
if(fh) return fh;
|
|
// definitely not here
|
|
return 0;
|
|
}
|
|
|
|
void ZipRead::close() {
|
|
fclose(handle);
|
|
}
|
|
|
|
int ZipRead::read(char *buffer, int size) {
|
|
return fread(buffer,1,size,handle);
|
|
}
|
|
|
|
int ZipRead::getPos() {
|
|
return ftell(handle);
|
|
}
|
|
|
|
int ZipRead::getLength() {
|
|
int pos=ftell(handle);
|
|
fseek(handle,0,SEEK_END);
|
|
int length=ftell(handle);
|
|
fseek(handle,pos,SEEK_SET);
|
|
return length;
|
|
}
|
|
|
|
using namespace wasabi;
|
|
|
|
TList<ZipRead::openedZipEntry> ZipRead::openedZipHandles;;
|