tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SplitHandler.cpp (8603B)


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