1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
#include "StdAfx.h"
#include "ArchiveZip.h"
#include <algorithm>
#include <stdexcept>
#include "Util.h"
#include "mmgr.h"
#include "LogOutput.h"
CArchiveZip::CArchiveZip(const std::string& name):
CArchiveBuffered(name),
curSearchHandle(1)
{
#ifdef USEWIN32IOAPI
zlib_filefunc_def ffunc;
fill_win32_filefunc(&ffunc);
zip = unzOpen2(name.c_str(),&ffunc);
#else
zip = unzOpen(name.c_str());
#endif
if (!zip) {
LogObject() << "Error opening " << name;
return;
}
// We need to map file positions to speed up opening later
for (int ret = unzGoToFirstFile(zip); ret == UNZ_OK; ret = unzGoToNextFile(zip)) {
unz_file_info info;
char fname[512];
unzGetCurrentFileInfo(zip, &info, fname, 512, NULL, 0, NULL, 0);
const std::string name = StringToLower(fname);
if (name.empty()) {
continue;
}
const char last = name[name.length() - 1];
if ((last == '/') || (last == '\\')) {
continue; // exclude directory names
}
FileData fd;
unzGetFilePos(zip, &fd.fp);
fd.size = info.uncompressed_size;
fd.origName = fname;
fd.crc = info.crc;
fileData[name] = fd;
}
}
CArchiveZip::~CArchiveZip(void)
{
if (zip)
unzClose(zip);
}
unsigned int CArchiveZip::GetCrc32 (const std::string& fileName)
{
std::string lower = StringToLower(fileName);
FileData fd = fileData[lower];
return fd.crc;
}
bool CArchiveZip::IsOpen()
{
return (zip != NULL);
}
class zip_exception: public std::exception {};
// To simplify things, files are always read completely into memory from the zipfile, since zlib does not
// provide any way of reading more than one file at a time
ABOpenFile_t* CArchiveZip::GetEntireFileImpl(const std::string& fName)
{
// Don't allow opening files on missing/invalid archives
if (!zip)
return NULL;
std::string fileName = StringToLower(fName);
//if (unzLocateFile(zip, fileName.c_str(), 2) != UNZ_OK)
// return 0;
if (fileData.find(fileName) == fileData.end())
return NULL;
FileData fd = fileData[fileName];
unzGoToFilePos(zip, &fileData[fileName].fp);
unz_file_info fi;
unzGetCurrentFileInfo(zip, &fi, NULL, 0, NULL, 0, NULL, 0);
ABOpenFile_t* of = new ABOpenFile_t;
of->pos = 0;
of->size = fi.uncompressed_size;
of->data = (char*)malloc(of->size);
// If anything fails, we abort
try {
if (unzOpenCurrentFile(zip) != UNZ_OK)
throw zip_exception();
if (unzReadCurrentFile(zip, of->data, of->size) < 0)
throw zip_exception();
if (unzCloseCurrentFile(zip) == UNZ_CRCERROR)
throw zip_exception();
}
catch (zip_exception) {
free(of->data);
delete of;
return NULL;
}
return of;
}
int CArchiveZip::FindFiles(int cur, std::string* name, int* size)
{
if (cur == 0) {
curSearchHandle++;
cur = curSearchHandle;
searchHandles[cur] = fileData.begin();
}
if (searchHandles.find(cur) == searchHandles.end())
throw std::runtime_error("Unregistered handle. Pass a handle returned by CArchiveZip::FindFiles.");
if (searchHandles[cur] == fileData.end()) {
searchHandles.erase(cur);
return 0;
}
*name = searchHandles[cur]->second.origName;
*size = searchHandles[cur]->second.size;
searchHandles[cur]++;
return cur;
}
void CArchiveZip::SetSlashesForwardToBack(std::string& name)
{
for (unsigned int i = 0; i < name.length(); ++i) {
if (name[i] == '/')
name[i] = '\\';
}
}
void CArchiveZip::SetSlashesBackToForward(std::string& name)
{
for (unsigned int i = 0; i < name.length(); ++i) {
if (name[i] == '\\')
name[i] = '/';
}
}
|