Mercurial > vba-clojure
diff src/win32/7zip/7zip.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/win32/7zip/7zip.cpp Sat Mar 03 10:31:27 2012 -0600 1.3 @@ -0,0 +1,392 @@ 1.4 +#include "7zip.h" 1.5 + 1.6 +#include "7z/C/Types.h" 1.7 +#include "7z/CPP/7zip/Archive/IArchive.h" 1.8 +#include "7z/CPP/Common/InitializeStaticLib.h" // important! (if using a static lib) 1.9 + 1.10 +#include <string> 1.11 +#include <vector> 1.12 +#include <cassert> 1.13 +#include <malloc.h> 1.14 + 1.15 +#include "7zipstreams.h" // defines OutStream and InFileStream 1.16 + 1.17 +STDAPI GetNumberOfFormats(UINT32 *numFormats); 1.18 +STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value); 1.19 +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); 1.20 + 1.21 +struct ArchiveFormatInfo 1.22 +{ 1.23 + std::string name; 1.24 + std::vector<std::string> extensions; 1.25 + std::string signature; 1.26 + GUID guid; 1.27 +}; 1.28 + 1.29 +static std::vector<ArchiveFormatInfo> s_formatInfos; 1.30 + 1.31 +static std::string wstrToStr(const wchar_t* wstr) 1.32 +{ 1.33 +/* 1.34 + // This thing wouldn't work 1.35 + char* str = (char*)_alloca((wcslen(wstr)+1)); 1.36 + sprintf(str, "%S", wstr); 1.37 + return std::string(str); 1.38 +*/ 1.39 +// setlocale(LC_CTYPE, ".ACP"); 1.40 + size_t n = wcstombs(NULL, wstr, 0); 1.41 + if (n == (size_t)-1) // failed 1.42 + { 1.43 +// setlocale(LC_CTYPE, "C"); 1.44 + return std::string(); 1.45 + } 1.46 + char* str = (char*)_alloca(n + 1); 1.47 + wcstombs(str, wstr, n); 1.48 + str[n] = '\0'; 1.49 +// setlocale(LC_CTYPE, "C"); 1.50 + return std::string(str); 1.51 +} 1.52 + 1.53 +static std::vector<std::string> tokenize(const std::string & str, const std::string & delim) 1.54 +{ 1.55 + std::vector<std::string> tokens; 1.56 + size_t p0 = 0, p1 = std::string::npos; 1.57 + while(p0 != std::string::npos) 1.58 + { 1.59 + p1 = str.find_first_of(delim, p0); 1.60 + if(p1 != p0) 1.61 + { 1.62 + std::string token = str.substr(p0, p1 - p0); 1.63 + tokens.push_back(token); 1.64 + } 1.65 + p0 = str.find_first_not_of(delim, p1); 1.66 + } 1.67 + return tokens; 1.68 +} 1.69 + 1.70 +static std::string s_supportedFormatsFilter; 1.71 +const char* GetSupportedFormatsFilter() 1.72 +{ 1.73 + assert(!s_formatInfos.empty()); 1.74 + if(s_supportedFormatsFilter.empty()) 1.75 + { 1.76 + s_supportedFormatsFilter = ""; 1.77 + for(size_t i = 0; i < s_formatInfos.size(); i++) 1.78 + { 1.79 + for(size_t j = 0; j < s_formatInfos[i].extensions.size(); j++) 1.80 + { 1.81 + s_supportedFormatsFilter += ";*."; 1.82 + s_supportedFormatsFilter += s_formatInfos[i].extensions[j]; 1.83 + } 1.84 + } 1.85 + } 1.86 + return s_supportedFormatsFilter.c_str(); 1.87 +} 1.88 + 1.89 +void InitDecoder() 1.90 +{ 1.91 + CleanupDecoder(); 1.92 + 1.93 + UINT32 numFormats = 0; 1.94 + GetNumberOfFormats(&numFormats); 1.95 + 1.96 + for(unsigned int i = 0; i < numFormats; i++) 1.97 + { 1.98 + PROPVARIANT var = {VT_EMPTY}; 1.99 + ArchiveFormatInfo info; 1.100 + 1.101 + GetHandlerProperty2(i, NArchive::kName, &var); 1.102 + if(var.vt == VT_BSTR) 1.103 + info.name = wstrToStr(var.bstrVal); 1.104 + 1.105 + GetHandlerProperty2(i, NArchive::kExtension, &var); 1.106 + if(var.vt == VT_BSTR) 1.107 + info.extensions = tokenize(wstrToStr(var.bstrVal), " "); 1.108 + 1.109 + GetHandlerProperty2(i, NArchive::kStartSignature, &var); 1.110 + if(var.vt == VT_BSTR) 1.111 + info.signature = (const char*)var.bstrVal; // note: there's no 100% correct way of doing this with the existing 7-zip interface, but this is much better than using SysStringLen() in any way (it would return 1 for the signature "BZh", for example) 1.112 + 1.113 + GetHandlerProperty2(i,NArchive::kClassID,&var); 1.114 + if(var.vt == VT_BSTR) 1.115 + memcpy(&info.guid, var.bstrVal, 16); 1.116 + else 1.117 + memset(&info.guid, 0, 16); 1.118 + 1.119 + s_formatInfos.push_back(info); 1.120 + 1.121 + VariantClear((VARIANTARG*)&var); 1.122 + } 1.123 +} 1.124 + 1.125 +void CleanupDecoder() 1.126 +{ 1.127 + s_formatInfos.clear(); 1.128 + s_supportedFormatsFilter.clear(); 1.129 +} 1.130 + 1.131 +#include "7z/CPP/7zip/Archive/Zip/ZipHandler.h" 1.132 + 1.133 + 1.134 +ArchiveFile::ArchiveFile(const char* filename, const char* displayFilename) 1.135 +{ 1.136 + assert(!s_formatInfos.empty()); 1.137 + 1.138 + m_typeIndex = -1; 1.139 + m_numItems = 0; 1.140 + m_items = NULL; 1.141 + m_filename = NULL; 1.142 + m_displayFilename = NULL; 1.143 + m_userMadeSelection = false; 1.144 + 1.145 + FILE* file = fopen(filename, "rb"); 1.146 + if(!file) 1.147 + return; 1.148 + 1.149 + m_filename = new char[strlen(filename)+1]; 1.150 + strcpy(m_filename, filename); 1.151 + 1.152 + if(displayFilename) 1.153 + { 1.154 + m_displayFilename = new char[strlen(displayFilename)+1]; 1.155 + strcpy(m_displayFilename, displayFilename); 1.156 + } 1.157 + 1.158 + // detect archive type using format signature in file 1.159 + for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++) 1.160 + { 1.161 + fseek(file, 0, SEEK_SET); 1.162 + 1.163 + std::string& formatSig = s_formatInfos[i].signature; 1.164 + int len = formatSig.size(); 1.165 + 1.166 + if(len == 0) 1.167 + continue; // because some formats have no signature 1.168 + 1.169 + char* fileSig = (char*)_alloca(len); 1.170 + fread(fileSig, 1, len, file); 1.171 + 1.172 + if(!memcmp(formatSig.c_str(), fileSig, len)) 1.173 + m_typeIndex = i; 1.174 + } 1.175 + 1.176 + // if no signature match has been found, detect archive type using filename. 1.177 + // this is only for signature-less formats 1.178 + const char* fileExt = strrchr(filename, '.'); 1.179 + if(fileExt++) 1.180 + { 1.181 + for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++) 1.182 + { 1.183 + if(s_formatInfos[i].signature.empty()) 1.184 + { 1.185 + std::vector<std::string>& formatExts = s_formatInfos[i].extensions; 1.186 + for(size_t j = 0; j < formatExts.size(); j++) 1.187 + { 1.188 + if(!_stricmp(formatExts[j].c_str(), fileExt)) 1.189 + { 1.190 + m_typeIndex = i; 1.191 + break; 1.192 + } 1.193 + } 1.194 + } 1.195 + } 1.196 + } 1.197 + 1.198 + if(m_typeIndex < 0) 1.199 + { 1.200 + // uncompressed 1.201 + 1.202 + m_numItems = 1; 1.203 + m_items = new ArchiveItem[m_numItems]; 1.204 + 1.205 + fseek(file, 0, SEEK_END); 1.206 + m_items[0].size = ftell(file); 1.207 + 1.208 + m_items[0].name = new char[strlen(filename)+1]; 1.209 + strcpy(m_items[0].name, filename); 1.210 + } 1.211 + else 1.212 + { 1.213 + IInArchive* object = NULL; 1.214 + if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object))) 1.215 + { 1.216 + InFileStream* ifs = new InFileStream(filename); 1.217 + if(SUCCEEDED(object->Open(ifs,0,0))) 1.218 + { 1.219 + UInt32 numItems = 0; 1.220 + object->GetNumberOfItems(&numItems); 1.221 + m_numItems = numItems; 1.222 + m_items = new ArchiveItem[m_numItems]; 1.223 + 1.224 + for(int i = 0; i < m_numItems; i++) 1.225 + { 1.226 + PROPVARIANT var = {VT_EMPTY}; 1.227 + ArchiveItem& item = m_items[i]; 1.228 + 1.229 + object->GetProperty(i, kpidSize, &var); 1.230 + item.size = var.uhVal.LowPart; 1.231 + 1.232 + object->GetProperty(i, kpidPath, &var); 1.233 + std::string& path = wstrToStr(var.bstrVal); 1.234 + item.name = new char[path.size()+1]; 1.235 + strcpy(item.name, path.c_str()); 1.236 + 1.237 + //object->GetProperty(i, kpidMethod, &var); 1.238 + //std::string& method = wstrToStr(var.bstrVal); 1.239 + //item.method = new char[method.size()+1]; 1.240 + //strcpy(item.method, method.c_str()); 1.241 + 1.242 + object->GetProperty(i, kpidEncrypted, &var); 1.243 +#ifdef _NO_CRYPTO 1.244 + if(var.boolVal) 1.245 + item.size = 0; // don't support decompressing it, pretend size zero 1.246 +#else 1.247 + #error password support NYI... see client7z.cpp 1.248 + item.encrypted = !!var.boolVal; 1.249 +#endif 1.250 + 1.251 + VariantClear((VARIANTARG*)&var); 1.252 + } 1.253 + 1.254 + object->Close(); 1.255 + } 1.256 + 1.257 + object->Release(); 1.258 + } 1.259 + } 1.260 + 1.261 + fclose(file); 1.262 +} 1.263 + 1.264 +ArchiveFile::~ArchiveFile() 1.265 +{ 1.266 + for(int i = 0; i < m_numItems; i++) 1.267 + { 1.268 + delete[] m_items[i].name; 1.269 + } 1.270 + delete[] m_items; 1.271 + delete[] m_filename; 1.272 + delete[] m_displayFilename; 1.273 +} 1.274 + 1.275 +const char* ArchiveFile::GetArchiveTypeName() 1.276 +{ 1.277 + assert(!s_formatInfos.empty()); 1.278 + 1.279 + if((size_t)m_typeIndex >= s_formatInfos.size()) 1.280 + return ""; 1.281 + 1.282 + return s_formatInfos[m_typeIndex].name.c_str(); 1.283 +} 1.284 + 1.285 +int ArchiveFile::GetNumItems() 1.286 +{ 1.287 + return m_numItems; 1.288 +} 1.289 + 1.290 +int ArchiveFile::GetItemSize(int item) 1.291 +{ 1.292 + assert(item >= 0 && item < m_numItems); 1.293 + if(!(item >= 0 && item < m_numItems)) return 0; 1.294 + return m_items[item].size; 1.295 +} 1.296 + 1.297 +const char* ArchiveFile::GetItemName(int item) 1.298 +{ 1.299 + //assert(item >= 0 && item < m_numItems); 1.300 + if(!(item >= 0 && item < m_numItems)) return ""; 1.301 + return m_items[item].name; 1.302 +} 1.303 + 1.304 +bool ArchiveFile::IsCompressed() 1.305 +{ 1.306 + return (m_typeIndex >= 0); 1.307 +} 1.308 + 1.309 +int ArchiveFile::ExtractItem(int index, unsigned char* outBuffer, int bufSize) const 1.310 +{ 1.311 + assert(!s_formatInfos.empty()); 1.312 + //assert(index >= 0 && index < m_numItems); 1.313 + if(!(index >= 0 && index < m_numItems)) return 0; 1.314 + 1.315 + ArchiveItem& item = m_items[index]; 1.316 + 1.317 + if(bufSize < item.size) 1.318 + return 0; 1.319 + 1.320 + if(m_typeIndex < 0) 1.321 + { 1.322 + // uncompressed 1.323 + FILE* file = fopen(m_filename, "rb"); 1.324 + fread(outBuffer, 1, item.size, file); 1.325 + fclose(file); 1.326 + } 1.327 + else 1.328 + { 1.329 + IInArchive* object = NULL; 1.330 + HRESULT hr = E_FAIL; 1.331 + if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object))) 1.332 + { 1.333 + InFileStream* ifs = new InFileStream(m_filename); 1.334 + if(SUCCEEDED(object->Open(ifs,0,0))) 1.335 + { 1.336 + OutStream* os = new OutStream(index, outBuffer, item.size); 1.337 + const UInt32 indices [1] = {index}; 1.338 + hr = object->Extract(indices, 1, 0, os); 1.339 + object->Close(); 1.340 + } 1.341 + object->Release(); 1.342 + } 1.343 + if(FAILED(hr)) 1.344 + return 0; 1.345 + } 1.346 + 1.347 + return item.size; 1.348 +} 1.349 + 1.350 + 1.351 + 1.352 +int ArchiveFile::ExtractItem(int index, const char* outFilename) const 1.353 +{ 1.354 + assert(!s_formatInfos.empty()); 1.355 + //assert(index >= 0 && index < m_numItems); 1.356 + if(!(index >= 0 && index < m_numItems)) return 0; 1.357 + 1.358 + ArchiveItem& item = m_items[index]; 1.359 + int rv = item.size; 1.360 + 1.361 + DWORD outAttributes = GetFileAttributes(outFilename); 1.362 + if(outAttributes & FILE_ATTRIBUTE_READONLY) 1.363 + SetFileAttributes(outFilename, outAttributes & ~FILE_ATTRIBUTE_READONLY); // temporarily remove read-only attribute so we can decompress to there 1.364 + 1.365 + if(m_typeIndex < 0) 1.366 + { 1.367 + // uncompressed 1.368 + if(!CopyFile(m_filename, outFilename, false)) 1.369 + rv = 0; 1.370 + } 1.371 + else 1.372 + { 1.373 + IInArchive* object = NULL; 1.374 + HRESULT hr = E_FAIL; 1.375 + if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object))) 1.376 + { 1.377 + InFileStream* ifs = new InFileStream(m_filename); 1.378 + if(SUCCEEDED(object->Open(ifs,0,0))) 1.379 + { 1.380 + OutStream* os = new OutStream(index, outFilename); 1.381 + const UInt32 indices [1] = {index}; 1.382 + hr = object->Extract(indices, 1, 0, os); 1.383 + object->Close(); 1.384 + } 1.385 + object->Release(); 1.386 + } 1.387 + if(FAILED(hr)) 1.388 + rv = 0; 1.389 + } 1.390 + 1.391 + if(outAttributes & FILE_ATTRIBUTE_READONLY) 1.392 + SetFileAttributes(outFilename, outAttributes); // restore read-only attribute 1.393 + 1.394 + return rv; 1.395 +}