annotate src/win32/7zip/7zip.cpp @ 5:8fe0c57e53d2

concentrating on lua first
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:39:40 -0600
parents f9f4f1b99eed
children
rev   line source
rlm@1 1 #include "7zip.h"
rlm@1 2
rlm@1 3 #include "7z/C/Types.h"
rlm@1 4 #include "7z/CPP/7zip/Archive/IArchive.h"
rlm@1 5 #include "7z/CPP/Common/InitializeStaticLib.h" // important! (if using a static lib)
rlm@1 6
rlm@1 7 #include <string>
rlm@1 8 #include <vector>
rlm@1 9 #include <cassert>
rlm@1 10 #include <malloc.h>
rlm@1 11
rlm@1 12 #include "7zipstreams.h" // defines OutStream and InFileStream
rlm@1 13
rlm@1 14 STDAPI GetNumberOfFormats(UINT32 *numFormats);
rlm@1 15 STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value);
rlm@1 16 STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject);
rlm@1 17
rlm@1 18 struct ArchiveFormatInfo
rlm@1 19 {
rlm@1 20 std::string name;
rlm@1 21 std::vector<std::string> extensions;
rlm@1 22 std::string signature;
rlm@1 23 GUID guid;
rlm@1 24 };
rlm@1 25
rlm@1 26 static std::vector<ArchiveFormatInfo> s_formatInfos;
rlm@1 27
rlm@1 28 static std::string wstrToStr(const wchar_t* wstr)
rlm@1 29 {
rlm@1 30 /*
rlm@1 31 // This thing wouldn't work
rlm@1 32 char* str = (char*)_alloca((wcslen(wstr)+1));
rlm@1 33 sprintf(str, "%S", wstr);
rlm@1 34 return std::string(str);
rlm@1 35 */
rlm@1 36 // setlocale(LC_CTYPE, ".ACP");
rlm@1 37 size_t n = wcstombs(NULL, wstr, 0);
rlm@1 38 if (n == (size_t)-1) // failed
rlm@1 39 {
rlm@1 40 // setlocale(LC_CTYPE, "C");
rlm@1 41 return std::string();
rlm@1 42 }
rlm@1 43 char* str = (char*)_alloca(n + 1);
rlm@1 44 wcstombs(str, wstr, n);
rlm@1 45 str[n] = '\0';
rlm@1 46 // setlocale(LC_CTYPE, "C");
rlm@1 47 return std::string(str);
rlm@1 48 }
rlm@1 49
rlm@1 50 static std::vector<std::string> tokenize(const std::string & str, const std::string & delim)
rlm@1 51 {
rlm@1 52 std::vector<std::string> tokens;
rlm@1 53 size_t p0 = 0, p1 = std::string::npos;
rlm@1 54 while(p0 != std::string::npos)
rlm@1 55 {
rlm@1 56 p1 = str.find_first_of(delim, p0);
rlm@1 57 if(p1 != p0)
rlm@1 58 {
rlm@1 59 std::string token = str.substr(p0, p1 - p0);
rlm@1 60 tokens.push_back(token);
rlm@1 61 }
rlm@1 62 p0 = str.find_first_not_of(delim, p1);
rlm@1 63 }
rlm@1 64 return tokens;
rlm@1 65 }
rlm@1 66
rlm@1 67 static std::string s_supportedFormatsFilter;
rlm@1 68 const char* GetSupportedFormatsFilter()
rlm@1 69 {
rlm@1 70 assert(!s_formatInfos.empty());
rlm@1 71 if(s_supportedFormatsFilter.empty())
rlm@1 72 {
rlm@1 73 s_supportedFormatsFilter = "";
rlm@1 74 for(size_t i = 0; i < s_formatInfos.size(); i++)
rlm@1 75 {
rlm@1 76 for(size_t j = 0; j < s_formatInfos[i].extensions.size(); j++)
rlm@1 77 {
rlm@1 78 s_supportedFormatsFilter += ";*.";
rlm@1 79 s_supportedFormatsFilter += s_formatInfos[i].extensions[j];
rlm@1 80 }
rlm@1 81 }
rlm@1 82 }
rlm@1 83 return s_supportedFormatsFilter.c_str();
rlm@1 84 }
rlm@1 85
rlm@1 86 void InitDecoder()
rlm@1 87 {
rlm@1 88 CleanupDecoder();
rlm@1 89
rlm@1 90 UINT32 numFormats = 0;
rlm@1 91 GetNumberOfFormats(&numFormats);
rlm@1 92
rlm@1 93 for(unsigned int i = 0; i < numFormats; i++)
rlm@1 94 {
rlm@1 95 PROPVARIANT var = {VT_EMPTY};
rlm@1 96 ArchiveFormatInfo info;
rlm@1 97
rlm@1 98 GetHandlerProperty2(i, NArchive::kName, &var);
rlm@1 99 if(var.vt == VT_BSTR)
rlm@1 100 info.name = wstrToStr(var.bstrVal);
rlm@1 101
rlm@1 102 GetHandlerProperty2(i, NArchive::kExtension, &var);
rlm@1 103 if(var.vt == VT_BSTR)
rlm@1 104 info.extensions = tokenize(wstrToStr(var.bstrVal), " ");
rlm@1 105
rlm@1 106 GetHandlerProperty2(i, NArchive::kStartSignature, &var);
rlm@1 107 if(var.vt == VT_BSTR)
rlm@1 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)
rlm@1 109
rlm@1 110 GetHandlerProperty2(i,NArchive::kClassID,&var);
rlm@1 111 if(var.vt == VT_BSTR)
rlm@1 112 memcpy(&info.guid, var.bstrVal, 16);
rlm@1 113 else
rlm@1 114 memset(&info.guid, 0, 16);
rlm@1 115
rlm@1 116 s_formatInfos.push_back(info);
rlm@1 117
rlm@1 118 VariantClear((VARIANTARG*)&var);
rlm@1 119 }
rlm@1 120 }
rlm@1 121
rlm@1 122 void CleanupDecoder()
rlm@1 123 {
rlm@1 124 s_formatInfos.clear();
rlm@1 125 s_supportedFormatsFilter.clear();
rlm@1 126 }
rlm@1 127
rlm@1 128 #include "7z/CPP/7zip/Archive/Zip/ZipHandler.h"
rlm@1 129
rlm@1 130
rlm@1 131 ArchiveFile::ArchiveFile(const char* filename, const char* displayFilename)
rlm@1 132 {
rlm@1 133 assert(!s_formatInfos.empty());
rlm@1 134
rlm@1 135 m_typeIndex = -1;
rlm@1 136 m_numItems = 0;
rlm@1 137 m_items = NULL;
rlm@1 138 m_filename = NULL;
rlm@1 139 m_displayFilename = NULL;
rlm@1 140 m_userMadeSelection = false;
rlm@1 141
rlm@1 142 FILE* file = fopen(filename, "rb");
rlm@1 143 if(!file)
rlm@1 144 return;
rlm@1 145
rlm@1 146 m_filename = new char[strlen(filename)+1];
rlm@1 147 strcpy(m_filename, filename);
rlm@1 148
rlm@1 149 if(displayFilename)
rlm@1 150 {
rlm@1 151 m_displayFilename = new char[strlen(displayFilename)+1];
rlm@1 152 strcpy(m_displayFilename, displayFilename);
rlm@1 153 }
rlm@1 154
rlm@1 155 // detect archive type using format signature in file
rlm@1 156 for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++)
rlm@1 157 {
rlm@1 158 fseek(file, 0, SEEK_SET);
rlm@1 159
rlm@1 160 std::string& formatSig = s_formatInfos[i].signature;
rlm@1 161 int len = formatSig.size();
rlm@1 162
rlm@1 163 if(len == 0)
rlm@1 164 continue; // because some formats have no signature
rlm@1 165
rlm@1 166 char* fileSig = (char*)_alloca(len);
rlm@1 167 fread(fileSig, 1, len, file);
rlm@1 168
rlm@1 169 if(!memcmp(formatSig.c_str(), fileSig, len))
rlm@1 170 m_typeIndex = i;
rlm@1 171 }
rlm@1 172
rlm@1 173 // if no signature match has been found, detect archive type using filename.
rlm@1 174 // this is only for signature-less formats
rlm@1 175 const char* fileExt = strrchr(filename, '.');
rlm@1 176 if(fileExt++)
rlm@1 177 {
rlm@1 178 for(size_t i = 0; i < s_formatInfos.size() && m_typeIndex < 0; i++)
rlm@1 179 {
rlm@1 180 if(s_formatInfos[i].signature.empty())
rlm@1 181 {
rlm@1 182 std::vector<std::string>& formatExts = s_formatInfos[i].extensions;
rlm@1 183 for(size_t j = 0; j < formatExts.size(); j++)
rlm@1 184 {
rlm@1 185 if(!_stricmp(formatExts[j].c_str(), fileExt))
rlm@1 186 {
rlm@1 187 m_typeIndex = i;
rlm@1 188 break;
rlm@1 189 }
rlm@1 190 }
rlm@1 191 }
rlm@1 192 }
rlm@1 193 }
rlm@1 194
rlm@1 195 if(m_typeIndex < 0)
rlm@1 196 {
rlm@1 197 // uncompressed
rlm@1 198
rlm@1 199 m_numItems = 1;
rlm@1 200 m_items = new ArchiveItem[m_numItems];
rlm@1 201
rlm@1 202 fseek(file, 0, SEEK_END);
rlm@1 203 m_items[0].size = ftell(file);
rlm@1 204
rlm@1 205 m_items[0].name = new char[strlen(filename)+1];
rlm@1 206 strcpy(m_items[0].name, filename);
rlm@1 207 }
rlm@1 208 else
rlm@1 209 {
rlm@1 210 IInArchive* object = NULL;
rlm@1 211 if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object)))
rlm@1 212 {
rlm@1 213 InFileStream* ifs = new InFileStream(filename);
rlm@1 214 if(SUCCEEDED(object->Open(ifs,0,0)))
rlm@1 215 {
rlm@1 216 UInt32 numItems = 0;
rlm@1 217 object->GetNumberOfItems(&numItems);
rlm@1 218 m_numItems = numItems;
rlm@1 219 m_items = new ArchiveItem[m_numItems];
rlm@1 220
rlm@1 221 for(int i = 0; i < m_numItems; i++)
rlm@1 222 {
rlm@1 223 PROPVARIANT var = {VT_EMPTY};
rlm@1 224 ArchiveItem& item = m_items[i];
rlm@1 225
rlm@1 226 object->GetProperty(i, kpidSize, &var);
rlm@1 227 item.size = var.uhVal.LowPart;
rlm@1 228
rlm@1 229 object->GetProperty(i, kpidPath, &var);
rlm@1 230 std::string& path = wstrToStr(var.bstrVal);
rlm@1 231 item.name = new char[path.size()+1];
rlm@1 232 strcpy(item.name, path.c_str());
rlm@1 233
rlm@1 234 //object->GetProperty(i, kpidMethod, &var);
rlm@1 235 //std::string& method = wstrToStr(var.bstrVal);
rlm@1 236 //item.method = new char[method.size()+1];
rlm@1 237 //strcpy(item.method, method.c_str());
rlm@1 238
rlm@1 239 object->GetProperty(i, kpidEncrypted, &var);
rlm@1 240 #ifdef _NO_CRYPTO
rlm@1 241 if(var.boolVal)
rlm@1 242 item.size = 0; // don't support decompressing it, pretend size zero
rlm@1 243 #else
rlm@1 244 #error password support NYI... see client7z.cpp
rlm@1 245 item.encrypted = !!var.boolVal;
rlm@1 246 #endif
rlm@1 247
rlm@1 248 VariantClear((VARIANTARG*)&var);
rlm@1 249 }
rlm@1 250
rlm@1 251 object->Close();
rlm@1 252 }
rlm@1 253
rlm@1 254 object->Release();
rlm@1 255 }
rlm@1 256 }
rlm@1 257
rlm@1 258 fclose(file);
rlm@1 259 }
rlm@1 260
rlm@1 261 ArchiveFile::~ArchiveFile()
rlm@1 262 {
rlm@1 263 for(int i = 0; i < m_numItems; i++)
rlm@1 264 {
rlm@1 265 delete[] m_items[i].name;
rlm@1 266 }
rlm@1 267 delete[] m_items;
rlm@1 268 delete[] m_filename;
rlm@1 269 delete[] m_displayFilename;
rlm@1 270 }
rlm@1 271
rlm@1 272 const char* ArchiveFile::GetArchiveTypeName()
rlm@1 273 {
rlm@1 274 assert(!s_formatInfos.empty());
rlm@1 275
rlm@1 276 if((size_t)m_typeIndex >= s_formatInfos.size())
rlm@1 277 return "";
rlm@1 278
rlm@1 279 return s_formatInfos[m_typeIndex].name.c_str();
rlm@1 280 }
rlm@1 281
rlm@1 282 int ArchiveFile::GetNumItems()
rlm@1 283 {
rlm@1 284 return m_numItems;
rlm@1 285 }
rlm@1 286
rlm@1 287 int ArchiveFile::GetItemSize(int item)
rlm@1 288 {
rlm@1 289 assert(item >= 0 && item < m_numItems);
rlm@1 290 if(!(item >= 0 && item < m_numItems)) return 0;
rlm@1 291 return m_items[item].size;
rlm@1 292 }
rlm@1 293
rlm@1 294 const char* ArchiveFile::GetItemName(int item)
rlm@1 295 {
rlm@1 296 //assert(item >= 0 && item < m_numItems);
rlm@1 297 if(!(item >= 0 && item < m_numItems)) return "";
rlm@1 298 return m_items[item].name;
rlm@1 299 }
rlm@1 300
rlm@1 301 bool ArchiveFile::IsCompressed()
rlm@1 302 {
rlm@1 303 return (m_typeIndex >= 0);
rlm@1 304 }
rlm@1 305
rlm@1 306 int ArchiveFile::ExtractItem(int index, unsigned char* outBuffer, int bufSize) const
rlm@1 307 {
rlm@1 308 assert(!s_formatInfos.empty());
rlm@1 309 //assert(index >= 0 && index < m_numItems);
rlm@1 310 if(!(index >= 0 && index < m_numItems)) return 0;
rlm@1 311
rlm@1 312 ArchiveItem& item = m_items[index];
rlm@1 313
rlm@1 314 if(bufSize < item.size)
rlm@1 315 return 0;
rlm@1 316
rlm@1 317 if(m_typeIndex < 0)
rlm@1 318 {
rlm@1 319 // uncompressed
rlm@1 320 FILE* file = fopen(m_filename, "rb");
rlm@1 321 fread(outBuffer, 1, item.size, file);
rlm@1 322 fclose(file);
rlm@1 323 }
rlm@1 324 else
rlm@1 325 {
rlm@1 326 IInArchive* object = NULL;
rlm@1 327 HRESULT hr = E_FAIL;
rlm@1 328 if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object)))
rlm@1 329 {
rlm@1 330 InFileStream* ifs = new InFileStream(m_filename);
rlm@1 331 if(SUCCEEDED(object->Open(ifs,0,0)))
rlm@1 332 {
rlm@1 333 OutStream* os = new OutStream(index, outBuffer, item.size);
rlm@1 334 const UInt32 indices [1] = {index};
rlm@1 335 hr = object->Extract(indices, 1, 0, os);
rlm@1 336 object->Close();
rlm@1 337 }
rlm@1 338 object->Release();
rlm@1 339 }
rlm@1 340 if(FAILED(hr))
rlm@1 341 return 0;
rlm@1 342 }
rlm@1 343
rlm@1 344 return item.size;
rlm@1 345 }
rlm@1 346
rlm@1 347
rlm@1 348
rlm@1 349 int ArchiveFile::ExtractItem(int index, const char* outFilename) const
rlm@1 350 {
rlm@1 351 assert(!s_formatInfos.empty());
rlm@1 352 //assert(index >= 0 && index < m_numItems);
rlm@1 353 if(!(index >= 0 && index < m_numItems)) return 0;
rlm@1 354
rlm@1 355 ArchiveItem& item = m_items[index];
rlm@1 356 int rv = item.size;
rlm@1 357
rlm@1 358 DWORD outAttributes = GetFileAttributes(outFilename);
rlm@1 359 if(outAttributes & FILE_ATTRIBUTE_READONLY)
rlm@1 360 SetFileAttributes(outFilename, outAttributes & ~FILE_ATTRIBUTE_READONLY); // temporarily remove read-only attribute so we can decompress to there
rlm@1 361
rlm@1 362 if(m_typeIndex < 0)
rlm@1 363 {
rlm@1 364 // uncompressed
rlm@1 365 if(!CopyFile(m_filename, outFilename, false))
rlm@1 366 rv = 0;
rlm@1 367 }
rlm@1 368 else
rlm@1 369 {
rlm@1 370 IInArchive* object = NULL;
rlm@1 371 HRESULT hr = E_FAIL;
rlm@1 372 if(SUCCEEDED(CreateObject(&s_formatInfos[m_typeIndex].guid, &IID_IInArchive, (void**)&object)))
rlm@1 373 {
rlm@1 374 InFileStream* ifs = new InFileStream(m_filename);
rlm@1 375 if(SUCCEEDED(object->Open(ifs,0,0)))
rlm@1 376 {
rlm@1 377 OutStream* os = new OutStream(index, outFilename);
rlm@1 378 const UInt32 indices [1] = {index};
rlm@1 379 hr = object->Extract(indices, 1, 0, os);
rlm@1 380 object->Close();
rlm@1 381 }
rlm@1 382 object->Release();
rlm@1 383 }
rlm@1 384 if(FAILED(hr))
rlm@1 385 rv = 0;
rlm@1 386 }
rlm@1 387
rlm@1 388 if(outAttributes & FILE_ATTRIBUTE_READONLY)
rlm@1 389 SetFileAttributes(outFilename, outAttributes); // restore read-only attribute
rlm@1 390
rlm@1 391 return rv;
rlm@1 392 }