Files
easy7zip/CPP/7zip/Archive/Tar/TarIn.cpp
Igor Pavlov c65230d858 9.18
2016-05-28 00:16:04 +01:00

208 lines
5.2 KiB
C++
Executable File

// TarIn.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "Common/StringToInt.h"
#include "../../Common/StreamUtils.h"
#include "TarIn.h"
namespace NArchive {
namespace NTar {
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 *buf)
{
for (int i = 0; i < NFileHeader::kRecordSize; i++)
if (buf[i] != 0)
return false;
return true;
}
static void ReadString(const char *s, int size, AString &result)
{
char temp[NFileHeader::kRecordSize + 1];
MyStrNCpy(temp, s, size);
temp[size] = '\0';
result = temp;
}
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{
char buf[NFileHeader::kRecordSize];
char *p = buf;
error.Empty();
filled = false;
bool thereAreEmptyRecords = false;
for (;;)
{
size_t processedSize = NFileHeader::kRecordSize;
RINOK(ReadStream(stream, buf, &processedSize));
if (processedSize == 0)
{
if (!thereAreEmptyRecords )
error = "There are no trailing zero-filled records";
return S_OK;
}
if (processedSize != NFileHeader::kRecordSize)
{
error = "There is no correct record at the end of archive";
return S_OK;
}
item.HeaderSize += NFileHeader::kRecordSize;
if (!IsRecordLast(buf))
break;
thereAreEmptyRecords = true;
}
if (thereAreEmptyRecords)
{
error = "There are data after end of archive";
return S_OK;
}
ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;
if (GetBe32(p) == (UInt32)1 << 31)
{
// GNU extension
item.Size = GetBe64(p + 4);
}
else
{
RIF(OctalToNumber(p, 12, item.Size));
}
p += 12;
RIF(OctalToNumber32(p, 12, item.MTime)); p += 12;
UInt32 checkSum;
RIF(OctalToNumber32(p, 8, checkSum));
memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8;
item.LinkFlag = *p++;
ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
memcpy(item.Magic, p, 8); p += 8;
ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8;
item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8;
AString prefix;
ReadString(p, NFileHeader::kPrefixSize, prefix);
p += NFileHeader::kPrefixSize;
if (!prefix.IsEmpty() && item.IsMagic() &&
(item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
item.Name = prefix + AString('/') + item.Name;
if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
item.Size = 0;
UInt32 checkSumReal = 0;
for (int i = 0; i < NFileHeader::kRecordSize; i++)
checkSumReal += (Byte)buf[i];
if (checkSumReal != checkSum)
return S_FALSE;
filled = true;
return S_OK;
}
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{
item.HeaderSize = 0;
bool flagL = false;
bool flagK = false;
AString nameL;
AString nameK;
for (;;)
{
RINOK(GetNextItemReal(stream, filled, item, error));
if (!filled)
return S_OK;
if (item.LinkFlag == 'L' || // NEXT file has a long name
item.LinkFlag == 'K') // NEXT file has a long linkname
{
AString *name;
if (item.LinkFlag == 'L')
{ if (flagL) return S_FALSE; flagL = true; name = &nameL; }
else
{ if (flagK) return S_FALSE; flagK = true; name = &nameK; }
if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
item.Name.Compare(NFileHeader::kLongLink2) != 0)
return S_FALSE;
if (item.Size > (1 << 14))
return S_FALSE;
int packSize = (int)item.GetPackSize();
char *buf = name->GetBuffer(packSize);
RINOK(ReadStream_FALSE(stream, buf, packSize));
item.HeaderSize += packSize;
buf[(size_t)item.Size] = '\0';
name->ReleaseBuffer();
continue;
}
if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
{
// pax Extended Header
}
else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
{
// GNU Extensions to the Archive Format
}
else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
return S_FALSE;
if (flagL) item.Name = nameL;
if (flagK) item.LinkName = nameK;
return S_OK;
}
}
}}