rlm@1
|
1 // SplitHandler.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Common/ComTry.h"
|
rlm@1
|
6 #include "Common/Defs.h"
|
rlm@1
|
7 #include "Common/NewHandler.h"
|
rlm@1
|
8 #include "Common/StringConvert.h"
|
rlm@1
|
9
|
rlm@1
|
10 #include "Windows/PropVariant.h"
|
rlm@1
|
11 #include "Windows/Time.h"
|
rlm@1
|
12
|
rlm@1
|
13 #include "../../Common/ProgressUtils.h"
|
rlm@1
|
14
|
rlm@1
|
15 #include "../../Compress/CopyCoder.h"
|
rlm@1
|
16
|
rlm@1
|
17 #include "../Common/ItemNameUtils.h"
|
rlm@1
|
18 #include "../Common/MultiStream.h"
|
rlm@1
|
19
|
rlm@1
|
20 #include "SplitHandler.h"
|
rlm@1
|
21
|
rlm@1
|
22 using namespace NWindows;
|
rlm@1
|
23 using namespace NTime;
|
rlm@1
|
24
|
rlm@1
|
25 namespace NArchive {
|
rlm@1
|
26 namespace NSplit {
|
rlm@1
|
27
|
rlm@1
|
28 STATPROPSTG kProps[] =
|
rlm@1
|
29 {
|
rlm@1
|
30 { NULL, kpidPath, VT_BSTR},
|
rlm@1
|
31 { NULL, kpidSize, VT_UI8},
|
rlm@1
|
32 { NULL, kpidPackSize, VT_UI8},
|
rlm@1
|
33 };
|
rlm@1
|
34
|
rlm@1
|
35 IMP_IInArchive_Props
|
rlm@1
|
36 IMP_IInArchive_ArcProps_NO
|
rlm@1
|
37
|
rlm@1
|
38 class CSeqName
|
rlm@1
|
39 {
|
rlm@1
|
40 public:
|
rlm@1
|
41 UString _unchangedPart;
|
rlm@1
|
42 UString _changedPart;
|
rlm@1
|
43 bool _splitStyle;
|
rlm@1
|
44 UString GetNextName()
|
rlm@1
|
45 {
|
rlm@1
|
46 UString newName;
|
rlm@1
|
47 if (_splitStyle)
|
rlm@1
|
48 {
|
rlm@1
|
49 int i;
|
rlm@1
|
50 int numLetters = _changedPart.Length();
|
rlm@1
|
51 for (i = numLetters - 1; i >= 0; i--)
|
rlm@1
|
52 {
|
rlm@1
|
53 wchar_t c = _changedPart[i];
|
rlm@1
|
54 if (c == 'z')
|
rlm@1
|
55 {
|
rlm@1
|
56 c = 'a';
|
rlm@1
|
57 newName = c + newName;
|
rlm@1
|
58 continue;
|
rlm@1
|
59 }
|
rlm@1
|
60 else if (c == 'Z')
|
rlm@1
|
61 {
|
rlm@1
|
62 c = 'A';
|
rlm@1
|
63 newName = c + newName;
|
rlm@1
|
64 continue;
|
rlm@1
|
65 }
|
rlm@1
|
66 c++;
|
rlm@1
|
67 if ((c == 'z' || c == 'Z') && i == 0)
|
rlm@1
|
68 {
|
rlm@1
|
69 _unchangedPart += c;
|
rlm@1
|
70 wchar_t newChar = (c == 'z') ? L'a' : L'A';
|
rlm@1
|
71 newName.Empty();
|
rlm@1
|
72 numLetters++;
|
rlm@1
|
73 for (int k = 0; k < numLetters; k++)
|
rlm@1
|
74 newName += newChar;
|
rlm@1
|
75 break;
|
rlm@1
|
76 }
|
rlm@1
|
77 newName = c + newName;
|
rlm@1
|
78 i--;
|
rlm@1
|
79 for (; i >= 0; i--)
|
rlm@1
|
80 newName = _changedPart[i] + newName;
|
rlm@1
|
81 break;
|
rlm@1
|
82 }
|
rlm@1
|
83 }
|
rlm@1
|
84 else
|
rlm@1
|
85 {
|
rlm@1
|
86 int i;
|
rlm@1
|
87 int numLetters = _changedPart.Length();
|
rlm@1
|
88 for (i = numLetters - 1; i >= 0; i--)
|
rlm@1
|
89 {
|
rlm@1
|
90 wchar_t c = _changedPart[i];
|
rlm@1
|
91 if (c == L'9')
|
rlm@1
|
92 {
|
rlm@1
|
93 c = L'0';
|
rlm@1
|
94 newName = c + newName;
|
rlm@1
|
95 if (i == 0)
|
rlm@1
|
96 newName = UString(L'1') + newName;
|
rlm@1
|
97 continue;
|
rlm@1
|
98 }
|
rlm@1
|
99 c++;
|
rlm@1
|
100 newName = c + newName;
|
rlm@1
|
101 i--;
|
rlm@1
|
102 for (; i >= 0; i--)
|
rlm@1
|
103 newName = _changedPart[i] + newName;
|
rlm@1
|
104 break;
|
rlm@1
|
105 }
|
rlm@1
|
106 }
|
rlm@1
|
107 _changedPart = newName;
|
rlm@1
|
108 return _unchangedPart + _changedPart;
|
rlm@1
|
109 }
|
rlm@1
|
110 };
|
rlm@1
|
111
|
rlm@1
|
112 STDMETHODIMP CHandler::Open(IInStream *stream,
|
rlm@1
|
113 const UInt64 * /* maxCheckStartPosition */,
|
rlm@1
|
114 IArchiveOpenCallback *openArchiveCallback)
|
rlm@1
|
115 {
|
rlm@1
|
116 COM_TRY_BEGIN
|
rlm@1
|
117 Close();
|
rlm@1
|
118 if (openArchiveCallback == 0)
|
rlm@1
|
119 return S_FALSE;
|
rlm@1
|
120 // try
|
rlm@1
|
121 {
|
rlm@1
|
122 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
rlm@1
|
123 CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
|
rlm@1
|
124 if (openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback,
|
rlm@1
|
125 &openVolumeCallback) != S_OK)
|
rlm@1
|
126 return S_FALSE;
|
rlm@1
|
127
|
rlm@1
|
128 {
|
rlm@1
|
129 NCOM::CPropVariant prop;
|
rlm@1
|
130 RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
|
rlm@1
|
131 if (prop.vt != VT_BSTR)
|
rlm@1
|
132 return S_FALSE;
|
rlm@1
|
133 _name = prop.bstrVal;
|
rlm@1
|
134 }
|
rlm@1
|
135
|
rlm@1
|
136 int dotPos = _name.ReverseFind('.');
|
rlm@1
|
137 UString prefix, ext;
|
rlm@1
|
138 if (dotPos >= 0)
|
rlm@1
|
139 {
|
rlm@1
|
140 prefix = _name.Left(dotPos + 1);
|
rlm@1
|
141 ext = _name.Mid(dotPos + 1);
|
rlm@1
|
142 }
|
rlm@1
|
143 else
|
rlm@1
|
144 ext = _name;
|
rlm@1
|
145 UString extBig = ext;
|
rlm@1
|
146 extBig.MakeUpper();
|
rlm@1
|
147
|
rlm@1
|
148 CSeqName seqName;
|
rlm@1
|
149
|
rlm@1
|
150 int numLetters = 2;
|
rlm@1
|
151 bool splitStyle = false;
|
rlm@1
|
152 if (extBig.Right(2) == L"AA")
|
rlm@1
|
153 {
|
rlm@1
|
154 splitStyle = true;
|
rlm@1
|
155 while (numLetters < extBig.Length())
|
rlm@1
|
156 {
|
rlm@1
|
157 if (extBig[extBig.Length() - numLetters - 1] != 'A')
|
rlm@1
|
158 break;
|
rlm@1
|
159 numLetters++;
|
rlm@1
|
160 }
|
rlm@1
|
161 }
|
rlm@1
|
162 else if (ext.Right(2) == L"01")
|
rlm@1
|
163 {
|
rlm@1
|
164 while (numLetters < extBig.Length())
|
rlm@1
|
165 {
|
rlm@1
|
166 if (extBig[extBig.Length() - numLetters - 1] != '0')
|
rlm@1
|
167 break;
|
rlm@1
|
168 numLetters++;
|
rlm@1
|
169 }
|
rlm@1
|
170 if (numLetters != ext.Length())
|
rlm@1
|
171 return S_FALSE;
|
rlm@1
|
172 }
|
rlm@1
|
173 else
|
rlm@1
|
174 return S_FALSE;
|
rlm@1
|
175
|
rlm@1
|
176 _streams.Add(stream);
|
rlm@1
|
177
|
rlm@1
|
178 seqName._unchangedPart = prefix + ext.Left(extBig.Length() - numLetters);
|
rlm@1
|
179 seqName._changedPart = ext.Right(numLetters);
|
rlm@1
|
180 seqName._splitStyle = splitStyle;
|
rlm@1
|
181
|
rlm@1
|
182 if (prefix.Length() < 1)
|
rlm@1
|
183 _subName = L"file";
|
rlm@1
|
184 else
|
rlm@1
|
185 _subName = prefix.Left(prefix.Length() - 1);
|
rlm@1
|
186
|
rlm@1
|
187 _totalSize = 0;
|
rlm@1
|
188 UInt64 size;
|
rlm@1
|
189 {
|
rlm@1
|
190 NCOM::CPropVariant prop;
|
rlm@1
|
191 RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
|
rlm@1
|
192 if (prop.vt != VT_UI8)
|
rlm@1
|
193 return E_INVALIDARG;
|
rlm@1
|
194 size = prop.uhVal.QuadPart;
|
rlm@1
|
195 }
|
rlm@1
|
196 _totalSize += size;
|
rlm@1
|
197 _sizes.Add(size);
|
rlm@1
|
198
|
rlm@1
|
199 if (openArchiveCallback != NULL)
|
rlm@1
|
200 {
|
rlm@1
|
201 UInt64 numFiles = _streams.Size();
|
rlm@1
|
202 RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
|
rlm@1
|
203 }
|
rlm@1
|
204
|
rlm@1
|
205 for (;;)
|
rlm@1
|
206 {
|
rlm@1
|
207 UString fullName = seqName.GetNextName();
|
rlm@1
|
208 CMyComPtr<IInStream> nextStream;
|
rlm@1
|
209 HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
|
rlm@1
|
210 if (result == S_FALSE)
|
rlm@1
|
211 break;
|
rlm@1
|
212 if (result != S_OK)
|
rlm@1
|
213 return result;
|
rlm@1
|
214 if (!stream)
|
rlm@1
|
215 break;
|
rlm@1
|
216 {
|
rlm@1
|
217 NCOM::CPropVariant prop;
|
rlm@1
|
218 RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
|
rlm@1
|
219 if (prop.vt != VT_UI8)
|
rlm@1
|
220 return E_INVALIDARG;
|
rlm@1
|
221 size = prop.uhVal.QuadPart;
|
rlm@1
|
222 }
|
rlm@1
|
223 _totalSize += size;
|
rlm@1
|
224 _sizes.Add(size);
|
rlm@1
|
225 _streams.Add(nextStream);
|
rlm@1
|
226 if (openArchiveCallback != NULL)
|
rlm@1
|
227 {
|
rlm@1
|
228 UInt64 numFiles = _streams.Size();
|
rlm@1
|
229 RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
|
rlm@1
|
230 }
|
rlm@1
|
231 }
|
rlm@1
|
232 }
|
rlm@1
|
233 /*
|
rlm@1
|
234 catch(...)
|
rlm@1
|
235 {
|
rlm@1
|
236 return S_FALSE;
|
rlm@1
|
237 }
|
rlm@1
|
238 */
|
rlm@1
|
239 return S_OK;
|
rlm@1
|
240 COM_TRY_END
|
rlm@1
|
241 }
|
rlm@1
|
242
|
rlm@1
|
243 STDMETHODIMP CHandler::Close()
|
rlm@1
|
244 {
|
rlm@1
|
245 _sizes.Clear();
|
rlm@1
|
246 _streams.Clear();
|
rlm@1
|
247 return S_OK;
|
rlm@1
|
248 }
|
rlm@1
|
249
|
rlm@1
|
250 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
rlm@1
|
251 {
|
rlm@1
|
252 *numItems = _streams.IsEmpty() ? 0 : 1;
|
rlm@1
|
253 return S_OK;
|
rlm@1
|
254 }
|
rlm@1
|
255
|
rlm@1
|
256 STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
|
rlm@1
|
257 {
|
rlm@1
|
258 NWindows::NCOM::CPropVariant prop;
|
rlm@1
|
259 switch(propID)
|
rlm@1
|
260 {
|
rlm@1
|
261 case kpidPath:
|
rlm@1
|
262 prop = _subName;
|
rlm@1
|
263 break;
|
rlm@1
|
264 case kpidSize:
|
rlm@1
|
265 case kpidPackSize:
|
rlm@1
|
266 prop = _totalSize;
|
rlm@1
|
267 break;
|
rlm@1
|
268 }
|
rlm@1
|
269 prop.Detach(value);
|
rlm@1
|
270 return S_OK;
|
rlm@1
|
271 }
|
rlm@1
|
272
|
rlm@1
|
273 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
rlm@1
|
274 Int32 _aTestMode, IArchiveExtractCallback *_anExtractCallback)
|
rlm@1
|
275 {
|
rlm@1
|
276 COM_TRY_BEGIN
|
rlm@1
|
277
|
rlm@1
|
278 if (numItems != UInt32(-1))
|
rlm@1
|
279 {
|
rlm@1
|
280 if (numItems != 1)
|
rlm@1
|
281 return E_INVALIDARG;
|
rlm@1
|
282 if (indices[0] != 0)
|
rlm@1
|
283 return E_INVALIDARG;
|
rlm@1
|
284 }
|
rlm@1
|
285 bool testMode = (_aTestMode != 0);
|
rlm@1
|
286 CMyComPtr<IArchiveExtractCallback> extractCallback = _anExtractCallback;
|
rlm@1
|
287 extractCallback->SetTotal(_totalSize);
|
rlm@1
|
288
|
rlm@1
|
289 /*
|
rlm@1
|
290 CMyComPtr<IArchiveVolumeExtractCallback> volumeExtractCallback;
|
rlm@1
|
291 if (extractCallback.QueryInterface(&volumeExtractCallback) != S_OK)
|
rlm@1
|
292 return E_FAIL;
|
rlm@1
|
293 */
|
rlm@1
|
294
|
rlm@1
|
295 UInt64 currentTotalSize = 0;
|
rlm@1
|
296 UInt64 currentItemSize;
|
rlm@1
|
297
|
rlm@1
|
298 RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
rlm@1
|
299 CMyComPtr<ISequentialOutStream> realOutStream;
|
rlm@1
|
300 Int32 askMode;
|
rlm@1
|
301 askMode = testMode ? NArchive::NExtract::NAskMode::kTest :
|
rlm@1
|
302 NArchive::NExtract::NAskMode::kExtract;
|
rlm@1
|
303 Int32 index = 0;
|
rlm@1
|
304 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
rlm@1
|
305
|
rlm@1
|
306 RINOK(extractCallback->PrepareOperation(askMode));
|
rlm@1
|
307 if (testMode)
|
rlm@1
|
308 {
|
rlm@1
|
309 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
rlm@1
|
310 return S_OK;
|
rlm@1
|
311 }
|
rlm@1
|
312
|
rlm@1
|
313 if (!testMode && (!realOutStream))
|
rlm@1
|
314 return S_OK;
|
rlm@1
|
315
|
rlm@1
|
316 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
|
rlm@1
|
317 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
rlm@1
|
318
|
rlm@1
|
319 CLocalProgress *lps = new CLocalProgress;
|
rlm@1
|
320 CMyComPtr<ICompressProgressInfo> progress = lps;
|
rlm@1
|
321 lps->Init(extractCallback, false);
|
rlm@1
|
322
|
rlm@1
|
323 for (int i = 0; i < _streams.Size(); i++, currentTotalSize += currentItemSize)
|
rlm@1
|
324 {
|
rlm@1
|
325 lps->InSize = lps->OutSize = currentTotalSize;
|
rlm@1
|
326 RINOK(lps->SetCur());
|
rlm@1
|
327 IInStream *inStream = _streams[i];
|
rlm@1
|
328 RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
|
rlm@1
|
329 RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
rlm@1
|
330 currentItemSize = copyCoderSpec->TotalSize;
|
rlm@1
|
331 }
|
rlm@1
|
332 realOutStream.Release();
|
rlm@1
|
333 return extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK);
|
rlm@1
|
334 COM_TRY_END
|
rlm@1
|
335 }
|
rlm@1
|
336
|
rlm@1
|
337 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
rlm@1
|
338 {
|
rlm@1
|
339 if (index != 0)
|
rlm@1
|
340 return E_INVALIDARG;
|
rlm@1
|
341 *stream = 0;
|
rlm@1
|
342 CMultiStream *streamSpec = new CMultiStream;
|
rlm@1
|
343 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
|
rlm@1
|
344 for (int i = 0; i < _streams.Size(); i++)
|
rlm@1
|
345 {
|
rlm@1
|
346 CMultiStream::CSubStreamInfo subStreamInfo;
|
rlm@1
|
347 subStreamInfo.Stream = _streams[i];
|
rlm@1
|
348 subStreamInfo.Pos = 0;
|
rlm@1
|
349 subStreamInfo.Size = _sizes[i];
|
rlm@1
|
350 streamSpec->Streams.Add(subStreamInfo);
|
rlm@1
|
351 }
|
rlm@1
|
352 streamSpec->Init();
|
rlm@1
|
353 *stream = streamTemp.Detach();
|
rlm@1
|
354 return S_OK;
|
rlm@1
|
355 }
|
rlm@1
|
356
|
rlm@1
|
357 }}
|