Mercurial > vba-clojure
view 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 source
1 #include "7zip.h"3 #include "7z/C/Types.h"4 #include "7z/CPP/7zip/Archive/IArchive.h"5 #include "7z/CPP/Common/InitializeStaticLib.h" // important! (if using a static lib)7 #include <string>8 #include <vector>9 #include <cassert>10 #include <malloc.h>12 #include "7zipstreams.h" // defines OutStream and InFileStream14 STDAPI GetNumberOfFormats(UINT32 *numFormats);15 STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value);16 STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject);18 struct ArchiveFormatInfo19 {20 std::string name;21 std::vector<std::string> extensions;22 std::string signature;23 GUID guid;24 };26 static std::vector<ArchiveFormatInfo> s_formatInfos;28 static std::string wstrToStr(const wchar_t* wstr)29 {30 /*31 // This thing wouldn't work32 char* str = (char*)_alloca((wcslen(wstr)+1));33 sprintf(str, "%S", wstr);34 return std::string(str);35 */36 // setlocale(LC_CTYPE, ".ACP");37 size_t n = wcstombs(NULL, wstr, 0);38 if (n == (size_t)-1) // failed39 {40 // setlocale(LC_CTYPE, "C");41 return std::string();42 }43 char* str = (char*)_alloca(n + 1);44 wcstombs(str, wstr, n);45 str[n] = '\0';46 // setlocale(LC_CTYPE, "C");47 return std::string(str);48 }50 static std::vector<std::string> tokenize(const std::string & str, const std::string & delim)51 {52 std::vector<std::string> tokens;53 size_t p0 = 0, p1 = std::string::npos;54 while(p0 != std::string::npos)55 {56 p1 = str.find_first_of(delim, p0);57 if(p1 != p0)58 {59 std::string token = str.substr(p0, p1 - p0);60 tokens.push_back(token);61 }62 p0 = str.find_first_not_of(delim, p1);63 }64 return tokens;65 }67 static std::string s_supportedFormatsFilter;68 const char* GetSupportedFormatsFilter()69 {70 assert(!s_formatInfos.empty());71 if(s_supportedFormatsFilter.empty())72 {73 s_supportedFormatsFilter = "";74 for(size_t i = 0; i < s_formatInfos.size(); i++)75 {76 for(size_t j = 0; j < s_formatInfos[i].extensions.size(); j++)77 {78 s_supportedFormatsFilter += ";*.";79 s_supportedFormatsFilter += s_formatInfos[i].extensions[j];80 }81 }82 }83 return s_supportedFormatsFilter.c_str();84 }86 void InitDecoder()87 {88 CleanupDecoder();90 UINT32 numFormats = 0;91 GetNumberOfFormats(&numFormats);93 for(unsigned int i = 0; i < numFormats; i++)94 {95 PROPVARIANT var = {VT_EMPTY};96 ArchiveFormatInfo info;98 GetHandlerProperty2(i, NArchive::kName, &var);99 if(var.vt == VT_BSTR)100 info.name = wstrToStr(var.bstrVal);102 GetHandlerProperty2(i, NArchive::kExtension, &var);103 if(var.vt == VT_BSTR)104 info.extensions = tokenize(wstrToStr(var.bstrVal), " ");106 GetHandlerProperty2(i, NArchive::kStartSignature, &var);107 if(var.vt == VT_BSTR)108 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)110 GetHandlerProperty2(i,NArchive::kClassID,&var);111 if(var.vt == VT_BSTR)112 memcpy(&info.guid, var.bstrVal, 16);113 else114 memset(&info.guid, 0, 16);116 s_formatInfos.push_back(info);118 VariantClear((VARIANTARG*)&var);119 }120 }122 void CleanupDecoder()123 {124 s_formatInfos.clear();125 s_supportedFormatsFilter.clear();126 }128 #include "7z/CPP/7zip/Archive/Zip/ZipHandler.h"131 ArchiveFile::ArchiveFile(const char* filename, const char* displayFilename)132 {133 assert(!s_formatInfos.empty());135 m_typeIndex = -1;136 m_numItems = 0;137 m_items = NULL;138 m_filename = NULL;139 m_displayFilename = NULL;140 m_userMadeSelection = false;142 FILE* file = fopen(filename, "rb");143 if(!file)144 return;146 m_filename = new char[strlen(filename)+1];147 strcpy(m_filename, filename);149 if(displayFilename)150 {151 m_displayFilename = new char[strlen(displayFilename)+1];152 strcpy(m_displayFilename, displayFilename);153 }155 // detect archive type using format signature in file156 for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++)157 {158 fseek(file, 0, SEEK_SET);160 std::string& formatSig = s_formatInfos[i].signature;161 int len = formatSig.size();163 if(len == 0)164 continue; // because some formats have no signature166 char* fileSig = (char*)_alloca(len);167 fread(fileSig, 1, len, file);169 if(!memcmp(formatSig.c_str(), fileSig, len))170 m_typeIndex = i;171 }173 // if no signature match has been found, detect archive type using filename.174 // this is only for signature-less formats175 const char* fileExt = strrchr(filename, '.');176 if(fileExt++)177 {178 for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++)179 {180 if(s_formatInfos[i].signature.empty())181 {182 std::vector<std::string>& formatExts = s_formatInfos[i].extensions;183 for(size_t j = 0; j < formatExts.size(); j++)184 {185 if(!_stricmp(formatExts[j].c_str(), fileExt))186 {187 m_typeIndex = i;188 break;189 }190 }191 }192 }193 }195 if(m_typeIndex < 0)196 {197 // uncompressed199 m_numItems = 1;200 m_items = new ArchiveItem[m_numItems];202 fseek(file, 0, SEEK_END);203 m_items[0].size = ftell(file);205 m_items[0].name = new char[strlen(filename)+1];206 strcpy(m_items[0].name, filename);207 }208 else209 {210 IInArchive* object = NULL;211 if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object)))212 {213 InFileStream* ifs = new InFileStream(filename);214 if(SUCCEEDED(object->Open(ifs,0,0)))215 {216 UInt32 numItems = 0;217 object->GetNumberOfItems(&numItems);218 m_numItems = numItems;219 m_items = new ArchiveItem[m_numItems];221 for(int i = 0; i < m_numItems; i++)222 {223 PROPVARIANT var = {VT_EMPTY};224 ArchiveItem& item = m_items[i];226 object->GetProperty(i, kpidSize, &var);227 item.size = var.uhVal.LowPart;229 object->GetProperty(i, kpidPath, &var);230 std::string& path = wstrToStr(var.bstrVal);231 item.name = new char[path.size()+1];232 strcpy(item.name, path.c_str());234 //object->GetProperty(i, kpidMethod, &var);235 //std::string& method = wstrToStr(var.bstrVal);236 //item.method = new char[method.size()+1];237 //strcpy(item.method, method.c_str());239 object->GetProperty(i, kpidEncrypted, &var);240 #ifdef _NO_CRYPTO241 if(var.boolVal)242 item.size = 0; // don't support decompressing it, pretend size zero243 #else244 #error password support NYI... see client7z.cpp245 item.encrypted = !!var.boolVal;246 #endif248 VariantClear((VARIANTARG*)&var);249 }251 object->Close();252 }254 object->Release();255 }256 }258 fclose(file);259 }261 ArchiveFile::~ArchiveFile()262 {263 for(int i = 0; i < m_numItems; i++)264 {265 delete[] m_items[i].name;266 }267 delete[] m_items;268 delete[] m_filename;269 delete[] m_displayFilename;270 }272 const char* ArchiveFile::GetArchiveTypeName()273 {274 assert(!s_formatInfos.empty());276 if((size_t)m_typeIndex >= s_formatInfos.size())277 return "";279 return s_formatInfos[m_typeIndex].name.c_str();280 }282 int ArchiveFile::GetNumItems()283 {284 return m_numItems;285 }287 int ArchiveFile::GetItemSize(int item)288 {289 assert(item >= 0 && item < m_numItems);290 if(!(item >= 0 && item < m_numItems)) return 0;291 return m_items[item].size;292 }294 const char* ArchiveFile::GetItemName(int item)295 {296 //assert(item >= 0 && item < m_numItems);297 if(!(item >= 0 && item < m_numItems)) return "";298 return m_items[item].name;299 }301 bool ArchiveFile::IsCompressed()302 {303 return (m_typeIndex >= 0);304 }306 int ArchiveFile::ExtractItem(int index, unsigned char* outBuffer, int bufSize) const307 {308 assert(!s_formatInfos.empty());309 //assert(index >= 0 && index < m_numItems);310 if(!(index >= 0 && index < m_numItems)) return 0;312 ArchiveItem& item = m_items[index];314 if(bufSize < item.size)315 return 0;317 if(m_typeIndex < 0)318 {319 // uncompressed320 FILE* file = fopen(m_filename, "rb");321 fread(outBuffer, 1, item.size, file);322 fclose(file);323 }324 else325 {326 IInArchive* object = NULL;327 HRESULT hr = E_FAIL;328 if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object)))329 {330 InFileStream* ifs = new InFileStream(m_filename);331 if(SUCCEEDED(object->Open(ifs,0,0)))332 {333 OutStream* os = new OutStream(index, outBuffer, item.size);334 const UInt32 indices [1] = {index};335 hr = object->Extract(indices, 1, 0, os);336 object->Close();337 }338 object->Release();339 }340 if(FAILED(hr))341 return 0;342 }344 return item.size;345 }349 int ArchiveFile::ExtractItem(int index, const char* outFilename) const350 {351 assert(!s_formatInfos.empty());352 //assert(index >= 0 && index < m_numItems);353 if(!(index >= 0 && index < m_numItems)) return 0;355 ArchiveItem& item = m_items[index];356 int rv = item.size;358 DWORD outAttributes = GetFileAttributes(outFilename);359 if(outAttributes & FILE_ATTRIBUTE_READONLY)360 SetFileAttributes(outFilename, outAttributes & ~FILE_ATTRIBUTE_READONLY); // temporarily remove read-only attribute so we can decompress to there362 if(m_typeIndex < 0)363 {364 // uncompressed365 if(!CopyFile(m_filename, outFilename, false))366 rv = 0;367 }368 else369 {370 IInArchive* object = NULL;371 HRESULT hr = E_FAIL;372 if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object)))373 {374 InFileStream* ifs = new InFileStream(m_filename);375 if(SUCCEEDED(object->Open(ifs,0,0)))376 {377 OutStream* os = new OutStream(index, outFilename);378 const UInt32 indices [1] = {index};379 hr = object->Extract(indices, 1, 0, os);380 object->Close();381 }382 object->Release();383 }384 if(FAILED(hr))385 rv = 0;386 }388 if(outAttributes & FILE_ATTRIBUTE_READONLY)389 SetFileAttributes(outFilename, outAttributes); // restore read-only attribute391 return rv;392 }