chore: initial commit (extracted from Launchers monorepo)

Plugin: ns7zip v2.0.0
Architectures: x86-ansi, x86-unicode, amd64-unicode
License: LGPL-2.1-or-later
This commit is contained in:
Simone
2026-04-29 14:07:51 +02:00
commit d074cc7c07
3848 changed files with 1076682 additions and 0 deletions
@@ -0,0 +1,496 @@
// IsoHandler.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/StreamUtils.h"
#include "../../Compress/CopyCoder.h"
#include "../Common/ItemNameUtils.h"
#include "IsoHandler.h"
using namespace NWindows;
using namespace NTime;
namespace NArchive {
namespace NIso {
static const Byte kProps[] =
{
kpidPath,
kpidIsDir,
kpidSize,
kpidPackSize,
kpidMTime,
// kpidCTime,
// kpidATime,
kpidPosixAttrib,
// kpidUserId,
// kpidGroupId,
// kpidLinks,
kpidSymLink
};
static const Byte kArcProps[] =
{
kpidComment,
kpidCTime,
kpidMTime,
// kpidHeadersSize
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * /* openArchiveCallback */))
{
COM_TRY_BEGIN
Close();
{
RINOK(_archive.Open(stream))
_stream = stream;
}
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::Close())
{
_archive.Clear();
_stream.Release();
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
{
*numItems = _archive.Refs.Size() + _archive.BootEntries.Size();
return S_OK;
}
static void AddString(AString &s, const char *name, const Byte *p, unsigned size)
{
unsigned i;
for (i = 0; i < size && p[i]; i++);
for (; i > 0 && p[i - 1] == ' '; i--);
if (i != 0)
{
AString d;
d.SetFrom((const char *)p, i);
s += name;
s += ": ";
s += d;
s.Add_LF();
}
}
static void AddProp_Size64(AString &s, const char *name, UInt64 size)
{
s += name;
s += ": ";
s.Add_UInt64(size);
s.Add_LF();
}
#define ADD_STRING(n, v) AddString(s, n, vol. v, sizeof(vol. v))
static void AddErrorMessage(AString &s, const char *message)
{
if (!s.IsEmpty())
s += ". ";
s += message;
}
Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
if (_stream)
{
const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
switch (propID)
{
case kpidComment:
{
AString s;
ADD_STRING("System", SystemId);
ADD_STRING("Volume", VolumeId);
ADD_STRING("VolumeSet", VolumeSetId);
ADD_STRING("Publisher", PublisherId);
ADD_STRING("Preparer", DataPreparerId);
ADD_STRING("Application", ApplicationId);
ADD_STRING("Copyright", CopyrightFileId);
ADD_STRING("Abstract", AbstractFileId);
ADD_STRING("Bib", BibFileId);
// ADD_STRING("EscapeSequence", EscapeSequence);
AddProp_Size64(s, "VolumeSpaceSize", vol.Get_VolumeSpaceSize_inBytes());
AddProp_Size64(s, "VolumeSetSize", vol.VolumeSetSize);
AddProp_Size64(s, "VolumeSequenceNumber", vol.VolumeSequenceNumber);
prop = s;
break;
}
case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
}
}
switch (propID)
{
case kpidPhySize: prop = _archive.PhySize; break;
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError;
prop = v;
break;
}
case kpidError:
{
AString s;
if (_archive.IncorrectBigEndian)
AddErrorMessage(s, "Incorrect big-endian headers");
if (_archive.SelfLinkedDirs)
AddErrorMessage(s, "Self-linked directory");
if (_archive.TooDeepDirs)
AddErrorMessage(s, "Too deep directory levels");
if (!s.IsEmpty())
prop = s;
break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
if (index >= (UInt32)_archive.Refs.Size())
{
index -= _archive.Refs.Size();
const CBootInitialEntry &be = _archive.BootEntries[index];
switch (propID)
{
case kpidPath:
{
AString s ("[BOOT]" STRING_PATH_SEPARATOR);
if (_archive.BootEntries.Size() != 1)
{
s.Add_UInt32(index + 1);
s.Add_Minus();
}
s += be.GetName();
prop = s;
break;
}
case kpidIsDir: prop = false; break;
case kpidSize:
case kpidPackSize:
prop = (UInt64)_archive.GetBootItemSize(index);
break;
}
}
else
{
const CRef &ref = _archive.Refs[index];
const CDir &item = ref.Dir->_subItems[ref.Index];
switch (propID)
{
case kpidPath:
// if (item.FileId.GetCapacity() >= 0)
{
UString s;
if (_archive.IsJoliet())
item.GetPathU(s);
else
s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1')
s.DeleteFrom(s.Len() - 2);
if (!s.IsEmpty() && s.Back() == L'.')
s.DeleteBack();
NItemName::ReplaceToOsSlashes_Remove_TailSlash(s);
prop = s;
}
break;
case kpidSymLink:
if (_archive.IsSusp)
{
UInt32 mode;
if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode))
{
if (MY_LIN_S_ISLNK(mode))
{
AString s8;
if (item.GetSymLink(_archive.SuspSkipSize, s8))
{
UString s = MultiByteToUnicodeString(s8, CP_OEMCP);
prop = s;
}
}
}
}
break;
case kpidPosixAttrib:
/*
case kpidLinks:
case kpidUserId:
case kpidGroupId:
*/
{
if (_archive.IsSusp)
{
UInt32 t = 0;
switch (propID)
{
case kpidPosixAttrib: t = k_Px_Mode; break;
/*
case kpidLinks: t = k_Px_Links; break;
case kpidUserId: t = k_Px_User; break;
case kpidGroupId: t = k_Px_Group; break;
*/
}
UInt32 v;
if (item.GetPx(_archive.SuspSkipSize, t, v))
prop = v;
}
break;
}
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize:
case kpidPackSize:
if (!item.IsDir())
prop = (UInt64)ref.TotalSize;
break;
case kpidMTime:
// case kpidCTime:
// case kpidATime:
{
// if
item.DateTime.GetFileTime(prop);
/*
else
{
UInt32 t = 0;
switch (propID)
{
case kpidMTime: t = k_Tf_MTime; break;
case kpidCTime: t = k_Tf_CTime; break;
case kpidATime: t = k_Tf_ATime; break;
}
CRecordingDateTime dt;
if (item.GetTf(_archive.SuspSkipSize, t, dt))
{
FILETIME utc;
if (dt.GetFileTime(utc))
prop = utc;
}
}
*/
break;
}
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback))
{
COM_TRY_BEGIN
const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _archive.Refs.Size();
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
{
UInt32 index = (allFilesMode ? i : indices[i]);
if (index < (UInt32)_archive.Refs.Size())
{
const CRef &ref = _archive.Refs[index];
const CDir &item = ref.Dir->_subItems[ref.Index];
if (!item.IsDir())
totalSize += ref.TotalSize;
}
else
totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
}
RINOK(extractCallback->SetTotal(totalSize))
UInt64 currentTotalSize = 0;
UInt64 currentItemSize;
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, false);
CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
inStream->SetStream(_stream);
for (i = 0;; i++, currentTotalSize += currentItemSize)
{
lps->InSize = lps->OutSize = currentTotalSize;
RINOK(lps->SetCur())
if (i >= numItems)
break;
currentItemSize = 0;
Int32 opRes = NExtract::NOperationResult::kOK;
{
CMyComPtr<ISequentialOutStream> realOutStream;
const Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
const UInt32 index = allFilesMode ? i : indices[i];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
UInt64 blockIndex;
if (index < (UInt32)_archive.Refs.Size())
{
const CRef &ref = _archive.Refs[index];
const CDir &item = ref.Dir->_subItems[ref.Index];
if (item.IsDir())
{
RINOK(extractCallback->PrepareOperation(askMode))
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
continue;
}
currentItemSize = ref.TotalSize;
blockIndex = item.ExtentLocation;
}
else
{
unsigned bootIndex = index - _archive.Refs.Size();
const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
currentItemSize = _archive.GetBootItemSize(bootIndex);
blockIndex = be.LoadRBA;
}
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode))
if (index < (UInt32)_archive.Refs.Size())
{
const CRef &ref = _archive.Refs[index];
UInt64 offset = 0;
for (UInt32 e = 0; e < ref.NumExtents; e++)
{
const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
if (item2.Size == 0)
continue;
lps->InSize = lps->OutSize = currentTotalSize + offset;
RINOK(InStream_SeekSet(_stream, (UInt64)item2.ExtentLocation * kBlockSize))
inStream->Init(item2.Size);
RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
if (copyCoder->TotalSize != item2.Size)
{
opRes = NExtract::NOperationResult::kDataError;
break;
}
offset += item2.Size;
}
}
else
{
RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize))
inStream->Init(currentItemSize);
RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
if (copyCoder->TotalSize != currentItemSize)
opRes = NExtract::NOperationResult::kDataError;
}
// realOutStream.Release();
}
RINOK(extractCallback->SetOperationResult(opRes))
}
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
{
COM_TRY_BEGIN
*stream = NULL;
UInt64 blockIndex;
UInt64 currentItemSize;
if (index < _archive.Refs.Size())
{
const CRef &ref = _archive.Refs[index];
const CDir &item = ref.Dir->_subItems[ref.Index];
if (item.IsDir())
return S_FALSE;
if (ref.NumExtents > 1)
{
CExtentsStream *extentStreamSpec = new CExtentsStream();
CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
extentStreamSpec->Stream = _stream;
UInt64 virtOffset = 0;
for (UInt32 i = 0; i < ref.NumExtents; i++)
{
const CDir &item2 = ref.Dir->_subItems[ref.Index + i];
if (item2.Size == 0)
continue;
CSeekExtent se;
se.Phy = (UInt64)item2.ExtentLocation * kBlockSize;
se.Virt = virtOffset;
extentStreamSpec->Extents.Add(se);
virtOffset += item2.Size;
}
if (virtOffset != ref.TotalSize)
return S_FALSE;
CSeekExtent se;
se.Phy = 0;
se.Virt = virtOffset;
extentStreamSpec->Extents.Add(se);
extentStreamSpec->Init();
*stream = extentStream.Detach();
return S_OK;
}
currentItemSize = item.Size;
blockIndex = item.ExtentLocation;
}
else
{
unsigned bootIndex = index - _archive.Refs.Size();
const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
currentItemSize = _archive.GetBootItemSize(bootIndex);
blockIndex = be.LoadRBA;
}
return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream);
COM_TRY_END
}
}}
@@ -0,0 +1,24 @@
// IsoHandler.h
#ifndef ZIP7_INC_ISO_HANDLER_H
#define ZIP7_INC_ISO_HANDLER_H
#include "../../../Common/MyCom.h"
#include "../IArchive.h"
#include "IsoIn.h"
namespace NArchive {
namespace NIso {
Z7_CLASS_IMP_CHandler_IInArchive_1(
IInArchiveGetStream
)
CMyComPtr<IInStream> _stream;
CInArchive _archive;
};
}}
#endif
@@ -0,0 +1,12 @@
// Archive/Iso/Header.h
#include "StdAfx.h"
#include "IsoHeader.h"
namespace NArchive {
namespace NIso {
const char * const kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0";
}}
@@ -0,0 +1,64 @@
// Archive/IsoHeader.h
#ifndef ZIP7_INC_ARCHIVE_ISO_HEADER_H
#define ZIP7_INC_ARCHIVE_ISO_HEADER_H
#include "../../../Common/MyTypes.h"
namespace NArchive {
namespace NIso {
namespace NVolDescType
{
const Byte kBootRecord = 0;
const Byte kPrimaryVol = 1;
const Byte kSupplementaryVol = 2;
const Byte kVolParttition = 3;
const Byte kTerminator = 255;
}
const Byte kVersion = 1;
namespace NFileFlags
{
const Byte kDirectory = 1 << 1;
const Byte kNonFinalExtent = 1 << 7;
}
extern const char * const kElToritoSpec;
const UInt32 kStartPos = 0x8000;
namespace NBootEntryId
{
const Byte kValidationEntry = 1;
const Byte kInitialEntryNotBootable = 0;
const Byte kInitialEntryBootable = 0x88;
const Byte kMoreHeaders = 0x90;
const Byte kFinalHeader = 0x91;
const Byte kExtensionIndicator = 0x44;
}
namespace NBootPlatformId
{
const Byte kX86 = 0;
const Byte kPowerPC = 1;
const Byte kMac = 2;
}
const Byte kBootMediaTypeMask = 0xF;
namespace NBootMediaType
{
const Byte kNoEmulation = 0;
const Byte k1d2Floppy = 1;
const Byte k1d44Floppy = 2;
const Byte k2d88Floppy = 3;
const Byte kHardDisk = 4;
}
}}
#endif
@@ -0,0 +1,735 @@
// Archive/IsoIn.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/MyException.h"
#include "../../Common/StreamUtils.h"
#include "../HandlerCont.h"
#include "IsoIn.h"
namespace NArchive {
namespace NIso {
struct CUnexpectedEndException {};
struct CHeaderErrorException {};
struct CEndianErrorException {};
static const char * const kMediaTypes[] =
{
"NoEmul"
, "1.2M"
, "1.44M"
, "2.88M"
, "HardDisk"
};
bool CBootInitialEntry::Parse(const Byte *p)
{
Bootable = (p[0] == NBootEntryId::kInitialEntryBootable);
BootMediaType = p[1];
LoadSegment = GetUi16(p + 2);
SystemType = p[4];
SectorCount = GetUi16(p + 6);
LoadRBA = GetUi32(p + 8);
memcpy(VendorSpec, p + 12, 20);
if (p[5] != 0)
return false;
if (p[0] != NBootEntryId::kInitialEntryBootable
&& p[0] != NBootEntryId::kInitialEntryNotBootable)
return false;
return true;
}
AString CBootInitialEntry::GetName() const
{
AString s (Bootable ? "Boot" : "NotBoot");
s.Add_Minus();
if (BootMediaType < Z7_ARRAY_SIZE(kMediaTypes))
s += kMediaTypes[BootMediaType];
else
s.Add_UInt32(BootMediaType);
if (VendorSpec[0] == 1)
{
// "Language and Version Information (IBM)"
unsigned i;
for (i = 1; i < sizeof(VendorSpec); i++)
if (VendorSpec[i] > 0x7F)
break;
if (i == sizeof(VendorSpec))
{
s.Add_Minus();
for (i = 1; i < sizeof(VendorSpec); i++)
{
char c = (char)VendorSpec[i];
if (c == 0)
break;
if (c == '\\' || c == '/')
c = '_';
s += c;
}
}
}
s += ".img";
return s;
}
Byte CInArchive::ReadByte()
{
if (m_BufferPos >= kBlockSize)
m_BufferPos = 0;
if (m_BufferPos == 0)
{
size_t processed = kBlockSize;
HRESULT res = ReadStream(_stream, m_Buffer, &processed);
if (res != S_OK)
throw CSystemException(res);
if (processed != kBlockSize)
throw CUnexpectedEndException();
UInt64 end = _position + processed;
if (PhySize < end)
PhySize = end;
}
Byte b = m_Buffer[m_BufferPos++];
_position++;
return b;
}
void CInArchive::ReadBytes(Byte *data, UInt32 size)
{
for (UInt32 i = 0; i < size; i++)
data[i] = ReadByte();
}
void CInArchive::Skip(size_t size)
{
while (size-- != 0)
ReadByte();
}
void CInArchive::SkipZeros(size_t size)
{
while (size-- != 0)
{
Byte b = ReadByte();
if (b != 0)
throw CHeaderErrorException();
}
}
UInt16 CInArchive::ReadUInt16()
{
Byte b[4];
ReadBytes(b, 4);
UInt32 val = 0;
for (int i = 0; i < 2; i++)
{
if (b[i] != b[3 - i])
IncorrectBigEndian = true;
val |= ((UInt32)(b[i]) << (8 * i));
}
return (UInt16)val;
}
UInt32 CInArchive::ReadUInt32Le()
{
UInt32 val = 0;
for (int i = 0; i < 4; i++)
val |= ((UInt32)(ReadByte()) << (8 * i));
return val;
}
UInt32 CInArchive::ReadUInt32Be()
{
UInt32 val = 0;
for (int i = 0; i < 4; i++)
{
val <<= 8;
val |= ReadByte();
}
return val;
}
UInt32 CInArchive::ReadUInt32()
{
Byte b[8];
ReadBytes(b, 8);
UInt32 val = 0;
for (int i = 0; i < 4; i++)
{
if (b[i] != b[7 - i])
throw CEndianErrorException();
val |= ((UInt32)(b[i]) << (8 * i));
}
return val;
}
UInt32 CInArchive::ReadDigits(int numDigits)
{
UInt32 res = 0;
for (int i = 0; i < numDigits; i++)
{
Byte b = ReadByte();
if (b < '0' || b > '9')
{
if (b == 0 || b == ' ') // it's bug in some CD's
b = '0';
else
throw CHeaderErrorException();
}
UInt32 d = (UInt32)(b - '0');
res *= 10;
res += d;
}
return res;
}
void CInArchive::ReadDateTime(CDateTime &d)
{
d.Year = (UInt16)ReadDigits(4);
d.Month = (Byte)ReadDigits(2);
d.Day = (Byte)ReadDigits(2);
d.Hour = (Byte)ReadDigits(2);
d.Minute = (Byte)ReadDigits(2);
d.Second = (Byte)ReadDigits(2);
d.Hundredths = (Byte)ReadDigits(2);
d.GmtOffset = (signed char)ReadByte();
}
void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d)
{
ReadBytes(d.BootSystemId, sizeof(d.BootSystemId));
ReadBytes(d.BootId, sizeof(d.BootId));
ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse));
}
void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t)
{
t.Year = ReadByte();
t.Month = ReadByte();
t.Day = ReadByte();
t.Hour = ReadByte();
t.Minute = ReadByte();
t.Second = ReadByte();
t.GmtOffset = (signed char)ReadByte();
}
void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
{
r.ExtendedAttributeRecordLen = ReadByte();
if (r.ExtendedAttributeRecordLen != 0)
throw CHeaderErrorException();
r.ExtentLocation = ReadUInt32();
r.Size = ReadUInt32();
ReadRecordingDateTime(r.DateTime);
r.FileFlags = ReadByte();
r.FileUnitSize = ReadByte();
r.InterleaveGapSize = ReadByte();
r.VolSequenceNumber = ReadUInt16();
Byte idLen = ReadByte();
r.FileId.Alloc(idLen);
ReadBytes((Byte *)r.FileId, idLen);
unsigned padSize = 1 - (idLen & 1);
// SkipZeros(padSize);
Skip(padSize); // it's bug in some cd's. Must be zeros
unsigned curPos = 33 + idLen + padSize;
if (curPos > len)
throw CHeaderErrorException();
unsigned rem = len - curPos;
r.SystemUse.Alloc(rem);
ReadBytes((Byte *)r.SystemUse, rem);
}
void CInArchive::ReadDirRecord(CDirRecord &r)
{
Byte len = ReadByte();
// Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor.
// But maybe we must use real "len" for other records.
len = 34;
ReadDirRecord2(r, len);
}
void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
{
d.VolFlags = ReadByte();
ReadBytes(d.SystemId, sizeof(d.SystemId));
ReadBytes(d.VolumeId, sizeof(d.VolumeId));
SkipZeros(8);
d.VolumeSpaceSize = ReadUInt32();
ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence));
d.VolumeSetSize = ReadUInt16();
d.VolumeSequenceNumber = ReadUInt16();
d.LogicalBlockSize = ReadUInt16();
d.PathTableSize = ReadUInt32();
d.LPathTableLocation = ReadUInt32Le();
d.LOptionalPathTableLocation = ReadUInt32Le();
d.MPathTableLocation = ReadUInt32Be();
d.MOptionalPathTableLocation = ReadUInt32Be();
ReadDirRecord(d.RootDirRecord);
ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId));
ReadBytes(d.PublisherId, sizeof(d.PublisherId));
ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId));
ReadBytes(d.ApplicationId, sizeof(d.ApplicationId));
ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId));
ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId));
ReadBytes(d.BibFileId, sizeof(d.BibFileId));
ReadDateTime(d.CTime);
ReadDateTime(d.MTime);
ReadDateTime(d.ExpirationTime);
ReadDateTime(d.EffectiveTime);
const Byte fileStructureVersion = ReadByte();
// d.FileStructureVersion = fileStructureVersion;
if (fileStructureVersion != 1 && // ECMA-119
fileStructureVersion != 2) // some ISO files have fileStructureVersion == 2.
{
// v24.05: we ignore that field, because we don't know what exact values are allowed there
// throw CHeaderErrorException();
}
SkipZeros(1); // (Reserved for future standardization)
ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
// Most ISO contain zeros in the following field (reserved for future standardization).
// But some ISO programs write some data to that area.
// So we disable check for zeros.
Skip(653); // SkipZeros(653);
}
static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' };
/*
static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' };
static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' };
static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' };
static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' };
*/
static inline bool CheckSignature(const Byte *sig, const Byte *data)
{
for (int i = 0; i < 5; i++)
if (sig[i] != data[i])
return false;
return true;
}
void CInArchive::SeekToBlock(UInt32 blockIndex)
{
const HRESULT res = _stream->Seek(
(Int64)((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize),
STREAM_SEEK_SET, &_position);
if (res != S_OK)
throw CSystemException(res);
m_BufferPos = 0;
}
static const int kNumLevelsMax = 256;
void CInArchive::ReadDir(CDir &d, int level)
{
if (!d.IsDir())
return;
if (level > kNumLevelsMax)
{
TooDeepDirs = true;
return;
}
{
FOR_VECTOR (i, UniqStartLocations)
if (UniqStartLocations[i] == d.ExtentLocation)
{
SelfLinkedDirs = true;
return;
}
UniqStartLocations.Add(d.ExtentLocation);
}
SeekToBlock(d.ExtentLocation);
UInt64 startPos = _position;
bool firstItem = true;
for (;;)
{
UInt64 offset = _position - startPos;
if (offset >= d.Size)
break;
Byte len = ReadByte();
if (len == 0)
continue;
CDir subItem;
ReadDirRecord2(subItem, len);
if (firstItem && level == 0)
IsSusp = subItem.CheckSusp(SuspSkipSize);
if (!subItem.IsSystemItem())
d._subItems.Add(subItem);
firstItem = false;
}
FOR_VECTOR (i, d._subItems)
ReadDir(d._subItems[i], level + 1);
UniqStartLocations.DeleteBack();
}
void CInArchive::CreateRefs(CDir &d)
{
if (!d.IsDir())
return;
for (unsigned i = 0; i < d._subItems.Size();)
{
CRef ref;
CDir &subItem = d._subItems[i];
subItem.Parent = &d;
ref.Dir = &d;
ref.Index = i++;
ref.NumExtents = 1;
ref.TotalSize = subItem.Size;
if (subItem.IsNonFinalExtent())
{
for (;;)
{
if (i == d._subItems.Size())
{
HeadersError = true;
break;
}
const CDir &next = d._subItems[i];
if (!subItem.AreMultiPartEqualWith(next))
break;
i++;
ref.NumExtents++;
ref.TotalSize += next.Size;
if (!next.IsNonFinalExtent())
break;
}
}
Refs.Add(ref);
CreateRefs(subItem);
}
}
void CInArchive::ReadBootInfo()
{
if (!_bootIsDefined)
return;
HeadersError = true;
if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0)
return;
UInt32 blockIndex = GetUi32(_bootDesc.BootSystemUse);
SeekToBlock(blockIndex);
Byte buf[32];
ReadBytes(buf, 32);
if (buf[0] != NBootEntryId::kValidationEntry
|| buf[2] != 0
|| buf[3] != 0
|| buf[30] != 0x55
|| buf[31] != 0xAA)
return;
{
UInt32 sum = 0;
for (unsigned i = 0; i < 32; i += 2)
sum += GetUi16(buf + i);
if ((sum & 0xFFFF) != 0)
return;
/*
CBootValidationEntry e;
e.PlatformId = buf[1];
memcpy(e.Id, buf + 4, sizeof(e.Id));
// UInt16 checkSum = GetUi16(p + 28);
*/
}
ReadBytes(buf, 32);
{
CBootInitialEntry e;
if (!e.Parse(buf))
return;
BootEntries.Add(e);
}
bool error = false;
for (;;)
{
ReadBytes(buf, 32);
Byte headerIndicator = buf[0];
if (headerIndicator != NBootEntryId::kMoreHeaders
&& headerIndicator != NBootEntryId::kFinalHeader)
break;
// Section Header
// Byte platform = p[1];
unsigned numEntries = GetUi16(buf + 2);
// id[28]
for (unsigned i = 0; i < numEntries; i++)
{
ReadBytes(buf, 32);
CBootInitialEntry e;
if (!e.Parse(buf))
{
error = true;
break;
}
if (e.BootMediaType & (1 << 5))
{
// Section entry extension
for (unsigned j = 0;; j++)
{
ReadBytes(buf, 32);
if (j > 32 || buf[0] != NBootEntryId::kExtensionIndicator)
{
error = true;
break;
}
if ((buf[1] & (1 << 5)) == 0)
break;
// info += (buf + 2, 30)
}
}
BootEntries.Add(e);
}
if (headerIndicator != NBootEntryId::kMoreHeaders)
break;
}
HeadersError = error;
}
HRESULT CInArchive::Open2()
{
_position = 0;
RINOK(InStream_GetSize_SeekToEnd(_stream, _fileSize))
if (_fileSize < kStartPos)
return S_FALSE;
RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position))
PhySize = _position;
m_BufferPos = 0;
// BlockSize = kBlockSize;
for (;;)
{
Byte sig[7];
ReadBytes(sig, 7);
Byte ver = sig[6];
if (!CheckSignature(kSig_CD001, sig + 1))
{
return S_FALSE;
/*
if (sig[0] != 0 || ver != 1)
break;
if (CheckSignature(kSig_BEA01, sig + 1))
{
}
else if (CheckSignature(kSig_TEA01, sig + 1))
{
break;
}
else if (CheckSignature(kSig_NSR02, sig + 1))
{
}
else
break;
SkipZeros(0x800 - 7);
continue;
*/
}
// version = 2 for ISO 9660:1999?
if (ver > 2)
return S_FALSE;
if (sig[0] == NVolDescType::kTerminator)
{
break;
// Skip(0x800 - 7);
// continue;
}
switch (sig[0])
{
case NVolDescType::kBootRecord:
{
_bootIsDefined = true;
ReadBootRecordDescriptor(_bootDesc);
break;
}
case NVolDescType::kPrimaryVol:
case NVolDescType::kSupplementaryVol:
{
// some ISOs have two PrimaryVols.
CVolumeDescriptor vd;
ReadVolumeDescriptor(vd);
if (sig[0] == NVolDescType::kPrimaryVol)
{
// some burners write "Joliet" Escape Sequence to primary volume
memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence));
}
VolDescs.Add(vd);
break;
}
default:
break;
}
}
if (VolDescs.IsEmpty())
return S_FALSE;
for (MainVolDescIndex = (int)VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
if (VolDescs[MainVolDescIndex].IsJoliet())
break;
/* FIXME: some volume can contain Rock Ridge, that is better than
Joliet volume. So we need some way to detect such case */
// MainVolDescIndex = 0; // to read primary volume
const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
if (vd.LogicalBlockSize != kBlockSize)
return S_FALSE;
{
FOR_VECTOR (i, VolDescs)
{
const CVolumeDescriptor &vd2 = VolDescs[i];
UpdatePhySize(0, vd2.Get_VolumeSpaceSize_inBytes());
}
}
IsArc = true;
(CDirRecord &)_rootDir = vd.RootDirRecord;
ReadDir(_rootDir, 0);
CreateRefs(_rootDir);
ReadBootInfo();
{
FOR_VECTOR (i, Refs)
{
const CRef &ref = Refs[i];
for (UInt32 j = 0; j < ref.NumExtents; j++)
{
const CDir &item = ref.Dir->_subItems[ref.Index + j];
if (!item.IsDir() && item.Size != 0)
UpdatePhySize(item.ExtentLocation, item.Size);
}
}
}
{
// find boot item for expand:
// UEFI Specification : 13.3.2.1. ISO-9660 and El Torito
_expand_BootEntries_index = -1;
FOR_VECTOR (i, BootEntries)
{
const CBootInitialEntry &be = BootEntries[i];
if (be.SectorCount <= 1 && be.BootMediaType == NBootMediaType::kNoEmulation)
if (_expand_BootEntries_index == -1
|| be.LoadRBA >= BootEntries[_expand_BootEntries_index].LoadRBA)
_expand_BootEntries_index = (int)i;
}
}
{
FOR_VECTOR (i, BootEntries)
{
const CBootInitialEntry &be = BootEntries[i];
UpdatePhySize(be.LoadRBA, GetBootItemSize(i));
}
}
if (PhySize < _fileSize)
{
UInt64 rem = _fileSize - PhySize;
const UInt64 kRemMax = 1 << 21;
if (rem <= kRemMax)
{
RINOK(InStream_SeekSet(_stream, PhySize))
bool areThereNonZeros = false;
UInt64 numZeros = 0;
RINOK(ReadZeroTail(_stream, areThereNonZeros, numZeros, kRemMax))
if (!areThereNonZeros)
PhySize += numZeros;
}
}
return S_OK;
}
HRESULT CInArchive::Open(IInStream *inStream)
{
Clear();
_stream = inStream;
try { return Open2(); }
catch(const CSystemException &e) { return e.ErrorCode; }
catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; }
catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; }
}
void CInArchive::Clear()
{
IsArc = false;
UnexpectedEnd = false;
HeadersError = false;
IncorrectBigEndian = false;
TooDeepDirs = false;
SelfLinkedDirs = false;
UniqStartLocations.Clear();
Refs.Clear();
_rootDir.Clear();
VolDescs.Clear();
_bootIsDefined = false;
BootEntries.Clear();
SuspSkipSize = 0;
IsSusp = false;
_expand_BootEntries_index = -1;
}
UInt64 CInArchive::GetBootItemSize(unsigned index) const
{
const CBootInitialEntry &be = BootEntries[index];
UInt64 size = be.GetSize();
if (be.BootMediaType == NBootMediaType::k1d2Floppy) size = 1200 << 10;
else if (be.BootMediaType == NBootMediaType::k1d44Floppy) size = 1440 << 10;
else if (be.BootMediaType == NBootMediaType::k2d88Floppy) size = 2880 << 10;
const UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize;
if (startPos < _fileSize)
{
const UInt64 rem = _fileSize - startPos;
/*
UEFI modification to ISO specification:
because SectorCount is 16-bit, size is limited by (32 MB).
UEFI Specification :
13.3.2.1. ISO-9660 and El Torito
If the value of Sector Count is set to 0 or 1,
EFI will assume the system partition consumes the space
from the beginning of the "no emulation" image to the end of the CD-ROM.
*/
//
if ((int)index == _expand_BootEntries_index || rem < size)
size = rem;
}
return size;
}
}}
+322
View File
@@ -0,0 +1,322 @@
// Archive/IsoIn.h
#ifndef ZIP7_INC_ARCHIVE_ISO_IN_H
#define ZIP7_INC_ARCHIVE_ISO_IN_H
#include "../../../Common/MyCom.h"
#include "../../IStream.h"
#include "IsoHeader.h"
#include "IsoItem.h"
namespace NArchive {
namespace NIso {
struct CDir: public CDirRecord
{
CDir *Parent;
CObjectVector<CDir> _subItems;
void Clear()
{
Parent = NULL;
_subItems.Clear();
}
AString GetPath(bool checkSusp, unsigned skipSize) const
{
AString s;
unsigned len = 0;
const CDir *cur = this;
for (;;)
{
unsigned curLen;
cur->GetNameCur(checkSusp, skipSize, curLen);
len += curLen;
cur = cur->Parent;
if (!cur || !cur->Parent)
break;
len++;
}
char *p = s.GetBuf_SetEnd(len) + len;
cur = this;
for (;;)
{
unsigned curLen;
const Byte *name = cur->GetNameCur(checkSusp, skipSize, curLen);
p -= curLen;
if (curLen != 0)
memcpy(p, name, curLen);
cur = cur->Parent;
if (!cur || !cur->Parent)
break;
p--;
*p = CHAR_PATH_SEPARATOR;
}
return s;
}
void GetPathU(UString &s) const
{
s.Empty();
unsigned len = 0;
const CDir *cur = this;
for (;;)
{
unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
const Byte *fid = cur->FileId;
unsigned i;
for (i = 0; i < curLen; i++)
if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0)
break;
len += i;
cur = cur->Parent;
if (!cur || !cur->Parent)
break;
len++;
}
wchar_t *p = s.GetBuf_SetEnd(len) + len;
cur = this;
for (;;)
{
unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
const Byte *fid = cur->FileId;
unsigned i;
for (i = 0; i < curLen; i++)
if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0)
break;
curLen = i;
p -= curLen;
for (i = 0; i < curLen; i++)
p[i] = (wchar_t)(((wchar_t)fid[i * 2] << 8) | fid[i * 2 + 1]);
cur = cur->Parent;
if (!cur || !cur->Parent)
break;
p--;
*p = WCHAR_PATH_SEPARATOR;
}
}
};
struct CDateTime
{
UInt16 Year;
Byte Month;
Byte Day;
Byte Hour;
Byte Minute;
Byte Second;
Byte Hundredths;
signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
{
UInt64 v;
const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v);
if (res)
{
v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60));
v *= 10000000;
if (Hundredths < 100)
v += (UInt32)Hundredths * 100000;
prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2);
}
return res;
}
};
struct CBootRecordDescriptor
{
Byte BootSystemId[32]; // a-characters
Byte BootId[32]; // a-characters
Byte BootSystemUse[1977];
};
struct CBootValidationEntry
{
Byte PlatformId;
Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM.
};
struct CBootInitialEntry
{
bool Bootable;
Byte BootMediaType;
UInt16 LoadSegment;
/* This is the load segment for the initial boot image. If this
value is 0 the system will use the traditional segment of 7C0. If this value
is non-zero the system will use the specified segment. This applies to x86
architectures only. For "flat" model architectures (such as Motorola) this
is the address divided by 10. */
Byte SystemType; // This must be a copy of byte 5 (System Type) from the
// Partition Table found in the boot image.
UInt16 SectorCount; // This is the number of virtual/emulated sectors the system
// will store at Load Segment during the initial boot procedure.
UInt32 LoadRBA; // This is the start address of the virtual disk. CDs use
// Relative/Logical block addressing.
Byte VendorSpec[20];
UInt32 GetSize() const
{
// if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10);
return (UInt32)SectorCount * 512;
}
bool Parse(const Byte *p);
AString GetName() const;
};
struct CVolumeDescriptor
{
Byte VolFlags;
Byte SystemId[32]; // a-characters. An identification of a system
// which can recognize and act upon the content of the Logical
// Sectors with logical Sector Numbers 0 to 15 of the volume.
Byte VolumeId[32]; // d-characters. An identification of the volume.
UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded
Byte EscapeSequence[32];
UInt16 VolumeSetSize;
UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member.
UInt16 LogicalBlockSize;
UInt32 PathTableSize;
UInt32 LPathTableLocation;
UInt32 LOptionalPathTableLocation;
UInt32 MPathTableLocation;
UInt32 MOptionalPathTableLocation;
CDirRecord RootDirRecord;
Byte VolumeSetId[128];
Byte PublisherId[128];
Byte DataPreparerId[128];
Byte ApplicationId[128];
Byte CopyrightFileId[37];
Byte AbstractFileId[37];
Byte BibFileId[37];
CDateTime CTime;
CDateTime MTime;
CDateTime ExpirationTime;
CDateTime EffectiveTime;
// Byte FileStructureVersion; // = 1;
Byte ApplicationUse[512];
bool IsJoliet() const
{
if ((VolFlags & 1) != 0)
return false;
const Byte b = EscapeSequence[2];
return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
(b == 0x40 || b == 0x43 || b == 0x45));
}
UInt64 Get_VolumeSpaceSize_inBytes() const { return (UInt64)VolumeSpaceSize * LogicalBlockSize; }
};
struct CRef
{
const CDir *Dir;
UInt32 Index;
UInt32 NumExtents;
UInt64 TotalSize;
};
const UInt32 kBlockSize = 1 << 11;
class CInArchive
{
IInStream *_stream;
UInt64 _position;
UInt32 m_BufferPos;
void Skip(size_t size);
void SkipZeros(size_t size);
Byte ReadByte();
void ReadBytes(Byte *data, UInt32 size);
UInt16 ReadUInt16();
UInt32 ReadUInt32Le();
UInt32 ReadUInt32Be();
UInt32 ReadUInt32();
UInt64 ReadUInt64();
UInt32 ReadDigits(int numDigits);
void ReadDateTime(CDateTime &d);
void ReadRecordingDateTime(CRecordingDateTime &t);
void ReadDirRecord2(CDirRecord &r, Byte len);
void ReadDirRecord(CDirRecord &r);
void ReadBootRecordDescriptor(CBootRecordDescriptor &d);
void ReadVolumeDescriptor(CVolumeDescriptor &d);
void SeekToBlock(UInt32 blockIndex);
void ReadDir(CDir &d, int level);
void CreateRefs(CDir &d);
void ReadBootInfo();
HRESULT Open2();
public:
HRESULT Open(IInStream *inStream);
void Clear();
UInt64 _fileSize;
UInt64 PhySize;
CRecordVector<CRef> Refs;
CObjectVector<CVolumeDescriptor> VolDescs;
int MainVolDescIndex;
// UInt32 BlockSize;
CObjectVector<CBootInitialEntry> BootEntries;
private:
bool _bootIsDefined;
public:
bool IsArc;
bool UnexpectedEnd;
bool HeadersError;
bool IncorrectBigEndian;
bool TooDeepDirs;
bool SelfLinkedDirs;
bool IsSusp;
unsigned SuspSkipSize;
int _expand_BootEntries_index;
CRecordVector<UInt32> UniqStartLocations;
void UpdatePhySize(const UInt32 blockIndex, const UInt64 size)
{
const UInt64 alignedSize = (size + kBlockSize - 1) & ~((UInt64)kBlockSize - 1);
const UInt64 end = (UInt64)blockIndex * kBlockSize + alignedSize;
if (PhySize < end)
PhySize = end;
}
bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
UInt64 GetBootItemSize(unsigned index) const;
private:
CDir _rootDir;
Byte m_Buffer[kBlockSize];
CBootRecordDescriptor _bootDesc;
};
}}
#endif
@@ -0,0 +1,320 @@
// Archive/IsoItem.h
#ifndef ZIP7_INC_ARCHIVE_ISO_ITEM_H
#define ZIP7_INC_ARCHIVE_ISO_ITEM_H
#include "../../../../C/CpuArch.h"
#include "../../../Common/MyString.h"
#include "../../../Common/MyBuffer.h"
#include "../../../Windows/TimeUtils.h"
#include "IsoHeader.h"
namespace NArchive {
namespace NIso {
struct CRecordingDateTime
{
Byte Year;
Byte Month;
Byte Day;
Byte Hour;
Byte Minute;
Byte Second;
signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
{
UInt64 v;
const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v);
if (res)
{
v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60));
v *= 10000000;
prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base);
}
return res;
}
};
enum EPx
{
k_Px_Mode,
k_Px_Links,
k_Px_User,
k_Px_Group,
k_Px_SerialNumber
// k_Px_Num
};
/*
enum ETf
{
k_Tf_CTime,
k_Tf_MTime,
k_Tf_ATime,
k_Tf_Attrib,
k_Tf_Backup,
k_Tf_Expiration,
k_Tf_Effective
// k_Tf_Num
};
*/
struct CDirRecord
{
UInt32 ExtentLocation;
UInt32 Size;
CRecordingDateTime DateTime;
Byte FileFlags;
Byte FileUnitSize;
Byte InterleaveGapSize;
Byte ExtendedAttributeRecordLen;
UInt16 VolSequenceNumber;
CByteBuffer FileId;
CByteBuffer SystemUse;
bool AreMultiPartEqualWith(const CDirRecord &a) const
{
return FileId == a.FileId
&& (FileFlags & (~NFileFlags::kNonFinalExtent)) ==
(a.FileFlags & (~NFileFlags::kNonFinalExtent));
}
bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; }
bool IsNonFinalExtent() const { return (FileFlags & NFileFlags::kNonFinalExtent) != 0; }
bool IsSystemItem() const
{
if (FileId.Size() != 1)
return false;
Byte b = *(const Byte *)FileId;
return (b == 0 || b == 1);
}
const Byte* FindSuspRecord(unsigned skipSize, Byte id0, Byte id1, unsigned &lenRes) const
{
lenRes = 0;
if (SystemUse.Size() < skipSize)
return NULL;
const Byte *p = (const Byte *)SystemUse + skipSize;
unsigned rem = (unsigned)(SystemUse.Size() - skipSize);
while (rem >= 5)
{
unsigned len = p[2];
if (len < 3 || len > rem)
return NULL;
if (p[0] == id0 && p[1] == id1 && p[3] == 1)
{
if (len < 4)
return NULL; // Check it
lenRes = len - 4;
return p + 4;
}
p += len;
rem -= len;
}
return NULL;
}
const Byte* GetNameCur(bool checkSusp, unsigned skipSize, unsigned &nameLenRes) const
{
const Byte *res = NULL;
unsigned len = 0;
if (checkSusp)
res = FindSuspRecord(skipSize, 'N', 'M', len);
if (!res || len < 1)
{
res = (const Byte *)FileId;
len = (unsigned)FileId.Size();
}
else
{
res++;
len--;
}
unsigned i;
for (i = 0; i < len; i++)
if (res[i] == 0)
break;
nameLenRes = i;
return res;
}
bool GetSymLink(unsigned skipSize, AString &link) const
{
link.Empty();
const Byte *p = NULL;
unsigned len = 0;
p = FindSuspRecord(skipSize, 'S', 'L', len);
if (!p || len < 1)
return false;
if (*p != 0)
return false;
p++;
len--;
while (len != 0)
{
if (len < 2)
return false;
unsigned flags = p[0];
unsigned cl = p[1];
p += 2;
len -= 2;
if (cl > len)
return false;
bool needSlash = false;
if (flags & (1 << 1)) link += "./";
else if (flags & (1 << 2)) link += "../";
else if (flags & (1 << 3)) link.Add_Slash();
else
needSlash = true;
for (unsigned i = 0; i < cl; i++)
{
const Byte c = p[i];
if (c == 0)
{
break;
// return false;
}
link += (char)c;
}
p += cl;
len -= cl;
if (len == 0)
break;
if (needSlash)
link.Add_Slash();
}
return true;
}
static bool GetLe32Be32(const Byte *p, UInt32 &dest)
{
UInt32 v1 = GetUi32(p);
UInt32 v2 = GetBe32(p + 4);
if (v1 == v2)
{
dest = v1;
return true;
}
return false;
}
bool GetPx(unsigned skipSize, unsigned pxType, UInt32 &val) const
{
val = 0;
const Byte *p = NULL;
unsigned len = 0;
p = FindSuspRecord(skipSize, 'P', 'X', len);
if (!p)
return false;
// px.Clear();
if (len < (pxType + 1) * 8)
return false;
return GetLe32Be32(p + pxType * 8, val);
}
/*
bool GetTf(int skipSize, unsigned pxType, CRecordingDateTime &t) const
{
const Byte *p = NULL;
unsigned len = 0;
p = FindSuspRecord(skipSize, 'T', 'F', len);
if (!p)
return false;
if (len < 1)
return false;
Byte flags = *p++;
len--;
unsigned step = 7;
if (flags & 0x80)
{
step = 17;
return false;
}
if ((flags & (1 << pxType)) == 0)
return false;
for (unsigned i = 0; i < pxType; i++)
{
if (len < step)
return false;
if (flags & (1 << i))
{
p += step;
len -= step;
}
}
if (len < step)
return false;
t.Year = p[0];
t.Month = p[1];
t.Day = p[2];
t.Hour = p[3];
t.Minute = p[4];
t.Second = p[5];
t.GmtOffset = (signed char)p[6];
return true;
}
*/
bool CheckSusp(const Byte *p, unsigned &startPos) const
{
if (p[0] == 'S' &&
p[1] == 'P' &&
p[2] == 0x7 &&
p[3] == 0x1 &&
p[4] == 0xBE &&
p[5] == 0xEF)
{
startPos = p[6];
return true;
}
return false;
}
bool CheckSusp(unsigned &startPos) const
{
const Byte *p = (const Byte *)SystemUse;
const size_t len = SystemUse.Size();
const unsigned kMinLen = 7;
if (len < kMinLen)
return false;
if (CheckSusp(p, startPos))
return true;
const unsigned kOffset2 = 14;
if (len < kOffset2 + kMinLen)
return false;
return CheckSusp(p + kOffset2, startPos);
}
};
}}
#endif
@@ -0,0 +1,21 @@
// IsoRegister.cpp
#include "StdAfx.h"
#include "../../Common/RegisterArc.h"
#include "IsoHandler.h"
namespace NArchive {
namespace NIso {
static const Byte k_Signature[] = { 'C', 'D', '0', '0', '1' };
REGISTER_ARC_I(
"Iso", "iso img", NULL, 0xE7,
k_Signature,
NArchive::NIso::kStartPos + 1,
0,
NULL)
}}
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../../Common/Common.h"
#endif