1 // IsoHandler.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/ComTry.h"
6 #include "../../../Common/MyLinux.h"
7 #include "../../../Common/StringConvert.h"
8
9 #include "../../Common/LimitedStreams.h"
10 #include "../../Common/ProgressUtils.h"
11 #include "../../Common/StreamUtils.h"
12
13 #include "../../Compress/CopyCoder.h"
14
15 #include "../Common/ItemNameUtils.h"
16
17 #include "IsoHandler.h"
18
19 using namespace NWindows;
20 using namespace NTime;
21
22 namespace NArchive {
23 namespace NIso {
24
25 static const Byte kProps[] =
26 {
27 kpidPath,
28 kpidIsDir,
29 kpidSize,
30 kpidPackSize,
31 kpidMTime,
32 // kpidCTime,
33 // kpidATime,
34 kpidPosixAttrib,
35 // kpidUserId,
36 // kpidGroupId,
37 // kpidLinks,
38 kpidSymLink
39 };
40
41 static const Byte kArcProps[] =
42 {
43 kpidComment,
44 kpidCTime,
45 kpidMTime,
46 // kpidHeadersSize
47 };
48
49 IMP_IInArchive_Props
50 IMP_IInArchive_ArcProps
51
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback *))52 Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
53 const UInt64 * /* maxCheckStartPosition */,
54 IArchiveOpenCallback * /* openArchiveCallback */))
55 {
56 COM_TRY_BEGIN
57 Close();
58 {
59 RINOK(_archive.Open(stream))
60 _stream = stream;
61 }
62 return S_OK;
63 COM_TRY_END
64 }
65
Z7_COM7F_IMF(CHandler::Close ())66 Z7_COM7F_IMF(CHandler::Close())
67 {
68 _archive.Clear();
69 _stream.Release();
70 return S_OK;
71 }
72
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))73 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
74 {
75 *numItems = _archive.Refs.Size() + _archive.BootEntries.Size();
76 return S_OK;
77 }
78
AddString(AString & s,const char * name,const Byte * p,unsigned size)79 static void AddString(AString &s, const char *name, const Byte *p, unsigned size)
80 {
81 unsigned i;
82 for (i = 0; i < size && p[i]; i++);
83 for (; i > 0 && p[i - 1] == ' '; i--);
84 if (i != 0)
85 {
86 AString d;
87 d.SetFrom((const char *)p, i);
88 s += name;
89 s += ": ";
90 s += d;
91 s.Add_LF();
92 }
93 }
94
AddProp_Size64(AString & s,const char * name,UInt64 size)95 static void AddProp_Size64(AString &s, const char *name, UInt64 size)
96 {
97 s += name;
98 s += ": ";
99 s.Add_UInt64(size);
100 s.Add_LF();
101 }
102
103 #define ADD_STRING(n, v) AddString(s, n, vol. v, sizeof(vol. v))
104
AddErrorMessage(AString & s,const char * message)105 static void AddErrorMessage(AString &s, const char *message)
106 {
107 if (!s.IsEmpty())
108 s += ". ";
109 s += message;
110 }
111
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))112 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
113 {
114 COM_TRY_BEGIN
115 NCOM::CPropVariant prop;
116 if (_stream)
117 {
118 const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
119 switch (propID)
120 {
121 case kpidComment:
122 {
123 AString s;
124 ADD_STRING("System", SystemId);
125 ADD_STRING("Volume", VolumeId);
126 ADD_STRING("VolumeSet", VolumeSetId);
127 ADD_STRING("Publisher", PublisherId);
128 ADD_STRING("Preparer", DataPreparerId);
129 ADD_STRING("Application", ApplicationId);
130 ADD_STRING("Copyright", CopyrightFileId);
131 ADD_STRING("Abstract", AbstractFileId);
132 ADD_STRING("Bib", BibFileId);
133 // ADD_STRING("EscapeSequence", EscapeSequence);
134 AddProp_Size64(s, "VolumeSpaceSize", vol.Get_VolumeSpaceSize_inBytes());
135 AddProp_Size64(s, "VolumeSetSize", vol.VolumeSetSize);
136 AddProp_Size64(s, "VolumeSequenceNumber", vol.VolumeSequenceNumber);
137
138 prop = s;
139 break;
140 }
141 case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
142 case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
143 }
144 }
145
146 switch (propID)
147 {
148 case kpidPhySize: prop = _archive.PhySize; break;
149 case kpidErrorFlags:
150 {
151 UInt32 v = 0;
152 if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
153 if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
154 if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError;
155 prop = v;
156 break;
157 }
158
159 case kpidError:
160 {
161 AString s;
162 if (_archive.IncorrectBigEndian)
163 AddErrorMessage(s, "Incorrect big-endian headers");
164 if (_archive.SelfLinkedDirs)
165 AddErrorMessage(s, "Self-linked directory");
166 if (_archive.TooDeepDirs)
167 AddErrorMessage(s, "Too deep directory levels");
168 if (!s.IsEmpty())
169 prop = s;
170 break;
171 }
172 }
173 prop.Detach(value);
174 return S_OK;
175 COM_TRY_END
176 }
177
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))178 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
179 {
180 COM_TRY_BEGIN
181 NCOM::CPropVariant prop;
182 if (index >= (UInt32)_archive.Refs.Size())
183 {
184 index -= _archive.Refs.Size();
185 const CBootInitialEntry &be = _archive.BootEntries[index];
186 switch (propID)
187 {
188 case kpidPath:
189 {
190 AString s ("[BOOT]" STRING_PATH_SEPARATOR);
191 if (_archive.BootEntries.Size() != 1)
192 {
193 s.Add_UInt32(index + 1);
194 s.Add_Minus();
195 }
196 s += be.GetName();
197 prop = s;
198 break;
199 }
200 case kpidIsDir: prop = false; break;
201 case kpidSize:
202 case kpidPackSize:
203 prop = (UInt64)_archive.GetBootItemSize(index);
204 break;
205 }
206 }
207 else
208 {
209 const CRef &ref = _archive.Refs[index];
210 const CDir &item = ref.Dir->_subItems[ref.Index];
211 switch (propID)
212 {
213 case kpidPath:
214 // if (item.FileId.GetCapacity() >= 0)
215 {
216 UString s;
217 if (_archive.IsJoliet())
218 item.GetPathU(s);
219 else
220 s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
221
222 if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1')
223 s.DeleteFrom(s.Len() - 2);
224
225 if (!s.IsEmpty() && s.Back() == L'.')
226 s.DeleteBack();
227
228 NItemName::ReplaceToOsSlashes_Remove_TailSlash(s);
229 prop = s;
230 }
231 break;
232
233 case kpidSymLink:
234 if (_archive.IsSusp)
235 {
236 UInt32 mode;
237 if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode))
238 {
239 if (MY_LIN_S_ISLNK(mode))
240 {
241 AString s8;
242 if (item.GetSymLink(_archive.SuspSkipSize, s8))
243 {
244 UString s = MultiByteToUnicodeString(s8, CP_OEMCP);
245 prop = s;
246 }
247 }
248 }
249 }
250 break;
251
252
253 case kpidPosixAttrib:
254 /*
255 case kpidLinks:
256 case kpidUserId:
257 case kpidGroupId:
258 */
259 {
260 if (_archive.IsSusp)
261 {
262 UInt32 t = 0;
263 switch (propID)
264 {
265 case kpidPosixAttrib: t = k_Px_Mode; break;
266 /*
267 case kpidLinks: t = k_Px_Links; break;
268 case kpidUserId: t = k_Px_User; break;
269 case kpidGroupId: t = k_Px_Group; break;
270 */
271 }
272 UInt32 v;
273 if (item.GetPx(_archive.SuspSkipSize, t, v))
274 prop = v;
275 }
276 break;
277 }
278
279 case kpidIsDir: prop = item.IsDir(); break;
280 case kpidSize:
281 case kpidPackSize:
282 if (!item.IsDir())
283 prop = (UInt64)ref.TotalSize;
284 break;
285
286 case kpidMTime:
287 // case kpidCTime:
288 // case kpidATime:
289 {
290 // if
291 item.DateTime.GetFileTime(prop);
292 /*
293 else
294 {
295 UInt32 t = 0;
296 switch (propID)
297 {
298 case kpidMTime: t = k_Tf_MTime; break;
299 case kpidCTime: t = k_Tf_CTime; break;
300 case kpidATime: t = k_Tf_ATime; break;
301 }
302 CRecordingDateTime dt;
303 if (item.GetTf(_archive.SuspSkipSize, t, dt))
304 {
305 FILETIME utc;
306 if (dt.GetFileTime(utc))
307 prop = utc;
308 }
309 }
310 */
311 break;
312 }
313 }
314 }
315 prop.Detach(value);
316 return S_OK;
317 COM_TRY_END
318 }
319
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))320 Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
321 Int32 testMode, IArchiveExtractCallback *extractCallback))
322 {
323 COM_TRY_BEGIN
324 const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
325 if (allFilesMode)
326 numItems = _archive.Refs.Size();
327 if (numItems == 0)
328 return S_OK;
329 UInt64 totalSize = 0;
330 UInt32 i;
331 for (i = 0; i < numItems; i++)
332 {
333 UInt32 index = (allFilesMode ? i : indices[i]);
334 if (index < (UInt32)_archive.Refs.Size())
335 {
336 const CRef &ref = _archive.Refs[index];
337 const CDir &item = ref.Dir->_subItems[ref.Index];
338 if (!item.IsDir())
339 totalSize += ref.TotalSize;
340 }
341 else
342 totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
343 }
344 RINOK(extractCallback->SetTotal(totalSize))
345
346 UInt64 currentTotalSize = 0;
347 UInt64 currentItemSize;
348
349 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
350 lps->Init(extractCallback, false);
351 CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
352 CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
353 inStream->SetStream(_stream);
354
355 for (i = 0;; i++, currentTotalSize += currentItemSize)
356 {
357 lps->InSize = lps->OutSize = currentTotalSize;
358 RINOK(lps->SetCur())
359 if (i >= numItems)
360 break;
361 currentItemSize = 0;
362 Int32 opRes = NExtract::NOperationResult::kOK;
363 {
364 CMyComPtr<ISequentialOutStream> realOutStream;
365 const Int32 askMode = testMode ?
366 NExtract::NAskMode::kTest :
367 NExtract::NAskMode::kExtract;
368 const UInt32 index = allFilesMode ? i : indices[i];
369
370 RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
371
372 UInt64 blockIndex;
373 if (index < (UInt32)_archive.Refs.Size())
374 {
375 const CRef &ref = _archive.Refs[index];
376 const CDir &item = ref.Dir->_subItems[ref.Index];
377 if (item.IsDir())
378 {
379 RINOK(extractCallback->PrepareOperation(askMode))
380 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
381 continue;
382 }
383 currentItemSize = ref.TotalSize;
384 blockIndex = item.ExtentLocation;
385 }
386 else
387 {
388 unsigned bootIndex = index - _archive.Refs.Size();
389 const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
390 currentItemSize = _archive.GetBootItemSize(bootIndex);
391 blockIndex = be.LoadRBA;
392 }
393
394
395 if (!testMode && !realOutStream)
396 continue;
397
398 RINOK(extractCallback->PrepareOperation(askMode))
399
400 if (index < (UInt32)_archive.Refs.Size())
401 {
402 const CRef &ref = _archive.Refs[index];
403 UInt64 offset = 0;
404 for (UInt32 e = 0; e < ref.NumExtents; e++)
405 {
406 const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
407 if (item2.Size == 0)
408 continue;
409 lps->InSize = lps->OutSize = currentTotalSize + offset;
410 RINOK(InStream_SeekSet(_stream, (UInt64)item2.ExtentLocation * kBlockSize))
411 inStream->Init(item2.Size);
412 RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
413 if (copyCoder->TotalSize != item2.Size)
414 {
415 opRes = NExtract::NOperationResult::kDataError;
416 break;
417 }
418 offset += item2.Size;
419 }
420 }
421 else
422 {
423 RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize))
424 inStream->Init(currentItemSize);
425 RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
426 if (copyCoder->TotalSize != currentItemSize)
427 opRes = NExtract::NOperationResult::kDataError;
428 }
429 // realOutStream.Release();
430 }
431 RINOK(extractCallback->SetOperationResult(opRes))
432 }
433 return S_OK;
434 COM_TRY_END
435 }
436
Z7_COM7F_IMF(CHandler::GetStream (UInt32 index,ISequentialInStream ** stream))437 Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
438 {
439 COM_TRY_BEGIN
440 *stream = NULL;
441 UInt64 blockIndex;
442 UInt64 currentItemSize;
443
444 if (index < _archive.Refs.Size())
445 {
446 const CRef &ref = _archive.Refs[index];
447 const CDir &item = ref.Dir->_subItems[ref.Index];
448 if (item.IsDir())
449 return S_FALSE;
450
451 if (ref.NumExtents > 1)
452 {
453 CExtentsStream *extentStreamSpec = new CExtentsStream();
454 CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
455
456 extentStreamSpec->Stream = _stream;
457
458 UInt64 virtOffset = 0;
459 for (UInt32 i = 0; i < ref.NumExtents; i++)
460 {
461 const CDir &item2 = ref.Dir->_subItems[ref.Index + i];
462 if (item2.Size == 0)
463 continue;
464 CSeekExtent se;
465 se.Phy = (UInt64)item2.ExtentLocation * kBlockSize;
466 se.Virt = virtOffset;
467 extentStreamSpec->Extents.Add(se);
468 virtOffset += item2.Size;
469 }
470 if (virtOffset != ref.TotalSize)
471 return S_FALSE;
472 CSeekExtent se;
473 se.Phy = 0;
474 se.Virt = virtOffset;
475 extentStreamSpec->Extents.Add(se);
476 extentStreamSpec->Init();
477 *stream = extentStream.Detach();
478 return S_OK;
479 }
480
481 currentItemSize = item.Size;
482 blockIndex = item.ExtentLocation;
483 }
484 else
485 {
486 unsigned bootIndex = index - _archive.Refs.Size();
487 const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
488 currentItemSize = _archive.GetBootItemSize(bootIndex);
489 blockIndex = be.LoadRBA;
490 }
491
492 return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream);
493 COM_TRY_END
494 }
495
496 }}
497