Mercurial > vba-clojure
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 #include "7zip.h" | |
2 | |
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) | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 #include <cassert> | |
10 #include <malloc.h> | |
11 | |
12 #include "7zipstreams.h" // defines OutStream and InFileStream | |
13 | |
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); | |
17 | |
18 struct ArchiveFormatInfo | |
19 { | |
20 std::string name; | |
21 std::vector<std::string> extensions; | |
22 std::string signature; | |
23 GUID guid; | |
24 }; | |
25 | |
26 static std::vector<ArchiveFormatInfo> s_formatInfos; | |
27 | |
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 } | |
49 | |
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 } | |
66 | |
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 } | |
85 | |
86 void InitDecoder() | |
87 { | |
88 CleanupDecoder(); | |
89 | |
90 UINT32 numFormats = 0; | |
91 GetNumberOfFormats(&numFormats); | |
92 | |
93 for(unsigned int i = 0; i < numFormats; i++) | |
94 { | |
95 PROPVARIANT var = {VT_EMPTY}; | |
96 ArchiveFormatInfo info; | |
97 | |
98 GetHandlerProperty2(i, NArchive::kName, &var); | |
99 if(var.vt == VT_BSTR) | |
100 info.name = wstrToStr(var.bstrVal); | |
101 | |
102 GetHandlerProperty2(i, NArchive::kExtension, &var); | |
103 if(var.vt == VT_BSTR) | |
104 info.extensions = tokenize(wstrToStr(var.bstrVal), " "); | |
105 | |
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) | |
109 | |
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); | |
115 | |
116 s_formatInfos.push_back(info); | |
117 | |
118 VariantClear((VARIANTARG*)&var); | |
119 } | |
120 } | |
121 | |
122 void CleanupDecoder() | |
123 { | |
124 s_formatInfos.clear(); | |
125 s_supportedFormatsFilter.clear(); | |
126 } | |
127 | |
128 #include "7z/CPP/7zip/Archive/Zip/ZipHandler.h" | |
129 | |
130 | |
131 ArchiveFile::ArchiveFile(const char* filename, const char* displayFilename) | |
132 { | |
133 assert(!s_formatInfos.empty()); | |
134 | |
135 m_typeIndex = -1; | |
136 m_numItems = 0; | |
137 m_items = NULL; | |
138 m_filename = NULL; | |
139 m_displayFilename = NULL; | |
140 m_userMadeSelection = false; | |
141 | |
142 FILE* file = fopen(filename, "rb"); | |
143 if(!file) | |
144 return; | |
145 | |
146 m_filename = new char[strlen(filename)+1]; | |
147 strcpy(m_filename, filename); | |
148 | |
149 if(displayFilename) | |
150 { | |
151 m_displayFilename = new char[strlen(displayFilename)+1]; | |
152 strcpy(m_displayFilename, displayFilename); | |
153 } | |
154 | |
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); | |
159 | |
160 std::string& formatSig = s_formatInfos[i].signature; | |
161 int len = formatSig.size(); | |
162 | |
163 if(len == 0) | |
164 continue; // because some formats have no signature | |
165 | |
166 char* fileSig = (char*)_alloca(len); | |
167 fread(fileSig, 1, len, file); | |
168 | |
169 if(!memcmp(formatSig.c_str(), fileSig, len)) | |
170 m_typeIndex = i; | |
171 } | |
172 | |
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 } | |
194 | |
195 if(m_typeIndex < 0) | |
196 { | |
197 // uncompressed | |
198 | |
199 m_numItems = 1; | |
200 m_items = new ArchiveItem[m_numItems]; | |
201 | |
202 fseek(file, 0, SEEK_END); | |
203 m_items[0].size = ftell(file); | |
204 | |
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]; | |
220 | |
221 for(int i = 0; i < m_numItems; i++) | |
222 { | |
223 PROPVARIANT var = {VT_EMPTY}; | |
224 ArchiveItem& item = m_items[i]; | |
225 | |
226 object->GetProperty(i, kpidSize, &var); | |
227 item.size = var.uhVal.LowPart; | |
228 | |
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()); | |
233 | |
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()); | |
238 | |
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 | |
247 | |
248 VariantClear((VARIANTARG*)&var); | |
249 } | |
250 | |
251 object->Close(); | |
252 } | |
253 | |
254 object->Release(); | |
255 } | |
256 } | |
257 | |
258 fclose(file); | |
259 } | |
260 | |
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 } | |
271 | |
272 const char* ArchiveFile::GetArchiveTypeName() | |
273 { | |
274 assert(!s_formatInfos.empty()); | |
275 | |
276 if((size_t)m_typeIndex >= s_formatInfos.size()) | |
277 return ""; | |
278 | |
279 return s_formatInfos[m_typeIndex].name.c_str(); | |
280 } | |
281 | |
282 int ArchiveFile::GetNumItems() | |
283 { | |
284 return m_numItems; | |
285 } | |
286 | |
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 } | |
293 | |
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 } | |
300 | |
301 bool ArchiveFile::IsCompressed() | |
302 { | |
303 return (m_typeIndex >= 0); | |
304 } | |
305 | |
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; | |
311 | |
312 ArchiveItem& item = m_items[index]; | |
313 | |
314 if(bufSize < item.size) | |
315 return 0; | |
316 | |
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 } | |
343 | |
344 return item.size; | |
345 } | |
346 | |
347 | |
348 | |
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; | |
354 | |
355 ArchiveItem& item = m_items[index]; | |
356 int rv = item.size; | |
357 | |
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 | |
361 | |
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 } | |
387 | |
388 if(outAttributes & FILE_ATTRIBUTE_READONLY) | |
389 SetFileAttributes(outFilename, outAttributes); // restore read-only attribute | |
390 | |
391 return rv; | |
392 } |