Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/MslzHandler.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/MslzHandler.cpp308
1 files changed, 222 insertions, 86 deletions
diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp
index 67495e76..cb124c40 100755..100644
--- a/CPP/7zip/Archive/MslzHandler.cpp
+++ b/CPP/7zip/Archive/MslzHandler.cpp
@@ -4,10 +4,10 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/MyString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyString.h"
-#include "Windows/PropVariant.h"
+#include "../../Windows/PropVariant.h"
#include "../Common/InBuffer.h"
#include "../Common/ProgressUtils.h"
@@ -19,28 +19,45 @@
namespace NArchive {
namespace NMslz {
+static const UInt32 kUnpackSizeMax = 0xFFFFFFE0;
+
class CHandler:
public IInArchive,
+ public IArchiveOpenSeq,
public CMyUnknownImp
{
- CMyComPtr<IInStream> _stream;
- UInt32 _size;
+ CMyComPtr<IInStream> _inStream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+
+ UInt32 _unpackSize;
UInt64 _packSize;
+ UInt64 _originalFileSize;
UString _name;
+
+ void ParseName(Byte replaceByte, IArchiveOpenCallback *callback);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps_NO_Table
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
@@ -48,15 +65,39 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidExtension: prop = "mslz"; break;
+ case kpidIsNotArcType: prop = true; break;
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
+ if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ prop = v;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
- switch(propID)
+ switch (propID)
{
case kpidPath: if (!_name.IsEmpty()) prop = _name; break;
- case kpidSize: prop = _size; break;
- case kpidPackSize: prop = _packSize; break;
+ case kpidSize: if (_unpackSize_Defined || _inStream) prop = _unpackSize; break;
+ case kpidPackSize: if (_packSize_Defined || _inStream) prop = _packSize; break;
}
prop.Detach(value);
return S_OK;
@@ -67,69 +108,80 @@ static const unsigned kSignatureSize = 9;
static const unsigned kHeaderSize = kSignatureSize + 1 + 4;
#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 }
// old signature: 53 5A 20 88 F0 27 33
-static const Byte signature[kSignatureSize] = MSLZ_SIGNATURE;
+static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE;
-static const wchar_t *g_Exts[] =
+// we support only 3 chars strings here
+static const char *g_Exts[] =
{
- L"dll",
- L"exe",
- L"kmd",
- L"sys"
+ "dll"
+ , "exe"
+ , "kmd"
+ , "sys"
};
+void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback)
+{
+ if (!callback)
+ return;
+ CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
+ if (!volumeCallback)
+ return;
+
+ NWindows::NCOM::CPropVariant prop;
+ if (volumeCallback->GetProperty(kpidName, &prop) != S_OK || prop.vt != VT_BSTR)
+ return;
+
+ UString s = prop.bstrVal;
+ if (s.IsEmpty() ||
+ s.Back() != L'_')
+ return;
+
+ s.DeleteBack();
+ _name = s;
+
+ if (replaceByte == 0)
+ {
+ if (s.Len() < 3 || s[s.Len() - 3] != '.')
+ return;
+ for (unsigned i = 0; i < ARRAY_SIZE(g_Exts); i++)
+ {
+ const char *ext = g_Exts[i];
+ if (s[s.Len() - 2] == ext[0] &&
+ s[s.Len() - 1] == ext[1])
+ {
+ replaceByte = ext[2];
+ break;
+ }
+ }
+ }
+ if (replaceByte >= 0x20 && replaceByte < 0x80)
+ _name += (wchar_t)replaceByte;
+}
+
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
{
Close();
+ _needSeekToStart = true;
Byte buffer[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize));
- if (memcmp(buffer, signature, kSignatureSize) != 0)
+ if (memcmp(buffer, kSignature, kSignatureSize) != 0)
return S_FALSE;
- _size = GetUi32(buffer + 10);
- if (_size > 0xFFFFFFE0)
+ _unpackSize = GetUi32(buffer + 10);
+ if (_unpackSize > kUnpackSizeMax)
return S_FALSE;
- RINOK(stream->Seek(0, STREAM_SEEK_END, &_packSize));
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &_originalFileSize));
+ _packSize = _originalFileSize;
- if (callback)
- {
- CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
- callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
- if (openVolumeCallback)
- {
- NWindows::NCOM::CPropVariant prop;
- if (openVolumeCallback->GetProperty(kpidName, &prop) == S_OK && prop.vt == VT_BSTR)
- {
- UString baseName = prop.bstrVal;
- if (!baseName.IsEmpty() && baseName.Back() == L'_')
- {
- baseName.DeleteBack();
- Byte replaceByte = buffer[kSignatureSize];
- if (replaceByte == 0)
- {
- for (int i = 0; i < sizeof(g_Exts) / sizeof(g_Exts[0]); i++)
- {
- UString s = g_Exts[i];
- int len = s.Length();
- Byte b = (Byte)s.Back();
- s.DeleteBack();
- if (baseName.Length() >= len &&
- baseName[baseName.Length() - len] == '.' &&
- s.CompareNoCase(baseName.Right(len - 1)) == 0)
- {
- replaceByte = b;
- break;
- }
- }
- }
- if (replaceByte >= 0x20 && replaceByte < 0x80)
- _name = baseName + (wchar_t)replaceByte;
- }
- }
- }
- }
- _stream = stream;
+ ParseName(buffer[kSignatureSize], callback);
+
+ _isArc = true;
+ _unpackSize_Defined = true;
+ _inStream = stream;
+ _seqStream = stream;
}
return S_OK;
COM_TRY_END
@@ -137,7 +189,20 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPo
STDMETHODIMP CHandler::Close()
{
- _stream.Release();
+ _originalFileSize = 0;
+ _packSize = 0;
+ _unpackSize = 0;
+
+ _isArc = false;
+ _needSeekToStart = false;
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+
+ _packSize_Defined = false;
+ _unpackSize_Defined = false;
+
+ _seqStream.Release();
+ _inStream.Release();
_name.Empty();
return S_OK;
}
@@ -147,12 +212,13 @@ STDMETHODIMP CHandler::Close()
// maxLen = 16; MS
#define PROGRESS_AND_WRITE \
- if ((dest & kMask) == 0) { RINOK(WriteStream(outStream, buf, kBufSize)); \
+ if ((dest & kMask) == 0) { if (outStream) RINOK(WriteStream(outStream, buf, kBufSize)); \
if ((dest & ((1 << 20) - 1)) == 0) \
- { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
- RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
+ if (progress) \
+ { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
+ RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
-static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, ICompressProgressInfo *progress)
+static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, bool &needMoreData, ICompressProgressInfo *progress)
{
const unsigned kBufSize = (1 << 12);
const unsigned kMask = kBufSize - 1;
@@ -163,11 +229,17 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn
{
Byte b;
if (!inStream.ReadByte(b))
+ {
+ needMoreData = true;
return S_FALSE;
+ }
for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1)
{
if (!inStream.ReadByte(b))
+ {
+ needMoreData = true;
return S_FALSE;
+ }
if (mask & 1)
{
buf[dest++ & kMask] = b;
@@ -177,7 +249,10 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn
{
Byte b1;
if (!inStream.ReadByte(b1))
+ {
+ needMoreData = true;
return S_FALSE;
+ }
const unsigned kMaxLen = 16; // 18 in Okumura's code.
unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask;
unsigned len = (b1 & 0xF) + 3;
@@ -192,7 +267,19 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn
}
}
}
- return WriteStream(outStream, buf, dest & kMask);
+ if (outStream)
+ RINOK(WriteStream(outStream, buf, dest & kMask));
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ COM_TRY_BEGIN
+ Close();
+ _isArc = true;
+ _seqStream = stream;
+ return S_OK;
+ COM_TRY_END
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
@@ -201,10 +288,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_BEGIN
if (numItems == 0)
return S_OK;
- if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
return E_INVALIDARG;
- extractCallback->SetTotal(_size);
+ // extractCallback->SetTotal(_unpackSize);
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
@@ -225,32 +312,81 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
-
- RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- CInBuffer s;
- if (!s.Create(1 << 20))
- return E_OUTOFMEMORY;
- s.SetStream(_stream);
- s.Init();
- Byte buffer[kHeaderSize];
+
+ if (_needSeekToStart)
+ {
+ if (!_inStream)
+ return E_FAIL;
+ RINOK(_inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ else
+ _needSeekToStart = true;
+
Int32 opRes = NExtract::NOperationResult::kDataError;
- if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize)
+
+ bool isArc = false;
+ bool needMoreInput = false;
+ try
{
- HRESULT result = MslzDec(s, outStream, _size, progress);
- if (result == S_OK)
- opRes = NExtract::NOperationResult::kOK;
- else if (result != S_FALSE)
- return result;
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(_seqStream);
+ s.Init();
+
+ Byte buffer[kHeaderSize];
+ if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize)
+ {
+ UInt32 unpackSize;
+ if (memcmp(buffer, kSignature, kSignatureSize) == 0)
+ {
+ unpackSize = GetUi32(buffer + 10);
+ if (unpackSize <= kUnpackSizeMax)
+ {
+ HRESULT result = MslzDec(s, outStream, unpackSize, needMoreInput, progress);
+ if (result == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (result != S_FALSE)
+ return result;
+ _unpackSize = unpackSize;
+ _unpackSize_Defined = true;
+
+ _packSize = s.GetProcessedSize();
+ _packSize_Defined = true;
+
+ if (_inStream && _packSize < _originalFileSize)
+ _dataAfterEnd = true;
+
+ isArc = true;
+ }
+ }
+ }
}
+ catch (CInBufferException &e) { return e.ErrorCode; }
+
+ _isArc = isArc;
+ if (isArc)
+ _needMoreInput = needMoreInput;
+ if (!_isArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (_needMoreInput)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (_dataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
+
outStream.Release();
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"MsLZ", L"", 0, 0xD5, MSLZ_SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+ { "MsLZ", "mslz", 0, 0xD5,
+ kSignatureSize, MSLZ_SIGNATURE,
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Mslz)