📄 7zupdate.cpp
字号:
CNum numUnPackStreams = database->NumUnPackStreamsVector[i];
for (CNum fileIndex = database->FolderStartFileIndex[i];
indexInFolder < numUnPackStreams; fileIndex++)
{
if (database->Files[fileIndex].HasStream)
{
indexInFolder++;
int updateIndex = fileIndexToUpdateIndexMap[fileIndex];
if (updateIndex >= 0)
if (!updateItems[updateIndex].NewData)
numCopyItems++;
}
}
if (numCopyItems != numUnPackStreams && numCopyItems != 0)
return E_NOTIMPL; // It needs repacking !!!
if (numCopyItems > 0)
{
CFolderRef folderRef;
folderRef.Database = database;
folderRef.FolderIndex = i;
folderRefs.Add(folderRef);
}
}
qsort(&folderRefs.Front(), folderRefs.Size(), sizeof(folderRefs[0]),
CompareFolderRefs);
}
CArchiveDatabase newDatabase;
/////////////////////////////////////////
// Write Empty Files & Folders
CRecordVector<const CUpdateItem *> emptyRefs;
for(i = 0; i < updateItems.Size(); i++)
{
const CUpdateItem &updateItem = updateItems[i];
if (updateItem.NewData)
{
if (updateItem.HasStream())
continue;
}
else
if (updateItem.IndexInArchive != -1)
if (database->Files[updateItem.IndexInArchive].HasStream)
continue;
emptyRefs.Add(&updateItem);
}
qsort(&emptyRefs.Front(), emptyRefs.Size(), sizeof(emptyRefs[0]),
CompareEmptyItems);
for(i = 0; i < emptyRefs.Size(); i++)
{
const CUpdateItem &updateItem = *emptyRefs[i];
CFileItem file;
if (updateItem.NewProperties)
FromUpdateItemToFileItem(updateItem, file);
else
file = database->Files[updateItem.IndexInArchive];
newDatabase.Files.Add(file);
}
////////////////////////////
COutArchive archive;
archive.Create(seqOutStream, false);
RINOK(archive.SkeepPrefixArchiveHeader());
UInt64 complexity = 0;
for(i = 0; i < folderRefs.Size(); i++)
complexity += database->GetFolderFullPackSize(folderRefs[i].FolderIndex);
for(i = 0; i < updateItems.Size(); i++)
{
const CUpdateItem &updateItem = updateItems[i];
if (updateItem.NewData)
complexity += updateItem.Size;
}
RINOK(updateCallback->SetTotal(complexity));
complexity = 0;
RINOK(updateCallback->SetCompleted(&complexity));
/////////////////////////////////////////
// Write Copy Items
for(i = 0; i < folderRefs.Size(); i++)
{
int folderIndex = folderRefs[i].FolderIndex;
RINOK(WriteRange(inStream, archive.SeqStream,
database->GetFolderStreamPos(folderIndex, 0),
database->GetFolderFullPackSize(folderIndex),
updateCallback, complexity));
const CFolder &folder = database->Folders[folderIndex];
CNum startIndex = database->FolderStartPackStreamIndex[folderIndex];
for (int j = 0; j < folder.PackStreams.Size(); j++)
{
newDatabase.PackSizes.Add(database->PackSizes[startIndex + j]);
// newDatabase.PackCRCsDefined.Add(database.PackCRCsDefined[startIndex + j]);
// newDatabase.PackCRCs.Add(database.PackCRCs[startIndex + j]);
}
newDatabase.Folders.Add(folder);
CNum numUnPackStreams = database->NumUnPackStreamsVector[folderIndex];
newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
CNum indexInFolder = 0;
for (CNum fi = database->FolderStartFileIndex[folderIndex];
indexInFolder < numUnPackStreams; fi++)
{
CFileItem file = database->Files[fi];
if (file.HasStream)
{
indexInFolder++;
int updateIndex = fileIndexToUpdateIndexMap[fi];
if (updateIndex >= 0)
{
const CUpdateItem &updateItem = updateItems[updateIndex];
if (updateItem.NewProperties)
{
CFileItem file2;
FromUpdateItemToFileItem(updateItem, file2);
file2.UnPackSize = file.UnPackSize;
file2.FileCRC = file.FileCRC;
file2.IsFileCRCDefined = file.IsFileCRCDefined;
file2.HasStream = file.HasStream;
file = file2;
}
}
newDatabase.Files.Add(file);
}
}
}
/////////////////////////////////////////
// Compress New Files
CObjectVector<CSolidGroup> groups;
SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter,
updateItems, groups);
for (int groupIndex = 0; groupIndex < groups.Size(); groupIndex++)
{
const CSolidGroup &group = groups[groupIndex];
int numFiles = group.Indices.Size();
if (numFiles == 0)
continue;
CRecordVector<CRefItem> refItems;
refItems.Reserve(numFiles);
for (i = 0; i < numFiles; i++)
refItems.Add(CRefItem(group.Indices[i],
updateItems[group.Indices[i]], numSolidFiles > 1));
qsort(&refItems.Front(), refItems.Size(), sizeof(refItems[0]), CompareUpdateItems);
CRecordVector<UInt32> indices;
indices.Reserve(numFiles);
for (i = 0; i < numFiles; i++)
{
UInt32 index = refItems[i].Index;
indices.Add(index);
/*
const CUpdateItem &updateItem = updateItems[index];
CFileItem file;
if (updateItem.NewProperties)
FromUpdateItemToFileItem(updateItem, file);
else
file = database.Files[updateItem.IndexInArchive];
if (file.IsAnti || file.IsDirectory)
return E_FAIL;
newDatabase.Files.Add(file);
*/
}
CEncoder encoder(group.Method);
for (i = 0; i < numFiles;)
{
UInt64 totalSize = 0;
int numSubFiles;
UString prevExtension;
for (numSubFiles = 0; i + numSubFiles < numFiles &&
numSubFiles < numSolidFiles; numSubFiles++)
{
const CUpdateItem &updateItem = updateItems[indices[i + numSubFiles]];
totalSize += updateItem.Size;
if (totalSize > options.NumSolidBytes)
break;
if (options.SolidExtension)
{
UString ext = updateItem.GetExtension();
if (numSubFiles == 0)
prevExtension = ext;
else
if (ext.CollateNoCase(prevExtension) != 0)
break;
}
}
if (numSubFiles < 1)
numSubFiles = 1;
CFolderInStream *inStreamSpec = new CFolderInStream;
CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
CFolder folderItem;
CLocalProgress *localProgressSpec = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
localProgressSpec->Init(updateCallback, true);
CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
localCompressProgressSpec->Init(localProgress, &complexity, NULL);
RINOK(encoder.Encode(solidInStream, NULL, folderItem,
archive.SeqStream, newDatabase.PackSizes, compressProgress));
// for()
// newDatabase.PackCRCsDefined.Add(false);
// newDatabase.PackCRCs.Add(0);
newDatabase.Folders.Add(folderItem);
CNum numUnPackStreams = 0;
for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
{
const CUpdateItem &updateItem = updateItems[indices[i + subIndex]];
CFileItem file;
if (updateItem.NewProperties)
FromUpdateItemToFileItem(updateItem, file);
else
file = database->Files[updateItem.IndexInArchive];
if (file.IsAnti || file.IsDirectory)
return E_FAIL;
/*
CFileItem &file = newDatabase.Files[
startFileIndexInDatabase + i + subIndex];
*/
if (!inStreamSpec->Processed[subIndex])
{
continue;
// file.Name += L".locked";
}
file.FileCRC = inStreamSpec->CRCs[subIndex];
file.UnPackSize = inStreamSpec->Sizes[subIndex];
if (file.UnPackSize != 0)
{
file.IsFileCRCDefined = true;
file.HasStream = true;
numUnPackStreams++;
complexity += file.UnPackSize;
}
else
{
file.IsFileCRCDefined = false;
file.HasStream = false;
}
newDatabase.Files.Add(file);
}
// numUnPackStreams = 0 is very bad case for locked files
// v3.13 doesn't understand it.
newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
i += numSubFiles;
}
}
/*
if (newDatabase.Files.Size() != updateItems.Size())
return E_FAIL;
*/
return archive.WriteDatabase(newDatabase, options.HeaderMethod,
options.UseAdditionalHeaderStreams, options.CompressMainHeader);
}
static HRESULT WriteVolumeHeader(COutArchive &archive, CFileItem &file, const CUpdateOptions &options)
{
CAltCoderInfo altCoder;
altCoder.MethodID.IDSize = 1;
altCoder.MethodID.ID[0] = 0;
CCoderInfo coder;
coder.NumInStreams = coder.NumOutStreams = 1;
coder.AltCoders.Add(altCoder);
CFolder folder;
folder.Coders.Add(coder);
folder.PackStreams.Add(0);
CNum numUnPackStreams = 0;
if (file.UnPackSize != 0)
{
file.IsFileCRCDefined = true;
file.HasStream = true;
numUnPackStreams++;
}
else
{
throw 1;
file.IsFileCRCDefined = false;
file.HasStream = false;
}
folder.UnPackSizes.Add(file.UnPackSize);
CArchiveDatabase newDatabase;
newDatabase.Files.Add(file);
newDatabase.Folders.Add(folder);
newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
newDatabase.PackSizes.Add(file.UnPackSize);
newDatabase.PackCRCsDefined.Add(false);
newDatabase.PackCRCs.Add(file.FileCRC);
return archive.WriteDatabase(newDatabase,
options.HeaderMethod,
false,
false);
}
#ifdef _7Z_VOL
HRESULT UpdateVolume(
IInStream *inStream,
const CArchiveDatabaseEx *database,
CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
IArchiveUpdateCallback *updateCallback,
const CUpdateOptions &options)
{
if (updateItems.Size() != 1)
return E_NOTIMPL;
CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
if (!volumeCallback)
return E_NOTIMPL;
CMyComPtr<ISequentialInStream> fileStream;
HRESULT result = updateCallback->GetStream(0, &fileStream);
if (result != S_OK && result != S_FALSE)
return result;
if (result == S_FALSE)
return E_FAIL;
CFileItem file;
const CUpdateItem &updateItem = updateItems[0];
if (updateItem.NewProperties)
FromUpdateItemToFileItem(updateItem, file);
else
file = database->Files[updateItem.IndexInArchive];
if (file.IsAnti || file.IsDirectory)
return E_FAIL;
UInt64 complexity = 0;
file.IsStartPosDefined = true;
file.StartPos = 0;
for (UInt64 volumeIndex = 0; true; volumeIndex++)
{
UInt64 volSize;
RINOK(volumeCallback->GetVolumeSize(volumeIndex, &volSize));
UInt64 pureSize = COutArchive::GetVolPureSize(volSize, file.Name.Length(), true);
CMyComPtr<ISequentialOutStream> volumeStream;
RINOK(volumeCallback->GetVolumeStream(volumeIndex, &volumeStream));
COutArchive archive;
archive.Create(volumeStream, true);
RINOK(archive.SkeepPrefixArchiveHeader());
CSequentialInStreamWithCRC *inCrcStreamSpec = new CSequentialInStreamWithCRC;
CMyComPtr<ISequentialInStream> inCrcStream = inCrcStreamSpec;
inCrcStreamSpec->Init(fileStream);
RINOK(WriteRange(inCrcStream, volumeStream, pureSize,
updateCallback, complexity));
file.UnPackSize = inCrcStreamSpec->GetSize();
if (file.UnPackSize == 0)
break;
file.FileCRC = inCrcStreamSpec->GetCRC();
RINOK(WriteVolumeHeader(archive, file, options));
file.StartPos += file.UnPackSize;
if (file.UnPackSize < pureSize)
break;
}
return S_OK;
}
class COutVolumeStream:
public ISequentialOutStream,
public CMyUnknownImp
{
int _volIndex;
UInt64 _volSize;
UInt64 _curPos;
CMyComPtr<ISequentialOutStream> _volumeStream;
COutArchive _archive;
CCRC _crc;
public:
MY_UNKNOWN_IMP
CFileItem _file;
CUpdateOptions _options;
CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
void Init(IArchiveUpdateCallback2 *volumeCallback,
const UString &name)
{
_file.Name = name;
_file.IsStartPosDefined = true;
_file.StartPos = 0;
VolumeCallback = volumeCallback;
_volIndex = 0;
_volSize = 0;
}
HRESULT Flush();
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize);
};
HRESULT COutVolumeStream::Flush()
{
if (_volumeStream)
{
_file.UnPackSize = _curPos;
_file.FileCRC = _crc.GetDigest();
RINOK(WriteVolumeHeader(_archive, _file, _options));
_archive.Close();
_volumeStream.Release();
_file.StartPos += _file.UnPackSize;
}
return S_OK;
}
STDMETHODIMP COutVolumeStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if(processedSize != NULL)
*processedSize = 0;
while(size > 0)
{
if (!_volumeStream)
{
RINOK(VolumeCallback->GetVolumeSize(_volIndex, &_volSize));
RINOK(VolumeCallback->GetVolumeStream(_volIndex, &_volumeStream));
_volIndex++;
_curPos = 0;
_archive.Create(_volumeStream, true);
RINOK(_archive.SkeepPrefixArchiveHeader());
_crc.Init();
continue;
}
UInt64 pureSize = COutArchive::GetVolPureSize(_volSize, _file.Name.Length());
UInt32 curSize = (UInt32)MyMin(UInt64(size), pureSize - _curPos);
_crc.Update(data, curSize);
UInt32 realProcessed;
RINOK(_volumeStream->Write(data, curSize, &realProcessed))
data = (void *)((Byte *)data + realProcessed);
size -= realProcessed;
if(processedSize != NULL)
*processedSize += realProcessed;
_curPos += realProcessed;
if (realProcessed != curSize)
return E_FAIL;
if (_curPos == pureSize)
{
RINOK(Flush());
}
}
return S_OK;
}
STDMETHODIMP COutVolumeStream::WritePart(const void *data, UInt32 size, UInt32 *processedSize)
{
return Write(data, size, processedSize);
}
#endif
HRESULT Update(
IInStream *inStream,
const CArchiveDatabaseEx *database,
CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
IArchiveUpdateCallback *updateCallback,
const CUpdateOptions &options)
{
#ifdef _7Z_VOL
if (seqOutStream)
#endif
return Update2(inStream, database, updateItems,
seqOutStream, updateCallback, options);
#ifdef _7Z_VOL
if (options.VolumeMode)
return UpdateVolume(inStream, database, updateItems,
seqOutStream, updateCallback, options);
COutVolumeStream *volStreamSpec = new COutVolumeStream;
CMyComPtr<ISequentialOutStream> volStream = volStreamSpec;
CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
if (!volumeCallback)
return E_NOTIMPL;
volStreamSpec->Init(volumeCallback, L"a.7z");
volStreamSpec->_options = options;
RINOK(Update2(inStream, database, updateItems,
volStream, updateCallback, options));
return volStreamSpec->Flush();
#endif
}
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -