Files
easy7zip/CPP/7zip/Archive/Tar/TarIn.cpp
Igor Pavlov d9666cf046 4.44 beta
2016-05-28 00:15:49 +01:00

249 lines
5.7 KiB
C++
Executable File

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