Files
easy7zip/7zip/FileManager/PanelSplitFile.cpp
Igor Pavlov cb9eea7264 4.37 beta
2016-05-28 00:15:47 +01:00

472 lines
12 KiB
C++
Executable File

// PanelSplitFile.cpp
#include "StdAfx.h"
#include "resource.h"
#include "Common/Alloc.h"
#include "Common/Types.h"
#include "Windows/COM.h"
#include "Windows/FileIO.h"
#include "Windows/FileFind.h"
#include "Windows/Thread.h"
#include "Resource/ProgressDialog2/ProgressDialog.h"
#include "Resource/SplitDialog/SplitDialog.h"
#include "Resource/CopyDialog/CopyDialog.h"
#include "App.h"
#include "FormatUtils.h"
#include "LangUtils.h"
using namespace NWindows;
class CMyBuffer
{
void *_data;
public:
CMyBuffer(): _data(0) {}
operator void *() { return _data; }
bool Allocate(size_t size)
{
if (_data != 0)
return false;
_data = ::MidAlloc(size);
return _data != 0;
}
~CMyBuffer() { ::MidFree(_data); }
};
struct CVolSeqName
{
UString UnchangedPart;
UString ChangedPart;
CVolSeqName(): ChangedPart(L"000") {};
bool ParseName(const UString &name)
{
if (name.Right(2) != L"01")
return false;
int numLetters = 2;
while (numLetters < name.Length())
{
if (name[name.Length() - numLetters - 1] != '0')
break;
numLetters++;
}
UnchangedPart = name.Left(name.Length() - numLetters);
ChangedPart = name.Right(numLetters);
return true;
}
UString GetNextName()
{
UString newName;
int i;
int numLetters = ChangedPart.Length();
for (i = numLetters - 1; i >= 0; i--)
{
wchar_t c = ChangedPart[i];
if (c == L'9')
{
c = L'0';
newName = c + newName;
if (i == 0)
newName = UString(L'1') + newName;
continue;
}
c++;
newName = c + newName;
i--;
for (; i >= 0; i--)
newName = ChangedPart[i] + newName;
break;
}
ChangedPart = newName;
return UnchangedPart + ChangedPart;
}
};
static const UInt32 kBufSize = (1 << 20);
struct CThreadSplit
{
// HRESULT Result;
// CPanel *Panel;
CProgressDialog *ProgressDialog;
UString FilePath;
UString VolBasePath;
CRecordVector<UInt64> VolumeSizes;
UString Error;
void Process2()
{
// NCOM::CComInitializer comInitializer;
ProgressDialog->WaitCreating();
NFile::NIO::CInFile inFile;
if (!inFile.Open(FilePath))
throw L"Can not open file";
NFile::NIO::COutFile outFile;
CMyBuffer bufferObject;
if (!bufferObject.Allocate(kBufSize))
throw L"Can not allocate buffer";
Byte *buffer = (Byte *)(void *)bufferObject;
UInt64 curVolSize = 0;
CVolSeqName seqName;
UInt64 length;
if (!inFile.GetLength(length))
throw "error";
ProgressDialog->ProgressSynch.SetProgress(length, 0);
UInt64 pos = 0;
int volIndex = 0;
while(true)
{
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))
throw L"Can not read input file";
if (processedSize == 0)
break;
needSize = processedSize;
if (curVolSize == 0)
{
UString name = VolBasePath;
name += L".";
name += seqName.GetNextName();
if (!outFile.Create(name, false))
throw L"Can not create output file";
ProgressDialog->ProgressSynch.SetCurrentFileName(name);
}
if (!outFile.Write(buffer, needSize, processedSize))
throw L"Can not write output file";
if (needSize != processedSize)
throw L"Can not write output file";
curVolSize += processedSize;
if (curVolSize == volSize)
{
outFile.Close();
volIndex++;
curVolSize = 0;
}
pos += processedSize;
HRESULT res = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(pos);
if (res != S_OK)
return;
}
}
DWORD Process()
{
try { Process2(); }
catch(const wchar_t *s) { Error = s; }
catch(...) { Error = L"Error"; }
ProgressDialog->MyClose();
return 0;
}
static DWORD WINAPI MyThreadFunction(void *param)
{
return ((CThreadSplit *)param)->Process();
}
};
void CApp::Split()
{
int srcPanelIndex = GetFocusedPanelIndex();
CPanel &srcPanel = Panels[srcPanelIndex];
if (!srcPanel.IsFSFolder())
{
srcPanel.MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
return;
}
CRecordVector<UInt32> indices;
srcPanel.GetOperatedItemIndices(indices);
if (indices.IsEmpty())
return;
if (indices.Size() != 1)
{
srcPanel.MessageBox(L"Select one file");
return;
}
int index = indices[0];
if (srcPanel.IsItemFolder(index))
{
srcPanel.MessageBox(L"Select one file");
return;
}
const UString itemName = srcPanel.GetItemName(index);
UString srcPath = srcPanel._currentFolderPrefix + 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._currentFolderPrefix;
CSplitDialog splitDialog;
splitDialog.FilePath = srcPanel.GetItemRelPath(index);
splitDialog.Path = path;
if (splitDialog.Create(srcPanel.GetParent()) == IDCANCEL)
return;
CThreadSplit spliter;
// spliter.Panel = this;
CProgressDialog progressDialog;
spliter.ProgressDialog = &progressDialog;
UString progressWindowTitle = LangString(IDS_APP_TITLE, 0x03000000);
UString title = LangString(IDS_SPLITTING, 0x03020510);
progressDialog.MainWindow = _window;
progressDialog.MainTitle = progressWindowTitle;
progressDialog.MainAddTitle = title + UString(L" ");
progressDialog.ProgressSynch.SetTitleFileName(itemName);
path = splitDialog.Path;
NFile::NName::NormalizeDirPathPrefix(path);
if (!NFile::NDirectory::CreateComplexDirectory(path))
{
srcPanel.MessageBoxMyError(L"Can not create output folder");
return;
}
spliter.FilePath = srcPath + itemName;
spliter.VolBasePath = path + itemName;
spliter.VolumeSizes = splitDialog.VolumeSizes;
if (splitDialog.VolumeSizes.Size() == 0)
{
srcPanel.MessageBoxMyError(L"Incorrect volume size");
return;
}
NFile::NFind::CFileInfoW fileInfo;
if (!NFile::NFind::FindFile(spliter.FilePath, fileInfo))
{
srcPanel.MessageBoxMyError(L"Can not find file");
return;
}
if (fileInfo.Size <= splitDialog.VolumeSizes.Front())
{
srcPanel.MessageBoxMyError(L"File is not larger than volume");
return;
}
// CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel);
// CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel);
CThread thread;
if (!thread.Create(CThreadSplit::MyThreadFunction, &spliter))
throw 271824;
progressDialog.Create(title, _window);
if (!spliter.Error.IsEmpty())
srcPanel.MessageBoxMyError(spliter.Error);
// disableTimerProcessing1.Restore();
// disableTimerProcessing2.Restore();
// srcPanel.SetFocusToList();
// srcPanel.RefreshListCtrlSaveFocused();
}
struct CThreadCombine
{
CProgressDialog *ProgressDialog;
UString InputDirPrefix;
UString FirstVolumeName;
UString OutputDirPrefix;
UString Error;
void Process2()
{
// NCOM::CComInitializer comInitializer;
ProgressDialog->WaitCreating();
CVolSeqName volSeqName;
if (!volSeqName.ParseName(FirstVolumeName))
throw L"Can not detect file as splitted file";
UString nextName = InputDirPrefix + FirstVolumeName;
UInt64 totalSize = 0;
while (true)
{
NFile::NFind::CFileInfoW fileInfo;
if (!NFile::NFind::FindFile(nextName, fileInfo))
break;
if (fileInfo.IsDirectory())
break;
totalSize += fileInfo.Size;
nextName = InputDirPrefix + volSeqName.GetNextName();
}
if (totalSize == 0)
throw L"no data";
ProgressDialog->ProgressSynch.SetProgress(totalSize, 0);
if (!volSeqName.ParseName(FirstVolumeName))
throw L"Can not detect file as splitted file";
UString outName = volSeqName.UnchangedPart;
while(!outName.IsEmpty())
{
int lastIndex = outName.Length() - 1;
if (outName[lastIndex] != L'.')
break;
outName.Delete(lastIndex);
}
if (outName.IsEmpty())
outName = L"file";
NFile::NIO::COutFile outFile;
if (!outFile.Create(OutputDirPrefix + outName, false))
throw L"Can create open output file";
NFile::NIO::CInFile inFile;
CMyBuffer bufferObject;
if (!bufferObject.Allocate(kBufSize))
throw L"Can not allocate buffer";
Byte *buffer = (Byte *)(void *)bufferObject;
UInt64 pos = 0;
nextName = InputDirPrefix + FirstVolumeName;
bool needOpen = true;
while(true)
{
if (needOpen)
{
NFile::NFind::CFileInfoW fileInfo;
if (!NFile::NFind::FindFile(nextName, fileInfo))
break;
if (fileInfo.IsDirectory())
break;
if (!inFile.Open(nextName))
throw L"Can not open file";
ProgressDialog->ProgressSynch.SetCurrentFileName(fileInfo.Name);
nextName = InputDirPrefix + volSeqName.GetNextName();
needOpen = false;
}
UInt32 processedSize;
if (!inFile.Read(buffer, kBufSize, processedSize))
throw L"Can not read input file";
if (processedSize == 0)
{
needOpen = true;
continue;
}
UInt32 needSize = processedSize;
if (!outFile.Write(buffer, needSize, processedSize))
throw L"Can not write output file";
if (needSize != processedSize)
throw L"Can not write output file";
pos += processedSize;
HRESULT res = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(pos);
if (res != S_OK)
return;
}
}
DWORD Process()
{
try { Process2(); }
catch(const wchar_t *s) { Error = s; }
catch(...) { Error = L"Error";}
ProgressDialog->MyClose();
return 0;
}
static DWORD WINAPI MyThreadFunction(void *param)
{
return ((CThreadCombine *)param)->Process();
}
};
void CApp::Combine()
{
int srcPanelIndex = GetFocusedPanelIndex();
CPanel &srcPanel = Panels[srcPanelIndex];
if (!srcPanel.IsFSFolder())
{
srcPanel.MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
return;
}
CRecordVector<UInt32> indices;
srcPanel.GetOperatedItemIndices(indices);
if (indices.IsEmpty())
return;
if (indices.Size() != 1)
{
srcPanel.MessageBox(L"Select only first file");
return;
}
int index = indices[0];
if (srcPanel.IsItemFolder(index))
{
srcPanel.MessageBox(L"Select only first file");
return;
}
const UString itemName = srcPanel.GetItemName(index);
UString srcPath = srcPanel._currentFolderPrefix + 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._currentFolderPrefix;
CCopyDialog copyDialog;
copyDialog.Value = path;
copyDialog.Title = LangString(IDS_COMBINE, 0x03020600);
copyDialog.Title += ' ';
copyDialog.Title += srcPanel.GetItemRelPath(index);
copyDialog.Static = LangString(IDS_COMBINE_TO, 0x03020601);;
if (copyDialog.Create(srcPanel.GetParent()) == IDCANCEL)
return;
CThreadCombine combiner;
// combiner.Panel = this;
CProgressDialog progressDialog;
combiner.ProgressDialog = &progressDialog;
UString progressWindowTitle = LangString(IDS_APP_TITLE, 0x03000000);
UString title = LangString(IDS_COMBINING, 0x03020610);
progressDialog.MainWindow = _window;
progressDialog.MainTitle = progressWindowTitle;
progressDialog.MainAddTitle = title + UString(L" ");
path = copyDialog.Value;
NFile::NName::NormalizeDirPathPrefix(path);
if (!NFile::NDirectory::CreateComplexDirectory(path))
{
srcPanel.MessageBoxMyError(L"Can not create output folder");
return;
}
combiner.InputDirPrefix = srcPath;
combiner.FirstVolumeName = itemName;
combiner.OutputDirPrefix = path;
// CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel);
// CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel);
CThread thread;
if (!thread.Create(CThreadCombine::MyThreadFunction, &combiner))
throw 271824;
progressDialog.Create(title, _window);
if (!combiner.Error.IsEmpty())
srcPanel.MessageBoxMyError(combiner.Error);
// disableTimerProcessing1.Restore();
// disableTimerProcessing2.Restore();
// srcPanel.SetFocusToList();
// srcPanel.RefreshListCtrlSaveFocused();
}