winamp/Src/Wasabi/api/filereader/zip/zipread.cpp
2024-09-24 14:54:57 +02:00

176 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;;