mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 16:07:04 -06:00
Initialer Commit
This commit is contained in:
413
CPP/7zip/Archive/Iso/IsoHandler.cpp
Normal file
413
CPP/7zip/Archive/Iso/IsoHandler.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
// IsoHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/IntToString.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.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
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidComment,
|
||||
kpidCTime,
|
||||
kpidMTime,
|
||||
// kpidHeadersSize
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP 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
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_archive.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP 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 += '\n';
|
||||
s += name;
|
||||
s += ": ";
|
||||
s += d;
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
STDMETHODIMP 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);
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; }
|
||||
case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; 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
|
||||
}
|
||||
|
||||
STDMETHODIMP 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)
|
||||
{
|
||||
char temp[16];
|
||||
ConvertUInt32ToString(index + 1, temp);
|
||||
s += temp;
|
||||
s += '-';
|
||||
}
|
||||
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::ConvertToOSName2(s);
|
||||
prop = s;
|
||||
}
|
||||
break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
if (!item.IsDir())
|
||||
prop = (UInt64)ref.TotalSize;
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
FILETIME utc;
|
||||
if (item.DateTime.GetFileTime(utc))
|
||||
prop = utc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
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());
|
||||
}
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
UInt64 currentItemSize;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
currentItemSize = 0;
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
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));
|
||||
|
||||
bool isOK = true;
|
||||
if (index < (UInt32)_archive.Refs.Size())
|
||||
{
|
||||
const CRef &ref = _archive.Refs[index];
|
||||
UInt64 offset = 0;
|
||||
for (UInt32 e = 0; e < ref.NumExtents; e++)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize + offset;
|
||||
const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
|
||||
RINOK(_stream->Seek((UInt64)item2.ExtentLocation * kBlockSize, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item2.Size);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize != item2.Size)
|
||||
{
|
||||
isOK = false;
|
||||
break;
|
||||
}
|
||||
offset += item2.Size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(_stream->Seek((UInt64)blockIndex * kBlockSize, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(currentItemSize);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize != currentItemSize)
|
||||
isOK = false;
|
||||
}
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(isOK ?
|
||||
NExtract::NOperationResult::kOK:
|
||||
NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = 0;
|
||||
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
|
||||
}
|
||||
|
||||
}}
|
||||
31
CPP/7zip/Archive/Iso/IsoHandler.h
Normal file
31
CPP/7zip/Archive/Iso/IsoHandler.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// IsoHandler.h
|
||||
|
||||
#ifndef __ISO_HANDLER_H
|
||||
#define __ISO_HANDLER_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "IsoIn.h"
|
||||
#include "IsoItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NIso {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CInArchive _archive;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
12
CPP/7zip/Archive/Iso/IsoHeader.cpp
Normal file
12
CPP/7zip/Archive/Iso/IsoHeader.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// Archive/Iso/Header.h
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "IsoHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NIso {
|
||||
|
||||
const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0";
|
||||
|
||||
}}
|
||||
64
CPP/7zip/Archive/Iso/IsoHeader.h
Normal file
64
CPP/7zip/Archive/Iso/IsoHeader.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// Archive/IsoHeader.h
|
||||
|
||||
#ifndef __ARCHIVE_ISO_HEADER_H
|
||||
#define __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 *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
|
||||
673
CPP/7zip/Archive/Iso/IsoIn.cpp
Normal file
673
CPP/7zip/Archive/Iso/IsoIn.cpp
Normal file
@@ -0,0 +1,673 @@
|
||||
// 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 += '-';
|
||||
|
||||
if (BootMediaType < ARRAY_SIZE(kMediaTypes))
|
||||
s += kMediaTypes[BootMediaType];
|
||||
else
|
||||
{
|
||||
char name[16];
|
||||
ConvertUInt32ToString(BootMediaType, name);
|
||||
s += name;
|
||||
}
|
||||
|
||||
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 += '-';
|
||||
for (i = 1; i < sizeof(VendorSpec); i++)
|
||||
{
|
||||
char c = 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 |= ((UInt16)(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) // 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);
|
||||
d.FileStructureVersion = ReadByte(); // = 1
|
||||
SkipZeros(1);
|
||||
ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
|
||||
|
||||
// Most ISO contains 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)
|
||||
{
|
||||
HRESULT res = _stream->Seek((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(_stream->Seek(0, STREAM_SEEK_END, &_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 = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
|
||||
if (VolDescs[MainVolDescIndex].IsJoliet())
|
||||
break;
|
||||
// MainVolDescIndex = 0; // to read primary volume
|
||||
const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
|
||||
if (vd.LogicalBlockSize != kBlockSize)
|
||||
return S_FALSE;
|
||||
|
||||
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())
|
||||
UpdatePhySize(item.ExtentLocation, item.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
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(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL));
|
||||
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;
|
||||
}
|
||||
|
||||
}}
|
||||
333
CPP/7zip/Archive/Iso/IsoIn.h
Normal file
333
CPP/7zip/Archive/Iso/IsoIn.h
Normal file
@@ -0,0 +1,333 @@
|
||||
// Archive/IsoIn.h
|
||||
|
||||
#ifndef __ARCHIVE_ISO_IN_H
|
||||
#define __ARCHIVE_ISO_IN_H
|
||||
|
||||
#include "../../../Common/IntToString.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 = 0;
|
||||
_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(FILETIME &ft) const
|
||||
{
|
||||
UInt64 value;
|
||||
bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
|
||||
if (res)
|
||||
{
|
||||
value -= (Int64)((Int32)GmtOffset * 15 * 60);
|
||||
value *= 10000000;
|
||||
}
|
||||
ft.dwLowDateTime = (DWORD)value;
|
||||
ft.dwHighDateTime = (DWORD)(value >> 32);
|
||||
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;
|
||||
Byte b = EscapeSequence[2];
|
||||
return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
|
||||
(b == 0x40 || b == 0x43 || b == 0x45));
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
CDir _rootDir;
|
||||
bool _bootIsDefined;
|
||||
CBootRecordDescriptor _bootDesc;
|
||||
|
||||
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;
|
||||
|
||||
bool IsArc;
|
||||
bool UnexpectedEnd;
|
||||
bool HeadersError;
|
||||
bool IncorrectBigEndian;
|
||||
bool TooDeepDirs;
|
||||
bool SelfLinkedDirs;
|
||||
CRecordVector<UInt32> UniqStartLocations;
|
||||
|
||||
Byte m_Buffer[kBlockSize];
|
||||
|
||||
void UpdatePhySize(UInt32 blockIndex, 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(int 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);
|
||||
UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize;
|
||||
if (startPos < _fileSize)
|
||||
{
|
||||
if (_fileSize - startPos < size)
|
||||
size = _fileSize - startPos;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool IsSusp;
|
||||
unsigned SuspSkipSize;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
150
CPP/7zip/Archive/Iso/IsoItem.h
Normal file
150
CPP/7zip/Archive/Iso/IsoItem.h
Normal file
@@ -0,0 +1,150 @@
|
||||
// Archive/IsoItem.h
|
||||
|
||||
#ifndef __ARCHIVE_ISO_ITEM_H
|
||||
#define __ARCHIVE_ISO_ITEM_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(FILETIME &ft) const
|
||||
{
|
||||
UInt64 value;
|
||||
bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value);
|
||||
if (res)
|
||||
{
|
||||
value -= (Int64)((Int32)GmtOffset * 15 * 60);
|
||||
value *= 10000000;
|
||||
}
|
||||
ft.dwLowDateTime = (DWORD)value;
|
||||
ft.dwHighDateTime = (DWORD)(value >> 32);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
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* FindSuspName(unsigned skipSize, unsigned &lenRes) const
|
||||
{
|
||||
lenRes = 0;
|
||||
if (SystemUse.Size() < skipSize)
|
||||
return 0;
|
||||
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 0;
|
||||
if (p[0] == 'N' && p[1] == 'M' && p[3] == 1)
|
||||
{
|
||||
if (len < 5)
|
||||
return 0; // Check it
|
||||
lenRes = len - 5;
|
||||
return p + 5;
|
||||
}
|
||||
p += len;
|
||||
rem -= len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Byte* GetNameCur(bool checkSusp, int skipSize, unsigned &nameLenRes) const
|
||||
{
|
||||
const Byte *res = NULL;
|
||||
unsigned len = 0;
|
||||
if (checkSusp)
|
||||
res = FindSuspName(skipSize, len);
|
||||
if (!res)
|
||||
{
|
||||
res = (const Byte *)FileId;
|
||||
len = (unsigned)FileId.Size();
|
||||
}
|
||||
unsigned i;
|
||||
for (i = 0; i < len; i++)
|
||||
if (res[i] == 0)
|
||||
break;
|
||||
nameLenRes = i;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
unsigned len = (int)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
|
||||
21
CPP/7zip/Archive/Iso/IsoRegister.cpp
Normal file
21
CPP/7zip/Archive/Iso/IsoRegister.cpp
Normal file
@@ -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", 0, 0xE7,
|
||||
k_Signature,
|
||||
NArchive::NIso::kStartPos + 1,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
8
CPP/7zip/Archive/Iso/StdAfx.h
Normal file
8
CPP/7zip/Archive/Iso/StdAfx.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user