diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2007-08-03 04:00:00 +0400 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:15:53 +0300 |
commit | 33ccab7e728a996800e166d849fe1e92a17e1afe (patch) | |
tree | e9d1148bae1da8127a3eefbc217aafd736fb74af /CPP/7zip/Archive/Com/ComIn.cpp | |
parent | d14d4dcdefbef6695a618c3cdac05ba2ede5572e (diff) |
4.52 beta
Diffstat (limited to 'CPP/7zip/Archive/Com/ComIn.cpp')
-rwxr-xr-x | CPP/7zip/Archive/Com/ComIn.cpp | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Com/ComIn.cpp b/CPP/7zip/Archive/Com/ComIn.cpp new file mode 100755 index 00000000..0db3f1c6 --- /dev/null +++ b/CPP/7zip/Archive/Com/ComIn.cpp @@ -0,0 +1,371 @@ +// Archive/ComIn.cpp + +#include "StdAfx.h" + +extern "C" +{ +#include "../../../../C/Alloc.h" +} + +#include "Common/MyCom.h" +#include "../../Common/StreamUtils.h" +#include "Common/IntToString.h" + +#include "ComIn.h" + +namespace NArchive{ +namespace NCom{ + +static const UInt32 kSignatureSize = 8; +static const Byte kSignature[kSignatureSize] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; + +static HRESULT ReadBytes(ISequentialInStream *inStream, void *data, UInt32 size) +{ + UInt32 realProcessedSize; + RINOK(ReadStream(inStream, data, size, &realProcessedSize)); + return (realProcessedSize == size) ? S_OK : S_FALSE; +} + +#ifdef LITTLE_ENDIAN_UNALIGN +#define GetUi16(p) (*(const UInt16 *)(p)) +#define GetUi32(p) (*(const UInt32 *)(p)) +#else +#define GetUi16(p) ((p)[0] | ((UInt16)(p)[1] << 8)) +#define GetUi32(p) ((p)[0] | ((UInt32)(p)[1] << 8) | ((UInt32)(p)[2] << 16) | ((UInt32)(p)[3] << 24)) +#endif + + +void CUInt32Buf::Free() +{ + MyFree(_buf); + _buf = 0; +} + +bool CUInt32Buf::Allocate(UInt32 numItems) +{ + Free(); + if (numItems == 0) + return true; + size_t newSize = (size_t)numItems * sizeof(UInt32); + if (newSize / sizeof(UInt32) != numItems) + return false; + _buf = (UInt32 *)MyAlloc(newSize); + return (_buf != 0); +} + +static HRESULT ReadSector(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid) +{ + RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL)); + return ReadBytes(inStream, buf, (UInt32)1 << sectorSizeBits); +} + +static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid, UInt32 *dest) +{ + RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)); + UInt32 sectorSize = (UInt32)1 << sectorSizeBits; + for (UInt32 t = 0; t < sectorSize; t += 4) + *dest++ = GetUi32(buf + t); + return S_OK; +} + +static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) +{ + ft->dwLowDateTime = GetUi32(p); + ft->dwHighDateTime = GetUi32(p + 4); +} + +static void ReadItem(Byte *p, CItem &item, bool mode64bit) +{ + memcpy(item.Name, p, 64); + // item.NameSize = GetUi16(p + 64); + item.Type = p[66]; + item.LeftDid = GetUi32(p + 68); + item.RightDid = GetUi32(p + 72); + item.SonDid = GetUi32(p + 76); + // item.Flags = GetUi32(p + 96); + GetFileTimeFromMem(p + 100, &item.CreationTime); + GetFileTimeFromMem(p + 108, &item.LastWriteTime); + item.Sid = GetUi32(p + 116); + item.Size = GetUi32(p + 120); + if (mode64bit) + item.Size |= ((UInt64)GetUi32(p + 124) << 32); +} + +static const UInt32 kNoDid = 0xFFFFFFFF; + +HRESULT CDatabase::AddNode(int parent, UInt32 did) +{ + if (did == kNoDid) + return S_OK; + if (did >= (UInt32)Items.Size()) + return S_FALSE; + const CItem &item = Items[did]; + if (item.IsEmpty()) + return S_FALSE; + CRef ref; + ref.Parent = parent; + ref.Did = did; + int index = Refs.Add(ref); + if (Refs.Size() > Items.Size()) + return S_FALSE; + RINOK(AddNode(parent, item.LeftDid)); + RINOK(AddNode(parent, item.RightDid)); + if (item.IsDir()) + { + RINOK(AddNode(index, item.SonDid)); + } + return S_OK; +} + +static const char kCharOpenBracket = '['; +static const char kCharCloseBracket = ']'; + +UString DWORDToString(UInt32 val) +{ + wchar_t buf[32]; + ConvertUInt64ToString(val, buf); + return buf; +} + +static UString CompoundNameToFileName(const UString &s) +{ + UString res; + for (int i = 0; i < s.Length(); i++) + { + wchar_t c = s[i]; + if (c < 0x20) + { + res += kCharOpenBracket; + res += DWORDToString(c); + res += kCharCloseBracket; + } + else + res += c; + } + return res; +} + +static char g_MsiChars[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; + +static const wchar_t *kMsi_ID = L""; // L"{msi}"; + +static const int kMsiNumBits = 6; +static const UInt32 kMsiNumChars = 1 << kMsiNumBits; +static const UInt32 kMsiCharMask = kMsiNumChars - 1; +static const UInt32 kMsiStartUnicodeChar = 0x3800; +static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1); + +bool CompoundMsiNameToFileName(const UString &name, UString &resultName) +{ + resultName.Empty(); + for (int i = 0; i < name.Length(); i++) + { + wchar_t c = name[i]; + if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange) + return false; + if (i == 0) + resultName += kMsi_ID; + c -= kMsiStartUnicodeChar; + + UInt32 c0 = c & kMsiCharMask; + UInt32 c1 = c >> kMsiNumBits; + + if (c1 <= kMsiNumChars) + { + resultName += (wchar_t)g_MsiChars[c0]; + if (c1 == kMsiNumChars) + break; + resultName += (wchar_t)g_MsiChars[c1]; + } + else + resultName += L'!'; + } + return true; +} + +static UString ConvertName(const Byte *p) +{ + UString s; + for (int i = 0; i < kNameSizeMax; i += 2) + { + wchar_t c = (p[i] | (wchar_t)p[i + 1] << 8); + if (c == 0) + break; + s += c; + } + UString msiName; + if (CompoundMsiNameToFileName(s, msiName)) + return msiName; + return CompoundNameToFileName(s); +} + +UString CDatabase::GetItemPath(UInt32 index) const +{ + UString s; + while (index != kNoDid) + { + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.Did]; + if (!s.IsEmpty()) + s = (UString)WCHAR_PATH_SEPARATOR + s; + s = ConvertName(item.Name) + s; + index = ref.Parent; + } + return s; +} + +HRESULT OpenArchive(IInStream *inStream, CDatabase &db) +{ + static const UInt32 kHeaderSize = 512; + Byte p[kHeaderSize]; + RINOK(ReadBytes(inStream, p, kHeaderSize)); + if (memcmp(p, kSignature, kSignatureSize) != 0) + return S_FALSE; + UInt16 majorVer = GetUi16(p + 0x1A); + if (majorVer > 4) + return S_FALSE; + if (GetUi16(p + 0x1C) != 0xFFFE) + return S_FALSE; + UInt16 sectorSizeBits = GetUi16(p + 0x1E); + bool mode64bit = (sectorSizeBits >= 12); + UInt16 miniSectorSizeBits = GetUi16(p + 0x20); + db.SectorSizeBits = sectorSizeBits; + db.MiniSectorSizeBits = miniSectorSizeBits; + + if (sectorSizeBits > 28 || miniSectorSizeBits > 28 || + sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits) + return S_FALSE; + UInt32 numSectorsForFAT = GetUi32(p + 0x2C); + db.LongStreamMinSize = GetUi32(p + 0x38); + + UInt32 sectSize = (UInt32)1 << (int)(sectorSizeBits); + + CByteBuffer sect; + sect.SetCapacity(sectSize); + + int ssb2 = (int)(sectorSizeBits - 2); + UInt32 numSidsInSec = (UInt32)1 << ssb2; + UInt32 numFatItems = numSectorsForFAT << ssb2; + if ((numFatItems >> ssb2) != numSectorsForFAT) + return S_FALSE; + db.FatSize = numFatItems; + + { + CUInt32Buf bat; + UInt32 numSectorsForBat = GetUi32(p + 0x48); + const UInt32 kNumHeaderBatItems = 109; + UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); + if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) + return S_FALSE; + if (!bat.Allocate(numBatItems)) + return S_FALSE; + UInt32 i; + for (i = 0; i < kNumHeaderBatItems; i++) + bat[i] = GetUi32(p + 0x4c + i * 4); + UInt32 sid = GetUi32(p + 0x44); + for (UInt32 s = 0; s < numSectorsForBat; s++) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)); + i += numSidsInSec - 1; + sid = bat[i]; + } + numBatItems = i; + + if (!db.Fat.Allocate(numFatItems)) + return S_FALSE; + UInt32 j = 0; + + for (i = 0; i < numFatItems; j++, i += numSidsInSec) + { + if (j >= numBatItems) + return S_FALSE; + RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], db.Fat + i)); + } + } + + UInt32 numMatItems; + { + UInt32 numSectorsForMat = GetUi32(p + 0x40); + numMatItems = (UInt32)numSectorsForMat << ssb2; + if ((numMatItems >> ssb2) != numSectorsForMat) + return S_FALSE; + if (!db.Mat.Allocate(numMatItems)) + return S_FALSE; + UInt32 i; + UInt32 sid = GetUi32(p + 0x3C); + for (i = 0; i < numMatItems; i += numSidsInSec) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, db.Mat + i)); + if (sid >= numFatItems) + return S_FALSE; + sid = db.Fat[sid]; + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + } + + { + UInt32 sid = GetUi32(p + 0x30); + for (;;) + { + if (sid >= numFatItems) + return S_FALSE; + RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)); + for (UInt32 i = 0; i < sectSize; i += 128) + { + CItem item; + ReadItem(sect + i, item, mode64bit); + db.Items.Add(item); + } + sid = db.Fat[sid]; + if (sid == NFatID::kEndOfChain) + break; + } + } + + CItem root = db.Items[0]; + + { + UInt32 numSectorsInMiniStream; + { + UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; + if (numSatSects64 > NFatID::kMaxValue) + return S_FALSE; + numSectorsInMiniStream = (UInt32)numSatSects64; + } + db.NumSectorsInMiniStream = numSectorsInMiniStream; + if (!db.MiniSids.Allocate(numSectorsInMiniStream)) + return S_FALSE; + { + UInt64 matSize64 = (root.Size + (1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; + if (matSize64 > NFatID::kMaxValue) + return S_FALSE; + db.MatSize = (UInt32)matSize64; + if (numMatItems < db.MatSize) + return S_FALSE; + } + + + UInt32 sid = root.Sid; + for (UInt32 i = 0; ; i++) + { + if (sid == NFatID::kEndOfChain) + { + if (i != numSectorsInMiniStream) + return S_FALSE; + break; + } + if (i >= numSectorsInMiniStream) + return S_FALSE; + db.MiniSids[i] = sid; + if (sid >= numFatItems) + return S_FALSE; + sid = db.Fat[sid]; + } + } + + return db.AddNode(-1, root.SonDid); +} + +}} |