summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
diff options
context:
space:
mode:
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.cpp639
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
-}
-
-}}