aboutsummaryrefslogtreecommitdiff
path: root/CPP/7zip/Archive/Zip/ZipItem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipItem.cpp')
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.cpp418
1 files changed, 418 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp
new file mode 100644
index 0000000..be33648
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -0,0 +1,418 @@
1// Archive/ZipItem.cpp
2
3#include "StdAfx.h"
4
5#include "../../../../C/CpuArch.h"
6#include "../../../../C/7zCrc.h"
7
8#include "../../../Common/IntToString.h"
9#include "../../../Common/MyLinux.h"
10#include "../../../Common/StringConvert.h"
11
12#include "../../../Windows/PropVariantUtils.h"
13
14#include "../Common/ItemNameUtils.h"
15
16#include "ZipItem.h"
17
18namespace NArchive {
19namespace NZip {
20
21using namespace NFileHeader;
22
23
24/*
25const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@";
26const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@";
27*/
28
29static const CUInt32PCharPair g_ExtraTypes[] =
30{
31 { NExtraID::kZip64, "Zip64" },
32 { NExtraID::kNTFS, "NTFS" },
33 { NExtraID::kStrongEncrypt, "StrongCrypto" },
34 { NExtraID::kUnixTime, "UT" },
35 { NExtraID::kUnixExtra, "UX" },
36 { NExtraID::kUnix2Extra, "Ux" },
37 { NExtraID::kUnix3Extra, "ux" },
38 { NExtraID::kIzUnicodeComment, "uc" },
39 { NExtraID::kIzUnicodeName, "up" },
40 { NExtraID::kIzNtSecurityDescriptor, "SD" },
41 { NExtraID::kWzAES, "WzAES" },
42 { NExtraID::kApkAlign, "ApkAlign" }
43};
44
45void CExtraSubBlock::PrintInfo(AString &s) const
46{
47 for (unsigned i = 0; i < ARRAY_SIZE(g_ExtraTypes); i++)
48 {
49 const CUInt32PCharPair &pair = g_ExtraTypes[i];
50 if (pair.Value == ID)
51 {
52 s += pair.Name;
53 /*
54 if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
55 {
56 char sz[32];
57 sz[0] = ':';
58 ConvertUInt32ToHex(GetUi16(Data), sz + 1);
59 s += sz;
60 for (unsigned j = 2; j < Data.Size(); j++)
61 {
62 char sz[32];
63 sz[0] = '-';
64 ConvertUInt32ToHex(Data[j], sz + 1);
65 s += sz;
66 }
67 }
68 */
69 return;
70 }
71 }
72 {
73 char sz[32];
74 sz[0] = '0';
75 sz[1] = 'x';
76 ConvertUInt32ToHex(ID, sz + 2);
77 s += sz;
78 }
79}
80
81
82void CExtraBlock::PrintInfo(AString &s) const
83{
84 if (Error)
85 s.Add_OptSpaced("Extra_ERROR");
86
87 if (MinorError)
88 s.Add_OptSpaced("Minor_Extra_ERROR");
89
90 if (IsZip64 || IsZip64_Error)
91 {
92 s.Add_OptSpaced("Zip64");
93 if (IsZip64_Error)
94 s += "_ERROR";
95 }
96
97 FOR_VECTOR (i, SubBlocks)
98 {
99 s.Add_Space_if_NotEmpty();
100 SubBlocks[i].PrintInfo(s);
101 }
102}
103
104
105bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
106{
107 ft.dwHighDateTime = ft.dwLowDateTime = 0;
108 UInt32 size = (UInt32)Data.Size();
109 if (ID != NExtraID::kNTFS || size < 32)
110 return false;
111 const Byte *p = (const Byte *)Data;
112 p += 4; // for reserved
113 size -= 4;
114 while (size > 4)
115 {
116 UInt16 tag = GetUi16(p);
117 unsigned attrSize = GetUi16(p + 2);
118 p += 4;
119 size -= 4;
120 if (attrSize > size)
121 attrSize = size;
122
123 if (tag == NNtfsExtra::kTagTime && attrSize >= 24)
124 {
125 p += 8 * index;
126 ft.dwLowDateTime = GetUi32(p);
127 ft.dwHighDateTime = GetUi32(p + 4);
128 return true;
129 }
130 p += attrSize;
131 size -= attrSize;
132 }
133 return false;
134}
135
136bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const
137{
138 res = 0;
139 UInt32 size = (UInt32)Data.Size();
140 if (ID != NExtraID::kUnixTime || size < 5)
141 return false;
142 const Byte *p = (const Byte *)Data;
143 Byte flags = *p++;
144 size--;
145 if (isCentral)
146 {
147 if (index != NUnixTime::kMTime ||
148 (flags & (1 << NUnixTime::kMTime)) == 0 ||
149 size < 4)
150 return false;
151 res = GetUi32(p);
152 return true;
153 }
154 for (unsigned i = 0; i < 3; i++)
155 if ((flags & (1 << i)) != 0)
156 {
157 if (size < 4)
158 return false;
159 if (index == i)
160 {
161 res = GetUi32(p);
162 return true;
163 }
164 p += 4;
165 size -= 4;
166 }
167 return false;
168}
169
170
171bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const
172{
173 res = 0;
174 const size_t size = Data.Size();
175 unsigned offset = index * 4;
176 if (ID != NExtraID::kUnixExtra || size < offset + 4)
177 return false;
178 const Byte *p = (const Byte *)Data + offset;
179 res = GetUi32(p);
180 return true;
181}
182
183
184bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
185{
186 FOR_VECTOR (i, SubBlocks)
187 {
188 const CExtraSubBlock &sb = SubBlocks[i];
189 if (sb.ID == NFileHeader::NExtraID::kNTFS)
190 return sb.ExtractNtfsTime(index, ft);
191 }
192 return false;
193}
194
195bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
196{
197 {
198 FOR_VECTOR (i, SubBlocks)
199 {
200 const CExtraSubBlock &sb = SubBlocks[i];
201 if (sb.ID == NFileHeader::NExtraID::kUnixTime)
202 return sb.ExtractUnixTime(isCentral, index, res);
203 }
204 }
205
206 switch (index)
207 {
208 case NUnixTime::kMTime: index = NUnixExtra::kMTime; break;
209 case NUnixTime::kATime: index = NUnixExtra::kATime; break;
210 default: return false;
211 }
212
213 {
214 FOR_VECTOR (i, SubBlocks)
215 {
216 const CExtraSubBlock &sb = SubBlocks[i];
217 if (sb.ID == NFileHeader::NExtraID::kUnixExtra)
218 return sb.ExtractUnixExtraTime(index, res);
219 }
220 }
221 return false;
222}
223
224
225bool CLocalItem::IsDir() const
226{
227 return NItemName::HasTailSlash(Name, GetCodePage());
228}
229
230bool CItem::IsDir() const
231{
232 // FIXME: we can check InfoZip UTF-8 name at first.
233 if (NItemName::HasTailSlash(Name, GetCodePage()))
234 return true;
235
236 Byte hostOS = GetHostOS();
237
238 if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\')
239 {
240 // do we need to use CharPrevExA?
241 // .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers?
242 // so we support that case
243 switch (hostOS)
244 {
245 case NHostOS::kFAT:
246 case NHostOS::kNTFS:
247 case NHostOS::kHPFS:
248 case NHostOS::kVFAT:
249 return true;
250 }
251 }
252
253 if (!FromCentral)
254 return false;
255
256 UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF);
257
258 switch (hostOS)
259 {
260 case NHostOS::kAMIGA:
261 switch (highAttrib & NAmigaAttrib::kIFMT)
262 {
263 case NAmigaAttrib::kIFDIR: return true;
264 case NAmigaAttrib::kIFREG: return false;
265 default: return false; // change it throw kUnknownAttributes;
266 }
267 case NHostOS::kFAT:
268 case NHostOS::kNTFS:
269 case NHostOS::kHPFS:
270 case NHostOS::kVFAT:
271 return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
272 case NHostOS::kAtari:
273 case NHostOS::kMac:
274 case NHostOS::kVMS:
275 case NHostOS::kVM_CMS:
276 case NHostOS::kAcorn:
277 case NHostOS::kMVS:
278 return false; // change it throw kUnknownAttributes;
279 case NHostOS::kUnix:
280 return MY_LIN_S_ISDIR(highAttrib);
281 default:
282 return false;
283 }
284}
285
286UInt32 CItem::GetWinAttrib() const
287{
288 UInt32 winAttrib = 0;
289 switch (GetHostOS())
290 {
291 case NHostOS::kFAT:
292 case NHostOS::kNTFS:
293 if (FromCentral)
294 winAttrib = ExternalAttrib;
295 break;
296 case NHostOS::kUnix:
297 // do we need to clear 16 low bits in this case?
298 if (FromCentral)
299 {
300 /*
301 Some programs write posix attributes in high 16 bits of ExternalAttrib
302 Also some programs can write additional marker flag:
303 0x8000 - p7zip
304 0x4000 - Zip in MacOS
305 no marker - Info-Zip
306
307 Client code has two options to detect posix field:
308 1) check 0x8000 marker. In that case we must add 0x8000 marker here.
309 2) check that high 4 bits (file type bits in posix field) of attributes are not zero.
310 */
311
312 winAttrib = ExternalAttrib & 0xFFFF0000;
313
314 // #ifndef _WIN32
315 winAttrib |= 0x8000; // add posix mode marker
316 // #endif
317 }
318 break;
319 }
320 if (IsDir()) // test it;
321 winAttrib |= FILE_ATTRIBUTE_DIRECTORY;
322 return winAttrib;
323}
324
325bool CItem::GetPosixAttrib(UInt32 &attrib) const
326{
327 // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT.
328 if (FromCentral && GetHostOS() == NHostOS::kUnix)
329 {
330 attrib = ExternalAttrib >> 16;
331 return (attrib != 0);
332 }
333 attrib = 0;
334 if (IsDir())
335 attrib = MY_LIN_S_IFDIR;
336 return false;
337}
338
339
340bool CExtraSubBlock::CheckIzUnicode(const AString &s) const
341{
342 size_t size = Data.Size();
343 if (size < 1 + 4)
344 return false;
345 const Byte *p = (const Byte *)Data;
346 if (p[0] > 1)
347 return false;
348 if (CrcCalc(s, s.Len()) != GetUi32(p + 1))
349 return false;
350 size -= 5;
351 p += 5;
352 for (size_t i = 0; i < size; i++)
353 if (p[i] == 0)
354 return false;
355 return Check_UTF8_Buf((const char *)(const void *)p, size, false);
356}
357
358
359void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const
360{
361 bool isUtf8 = IsUtf8();
362 // bool ignore_Utf8_Errors = true;
363
364 if (!isUtf8)
365 {
366 {
367 const unsigned id = isComment ?
368 NFileHeader::NExtraID::kIzUnicodeComment:
369 NFileHeader::NExtraID::kIzUnicodeName;
370 const CObjectVector<CExtraSubBlock> &subBlocks = GetMainExtra().SubBlocks;
371
372 FOR_VECTOR (i, subBlocks)
373 {
374 const CExtraSubBlock &sb = subBlocks[i];
375 if (sb.ID == id)
376 {
377 if (sb.CheckIzUnicode(s))
378 {
379 // const unsigned kIzUnicodeHeaderSize = 5;
380 if (Convert_UTF8_Buf_To_Unicode(
381 (const char *)(const void *)(const Byte *)sb.Data + 5,
382 sb.Data.Size() - 5, res))
383 return;
384 }
385 break;
386 }
387 }
388 }
389
390 if (useSpecifiedCodePage)
391 isUtf8 = (codePage == CP_UTF8);
392 #ifdef _WIN32
393 else if (GetHostOS() == NFileHeader::NHostOS::kUnix)
394 {
395 /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header.
396 We try to get name as UTF-8.
397 Do we need to do it in POSIX version also? */
398 isUtf8 = true;
399
400 /* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed
401 of UTF-8 and non-UTF-8 characters. */
402 // ignore_Utf8_Errors = false;
403 // ignore_Utf8_Errors = true;
404 }
405 #endif
406 }
407
408
409 if (isUtf8)
410 {
411 ConvertUTF8ToUnicode(s, res);
412 return;
413 }
414
415 MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage());
416}
417
418}}