OSDN Git Service

add japanese site html
[sevenzip/7-Zip.git] / 7z457 / CPP / 7zip / Archive / Zip / ZipHandlerOut.cpp
1 // Zip/HandlerOut.cpp
2
3 #include "StdAfx.h"
4
5 #include "ZipHandler.h"
6 #include "ZipUpdate.h"
7
8 #include "Common/StringConvert.h"
9 #include "Common/ComTry.h"
10 #include "Common/StringToInt.h"
11
12 #include "Windows/PropVariant.h"
13 #include "Windows/Time.h"
14
15 #include "../../IPassword.h"
16 #include "../Common/ItemNameUtils.h"
17 #include "../Common/ParseProperties.h"
18 #include "../../Crypto/WzAES/WzAES.h"
19 #include "../../Common/OutBuffer.h"
20
21 using namespace NWindows;
22 using namespace NCOM;
23 using namespace NTime;
24
25 namespace NArchive {
26 namespace NZip {
27
28 static const UInt32 kDeflateAlgoX1 = 0;
29 static const UInt32 kDeflateAlgoX5 = 1;
30
31 static const UInt32 kDeflateNumPassesX1  = 1;
32 static const UInt32 kDeflateNumPassesX7  = 3;
33 static const UInt32 kDeflateNumPassesX9  = 10;
34
35 static const UInt32 kNumFastBytesX1 = 32;
36 static const UInt32 kNumFastBytesX7 = 64;
37 static const UInt32 kNumFastBytesX9 = 128;
38
39 static const UInt32 kBZip2NumPassesX1 = 1;
40 static const UInt32 kBZip2NumPassesX7 = 2;
41 static const UInt32 kBZip2NumPassesX9 = 7;
42
43 static const UInt32 kBZip2DicSizeX1 = 100000;
44 static const UInt32 kBZip2DicSizeX3 = 500000;
45 static const UInt32 kBZip2DicSizeX5 = 900000;
46
47 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
48 {
49   *timeType = NFileTimeType::kDOS;
50   return S_OK;
51 }
52
53 static bool IsAsciiString(const UString &s)
54 {
55   for (int i = 0; i < s.Length(); i++)
56   {
57     wchar_t c = s[i];
58     if (c < 0x20 || c > 0x7F)
59       return false;
60   }
61   return true;
62 }
63
64 #define COM_TRY_BEGIN2 try {
65 #define COM_TRY_END2 } \
66 catch(const CSystemException &e) { return e.ErrorCode; } \
67 catch(...) { return E_OUTOFMEMORY; }
68
69 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
70     IArchiveUpdateCallback *updateCallback)
71 {
72   COM_TRY_BEGIN2
73   CObjectVector<CUpdateItem> updateItems;
74   for(UInt32 i = 0; i < numItems; i++)
75   {
76     CUpdateItem updateItem;
77     Int32 newData;
78     Int32 newProperties;
79     UInt32 indexInArchive;
80     if (!updateCallback)
81       return E_FAIL;
82     RINOK(updateCallback->GetUpdateItemInfo(i,
83         &newData, // 1 - compress 0 - copy
84         &newProperties,
85         &indexInArchive));
86     updateItem.NewProperties = IntToBool(newProperties);
87     updateItem.NewData = IntToBool(newData);
88     updateItem.IndexInArchive = indexInArchive;
89     updateItem.IndexInClient = i;
90     // bool existInArchive = (indexInArchive != UInt32(-1));
91     if (IntToBool(newProperties))
92     {
93       FILETIME utcFileTime;
94       UString name;
95       bool isDirectoryStatusDefined;
96       {
97         NCOM::CPropVariant propVariant;
98         RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant));
99         if (propVariant.vt == VT_EMPTY)
100           updateItem.Attributes = 0;
101         else if (propVariant.vt != VT_UI4)
102           return E_INVALIDARG;
103         else
104           updateItem.Attributes = propVariant.ulVal;
105       }
106       {
107         NCOM::CPropVariant propVariant;
108         RINOK(updateCallback->GetProperty(i, kpidLastWriteTime, &propVariant));
109         if (propVariant.vt != VT_FILETIME)
110           return E_INVALIDARG;
111         utcFileTime = propVariant.filetime;
112       }
113       {
114         NCOM::CPropVariant propVariant;
115         RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant));
116         if (propVariant.vt == VT_EMPTY)
117           name.Empty();
118         else if (propVariant.vt != VT_BSTR)
119           return E_INVALIDARG;
120         else
121           name = propVariant.bstrVal;
122       }
123       {
124         NCOM::CPropVariant propVariant;
125         RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant));
126         if (propVariant.vt == VT_EMPTY)
127           isDirectoryStatusDefined = false;
128         else if (propVariant.vt != VT_BOOL)
129           return E_INVALIDARG;
130         else
131         {
132           updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE);
133           isDirectoryStatusDefined = true;
134         }
135       }
136       FILETIME localFileTime;
137       if(!FileTimeToLocalFileTime(&utcFileTime, &localFileTime))
138         return E_INVALIDARG;
139       if(!FileTimeToDosTime(localFileTime, updateItem.Time))
140       {
141         // return E_INVALIDARG;
142       }
143
144       if (!isDirectoryStatusDefined)
145         updateItem.IsDirectory = ((updateItem.Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
146
147       name = NItemName::MakeLegalName(name);
148       bool needSlash = updateItem.IsDirectory;
149       const wchar_t kSlash = L'/';
150       if (!name.IsEmpty())
151       {
152         if (name[name.Length() - 1] == kSlash)
153         {
154           if (!updateItem.IsDirectory)
155             return E_INVALIDARG;
156           needSlash = false;
157         }
158       }
159       if (needSlash)
160         name += kSlash;
161       updateItem.Name = UnicodeStringToMultiByte(name, CP_OEMCP);
162       if (updateItem.Name.Length() > 0xFFFF)
163         return E_INVALIDARG;
164
165       updateItem.IndexInClient = i;
166       /*
167       if(existInArchive)
168       {
169         const CItemEx &itemInfo = m_Items[indexInArchive];
170         // updateItem.Commented = itemInfo.IsCommented();
171         updateItem.Commented = false;
172         if(updateItem.Commented)
173         {
174           updateItem.CommentRange.Position = itemInfo.GetCommentPosition();
175           updateItem.CommentRange.Size  = itemInfo.CommentSize;
176         }
177       }
178       else
179         updateItem.Commented = false;
180       */
181     }
182     if (IntToBool(newData))
183     {
184       UInt64 size;
185       {
186         NCOM::CPropVariant propVariant;
187         RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant));
188         if (propVariant.vt != VT_UI8)
189           return E_INVALIDARG;
190         size = propVariant.uhVal.QuadPart;
191       }
192       updateItem.Size = size;
193     }
194     updateItems.Add(updateItem);
195   }
196
197   CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
198   if (!getTextPassword)
199   {
200     CMyComPtr<IArchiveUpdateCallback> udateCallBack2(updateCallback);
201     udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
202   }
203   CCompressionMethodMode options;
204
205   if (getTextPassword)
206   {
207     CMyComBSTR password;
208     Int32 passwordIsDefined;
209     RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password));
210     options.PasswordIsDefined = IntToBool(passwordIsDefined);
211     if (options.PasswordIsDefined)
212     {
213       if (!IsAsciiString((const wchar_t *)password))
214         return E_INVALIDARG;
215       if (m_IsAesMode)
216       {
217         if (options.Password.Length() > NCrypto::NWzAES::kPasswordSizeMax)
218           return E_INVALIDARG;
219       }
220       options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
221       options.IsAesMode = m_IsAesMode;
222       options.AesKeyMode = m_AesKeyMode;
223     }
224   }
225   else
226     options.PasswordIsDefined = false;
227
228   int level = m_Level;
229   if (level < 0)
230     level = 5;
231   
232   Byte mainMethod;
233   if (m_MainMethod < 0)
234     mainMethod = (Byte)(((level == 0) ?
235         NFileHeader::NCompressionMethod::kStored :
236         NFileHeader::NCompressionMethod::kDeflated));
237   else
238     mainMethod = (Byte)m_MainMethod;
239   options.MethodSequence.Add(mainMethod);
240   if (mainMethod != NFileHeader::NCompressionMethod::kStored)
241     options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored);
242   bool isDeflate = (mainMethod == NFileHeader::NCompressionMethod::kDeflated) || 
243       (mainMethod == NFileHeader::NCompressionMethod::kDeflated64);
244   bool isBZip2 = (mainMethod == NFileHeader::NCompressionMethod::kBZip2);
245   options.NumPasses = m_NumPasses;
246   options.DicSize = m_DicSize;
247   options.NumFastBytes = m_NumFastBytes;
248   options.NumMatchFinderCycles = m_NumMatchFinderCycles;
249   options.NumMatchFinderCyclesDefined = m_NumMatchFinderCyclesDefined;
250   options.Algo = m_Algo;
251   #ifdef COMPRESS_MT
252   options.NumThreads = _numThreads;
253   #endif
254   if (isDeflate)
255   {
256     if (options.NumPasses == 0xFFFFFFFF)
257       options.NumPasses = (level >= 9 ? kDeflateNumPassesX9 :  
258                           (level >= 7 ? kDeflateNumPassesX7 : 
259                                         kDeflateNumPassesX1));
260     if (options.NumFastBytes == 0xFFFFFFFF)
261       options.NumFastBytes = (level >= 9 ? kNumFastBytesX9 : 
262                              (level >= 7 ? kNumFastBytesX7 : 
263                                            kNumFastBytesX1));
264     if (options.Algo == 0xFFFFFFFF)
265         options.Algo = 
266                     (level >= 5 ? kDeflateAlgoX5 : 
267                                   kDeflateAlgoX1); 
268   }
269   if (isBZip2)
270   {
271     if (options.NumPasses == 0xFFFFFFFF)
272       options.NumPasses = (level >= 9 ? kBZip2NumPassesX9 : 
273                           (level >= 7 ? kBZip2NumPassesX7 :  
274                                         kBZip2NumPassesX1));
275     if (options.DicSize == 0xFFFFFFFF)
276       options.DicSize = (level >= 5 ? kBZip2DicSizeX5 : 
277                         (level >= 3 ? kBZip2DicSizeX3 : 
278                                       kBZip2DicSizeX1));
279   }
280
281   return Update(
282       EXTERNAL_CODECS_VARS
283       m_Items, updateItems, outStream, 
284       m_ArchiveIsOpen ? &m_Archive : NULL, &options, updateCallback);
285   COM_TRY_END2
286 }
287
288 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
289 {
290   #ifdef COMPRESS_MT
291   const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
292   _numThreads = numProcessors;
293   #endif
294   InitMethodProperties();
295   for (int i = 0; i < numProperties; i++)
296   {
297     UString name = UString(names[i]);
298     name.MakeUpper();
299     if (name.IsEmpty())
300       return E_INVALIDARG;
301
302     const PROPVARIANT &prop = values[i];
303
304     if (name[0] == L'X')
305     {
306       UInt32 level = 9;
307       RINOK(ParsePropValue(name.Mid(1), prop, level));
308       m_Level = level;
309       continue;
310     }
311     else if (name == L"M")
312     {
313       if (prop.vt == VT_BSTR)
314       {
315         UString valueString = prop.bstrVal;
316         valueString.MakeUpper();
317         if (valueString == L"COPY")
318           m_MainMethod = NFileHeader::NCompressionMethod::kStored;
319         else if (valueString == L"DEFLATE")
320           m_MainMethod = NFileHeader::NCompressionMethod::kDeflated;
321         else if (valueString == L"DEFLATE64")
322           m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64;
323         else if (valueString == L"BZIP2")
324           m_MainMethod = NFileHeader::NCompressionMethod::kBZip2;
325         else 
326           return E_INVALIDARG;
327       }
328       else if (prop.vt == VT_UI4)
329       {
330         switch(prop.ulVal)
331         {
332           case NFileHeader::NCompressionMethod::kStored:
333           case NFileHeader::NCompressionMethod::kDeflated:
334           case NFileHeader::NCompressionMethod::kDeflated64:
335           case NFileHeader::NCompressionMethod::kBZip2:
336             m_MainMethod = (Byte)prop.ulVal;
337             break;
338           default:
339             return E_INVALIDARG;
340         }
341       }
342       else
343         return E_INVALIDARG;
344     }
345     else if (name.Left(2) == L"EM")
346     {
347       if (prop.vt == VT_BSTR)
348       {
349         UString valueString = prop.bstrVal;
350         valueString.MakeUpper();
351         if (valueString.Left(3) == L"AES")
352         {
353           valueString = valueString.Mid(3);
354           if (valueString == L"128")
355             m_AesKeyMode = 1;
356           else if (valueString == L"192")
357             m_AesKeyMode = 2;
358           else if (valueString == L"256" || valueString.IsEmpty())
359             m_AesKeyMode = 3;
360           else
361             return E_INVALIDARG;
362           m_IsAesMode = true;
363         }
364         else if (valueString == L"ZIPCRYPTO")
365           m_IsAesMode = false;
366         else
367           return E_INVALIDARG;
368       }
369       else
370         return E_INVALIDARG;
371     }
372     else if (name[0] == L'D')
373     {
374       UInt32 dicSize = kBZip2DicSizeX5;
375       RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
376       m_DicSize = dicSize;
377     }
378     else if (name.Left(4) == L"PASS")
379     {
380       UInt32 num = kDeflateNumPassesX9;
381       RINOK(ParsePropValue(name.Mid(4), prop, num));
382       m_NumPasses = num;
383     }
384     else if (name.Left(2) == L"FB")
385     {
386       UInt32 num = kNumFastBytesX9;
387       RINOK(ParsePropValue(name.Mid(2), prop, num));
388       m_NumFastBytes = num;
389     }
390     else if (name.Left(2) == L"MC")
391     {
392       UInt32 num = 0xFFFFFFFF;
393       RINOK(ParsePropValue(name.Mid(2), prop, num));
394       m_NumMatchFinderCycles = num;
395       m_NumMatchFinderCyclesDefined = true;
396     }
397     else if (name.Left(2) == L"MT")
398     {
399       #ifdef COMPRESS_MT
400       RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
401       #endif
402     }
403     else if (name.Left(1) == L"A")
404     {
405       UInt32 num = kDeflateAlgoX5;
406       RINOK(ParsePropValue(name.Mid(1), prop, num));
407       m_Algo = num;
408     }
409     else 
410       return E_INVALIDARG;
411   }
412   return S_OK;
413 }  
414
415 }}