1370b324cSopenharmony_ci// SplitHandler.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../Common/ComTry.h"
6370b324cSopenharmony_ci#include "../../Common/MyString.h"
7370b324cSopenharmony_ci
8370b324cSopenharmony_ci#include "../../Windows/PropVariant.h"
9370b324cSopenharmony_ci
10370b324cSopenharmony_ci#include "../Common/ProgressUtils.h"
11370b324cSopenharmony_ci#include "../Common/RegisterArc.h"
12370b324cSopenharmony_ci#include "../Common/StreamUtils.h"
13370b324cSopenharmony_ci
14370b324cSopenharmony_ci#include "../Compress/CopyCoder.h"
15370b324cSopenharmony_ci
16370b324cSopenharmony_ci#include "Common/MultiStream.h"
17370b324cSopenharmony_ci
18370b324cSopenharmony_ciusing namespace NWindows;
19370b324cSopenharmony_ci
20370b324cSopenharmony_cinamespace NArchive {
21370b324cSopenharmony_cinamespace NSplit {
22370b324cSopenharmony_ci
23370b324cSopenharmony_cistatic const Byte kProps[] =
24370b324cSopenharmony_ci{
25370b324cSopenharmony_ci  kpidPath,
26370b324cSopenharmony_ci  kpidSize
27370b324cSopenharmony_ci};
28370b324cSopenharmony_ci
29370b324cSopenharmony_cistatic const Byte kArcProps[] =
30370b324cSopenharmony_ci{
31370b324cSopenharmony_ci  kpidNumVolumes,
32370b324cSopenharmony_ci  kpidTotalPhySize
33370b324cSopenharmony_ci};
34370b324cSopenharmony_ci
35370b324cSopenharmony_ci
36370b324cSopenharmony_ciZ7_CLASS_IMP_CHandler_IInArchive_1(
37370b324cSopenharmony_ci  IInArchiveGetStream
38370b324cSopenharmony_ci)
39370b324cSopenharmony_ci  CObjectVector<CMyComPtr<IInStream> > _streams;
40370b324cSopenharmony_ci  CRecordVector<UInt64> _sizes;
41370b324cSopenharmony_ci  UString _subName;
42370b324cSopenharmony_ci  UInt64 _totalSize;
43370b324cSopenharmony_ci
44370b324cSopenharmony_ci  HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
45370b324cSopenharmony_ci};
46370b324cSopenharmony_ci
47370b324cSopenharmony_ciIMP_IInArchive_Props
48370b324cSopenharmony_ciIMP_IInArchive_ArcProps
49370b324cSopenharmony_ci
50370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
51370b324cSopenharmony_ci{
52370b324cSopenharmony_ci  NCOM::CPropVariant prop;
53370b324cSopenharmony_ci  switch (propID)
54370b324cSopenharmony_ci  {
55370b324cSopenharmony_ci    case kpidMainSubfile: prop = (UInt32)0; break;
56370b324cSopenharmony_ci    case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break;
57370b324cSopenharmony_ci    case kpidTotalPhySize: prop = _totalSize; break;
58370b324cSopenharmony_ci    case kpidNumVolumes: prop = (UInt32)_streams.Size(); break;
59370b324cSopenharmony_ci  }
60370b324cSopenharmony_ci  prop.Detach(value);
61370b324cSopenharmony_ci  return S_OK;
62370b324cSopenharmony_ci}
63370b324cSopenharmony_ci
64370b324cSopenharmony_cistruct CSeqName
65370b324cSopenharmony_ci{
66370b324cSopenharmony_ci  UString _unchangedPart;
67370b324cSopenharmony_ci  UString _changedPart;
68370b324cSopenharmony_ci  bool _splitStyle;
69370b324cSopenharmony_ci
70370b324cSopenharmony_ci  bool GetNextName(UString &s)
71370b324cSopenharmony_ci  {
72370b324cSopenharmony_ci    {
73370b324cSopenharmony_ci      unsigned i = _changedPart.Len();
74370b324cSopenharmony_ci      for (;;)
75370b324cSopenharmony_ci      {
76370b324cSopenharmony_ci        wchar_t c = _changedPart[--i];
77370b324cSopenharmony_ci
78370b324cSopenharmony_ci        if (_splitStyle)
79370b324cSopenharmony_ci        {
80370b324cSopenharmony_ci          if (c == 'z')
81370b324cSopenharmony_ci          {
82370b324cSopenharmony_ci            _changedPart.ReplaceOneCharAtPos(i, L'a');
83370b324cSopenharmony_ci            if (i == 0)
84370b324cSopenharmony_ci              return false;
85370b324cSopenharmony_ci            continue;
86370b324cSopenharmony_ci          }
87370b324cSopenharmony_ci          else if (c == 'Z')
88370b324cSopenharmony_ci          {
89370b324cSopenharmony_ci            _changedPart.ReplaceOneCharAtPos(i, L'A');
90370b324cSopenharmony_ci            if (i == 0)
91370b324cSopenharmony_ci              return false;
92370b324cSopenharmony_ci            continue;
93370b324cSopenharmony_ci          }
94370b324cSopenharmony_ci        }
95370b324cSopenharmony_ci        else
96370b324cSopenharmony_ci        {
97370b324cSopenharmony_ci          if (c == '9')
98370b324cSopenharmony_ci          {
99370b324cSopenharmony_ci            _changedPart.ReplaceOneCharAtPos(i, L'0');
100370b324cSopenharmony_ci            if (i == 0)
101370b324cSopenharmony_ci            {
102370b324cSopenharmony_ci              _changedPart.InsertAtFront(L'1');
103370b324cSopenharmony_ci              break;
104370b324cSopenharmony_ci            }
105370b324cSopenharmony_ci            continue;
106370b324cSopenharmony_ci          }
107370b324cSopenharmony_ci        }
108370b324cSopenharmony_ci
109370b324cSopenharmony_ci        c++;
110370b324cSopenharmony_ci        _changedPart.ReplaceOneCharAtPos(i, c);
111370b324cSopenharmony_ci        break;
112370b324cSopenharmony_ci      }
113370b324cSopenharmony_ci    }
114370b324cSopenharmony_ci
115370b324cSopenharmony_ci    s = _unchangedPart + _changedPart;
116370b324cSopenharmony_ci    return true;
117370b324cSopenharmony_ci  }
118370b324cSopenharmony_ci};
119370b324cSopenharmony_ci
120370b324cSopenharmony_ci
121370b324cSopenharmony_ciHRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
122370b324cSopenharmony_ci{
123370b324cSopenharmony_ci  Close();
124370b324cSopenharmony_ci  if (!callback)
125370b324cSopenharmony_ci    return S_FALSE;
126370b324cSopenharmony_ci
127370b324cSopenharmony_ci  Z7_DECL_CMyComPtr_QI_FROM(
128370b324cSopenharmony_ci      IArchiveOpenVolumeCallback,
129370b324cSopenharmony_ci      volumeCallback, callback)
130370b324cSopenharmony_ci  if (!volumeCallback)
131370b324cSopenharmony_ci    return S_FALSE;
132370b324cSopenharmony_ci
133370b324cSopenharmony_ci  UString name;
134370b324cSopenharmony_ci  {
135370b324cSopenharmony_ci    NCOM::CPropVariant prop;
136370b324cSopenharmony_ci    RINOK(volumeCallback->GetProperty(kpidName, &prop))
137370b324cSopenharmony_ci    if (prop.vt != VT_BSTR)
138370b324cSopenharmony_ci      return S_FALSE;
139370b324cSopenharmony_ci    name = prop.bstrVal;
140370b324cSopenharmony_ci  }
141370b324cSopenharmony_ci
142370b324cSopenharmony_ci  const int dotPos = name.ReverseFind_Dot();
143370b324cSopenharmony_ci  const UString prefix = name.Left((unsigned)(dotPos + 1));
144370b324cSopenharmony_ci  const UString ext = name.Ptr((unsigned)(dotPos + 1));
145370b324cSopenharmony_ci  UString ext2 = ext;
146370b324cSopenharmony_ci  ext2.MakeLower_Ascii();
147370b324cSopenharmony_ci
148370b324cSopenharmony_ci  CSeqName seqName;
149370b324cSopenharmony_ci
150370b324cSopenharmony_ci  unsigned numLetters = 2;
151370b324cSopenharmony_ci  bool splitStyle = false;
152370b324cSopenharmony_ci
153370b324cSopenharmony_ci  if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa"))
154370b324cSopenharmony_ci  {
155370b324cSopenharmony_ci    splitStyle = true;
156370b324cSopenharmony_ci    while (numLetters < ext2.Len())
157370b324cSopenharmony_ci    {
158370b324cSopenharmony_ci      if (ext2[ext2.Len() - numLetters - 1] != 'a')
159370b324cSopenharmony_ci        break;
160370b324cSopenharmony_ci      numLetters++;
161370b324cSopenharmony_ci    }
162370b324cSopenharmony_ci  }
163370b324cSopenharmony_ci  else if (ext2.Len() >= 2 && (
164370b324cSopenharmony_ci         StringsAreEqual_Ascii(ext2.RightPtr(2), "01")
165370b324cSopenharmony_ci      || StringsAreEqual_Ascii(ext2.RightPtr(2), "00")
166370b324cSopenharmony_ci      ))
167370b324cSopenharmony_ci  {
168370b324cSopenharmony_ci    while (numLetters < ext2.Len())
169370b324cSopenharmony_ci    {
170370b324cSopenharmony_ci      if (ext2[ext2.Len() - numLetters - 1] != '0')
171370b324cSopenharmony_ci        break;
172370b324cSopenharmony_ci      numLetters++;
173370b324cSopenharmony_ci    }
174370b324cSopenharmony_ci    if (numLetters != ext2.Len())
175370b324cSopenharmony_ci      return S_FALSE;
176370b324cSopenharmony_ci  }
177370b324cSopenharmony_ci  else
178370b324cSopenharmony_ci    return S_FALSE;
179370b324cSopenharmony_ci
180370b324cSopenharmony_ci  seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters);
181370b324cSopenharmony_ci  seqName._changedPart = ext.RightPtr(numLetters);
182370b324cSopenharmony_ci  seqName._splitStyle = splitStyle;
183370b324cSopenharmony_ci
184370b324cSopenharmony_ci  if (prefix.Len() < 1)
185370b324cSopenharmony_ci    _subName = "file";
186370b324cSopenharmony_ci  else
187370b324cSopenharmony_ci    _subName.SetFrom(prefix, prefix.Len() - 1);
188370b324cSopenharmony_ci
189370b324cSopenharmony_ci  UInt64 size;
190370b324cSopenharmony_ci  {
191370b324cSopenharmony_ci    /*
192370b324cSopenharmony_ci    NCOM::CPropVariant prop;
193370b324cSopenharmony_ci    RINOK(volumeCallback->GetProperty(kpidSize, &prop))
194370b324cSopenharmony_ci    if (prop.vt != VT_UI8)
195370b324cSopenharmony_ci      return E_INVALIDARG;
196370b324cSopenharmony_ci    size = prop.uhVal.QuadPart;
197370b324cSopenharmony_ci    */
198370b324cSopenharmony_ci  }
199370b324cSopenharmony_ci  RINOK(InStream_AtBegin_GetSize(stream, size))
200370b324cSopenharmony_ci
201370b324cSopenharmony_ci  _totalSize += size;
202370b324cSopenharmony_ci  _sizes.Add(size);
203370b324cSopenharmony_ci  _streams.Add(stream);
204370b324cSopenharmony_ci
205370b324cSopenharmony_ci  {
206370b324cSopenharmony_ci    const UInt64 numFiles = _streams.Size();
207370b324cSopenharmony_ci    RINOK(callback->SetCompleted(&numFiles, NULL))
208370b324cSopenharmony_ci  }
209370b324cSopenharmony_ci
210370b324cSopenharmony_ci  for (;;)
211370b324cSopenharmony_ci  {
212370b324cSopenharmony_ci    UString fullName;
213370b324cSopenharmony_ci    if (!seqName.GetNextName(fullName))
214370b324cSopenharmony_ci      break;
215370b324cSopenharmony_ci    CMyComPtr<IInStream> nextStream;
216370b324cSopenharmony_ci    const HRESULT result = volumeCallback->GetStream(fullName, &nextStream);
217370b324cSopenharmony_ci    if (result == S_FALSE)
218370b324cSopenharmony_ci      break;
219370b324cSopenharmony_ci    if (result != S_OK)
220370b324cSopenharmony_ci      return result;
221370b324cSopenharmony_ci    if (!nextStream)
222370b324cSopenharmony_ci      break;
223370b324cSopenharmony_ci    RINOK(InStream_AtBegin_GetSize(nextStream, size))
224370b324cSopenharmony_ci    _totalSize += size;
225370b324cSopenharmony_ci    _sizes.Add(size);
226370b324cSopenharmony_ci    _streams.Add(nextStream);
227370b324cSopenharmony_ci    {
228370b324cSopenharmony_ci      const UInt64 numFiles = _streams.Size();
229370b324cSopenharmony_ci      RINOK(callback->SetCompleted(&numFiles, NULL))
230370b324cSopenharmony_ci    }
231370b324cSopenharmony_ci  }
232370b324cSopenharmony_ci
233370b324cSopenharmony_ci  if (_streams.Size() == 1)
234370b324cSopenharmony_ci  {
235370b324cSopenharmony_ci    if (splitStyle)
236370b324cSopenharmony_ci      return S_FALSE;
237370b324cSopenharmony_ci  }
238370b324cSopenharmony_ci  return S_OK;
239370b324cSopenharmony_ci}
240370b324cSopenharmony_ci
241370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
242370b324cSopenharmony_ci{
243370b324cSopenharmony_ci  COM_TRY_BEGIN
244370b324cSopenharmony_ci  const HRESULT res = Open2(stream, callback);
245370b324cSopenharmony_ci  if (res != S_OK)
246370b324cSopenharmony_ci    Close();
247370b324cSopenharmony_ci  return res;
248370b324cSopenharmony_ci  COM_TRY_END
249370b324cSopenharmony_ci}
250370b324cSopenharmony_ci
251370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Close())
252370b324cSopenharmony_ci{
253370b324cSopenharmony_ci  _totalSize = 0;
254370b324cSopenharmony_ci  _subName.Empty();
255370b324cSopenharmony_ci  _streams.Clear();
256370b324cSopenharmony_ci  _sizes.Clear();
257370b324cSopenharmony_ci  return S_OK;
258370b324cSopenharmony_ci}
259370b324cSopenharmony_ci
260370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
261370b324cSopenharmony_ci{
262370b324cSopenharmony_ci  *numItems = _streams.IsEmpty() ? 0 : 1;
263370b324cSopenharmony_ci  return S_OK;
264370b324cSopenharmony_ci}
265370b324cSopenharmony_ci
266370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
267370b324cSopenharmony_ci{
268370b324cSopenharmony_ci  NCOM::CPropVariant prop;
269370b324cSopenharmony_ci  switch (propID)
270370b324cSopenharmony_ci  {
271370b324cSopenharmony_ci    case kpidPath: prop = _subName; break;
272370b324cSopenharmony_ci    case kpidSize:
273370b324cSopenharmony_ci    case kpidPackSize:
274370b324cSopenharmony_ci      prop = _totalSize;
275370b324cSopenharmony_ci      break;
276370b324cSopenharmony_ci  }
277370b324cSopenharmony_ci  prop.Detach(value);
278370b324cSopenharmony_ci  return S_OK;
279370b324cSopenharmony_ci}
280370b324cSopenharmony_ci
281370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
282370b324cSopenharmony_ci    Int32 testMode, IArchiveExtractCallback *extractCallback))
283370b324cSopenharmony_ci{
284370b324cSopenharmony_ci  COM_TRY_BEGIN
285370b324cSopenharmony_ci  if (numItems == 0)
286370b324cSopenharmony_ci    return S_OK;
287370b324cSopenharmony_ci  if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
288370b324cSopenharmony_ci    return E_INVALIDARG;
289370b324cSopenharmony_ci
290370b324cSopenharmony_ci  UInt64 currentTotalSize = 0;
291370b324cSopenharmony_ci  RINOK(extractCallback->SetTotal(_totalSize))
292370b324cSopenharmony_ci  CMyComPtr<ISequentialOutStream> outStream;
293370b324cSopenharmony_ci  const Int32 askMode = testMode ?
294370b324cSopenharmony_ci      NExtract::NAskMode::kTest :
295370b324cSopenharmony_ci      NExtract::NAskMode::kExtract;
296370b324cSopenharmony_ci  RINOK(extractCallback->GetStream(0, &outStream, askMode))
297370b324cSopenharmony_ci  if (!testMode && !outStream)
298370b324cSopenharmony_ci    return S_OK;
299370b324cSopenharmony_ci  RINOK(extractCallback->PrepareOperation(askMode))
300370b324cSopenharmony_ci
301370b324cSopenharmony_ci  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
302370b324cSopenharmony_ci  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
303370b324cSopenharmony_ci
304370b324cSopenharmony_ci  CLocalProgress *lps = new CLocalProgress;
305370b324cSopenharmony_ci  CMyComPtr<ICompressProgressInfo> progress = lps;
306370b324cSopenharmony_ci  lps->Init(extractCallback, false);
307370b324cSopenharmony_ci
308370b324cSopenharmony_ci  for (unsigned i = 0;; i++)
309370b324cSopenharmony_ci  {
310370b324cSopenharmony_ci    lps->InSize = lps->OutSize = currentTotalSize;
311370b324cSopenharmony_ci    RINOK(lps->SetCur())
312370b324cSopenharmony_ci    if (i == _streams.Size())
313370b324cSopenharmony_ci      break;
314370b324cSopenharmony_ci    IInStream *inStream = _streams[i];
315370b324cSopenharmony_ci    RINOK(InStream_SeekToBegin(inStream))
316370b324cSopenharmony_ci    RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
317370b324cSopenharmony_ci    currentTotalSize += copyCoderSpec->TotalSize;
318370b324cSopenharmony_ci  }
319370b324cSopenharmony_ci  outStream.Release();
320370b324cSopenharmony_ci  return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
321370b324cSopenharmony_ci  COM_TRY_END
322370b324cSopenharmony_ci}
323370b324cSopenharmony_ci
324370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
325370b324cSopenharmony_ci{
326370b324cSopenharmony_ci  COM_TRY_BEGIN
327370b324cSopenharmony_ci  if (index != 0)
328370b324cSopenharmony_ci    return E_INVALIDARG;
329370b324cSopenharmony_ci  *stream = NULL;
330370b324cSopenharmony_ci  CMultiStream *streamSpec = new CMultiStream;
331370b324cSopenharmony_ci  CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
332370b324cSopenharmony_ci  FOR_VECTOR (i, _streams)
333370b324cSopenharmony_ci  {
334370b324cSopenharmony_ci    CMultiStream::CSubStreamInfo subStreamInfo;
335370b324cSopenharmony_ci    subStreamInfo.Stream = _streams[i];
336370b324cSopenharmony_ci    subStreamInfo.Size = _sizes[i];
337370b324cSopenharmony_ci    streamSpec->Streams.Add(subStreamInfo);
338370b324cSopenharmony_ci  }
339370b324cSopenharmony_ci  streamSpec->Init();
340370b324cSopenharmony_ci  *stream = streamTemp.Detach();
341370b324cSopenharmony_ci  return S_OK;
342370b324cSopenharmony_ci  COM_TRY_END
343370b324cSopenharmony_ci}
344370b324cSopenharmony_ci
345370b324cSopenharmony_ciREGISTER_ARC_I_NO_SIG(
346370b324cSopenharmony_ci  "Split", "001", NULL, 0xEA,
347370b324cSopenharmony_ci  0,
348370b324cSopenharmony_ci  0,
349370b324cSopenharmony_ci  NULL)
350370b324cSopenharmony_ci
351370b324cSopenharmony_ci}}
352