diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp | 639 |
1 files changed, 0 insertions, 639 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp deleted file mode 100644 index 50b879e79..000000000 --- a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ /dev/null @@ -1,639 +0,0 @@ -// WimHandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "Common/ComTry.h" -#include "Common/IntToString.h" - -#include "Windows/PropVariant.h" -#include "Windows/Time.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "../../Crypto/RandGen.h" -#include "../../Crypto/Sha1.h" - -#include "WimHandler.h" - -using namespace NWindows; - -namespace NArchive { -namespace NWim { - -struct CSha1Hash -{ - Byte Hash[kHashSize]; -}; - -struct CHashList -{ - CRecordVector<CSha1Hash> Digests; - CIntVector Sorted; - - int AddUnique(const CSha1Hash &h); -}; - -int CHashList::AddUnique(const CSha1Hash &h) -{ - int left = 0, right = Sorted.Size(); - while (left != right) - { - int mid = (left + right) / 2; - int index = Sorted[mid]; - UInt32 i; - const Byte *hash2 = Digests[index].Hash; - for (i = 0; i < kHashSize; i++) - if (h.Hash[i] != hash2[i]) - break; - if (i == kHashSize) - return index; - if (h.Hash[i] < hash2[i]) - right = mid; - else - left = mid + 1; - } - Sorted.Insert(left, Digests.Add(h)); - return -1; -} - -struct CUpdateItem -{ - UString Name; - UInt64 Size; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - UInt32 Attrib; - bool IsDir; - int HashIndex; - - CUpdateItem(): HashIndex(-1) {} -}; - -struct CDir -{ - int Index; - UString Name; - CObjectVector<CDir> Dirs; - CIntVector Files; - - CDir(): Index(-1) {} - bool IsLeaf() const { return Index >= 0; } - UInt64 GetNumDirs() const; - UInt64 GetNumFiles() const; - CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index); -}; - -UInt64 CDir::GetNumDirs() const -{ - UInt64 num = Dirs.Size(); - for (int i = 0; i < Dirs.Size(); i++) - num += Dirs[i].GetNumDirs(); - return num; -} - -UInt64 CDir::GetNumFiles() const -{ - UInt64 num = Files.Size(); - for (int i = 0; i < Dirs.Size(); i++) - num += Dirs[i].GetNumFiles(); - return num; -} - -CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index) -{ - int left = 0, right = Dirs.Size(); - while (left != right) - { - int mid = (left + right) / 2; - CDir &d = Dirs[mid]; - int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name); - if (compare == 0) - { - if (index >= 0) - d.Index = index; - return &d; - } - if (compare < 0) - right = mid; - else - left = mid + 1; - } - Dirs.Insert(left, CDir()); - CDir &d = Dirs[left]; - d.Index = index; - if (index < 0) - d.Name = name; - return &d; -} - - -STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type) -{ - *type = NFileTimeType::kWindows; - return S_OK; -} - -static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft) -{ - ft.dwLowDateTime = ft.dwHighDateTime = 0; - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propID, &prop)); - if (prop.vt == VT_FILETIME) - ft = prop.filetime; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - return S_OK; -} - -#define Set16(p, d) SetUi16(p, d) -#define Set32(p, d) SetUi32(p, d) -#define Set64(p, d) SetUi64(p, d) - -void CResource::WriteTo(Byte *p) const -{ - Set64(p, PackSize); - p[7] = Flags; - Set64(p + 8, Offset); - Set64(p + 16, UnpackSize); -} - -void CHeader::WriteTo(Byte *p) const -{ - memcpy(p, kSignature, kSignatureSize); - Set32(p + 8, kHeaderSizeMax); - Set32(p + 0xC, Version); - Set32(p + 0x10, Flags); - Set32(p + 0x14, ChunkSize); - memcpy(p + 0x18, Guid, 16); - Set16(p + 0x28, PartNumber); - Set16(p + 0x2A, NumParts); - Set32(p + 0x2C, NumImages); - OffsetResource.WriteTo(p + 0x30); - XmlResource.WriteTo(p + 0x48); - MetadataResource.WriteTo(p + 0x60); - IntegrityResource.WriteTo(p + 0x7C); - Set32(p + 0x78, BootIndex); - memset(p + 0x94, 0, 60); -} - -void CStreamInfo::WriteTo(Byte *p) const -{ - Resource.WriteTo(p); - Set16(p + 0x18, PartNumber); - Set32(p + 0x1A, RefCount); - memcpy(p + 0x1E, Hash, kHashSize); -} - -class CInStreamWithSha1: - public ISequentialInStream, - public CMyUnknownImp -{ - CMyComPtr<ISequentialInStream> _stream; - UInt64 _size; - NCrypto::NSha1::CContext _sha; -public: - MY_UNKNOWN_IMP1(IInStream) - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - _sha.Init(); - } - void ReleaseStream() { _stream.Release(); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { _sha.Final(digest); } -}; - -STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - UInt32 realProcessedSize; - HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - _sha.Update((const Byte *)data, realProcessedSize); - if (processedSize != NULL) - *processedSize = realProcessedSize; - return result; -} - -static void SetFileTimeToMem(Byte *p, const FILETIME &ft) -{ - Set32(p, ft.dwLowDateTime); - Set32(p + 4, ft.dwHighDateTime); -} - -static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash) -{ - int fileNameLen = item.Name.Length() * 2; - int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - - size_t totalLen = ((kDirRecordSize + fileNameLen2 + 6) & ~7); - if (p) - { - memset(p, 0, totalLen); - Set64(p, totalLen); - Set64(p + 8, item.Attrib); - Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId - // Set64(p + 0x10, 0); // subdirOffset - SetFileTimeToMem(p + 0x28, item.CTime); - SetFileTimeToMem(p + 0x30, item.ATime); - SetFileTimeToMem(p + 0x38, item.MTime); - if (hash) - memcpy(p + 0x40, hash, kHashSize); - /* - else - memset(p + 0x40, 0, kHashSize); - */ - // Set16(p + 98, 0); // shortNameLen - Set16(p + 100, (UInt16)fileNameLen); - for (int i = 0; i * 2 < fileNameLen; i++) - Set16(p + kDirRecordSize + i * 2, item.Name[i]); - } - return totalLen; -} - -static void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests, - CUpdateItem &defaultDirItem, - CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos) -{ - int i; - for (i = 0; i < tree.Files.Size(); i++) - { - const CUpdateItem &ui = updateItems[tree.Files[i]]; - pos += WriteItem(ui, dest ? dest + pos : NULL, - ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL); - } - - size_t posStart = pos; - for (i = 0; i < tree.Dirs.Size(); i++) - { - const CDir &subfolder = tree.Dirs[i]; - CUpdateItem *item = &defaultDirItem; - if (subfolder.IsLeaf()) - item = &updateItems[subfolder.Index]; - else - defaultDirItem.Name = subfolder.Name; - pos += WriteItem(*item, NULL, NULL); - } - - if (dest) - Set64(dest + pos, 0); - - pos += 8; - - for (i = 0; i < tree.Dirs.Size(); i++) - { - const CDir &subfolder = tree.Dirs[i]; - if (dest) - { - CUpdateItem *item = &defaultDirItem; - if (subfolder.IsLeaf()) - item = &updateItems[subfolder.Index]; - else - defaultDirItem.Name = subfolder.Name; - size_t len = WriteItem(*item, dest + posStart, NULL); - Set64(dest + posStart + 0x10, pos); - posStart += len; - } - WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos); - } -} - -static void AddTag(AString &s, const char *name, const AString &value) -{ - s += "<"; - s += name; - s += ">"; - s += value; - s += "</"; - s += name; - s += ">"; -} - -static void AddTagUInt64(AString &s, const char *name, UInt64 value) -{ - char temp[32]; - ConvertUInt64ToString(value, temp); - AddTag(s, name, temp); -} - -static AString TimeToXml(FILETIME &ft) -{ - AString res; - char temp[16] = { '0', 'x' }; - ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2); - AddTag(res, "HIGHPART", temp); - ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2); - AddTag(res, "LOWPART", temp); - return res; -} - -void CHeader::SetDefaultFields(bool useLZX) -{ - Version = kWimVersion; - Flags = NHeaderFlags::kRpFix; - ChunkSize = 0; - if (useLZX) - { - Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX; - ChunkSize = kChunkSize; - } - g_RandomGenerator.Generate(Guid, 16); - PartNumber = 1; - NumParts = 1; - NumImages = 1; - BootIndex = 0; - OffsetResource.Clear(); - XmlResource.Clear(); - MetadataResource.Clear(); - IntegrityResource.Clear(); -} - -static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, - CDir &rootFolder, - CObjectVector<CUpdateItem> &updateItems, - IArchiveUpdateCallback *callback) -{ - CMyComPtr<IOutStream> outStream; - RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); - if (!outStream) - return E_NOTIMPL; - - UInt64 complexity = 0; - - int i; - for (i = 0; i < updateItems.Size(); i++) - complexity += updateItems[i].Size; - - RINOK(callback->SetTotal(complexity)); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(callback, true); - - complexity = 0; - - bool useCompression = false; - - CHeader header; - header.SetDefaultFields(useCompression); - Byte buf[kHeaderSizeMax]; - header.WriteTo(buf); - RINOK(WriteStream(outStream, buf, kHeaderSizeMax)); - - CHashList hashes; - CObjectVector<CStreamInfo> streams; - - UInt64 curPos = kHeaderSizeMax; - UInt64 unpackTotalSize = 0; - for (i = 0; i < updateItems.Size(); i++) - { - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()); - - CUpdateItem &ui = updateItems[i]; - if (ui.IsDir || ui.Size == 0) - continue; - - CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1; - CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec; - - { - CMyComPtr<ISequentialInStream> fileInStream; - HRESULT res = callback->GetStream(i, &fileInStream); - if (res != S_FALSE) - { - RINOK(res); - inShaStreamSpec->SetStream(fileInStream); - fileInStream.Release(); - inShaStreamSpec->Init(); - UInt64 offsetBlockSize = 0; - if (useCompression) - { - for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize) - { - Byte buf[8]; - SetUi32(buf, (UInt32)t); - RINOK(WriteStream(outStream, buf, 4)); - offsetBlockSize += 4; - } - } - - RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress)); - ui.Size = copyCoderSpec->TotalSize; - - CSha1Hash hash; - unpackTotalSize += ui.Size; - UInt64 packSize = offsetBlockSize + ui.Size; - inShaStreamSpec->Final(hash.Hash); - int index = hashes.AddUnique(hash); - if (index >= 0) - { - ui.HashIndex = index; - streams[index].RefCount++; - outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); - outStream->SetSize(curPos); - } - else - { - ui.HashIndex = hashes.Digests.Size() - 1; - CStreamInfo s; - s.Resource.PackSize = packSize; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = ui.Size; - s.Resource.Flags = 0; - if (useCompression) - s.Resource.Flags = NResourceFlags::Compressed; - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, hash.Hash, kHashSize); - streams.Add(s); - curPos += packSize; - } - } - fileInStream.Release(); - complexity += ui.Size; - RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - } - } - - - CUpdateItem ri; - FILETIME ft; - NTime::GetCurUtcFileTime(ft); - ri.MTime = ri.ATime = ri.CTime = ft; - ri.Attrib = FILE_ATTRIBUTE_DIRECTORY; - - const UInt32 kSecuritySize = 8; - size_t pos = kSecuritySize; - WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos); - - CByteBuffer meta; - meta.SetCapacity(pos); - - // we can write 0 here only if there is no security data, imageX does it, - // but some programs expect size = 8 - Set32((Byte *)meta, 8); // size of security data - Set32((Byte *)meta + 4, 0); // num security entries - - pos = kSecuritySize; - WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos); - - { - NCrypto::NSha1::CContext sha; - sha.Init(); - sha.Update((const Byte *)meta, pos); - CSha1Hash digest; - sha.Final(digest.Hash); - - CStreamInfo s; - s.Resource.PackSize = pos; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = pos; - s.Resource.Flags = NResourceFlags::kMetadata; - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, digest.Hash, kHashSize); - streams.Add(s); - RINOK(WriteStream(outStream, (const Byte *)meta, pos)); - meta.Free(); - curPos += pos; - } - - - header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize; - header.OffsetResource.Offset = curPos; - header.OffsetResource.Flags = NResourceFlags::kMetadata; - - for (i = 0; i < streams.Size(); i++) - { - Byte buf[kStreamInfoSize]; - streams[i].WriteTo(buf); - RINOK(WriteStream(outStream, buf, kStreamInfoSize)); - curPos += kStreamInfoSize; - } - - AString xml = "<WIM>"; - AddTagUInt64(xml, "TOTALBYTES", curPos); - xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>"; - AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs()); - AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles()); - AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize); - NTime::GetCurUtcFileTime(ft); - AddTag(xml, "CREATIONTIME", TimeToXml(ft)); - AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft)); - xml += "</IMAGE></WIM>"; - - size_t xmlSize = (xml.Length() + 1) * 2; - meta.SetCapacity(xmlSize); - Set16((Byte *)meta, 0xFEFF); - for (i = 0; i < xml.Length(); i++) - Set16((Byte *)meta + 2 + i * 2, xml[i]); - RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize)); - meta.Free(); - - header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize; - header.XmlResource.Offset = curPos; - header.XmlResource.Flags = NResourceFlags::kMetadata; - - outStream->Seek(0, STREAM_SEEK_SET, NULL); - header.WriteTo(buf); - return WriteStream(outStream, buf, kHeaderSizeMax); -} - -STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback) -{ - COM_TRY_BEGIN - CObjectVector<CUpdateItem> updateItems; - CDir tree; - tree.Dirs.Add(CDir()); - CDir &rootFolder = tree.Dirs.Back(); - - for (UInt32 i = 0; i < numItems; i++) - { - CUpdateItem ui; - Int32 newData, newProps; - UInt32 indexInArchive; - if (!callback) - return E_FAIL; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidIsDir, &prop)); - if (prop.vt == VT_EMPTY) - ui.IsDir = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - ui.IsDir = (prop.boolVal != VARIANT_FALSE); - } - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidAttrib, &prop)); - if (prop.vt == VT_EMPTY) - ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0); - else if (prop.vt != VT_UI4) - return E_INVALIDARG; - else - ui.Attrib = prop.ulVal; - } - - RINOK(GetTime(callback, i, kpidCTime, ui.CTime)); - RINOK(GetTime(callback, i, kpidATime, ui.ATime)); - RINOK(GetTime(callback, i, kpidMTime, ui.MTime)); - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidSize, &prop)); - if (prop.vt != VT_UI8) - return E_INVALIDARG; - ui.Size = prop.uhVal.QuadPart; - } - - UString path; - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidPath, &prop)); - if (prop.vt == VT_BSTR) - path = prop.bstrVal; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - - CDir *curItem = &rootFolder; - int len = path.Length(); - UString fileName; - for (int j = 0; j < len; j++) - { - wchar_t c = path[j]; - if (c == WCHAR_PATH_SEPARATOR || c == L'/') - { - curItem = curItem->AddDir(updateItems, fileName, -1); - fileName.Empty(); - } - else - fileName += c; - } - - ui.Name = fileName; - updateItems.Add(ui); - if (ui.IsDir) - curItem->AddDir(updateItems, fileName, (int)i); - else - curItem->Files.Add(i); - } - return UpdateArchive(outStream, tree, updateItems, callback); - COM_TRY_END -} - -}} |