view 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
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 InFileStream
14 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 ArchiveFormatInfo
19 {
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 work
32 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) // failed
39 {
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 else
114 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 file
156 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 signature
166 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 formats
175 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 // uncompressed
199 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 else
209 {
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_CRYPTO
241 if(var.boolVal)
242 item.size = 0; // don't support decompressing it, pretend size zero
243 #else
244 #error password support NYI... see client7z.cpp
245 item.encrypted = !!var.boolVal;
246 #endif
248 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) const
307 {
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 // uncompressed
320 FILE* file = fopen(m_filename, "rb");
321 fread(outBuffer, 1, item.size, file);
322 fclose(file);
323 }
324 else
325 {
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) const
350 {
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 there
362 if(m_typeIndex < 0)
363 {
364 // uncompressed
365 if(!CopyFile(m_filename, outFilename, false))
366 rv = 0;
367 }
368 else
369 {
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 attribute
391 return rv;
392 }