Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/CpioHandler.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/CpioHandler.cpp834
1 files changed, 504 insertions, 330 deletions
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index 0f32ef66..9c1271c4 100755..100644
--- a/CPP/7zip/Archive/CpioHandler.cpp
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -2,12 +2,15 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
-#include "Common/StringToInt.h"
+#include "../../../C/CpuArch.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -18,24 +21,30 @@
#include "Common/ItemNameUtils.h"
+using namespace NWindows;
+
namespace NArchive {
namespace NCpio {
-namespace NFileHeader
-{
- namespace NMagic
- {
- const char *kMagic1 = "070701";
- const char *kMagic2 = "070702";
- const char *kMagic3 = "070707";
- const char *kEndName = "TRAILER!!!";
+static const Byte kMagicBin0 = 0xC7;
+static const Byte kMagicBin1 = 0x71;
- const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
- }
+// #define MAGIC_ASCII { '0', '7', '0', '7', '0' }
+
+static const Byte kMagicHex = '1'; // New ASCII Format
+static const Byte kMagicHexCrc = '2'; // New CRC Format
+static const Byte kMagicOct = '7'; // Portable ASCII Format
+
+static const char *kName_TRAILER = "TRAILER!!!";
+
+static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4;
+static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11;
+static const unsigned k_HexRecord_Size = 6 + 13 * 8;
+
+static const unsigned k_RecordSize_Max = k_HexRecord_Size;
- const UInt32 kRecord2Size = 26;
/*
- struct CRecord2
+ struct CBinRecord
{
unsigned short c_magic;
short c_dev;
@@ -49,13 +58,10 @@ namespace NFileHeader
unsigned short c_namesize;
unsigned short c_filesizes[2];
};
- */
-
- const UInt32 kRecordSize = 110;
- /*
- struct CRecord
+
+ struct CHexRecord
{
- char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format
+ char Magic[6];
char inode[8];
char Mode[8];
char UID[8];
@@ -69,15 +75,26 @@ namespace NFileHeader
char RDevMinor[8]; //only valid for chr and blk special files
char NameSize[8]; // count includes terminating NUL in pathname
char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
- bool CheckMagic() const
- { return memcmp(Magic, NMagic::kMagic1, 6) == 0 ||
- memcmp(Magic, NMagic::kMagic2, 6) == 0; };
};
- */
+*/
- const UInt32 kOctRecordSize = 76;
-
-}
+enum EType
+{
+ k_Type_BinLe,
+ k_Type_BinBe,
+ k_Type_Oct,
+ k_Type_Hex,
+ k_Type_HexCrc
+};
+
+static const char *k_Types[] =
+{
+ "Binary LE"
+ , "Binary BE"
+ , "Portable ASCII"
+ , "New ASCII"
+ , "New CRC"
+};
struct CItem
{
@@ -86,12 +103,9 @@ struct CItem
UInt32 Mode;
UInt32 UID;
UInt32 GID;
- UInt32 Size;
+ UInt64 Size;
UInt32 MTime;
- // char LinkFlag;
- // AString LinkName; ?????
- char Magic[8];
UInt32 NumLinks;
UInt32 DevMajor;
UInt32 DevMinor;
@@ -100,394 +114,479 @@ struct CItem
UInt32 ChkSum;
UInt32 Align;
+ EType Type;
+
+ UInt32 HeaderSize;
+ UInt64 HeaderPos;
+ bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; }
+ bool IsCrcFormat() const { return Type == k_Type_HexCrc; };
bool IsDir() const { return (Mode & 0170000) == 0040000; }
+ bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; }
+ UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; };
};
-class CItemEx: public CItem
+enum EErrorType
{
-public:
- UInt64 HeaderPosition;
- UInt32 HeaderSize;
- UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; };
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd,
};
-const UInt32 kMaxBlockSize = NFileHeader::kRecordSize;
-
-class CInArchive
+struct CInArchive
{
- CMyComPtr<IInStream> m_Stream;
- UInt64 m_Position;
-
- UInt16 _blockSize;
- Byte _block[kMaxBlockSize];
- UInt32 _blockPos;
- Byte ReadByte();
- UInt16 ReadUInt16();
- UInt32 ReadUInt32();
+ ISequentialInStream *Stream;
+ UInt64 Processed;
- bool ReadNumber(UInt32 &resultValue);
- bool ReadOctNumber(int size, UInt32 &resultValue);
-
- HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
-public:
- HRESULT Open(IInStream *inStream);
- HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
- HRESULT Skip(UInt64 numBytes);
- HRESULT SkipDataRecords(UInt64 dataSize, UInt32 align);
+ HRESULT Read(void *data, size_t *size);
+ HRESULT GetNextItem(CItem &item, EErrorType &errorType);
};
-HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+HRESULT CInArchive::Read(void *data, size_t *size)
{
- size_t realProcessedSize = size;
- RINOK(ReadStream(m_Stream, data, &realProcessedSize));
- processedSize = (UInt32)realProcessedSize;
- m_Position += processedSize;
- return S_OK;
+ HRESULT res = ReadStream(Stream, data, size);
+ Processed += *size;
+ return res;
}
-Byte CInArchive::ReadByte()
+static bool ReadHex(const Byte *p, UInt32 &resVal)
{
- if (_blockPos >= _blockSize)
- throw "Incorrect cpio archive";
- return _block[_blockPos++];
+ char sz[16];
+ memcpy(sz, p, 8);
+ sz[8] = 0;
+ const char *end;
+ resVal = ConvertHexStringToUInt32(sz, &end);
+ return (unsigned)(end - sz) == 8;
}
-UInt16 CInArchive::ReadUInt16()
+static bool ReadOct6(const Byte *p, UInt32 &resVal)
{
- UInt16 value = 0;
- for (int i = 0; i < 2; i++)
- {
- Byte b = ReadByte();
- value |= (UInt16(b) << (8 * i));
- }
- return value;
+ char sz[16];
+ memcpy(sz, p, 6);
+ sz[6] = 0;
+ const char *end;
+ resVal = ConvertOctStringToUInt32(sz, &end);
+ return (unsigned)(end - sz) == 6;
}
-UInt32 CInArchive::ReadUInt32()
+static bool ReadOct11(const Byte *p, UInt64 &resVal)
{
- UInt32 value = 0;
- for (int i = 0; i < 4; i++)
- {
- Byte b = ReadByte();
- value |= (UInt32(b) << (8 * i));
- }
- return value;
+ char sz[16];
+ memcpy(sz, p, 11);
+ sz[11] = 0;
+ const char *end;
+ resVal = ConvertOctStringToUInt64(sz, &end);
+ return (unsigned)(end - sz) == 11;
}
-HRESULT CInArchive::Open(IInStream *inStream)
-{
- RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
- m_Stream = inStream;
- return S_OK;
-}
-bool CInArchive::ReadNumber(UInt32 &resultValue)
-{
- resultValue = 0;
- for (int i = 0; i < 8; i++)
- {
- char c = char(ReadByte());
- int d;
- if (c >= '0' && c <= '9')
- d = c - '0';
- else if (c >= 'A' && c <= 'F')
- d = 10 + c - 'A';
- else if (c >= 'a' && c <= 'f')
- d = 10 + c - 'a';
- else
- return false;
- resultValue *= 0x10;
- resultValue += d;
- }
- return true;
-}
+#define READ_HEX(y) { if (!ReadHex(p2, y)) return S_OK; p2 += 8; }
+#define READ_OCT_6(y) { if (!ReadOct6(p2, y)) return S_OK; p2 += 6; }
+#define READ_OCT_11(y) { if (!ReadOct11(p2, y)) return S_OK; p2 += 11; }
-static bool OctalToNumber(const char *s, UInt64 &res)
+static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
{
- const char *end;
- res = ConvertOctStringToUInt64(s, &end);
- return (*end == ' ' || *end == 0);
+ while ((size & (align - 1)) != 0)
+ size++;
+ return size;
}
-static bool OctalToNumber32(const char *s, UInt32 &res)
-{
- UInt64 res64;
- if (!OctalToNumber(s, res64))
- return false;
- res = (UInt32)res64;
- return (res64 <= 0xFFFFFFFF);
-}
+static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); }
+static UInt32 Get32(const Byte *p, bool be) { return ((UInt32)Get16(p, be) << 16) + Get16(p + 2, be); }
-bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue)
-{
- char sz[32 + 4];
- int i;
- for (i = 0; i < size && i < 32; i++)
- sz[i] = (char)ReadByte();
- sz[i] = 0;
- return OctalToNumber32(sz, resultValue);
-}
+#define G16(offs, v) v = Get16(p + (offs), be)
+#define G32(offs, v) v = Get32(p + (offs), be)
-#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; }
-#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; }
-#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; }
+static const unsigned kNameSizeMax = 1 << 12;
-static unsigned short ConvertValue(unsigned short value, bool convert)
+API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size)
{
- if (!convert)
- return value;
- return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8));
-}
+ if (size < k_BinRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
-static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
-{
- while ((size & (align - 1)) != 0)
- size++;
- return size;
+ UInt32 nameSize;
+ UInt32 numLinks;
+ if (p[0] == '0')
+ {
+ if (p[1] != '7' ||
+ p[2] != '0' ||
+ p[3] != '7' ||
+ p[4] != '0')
+ return k_IsArc_Res_NO;
+ if (p[5] == '7')
+ {
+ if (size < k_OctRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
+ for (int i = 6; i < k_OctRecord_Size; i++)
+ {
+ char c = p[i];
+ if (c < '0' || c > '7')
+ return k_IsArc_Res_NO;
+ }
+ ReadOct6(p + 6 * 6, numLinks);
+ ReadOct6(p + 8 * 6 + 11, nameSize);
+ }
+ else if (p[5] == '1' || p[5] == '2')
+ {
+ if (size < k_HexRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
+ for (int i = 6; i < k_HexRecord_Size; i++)
+ {
+ char c = p[i];
+ if ((c < '0' || c > '9') &&
+ (c < 'A' || c > 'F') &&
+ (c < 'a' || c > 'f'))
+ return k_IsArc_Res_NO;
+ }
+ ReadHex(p + 6 + 4 * 8, numLinks);
+ ReadHex(p + 6 + 11 * 8, nameSize);
+ }
+ else
+ return k_IsArc_Res_NO;
+ }
+ else
+ {
+ UInt32 rDevMinor;
+ if (p[0] == kMagicBin0 && p[1] == kMagicBin1)
+ {
+ numLinks = GetUi16(p + 12);
+ rDevMinor = GetUi16(p + 14);
+ nameSize = GetUi16(p + 20);
+ }
+ else if (p[0] == kMagicBin1 && p[1] == kMagicBin0)
+ {
+ numLinks = GetBe16(p + 12);
+ rDevMinor = GetBe16(p + 14);
+ nameSize = GetBe16(p + 20);
+ }
+ else
+ return k_IsArc_Res_NO;
+
+ if (rDevMinor != 0)
+ return k_IsArc_Res_NO;
+ if (nameSize > (1 << 8))
+ return k_IsArc_Res_NO;
+ }
+ if (numLinks == 0 || numLinks >= (1 << 10))
+ return k_IsArc_Res_NO;
+ if (nameSize == 0 || nameSize > kNameSizeMax)
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
}
+#define READ_STREAM(_dest_, _size_) \
+ { size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \
+if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } }
-HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
+HRESULT CInArchive::GetNextItem(CItem &item, EErrorType &errorType)
{
- filled = false;
+ errorType = k_ErrorType_Corrupted;
- UInt32 processedSize;
- item.HeaderPosition = m_Position;
+ Byte p[k_RecordSize_Max];
- _blockSize = kMaxBlockSize;
- RINOK(ReadBytes(_block, 2, processedSize));
- if (processedSize != 2)
- return S_FALSE;
- _blockPos = 0;
+ READ_STREAM(p, k_BinRecord_Size)
UInt32 nameSize;
- bool oldBE =
- _block[0] == NFileHeader::NMagic::kMagicForRecord2[1] &&
- _block[1] == NFileHeader::NMagic::kMagicForRecord2[0];
-
- bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] &&
- _block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) ||
- oldBE;
-
- if (binMode)
+ if (p[0] != '0')
{
- RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize));
- if (processedSize != NFileHeader::kRecord2Size - 2)
- return S_FALSE;
+ bool be;
+ if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { be = false; item.Type = k_Type_BinLe; }
+ else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) { be = true; item.Type = k_Type_BinBe; }
+ else return S_FALSE;
+
item.Align = 2;
- _blockPos = 2;
item.DevMajor = 0;
- item.DevMinor = ConvertValue(ReadUInt16(), oldBE);
- item.inode = ConvertValue(ReadUInt16(), oldBE);
- item.Mode = ConvertValue(ReadUInt16(), oldBE);
- item.UID = ConvertValue(ReadUInt16(), oldBE);
- item.GID = ConvertValue(ReadUInt16(), oldBE);
- item.NumLinks = ConvertValue(ReadUInt16(), oldBE);
item.RDevMajor =0;
- item.RDevMinor = ConvertValue(ReadUInt16(), oldBE);
- UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE);
- UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE);
- item.MTime = (UInt32(timeHigh) << 16) + timeLow;
- nameSize = ConvertValue(ReadUInt16(), oldBE);
- UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE);
- UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE);
- item.Size = (UInt32(sizeHigh) << 16) + sizeLow;
-
item.ChkSum = 0;
- item.HeaderSize = GetAlignedSize(
- nameSize + NFileHeader::kRecord2Size, item.Align);
- nameSize = item.HeaderSize - NFileHeader::kRecord2Size;
+
+ G16(2, item.DevMinor);
+ G16(4, item.inode);
+ G16(6, item.Mode);
+ G16(8, item.UID);
+ G16(10, item.GID);
+ G16(12, item.NumLinks);
+ G16(14, item.RDevMinor);
+ G32(16, item.MTime);
+ G16(20, nameSize);
+ G32(22, item.Size);
+
+ /*
+ if (item.RDevMinor != 0)
+ return S_FALSE;
+ */
+
+ item.HeaderSize = GetAlignedSize(nameSize + k_BinRecord_Size, item.Align);
+ nameSize = item.HeaderSize - k_BinRecord_Size;
}
else
{
- RINOK(ReadBytes(_block + 2, 4, processedSize));
- if (processedSize != 4)
+ if (p[1] != '7' ||
+ p[2] != '0' ||
+ p[3] != '7' ||
+ p[4] != '0')
return S_FALSE;
-
- bool magicOK =
- memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 ||
- memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0;
- _blockPos = 6;
- if (magicOK)
+ if (p[5] == kMagicOct)
{
- RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize));
- if (processedSize != NFileHeader::kRecordSize - 6)
- return S_FALSE;
- item.Align = 4;
+ item.Type = k_Type_Oct;
+ READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size)
+ item.Align = 1;
+ item.DevMajor = 0;
+ item.RDevMajor = 0;
- GetFromHex(item.inode);
- GetFromHex(item.Mode);
- GetFromHex(item.UID);
- GetFromHex(item.GID);
- GetFromHex(item.NumLinks);
- UInt32 mTime;
- GetFromHex(mTime);
- item.MTime = mTime;
- GetFromHex(item.Size);
- GetFromHex(item.DevMajor);
- GetFromHex(item.DevMinor);
- GetFromHex(item.RDevMajor);
- GetFromHex(item.RDevMinor);
- GetFromHex(nameSize);
- GetFromHex(item.ChkSum);
- item.HeaderSize = GetAlignedSize(
- nameSize + NFileHeader::kRecordSize, item.Align);
- nameSize = item.HeaderSize - NFileHeader::kRecordSize;
+ const Byte *p2 = p + 6;
+ READ_OCT_6(item.DevMinor);
+ READ_OCT_6(item.inode);
+ READ_OCT_6(item.Mode);
+ READ_OCT_6(item.UID);
+ READ_OCT_6(item.GID);
+ READ_OCT_6(item.NumLinks);
+ READ_OCT_6(item.RDevMinor);
+ {
+ UInt64 mTime64;
+ READ_OCT_11(mTime64);
+ item.MTime = 0;
+ if (mTime64 < (UInt32)(Int32)-1)
+ item.MTime = (UInt32)mTime64;
+ }
+ READ_OCT_6(nameSize);
+ READ_OCT_11(item.Size); // ?????
+ item.HeaderSize = GetAlignedSize(nameSize + k_OctRecord_Size, item.Align);
+ nameSize = item.HeaderSize - k_OctRecord_Size;
}
else
{
- if (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0)
- return S_FALSE;
- RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize));
- if (processedSize != NFileHeader::kOctRecordSize - 6)
+ if (p[5] == kMagicHex)
+ item.Type = k_Type_Hex;
+ else if (p[5] == kMagicHexCrc)
+ item.Type = k_Type_HexCrc;
+ else
return S_FALSE;
- item.Align = 1;
- item.DevMajor = 0;
- GetFromOct6(item.DevMinor);
- GetFromOct6(item.inode);
- GetFromOct6(item.Mode);
- GetFromOct6(item.UID);
- GetFromOct6(item.GID);
- GetFromOct6(item.NumLinks);
- item.RDevMajor = 0;
- GetFromOct6(item.RDevMinor);
- UInt32 mTime;
- GetFromOct11(mTime);
- item.MTime = mTime;
- GetFromOct6(nameSize);
- GetFromOct11(item.Size); // ?????
- item.HeaderSize = GetAlignedSize(
- nameSize + NFileHeader::kOctRecordSize, item.Align);
- nameSize = item.HeaderSize - NFileHeader::kOctRecordSize;
+
+ READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size)
+
+ item.Align = 4;
+
+ const Byte *p2 = p + 6;
+ READ_HEX(item.inode);
+ READ_HEX(item.Mode);
+ READ_HEX(item.UID);
+ READ_HEX(item.GID);
+ READ_HEX(item.NumLinks);
+ READ_HEX(item.MTime);
+ {
+ UInt32 size32;
+ READ_HEX(size32);
+ item.Size = size32;
+ }
+ READ_HEX(item.DevMajor);
+ READ_HEX(item.DevMinor);
+ READ_HEX(item.RDevMajor);
+ READ_HEX(item.RDevMinor);
+ READ_HEX(nameSize);
+ READ_HEX(item.ChkSum);
+ if (nameSize >= kNameSizeMax)
+ return S_OK;
+ item.HeaderSize = GetAlignedSize(nameSize + k_HexRecord_Size, item.Align);
+ nameSize = item.HeaderSize - k_HexRecord_Size;
}
}
- if (nameSize == 0 || nameSize >= (1 << 27))
- return E_FAIL;
- RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize));
- if (processedSize != nameSize)
- return E_FAIL;
+ if (nameSize > kNameSizeMax)
+ return S_FALSE;
+ if (nameSize == 0 || nameSize >= kNameSizeMax)
+ return S_OK;
+ char *s = item.Name.GetBuffer(nameSize);
+ size_t processedSize = nameSize;
+ RINOK(Read(s, &processedSize));
+ s[nameSize] = 0;
item.Name.ReleaseBuffer();
- if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0)
+ if (processedSize != nameSize)
+ {
+ errorType = k_ErrorType_UnexpectedEnd;
return S_OK;
- filled = true;
- return S_OK;
-}
-
-HRESULT CInArchive::Skip(UInt64 numBytes)
-{
- UInt64 newPostion;
- RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
- m_Position += numBytes;
- if (m_Position != newPostion)
- return E_FAIL;
+ }
+ errorType = k_ErrorType_OK;
return S_OK;
}
-HRESULT CInArchive::SkipDataRecords(UInt64 dataSize, UInt32 align)
-{
- while ((dataSize & (align - 1)) != 0)
- dataSize++;
- return Skip(dataSize);
-}
-
-
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
- CObjectVector<CItemEx> _items;
+ CObjectVector<CItem> _items;
CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ EType _Type;
+ EErrorType _error;
+ bool _isArc;
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-/*
-enum
+static const Byte kArcProps[] =
{
- kpidinode = kpidUserDefined,
- kpidiChkSum
+ kpidSubType
};
-*/
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidPosixAttrib, VT_UI4},
- // { L"inode", kpidinode, VT_UI4}
- // { L"CheckSum", kpidiChkSum, VT_UI4}
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidMTime,
+ kpidPosixAttrib,
+ kpidLinks
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps
-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- // try
+ NCOM::CPropVariant prop;
+ switch (propID)
{
- CInArchive archive;
+ case kpidSubType: prop = k_Types[_Type]; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc)
+ v |= kpv_ErrorFlags_IsNotArc;
+ switch (_error)
+ {
+ case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
+ case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break;
+ }
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+
UInt64 endPos = 0;
- bool needSetTotal = true;
- if (callback != NULL)
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (callback)
{
- RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
- RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(callback->SetTotal(NULL, &endPos));
}
- RINOK(archive.Open(stream));
-
_items.Clear();
+ CInArchive arc;
+
+ arc.Stream = stream;
+ arc.Processed = 0;
for (;;)
{
- CItemEx item;
- bool filled;
- HRESULT result = archive.GetNextItem(filled, item);
+ CItem item;
+ item.HeaderPos = arc.Processed;
+ HRESULT result = arc.GetNextItem(item, _error);
if (result == S_FALSE)
return S_FALSE;
if (result != S_OK)
return S_FALSE;
- if (!filled)
+ if (_error != k_ErrorType_OK)
+ {
+ if (_error == k_ErrorType_Corrupted)
+ arc.Processed = item.HeaderPos;
break;
+ }
+ if (_items.IsEmpty())
+ _Type = item.Type;
+ else if (_items.Back().Type != item.Type)
+ {
+ _error = k_ErrorType_Corrupted;
+ arc.Processed = item.HeaderPos;
+ break;
+ }
+ if (item.IsTrailer())
+ break;
+
_items.Add(item);
- archive.SkipDataRecords(item.Size, item.Align);
- if (callback != NULL)
+
{
- if (needSetTotal)
+ // archive.SkipDataRecords(item.Size, item.Align);
+ UInt64 dataSize = item.Size;
+ UInt32 align = item.Align;
+ while ((dataSize & (align - 1)) != 0)
+ dataSize++;
+
+ // _error = k_ErrorType_UnexpectedEnd; break;
+
+ arc.Processed += dataSize;
+ if (arc.Processed > endPos)
{
- RINOK(callback->SetTotal(NULL, &endPos));
- needSetTotal = false;
+ _error = k_ErrorType_UnexpectedEnd;
+ break;
}
- if (_items.Size() % 100 == 0)
+
+ UInt64 newPostion;
+ RINOK(stream->Seek(dataSize, STREAM_SEEK_CUR, &newPostion));
+ if (arc.Processed != newPostion)
+ return E_FAIL;
+ }
+
+ if (callback && (_items.Size() & 0xFF) == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos));
+ }
+ }
+ _phySize = arc.Processed;
+ if (_error != k_ErrorType_OK)
+ {
+ if (_items.Size() == 0)
+ return S_FALSE;
+ if (_items.Size() == 1 && _items[0].IsBin())
+ {
+ // probably it's false detected archive. So we return error
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ // Read tailing zeros.
+ // Most of cpio files use 512-bytes aligned zeros
+ UInt64 pos = arc.Processed;
+ const UInt32 kTailSize_MAX = 1 << 9;
+ Byte buf[kTailSize_MAX];
+
+ UInt32 rem = (kTailSize_MAX - (UInt32)pos) & (kTailSize_MAX - 1);
+ if (rem != 0)
+ {
+ rem++; // we need to see that it's end of file
+ size_t processed = rem;
+ RINOK(ReadStream(stream, buf, &processed));
+ if (processed < rem)
{
- UInt64 numFiles = _items.Size();
- UInt64 numBytes = item.HeaderPosition;
- RINOK(callback->SetCompleted(&numFiles, &numBytes));
+ unsigned i;
+ for (i = 0; i < processed && buf[i] == 0; i++);
+ if (i == processed)
+ _phySize += processed;
}
}
}
- if (_items.Size() == 0)
- return S_FALSE;
-
+
+ _isArc = true;
_stream = stream;
}
- /*
- catch(...)
- {
- return S_FALSE;
- }
- */
return S_OK;
COM_TRY_END
}
@@ -496,6 +595,10 @@ STDMETHODIMP CHandler::Close()
{
_items.Clear();
_stream.Release();
+ _phySize = 0;
+ _Type = k_Type_BinLe;
+ _isArc = false;
+ _error = k_ErrorType_OK;
return S_OK;
}
@@ -508,12 +611,24 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- const CItemEx &item = _items[index];
+ NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidPath:
+ {
+ UString res;
+ bool needConvert = true;
+ #ifdef _WIN32
+ if (ConvertUTF8ToUnicode(item.Name, res))
+ needConvert = false;
+ #endif
+ if (needConvert)
+ res = MultiByteToUnicodeString(item.Name, CP_OEMCP);
+ prop = NItemName::GetOSName(res);
+ break;
+ }
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize:
case kpidPackSize:
@@ -524,12 +639,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (item.MTime != 0)
{
FILETIME utc;
- NWindows::NTime::UnixTimeToFileTime(item.MTime, utc);
+ NTime::UnixTimeToFileTime(item.MTime, utc);
prop = utc;
}
break;
}
case kpidPosixAttrib: prop = item.Mode; break;
+ case kpidLinks: prop = item.NumLinks; break;
/*
case kpidinode: prop = item.inode; break;
case kpidiChkSum: prop = item.ChkSum; break;
@@ -540,11 +656,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
COM_TRY_END
}
+class COutStreamWithSum:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _calculate;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _crc = 0;
+ }
+ void EnableCalc(bool calculate) { _calculate = calculate; }
+ void InitCRC() { _crc = 0; }
+ UInt64 GetSize() const { return _size; }
+ UInt32 GetCRC() const { return _crc; }
+};
+
+STDMETHODIMP COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ {
+ UInt32 crc = 0;
+ for (UInt32 i = 0; i < size; i++)
+ crc += (UInt32)(((const Byte *)data)[i]);
+ _crc += crc;
+ }
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
@@ -568,6 +726,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CMyComPtr<ISequentialInStream> inStream(streamSpec);
streamSpec->SetStream(_stream);
+ COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum;
+ CMyComPtr<ISequentialOutStream> outStreamSum(outStreamSumSpec);
+
for (i = 0; i < numItems; i++)
{
lps->InSize = lps->OutSize = currentTotalSize;
@@ -577,7 +738,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
- const CItemEx &item = _items[index];
+ const CItem &item = _items[index];
RINOK(extractCallback->GetStream(index, &outStream, askMode));
currentTotalSize += item.Size;
if (item.IsDir())
@@ -588,19 +749,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
if (!testMode && !outStream)
continue;
+ outStreamSumSpec->Init(item.IsCrcFormat());
+ outStreamSumSpec->SetStream(outStream);
+ outStream.Release();
+
RINOK(extractCallback->PrepareOperation(askMode));
- if (testMode)
- {
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
- continue;
- }
RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
streamSpec->Init(item.Size);
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
- outStream.Release();
- RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
- NExtract::NOperationResult::kOK:
- NExtract::NOperationResult::kDataError));
+ RINOK(copyCoder->Code(inStream, outStreamSum, NULL, NULL, progress));
+ outStreamSumSpec->ReleaseStream();
+ Int32 res = NExtract::NOperationResult::kDataError;
+ if (copyCoderSpec->TotalSize == item.Size)
+ {
+ res = NExtract::NOperationResult::kOK;
+ if (item.IsCrcFormat() && item.ChkSum != outStreamSumSpec->GetCRC())
+ res = NExtract::NOperationResult::kCRCError;
+ }
+ RINOK(extractCallback->SetOperationResult(res));
}
return S_OK;
COM_TRY_END
@@ -609,15 +774,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
- const CItemEx &item = _items[index];
+ const CItem &item = _items[index];
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 };
+ { "Cpio", "cpio", 0, 0xED,
+ 3 + 5 + 2 + 2,
+ {
+ 5, '0', '7', '0', '7', '0',
+ 2, kMagicBin0, kMagicBin1,
+ 2, kMagicBin1, kMagicBin0,
+ },
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ CreateArc, NULL, IsArc_Cpio };
REGISTER_ARC(Cpio)