Exemplo n.º 1
0
UString GetMyDocsPath()
{
  UString us;
  WCHAR s[MAX_PATH + 1];
  SHGetSpecialFolderPathWp getW = (SHGetSpecialFolderPathWp)
      #ifdef UNDER_CE
      My_GetProcAddress(GetModuleHandle(TEXT("coredll.dll")), "SHGetSpecialFolderPath");
      #else
      My_GetProcAddress(GetModuleHandle(TEXT("shell32.dll")), "SHGetSpecialFolderPathW");
      #endif
  if (getW && getW(0, s, CSIDL_PERSONAL, FALSE))
    us = s;
  #ifndef _UNICODE
  else
  {
    SHGetSpecialFolderPathAp getA = (SHGetSpecialFolderPathAp)
        ::GetProcAddress(::GetModuleHandleA("shell32.dll"), "SHGetSpecialFolderPathA");
    CHAR s2[MAX_PATH + 1];
    if (getA && getA(0, s2, CSIDL_PERSONAL, FALSE))
      us = GetUnicodeString(s2);
  }
  #endif
  if (us.Length() > 0 && us.Back() != WCHAR_PATH_SEPARATOR)
    us += WCHAR_PATH_SEPARATOR;
  return us;
}
Exemplo n.º 2
0
void NormalizeDirPathPrefix(UString &dirPath)
{
  if (dirPath.IsEmpty())
    return;
  if (dirPath.Back() != WCHAR_PATH_SEPARATOR)
    dirPath += WCHAR_PATH_SEPARATOR;
}
UString GetOSName2(const UString &name)
{
  if (name.IsEmpty())
    return UString();
  UString newName = GetOSName(name);
  if (newName.Back() == kOSDirDelimiter)
    newName.DeleteBack();
  return newName;
}
void ConvertToOSName2(UString &name)
{
  if (!name.IsEmpty())
  {
    name.Replace(kDirDelimiter, kOSDirDelimiter);
    if (name.Back() == kOSDirDelimiter)
      name.DeleteBack();
  }
}
Exemplo n.º 5
0
static void AddName(UStringVector &strings, UString &s)
{
  s.Trim();
  if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar)
  {
    s.DeleteBack();
    s.Delete(0);
  }
  if (!s.IsEmpty())
    strings.Add(s);
}
Exemplo n.º 6
0
bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name)
{
  parentPrefix.Empty();
  name.Empty();
  if (path.IsEmpty())
    return false;
  if (_topDirPrefix == path)
    return false;
  UString s = path;
  if (s.Back() == WCHAR_PATH_SEPARATOR)
    s.DeleteBack();
  if (s.IsEmpty())
    return false;
  if (s.Back() == WCHAR_PATH_SEPARATOR)
    return false;
  int pos = s.ReverseFind_PathSepar();
  parentPrefix.SetFrom(s, pos + 1);
  name = s.Ptr(pos + 1);
  return true;
}
Exemplo n.º 7
0
STDMETHODIMP CFSFolder::CopyTo(const UInt32 *indices, UInt32 numItems,
    const wchar_t *path, IFolderOperationsExtractCallback *callback)
{
  if (numItems == 0)
    return S_OK;
  
  UInt64 numFolders, numFiles, totalSize;
  GetItemsFullSize(indices, numItems, numFolders, numFiles, totalSize, callback);
  RINOK(callback->SetTotal(totalSize));
  RINOK(callback->SetNumFiles(numFiles));
  
  UString destPath = path;
  if (destPath.IsEmpty())
    return E_INVALIDARG;
  bool directName = (destPath.Back() != WCHAR_PATH_SEPARATOR);
  if (directName)
  {
    if (numItems > 1)
      return E_INVALIDARG;
  }
    /*
    // doesn't work in network
  else
    if (!NDirectory::CreateComplexDirectory(destPath)))
    {
      DWORD lastError = ::GetLastError();
      UString message = UString(L"can not create folder ") +
        destPath;
      RINOK(callback->ShowMessage(message));
      return E_ABORT;
    }
    */

  UInt64 completedSize = 0;
  RINOK(callback->SetCompleted(&completedSize));
  for (UInt32 i = 0; i < numItems; i++)
  {
    const CDirItem &fi = *_refs[indices[i]];
    FString destPath2 = us2fs(destPath);
    if (!directName)
      destPath2 += fi.Name;
    FString srcPath = _path + GetPrefix(fi) + fi.Name;
    if (fi.IsDir())
    {
      RINOK(CopyFolder(srcPath, destPath2, callback, completedSize));
    }
    else
    {
      RINOK(MyCopyFile(srcPath, fi, destPath2, callback, completedSize));
    }
  }
  return S_OK;
}
Exemplo n.º 8
0
  bool ParseName(const UString &name)
  {
    if (name.Len() < 2)
      return false;
    if (name.Back() != L'1' || name[name.Len() - 2] != L'0')
      return false;

    unsigned pos = name.Len() - 2;
    for (; pos > 0 && name[pos - 1] == '0'; pos--);
    UnchangedPart.SetFrom(name, pos);
    ChangedPart = name.Ptr(pos);
    return true;
  }
Exemplo n.º 9
0
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
{
  if (properties.IsEmpty())
    return S_OK;
  CMyComPtr<ISetProperties> setProperties;
  unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
  if (!setProperties)
    return S_OK;

  UStringVector realNames;
  CPropVariant *values = new CPropVariant[properties.Size()];
  try
  {
    int i;
    for(i = 0; i < properties.Size(); i++)
    {
      const CProperty &property = properties[i];
      NCOM::CPropVariant propVariant;
      UString name = property.Name;
      if (property.Value.IsEmpty())
      {
        if (!name.IsEmpty())
        {
          wchar_t c = name.Back();
          if (c == L'-')
            propVariant = false;
          else if (c == L'+')
            propVariant = true;
          if (propVariant.vt != VT_EMPTY)
            name.DeleteBack();
        }
      }
      else
        ParseNumberString(property.Value, propVariant);
      realNames.Add(name);
      values[i] = propVariant;
    }
    CRecordVector<const wchar_t *> names;
    for(i = 0; i < realNames.Size(); i++)
      names.Add((const wchar_t *)realNames[i]);
    
    RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
  }
  catch(...)
  {
    delete []values;
    throw;
  }
  delete []values;
  return S_OK;
}
Exemplo n.º 10
0
void CPanel::LoadFullPathAndShow()
{
  LoadFullPath();
  _appState->FolderHistory.AddString(_currentFolderPrefix);

  _headerComboBox.SetText(_currentFolderPrefix);

  #ifndef UNDER_CE

  COMBOBOXEXITEM item;
  item.mask = 0;

  UString path = _currentFolderPrefix;
  if (path.Len() >
      #ifdef _WIN32
      3
      #else
      1
      #endif
      && path.Back() == WCHAR_PATH_SEPARATOR)
    path.DeleteBack();

  DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;

  // GetRealIconIndex is slow for direct DVD/UDF path. So we use dummy path
  if (path.IsPrefixedBy(L"\\\\.\\"))
    path = L"_TestFolder_";
  else
  {
    CFileInfo fi;
    if (fi.Find(us2fs(path)))
      attrib = fi.Attrib;
  }
  item.iImage = GetRealIconIndex(us2fs(path), attrib);

  if (item.iImage >= 0)
  {
    item.iSelectedImage = item.iImage;
    item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
  }
  item.iItem = -1;
  _headerComboBox.SetItem(&item);
  
  #endif

  RefreshTitle();
}
Exemplo n.º 11
0
void CPanel::OpenAltStreams()
{
  CRecordVector<UInt32> indices;
  GetOperatedItemIndices(indices);
  Int32 realIndex = -1;
  if (indices.Size() > 1)
    return;
  if (indices.Size() == 1)
    realIndex = indices[0];

  if (_folderAltStreams)
  {
    CMyComPtr<IFolderFolder> newFolder;
    _folderAltStreams->BindToAltStreams(realIndex, &newFolder);
    if (newFolder)
    {
      CDisableTimerProcessing disableTimerProcessing(*this);
      CDisableNotify disableNotify(*this);
      SetNewFolder(newFolder);
      RefreshListCtrl(UString(), -1, true, UStringVector());
      return;
    }
    return;
  }
  
  #if defined(_WIN32) && !defined(UNDER_CE)
  UString path;
  if (realIndex >= 0)
    path = GetItemFullPath(realIndex);
  else
  {
    path = GetFsPath();
    if (!NName::IsDriveRootPath_SuperAllowed(us2fs(path)))
      if (!path.IsEmpty() && IS_PATH_SEPAR(path.Back()))
        path.DeleteBack();
  }

  path += L':';
  BindToPathAndRefresh(path);
  #endif
}
Exemplo n.º 12
0
void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback)
{
  if (!callback)
    return;
  CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
  callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
  if (!volumeCallback)
    return;

  NWindows::NCOM::CPropVariant prop;
  if (volumeCallback->GetProperty(kpidName, &prop) != S_OK || prop.vt != VT_BSTR)
    return;

  UString s = prop.bstrVal;
  if (s.IsEmpty() ||
      s.Back() != L'_')
    return;
  
  s.DeleteBack();
  _name = s;
   
  if (replaceByte == 0)
  {
    if (s.Len() < 3 || s[s.Len() - 3] != '.')
      return;
    for (unsigned i = 0; i < ARRAY_SIZE(g_Exts); i++)
    {
      const char *ext = g_Exts[i];
      if (s[s.Len() - 2] == (Byte)ext[0] &&
          s[s.Len() - 1] == (Byte)ext[1])
      {
        replaceByte = ext[2];
        break;
      }
    }
  }
  
  if (replaceByte >= 0x20 && replaceByte < 0x80)
    _name += (wchar_t)replaceByte;
}
Exemplo n.º 13
0
bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res)
{
  res = s;

  #ifdef UNDER_CE

  if (s[0] != CHAR_PATH_SEPARATOR)
  {
    if (!dirPrefix)
      return false;
    res = dirPrefix;
    res += s;
  }

  #else

  unsigned prefixSize = GetRootPrefixSize(s);
  if (prefixSize != 0)
  {
    if (!AreThereDotsFolders(s + prefixSize))
      return true;
    
    UString rem = fs2us(s + prefixSize);
    if (!ResolveDotsFolders(rem))
      return true; // maybe false;
    res.DeleteFrom(prefixSize);
    res += us2fs(rem);
    return true;
  }

  /*
  FChar c = s[0];
  if (c == 0)
    return true;
  if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
    return true;
  if (c == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR)
    return true;
  if (IsDrivePath(s))
    return true;
  */

  UString curDir;
  if (dirPrefix)
    curDir = fs2us(dirPrefix);
  else
  {
    if (!GetCurDir(curDir))
      return false;
  }
  if (!curDir.IsEmpty() && curDir.Back() != WCHAR_PATH_SEPARATOR)
    curDir += WCHAR_PATH_SEPARATOR;

  unsigned fixedSize = 0;

    if (IsDrivePath(curDir))
      fixedSize = kDrivePrefixSize;
  
  UString temp;
  if (s[0] == CHAR_PATH_SEPARATOR)
  {
    temp = fs2us(s + 1);
  }
  else
  {
    temp += curDir.Ptr(fixedSize);
    temp += fs2us(s);
  }
  if (!ResolveDotsFolders(temp))
    return false;
  curDir.DeleteFrom(fixedSize);
  res = us2fs(curDir);
  res += us2fs(temp);
  
  #endif // UNDER_CE

  return true;
}
Exemplo n.º 14
0
static bool GetSuperPathBase(CFSTR s, UString &res)
{
  res.Empty();
  
  FChar c = s[0];
  if (c == 0)
    return true;
  if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
    return true;
  
  if (IsSuperOrDevicePath(s))
  {
    #ifdef LONG_PATH_DOTS_FOLDERS_PARSING
    
    if ((s)[2] == '.')
      return true;

    // we will return true here, so we will try to use these problem paths.

    if (!AreThereDotsFolders(s + kSuperPathPrefixSize))
      return true;
    
    UString temp = fs2us(s);
    unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp);
    if (fixedSize == 0)
      return true;

    UString rem = &temp[fixedSize];
    if (!ResolveDotsFolders(rem))
      return true;

    temp.DeleteFrom(fixedSize);
    res += temp;
    res += rem;
    
    #endif

    return true;
  }

  if (c == CHAR_PATH_SEPARATOR)
  {
    if (s[1] == CHAR_PATH_SEPARATOR)
    {
      UString temp = fs2us(s + 2);
      unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp);
      if (fixedSize == 0) // maybe we must ignore that error to allow short network paths?
        return false;
      UString rem = &temp[fixedSize];
      if (!ResolveDotsFolders(rem))
        return false;
      res += kSuperUncPrefix;
      temp.DeleteFrom(fixedSize);
      res += temp;
      res += rem;
      return true;
    }
  }
  else
  {
    if (IsDrivePath(s))
    {
      UString temp = fs2us(s);
      UString rem = &temp[kDrivePrefixSize];
      if (!ResolveDotsFolders(rem))
        return true;
      res += kSuperPathPrefix;
      temp.DeleteFrom(kDrivePrefixSize);
      res += temp;
      res += rem;
      return true;
    }
  }

  UString curDir;
  if (!GetCurDir(curDir))
    return false;
  if (curDir.Back() != WCHAR_PATH_SEPARATOR)
    curDir += WCHAR_PATH_SEPARATOR;

  unsigned fixedSizeStart = 0;
  unsigned fixedSize = 0;
  const wchar_t *superMarker = NULL;
  if (IsSuperPath(curDir))
  {
    fixedSize = GetRootPrefixSize_Of_SuperPath(curDir);
    if (fixedSize == 0)
      return false;
  }
  else
  {
    if (IsDrivePath(curDir))
    {
      superMarker = kSuperPathPrefix;
      fixedSize = kDrivePrefixSize;
    }
    else
    {
      if (curDir[0] != CHAR_PATH_SEPARATOR || curDir[1] != CHAR_PATH_SEPARATOR)
        return false;
      fixedSizeStart = 2;
      fixedSize = GetRootPrefixSize_Of_NetworkPath(&curDir[2]);
      if (fixedSize == 0)
        return false;
      superMarker = kSuperUncPrefix;
    }
  }
  
  UString temp;
  if (c == CHAR_PATH_SEPARATOR)
  {
    temp = fs2us(s + 1);
  }
  else
  {
    temp += &curDir[fixedSizeStart + fixedSize];
    temp += fs2us(s);
  }
  if (!ResolveDotsFolders(temp))
    return false;
  if (superMarker)
    res += superMarker;
  res += curDir.Mid(fixedSizeStart, fixedSize);
  res += temp;
  return true;
}
Exemplo n.º 15
0
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NCOM::CPropVariant prop;
  if (index >= (UInt32)_archive.Refs.Size())
  {
    index -= _archive.Refs.Size();
    const CBootInitialEntry &be = _archive.BootEntries[index];
    switch (propID)
    {
      case kpidPath:
      {
        AString s = "[BOOT]" STRING_PATH_SEPARATOR;
        if (_archive.BootEntries.Size() != 1)
        {
          char temp[16];
          ConvertUInt32ToString(index + 1, temp);
          s += temp;
          s += '-';
        }
        s += be.GetName();
        prop = s;
        break;
      }
      case kpidIsDir: prop = false; break;
      case kpidSize:
      case kpidPackSize:
        prop = (UInt64)_archive.GetBootItemSize(index);
        break;
    }
  }
  else
  {
    const CRef &ref = _archive.Refs[index];
    const CDir &item = ref.Dir->_subItems[ref.Index];
    switch (propID)
    {
      case kpidPath:
        // if (item.FileId.GetCapacity() >= 0)
        {
          UString s;
          if (_archive.IsJoliet())
            item.GetPathU(s);
          else
            s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);

          if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1')
            s.DeleteFrom(s.Len() - 2);
          
          if (!s.IsEmpty() && s.Back() == L'.')
            s.DeleteBack();

          NItemName::ConvertToOSName2(s);
          prop = s;
        }
        break;
      case kpidIsDir: prop = item.IsDir(); break;
      case kpidSize:
      case kpidPackSize:
        if (!item.IsDir())
          prop = (UInt64)ref.TotalSize;
        break;
      case kpidMTime:
      {
        FILETIME utc;
        if (item.DateTime.GetFileTime(utc))
          prop = utc;
        break;
      }
    }
  }
  prop.Detach(value);
  return S_OK;
  COM_TRY_END
}
Exemplo n.º 16
0
HRESULT CPanel::BindToPath(const UString &fullPath, const UString &arcFormat, bool &archiveIsOpened, bool &encrypted)
{
  UString path = fullPath;
  #ifdef _WIN32
  path.Replace(L'/', WCHAR_PATH_SEPARATOR);
  #endif

  archiveIsOpened = false;
  encrypted = false;
  
  CDisableTimerProcessing disableTimerProcessing(*this);
  CDisableNotify disableNotify(*this);

  for (; !_parentFolders.IsEmpty(); CloseOneLevel())
  {
    // ---------- we try to use open archive ----------

    const CFolderLink &link = _parentFolders.Back();
    const UString &virtPath = link.VirtualPath;
    if (!path.IsPrefixedBy(virtPath))
      continue;
    UString relatPath = path.Ptr(virtPath.Len());
    if (!relatPath.IsEmpty())
    {
      if (!IS_PATH_SEPAR(relatPath[0]))
        continue;
      else
        relatPath.Delete(0);
    }
    
    UString relatPath2 = relatPath;
    if (!relatPath2.IsEmpty() && !IS_PATH_SEPAR(relatPath2.Back()))
      relatPath2.Add_PathSepar();

    for (;;)
    {
      const UString foldPath = GetFolderPath(_folder);
      if (relatPath2 == foldPath)
        break;
      if (relatPath.IsPrefixedBy(foldPath))
      {
        path = relatPath.Ptr(foldPath.Len());
        break;
      }
      CMyComPtr<IFolderFolder> newFolder;
      if (_folder->BindToParentFolder(&newFolder) != S_OK)
        throw 20140918;
      if (!newFolder) // we exit from loop above if (relatPath.IsPrefixedBy(empty path for root folder)
        throw 20140918;
      SetNewFolder(newFolder);
    }
    break;
  }

  if (_parentFolders.IsEmpty())
  {
    // ---------- we open file or folder from file system ----------

    CloseOpenFolders();
    UString sysPath = path;
    
    unsigned prefixSize = NName::GetRootPrefixSize(sysPath);
    if (prefixSize == 0 || sysPath[prefixSize] == 0)
      sysPath.Empty();
    
    #if defined(_WIN32) && !defined(UNDER_CE)
    if (!sysPath.IsEmpty() && sysPath.Back() == ':' &&
      (sysPath.Len() != 2 || !NName::IsDrivePath2(sysPath)))
    {
      UString baseFile = sysPath;
      baseFile.DeleteBack();
      if (NFind::DoesFileOrDirExist(us2fs(baseFile)))
        sysPath.Empty();
    }
    #endif
    
    CFileInfo fileInfo;
    
    while (!sysPath.IsEmpty())
    {
      if (fileInfo.Find(us2fs(sysPath)))
        break;
      int pos = sysPath.ReverseFind_PathSepar();
      if (pos < 0)
        sysPath.Empty();
      else
      {
        /*
        if (reducedParts.Size() > 0 || pos < (int)sysPath.Len() - 1)
          reducedParts.Add(sysPath.Ptr(pos + 1));
        */
        #if defined(_WIN32) && !defined(UNDER_CE)
        if (pos == 2 && NName::IsDrivePath2(sysPath) && sysPath.Len() > 3)
          pos++;
        #endif

        sysPath.DeleteFrom(pos);
      }
    }
    
    SetToRootFolder();

    CMyComPtr<IFolderFolder> newFolder;
  
    if (sysPath.IsEmpty())
    {
      _folder->BindToFolder(path, &newFolder);
    }
    else if (fileInfo.IsDir())
    {
      NName::NormalizeDirPathPrefix(sysPath);
      _folder->BindToFolder(sysPath, &newFolder);
    }
    else
    {
      FString dirPrefix, fileName;
      NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName);
      HRESULT res;
      // = OpenAsArc(fs2us(fileName), arcFormat, encrypted);
      {
        CTempFileInfo tfi;
        tfi.RelPath = fs2us(fileName);
        tfi.FolderPath = dirPrefix;
        tfi.FilePath = us2fs(sysPath);
        res = OpenAsArc(NULL, tfi, sysPath, arcFormat, encrypted);
      }
      
      if (res == S_FALSE)
        _folder->BindToFolder(fs2us(dirPrefix), &newFolder);
      else
      {
        RINOK(res);
        archiveIsOpened = true;
        _parentFolders.Back().ParentFolderPath = fs2us(dirPrefix);
        path.DeleteFrontal(sysPath.Len());
        if (!path.IsEmpty() && IS_PATH_SEPAR(path[0]))
          path.Delete(0);
      }
    }
    
    if (newFolder)
    {
      SetNewFolder(newFolder);
      // LoadFullPath();
      return S_OK;
    }
  }
  
  {
    // ---------- we open folder remPath in archive and sub archives ----------

    for (unsigned curPos = 0; curPos != path.Len();)
    {
      UString s = path.Ptr(curPos);
      int slashPos = NName::FindSepar(s);
      unsigned skipLen = s.Len();
      if (slashPos >= 0)
      {
        s.DeleteFrom(slashPos);
        skipLen = slashPos + 1;
      }

      CMyComPtr<IFolderFolder> newFolder;
      _folder->BindToFolder(s, &newFolder);
      if (newFolder)
        curPos += skipLen;
      else if (_folderAltStreams)
      {
        int pos = s.Find(L':');
        if (pos >= 0)
        {
          UString baseName = s;
          baseName.DeleteFrom(pos);
          if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder)
            curPos += pos + 1;
        }
      }
      
      if (!newFolder)
        break;

      SetNewFolder(newFolder);
    }
  }

  return S_OK;
}
Exemplo n.º 17
0
void CContentsView::OnCopy(bool move, bool copyToSame)
{
  CContentsView &srcPanel = *this;
  CContentsView &destPanel = *this;

  CDisableTimerProcessing disableTimerProcessing1(destPanel);
  CDisableTimerProcessing disableTimerProcessing2(srcPanel);

  if (move)
  {
    if (!srcPanel.CheckBeforeUpdate(IDS_MOVE))
      return;
  }
  else if (!srcPanel.DoesItSupportOperations())
  {
    srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
    return;
  }

  CRecordVector<UInt32> indices;
  UString destPath;
  bool useDestPanel = false;

  {
    if (copyToSame)
    {
      int focusedItem = srcPanel.GetFocusedItem();
      if (focusedItem < 0)
        return;
      int realIndex = srcPanel.GetRealItemIndex(focusedItem);
      if (realIndex == kParentIndex)
        return;
      indices.Add(realIndex);
      destPath = srcPanel.GetItemName(realIndex);
    }
    else
    {
      srcPanel.GetOperatedIndicesSmart(indices);
      if (indices.Size() == 0)
        return;
      destPath = destPanel.GetFsPath();
      ReducePathToRealFileSystemPath(destPath);
    }
  }

  UStringVector copyFolders;
  //   ReadCopyHistory(copyFolders);

  {
    CCopyDialog copyDialog;

    copyDialog.Strings = copyFolders;
    copyDialog.Value = destPath;
    LangString(move ? IDS_MOVE : IDS_COPY, copyDialog.Title);
    LangString(move ? IDS_MOVE_TO : IDS_COPY_TO, copyDialog.Static);
    copyDialog.Info = srcPanel.GetItemsInfoString(indices);

    if (copyDialog.DoModal() != IDOK)
      return;

    destPath = copyDialog.Value;
  }

  {
    if (destPath.IsEmpty())
    {
      srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
      return;
    }

    UString correctName;
    if (!srcPanel.CorrectFsPath(destPath, correctName))
    {
      srcPanel.MessageBoxError(E_INVALIDARG);
      return;
    }

    if (IsAbsolutePath(destPath))
      destPath.Empty();
    else
      destPath = srcPanel.GetFsPath();
    destPath += correctName;

#if defined(_WIN32) && !defined(UNDER_CE)
    if (destPath.Len() > 0 && destPath[0] == '\\')
      if (destPath.Len() == 1 || destPath[1] != '\\')
      {
        srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
        return;
      }
#endif

    if (CompareFileNames(destPath, destPanel.GetFsPath()) == 0)
    {
      srcPanel.MessageBoxMyError(L"Can not copy files onto itself");
      return;
    }

    bool destIsFsPath = false;

    if (IsAltPathPrefix(us2fs(destPath)))
    {
      // we allow alt streams dest only to alt stream folder in second panel
      srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
      return;
      /*
      FString basePath = us2fs(destPath);
      basePath.DeleteBack();
      if (!DoesFileOrDirExist(basePath))
      {
      srcPanel.MessageBoxError2Lines(basePath, ERROR_FILE_NOT_FOUND); // GetLastError()
      return;
      }
      destIsFsPath = true;
      */
    }
    else
    {
      if (indices.Size() == 1 &&
        !destPath.IsEmpty() && destPath.Back() != WCHAR_PATH_SEPARATOR)
      {
        int pos = destPath.ReverseFind_PathSepar();
        if (pos < 0)
        {
          srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
          return;
        }
        {
          /*
          #ifdef _WIN32
          UString name = destPath.Ptr(pos + 1);
          if (name.Find(L':') >= 0)
          {
          srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
          return;
          }
          #endif
          */
          UString prefix = destPath.Left(pos + 1);
          if (!CreateComplexDir(us2fs(prefix)))
          {
            srcPanel.MessageBoxError2Lines(prefix, GetLastError());
            return;
          }
        }
        // bool isFolder = srcPanael.IsItem_Folder(indices[0]);
      }
      else
      {
        NName::NormalizeDirPathPrefix(destPath);
        if (!CreateComplexDir(us2fs(destPath)))
        {
          srcPanel.MessageBoxError2Lines(destPath, GetLastError());
          return;
        }
      }
      destIsFsPath = true;
    }

    if (!destIsFsPath)
      useDestPanel = true;

    //     AddUniqueStringToHeadOfList(copyFolders, destPath);
    while (copyFolders.Size() > 20)
      copyFolders.DeleteBack();
    //     SaveCopyHistory(copyFolders);
  }

  bool useSrcPanel = !useDestPanel || !srcPanel.Is_IO_FS_Folder();

  bool useTemp = useSrcPanel && useDestPanel;
  if (useTemp)
  {
    srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
    return;
  }

  CTempDir tempDirectory;
  FString tempDirPrefix;
  if (useTemp)
  {
    tempDirectory.Create(kTempDirPrefix);
    tempDirPrefix = tempDirectory.GetPath();
    NFile::NName::NormalizeDirPathPrefix(tempDirPrefix);
  }

  CSelectedState srcSelState;
  CSelectedState destSelState;
  srcPanel.SaveSelectedState(srcSelState);
  destPanel.SaveSelectedState(destSelState);

  CDisableNotify disableNotify1(destPanel);
  CDisableNotify disableNotify2(srcPanel);

  HRESULT result = S_OK;

  if (useSrcPanel)
  {
    CCopyToOptions options;
    options.folder = useTemp ? fs2us(tempDirPrefix) : destPath;
    options.moveMode = move;
    options.includeAltStreams = true;
    options.replaceAltStreamChars = false;
    options.showErrorMessages = true;

    result = srcPanel.CopyTo(options, indices, NULL);
  }

  if (result == S_OK && useDestPanel)
  {
    UStringVector filePaths;
    UString folderPrefix;
    if (useTemp)
      folderPrefix = fs2us(tempDirPrefix);
    else
      folderPrefix = srcPanel.GetFsPath();
    filePaths.ClearAndReserve(indices.Size());
    FOR_VECTOR(i, indices)
      filePaths.AddInReserved(srcPanel.GetItemRelPath2(indices[i]));
    result = destPanel.CopyFrom(move, folderPrefix, filePaths, true, 0);
  }

  if (result != S_OK)
  {
    // disableNotify1.Restore();
    // disableNotify2.Restore();
    // For Password:
    // srcPanel.SetFocusToList();
    // srcPanel.InvalidateList(NULL, true);

    if (result != E_ABORT)
      srcPanel.MessageBoxError(result, L"Error");
    // return;
  }

  RefreshTitle();

  if (copyToSame || move)
  {
    srcPanel.RefreshListCtrl(srcSelState);
  }

  if (!copyToSame)
  {
    destPanel.RefreshListCtrl(destSelState);
    srcPanel.KillSelection();
  }

  disableNotify1.Restore();
  disableNotify2.Restore();
  srcPanel.SetFocus();
}
Exemplo n.º 18
0
Arquivo: App.cpp Projeto: Dabil/puNES
void CApp::OnCopy(bool move, bool copyToSame, int srcPanelIndex)
{
  int destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
  CPanel &srcPanel = Panels[srcPanelIndex];
  CPanel &destPanel = Panels[destPanelIndex];

  CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel);
  CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel);

  if (!srcPanel.DoesItSupportOperations())
  {
    srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
    return;
  }

  CRecordVector<UInt32> indices;
  UString destPath;
  bool useDestPanel = false;

  {
    if (copyToSame)
    {
      int focusedItem = srcPanel._listView.GetFocusedItem();
      if (focusedItem < 0)
        return;
      int realIndex = srcPanel.GetRealItemIndex(focusedItem);
      if (realIndex == kParentIndex)
        return;
      indices.Add(realIndex);
      destPath = srcPanel.GetItemName(realIndex);
    }
    else
    {
      srcPanel.GetOperatedIndicesSmart(indices);
      if (indices.Size() == 0)
        return;
      destPath = destPanel._currentFolderPrefix;
      if (NumPanels == 1)
        ReducePathToRealFileSystemPath(destPath);
    }

    CCopyDialog copyDialog;
    UStringVector copyFolders;
    ReadCopyHistory(copyFolders);

    copyDialog.Strings = copyFolders;
    copyDialog.Value = destPath;
    
    copyDialog.Title = move ?
        LangString(IDS_MOVE, 0x03020202):
        LangString(IDS_COPY, 0x03020201);
    copyDialog.Static = move ?
        LangString(IDS_MOVE_TO, 0x03020204):
        LangString(IDS_COPY_TO, 0x03020203);

    copyDialog.Info = srcPanel.GetItemsInfoString(indices);

    if (copyDialog.Create(srcPanel.GetParent()) == IDCANCEL)
      return;

    destPath = copyDialog.Value;

    if (destPath.IsEmpty())
    {
      srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
      return;
    }

    if (!IsPathAbsolute(destPath))
    {
      if (!srcPanel.IsFSFolder())
      {
        srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
        return;
      }
      destPath = srcPanel._currentFolderPrefix + destPath;
    }

    #ifndef UNDER_CE
    if (destPath.Length() > 0 && destPath[0] == '\\')
      if (destPath.Length() == 1 || destPath[1] != '\\')
      {
        srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
        return;
      }
    #endif

    if (indices.Size() > 1 ||
        (!destPath.IsEmpty() && destPath.Back() == WCHAR_PATH_SEPARATOR) ||
        NFind::DoesDirExist(us2fs(destPath)) ||
        srcPanel.IsArcFolder())
    {
      NDirectory::CreateComplexDirectory(us2fs(destPath));
      NName::NormalizeDirPathPrefix(destPath);
      if (!CheckFolderPath(destPath))
      {
        if (NumPanels < 2 || destPath != destPanel._currentFolderPrefix || !destPanel.DoesItSupportOperations())
        {
          srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
          return;
        }
        useDestPanel = true;
      }
    }
    else
    {
      if (!IsCorrectFsName(destPath))
      {
        srcPanel.MessageBoxError(E_INVALIDARG);
        return;
      }
      int pos = destPath.ReverseFind(WCHAR_PATH_SEPARATOR);
      if (pos >= 0)
      {
        UString prefix = destPath.Left(pos + 1);
        NDirectory::CreateComplexDirectory(us2fs(prefix));
        if (!CheckFolderPath(prefix))
        {
          srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
          return;
        }
      }
    }

    AddUniqueStringToHeadOfList(copyFolders, destPath);
    while (copyFolders.Size() > 20)
      copyFolders.DeleteBack();
    SaveCopyHistory(copyFolders);
  }

  /*
  if (destPath == destPanel._currentFolderPrefix)
  {
    if (destPanel.GetFolderTypeID() == L"PhysDrive")
      useDestPanel = true;
  }
  */

  bool useSrcPanel = (!useDestPanel || !srcPanel.IsFsOrDrivesFolder() || destPanel.IsFSFolder());
  bool useTemp = useSrcPanel && useDestPanel;
  NFile::NDirectory::CTempDir tempDirectory;
  FString tempDirPrefix;
  if (useTemp)
  {
    tempDirectory.Create(kTempDirPrefix);
    tempDirPrefix = tempDirectory.GetPath();
    NFile::NName::NormalizeDirPathPrefix(tempDirPrefix);
  }

  CSelectedState srcSelState;
  CSelectedState destSelState;
  srcPanel.SaveSelectedState(srcSelState);
  destPanel.SaveSelectedState(destSelState);

  HRESULT result;
  if (useSrcPanel)
  {
    UString folder = useTemp ? fs2us(tempDirPrefix) : destPath;
    result = srcPanel.CopyTo(indices, folder, move, true, 0);
    if (result != S_OK)
    {
      disableTimerProcessing1.Restore();
      disableTimerProcessing2.Restore();
      // For Password:
      srcPanel.SetFocusToList();
      if (result != E_ABORT)
        srcPanel.MessageBoxError(result, L"Error");
      return;
    }
  }
  
  if (useDestPanel)
  {
    UStringVector filePaths;
    UString folderPrefix;
    if (useTemp)
      folderPrefix = fs2us(tempDirPrefix);
    else
      folderPrefix = srcPanel._currentFolderPrefix;
    filePaths.Reserve(indices.Size());
    for (int i = 0; i < indices.Size(); i++)
      filePaths.Add(srcPanel.GetItemRelPath(indices[i]));

    result = destPanel.CopyFrom(folderPrefix, filePaths, true, 0);

    if (result != S_OK)
    {
      disableTimerProcessing1.Restore();
      disableTimerProcessing2.Restore();
      // For Password:
      srcPanel.SetFocusToList();
      if (result != E_ABORT)
        srcPanel.MessageBoxError(result, L"Error");
      return;
    }
  }

  RefreshTitleAlways();
  if (copyToSame || move)
  {
    srcPanel.RefreshListCtrl(srcSelState);
  }
  if (!copyToSame)
  {
    destPanel.RefreshListCtrl(destSelState);
    srcPanel.KillSelection();
  }
  disableTimerProcessing1.Restore();
  disableTimerProcessing2.Restore();
  srcPanel.SetFocusToList();
}
Exemplo n.º 19
0
// Make sure the path is terminated with only a single /
void FixPathFormat(UString& path)
{
	while (path.Back() == L'/') path.DeleteBack();
	path += L'/';
}
Exemplo n.º 20
0
NFileOperationReturnCode::EEnum CPlugin::GetFilesReal(struct PluginPanelItem *panelItems,
    int itemsNumber, int move, const char *destPathLoc, int opMode, bool showBox)
{
  if (move != 0)
  {
    g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported);
    return NFileOperationReturnCode::kError;
  }

  AString destPath = destPathLoc;
  UString destPathU = GetUnicodeString(destPath, CP_OEMCP);
  NFile::NName::NormalizeDirPathPrefix(destPathU);
  destPath = UnicodeStringToMultiByte(destPathU, CP_OEMCP);

  bool extractSelectedFiles = true;
  
  NExtract::CInfo extractionInfo;
  extractionInfo.PathMode = NExtract::NPathMode::kCurrentPathnames;
  extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;

  bool silent = (opMode & OPM_SILENT) != 0;
  bool decompressAllItems = false;
  UString password = Password;
  bool passwordIsDefined = PasswordIsDefined;

  if (!silent)
  {
    const int kPathIndex = 2;

    extractionInfo.Load();

    const int kPathModeRadioIndex = 4;
    const int kOverwriteModeRadioIndex = kPathModeRadioIndex + 4;
    const int kNumOverwriteOptions = 6;
    const int kFilesModeIndex = kOverwriteModeRadioIndex + kNumOverwriteOptions;
    const int kXSize = 76;
    const int kYSize = 19;
    const int kPasswordYPos = 12;
    
    const int kXMid = kXSize / 2;

    AString oemPassword = UnicodeStringToMultiByte(password, CP_OEMCP);
    
    struct CInitDialogItem initItems[]={
      { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kExtractTitle, NULL, NULL },
      { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kExtractTo, NULL, NULL },
      
      { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, kExractPathHistoryName},
      // { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, 0, false, -1, destPath, NULL},
      
      { DI_SINGLEBOX, 4, 5, kXMid - 2, 5 + 4, false, false, 0, false, NMessageID::kExtractPathMode, NULL, NULL },
      { DI_RADIOBUTTON, 6, 6, 0, 0, false,
          extractionInfo.PathMode == NExtract::NPathMode::kFullPathnames,
          DIF_GROUP, false, NMessageID::kExtractPathFull, NULL, NULL },
      { DI_RADIOBUTTON, 6, 7, 0, 0, false,
          extractionInfo.PathMode == NExtract::NPathMode::kCurrentPathnames,
          0, false, NMessageID::kExtractPathCurrent, NULL, NULL },
      { DI_RADIOBUTTON, 6, 8, 0, 0, false,
          extractionInfo.PathMode == NExtract::NPathMode::kNoPathnames,
          false, 0, NMessageID::kExtractPathNo, NULL, NULL },
      
      { DI_SINGLEBOX, kXMid, 5, kXSize - 6, 5 + kNumOverwriteOptions, false, false, 0, false, NMessageID::kExtractOwerwriteMode, NULL, NULL },
      { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false,
          extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kAskBefore,
          DIF_GROUP, false, NMessageID::kExtractOwerwriteAsk, NULL, NULL },
      { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false,
          extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kWithoutPrompt,
          0, false, NMessageID::kExtractOwerwritePrompt, NULL, NULL },
      { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false,
          extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kSkipExisting,
          0, false, NMessageID::kExtractOwerwriteSkip, NULL, NULL },
      { DI_RADIOBUTTON, kXMid + 2, 9, 0, 0, false,
          extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kAutoRename,
          0, false, NMessageID::kExtractOwerwriteAutoRename, NULL, NULL },
      { DI_RADIOBUTTON, kXMid + 2, 10, 0, 0, false,
          extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting,
          0, false, NMessageID::kExtractOwerwriteAutoRenameExisting, NULL, NULL },
      
      { DI_SINGLEBOX, 4, 10, kXMid- 2, 10 + 3, false, false, 0, false, NMessageID::kExtractFilesMode, NULL, NULL },
      { DI_RADIOBUTTON, 6, 11, 0, 0, false, true, DIF_GROUP, false, NMessageID::kExtractFilesSelected, NULL, NULL },
      { DI_RADIOBUTTON, 6, 12, 0, 0, false, false, 0, false, NMessageID::kExtractFilesAll, NULL, NULL },
      
      { DI_SINGLEBOX, kXMid, kPasswordYPos, kXSize - 6, kPasswordYPos + 2, false, false, 0, false, NMessageID::kExtractPassword, NULL, NULL },
      { DI_PSWEDIT, kXMid + 2, kPasswordYPos + 1, kXSize - 8, 12, false, false, 0, false, -1, oemPassword, NULL},
      
      { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL  },
      
      
      { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kExtractExtract, NULL, NULL  },
      { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kExtractCancel, NULL, NULL  }
    };
   
    const int kNumDialogItems = sizeof(initItems) / sizeof(initItems[0]);
    const int kOkButtonIndex = kNumDialogItems - 2;
    const int kPasswordIndex = kNumDialogItems - 4;

    FarDialogItem dialogItems[kNumDialogItems];
    g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
    for (;;)
    {
      int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize,
        kHelpTopicExtrFromSevenZip, dialogItems, kNumDialogItems);
      if (askCode != kOkButtonIndex)
        return NFileOperationReturnCode::kInterruptedByUser;
      destPath = dialogItems[kPathIndex].Data;
      destPathU = GetUnicodeString(destPath, CP_OEMCP);
      destPathU.Trim();
      if (destPathU.IsEmpty())
      {
        #ifdef UNDER_CE
        destPathU = L"\\";
        #else
        if (!NFile::NDirectory::MyGetCurrentDirectory(destPathU))
          throw 318016;
        NFile::NName::NormalizeDirPathPrefix(destPathU);
        #endif
        break;
      }
      else
      {
        if (destPathU.Back() == kDirDelimiter)
          break;
      }
      g_StartupInfo.ShowMessage("You must specify directory path");
    }

    if (dialogItems[kPathModeRadioIndex].Selected)
      extractionInfo.PathMode = NExtract::NPathMode::kFullPathnames;
    else if (dialogItems[kPathModeRadioIndex + 1].Selected)
      extractionInfo.PathMode = NExtract::NPathMode::kCurrentPathnames;
    else if (dialogItems[kPathModeRadioIndex + 2].Selected)
      extractionInfo.PathMode = NExtract::NPathMode::kNoPathnames;
    else
      throw 31806;

    if (dialogItems[kOverwriteModeRadioIndex].Selected)
      extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
    else if (dialogItems[kOverwriteModeRadioIndex + 1].Selected)
      extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
    else if (dialogItems[kOverwriteModeRadioIndex + 2].Selected)
      extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kSkipExisting;
    else if (dialogItems[kOverwriteModeRadioIndex + 3].Selected)
      extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kAutoRename;
    else if (dialogItems[kOverwriteModeRadioIndex + 4].Selected)
      extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kAutoRenameExisting;
    else
      throw 31806;
    
    if (dialogItems[kFilesModeIndex].Selected)
      decompressAllItems = false;
    else if (dialogItems[kFilesModeIndex + 1].Selected)
      decompressAllItems = true;
    else
      throw 31806;

    extractionInfo.Save();

    if (dialogItems[kFilesModeIndex].Selected)
      extractSelectedFiles = true;
    else if (dialogItems[kFilesModeIndex + 1].Selected)
      extractSelectedFiles = false;
    else
      throw 31806;

    oemPassword = dialogItems[kPasswordIndex].Data;
    password = MultiByteToUnicodeString(oemPassword, CP_OEMCP);
    passwordIsDefined = !password.IsEmpty();
  }

  NFile::NDirectory::CreateComplexDirectory(destPathU);

  /*
  vector<int> realIndices;
  if (!decompressAllItems)
    GetRealIndexes(panelItems, itemsNumber, realIndices);
  */
  CRecordVector<UINT32> indices;
  indices.Reserve(itemsNumber);
  for (int i = 0; i < itemsNumber; i++)
    indices.Add((UINT32)panelItems[i].UserData);

  HRESULT result = ExtractFiles(decompressAllItems, &indices.Front(), itemsNumber,
      !showBox, extractionInfo.PathMode, extractionInfo.OverwriteMode,
      destPathU,
      passwordIsDefined, password);
  // HRESULT result = ExtractFiles(decompressAllItems, realIndices, !showBox,
  //     extractionInfo, destPath, passwordIsDefined, password);
  if (result != S_OK)
  {
    if (result == E_ABORT)
      return NFileOperationReturnCode::kInterruptedByUser;
    ShowErrorMessage(result);
    return NFileOperationReturnCode::kError;
  }

  // if (move != 0)
  // {
  //   if (DeleteFiles(panelItems, itemsNumber, opMode) == FALSE)
  //     return NFileOperationReturnCode::kError;
  // }
  return NFileOperationReturnCode::kSuccess;
}
Exemplo n.º 21
0
STDMETHODIMP CFSDrives::CopyTo(const UInt32 *indices, UInt32 numItems,
                               const wchar_t *path, IFolderOperationsExtractCallback *callback)
{
    if (numItems == 0)
        return S_OK;

    if (!_volumeMode)
        return E_NOTIMPL;

    UInt64 totalSize = 0;
    UInt32 i;
    for (i = 0; i < numItems; i++)
    {
        const CDriveInfo &di = _drives[indices[i]];
        if (di.KnownSizes)
            totalSize += di.DriveSize;
    }
    RINOK(callback->SetTotal(totalSize));
    RINOK(callback->SetNumFiles(numItems));

    UString destPath = path;
    if (destPath.IsEmpty())
        return E_INVALIDARG;
    bool directName = (destPath.Back() != WCHAR_PATH_SEPARATOR);
    if (directName)
    {
        if (numItems > 1)
            return E_INVALIDARG;
    }

    UInt64 completedSize = 0;
    RINOK(callback->SetCompleted(&completedSize));
    for (i = 0; i < numItems; i++)
    {
        int index = indices[i];
        const CDriveInfo &di = _drives[index];
        UString destPath2 = destPath;
        UString name = fs2us(di.Name);
        if (!directName)
        {
            UString destName = name;
            if (!destName.IsEmpty() && destName.Back() == L':')
            {
                destName.DeleteBack();
                destName += GetExt(index);
            }
            destPath2 += destName;
        }
        FString srcPath = di.GetDeviceFileIoName();

        UInt64 fileSize = 0;
        if (GetLength(index, fileSize) != S_OK)
        {
            return E_FAIL;
        }
        if (!di.KnownSizes)
            totalSize += fileSize;
        RINOK(callback->SetTotal(totalSize));

        Int32 writeAskResult;
        CMyComBSTR destPathResult;
        RINOK(callback->AskWrite(fs2us(srcPath), BoolToInt(false), NULL, &fileSize,
                                 destPath2, &destPathResult, &writeAskResult));
        if (!IntToBool(writeAskResult))
            continue;

        RINOK(callback->SetCurrentFilePath(fs2us(srcPath)));

        static const UInt32 kBufferSize = (4 << 20);
        UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize;
        RINOK(CopyFileSpec(srcPath, us2fs(destPathResult), false, fileSize, bufferSize, completedSize, callback));
        completedSize += fileSize;
    }
    return S_OK;
}