p7zip-rar/CPP/7zip/UI/FileManager/PanelSplitFile.cpp
2017-10-11 12:40:22 +02:00

490 lines
12 KiB
C++

// PanelSplitFile.cpp
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/FileName.h"
#include "../GUI/ExtractRes.h"
#include "resource.h"
#include "App.h"
#include "CopyDialog.h"
#include "FormatUtils.h"
#include "LangUtils.h"
#include "SplitDialog.h"
#include "SplitUtils.h"
#include "PropertyNameRes.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
static const wchar_t *g_Message_FileWriteError = L"File write error";
struct CVolSeqName
{
UString UnchangedPart;
UString ChangedPart;
CVolSeqName(): ChangedPart(L"000") {};
void SetNumDigits(UInt64 numVolumes)
{
ChangedPart = L"000";
while (numVolumes > 999)
{
numVolumes /= 10;
ChangedPart += L'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;
}
UString GetNextName();
};
UString CVolSeqName::GetNextName()
{
for (int i = (int)ChangedPart.Len() - 1; i >= 0; i--)
{
wchar_t c = ChangedPart[i];
if (c != L'9')
{
ChangedPart.ReplaceOneCharAtPos(i, (wchar_t)(c + 1));
break;
}
ChangedPart.ReplaceOneCharAtPos(i, L'0');
if (i == 0)
ChangedPart.InsertAtFront(L'1');
}
return UnchangedPart + ChangedPart;
}
static const UInt32 kBufSize = (1 << 20);
class CThreadSplit: public CProgressThreadVirt
{
HRESULT ProcessVirt();
public:
FString FilePath;
FString VolBasePath;
UInt64 NumVolumes;
CRecordVector<UInt64> VolumeSizes;
};
HRESULT CThreadSplit::ProcessVirt()
{
NIO::CInFile inFile;
if (!inFile.Open(FilePath))
return GetLastError();
NIO::COutFile outFile;
CMyBuffer bufferObject;
if (!bufferObject.Allocate(kBufSize))
return E_OUTOFMEMORY;
Byte *buffer = (Byte *)(void *)bufferObject;
UInt64 curVolSize = 0;
CVolSeqName seqName;
seqName.SetNumDigits(NumVolumes);
UInt64 length;
if (!inFile.GetLength(length))
return GetLastError();
CProgressSync &sync = ProgressDialog.Sync;
sync.Set_NumBytesTotal(length);
UInt64 pos = 0;
UInt64 numFiles = 0;
unsigned volIndex = 0;
for (;;)
{
UInt64 volSize;
if (volIndex < VolumeSizes.Size())
volSize = VolumeSizes[volIndex];
else
volSize = VolumeSizes.Back();
UInt32 needSize = (UInt32)(MyMin((UInt64)kBufSize, volSize - curVolSize));
UInt32 processedSize;
if (!inFile.Read(buffer, needSize, processedSize))
return GetLastError();
if (processedSize == 0)
break;
needSize = processedSize;
if (curVolSize == 0)
{
FString name = VolBasePath;
name += FTEXT('.');
name += us2fs(seqName.GetNextName());
sync.Set_FilePath(fs2us(name));
sync.Set_NumFilesCur(numFiles++);
if (!outFile.Create(name, false))
{
HRESULT res = GetLastError();
AddErrorPath(name);
return res;
}
}
if (!outFile.Write(buffer, needSize, processedSize))
return GetLastError();
if (needSize != processedSize)
throw g_Message_FileWriteError;
curVolSize += processedSize;
if (curVolSize == volSize)
{
outFile.Close();
if (volIndex < VolumeSizes.Size())
volIndex++;
curVolSize = 0;
}
pos += processedSize;
RINOK(sync.Set_NumBytesCur(pos));
}
sync.Set_NumFilesCur(numFiles);
return S_OK;
}
void CApp::Split()
{
int srcPanelIndex = GetFocusedPanelIndex();
CPanel &srcPanel = Panels[srcPanelIndex];
if (!srcPanel.Is_IO_FS_Folder())
{
srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
return;
}
CRecordVector<UInt32> indices;
srcPanel.GetOperatedItemIndices(indices);
if (indices.IsEmpty())
return;
if (indices.Size() != 1)
{
srcPanel.MessageBoxErrorLang(IDS_SELECT_ONE_FILE);
return;
}
int index = indices[0];
if (srcPanel.IsItem_Folder(index))
{
srcPanel.MessageBoxErrorLang(IDS_SELECT_ONE_FILE);
return;
}
const UString itemName = srcPanel.GetItemName(index);
UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index);
UString path = srcPath;
int destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
CPanel &destPanel = Panels[destPanelIndex];
if (NumPanels > 1)
if (destPanel.IsFSFolder())
path = destPanel.GetFsPath();
CSplitDialog splitDialog;
splitDialog.FilePath = srcPanel.GetItemRelPath(index);
splitDialog.Path = path;
if (splitDialog.Create(srcPanel.GetParent()) != IDOK)
return;
NFind::CFileInfo fileInfo;
if (!fileInfo.Find(us2fs(srcPath + itemName)))
{
srcPanel.MessageBoxMyError(L"Can not find file");
return;
}
if (fileInfo.Size <= splitDialog.VolumeSizes.Front())
{
srcPanel.MessageBoxErrorLang(IDS_SPLIT_VOL_MUST_BE_SMALLER);
return;
}
const UInt64 numVolumes = GetNumberOfVolumes(fileInfo.Size, splitDialog.VolumeSizes);
if (numVolumes >= 100)
{
wchar_t s[32];
ConvertUInt64ToString(numVolumes, s);
if (::MessageBoxW(srcPanel, MyFormatNew(IDS_SPLIT_CONFIRM_MESSAGE, s),
LangString(IDS_SPLIT_CONFIRM_TITLE),
MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES)
return;
}
path = splitDialog.Path;
NName::NormalizeDirPathPrefix(path);
if (!CreateComplexDir(us2fs(path)))
{
srcPanel.MessageBoxError2Lines(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), ::GetLastError());
return;
}
{
CThreadSplit spliter;
spliter.NumVolumes = numVolumes;
CProgressDialog &progressDialog = spliter.ProgressDialog;
UString progressWindowTitle = L"7-Zip"; // LangString(IDS_APP_TITLE, 0x03000000);
UString title = LangString(IDS_SPLITTING);
progressDialog.ShowCompressionInfo = false;
progressDialog.MainWindow = _window;
progressDialog.MainTitle = progressWindowTitle;
progressDialog.MainAddTitle = title;
progressDialog.MainAddTitle.Add_Space();
progressDialog.Sync.Set_TitleFileName(itemName);
spliter.FilePath = us2fs(srcPath + itemName);
spliter.VolBasePath = us2fs(path + srcPanel.GetItemName_for_Copy(index));
spliter.VolumeSizes = splitDialog.VolumeSizes;
// if (splitDialog.VolumeSizes.Size() == 0) return;
// CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel);
// CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel);
if (spliter.Create(title, _window) != 0)
return;
}
RefreshTitleAlways();
// disableNotify.Restore();
// disableNotify.Restore();
// srcPanel.SetFocusToList();
// srcPanel.RefreshListCtrlSaveFocused();
}
class CThreadCombine: public CProgressThreadVirt
{
HRESULT ProcessVirt();
public:
FString InputDirPrefix;
FStringVector Names;
FString OutputPath;
UInt64 TotalSize;
};
HRESULT CThreadCombine::ProcessVirt()
{
NIO::COutFile outFile;
if (!outFile.Create(OutputPath, false))
{
HRESULT res = GetLastError();
AddErrorPath(OutputPath);
return res;
}
CProgressSync &sync = ProgressDialog.Sync;
sync.Set_NumBytesTotal(TotalSize);
CMyBuffer bufferObject;
if (!bufferObject.Allocate(kBufSize))
return E_OUTOFMEMORY;
Byte *buffer = (Byte *)(void *)bufferObject;
UInt64 pos = 0;
FOR_VECTOR (i, Names)
{
NIO::CInFile inFile;
const FString nextName = InputDirPrefix + Names[i];
if (!inFile.Open(nextName))
{
HRESULT res = GetLastError();
AddErrorPath(nextName);
return res;
}
sync.Set_FilePath(fs2us(nextName));
for (;;)
{
UInt32 processedSize;
if (!inFile.Read(buffer, kBufSize, processedSize))
{
HRESULT res = GetLastError();
AddErrorPath(nextName);
return res;
}
if (processedSize == 0)
break;
UInt32 needSize = processedSize;
if (!outFile.Write(buffer, needSize, processedSize))
{
HRESULT res = GetLastError();
AddErrorPath(OutputPath);
return res;
}
if (needSize != processedSize)
throw g_Message_FileWriteError;
pos += processedSize;
RINOK(sync.Set_NumBytesCur(pos));
}
}
return S_OK;
}
extern void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size);
static void AddInfoFileName(UString &dest, const UString &name)
{
dest += L"\n ";
dest += name;
}
void CApp::Combine()
{
int srcPanelIndex = GetFocusedPanelIndex();
CPanel &srcPanel = Panels[srcPanelIndex];
if (!srcPanel.IsFSFolder())
{
srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
return;
}
CRecordVector<UInt32> indices;
srcPanel.GetOperatedItemIndices(indices);
if (indices.IsEmpty())
return;
int index = indices[0];
if (indices.Size() != 1 || srcPanel.IsItem_Folder(index))
{
srcPanel.MessageBoxErrorLang(IDS_COMBINE_SELECT_ONE_FILE);
return;
}
const UString itemName = srcPanel.GetItemName(index);
UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index);
UString path = srcPath;
int destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
CPanel &destPanel = Panels[destPanelIndex];
if (NumPanels > 1)
if (destPanel.IsFSFolder())
path = destPanel.GetFsPath();
CVolSeqName volSeqName;
if (!volSeqName.ParseName(itemName))
{
srcPanel.MessageBoxErrorLang(IDS_COMBINE_CANT_DETECT_SPLIT_FILE);
return;
}
{
CThreadCombine combiner;
UString nextName = itemName;
combiner.TotalSize = 0;
for (;;)
{
NFind::CFileInfo fileInfo;
if (!fileInfo.Find(us2fs(srcPath + nextName)) || fileInfo.IsDir())
break;
combiner.Names.Add(us2fs(nextName));
combiner.TotalSize += fileInfo.Size;
nextName = volSeqName.GetNextName();
}
if (combiner.Names.Size() == 1)
{
srcPanel.MessageBoxErrorLang(IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART);
return;
}
if (combiner.TotalSize == 0)
{
srcPanel.MessageBoxMyError(L"No data");
return;
}
UString info;
AddValuePair2(info, IDS_PROP_FILES, combiner.Names.Size(), combiner.TotalSize);
info.Add_LF();
info += srcPath;
unsigned i;
for (i = 0; i < combiner.Names.Size() && i < 2; i++)
AddInfoFileName(info, fs2us(combiner.Names[i]));
if (i != combiner.Names.Size())
{
if (i + 1 != combiner.Names.Size())
AddInfoFileName(info, L"...");
AddInfoFileName(info, fs2us(combiner.Names.Back()));
}
{
CCopyDialog copyDialog;
copyDialog.Value = path;
LangString(IDS_COMBINE, copyDialog.Title);
copyDialog.Title.Add_Space();
copyDialog.Title += srcPanel.GetItemRelPath(index);
LangString(IDS_COMBINE_TO, copyDialog.Static);
copyDialog.Info = info;
if (copyDialog.Create(srcPanel.GetParent()) != IDOK)
return;
path = copyDialog.Value;
}
NName::NormalizeDirPathPrefix(path);
if (!CreateComplexDir(us2fs(path)))
{
srcPanel.MessageBoxError2Lines(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), ::GetLastError());
return;
}
UString outName = volSeqName.UnchangedPart;
while (!outName.IsEmpty())
{
if (outName.Back() != L'.')
break;
outName.DeleteBack();
}
if (outName.IsEmpty())
outName = L"file";
NFind::CFileInfo fileInfo;
UString destFilePath = path + outName;
combiner.OutputPath = us2fs(destFilePath);
if (fileInfo.Find(combiner.OutputPath))
{
srcPanel.MessageBoxMyError(MyFormatNew(IDS_FILE_EXIST, destFilePath));
return;
}
CProgressDialog &progressDialog = combiner.ProgressDialog;
progressDialog.ShowCompressionInfo = false;
UString progressWindowTitle = L"7-Zip"; // LangString(IDS_APP_TITLE, 0x03000000);
UString title = LangString(IDS_COMBINING);
progressDialog.MainWindow = _window;
progressDialog.MainTitle = progressWindowTitle;
progressDialog.MainAddTitle = title;
progressDialog.MainAddTitle.Add_Space();
combiner.InputDirPrefix = us2fs(srcPath);
// CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel);
// CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel);
if (combiner.Create(title, _window) != 0)
return;
}
RefreshTitleAlways();
// disableNotify.Restore();
// disableNotify.Restore();
// srcPanel.SetFocusToList();
// srcPanel.RefreshListCtrlSaveFocused();
}