annotate 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
rev   line source
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(&currentTotalSize));
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 }}