view src/win32/7zip/7z/CPP/7zip/Archive/Split/SplitHandler.cpp @ 1:f9f4f1b99eed

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