mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-10 16:07:09 -06:00
9.34
This commit is contained in:
committed by
Kornel Lesiński
parent
83f8ddcc5b
commit
f08f4dcc3c
228
CPP/7zip/Archive/Tar/TarOut.cpp
Executable file → Normal file
228
CPP/7zip/Archive/Tar/TarOut.cpp
Executable file → Normal file
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/IntToString.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "TarOut.h"
|
||||
@@ -11,26 +9,15 @@
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)
|
||||
HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
|
||||
{
|
||||
return WriteStream(m_Stream, buffer, size);
|
||||
Pos += size;
|
||||
return WriteStream(m_Stream, data, size);
|
||||
}
|
||||
|
||||
void COutArchive::Create(ISequentialOutStream *outStream)
|
||||
static void MyStrNCpy(char *dest, const char *src, unsigned size)
|
||||
{
|
||||
m_Stream = outStream;
|
||||
}
|
||||
|
||||
static AString MakeOctalString(UInt64 value)
|
||||
{
|
||||
char s[32];
|
||||
ConvertUInt64ToString(value, s, 8);
|
||||
return AString(s) + ' ';
|
||||
}
|
||||
|
||||
static void MyStrNCpy(char *dest, const char *src, int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
char c = src[i];
|
||||
dest[i] = c;
|
||||
@@ -39,54 +26,53 @@ static void MyStrNCpy(char *dest, const char *src, int size)
|
||||
}
|
||||
}
|
||||
|
||||
static bool MakeOctalString8(char *s, UInt32 value)
|
||||
static bool WriteOctal_8(char *s, UInt32 val)
|
||||
{
|
||||
AString tempString = MakeOctalString(value);
|
||||
|
||||
const int kMaxSize = 8;
|
||||
if (tempString.Length() >= kMaxSize)
|
||||
const unsigned kNumDigits = 8 - 1;
|
||||
if (val >= ((UInt32)1 << (kNumDigits * 3)))
|
||||
return false;
|
||||
int numSpaces = kMaxSize - (tempString.Length() + 1);
|
||||
for (int i = 0; i < numSpaces; i++)
|
||||
s[i] = ' ';
|
||||
MyStringCopy(s + numSpaces, (const char *)tempString);
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void MakeOctalString12(char *s, UInt64 value)
|
||||
static void WriteOctal_12(char *s, UInt64 val)
|
||||
{
|
||||
AString tempString = MakeOctalString(value);
|
||||
const int kMaxSize = 12;
|
||||
if (tempString.Length() > kMaxSize)
|
||||
const unsigned kNumDigits = 12 - 1;
|
||||
if (val >= ((UInt64)1 << (kNumDigits * 3)))
|
||||
{
|
||||
// GNU extension;
|
||||
s[0] = (char)(Byte)0x80;
|
||||
s[1] = s[2] = s[3] = 0;
|
||||
for (int i = 0; i < 8; i++, value <<= 8)
|
||||
s[4 + i] = (char)(value >> 56);
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
return;
|
||||
}
|
||||
int numSpaces = kMaxSize - tempString.Length();
|
||||
for (int i = 0; i < numSpaces; i++)
|
||||
s[i] = ' ';
|
||||
memmove(s + numSpaces, (const char *)tempString, tempString.Length());
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void MakeOctalString12_From_Int64(char *s, Int64 value)
|
||||
static void WriteOctal_12_Signed(char *s, Int64 val)
|
||||
{
|
||||
if (value >= 0)
|
||||
if (val >= 0)
|
||||
{
|
||||
MakeOctalString12(s, value);
|
||||
WriteOctal_12(s, val);
|
||||
return;
|
||||
}
|
||||
s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
|
||||
for (int i = 0; i < 8; i++, value <<= 8)
|
||||
s[4 + i] = (char)(value >> 56);
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
}
|
||||
|
||||
static bool CopyString(char *dest, const AString &src, int maxSize)
|
||||
static bool CopyString(char *dest, const AString &src, unsigned maxSize)
|
||||
{
|
||||
if (src.Length() >= maxSize)
|
||||
if (src.Len() >= maxSize)
|
||||
return false;
|
||||
MyStringCopy(dest, (const char *)src);
|
||||
return true;
|
||||
@@ -97,25 +83,22 @@ static bool CopyString(char *dest, const AString &src, int maxSize)
|
||||
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
{
|
||||
char record[NFileHeader::kRecordSize];
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
char *cur = record;
|
||||
int i;
|
||||
for (i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
record[i] = 0;
|
||||
|
||||
// RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize));
|
||||
if (item.Name.Length() > NFileHeader::kNameSize)
|
||||
if (item.Name.Len() > NFileHeader::kNameSize)
|
||||
return E_FAIL;
|
||||
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8;
|
||||
|
||||
MakeOctalString12(cur, item.PackSize); cur += 12;
|
||||
MakeOctalString12_From_Int64(cur, item.MTime); cur += 12;
|
||||
WriteOctal_12(cur, item.PackSize); cur += 12;
|
||||
WriteOctal_12_Signed(cur, item.MTime); cur += 12;
|
||||
|
||||
memmove(cur, NFileHeader::kCheckSumBlanks, 8);
|
||||
memset(cur, ' ', 8);
|
||||
cur += 8;
|
||||
|
||||
*cur++ = item.LinkFlag;
|
||||
@@ -123,7 +106,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
memmove(cur, item.Magic, 8);
|
||||
memcpy(cur, item.Magic, 8);
|
||||
cur += 8;
|
||||
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
|
||||
@@ -132,64 +115,127 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
cur += NFileHeader::kGroupNameSize;
|
||||
|
||||
|
||||
if (item.DeviceMajorDefined)
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor));
|
||||
cur += 8;
|
||||
if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8;
|
||||
if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8;
|
||||
|
||||
if (item.DeviceMinorDefined)
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor));
|
||||
cur += 8;
|
||||
if (item.IsSparse())
|
||||
{
|
||||
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
|
||||
WriteOctal_12(record + 483, item.Size);
|
||||
for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 386 + 24 * i;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 checkSum = 0;
|
||||
{
|
||||
for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSum += (Byte)record[i];
|
||||
}
|
||||
/* we use GNU TAR scheme:
|
||||
checksum field is formatted differently from the
|
||||
other fields: it has [6] digits, a null, then a space. */
|
||||
// RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum));
|
||||
const unsigned kNumDigits = 6;
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7));
|
||||
checkSum >>= 3;
|
||||
}
|
||||
record[148 + 6] = 0;
|
||||
}
|
||||
|
||||
UInt32 checkSumReal = 0;
|
||||
for (i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSumReal += Byte(record[i]);
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));
|
||||
if (item.IsSparse())
|
||||
{
|
||||
for (unsigned i = 4; i < item.SparseBlocks.Size();)
|
||||
{
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 24 * t;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
}
|
||||
|
||||
return WriteBytes(record, NFileHeader::kRecordSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteHeader(const CItem &item)
|
||||
{
|
||||
int nameSize = item.Name.Length();
|
||||
if (nameSize < NFileHeader::kNameSize)
|
||||
unsigned nameSize = item.Name.Len();
|
||||
unsigned linkSize = item.LinkName.Len();
|
||||
|
||||
/* There two versions of GNU tar:
|
||||
OLDGNU_FORMAT: it writes short name and zero at the end
|
||||
GNU_FORMAT: it writes only short name without zero at the end
|
||||
we write it as OLDGNU_FORMAT with zero at the end */
|
||||
|
||||
if (nameSize < NFileHeader::kNameSize &&
|
||||
linkSize < NFileHeader::kNameSize)
|
||||
return WriteHeaderReal(item);
|
||||
|
||||
CItem modifiedItem = item;
|
||||
int nameStreamSize = nameSize + 1;
|
||||
modifiedItem.PackSize = nameStreamSize;
|
||||
modifiedItem.LinkFlag = 'L';
|
||||
modifiedItem.Name = NFileHeader::kLongLink;
|
||||
modifiedItem.LinkName.Empty();
|
||||
RINOK(WriteHeaderReal(modifiedItem));
|
||||
RINOK(WriteBytes(item.Name, nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
CItem mi = item;
|
||||
mi.Name = NFileHeader::kLongLink;
|
||||
mi.LinkName.Empty();
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const AString *name;
|
||||
// We suppose that GNU tar also writes item for long link before item for LongName?
|
||||
if (i == 0)
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
|
||||
name = &item.LinkName;
|
||||
}
|
||||
else
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
|
||||
name = &item.Name;
|
||||
}
|
||||
if (name->Len() < NFileHeader::kNameSize)
|
||||
continue;
|
||||
unsigned nameStreamSize = name->Len() + 1;
|
||||
mi.PackSize = nameStreamSize;
|
||||
RINOK(WriteHeaderReal(mi));
|
||||
RINOK(WriteBytes((const char *)*name, nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
}
|
||||
|
||||
modifiedItem = item;
|
||||
modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1);
|
||||
return WriteHeaderReal(modifiedItem);
|
||||
mi = item;
|
||||
if (mi.Name.Len() >= NFileHeader::kNameSize)
|
||||
mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1);
|
||||
if (mi.LinkName.Len() >= NFileHeader::kNameSize)
|
||||
mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1);
|
||||
return WriteHeaderReal(mi);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
|
||||
{
|
||||
UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1));
|
||||
unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
|
||||
if (lastRecordSize == 0)
|
||||
return S_OK;
|
||||
UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte residualBytes[NFileHeader::kRecordSize];
|
||||
for (UInt32 i = 0; i < residualSize; i++)
|
||||
residualBytes[i] = 0;
|
||||
return WriteBytes(residualBytes, residualSize);
|
||||
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte buf[NFileHeader::kRecordSize];
|
||||
memset(buf, 0, rem);
|
||||
return WriteBytes(buf, rem);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteFinishHeader()
|
||||
{
|
||||
Byte record[NFileHeader::kRecordSize];
|
||||
int i;
|
||||
for (i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
record[i] = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user