⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wimin.cpp

📁 7z一个高压缩比的压缩程序源代码,重要的是里面的算法值得学习
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    if (pos + 8 > size)
      return S_FALSE;
    const Byte *p = base + pos;
    UInt64 length = Get64(p);
    if (length == 0)
      return S_OK;
    if (pos + 102 > size || pos + length + 8 > size || length > ((UInt64)1 << 62))
      return S_FALSE;
    CItem item;
    item.Attrib = Get32(p + 8);
    // item.SecurityId = Get32(p + 0xC);
    UInt64 subdirOffset = Get64(p + 0x10);
    GetFileTimeFromMem(p + 0x28, &item.CTime);
    GetFileTimeFromMem(p + 0x30, &item.ATime);
    GetFileTimeFromMem(p + 0x38, &item.MTime);
    memcpy(item.Hash, p + 0x40, kHashSize);

    // UInt16 shortNameLen = Get16(p + 98);
    UInt16 fileNameLen = Get16(p + 100);
    
    size_t tempPos = pos + 102;
    if (tempPos + fileNameLen > size)
      return S_FALSE;
    
    wchar_t *sz = item.Name.GetBuffer(prefix.Length() + fileNameLen / 2 + 1);
    MyStringCopy(sz, (const wchar_t *)prefix);
    sz += prefix.Length();
    for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2)
      *sz++ = Get16(base + tempPos + i);
    *sz++ = '\0';
    item.Name.ReleaseBuffer();
    if (fileNameLen == 0 && item.isDir() && !item.HasStream())
    {
      item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
      item.Name.Delete(item.Name.Length() - 1);
    }
    items.Add(item);
    pos += (size_t)length;
    if (item.isDir() && (subdirOffset != 0))
    {
      if (subdirOffset >= size)
        return S_FALSE;
      RINOK(ParseDirItem(base, (size_t)subdirOffset, size, item.Name + WCHAR_PATH_SEPARATOR, items));
    }
  }
}

static HRESULT ParseDir(const Byte *base, size_t size,
    const UString &prefix, CObjectVector<CItem> &items)
{
  size_t pos = 0;
  if (pos + 8 > size)
    return S_FALSE;
  const Byte *p = base + pos;
  UInt32 totalLength = Get32(p);
  // UInt32 numEntries = Get32(p + 4);
  pos += 8;
  {
    /*
    CRecordVector<UInt64> entryLens;
    UInt64 sum = 0;
    for (UInt32 i = 0; i < numEntries; i++)
    {
      if (pos + 8 > size)
        return S_FALSE;
      UInt64 len = Get64(p + pos);
      entryLens.Add(len);
      sum += len;
      pos += 8;
    }
    pos += sum; // skeep security descriptors
    while ((pos & 7) != 0)
      pos++;
    if (pos != totalLength)
      return S_FALSE;
    */
    pos = totalLength;
  }
  return ParseDirItem(base, pos, size, prefix, items);
}

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 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);
}

int CompareItems(void *const *a1, void *const *a2, void * /* param */)
{
  const CItem &i1 = **((const CItem **)a1);
  const CItem &i2 = **((const CItem **)a2);

  if (i1.isDir() != i2.isDir())
    return (i1.isDir()) ? 1 : -1;
  if (i1.isDir())
    return -MyStringCompareNoCase(i1.Name, i2.Name);

  int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
  if (res != 0)
    return res;
  return MyStringCompareNoCase(i1.Name, i2.Name);
}

static int FindHash(const CRecordVector<CStreamInfo> &streams,
    const CRecordVector<int> &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;
}

HRESULT CHeader::Parse(const Byte *p)
{
  UInt32 haderSize = Get32(p + 8);
  if (haderSize < 0x74)
    return S_FALSE;
  Version = Get32(p + 0x0C);
  Flags = Get32(p + 0x10);
  if (!IsSupported())
    return S_FALSE;
  UInt32 chunkSize = Get32(p + 0x14);
  if (chunkSize != kChunkSize && chunkSize != 0)
    return S_FALSE;
  memcpy(Guid, p + 0x18, 16);
  PartNumber = Get16(p + 0x28);
  NumParts = Get16(p + 0x2A);
  int 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 (haderSize < 0xD0)
      return S_FALSE;
    IntegrityResource.Parse(p + offset + 0x4C);
    BootIndex = Get32(p + 0x48);
  }
  */
  return S_OK;
}

HRESULT ReadHeader(IInStream *inStream, CHeader &h)
{
  const UInt32 kHeaderSizeMax = 0xD0;
  Byte p[kHeaderSizeMax];
  RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
  if (memcmp(p, kSignature, kSignatureSize) != 0)
    return S_FALSE;
  return h.Parse(p);
}

HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
{
  CByteBuffer offsetBuf;
  RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
  for (size_t i = 0; i + kStreamInfoSize <= offsetBuf.GetCapacity(); i += kStreamInfoSize)
  {
    CStreamInfo s;
    GetStream((const Byte *)offsetBuf + i, s);
    if (s.PartNumber == h.PartNumber)
      db.Streams.Add(s);
  }
  return S_OK;
}

HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDatabase &db)
{
  RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));

  RINOK(ReadStreams(inStream, h, db));
  bool needBootMetadata = !h.MetadataResource.IsEmpty();
  if (h.PartNumber == 1)
  {
    int imageIndex = 1;
    for (int j = 0; j < db.Streams.Size(); j++)
    {
      // if (imageIndex > 1) break;
      const CStreamInfo &si = db.Streams[j];
      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)
        return S_FALSE;
      wchar_t sz[32];
      ConvertUInt64ToString(imageIndex++, sz);
      UString s = sz;
      s += WCHAR_PATH_SEPARATOR;
      RINOK(ParseDir(metadata, metadata.GetCapacity(), s, db.Items));
      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(ParseDir(metadata, metadata.GetCapacity(), L"0" WSTRING_PATH_SEPARATOR, db.Items));
  }
  return S_OK;
}


HRESULT SortDatabase(CDatabase &db)
{
  db.Streams.Sort(CompareStreamsByPos, NULL);

  {
    CRecordVector<int> sortedByHash;
    {
      for (int j = 0; j < db.Streams.Size(); j++)
        sortedByHash.Add(j);
      sortedByHash.Sort(CompareHashRefs, &db.Streams);
    }
    
    for (int i = 0; i < db.Items.Size(); i++)
    {
      CItem &item = db.Items[i];
      item.StreamIndex = -1;
      if (item.HasStream())
        item.StreamIndex = FindHash(db.Streams, sortedByHash, item.Hash);
    }
  }

  {
    CRecordVector<bool> used;
    int j;
    for (j = 0; j < db.Streams.Size(); j++)
    {
      const CStreamInfo &s = db.Streams[j];
      used.Add(s.Resource.IsMetadata() && s.PartNumber == 1);
    }
    for (int i = 0; i < db.Items.Size(); i++)
    {
      CItem &item = db.Items[i];
      if (item.StreamIndex >= 0)
        used[item.StreamIndex] = true;
    }
    for (j = 0; j < db.Streams.Size(); j++)
      if (!used[j])
      {
        CItem item;
        item.StreamIndex = j;
        item.HasMetadata = false;
        db.Items.Add(item);
    }
  }
  
  db.Items.Sort(CompareItems, NULL);
  return S_OK;
}

}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -