1 // Bz2Handler.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../Common/ComTry.h"
6
7 #include "../Common/ProgressUtils.h"
8 #include "../Common/RegisterArc.h"
9 #include "../Common/StreamUtils.h"
10
11 #include "../Compress/BZip2Decoder.h"
12 #include "../Compress/BZip2Encoder.h"
13 #include "../Compress/CopyCoder.h"
14
15 #include "Common/DummyOutStream.h"
16 #include "Common/HandlerOut.h"
17
18 using namespace NWindows;
19
20 namespace NArchive {
21 namespace NBz2 {
22
23 Z7_CLASS_IMP_CHandler_IInArchive_3(
24 IArchiveOpenSeq,
25 IOutArchive,
26 ISetProperties
27 )
28 CMyComPtr<IInStream> _stream;
29 CMyComPtr<ISequentialInStream> _seqStream;
30
31 bool _isArc;
32 bool _needSeekToStart;
33 bool _dataAfterEnd;
34 bool _needMoreInput;
35
36 bool _packSize_Defined;
37 bool _unpackSize_Defined;
38 bool _numStreams_Defined;
39 bool _numBlocks_Defined;
40
41 UInt64 _packSize;
42 UInt64 _unpackSize;
43 UInt64 _numStreams;
44 UInt64 _numBlocks;
45
46 CSingleMethodProps _props;
47 };
48
49 static const Byte kProps[] =
50 {
51 kpidSize,
52 kpidPackSize
53 };
54
55 static const Byte kArcProps[] =
56 {
57 kpidNumStreams,
58 kpidNumBlocks
59 };
60
61 IMP_IInArchive_Props
62 IMP_IInArchive_ArcProps
63
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))64 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
65 {
66 NCOM::CPropVariant prop;
67 switch (propID)
68 {
69 case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
70 case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
71 case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
72 case kpidNumBlocks: if (_numBlocks_Defined) prop = _numBlocks; break;
73 case kpidErrorFlags:
74 {
75 UInt32 v = 0;
76 if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
77 if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
78 if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
79 prop = v;
80 break;
81 }
82 default: break;
83 }
84 prop.Detach(value);
85 return S_OK;
86 }
87
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))88 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
89 {
90 *numItems = 1;
91 return S_OK;
92 }
93
Z7_COM7F_IMF(CHandler::GetProperty (UInt32,PROPID propID,PROPVARIANT * value))94 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
95 {
96 NCOM::CPropVariant prop;
97 switch (propID)
98 {
99 case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
100 case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
101 default: break;
102 }
103 prop.Detach(value);
104 return S_OK;
105 }
106
107 static const unsigned kSignatureCheckSize = 10;
108
IsArc_BZip2(const Byte * p,size_t size)109 API_FUNC_static_IsArc IsArc_BZip2(const Byte *p, size_t size)
110 {
111 if (size < kSignatureCheckSize)
112 return k_IsArc_Res_NEED_MORE;
113 if (p[0] != 'B' || p[1] != 'Z' || p[2] != 'h' || p[3] < '1' || p[3] > '9')
114 return k_IsArc_Res_NO;
115 p += 4;
116 if (NCompress::NBZip2::IsBlockSig(p))
117 return k_IsArc_Res_YES;
118 if (NCompress::NBZip2::IsEndSig(p))
119 return k_IsArc_Res_YES;
120 return k_IsArc_Res_NO;
121 }
122 }
123
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback *))124 Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
125 {
126 COM_TRY_BEGIN
127 Close();
128 {
129 Byte buf[kSignatureCheckSize];
130 RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize))
131 if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO)
132 return S_FALSE;
133 _isArc = true;
134 _stream = stream;
135 _seqStream = stream;
136 _needSeekToStart = true;
137 }
138 return S_OK;
139 COM_TRY_END
140 }
141
142
Z7_COM7F_IMF(CHandler::OpenSeq (ISequentialInStream * stream))143 Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
144 {
145 Close();
146 _isArc = true;
147 _seqStream = stream;
148 return S_OK;
149 }
150
Z7_COM7F_IMF(CHandler::Close ())151 Z7_COM7F_IMF(CHandler::Close())
152 {
153 _isArc = false;
154 _needSeekToStart = false;
155 _dataAfterEnd = false;
156 _needMoreInput = false;
157
158 _packSize_Defined = false;
159 _unpackSize_Defined = false;
160 _numStreams_Defined = false;
161 _numBlocks_Defined = false;
162
163 _packSize = 0;
164
165 _seqStream.Release();
166 _stream.Release();
167 return S_OK;
168 }
169
170
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))171 Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
172 Int32 testMode, IArchiveExtractCallback *extractCallback))
173 {
174 COM_TRY_BEGIN
175 if (numItems == 0)
176 return S_OK;
177 if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
178 return E_INVALIDARG;
179
180 if (_packSize_Defined)
181 {
182 RINOK(extractCallback->SetTotal(_packSize))
183 }
184
185 Int32 opRes;
186 {
187 CMyComPtr<ISequentialOutStream> realOutStream;
188 const Int32 askMode = testMode ?
189 NExtract::NAskMode::kTest :
190 NExtract::NAskMode::kExtract;
191 RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
192 if (!testMode && !realOutStream)
193 return S_OK;
194
195 RINOK(extractCallback->PrepareOperation(askMode))
196
197 if (_needSeekToStart)
198 {
199 if (!_stream)
200 return E_FAIL;
201 RINOK(InStream_SeekToBegin(_stream))
202 }
203 else
204 _needSeekToStart = true;
205
206 // try {
207
208 CMyComPtr2_Create<ICompressCoder, NCompress::NBZip2::CDecoder> decoder;
209
210 #ifndef Z7_ST
211 RINOK(decoder->SetNumberOfThreads(_props._numThreads))
212 #endif
213
214 CMyComPtr2_Create<ISequentialOutStream, CDummyOutStream> outStream;
215 outStream->SetStream(realOutStream);
216 outStream->Init();
217 // realOutStream.Release();
218
219 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
220 lps->Init(extractCallback, true);
221
222 decoder->FinishMode = true;
223 decoder->Base.DecodeAllStreams = true;
224
225 _dataAfterEnd = false;
226 _needMoreInput = false;
227
228 HRESULT result = decoder.Interface()->Code(_seqStream, outStream, NULL, NULL, lps);
229
230 if (result != S_FALSE && result != S_OK)
231 return result;
232
233 if (decoder->Base.NumStreams == 0)
234 {
235 _isArc = false;
236 result = S_FALSE;
237 }
238 else
239 {
240 const UInt64 inProcessedSize = decoder->GetInputProcessedSize();
241 UInt64 packSize = inProcessedSize;
242
243 if (decoder->Base.NeedMoreInput)
244 _needMoreInput = true;
245
246 if (!decoder->Base.IsBz)
247 {
248 packSize = decoder->Base.FinishedPackSize;
249 if (packSize != inProcessedSize)
250 _dataAfterEnd = true;
251 }
252
253 _packSize = packSize;
254 _unpackSize = decoder->GetOutProcessedSize();
255 _numStreams = decoder->Base.NumStreams;
256 _numBlocks = decoder->GetNumBlocks();
257
258 _packSize_Defined = true;
259 _unpackSize_Defined = true;
260 _numStreams_Defined = true;
261 _numBlocks_Defined = true;
262
263 // RINOK(
264 lps.Interface()->SetRatioInfo(&packSize, &_unpackSize);
265 }
266
267 // outStream.Release();
268
269 if (!_isArc)
270 opRes = NExtract::NOperationResult::kIsNotArc;
271 else if (_needMoreInput)
272 opRes = NExtract::NOperationResult::kUnexpectedEnd;
273 else if (decoder->GetCrcError())
274 opRes = NExtract::NOperationResult::kCRCError;
275 else if (_dataAfterEnd)
276 opRes = NExtract::NOperationResult::kDataAfterEnd;
277 else if (result == S_FALSE)
278 opRes = NExtract::NOperationResult::kDataError;
279 else if (decoder->Base.MinorError)
280 opRes = NExtract::NOperationResult::kDataError;
281 else if (result == S_OK)
282 opRes = NExtract::NOperationResult::kOK;
283 else
284 return result;
285
286 }
287 return extractCallback->SetOperationResult(opRes);
288
289 // } catch(...) { return E_FAIL; }
290
291 COM_TRY_END
292 }
293
294
295 /*
296 static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
297 {
298 return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
299 }
300
301 static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
302 {
303 return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
304 }
305
306 static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
307 const UInt64 *unpackSize,
308 const UInt64 *numBlocks)
309 {
310 NCOM::CPropVariant sizeProp;
311 if (unpackSize)
312 {
313 sizeProp = *unpackSize;
314 RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
315 RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
316 }
317
318 if (unpackSize)
319 {
320 RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
321 }
322 if (numBlocks)
323 {
324 NCOM::CPropVariant prop;
325 prop = *numBlocks;
326 RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop));
327 }
328 return S_OK;
329 }
330 */
331
UpdateArchive(UInt64 unpackSize,ISequentialOutStream * outStream,const CProps & props,IArchiveUpdateCallback * updateCallback)332 static HRESULT UpdateArchive(
333 UInt64 unpackSize,
334 ISequentialOutStream *outStream,
335 const CProps &props,
336 IArchiveUpdateCallback *updateCallback
337 // , ArchiveUpdateCallbackArcProp *reportArcProp
338 )
339 {
340 {
341 CMyComPtr<ISequentialInStream> fileInStream;
342 RINOK(updateCallback->GetStream(0, &fileInStream))
343 if (!fileInStream)
344 return S_FALSE;
345 {
346 Z7_DECL_CMyComPtr_QI_FROM(
347 IStreamGetSize,
348 streamGetSize, fileInStream)
349 if (streamGetSize)
350 {
351 UInt64 size;
352 if (streamGetSize->GetSize(&size) == S_OK)
353 unpackSize = size;
354 }
355 }
356 RINOK(updateCallback->SetTotal(unpackSize))
357
358 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
359 lps->Init(updateCallback, true);
360 {
361 CMyComPtr2_Create<ICompressCoder, NCompress::NBZip2::CEncoder> encoder;
362 RINOK(props.SetCoderProps(encoder.ClsPtr(), NULL))
363 RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps))
364 /*
365 if (reportArcProp)
366 {
367 unpackSize = encoderSpec->GetInProcessedSize();
368 RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks));
369 }
370 */
371 }
372 }
373 return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
374 }
375
Z7_COM7F_IMF(CHandler::GetFileTimeType (UInt32 * timeType))376 Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
377 {
378 *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
379 // *timeType = NFileTimeType::kUnix;
380 return S_OK;
381 }
382
Z7_COM7F_IMF(CHandler::UpdateItems (ISequentialOutStream * outStream,UInt32 numItems,IArchiveUpdateCallback * updateCallback))383 Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
384 IArchiveUpdateCallback *updateCallback))
385 {
386 COM_TRY_BEGIN
387
388 if (numItems != 1)
389 return E_INVALIDARG;
390
391 {
392 Z7_DECL_CMyComPtr_QI_FROM(
393 IStreamSetRestriction,
394 setRestriction, outStream)
395 if (setRestriction)
396 RINOK(setRestriction->SetRestriction(0, 0))
397 }
398
399 Int32 newData, newProps;
400 UInt32 indexInArchive;
401 if (!updateCallback)
402 return E_FAIL;
403 RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
404
405 // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback)
406
407 if (IntToBool(newProps))
408 {
409 {
410 NCOM::CPropVariant prop;
411 RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
412 if (prop.vt != VT_EMPTY)
413 if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
414 return E_INVALIDARG;
415 }
416 }
417
418 if (IntToBool(newData))
419 {
420 UInt64 size;
421 {
422 NCOM::CPropVariant prop;
423 RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
424 if (prop.vt != VT_UI8)
425 return E_INVALIDARG;
426 size = prop.uhVal.QuadPart;
427 }
428
429 CMethodProps props2 = _props;
430 #ifndef Z7_ST
431 props2.AddProp_NumThreads(_props._numThreads);
432 #endif
433
434 return UpdateArchive(size, outStream, props2, updateCallback);
435 }
436
437 if (indexInArchive != 0)
438 return E_INVALIDARG;
439
440 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
441 lps->Init(updateCallback, true);
442
443 Z7_DECL_CMyComPtr_QI_FROM(
444 IArchiveUpdateCallbackFile,
445 opCallback, updateCallback)
446 if (opCallback)
447 {
448 RINOK(opCallback->ReportOperation(
449 NEventIndexType::kInArcIndex, 0,
450 NUpdateNotifyOp::kReplicate))
451 }
452
453 if (_stream)
454 RINOK(InStream_SeekToBegin(_stream))
455
456 return NCompress::CopyStream(_stream, outStream, lps);
457
458 // return ReportArcProps(reportArcProp, NULL, NULL);
459
460 COM_TRY_END
461 }
462
Z7_COM7F_IMF(CHandler::SetProperties (const wchar_t * const * names,const PROPVARIANT * values,UInt32 numProps))463 Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
464 {
465 return _props.SetProperties(names, values, numProps);
466 }
467
468 static const Byte k_Signature[] = { 'B', 'Z', 'h' };
469
470 REGISTER_ARC_IO(
471 "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
472 k_Signature,
473 0,
474 NArcInfoFlags::kKeepName
475 , 0
476 , IsArc_BZip2)
477
478 }}
479