diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp | 855 |
1 files changed, 0 insertions, 855 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp deleted file mode 100644 index c210804df..000000000 --- a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp +++ /dev/null @@ -1,855 +0,0 @@ -// Archive/WimIn.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "Common/IntToString.h" - -#include "../../Common/StreamUtils.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/LimitedStreams.h" - -#include "../Common/OutStreamWithSha1.h" - -#include "WimIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -namespace NArchive { -namespace NWim { - -namespace NXpress { - -class CDecoderFlusher -{ - CDecoder *m_Decoder; -public: - bool NeedFlush; - CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {} - ~CDecoderFlusher() - { - if (NeedFlush) - m_Decoder->Flush(); - m_Decoder->ReleaseStreams(); - } -}; - -HRESULT CDecoder::CodeSpec(UInt32 outSize) -{ - { - Byte levels[kMainTableSize]; - for (unsigned i = 0; i < kMainTableSize; i += 2) - { - Byte b = m_InBitStream.DirectReadByte(); - levels[i] = b & 0xF; - levels[i + 1] = b >> 4; - } - if (!m_MainDecoder.SetCodeLengths(levels)) - return S_FALSE; - } - - while (outSize > 0) - { - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); - if (number < 256) - { - m_OutWindowStream.PutByte((Byte)number); - outSize--; - } - else - { - if (number >= kMainTableSize) - return S_FALSE; - UInt32 posLenSlot = number - 256; - UInt32 posSlot = posLenSlot / kNumLenSlots; - UInt32 len = posLenSlot % kNumLenSlots; - UInt32 distance = (1 << posSlot) - 1 + m_InBitStream.ReadBits(posSlot); - - if (len == kNumLenSlots - 1) - { - len = m_InBitStream.DirectReadByte(); - if (len == 0xFF) - { - len = m_InBitStream.DirectReadByte(); - len |= (UInt32)m_InBitStream.DirectReadByte() << 8; - } - else - len += kNumLenSlots - 1; - } - - len += kMatchMinLen; - UInt32 locLen = (len <= outSize ? len : outSize); - - if (!m_OutWindowStream.CopyBlock(distance, locLen)) - return S_FALSE; - - len -= locLen; - outSize -= locLen; - if (len != 0) - return S_FALSE; - } - } - return S_OK; -} - -const UInt32 kDictSize = (1 << kNumPosSlots); - -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize) -{ - if (!m_OutWindowStream.Create(kDictSize) || !m_InBitStream.Create(1 << 16)) - return E_OUTOFMEMORY; - - CDecoderFlusher flusher(this); - - m_InBitStream.SetStream(inStream); - m_OutWindowStream.SetStream(outStream); - m_InBitStream.Init(); - m_OutWindowStream.Init(false); - - RINOK(CodeSpec(outSize)); - - flusher.NeedFlush = false; - return Flush(); -} - -HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize) -{ - try { return CodeReal(inStream, outStream, outSize); } - catch(const CInBufferException &e) { return e.ErrorCode; } \ - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -} - -HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL)); - - CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream(); - CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(inStream); - - if (!copyCoder) - { - copyCoderSpec = new NCompress::CCopyCoder; - copyCoder = copyCoderSpec; - } - if (!resource.IsCompressed()) - { - if (resource.PackSize != resource.UnpackSize) - return S_FALSE; - limitedStreamSpec->Init(resource.PackSize); - return copyCoder->Code(limitedStreamSpec, outStream, NULL, NULL, progress); - } - if (resource.UnpackSize == 0) - return S_OK; - UInt64 numChunks = (resource.UnpackSize + kChunkSize - 1) >> kChunkSizeBits; - unsigned entrySize = ((resource.UnpackSize > (UInt64)1 << 32) ? 8 : 4); - UInt64 sizesBufSize64 = entrySize * (numChunks - 1); - size_t sizesBufSize = (size_t)sizesBufSize64; - if (sizesBufSize != sizesBufSize64) - return E_OUTOFMEMORY; - if (sizesBufSize > sizesBuf.GetCapacity()) - { - sizesBuf.Free(); - sizesBuf.SetCapacity(sizesBufSize); - } - RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize)); - const Byte *p = (const Byte *)sizesBuf; - - if (lzxMode && !lzxDecoder) - { - lzxDecoderSpec = new NCompress::NLzx::CDecoder(true); - lzxDecoder = lzxDecoderSpec; - RINOK(lzxDecoderSpec->SetParams(kChunkSizeBits)); - } - - UInt64 baseOffset = resource.Offset + sizesBufSize64; - UInt64 outProcessed = 0; - for (UInt32 i = 0; i < (UInt32)numChunks; i++) - { - UInt64 offset = 0; - if (i > 0) - { - offset = (entrySize == 4) ? Get32(p): Get64(p); - p += entrySize; - } - UInt64 nextOffset = resource.PackSize - sizesBufSize64; - if (i + 1 < (UInt32)numChunks) - nextOffset = (entrySize == 4) ? Get32(p): Get64(p); - if (nextOffset < offset) - return S_FALSE; - - RINOK(inStream->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL)); - UInt64 inSize = nextOffset - offset; - limitedStreamSpec->Init(inSize); - - if (progress) - { - RINOK(progress->SetRatioInfo(&offset, &outProcessed)); - } - - UInt32 outSize = kChunkSize; - if (outProcessed + outSize > resource.UnpackSize) - outSize = (UInt32)(resource.UnpackSize - outProcessed); - UInt64 outSize64 = outSize; - if (inSize == outSize) - { - RINOK(copyCoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL)); - } - else - { - if (lzxMode) - { - lzxDecoderSpec->SetKeepHistory(false); - RINOK(lzxDecoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL)); - } - else - { - RINOK(xpressDecoder.Code(limitedStreamSpec, outStream, outSize)); - } - } - outProcessed += outSize; - } - return S_OK; -} - -HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest) -{ - COutStreamWithSha1 *shaStreamSpec = new COutStreamWithSha1(); - CMyComPtr<ISequentialOutStream> shaStream = shaStreamSpec; - shaStreamSpec->SetStream(outStream); - shaStreamSpec->Init(digest != NULL); - HRESULT result = Unpack(inStream, resource, lzxMode, shaStream, progress); - if (digest) - shaStreamSpec->Final(digest); - return result; -} - -static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool lzxMode, CByteBuffer &buf, Byte *digest) -{ - size_t size = (size_t)resource.UnpackSize; - if (size != resource.UnpackSize) - return E_OUTOFMEMORY; - buf.Free(); - buf.SetCapacity(size); - - CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream(); - CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; - outStreamSpec->Init((Byte *)buf, size); - - CUnpacker unpacker; - return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest); -} - -void CResource::Parse(const Byte *p) -{ - Flags = p[7]; - PackSize = Get64(p) & (((UInt64)1 << 56) - 1); - Offset = Get64(p + 8); - UnpackSize = Get64(p + 16); -} - -#define GetResource(p, res) res.Parse(p) - -static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s) -{ - s.Resource.Parse(p); - if (oldVersion) - { - s.PartNumber = 1; - s.Id = Get32(p + 24); - s.RefCount = Get32(p + 28); - memcpy(s.Hash, p + 32, kHashSize); - } - else - { - s.PartNumber = Get16(p + 24); - s.RefCount = Get32(p + 26); - memcpy(s.Hash, p + 30, kHashSize); - } -} - -static const wchar_t *kLongPath = L"[LongPath]"; - -UString CDatabase::GetItemPath(const int index1) const -{ - int size = 0; - int index = index1; - int newLevel; - for (newLevel = 0;; newLevel = 1) - { - const CItem &item = Items[index]; - index = item.Parent; - if (index >= 0 || !SkipRoot) - size += item.Name.Length() + newLevel; - if (index < 0) - break; - if ((UInt32)size >= ((UInt32)1 << 16)) - return kLongPath; - } - - wchar_t temp[16]; - int imageLen = 0; - if (ShowImageNumber) - { - ConvertUInt32ToString(-1 - index, temp); - imageLen = MyStringLen(temp); - size += imageLen + 1; - } - if ((UInt32)size >= ((UInt32)1 << 16)) - return kLongPath; - - UString path; - wchar_t *s = path.GetBuffer(size); - s[size] = 0; - if (ShowImageNumber) - { - memcpy(s, temp, imageLen * sizeof(wchar_t)); - s[imageLen] = WCHAR_PATH_SEPARATOR; - } - - index = index1; - - for (newLevel = 0;; newLevel = 1) - { - const CItem &item = Items[index]; - index = item.Parent; - if (index >= 0 || !SkipRoot) - { - if (newLevel) - s[--size] = WCHAR_PATH_SEPARATOR; - size -= item.Name.Length(); - memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length()); - } - if (index < 0) - { - path.ReleaseBuffer(); - return path; - } - } -} - -static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) -{ - ft->dwLowDateTime = Get32(p); - ft->dwHighDateTime = Get32(p + 4); -} - -static HRESULT ReadName(const Byte *p, int size, UString &dest) -{ - if (size == 0) - return S_OK; - if (Get16(p + size) != 0) - return S_FALSE; - wchar_t *s = dest.GetBuffer(size / 2); - for (int i = 0; i <= size; i += 2) - *s++ = Get16(p + i); - dest.ReleaseBuffer(); - return S_OK; -} - -HRESULT CDatabase::ParseDirItem(size_t pos, int parent) -{ - if ((pos & 7) != 0) - return S_FALSE; - - int prevIndex = -1; - for (int numItems = 0;; numItems++) - { - if (OpenCallback) - { - UInt64 numFiles = Items.Size(); - if ((numFiles & 0x3FF) == 0) - { - RINOK(OpenCallback->SetCompleted(&numFiles, NULL)); - } - } - size_t rem = DirSize - pos; - if (pos < DirStartOffset || pos > DirSize || rem < 8) - return S_FALSE; - const Byte *p = DirData + pos; - UInt64 len = Get64(p); - if (len == 0) - { - if (parent < 0 && numItems != 1) - SkipRoot = false; - DirProcessed += 8; - return S_OK; - } - if ((len & 7) != 0 || rem < len) - return S_FALSE; - if (!IsOldVersion) - if (len < 0x28) - return S_FALSE; - DirProcessed += (size_t)len; - if (DirProcessed > DirSize) - return S_FALSE; - int extraOffset = 0; - if (IsOldVersion) - { - if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0)) - { - extraOffset = 0x10; - } - } - else if (Get64(p + 8) == 0) - extraOffset = 0x24; - if (extraOffset) - { - if (prevIndex == -1) - return S_FALSE; - UInt32 fileNameLen = Get16(p + extraOffset); - if ((fileNameLen & 1) != 0) - return S_FALSE; - /* Probably different versions of ImageX can use different number of - additional ZEROs. So we don't use exact check. */ - UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len) - return S_FALSE; - - UString name; - RINOK(ReadName(p + extraOffset + 2, fileNameLen, name)); - - CItem &prevItem = Items[prevIndex]; - if (name.IsEmpty() && !prevItem.HasStream()) - { - if (IsOldVersion) - prevItem.Id = Get32(p + 8); - else - memcpy(prevItem.Hash, p + 0x10, kHashSize); - } - else - { - CItem item; - item.Name = prevItem.Name + L':' + name; - item.CTime = prevItem.CTime; - item.ATime = prevItem.ATime; - item.MTime = prevItem.MTime; - if (IsOldVersion) - { - item.Id = Get32(p + 8); - memset(item.Hash, 0, kHashSize); - } - else - memcpy(item.Hash, p + 0x10, kHashSize); - item.Attrib = 0; - item.Order = Order++; - item.Parent = parent; - Items.Add(item); - } - pos += (size_t)len; - continue; - } - - UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; - if (len < dirRecordSize) - return S_FALSE; - - CItem item; - item.Attrib = Get32(p + 8); - // item.SecurityId = Get32(p + 0xC); - UInt64 subdirOffset = Get64(p + 0x10); - UInt32 timeOffset = IsOldVersion ? 0x18: 0x28; - GetFileTimeFromMem(p + timeOffset, &item.CTime); - GetFileTimeFromMem(p + timeOffset + 8, &item.ATime); - GetFileTimeFromMem(p + timeOffset + 16, &item.MTime); - if (IsOldVersion) - { - item.Id = Get32(p + 0x10); - memset(item.Hash, 0, kHashSize); - } - else - { - memcpy(item.Hash, p + 0x40, kHashSize); - } - // UInt32 numStreams = Get16(p + dirRecordSize - 6); - UInt32 shortNameLen = Get16(p + dirRecordSize - 4); - UInt32 fileNameLen = Get16(p + dirRecordSize - 2); - - if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) - return S_FALSE; - - UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); - UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - - if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) - return S_FALSE; - p += dirRecordSize; - - RINOK(ReadName(p, fileNameLen, item.Name)); - RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName)); - - if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir())) - SkipRoot = false; - - /* - // there are some extra data for some files. - p -= dirRecordSize; - p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); - if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len) - p = p; - */ - - /* - if (parent >= 0) - { - UString s = GetItemPath(parent) + L"\\" + item.Name; - printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s); - } - */ - - if (fileNameLen == 0 && item.IsDir() && !item.HasStream()) - item.Attrib = 0x10; // some swm archives have system/hidden attributes for root - - item.Parent = parent; - prevIndex = Items.Add(item); - if (item.IsDir() && subdirOffset != 0) - { - RINOK(ParseDirItem((size_t)subdirOffset, prevIndex)); - } - Items[prevIndex].Order = Order++; - pos += (size_t)len; - } -} - -HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent) -{ - DirData = buf; - DirSize = buf.GetCapacity(); - - size_t pos = 0; - if (DirSize < 8) - return S_FALSE; - const Byte *p = DirData; - UInt32 totalLength = Get32(p); - if (IsOldVersion) - { - for (pos = 4;; pos += 8) - { - if (pos + 4 > DirSize) - return S_FALSE; - UInt32 n = Get32(p + pos); - if (n == 0) - break; - if (pos + 8 > DirSize) - return S_FALSE; - totalLength += Get32(p + pos + 4); - if (totalLength > DirSize) - return S_FALSE; - } - pos += totalLength + 4; - pos = (pos + 7) & ~(size_t)7; - if (pos > DirSize) - return S_FALSE; - } - else - { - - // UInt32 numEntries = Get32(p + 4); - pos += 8; - { - /* - CRecordVector<UInt64> entryLens; - UInt64 sum = 0; - for (UInt32 i = 0; i < numEntries; i++) - { - if (pos + 8 > DirSize) - return S_FALSE; - UInt64 len = Get64(p + pos); - entryLens.Add(len); - sum += len; - pos += 8; - } - pos += (size_t)sum; // skip security descriptors - while ((pos & 7) != 0) - pos++; - if (pos != totalLength) - return S_FALSE; - */ - if (totalLength == 0) - pos = 8; - else if (totalLength < 8) - return S_FALSE; - else - pos = totalLength; - } - } - DirStartOffset = DirProcessed = pos; - RINOK(ParseDirItem(pos, parent)); - if (DirProcessed == DirSize) - return S_OK; - /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but - reference to that folder is empty */ - if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 && - Get64(p + DirSize - 8) == 0) - return S_OK; - return S_FALSE; -} - -HRESULT CHeader::Parse(const Byte *p) -{ - UInt32 headerSize = Get32(p + 8); - Version = Get32(p + 0x0C); - Flags = Get32(p + 0x10); - if (!IsSupported()) - return S_FALSE; - ChunkSize = Get32(p + 0x14); - if (ChunkSize != kChunkSize && ChunkSize != 0) - return S_FALSE; - int offset; - if (IsOldVersion()) - { - if (headerSize != 0x60) - return S_FALSE; - memset(Guid, 0, 16); - offset = 0x18; - PartNumber = 1; - NumParts = 1; - } - else - { - if (headerSize < 0x74) - return S_FALSE; - memcpy(Guid, p + 0x18, 16); - PartNumber = Get16(p + 0x28); - NumParts = Get16(p + 0x2A); - offset = 0x2C; - if (IsNewVersion()) - { - NumImages = Get32(p + offset); - offset += 4; - } - } - GetResource(p + offset, OffsetResource); - GetResource(p + offset + 0x18, XmlResource); - GetResource(p + offset + 0x30, MetadataResource); - if (IsNewVersion()) - { - if (headerSize < 0xD0) - return S_FALSE; - BootIndex = Get32(p + 0x48); - IntegrityResource.Parse(p + offset + 0x4C); - } - return S_OK; -} - -const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; - -HRESULT ReadHeader(IInStream *inStream, CHeader &h) -{ - Byte p[kHeaderSizeMax]; - RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax)); - if (memcmp(p, kSignature, kSignatureSize) != 0) - return S_FALSE; - return h.Parse(p); -} - -static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader &h, CDatabase &db) -{ - CByteBuffer offsetBuf; - RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL)); - size_t i; - size_t streamInfoSize = oldVersion ? kStreamInfoSize + 2 : kStreamInfoSize; - for (i = 0; offsetBuf.GetCapacity() - i >= streamInfoSize; i += streamInfoSize) - { - CStreamInfo s; - GetStream(oldVersion, (const Byte *)offsetBuf + i, s); - if (s.PartNumber == h.PartNumber) - db.Streams.Add(s); - } - return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE; -} - -static bool IsEmptySha(const Byte *data) -{ - for (int i = 0; i < kHashSize; i++) - if (data[i] != 0) - return false; - return true; -} - -HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback) -{ - OpenCallback = openCallback; - IsOldVersion = h.IsOldVersion(); - RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL)); - RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this)); - bool needBootMetadata = !h.MetadataResource.IsEmpty(); - Order = 0; - if (h.PartNumber == 1) - { - int imageIndex = 1; - for (int i = 0; i < Streams.Size(); i++) - { - // if (imageIndex > 1) break; - const CStreamInfo &si = Streams[i]; - if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber) - continue; - Byte hash[kHashSize]; - CByteBuffer metadata; - RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash)); - if (memcmp(hash, si.Hash, kHashSize) != 0 && - !(h.IsOldVersion() && IsEmptySha(si.Hash))) - return S_FALSE; - NumImages++; - RINOK(ParseImageDirs(metadata, -(int)(++imageIndex))); - if (needBootMetadata) - if (h.MetadataResource.Offset == si.Resource.Offset) - needBootMetadata = false; - } - } - - if (needBootMetadata) - { - CByteBuffer metadata; - RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL)); - RINOK(ParseImageDirs(metadata, -1)); - NumImages++; - } - return S_OK; -} - - -static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) -{ - int res = MyCompare(p1->PartNumber, p2->PartNumber); - if (res != 0) - return res; - return MyCompare(p1->Resource.Offset, p2->Resource.Offset); -} - -static int CompareIDs(const int *p1, const int *p2, void *param) -{ - const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; - return MyCompare(streams[*p1].Id, streams[*p2].Id); -} - -static int CompareHashRefs(const int *p1, const int *p2, void *param) -{ - const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; - return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); -} - -static int FindId(const CRecordVector<CStreamInfo> &streams, - const CIntVector &sortedByHash, UInt32 id) -{ - int left = 0, right = streams.Size(); - while (left != right) - { - int mid = (left + right) / 2; - int streamIndex = sortedByHash[mid]; - UInt32 id2 = streams[streamIndex].Id; - if (id == id2) - return streamIndex; - if (id < id2) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int FindHash(const CRecordVector<CStreamInfo> &streams, - const CIntVector &sortedByHash, const Byte *hash) -{ - int left = 0, right = streams.Size(); - while (left != right) - { - int mid = (left + right) / 2; - int streamIndex = sortedByHash[mid]; - UInt32 i; - const Byte *hash2 = streams[streamIndex].Hash; - for (i = 0; i < kHashSize; i++) - if (hash[i] != hash2[i]) - break; - if (i == kHashSize) - return streamIndex; - if (hash[i] < hash2[i]) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int CompareItems(const int *a1, const int *a2, void *param) -{ - const CObjectVector<CItem> &items = ((CDatabase *)param)->Items; - const CItem &i1 = items[*a1]; - const CItem &i2 = items[*a2]; - - if (i1.IsDir() != i2.IsDir()) - return i1.IsDir() ? 1 : -1; - int res = MyCompare(i1.StreamIndex, i2.StreamIndex); - if (res != 0) - return res; - return MyCompare(i1.Order, i2.Order); -} - -HRESULT CDatabase::Sort(bool skipRootDir) -{ - Streams.Sort(CompareStreamsByPos, NULL); - - { - CIntVector sortedByHash; - { - for (int i = 0; i < Streams.Size(); i++) - sortedByHash.Add(i); - if (IsOldVersion) - sortedByHash.Sort(CompareIDs, &Streams); - else - sortedByHash.Sort(CompareHashRefs, &Streams); - } - - for (int i = 0; i < Items.Size(); i++) - { - CItem &item = Items[i]; - item.StreamIndex = -1; - if (item.HasStream()) - if (IsOldVersion) - item.StreamIndex = FindId(Streams, sortedByHash, item.Id); - else - item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash); - } - } - - { - CRecordVector<bool> used; - int i; - for (i = 0; i < Streams.Size(); i++) - { - const CStreamInfo &s = Streams[i]; - used.Add(s.Resource.IsMetadata() && s.PartNumber == 1); - // used.Add(false); - } - for (i = 0; i < Items.Size(); i++) - { - CItem &item = Items[i]; - if (item.StreamIndex >= 0) - used[item.StreamIndex] = true; - } - for (i = 0; i < Streams.Size(); i++) - if (!used[i]) - { - CItem item; - item.StreamIndex = i; - item.HasMetadata = false; - Items.Add(item); - } - } - - SortedItems.Reserve(Items.Size()); - for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++) - SortedItems.Add(i); - SortedItems.Sort(CompareItems, this); - return S_OK; -} - -}} |