diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2007-01-20 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:15:49 +0300 |
commit | d9666cf046a8453b33b3e2fbf4d82295a9f87df3 (patch) | |
tree | c722ed19b844b53042aec0c1d7d2f8381140a5ed /CPP/7zip/Archive/Tar/TarIn.cpp | |
parent | 804edc5756fede54dbb1aefda6d39d306111938d (diff) |
4.44 beta
Diffstat (limited to 'CPP/7zip/Archive/Tar/TarIn.cpp')
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarIn.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp new file mode 100755 index 00000000..86afc482 --- /dev/null +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -0,0 +1,248 @@ +// Archive/TarIn.cpp + +#include "StdAfx.h" + +#include "TarIn.h" +#include "TarHeader.h" + +#include "Common/StringToInt.h" +#include "Windows/Defs.h" + +#include "../../Common/StreamUtils.h" + +namespace NArchive { +namespace NTar { + +HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize) +{ + RINOK(ReadStream(m_Stream, data, size, &processedSize)); + m_Position += processedSize; + return S_OK; +} + +HRESULT CInArchive::Open(IInStream *inStream) +{ + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position)); + m_Stream = inStream; + return S_OK; +} + +static void MyStrNCpy(char *dest, const char *src, int size) +{ + for (int i = 0; i < size; i++) + { + char c = src[i]; + dest[i] = c; + if (c == 0) + break; + } +} + +static bool OctalToNumber(const char *srcString, int size, UInt64 &res) +{ + char sz[32]; + MyStrNCpy(sz, srcString, size); + sz[size] = 0; + const char *end; + int i; + for (i = 0; sz[i] == ' '; i++); + res = ConvertOctStringToUInt64(sz + i, &end); + return (*end == ' ' || *end == 0); +} + +static bool OctalToNumber32(const char *srcString, int size, UInt32 &res) +{ + UInt64 res64; + if (!OctalToNumber(srcString, size, res64)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + +static bool IsRecordLast(const char *record) +{ + for (int i = 0; i < NFileHeader::kRecordSize; i++) + if (record[i] != 0) + return false; + return true; +} + +static void ReadString(const char *s, int size, AString &result) +{ + if (size > NFileHeader::kRecordSize) + size = NFileHeader::kNameSize; + char tempString[NFileHeader::kRecordSize + 1]; + MyStrNCpy(tempString, s, size); + tempString[size] = '\0'; + result = tempString; +} + +static char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +HRESULT CInArchive::GetNextItemReal(bool &filled, CItemEx &item) +{ + item.LongLinkSize = 0; + // NFileHeader::CRecord record; + char record[NFileHeader::kRecordSize]; + char *cur = record; + + filled = false; + + UInt32 processedSize; + item.HeaderPosition = m_Position; + RINOK(ReadBytes(record, NFileHeader::kRecordSize, processedSize)); + if (processedSize == 0 || + (processedSize == NFileHeader::kRecordSize && IsRecordLast(record))) + return S_OK; + if (processedSize < NFileHeader::kRecordSize) + return S_FALSE; + + // NFileHeader::CHeader &header = record.Header; + + AString name; + ReadString(cur, NFileHeader::kNameSize, name); + cur += NFileHeader::kNameSize; + + item.Name.Empty(); + int i; + for (i = 0; i < name.Length(); i++) + { + char c = name[i]; + if (((Byte)c) < 0x08) + { + return S_FALSE; + } + if (((Byte)c) < 0x20) + { + item.Name += '['; + item.Name += GetHex((Byte)(((Byte)c) >> 4)); + item.Name += GetHex((Byte)(((Byte)c) & 0xF)); + item.Name += ']'; + } + else + item.Name += c; + } + + RIF(OctalToNumber32(cur, 8, item.Mode)); + cur += 8; + + if (!OctalToNumber32(cur, 8, item.UID)) + item.UID = 0; + cur += 8; + + if (!OctalToNumber32(cur, 8, item.GID)) + item.GID = 0; + cur += 8; + + RIF(OctalToNumber(cur, 12, item.Size)); + cur += 12; + + RIF(OctalToNumber32(cur, 12, item.ModificationTime)); + cur += 12; + + UInt32 checkSum; + RIF(OctalToNumber32(cur, 8, checkSum)); + memmove(cur, NFileHeader::kCheckSumBlanks, 8); + cur += 8; + + item.LinkFlag = *cur++; + + ReadString(cur, NFileHeader::kNameSize, item.LinkName); + cur += NFileHeader::kNameSize; + + memmove(item.Magic, cur, 8); + cur += 8; + + ReadString(cur, NFileHeader::kUserNameSize, item.UserName); + cur += NFileHeader::kUserNameSize; + ReadString(cur, NFileHeader::kUserNameSize, item.GroupName); + cur += NFileHeader::kUserNameSize; + + item.DeviceMajorDefined = (cur[0] != 0); + RIF(OctalToNumber32(cur, 8, item.DeviceMajor)); + cur += 8; + + item.DeviceMinorDefined = (cur[0] != 0); + RIF(OctalToNumber32(cur, 8, item.DeviceMinor)); + cur += 8; + + AString prefix; + ReadString(cur, NFileHeader::kPrefixSize, prefix); + cur += NFileHeader::kPrefixSize; + if (!prefix.IsEmpty() && item.IsMagic()) + item.Name = prefix + AString('/') + item.Name; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kLink) + item.Size = 0; + + + UInt32 checkSumReal = 0; + for(i = 0; i < NFileHeader::kRecordSize; i++) + checkSumReal += Byte(record[i]); + + if (checkSumReal != checkSum) + return S_FALSE; + + filled = true; + return S_OK; +} + +HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) +{ + RINOK(GetNextItemReal(filled, item)); + if (!filled) + return S_OK; + // GNUtar extension + if (item.LinkFlag == 'L') + { + if (item.Name.Compare(NFileHeader::kLongLink) != 0) + if (item.Name.Compare(NFileHeader::kLongLink2) != 0) + return S_FALSE; + UInt64 headerPosition = item.HeaderPosition; + + UInt32 processedSize; + AString fullName; + char *buffer = fullName.GetBuffer((UInt32)item.Size + 1); + RINOK(ReadBytes(buffer, (UInt32)item.Size, processedSize)); + buffer[item.Size] = '\0'; + fullName.ReleaseBuffer(); + if (processedSize != item.Size) + return S_FALSE; + RINOK(Skeep((0 - item.Size) & 0x1FF)); + RINOK(GetNextItemReal(filled, item)); + item.Name = fullName; + item.LongLinkSize = item.HeaderPosition - headerPosition; + item.HeaderPosition = headerPosition; + } + else if (item.LinkFlag == 'g' || item.LinkFlag == 'x') + { + // pax Extended Header + return S_OK; + } + else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) + return S_FALSE; + return S_OK; +} + +HRESULT CInArchive::Skeep(UInt64 numBytes) +{ + UInt64 newPostion; + RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion)); + m_Position += numBytes; + if (m_Position != newPostion) + return E_FAIL; + return S_OK; +} + + +HRESULT CInArchive::SkeepDataRecords(UInt64 dataSize) +{ + return Skeep((dataSize + 0x1FF) & (~((UInt64)0x1FF))); +} + +}} |