123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- #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;;
|