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,358 @@
// CWrappers.c
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "CWrappers.h"
#include "StreamUtils.h"
SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw()
{
switch (res)
{
case S_OK: return SZ_OK;
case E_OUTOFMEMORY: return SZ_ERROR_MEM;
case E_INVALIDARG: return SZ_ERROR_PARAM;
case E_ABORT: return SZ_ERROR_PROGRESS;
case S_FALSE: return SZ_ERROR_DATA;
case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED;
default: break;
}
return defaultRes;
}
HRESULT SResToHRESULT(SRes res) throw()
{
switch (res)
{
case SZ_OK: return S_OK;
case SZ_ERROR_DATA:
case SZ_ERROR_CRC:
case SZ_ERROR_INPUT_EOF:
case SZ_ERROR_ARCHIVE:
case SZ_ERROR_NO_ARCHIVE:
return S_FALSE;
case SZ_ERROR_MEM: return E_OUTOFMEMORY;
case SZ_ERROR_PARAM: return E_INVALIDARG;
case SZ_ERROR_PROGRESS: return E_ABORT;
case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
// case SZ_ERROR_OUTPUT_EOF:
// case SZ_ERROR_READ:
// case SZ_ERROR_WRITE:
// case SZ_ERROR_THREAD:
// case SZ_ERROR_ARCHIVE:
// case SZ_ERROR_NO_ARCHIVE:
// return E_FAIL;
default: break;
}
if (res < 0)
return res;
return E_FAIL;
}
#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1)
#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x)
static SRes CompressProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) throw()
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CCompressProgressWrap)
p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize));
return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
}
void CCompressProgressWrap::Init(ICompressProgressInfo *progress) throw()
{
vt.Progress = CompressProgress;
Progress = progress;
Res = SZ_OK;
}
static const UInt32 kStreamStepSize = (UInt32)1 << 31;
static SRes MyRead(ISeqInStreamPtr pp, void *data, size_t *size) throw()
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInStreamWrap)
UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
p->Res = (p->Stream->Read(data, curSize, &curSize));
*size = curSize;
p->Processed += curSize;
if (p->Res == S_OK)
return SZ_OK;
return HRESULT_To_SRes(p->Res, SZ_ERROR_READ);
}
static size_t MyWrite(ISeqOutStreamPtr pp, const void *data, size_t size) throw()
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqOutStreamWrap)
if (p->Stream)
{
p->Res = WriteStream(p->Stream, data, size);
if (p->Res != 0)
return 0;
}
else
p->Res = S_OK;
p->Processed += size;
return size;
}
void CSeqInStreamWrap::Init(ISequentialInStream *stream) throw()
{
vt.Read = MyRead;
Stream = stream;
Processed = 0;
Res = S_OK;
}
void CSeqOutStreamWrap::Init(ISequentialOutStream *stream) throw()
{
vt.Write = MyWrite;
Stream = stream;
Res = SZ_OK;
Processed = 0;
}
static SRes InStreamWrap_Read(ISeekInStreamPtr pp, void *data, size_t *size) throw()
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap)
UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
p->Res = p->Stream->Read(data, curSize, &curSize);
*size = curSize;
return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
}
static SRes InStreamWrap_Seek(ISeekInStreamPtr pp, Int64 *offset, ESzSeek origin) throw()
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap)
UInt32 moveMethod;
/* we need (int)origin to eliminate the clang warning:
default label in switch which covers all enumeration values
[-Wcovered-switch-default */
switch ((int)origin)
{
case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break;
case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break;
case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break;
default: return SZ_ERROR_PARAM;
}
UInt64 newPosition;
p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition);
*offset = (Int64)newPosition;
return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
}
void CSeekInStreamWrap::Init(IInStream *stream) throw()
{
Stream = stream;
vt.Read = InStreamWrap_Read;
vt.Seek = InStreamWrap_Seek;
Res = S_OK;
}
/* ---------- CByteInBufWrap ---------- */
void CByteInBufWrap::Free() throw()
{
::MidFree(Buf);
Buf = NULL;
}
bool CByteInBufWrap::Alloc(UInt32 size) throw()
{
if (!Buf || size != Size)
{
Free();
Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size);
Size = size;
}
return (Buf != NULL);
}
Byte CByteInBufWrap::ReadByteFromNewBlock() throw()
{
if (!Extra && Res == S_OK)
{
UInt32 avail;
Res = Stream->Read(Buf, Size, &avail);
Processed += (size_t)(Cur - Buf);
Cur = Buf;
Lim = Buf + avail;
if (avail != 0)
return *Cur++;
}
Extra = true;
return 0;
}
// #pragma GCC diagnostic ignored "-Winvalid-offsetof"
static Byte Wrap_ReadByte(IByteInPtr pp) throw()
{
CByteInBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteInBufWrap, vt);
// Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInBufWrap)
if (p->Cur != p->Lim)
return *p->Cur++;
return p->ReadByteFromNewBlock();
}
CByteInBufWrap::CByteInBufWrap() throw(): Buf(NULL)
{
vt.Read = Wrap_ReadByte;
}
/* ---------- CByteOutBufWrap ---------- */
/*
void CLookToSequentialWrap::Free() throw()
{
::MidFree(BufBase);
BufBase = NULL;
}
bool CLookToSequentialWrap::Alloc(UInt32 size) throw()
{
if (!BufBase || size != Size)
{
Free();
BufBase = (Byte *)::MidAlloc((size_t)size);
Size = size;
}
return (BufBase != NULL);
}
*/
/*
EXTERN_C_BEGIN
void CLookToSequentialWrap_Look(ILookInSeqStreamPtr pp)
{
CLookToSequentialWrap *p = (CLookToSequentialWrap *)pp->Obj;
if (p->Extra || p->Res != S_OK)
return;
{
UInt32 avail;
p->Res = p->Stream->Read(p->BufBase, p->Size, &avail);
p->Processed += avail;
pp->Buf = p->BufBase;
pp->Limit = pp->Buf + avail;
if (avail == 0)
p->Extra = true;
}
}
EXTERN_C_END
*/
/* ---------- CByteOutBufWrap ---------- */
void CByteOutBufWrap::Free() throw()
{
::MidFree(Buf);
Buf = NULL;
}
bool CByteOutBufWrap::Alloc(size_t size) throw()
{
if (!Buf || size != Size)
{
Free();
Buf = (Byte *)::MidAlloc(size);
Size = size;
}
return (Buf != NULL);
}
HRESULT CByteOutBufWrap::Flush() throw()
{
if (Res == S_OK)
{
const size_t size = (size_t)(Cur - Buf);
Res = WriteStream(Stream, Buf, size);
if (Res == S_OK)
Processed += size;
// else throw 11;
}
Cur = Buf; // reset pointer for later Wrap_WriteByte()
return Res;
}
static void Wrap_WriteByte(IByteOutPtr pp, Byte b) throw()
{
CByteOutBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteOutBufWrap, vt);
// Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteOutBufWrap)
Byte *dest = p->Cur;
*dest = b;
p->Cur = ++dest;
if (dest == p->Lim)
p->Flush();
}
CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(NULL), Size(0)
{
vt.Write = Wrap_WriteByte;
}
/* ---------- CLookOutWrap ---------- */
/*
void CLookOutWrap::Free() throw()
{
::MidFree(Buf);
Buf = NULL;
}
bool CLookOutWrap::Alloc(size_t size) throw()
{
if (!Buf || size != Size)
{
Free();
Buf = (Byte *)::MidAlloc(size);
Size = size;
}
return (Buf != NULL);
}
static size_t LookOutWrap_GetOutBuf(ILookOutStreamPtr pp, void **buf) throw()
{
CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt);
*buf = p->Buf;
return p->Size;
}
static size_t LookOutWrap_Write(ILookOutStreamPtr pp, size_t size) throw()
{
CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt);
if (p->Res == S_OK && size != 0)
{
p->Res = WriteStream(p->Stream, p->Buf, size);
if (p->Res == S_OK)
{
p->Processed += size;
return size;
}
}
return 0;
}
CLookOutWrap::CLookOutWrap() throw(): Buf(NULL), Size(0)
{
vt.GetOutBuf = LookOutWrap_GetOutBuf;
vt.Write = LookOutWrap_Write;
}
*/
+182
View File
@@ -0,0 +1,182 @@
// CWrappers.h
#ifndef ZIP7_INC_C_WRAPPERS_H
#define ZIP7_INC_C_WRAPPERS_H
#include "../ICoder.h"
#include "../../Common/MyCom.h"
SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw();
HRESULT SResToHRESULT(SRes res) throw();
struct CCompressProgressWrap
{
ICompressProgress vt;
ICompressProgressInfo *Progress;
HRESULT Res;
void Init(ICompressProgressInfo *progress) throw();
};
struct CSeqInStreamWrap
{
ISeqInStream vt;
ISequentialInStream *Stream;
HRESULT Res;
UInt64 Processed;
void Init(ISequentialInStream *stream) throw();
};
struct CSeekInStreamWrap
{
ISeekInStream vt;
IInStream *Stream;
HRESULT Res;
void Init(IInStream *stream) throw();
};
struct CSeqOutStreamWrap
{
ISeqOutStream vt;
ISequentialOutStream *Stream;
HRESULT Res;
UInt64 Processed;
void Init(ISequentialOutStream *stream) throw();
};
struct CByteInBufWrap
{
IByteIn vt;
const Byte *Cur;
const Byte *Lim;
Byte *Buf;
UInt32 Size;
ISequentialInStream *Stream;
UInt64 Processed;
bool Extra;
HRESULT Res;
CByteInBufWrap() throw();
~CByteInBufWrap() { Free(); }
void Free() throw();
bool Alloc(UInt32 size) throw();
void Init()
{
Lim = Cur = Buf;
Processed = 0;
Extra = false;
Res = S_OK;
}
UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); }
Byte ReadByteFromNewBlock() throw();
Byte ReadByte()
{
if (Cur != Lim)
return *Cur++;
return ReadByteFromNewBlock();
}
};
/*
struct CLookToSequentialWrap
{
Byte *BufBase;
UInt32 Size;
ISequentialInStream *Stream;
UInt64 Processed;
bool Extra;
HRESULT Res;
CLookToSequentialWrap(): BufBase(NULL) {}
~CLookToSequentialWrap() { Free(); }
void Free() throw();
bool Alloc(UInt32 size) throw();
void Init()
{
// Lim = Cur = Buf;
Processed = 0;
Extra = false;
Res = S_OK;
}
// UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
Byte ReadByteFromNewBlock() throw();
Byte ReadByte()
{
if (Cur != Lim)
return *Cur++;
return ReadByteFromNewBlock();
}
};
EXTERN_C_BEGIN
// void CLookToSequentialWrap_Look(ILookInSeqStream *pp);
EXTERN_C_END
*/
struct CByteOutBufWrap
{
IByteOut vt;
Byte *Cur;
const Byte *Lim;
Byte *Buf;
size_t Size;
ISequentialOutStream *Stream;
UInt64 Processed;
HRESULT Res;
CByteOutBufWrap() throw();
~CByteOutBufWrap() { Free(); }
void Free() throw();
bool Alloc(size_t size) throw();
void Init()
{
Cur = Buf;
Lim = Buf + Size;
Processed = 0;
Res = S_OK;
}
UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); }
HRESULT Flush() throw();
void WriteByte(Byte b)
{
*Cur++ = b;
if (Cur == Lim)
Flush();
}
};
/*
struct CLookOutWrap
{
ILookOutStream vt;
Byte *Buf;
size_t Size;
ISequentialOutStream *Stream;
UInt64 Processed;
HRESULT Res;
CLookOutWrap() throw();
~CLookOutWrap() { Free(); }
void Free() throw();
bool Alloc(size_t size) throw();
void Init()
{
Processed = 0;
Res = S_OK;
}
};
*/
#endif
@@ -0,0 +1,548 @@
// CreateCoder.cpp
#include "StdAfx.h"
#include "../../Windows/Defs.h"
#include "../../Windows/PropVariant.h"
#include "CreateCoder.h"
#include "FilterCoder.h"
#include "RegisterCodec.h"
static const unsigned kNumCodecsMax = 64;
extern
unsigned g_NumCodecs;
unsigned g_NumCodecs = 0;
extern
const CCodecInfo *g_Codecs[];
const CCodecInfo *g_Codecs[kNumCodecsMax];
// We use g_ExternalCodecs in other stages.
#ifdef Z7_EXTERNAL_CODECS
/*
extern CExternalCodecs g_ExternalCodecs;
#define CHECK_GLOBAL_CODECS \
if (!_externalCodecs || !_externalCodecs->IsSet()) _externalCodecs = &g_ExternalCodecs;
*/
#define CHECK_GLOBAL_CODECS
#endif
void RegisterCodec(const CCodecInfo *codecInfo) throw()
{
if (g_NumCodecs < kNumCodecsMax)
g_Codecs[g_NumCodecs++] = codecInfo;
}
static const unsigned kNumHashersMax = 32;
extern
unsigned g_NumHashers;
unsigned g_NumHashers = 0;
extern
const CHasherInfo *g_Hashers[];
const CHasherInfo *g_Hashers[kNumHashersMax];
void RegisterHasher(const CHasherInfo *hashInfo) throw()
{
if (g_NumHashers < kNumHashersMax)
g_Hashers[g_NumHashers++] = hashInfo;
}
#ifdef Z7_EXTERNAL_CODECS
static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
{
NWindows::NCOM::CPropVariant prop;
RINOK(codecsInfo->GetProperty(index, propID, &prop))
if (prop.vt == VT_EMPTY)
res = 1;
else if (prop.vt == VT_UI4)
res = prop.ulVal;
else
return E_INVALIDARG;
return S_OK;
}
static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
{
NWindows::NCOM::CPropVariant prop;
RINOK(codecsInfo->GetProperty(index, propID, &prop))
if (prop.vt == VT_EMPTY)
res = true;
else if (prop.vt == VT_BOOL)
res = VARIANT_BOOLToBool(prop.boolVal);
else
return E_INVALIDARG;
return S_OK;
}
HRESULT CExternalCodecs::Load()
{
Codecs.Clear();
Hashers.Clear();
if (GetCodecs)
{
CCodecInfoEx info;
UString s;
UInt32 num;
RINOK(GetCodecs->GetNumMethods(&num))
for (UInt32 i = 0; i < num; i++)
{
NWindows::NCOM::CPropVariant prop;
RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop))
if (prop.vt != VT_UI8)
continue; // old Interface
info.Id = prop.uhVal.QuadPart;
prop.Clear();
info.Name.Empty();
RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop))
if (prop.vt == VT_BSTR)
info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
else if (prop.vt != VT_EMPTY)
continue;
RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams))
{
UInt32 numUnpackStreams = 1;
RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams))
if (numUnpackStreams != 1)
continue;
}
RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned))
RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned))
RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kIsFilter, info.IsFilter))
Codecs.Add(info);
}
}
if (GetHashers)
{
UInt32 num = GetHashers->GetNumHashers();
CHasherInfoEx info;
for (UInt32 i = 0; i < num; i++)
{
NWindows::NCOM::CPropVariant prop;
RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop))
if (prop.vt != VT_UI8)
continue;
info.Id = prop.uhVal.QuadPart;
prop.Clear();
info.Name.Empty();
RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop))
if (prop.vt == VT_BSTR)
info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
else if (prop.vt != VT_EMPTY)
continue;
Hashers.Add(info);
}
}
return S_OK;
}
#endif
int FindMethod_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
const AString &name,
bool encode,
CMethodId &methodId,
UInt32 &numStreams,
bool &isFilter)
{
unsigned i;
for (i = 0; i < g_NumCodecs; i++)
{
const CCodecInfo &codec = *g_Codecs[i];
if ((encode ? codec.CreateEncoder : codec.CreateDecoder)
&& StringsAreEqualNoCase_Ascii(name, codec.Name))
{
methodId = codec.Id;
numStreams = codec.NumStreams;
isFilter = codec.IsFilter;
return (int)i;
}
}
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (_externalCodecs)
for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
{
const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)
&& StringsAreEqualNoCase_Ascii(name, codec.Name))
{
methodId = codec.Id;
numStreams = codec.NumStreams;
isFilter = codec.IsFilter;
return (int)(g_NumCodecs + i);
}
}
#endif
return -1;
}
static int FindMethod_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode)
{
unsigned i;
for (i = 0; i < g_NumCodecs; i++)
{
const CCodecInfo &codec = *g_Codecs[i];
if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder))
return (int)i;
}
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (_externalCodecs)
for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
{
const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned))
return (int)(g_NumCodecs + i);
}
#endif
return -1;
}
bool FindMethod(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId,
AString &name)
{
name.Empty();
unsigned i;
for (i = 0; i < g_NumCodecs; i++)
{
const CCodecInfo &codec = *g_Codecs[i];
if (methodId == codec.Id)
{
name = codec.Name;
return true;
}
}
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (_externalCodecs)
for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
{
const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
if (methodId == codec.Id)
{
name = codec.Name;
return true;
}
}
#endif
return false;
}
bool FindHashMethod(
DECL_EXTERNAL_CODECS_LOC_VARS
const AString &name,
CMethodId &methodId)
{
unsigned i;
for (i = 0; i < g_NumHashers; i++)
{
const CHasherInfo &codec = *g_Hashers[i];
if (StringsAreEqualNoCase_Ascii(name, codec.Name))
{
methodId = codec.Id;
return true;
}
}
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (_externalCodecs)
for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
{
const CHasherInfoEx &codec = _externalCodecs->Hashers[i];
if (StringsAreEqualNoCase_Ascii(name, codec.Name))
{
methodId = codec.Id;
return true;
}
}
#endif
return false;
}
void GetHashMethods(
DECL_EXTERNAL_CODECS_LOC_VARS
CRecordVector<CMethodId> &methods)
{
methods.ClearAndSetSize(g_NumHashers);
unsigned i;
for (i = 0; i < g_NumHashers; i++)
methods[i] = (*g_Hashers[i]).Id;
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (_externalCodecs)
for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
methods.Add(_externalCodecs->Hashers[i].Id);
#endif
}
HRESULT CreateCoder_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
unsigned i, bool encode,
CMyComPtr<ICompressFilter> &filter,
CCreatedCoder &cod)
{
cod.IsExternal = false;
cod.IsFilter = false;
cod.NumStreams = 1;
if (i < g_NumCodecs)
{
const CCodecInfo &codec = *g_Codecs[i];
// if (codec.Id == methodId)
{
if (encode)
{
if (codec.CreateEncoder)
{
void *p = codec.CreateEncoder();
if (codec.IsFilter) filter = (ICompressFilter *)p;
else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
return S_OK;
}
}
else
if (codec.CreateDecoder)
{
void *p = codec.CreateDecoder();
if (codec.IsFilter) filter = (ICompressFilter *)p;
else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
return S_OK;
}
}
}
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (_externalCodecs)
{
i -= g_NumCodecs;
cod.IsExternal = true;
if (i < _externalCodecs->Codecs.Size())
{
const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
// if (codec.Id == methodId)
{
if (encode)
{
if (codec.EncoderIsAssigned)
{
if (codec.NumStreams == 1)
{
const HRESULT res = _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
return res;
if (cod.Coder)
return res;
return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
}
cod.NumStreams = codec.NumStreams;
return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
}
}
else
if (codec.DecoderIsAssigned)
{
if (codec.NumStreams == 1)
{
const HRESULT res = _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
return res;
if (cod.Coder)
return res;
return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
}
cod.NumStreams = codec.NumStreams;
return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
}
}
}
}
#endif
return S_OK;
}
HRESULT CreateCoder_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
unsigned index, bool encode,
CCreatedCoder &cod)
{
CMyComPtr<ICompressFilter> filter;
const HRESULT res = CreateCoder_Index(
EXTERNAL_CODECS_LOC_VARS
index, encode,
filter, cod);
if (filter)
{
cod.IsFilter = true;
CFilterCoder *coderSpec = new CFilterCoder(encode);
cod.Coder = coderSpec;
coderSpec->Filter = filter;
}
return res;
}
HRESULT CreateCoder_Id(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CMyComPtr<ICompressFilter> &filter,
CCreatedCoder &cod)
{
const int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);
if (index < 0)
return S_OK;
return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)index, encode, filter, cod);
}
HRESULT CreateCoder_Id(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CCreatedCoder &cod)
{
CMyComPtr<ICompressFilter> filter;
const HRESULT res = CreateCoder_Id(
EXTERNAL_CODECS_LOC_VARS
methodId, encode,
filter, cod);
if (filter)
{
cod.IsFilter = true;
CFilterCoder *coderSpec = new CFilterCoder(encode);
cod.Coder = coderSpec;
coderSpec->Filter = filter;
}
return res;
}
HRESULT CreateCoder_Id(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CMyComPtr<ICompressCoder> &coder)
{
CCreatedCoder cod;
const HRESULT res = CreateCoder_Id(
EXTERNAL_CODECS_LOC_VARS
methodId, encode,
cod);
coder = cod.Coder;
return res;
}
HRESULT CreateFilter(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CMyComPtr<ICompressFilter> &filter)
{
CCreatedCoder cod;
return CreateCoder_Id(
EXTERNAL_CODECS_LOC_VARS
methodId, encode,
filter, cod);
}
HRESULT CreateHasher(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId,
AString &name,
CMyComPtr<IHasher> &hasher)
{
name.Empty();
unsigned i;
for (i = 0; i < g_NumHashers; i++)
{
const CHasherInfo &codec = *g_Hashers[i];
if (codec.Id == methodId)
{
hasher = codec.CreateHasher();
name = codec.Name;
break;
}
}
#ifdef Z7_EXTERNAL_CODECS
CHECK_GLOBAL_CODECS
if (!hasher && _externalCodecs)
for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
{
const CHasherInfoEx &codec = _externalCodecs->Hashers[i];
if (codec.Id == methodId)
{
name = codec.Name;
return _externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
}
}
#endif
return S_OK;
}
@@ -0,0 +1,200 @@
// CreateCoder.h
#ifndef ZIP7_INC_CREATE_CODER_H
#define ZIP7_INC_CREATE_CODER_H
#include "../../Common/MyCom.h"
#include "../../Common/MyString.h"
#include "../ICoder.h"
#include "MethodId.h"
/*
if Z7_EXTERNAL_CODECS is not defined, the code supports only codecs that
are statically linked at compile-time and link-time.
if Z7_EXTERNAL_CODECS is defined, the code supports also codecs from another
executable modules, that can be linked dynamically at run-time:
- EXE module can use codecs from external DLL files.
- DLL module can use codecs from external EXE and DLL files.
CExternalCodecs contains information about codecs and interfaces to create them.
The order of codecs:
1) Internal codecs
2) External codecs
*/
#ifdef Z7_EXTERNAL_CODECS
struct CCodecInfoEx
{
CMethodId Id;
AString Name;
UInt32 NumStreams;
bool EncoderIsAssigned;
bool DecoderIsAssigned;
bool IsFilter; // it's unused
CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false), IsFilter(false) {}
};
struct CHasherInfoEx
{
CMethodId Id;
AString Name;
};
#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC \
public ISetCompressCodecsInfo,
#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC \
Z7_COM_QI_ENTRY(ISetCompressCodecsInfo)
#define DECL_ISetCompressCodecsInfo \
Z7_COM7F_IMP(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo))
#define IMPL_ISetCompressCodecsInfo2(cls) \
Z7_COM7F_IMF(cls::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) \
{ COM_TRY_BEGIN _externalCodecs.GetCodecs = compressCodecsInfo; \
return _externalCodecs.Load(); COM_TRY_END }
#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
struct CExternalCodecs
{
CMyComPtr<ICompressCodecsInfo> GetCodecs;
CMyComPtr<IHashers> GetHashers;
CObjectVector<CCodecInfoEx> Codecs;
CObjectVector<CHasherInfoEx> Hashers;
bool IsSet() const { return GetCodecs != NULL || GetHashers != NULL; }
HRESULT Load();
void ClearAndRelease()
{
Hashers.Clear();
Codecs.Clear();
GetHashers.Release();
GetCodecs.Release();
}
~CExternalCodecs()
{
GetHashers.Release();
GetCodecs.Release();
}
};
extern CExternalCodecs g_ExternalCodecs;
#define EXTERNAL_CODECS_VARS2 (_externalCodecs.IsSet() ? &_externalCodecs : &g_ExternalCodecs)
#define EXTERNAL_CODECS_VARS2_L (&_externalCodecs)
#define EXTERNAL_CODECS_VARS2_G (&g_ExternalCodecs)
#define DECL_EXTERNAL_CODECS_VARS CExternalCodecs _externalCodecs;
#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
#define EXTERNAL_CODECS_VARS_L EXTERNAL_CODECS_VARS2_L,
#define EXTERNAL_CODECS_VARS_G EXTERNAL_CODECS_VARS2_G,
#define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *_externalCodecs
#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,
#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL DECL_EXTERNAL_CODECS_LOC_VARS2;
#define EXTERNAL_CODECS_LOC_VARS2 _externalCodecs
#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,
#else
#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
#define DECL_ISetCompressCodecsInfo
#define IMPL_ISetCompressCodecsInfo
#define EXTERNAL_CODECS_VARS2
#define DECL_EXTERNAL_CODECS_VARS
#define EXTERNAL_CODECS_VARS
#define EXTERNAL_CODECS_VARS_L
#define EXTERNAL_CODECS_VARS_G
#define DECL_EXTERNAL_CODECS_LOC_VARS2
#define DECL_EXTERNAL_CODECS_LOC_VARS
#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL
#define EXTERNAL_CODECS_LOC_VARS2
#define EXTERNAL_CODECS_LOC_VARS
#endif
int FindMethod_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
const AString &name,
bool encode,
CMethodId &methodId,
UInt32 &numStreams,
bool &isFilter);
bool FindMethod(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId,
AString &name);
bool FindHashMethod(
DECL_EXTERNAL_CODECS_LOC_VARS
const AString &name,
CMethodId &methodId);
void GetHashMethods(
DECL_EXTERNAL_CODECS_LOC_VARS
CRecordVector<CMethodId> &methods);
struct CCreatedCoder
{
CMyComPtr<ICompressCoder> Coder;
CMyComPtr<ICompressCoder2> Coder2;
bool IsExternal;
bool IsFilter; // = true, if Coder was created from filter
UInt32 NumStreams;
// CCreatedCoder(): IsExternal(false), IsFilter(false), NumStreams(1) {}
};
HRESULT CreateCoder_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
unsigned codecIndex, bool encode,
CMyComPtr<ICompressFilter> &filter,
CCreatedCoder &cod);
HRESULT CreateCoder_Index(
DECL_EXTERNAL_CODECS_LOC_VARS
unsigned index, bool encode,
CCreatedCoder &cod);
HRESULT CreateCoder_Id(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CMyComPtr<ICompressFilter> &filter,
CCreatedCoder &cod);
HRESULT CreateCoder_Id(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CCreatedCoder &cod);
HRESULT CreateCoder_Id(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CMyComPtr<ICompressCoder> &coder);
HRESULT CreateFilter(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId, bool encode,
CMyComPtr<ICompressFilter> &filter);
HRESULT CreateHasher(
DECL_EXTERNAL_CODECS_LOC_VARS
CMethodId methodId,
AString &name,
CMyComPtr<IHasher> &hasher);
#endif
@@ -0,0 +1,46 @@
// FilePathAutoRename.cpp
#include "StdAfx.h"
#include "../../Windows/FileFind.h"
#include "FilePathAutoRename.h"
using namespace NWindows;
static bool MakeAutoName(const FString &name,
const FString &extension, UInt32 value, FString &path)
{
path = name;
path.Add_UInt32(value);
path += extension;
return NFile::NFind::DoesFileOrDirExist(path);
}
bool AutoRenamePath(FString &path)
{
const int dotPos = path.ReverseFind_Dot();
const int slashPos = path.ReverseFind_PathSepar();
FString name = path;
FString extension;
if (dotPos > slashPos + 1)
{
name.DeleteFrom((unsigned)dotPos);
extension = path.Ptr((unsigned)dotPos);
}
name.Add_Char('_');
FString temp;
UInt32 left = 1, right = (UInt32)1 << 30;
while (left != right)
{
const UInt32 mid = (left + right) / 2;
if (MakeAutoName(name, extension, mid, temp))
left = mid + 1;
else
right = mid;
}
return !MakeAutoName(name, extension, right, path);
}
@@ -0,0 +1,10 @@
// FilePathAutoRename.h
#ifndef ZIP7_INC_FILE_PATH_AUTO_RENAME_H
#define ZIP7_INC_FILE_PATH_AUTO_RENAME_H
#include "../../Common/MyString.h"
bool AutoRenamePath(FString &fullProcessedPath);
#endif
@@ -0,0 +1,923 @@
// FileStreams.cpp
#include "StdAfx.h"
// #include <stdio.h>
#ifndef _WIN32
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
/*
inclusion of <sys/sysmacros.h> by <sys/types.h> is deprecated since glibc 2.25.
Since glibc 2.3.3, macros have been aliases for three GNU-specific
functions: gnu_dev_makedev(), gnu_dev_major(), and gnu_dev_minor()
Warning in GCC:
In the GNU C Library, "major" is defined by <sys/sysmacros.h>.
For historical compatibility, it is currently defined by
<sys/types.h> as well, but we plan to remove this soon.
To use "major", include <sys/sysmacros.h> directly.
If you did not intend to use a system-defined macro "major",
you should undefine it after including <sys/types.h>
*/
// for major()/minor():
#if defined(__APPLE__) || defined(__DragonFly__) || \
defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/types.h>
#else
#include <sys/sysmacros.h>
#endif
#endif // _WIN32
#include "../../Windows/FileFind.h"
#ifdef Z7_DEVICE_FILE
#include "../../../C/Alloc.h"
#include "../../Common/Defs.h"
#endif
#include "../PropID.h"
#include "FileStreams.h"
static inline HRESULT GetLastError_HRESULT()
{
DWORD lastError = ::GetLastError();
if (lastError == 0)
return E_FAIL;
return HRESULT_FROM_WIN32(lastError);
}
static inline HRESULT ConvertBoolToHRESULT(bool result)
{
if (result)
return S_OK;
return GetLastError_HRESULT();
}
#ifdef Z7_DEVICE_FILE
static const UInt32 kClusterSize = 1 << 18;
#endif
CInFileStream::CInFileStream():
#ifdef Z7_DEVICE_FILE
VirtPos(0),
PhyPos(0),
Buf(NULL),
BufSize(0),
#endif
#ifndef _WIN32
_uid(0),
_gid(0),
StoreOwnerId(false),
StoreOwnerName(false),
#endif
_info_WasLoaded(false),
SupportHardLinks(false),
Callback(NULL),
CallbackRef(0)
{
}
CInFileStream::~CInFileStream()
{
#ifdef Z7_DEVICE_FILE
MidFree(Buf);
#endif
if (Callback)
Callback->InFileStream_On_Destroy(this, CallbackRef);
}
Z7_COM7F_IMF(CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
// printf("\nCInFileStream::Read size=%d, VirtPos=%8d\n", (unsigned)size, (int)VirtPos);
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
#ifdef Z7_DEVICE_FILE
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
if (File.IsDeviceFile)
{
if (File.SizeDefined)
{
if (VirtPos >= File.Size)
return VirtPos == File.Size ? S_OK : E_FAIL;
const UInt64 rem = File.Size - VirtPos;
if (size > rem)
size = (UInt32)rem;
}
for (;;)
{
const UInt32 mask = kClusterSize - 1;
const UInt64 mask2 = ~(UInt64)mask;
const UInt64 alignedPos = VirtPos & mask2;
if (BufSize > 0 && BufStartPos == alignedPos)
{
const UInt32 pos = (UInt32)VirtPos & mask;
if (pos >= BufSize)
return S_OK;
const UInt32 rem = MyMin(BufSize - pos, size);
memcpy(data, Buf + pos, rem);
VirtPos += rem;
if (processedSize)
*processedSize += rem;
return S_OK;
}
bool useBuf = false;
if ((VirtPos & mask) != 0 || ((size_t)(ptrdiff_t)data & mask) != 0 )
useBuf = true;
else
{
UInt64 end = VirtPos + size;
if ((end & mask) != 0)
{
end &= mask2;
if (end <= VirtPos)
useBuf = true;
else
size = (UInt32)(end - VirtPos);
}
}
if (!useBuf)
break;
if (alignedPos != PhyPos)
{
UInt64 realNewPosition;
const bool result = File.Seek((Int64)alignedPos, FILE_BEGIN, realNewPosition);
if (!result)
return ConvertBoolToHRESULT(result);
PhyPos = realNewPosition;
}
BufStartPos = alignedPos;
UInt32 readSize = kClusterSize;
if (File.SizeDefined)
readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize);
if (!Buf)
{
Buf = (Byte *)MidAlloc(kClusterSize);
if (!Buf)
return E_OUTOFMEMORY;
}
const bool result = File.Read1(Buf, readSize, BufSize);
if (!result)
return ConvertBoolToHRESULT(result);
if (BufSize == 0)
return S_OK;
PhyPos += BufSize;
}
if (VirtPos != PhyPos)
{
UInt64 realNewPosition;
bool result = File.Seek((Int64)VirtPos, FILE_BEGIN, realNewPosition);
if (!result)
return ConvertBoolToHRESULT(result);
PhyPos = VirtPos = realNewPosition;
}
}
#endif
UInt32 realProcessedSize;
const bool result = File.ReadPart(data, size, realProcessedSize);
if (processedSize)
*processedSize = realProcessedSize;
#ifdef Z7_DEVICE_FILE
VirtPos += realProcessedSize;
PhyPos += realProcessedSize;
#endif
if (result)
return S_OK;
#else // Z7_FILE_STREAMS_USE_WIN_FILE
if (processedSize)
*processedSize = 0;
const ssize_t res = File.read_part(data, (size_t)size);
if (res != -1)
{
if (processedSize)
*processedSize = (UInt32)res;
return S_OK;
}
#endif // Z7_FILE_STREAMS_USE_WIN_FILE
{
const DWORD error = ::GetLastError();
#if 0
if (File.IsStdStream && error == ERROR_BROKEN_PIPE)
return S_OK; // end of stream
#endif
if (Callback)
return Callback->InFileStream_On_Error(CallbackRef, error);
if (error == 0)
return E_FAIL;
return HRESULT_FROM_WIN32(error);
}
}
#ifdef UNDER_CE
Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
size_t s2 = fread(data, 1, size, stdin);
int error = ferror(stdin);
if (processedSize)
*processedSize = s2;
if (s2 <= size && error == 0)
return S_OK;
return E_FAIL;
}
#else
Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
// printf("\nCStdInFileStream::Read size = %d\n", (unsigned)size);
#ifdef _WIN32
DWORD realProcessedSize;
UInt32 sizeTemp = (1 << 20);
if (sizeTemp > size)
sizeTemp = size;
/* in GUI mode : GetStdHandle(STD_INPUT_HANDLE) returns NULL,
and it doesn't set LastError. */
/*
SetLastError(0);
const HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
if (!h || h == INVALID_HANDLE_VALUE)
{
if (processedSize)
*processedSize = 0;
if (GetLastError() == 0)
SetLastError(ERROR_INVALID_HANDLE);
return GetLastError_noZero_HRESULT();
}
*/
BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
/*
printf("\nCInFileStream::Read: size=%d, processed=%8d res=%d 4rror=%3d\n",
(unsigned)size, (int)realProcessedSize,
(int)res, GetLastError());
*/
if (processedSize)
*processedSize = realProcessedSize;
if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
return S_OK;
return ConvertBoolToHRESULT(res != FALSE);
#else
if (processedSize)
*processedSize = 0;
ssize_t res;
do
{
res = read(0, data, (size_t)size);
}
while (res < 0 && (errno == EINTR));
if (res == -1)
return GetLastError_HRESULT();
if (processedSize)
*processedSize = (UInt32)res;
return S_OK;
#endif
}
#endif
/*
bool CreateStdInStream(CMyComPtr<ISequentialInStream> &str)
{
#if 0
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);;
if (!inStreamSpec->OpenStdIn())
return false;
if (!inStreamSpec->File.IsStdPipeStream)
str = inStreamLoc.Detach();
else
#endif
str = new CStdInFileStream;
return true;
}
*/
#if 0
bool CInFileStream::OpenStdIn()
{
_info_WasLoaded = false;
// Sleep(100);
bool res = File.AttachStdIn();
if (!res)
return false;
#if 1
CStreamFileProps props;
if (GetProps2(&props) != S_OK)
{
// we can ignore that error
return false;
}
// we can't use Size, because Size can be set for pipe streams for some value.
// Seek() sees only current chunk in pipe buffer.
// So Seek() can move across only current unread chunk.
// But after reading that chunk. it can't move position back.
// We need safe check that shows that we can use seek (non-pipe mode)
// Is it safe check that shows that pipe mode was used?
File.IsStdPipeStream = (props.VolID == 0);
// && FILETIME_IsZero(props.CTime)
// && FILETIME_IsZero(props.ATime)
// && FILETIME_IsZero(props.MTime);
#endif
// printf("\n######## pipe=%d", (unsigned)File.IsStdPipeStream);
return true;
}
#endif
Z7_COM7F_IMF(CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
/*
printf("\nCInFileStream::Seek seekOrigin=%d, offset=%8d, VirtPos=%8d\n",
(unsigned)seekOrigin, (int)offset, (int)VirtPos);
*/
if (seekOrigin >= 3)
return STG_E_INVALIDFUNCTION;
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
#ifdef Z7_DEVICE_FILE
if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += VirtPos; break;
case STREAM_SEEK_END: offset += File.Size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
VirtPos = (UInt64)offset;
if (newPosition)
*newPosition = (UInt64)offset;
return S_OK;
}
#endif
UInt64 realNewPosition = 0;
const bool result = File.Seek(offset, seekOrigin, realNewPosition);
const HRESULT hres = ConvertBoolToHRESULT(result);
/* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition)
in case of error. So we don't need additional code below */
// if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); }
#ifdef Z7_DEVICE_FILE
PhyPos = VirtPos = realNewPosition;
#endif
if (newPosition)
*newPosition = realNewPosition;
return hres;
#else
const off_t res = File.seek((off_t)offset, (int)seekOrigin);
if (res == -1)
{
const HRESULT hres = GetLastError_HRESULT();
if (newPosition)
*newPosition = (UInt64)File.seekToCur();
return hres;
}
if (newPosition)
*newPosition = (UInt64)res;
return S_OK;
#endif
}
Z7_COM7F_IMF(CInFileStream::GetSize(UInt64 *size))
{
return ConvertBoolToHRESULT(File.GetLength(*size));
}
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
{
if (!_info_WasLoaded)
{
RINOK(ReloadProps())
}
const BY_HANDLE_FILE_INFORMATION &info = _info;
/*
BY_HANDLE_FILE_INFORMATION info;
if (!File.GetFileInformation(&info))
return GetLastError_HRESULT();
*/
{
if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
if (cTime) *cTime = info.ftCreationTime;
if (aTime) *aTime = info.ftLastAccessTime;
if (mTime) *mTime = info.ftLastWriteTime;
if (attrib) *attrib = info.dwFileAttributes;
return S_OK;
}
}
Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
{
if (!_info_WasLoaded)
{
RINOK(ReloadProps())
}
const BY_HANDLE_FILE_INFORMATION &info = _info;
/*
BY_HANDLE_FILE_INFORMATION info;
if (!File.GetFileInformation(&info))
return GetLastError_HRESULT();
*/
{
props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
props->VolID = info.dwVolumeSerialNumber;
props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
props->FileID_High = 0;
props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1;
props->Attrib = info.dwFileAttributes;
props->CTime = info.ftCreationTime;
props->ATime = info.ftLastAccessTime;
props->MTime = info.ftLastWriteTime;
return S_OK;
}
}
Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
{
if (!_info_WasLoaded)
{
RINOK(ReloadProps())
}
if (!_info_WasLoaded)
return S_OK;
NWindows::NCOM::CPropVariant prop;
#ifdef Z7_DEVICE_FILE
if (File.IsDeviceFile)
{
switch (propID)
{
case kpidSize:
if (File.SizeDefined)
prop = File.Size;
break;
// case kpidAttrib: prop = (UInt32)0; break;
case kpidPosixAttrib:
{
prop = (UInt32)NWindows::NFile::NFind::NAttributes::
Get_PosixMode_From_WinAttrib(0);
/* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute
so we don't use MY_LIN_S_IFBLK here */
// prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug
break;
}
/*
case kpidDeviceMajor:
prop = (UInt32)8; // id for SCSI type device (sda)
break;
case kpidDeviceMinor:
prop = (UInt32)0;
break;
*/
}
}
else
#endif
{
switch (propID)
{
case kpidSize:
{
const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow;
prop = size;
break;
}
case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break;
case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break;
case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break;
case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break;
case kpidPosixAttrib:
prop = (UInt32)NWindows::NFile::NFind::NAttributes::
Get_PosixMode_From_WinAttrib(_info.dwFileAttributes);
// | (UInt32)(1 << 21); // for debug
break;
}
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CInFileStream::ReloadProps())
{
#ifdef Z7_DEVICE_FILE
if (File.IsDeviceFile)
{
memset(&_info, 0, sizeof(_info));
if (File.SizeDefined)
{
_info.nFileSizeHigh = (DWORD)(File.Size >> 32);
_info.nFileSizeLow = (DWORD)(File.Size);
}
_info.nNumberOfLinks = 1;
_info_WasLoaded = true;
return S_OK;
}
#endif
_info_WasLoaded = File.GetFileInformation(&_info);
if (!_info_WasLoaded)
return GetLastError_HRESULT();
#ifdef _WIN32
#if 0
printf(
"\ndwFileAttributes = %8x"
"\nftCreationTime = %8x"
"\nftLastAccessTime = %8x"
"\nftLastWriteTime = %8x"
"\ndwVolumeSerialNumber = %8x"
"\nnFileSizeHigh = %8x"
"\nnFileSizeLow = %8x"
"\nnNumberOfLinks = %8x"
"\nnFileIndexHigh = %8x"
"\nnFileIndexLow = %8x \n",
(unsigned)_info.dwFileAttributes,
(unsigned)_info.ftCreationTime.dwHighDateTime,
(unsigned)_info.ftLastAccessTime.dwHighDateTime,
(unsigned)_info.ftLastWriteTime.dwHighDateTime,
(unsigned)_info.dwVolumeSerialNumber,
(unsigned)_info.nFileSizeHigh,
(unsigned)_info.nFileSizeLow,
(unsigned)_info.nNumberOfLinks,
(unsigned)_info.nFileIndexHigh,
(unsigned)_info.nFileIndexLow);
#endif
#endif
return S_OK;
}
#elif !defined(_WIN32)
Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
{
// printf("\nCInFileStream::GetProps VirtPos = %8d\n", (int)VirtPos);
if (!_info_WasLoaded)
{
RINOK(ReloadProps())
}
const struct stat &st = _info;
/*
struct stat st;
if (File.my_fstat(&st) != 0)
return GetLastError_HRESULT();
*/
if (size) *size = (UInt64)st.st_size;
if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime);
if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime);
if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime);
if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
return S_OK;
}
// #include <stdio.h>
Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
{
// printf("\nCInFileStream::GetProps2 VirtPos = %8d\n", (int)VirtPos);
if (!_info_WasLoaded)
{
RINOK(ReloadProps())
}
const struct stat &st = _info;
/*
struct stat st;
if (File.my_fstat(&st) != 0)
return GetLastError_HRESULT();
*/
props->Size = (UInt64)st.st_size;
/*
dev_t stat::st_dev:
GCC:Linux long unsigned int : __dev_t
Mac: int
*/
props->VolID = (UInt64)(Int64)st.st_dev;
props->FileID_Low = st.st_ino;
props->FileID_High = 0;
props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long)
props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
FiTime_To_FILETIME (ST_CTIME(st), props->CTime);
FiTime_To_FILETIME (ST_ATIME(st), props->ATime);
FiTime_To_FILETIME (ST_MTIME(st), props->MTime);
/*
printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
, (unsigned)(props->NumLinks)
, (unsigned)(st.st_dev)
, (unsigned)(st.st_ino)
);
*/
return S_OK;
}
Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
{
// printf("\nCInFileStream::GetProperty VirtPos = %8d propID = %3d\n", (int)VirtPos, propID);
if (!_info_WasLoaded)
{
RINOK(ReloadProps())
}
if (!_info_WasLoaded)
return S_OK;
const struct stat &st = _info;
NWindows::NCOM::CPropVariant prop;
{
switch (propID)
{
case kpidSize: prop = (UInt64)st.st_size; break;
case kpidAttrib:
prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
break;
case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break;
case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break;
case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break;
case kpidPosixAttrib: prop = (UInt32)st.st_mode; break;
#if defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
case kpidDeviceMajor:
{
// printf("\nst.st_rdev = %d\n", st.st_rdev);
if (S_ISCHR(st.st_mode) ||
S_ISBLK(st.st_mode))
prop = (UInt32)(major(st.st_rdev)); // + 1000);
// prop = (UInt32)12345678; // for debug
break;
}
case kpidDeviceMinor:
if (S_ISCHR(st.st_mode) ||
S_ISBLK(st.st_mode))
prop = (UInt32)(minor(st.st_rdev)); // + 100);
// prop = (UInt32)(st.st_rdev); // for debug
// printf("\nst.st_rdev = %d\n", st.st_rdev);
// prop = (UInt32)123456789; // for debug
break;
#if defined(__APPLE__)
#pragma GCC diagnostic pop
#endif
/*
case kpidDevice:
if (S_ISCHR(st.st_mode) ||
S_ISBLK(st.st_mode))
prop = (UInt64)(st.st_rdev);
break;
*/
case kpidUserId:
{
if (StoreOwnerId)
prop = (UInt32)st.st_uid;
break;
}
case kpidGroupId:
{
if (StoreOwnerId)
prop = (UInt32)st.st_gid;
break;
}
case kpidUser:
{
if (StoreOwnerName)
{
const uid_t uid = st.st_uid;
{
if (!OwnerName.IsEmpty() && _uid == uid)
prop = OwnerName;
else
{
const passwd *pw = getpwuid(uid);
if (pw)
{
// we can use utf-8 here.
// prop = pw->pw_name;
}
}
}
}
break;
}
case kpidGroup:
{
if (StoreOwnerName)
{
const uid_t gid = st.st_gid;
{
if (!OwnerGroup.IsEmpty() && _gid == gid)
prop = OwnerGroup;
else
{
const group *gr = getgrgid(gid);
if (gr)
{
// we can use utf-8 here.
// prop = gr->gr_name;
}
}
}
}
break;
}
default: break;
}
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CInFileStream::ReloadProps())
{
_info_WasLoaded = (File.my_fstat(&_info) == 0);
if (!_info_WasLoaded)
return GetLastError_HRESULT();
return S_OK;
}
#endif
//////////////////////////
// COutFileStream
HRESULT COutFileStream::Close()
{
return ConvertBoolToHRESULT(File.Close());
}
Z7_COM7F_IMF(COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
UInt32 realProcessedSize;
const bool result = File.Write(data, size, realProcessedSize);
ProcessedSize += realProcessedSize;
if (processedSize)
*processedSize = realProcessedSize;
return ConvertBoolToHRESULT(result);
#else
if (processedSize)
*processedSize = 0;
size_t realProcessedSize;
const ssize_t res = File.write_full(data, (size_t)size, realProcessedSize);
ProcessedSize += realProcessedSize;
if (processedSize)
*processedSize = (UInt32)realProcessedSize;
if (res == -1)
return GetLastError_HRESULT();
return S_OK;
#endif
}
Z7_COM7F_IMF(COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
if (seekOrigin >= 3)
return STG_E_INVALIDFUNCTION;
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
UInt64 realNewPosition = 0;
const bool result = File.Seek(offset, seekOrigin, realNewPosition);
if (newPosition)
*newPosition = realNewPosition;
return ConvertBoolToHRESULT(result);
#else
const off_t res = File.seek((off_t)offset, (int)seekOrigin);
if (res == -1)
return GetLastError_HRESULT();
if (newPosition)
*newPosition = (UInt64)res;
return S_OK;
#endif
}
Z7_COM7F_IMF(COutFileStream::SetSize(UInt64 newSize))
{
return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize));
}
HRESULT COutFileStream::GetSize(UInt64 *size)
{
return ConvertBoolToHRESULT(File.GetLength(*size));
}
#ifdef UNDER_CE
Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
size_t s2 = fwrite(data, 1, size, stdout);
if (processedSize)
*processedSize = s2;
return (s2 == size) ? S_OK : E_FAIL;
}
#else
Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
#ifdef _WIN32
UInt32 realProcessedSize;
BOOL res = TRUE;
if (size > 0)
{
// Seems that Windows doesn't like big amounts writing to stdout.
// So we limit portions by 32KB.
UInt32 sizeTemp = (1 << 15);
if (sizeTemp > size)
sizeTemp = size;
res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
_size += realProcessedSize;
size -= realProcessedSize;
data = (const void *)((const Byte *)data + realProcessedSize);
if (processedSize)
*processedSize += realProcessedSize;
}
return ConvertBoolToHRESULT(res != FALSE);
#else
ssize_t res;
do
{
res = write(1, data, (size_t)size);
}
while (res < 0 && (errno == EINTR));
if (res == -1)
return GetLastError_HRESULT();
_size += (size_t)res;
if (processedSize)
*processedSize = (UInt32)res;
return S_OK;
#endif
}
#endif
@@ -0,0 +1,205 @@
// FileStreams.h
#ifndef ZIP7_INC_FILE_STREAMS_H
#define ZIP7_INC_FILE_STREAMS_H
#ifdef _WIN32
#define Z7_FILE_STREAMS_USE_WIN_FILE
#endif
#include "../../Common/MyCom.h"
#include "../../Common/MyString.h"
#include "../../Windows/FileIO.h"
#include "../IStream.h"
#include "UniqBlocks.h"
class CInFileStream;
Z7_PURE_INTERFACES_BEGIN
DECLARE_INTERFACE(IInFileStream_Callback)
{
virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0;
virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0;
};
Z7_PURE_INTERFACES_END
/*
Z7_CLASS_IMP_COM_5(
CInFileStream
, IInStream
, IStreamGetSize
, IStreamGetProps
, IStreamGetProps2
, IStreamGetProp
)
*/
Z7_class_final(CInFileStream) :
public IInStream,
public IStreamGetSize,
public IStreamGetProps,
public IStreamGetProps2,
public IStreamGetProp,
public CMyUnknownImp
{
Z7_COM_UNKNOWN_IMP_6(
IInStream,
ISequentialInStream,
IStreamGetSize,
IStreamGetProps,
IStreamGetProps2,
IStreamGetProp)
Z7_IFACE_COM7_IMP(ISequentialInStream)
Z7_IFACE_COM7_IMP(IInStream)
public:
Z7_IFACE_COM7_IMP(IStreamGetSize)
private:
Z7_IFACE_COM7_IMP(IStreamGetProps)
public:
Z7_IFACE_COM7_IMP(IStreamGetProps2)
Z7_IFACE_COM7_IMP(IStreamGetProp)
private:
NWindows::NFile::NIO::CInFile File;
public:
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
#ifdef Z7_DEVICE_FILE
UInt64 VirtPos;
UInt64 PhyPos;
UInt64 BufStartPos;
Byte *Buf;
UInt32 BufSize;
#endif
#endif
#ifdef _WIN32
BY_HANDLE_FILE_INFORMATION _info;
#else
struct stat _info;
UInt32 _uid;
UInt32 _gid;
UString OwnerName;
UString OwnerGroup;
bool StoreOwnerId;
bool StoreOwnerName;
#endif
bool _info_WasLoaded;
bool SupportHardLinks;
IInFileStream_Callback *Callback;
UINT_PTR CallbackRef;
CInFileStream();
~CInFileStream();
void Set_PreserveATime(bool v)
{
File.PreserveATime = v;
}
bool GetLength(UInt64 &length) const throw()
{
return File.GetLength(length);
}
#if 0
bool OpenStdIn();
#endif
bool Open(CFSTR fileName)
{
_info_WasLoaded = false;
return File.Open(fileName);
}
bool OpenShared(CFSTR fileName, bool shareForWrite)
{
_info_WasLoaded = false;
return File.OpenShared(fileName, shareForWrite);
}
};
// bool CreateStdInStream(CMyComPtr<ISequentialInStream> &str);
Z7_CLASS_IMP_NOQIB_1(
CStdInFileStream
, ISequentialInStream
)
};
Z7_CLASS_IMP_COM_1(
COutFileStream
, IOutStream
)
Z7_IFACE_COM7_IMP(ISequentialOutStream)
public:
NWindows::NFile::NIO::COutFile File;
bool Create_NEW(CFSTR fileName)
{
ProcessedSize = 0;
return File.Create_NEW(fileName);
}
bool Create_ALWAYS(CFSTR fileName)
{
ProcessedSize = 0;
return File.Create_ALWAYS(fileName);
}
bool Open_EXISTING(CFSTR fileName)
{
ProcessedSize = 0;
return File.Open_EXISTING(fileName);
}
bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways)
{
ProcessedSize = 0;
return File.Create_ALWAYS_or_Open_ALWAYS(fileName, createAlways);
}
HRESULT Close();
UInt64 ProcessedSize;
bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
{
return File.SetTime(cTime, aTime, mTime);
}
bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); }
bool SeekToBegin_bool()
{
#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
return File.SeekToBegin();
#else
return File.seekToBegin() == 0;
#endif
}
HRESULT GetSize(UInt64 *size);
};
Z7_CLASS_IMP_NOQIB_1(
CStdOutFileStream
, ISequentialOutStream
)
UInt64 _size;
public:
UInt64 GetSize() const { return _size; }
CStdOutFileStream(): _size(0) {}
};
#endif
@@ -0,0 +1,577 @@
// FilterCoder.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../Common/Defs.h"
#include "FilterCoder.h"
#include "StreamUtils.h"
#ifdef _WIN32
#define alignedMidBuffer_Alloc g_MidAlloc
#else
#define alignedMidBuffer_Alloc g_AlignedAlloc
#endif
CAlignedMidBuffer::~CAlignedMidBuffer()
{
ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf);
}
void CAlignedMidBuffer::AllocAligned(size_t size)
{
ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf);
_buf = (Byte *)ISzAlloc_Alloc(&alignedMidBuffer_Alloc, size);
}
/*
AES filters need 16-bytes alignment for HARDWARE-AES instructions.
So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block.
AES-CBC filters need data size aligned for 16-bytes.
So the encoder can add zeros to the end of original stream.
Some filters (BCJ and others) don't process data at the end of stream in some cases.
So the encoder and decoder write such last bytes without change.
Most filters process all data, if we send aligned size to filter.
But BCJ filter can process up 4 bytes less than sent size.
And ARMT filter can process 2 bytes less than sent size.
*/
static const UInt32 kBufSize = 1 << 21;
Z7_COM7F_IMF(CFilterCoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; }
Z7_COM7F_IMF(CFilterCoder::SetOutBufSize(UInt32 , UInt32 size)) { _outBufSize = size; return S_OK; }
HRESULT CFilterCoder::Alloc()
{
UInt32 size = MyMin(_inBufSize, _outBufSize);
/* minimal bufSize is 16 bytes for AES and IA64 filter.
bufSize for AES must be aligned for 16 bytes.
We use (1 << 12) min size to support future aligned filters. */
const UInt32 kMinSize = 1 << 12;
size &= ~(UInt32)(kMinSize - 1);
if (size < kMinSize)
size = kMinSize;
// size = (1 << 12); // + 117; // for debug
if (!_buf || _bufSize != size)
{
AllocAligned(size);
if (!_buf)
return E_OUTOFMEMORY;
_bufSize = size;
}
return S_OK;
}
HRESULT CFilterCoder::Init_and_Alloc()
{
RINOK(Filter->Init())
return Alloc();
}
CFilterCoder::CFilterCoder(bool encodeMode):
_bufSize(0),
_inBufSize(kBufSize),
_outBufSize(kBufSize),
_encodeMode(encodeMode),
_outSize_Defined(false),
_outSize(0),
_nowPos64(0)
{}
Z7_COM7F_IMF(CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
{
RINOK(Init_and_Alloc())
/*
It's expected that BCJ/ARMT filter can process up to 4 bytes less
than sent data size. For such BCJ/ARMT cases with non-filtered data we:
- write some filtered data to output stream
- move non-written data (filtered and non-filtered data) to start of buffer
- read more new data from input stream to position after end of non-filtered data
- call Filter() for concatenated data in buffer.
For all cases, even for cases with partial filtering (BCJ/ARMT),
we try to keep real/virtual alignment for all operations
(memmove, Read(), Filter(), Write()).
We use (kAlignSize=64) alignmnent that is larger than (16-bytes)
required for AES filter alignment.
AES-CBC uses 16-bytes blocks, that is simple case for processing here,
if we call Filter() for aligned size for all calls except of last call (last block).
And now there are no filters that use blocks with non-power2 size,
but we try to support such non-power2 filters too here at Code().
*/
UInt64 prev = 0;
UInt64 nowPos64 = 0;
bool inputFinished = false;
UInt32 readPos = 0;
UInt32 filterPos = 0;
while (!outSize || nowPos64 < *outSize)
{
HRESULT hres = S_OK;
if (!inputFinished)
{
size_t processedSize = _bufSize - readPos;
/* for AES filters we need at least max(16, kAlignSize) bytes in buffer.
But we try to read full buffer to reduce the number of Filter() and Write() calls.
*/
hres = ReadStream(inStream, _buf + readPos, &processedSize);
readPos += (UInt32)processedSize;
inputFinished = (readPos != _bufSize);
if (hres != S_OK)
{
// do we need to stop encoding after reading error?
// if (_encodeMode) return hres;
inputFinished = true;
}
}
if (readPos == 0)
return hres;
/* we set (needMoreInput = true), if it's block-filter (like AES-CBC)
that needs more data for current block filtering:
We read full input buffer with Read(), and _bufSize is aligned,
So the possible cases when we set (needMoreInput = true) are:
1) decode : filter needs more data after the end of input stream.
another cases are possible for non-power2-block-filter,
because buffer size is not aligned for filter_non_power2_block_size:
2) decode/encode : filter needs more data from non-finished input stream
3) encode : filter needs more space for zeros after the end of input stream
*/
bool needMoreInput = false;
while (readPos != filterPos)
{
/* Filter() is allowed to process part of data.
Here we use the loop to filter as max as possible.
when we call Filter(data, size):
if (size < 16), AES-CTR filter uses internal 16-byte buffer.
new (since v23.00) AES-CTR filter allows (size < 16) for non-last block,
but it will work less efficiently than calls with aligned (size).
We still support old (before v23.00) AES-CTR filters here.
We have aligned (size) for AES-CTR, if it's not last block.
We have aligned (readPos) for any filter, if (!inputFinished).
We also meet the requirements for (data) pointer in Filter() call:
{
(virtual_stream_offset % aligment_size) == (data_ptr % aligment_size)
(aligment_size == 2^N)
(aligment_size >= 16)
}
*/
const UInt32 cur = Filter->Filter(_buf + filterPos, readPos - filterPos);
if (cur == 0)
break;
const UInt32 f = filterPos + cur;
if (cur > readPos - filterPos)
{
// AES-CBC
if (hres != S_OK)
break;
if (!_encodeMode
|| cur > _bufSize - filterPos
|| !inputFinished)
{
/* (cur > _bufSize - filterPos) is unexpected for AES filter, if _bufSize is multiply of 16.
But we support this case, if some future filter will use block with non-power2-size.
*/
needMoreInput = true;
break;
}
/* (_encodeMode && inputFinished).
We add zero bytes as pad in current block after the end of read data. */
Byte *buf = _buf;
do
buf[readPos] = 0;
while (++readPos != f);
// (readPos) now is (size_of_real_input_data + size_of_zero_pad)
if (cur != Filter->Filter(buf + filterPos, cur))
return E_FAIL;
}
filterPos = f;
}
UInt32 size = filterPos;
if (hres == S_OK)
{
/* If we need more Read() or Filter() calls, then we need to Write()
some data and move unwritten data to get additional space in buffer.
We try to keep alignment for data moves, Read(), Filter() and Write() calls.
*/
const UInt32 kAlignSize = 1 << 6;
const UInt32 alignedFiltered = filterPos & ~(kAlignSize - 1);
if (inputFinished)
{
if (!needMoreInput)
size = readPos; // for risc/bcj filters in last block we write data after filterPos.
else if (_encodeMode)
size = alignedFiltered; // for non-power2-block-encode-filter
}
else
size = alignedFiltered;
}
{
UInt32 writeSize = size;
if (outSize)
{
const UInt64 rem = *outSize - nowPos64;
if (writeSize > rem)
writeSize = (UInt32)rem;
}
RINOK(WriteStream(outStream, _buf, writeSize))
nowPos64 += writeSize;
}
if (hres != S_OK)
return hres;
if (inputFinished)
{
if (readPos == size)
return hres;
if (!_encodeMode)
{
// block-decode-filter (AES-CBS) has non-full last block
// we don't want unaligned data move for more iterations with this error case.
return S_FALSE;
}
}
if (size == 0)
{
// it's unexpected that we have no any move in this iteration.
return E_FAIL;
}
// if (size != 0)
{
if (filterPos < size)
return E_FAIL; // filterPos = 0; else
filterPos -= size;
readPos -= size;
if (readPos != 0)
memmove(_buf, _buf + size, readPos);
}
// printf("\nnowPos64=%x, readPos=%x, filterPos=%x\n", (unsigned)nowPos64, (unsigned)readPos, (unsigned)filterPos);
if (progress && (nowPos64 - prev) >= (1 << 22))
{
prev = nowPos64;
RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64))
}
}
return S_OK;
}
// ---------- Write to Filter ----------
Z7_COM7F_IMF(CFilterCoder::SetOutStream(ISequentialOutStream *outStream))
{
_outStream = outStream;
return S_OK;
}
Z7_COM7F_IMF(CFilterCoder::ReleaseOutStream())
{
_outStream.Release();
return S_OK;
}
HRESULT CFilterCoder::Flush2()
{
while (_convSize != 0)
{
UInt32 num = _convSize;
if (_outSize_Defined)
{
const UInt64 rem = _outSize - _nowPos64;
if (num > rem)
num = (UInt32)rem;
if (num == 0)
return k_My_HRESULT_WritingWasCut;
}
UInt32 processed = 0;
const HRESULT res = _outStream->Write(_buf + _convPos, num, &processed);
if (processed == 0)
return res != S_OK ? res : E_FAIL;
_convPos += processed;
_convSize -= processed;
_nowPos64 += processed;
RINOK(res)
}
const UInt32 convPos = _convPos;
if (convPos != 0)
{
const UInt32 num = _bufPos - convPos;
Byte *buf = _buf;
for (UInt32 i = 0; i < num; i++)
buf[i] = buf[convPos + i];
_bufPos = num;
_convPos = 0;
}
return S_OK;
}
Z7_COM7F_IMF(CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
while (size != 0)
{
RINOK(Flush2())
// _convSize is 0
// _convPos is 0
// _bufPos is small
if (_bufPos != _bufSize)
{
UInt32 num = MyMin(size, _bufSize - _bufPos);
memcpy(_buf + _bufPos, data, num);
size -= num;
data = (const Byte *)data + num;
if (processedSize)
*processedSize += num;
_bufPos += num;
if (_bufPos != _bufSize)
continue;
}
// _bufPos == _bufSize
_convSize = Filter->Filter(_buf, _bufPos);
if (_convSize == 0)
break;
if (_convSize > _bufPos)
{
// that case is not possible.
_convSize = 0;
return E_FAIL;
}
}
return S_OK;
}
Z7_COM7F_IMF(CFilterCoder::OutStreamFinish())
{
for (;;)
{
RINOK(Flush2())
if (_bufPos == 0)
break;
const UInt32 convSize = Filter->Filter(_buf, _bufPos);
_convSize = convSize;
UInt32 bufPos = _bufPos;
if (convSize == 0)
_convSize = bufPos;
else if (convSize > bufPos)
{
// AES
if (convSize > _bufSize)
{
_convSize = 0;
return E_FAIL;
}
if (!_encodeMode)
{
_convSize = 0;
return S_FALSE;
}
Byte *buf = _buf;
for (; bufPos < convSize; bufPos++)
buf[bufPos] = 0;
_bufPos = bufPos;
_convSize = Filter->Filter(_buf, bufPos);
if (_convSize != _bufPos)
return E_FAIL;
}
}
CMyComPtr<IOutStreamFinish> finish;
_outStream.QueryInterface(IID_IOutStreamFinish, &finish);
if (finish)
return finish->OutStreamFinish();
return S_OK;
}
// ---------- Init functions ----------
Z7_COM7F_IMF(CFilterCoder::InitEncoder())
{
InitSpecVars();
return Init_and_Alloc();
}
HRESULT CFilterCoder::Init_NoSubFilterInit()
{
InitSpecVars();
return Alloc();
}
Z7_COM7F_IMF(CFilterCoder::SetOutStreamSize(const UInt64 *outSize))
{
InitSpecVars();
if (outSize)
{
_outSize = *outSize;
_outSize_Defined = true;
}
return Init_and_Alloc();
}
// ---------- Read from Filter ----------
Z7_COM7F_IMF(CFilterCoder::SetInStream(ISequentialInStream *inStream))
{
_inStream = inStream;
return S_OK;
}
Z7_COM7F_IMF(CFilterCoder::ReleaseInStream())
{
_inStream.Release();
return S_OK;
}
Z7_COM7F_IMF(CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
while (size != 0)
{
if (_convSize != 0)
{
if (size > _convSize)
size = _convSize;
if (_outSize_Defined)
{
const UInt64 rem = _outSize - _nowPos64;
if (size > rem)
size = (UInt32)rem;
}
memcpy(data, _buf + _convPos, size);
_convPos += size;
_convSize -= size;
_nowPos64 += size;
if (processedSize)
*processedSize = size;
break;
}
const UInt32 convPos = _convPos;
if (convPos != 0)
{
const UInt32 num = _bufPos - convPos;
Byte *buf = _buf;
for (UInt32 i = 0; i < num; i++)
buf[i] = buf[convPos + i];
_bufPos = num;
_convPos = 0;
}
{
size_t readSize = _bufSize - _bufPos;
const HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize);
_bufPos += (UInt32)readSize;
RINOK(res)
}
const UInt32 convSize = Filter->Filter(_buf, _bufPos);
_convSize = convSize;
UInt32 bufPos = _bufPos;
if (convSize == 0)
{
if (bufPos == 0)
break;
// BCJ
_convSize = bufPos;
continue;
}
if (convSize > bufPos)
{
// AES
if (convSize > _bufSize)
return E_FAIL;
if (!_encodeMode)
return S_FALSE;
Byte *buf = _buf;
do
buf[bufPos] = 0;
while (++bufPos != convSize);
_bufPos = bufPos;
_convSize = Filter->Filter(_buf, convSize);
if (_convSize != _bufPos)
return E_FAIL;
}
}
return S_OK;
}
#ifndef Z7_NO_CRYPTO
Z7_COM7F_IMF(CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size))
{ return _setPassword->CryptoSetPassword(data, size); }
Z7_COM7F_IMF(CFilterCoder::SetKey(const Byte *data, UInt32 size))
{ return _cryptoProperties->SetKey(data, size); }
Z7_COM7F_IMF(CFilterCoder::SetInitVector(const Byte *data, UInt32 size))
{ return _cryptoProperties->SetInitVector(data, size); }
#endif
#ifndef Z7_EXTRACT_ONLY
Z7_COM7F_IMF(CFilterCoder::SetCoderProperties(const PROPID *propIDs,
const PROPVARIANT *properties, UInt32 numProperties))
{ return _setCoderProperties->SetCoderProperties(propIDs, properties, numProperties); }
Z7_COM7F_IMF(CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream))
{ return _writeCoderProperties->WriteCoderProperties(outStream); }
Z7_COM7F_IMF(CFilterCoder::SetCoderPropertiesOpt(const PROPID *propIDs,
const PROPVARIANT *properties, UInt32 numProperties))
{ return _setCoderPropertiesOpt->SetCoderPropertiesOpt(propIDs, properties, numProperties); }
/*
Z7_COM7F_IMF(CFilterCoder::ResetSalt()
{ return _cryptoResetSalt->ResetSalt(); }
*/
Z7_COM7F_IMF(CFilterCoder::ResetInitVector())
{ return _cryptoResetInitVector->ResetInitVector(); }
#endif
Z7_COM7F_IMF(CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size))
{ return _setDecoderProperties2->SetDecoderProperties2(data, size); }
@@ -0,0 +1,201 @@
// FilterCoder.h
#ifndef ZIP7_INC_FILTER_CODER_H
#define ZIP7_INC_FILTER_CODER_H
#include "../../../C/Alloc.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#ifndef Z7_NO_CRYPTO
#include "../IPassword.h"
#endif
#define Z7_COM_QI_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \
{ if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
*outObject = (void *)(i *)this; }
struct CAlignedMidBuffer
{
Byte *_buf;
CAlignedMidBuffer(): _buf(NULL) {}
~CAlignedMidBuffer();
void AllocAligned(size_t size);
};
class CFilterCoder Z7_final :
public ICompressCoder,
public ICompressSetOutStreamSize,
public ICompressInitEncoder,
public ICompressSetInStream,
public ISequentialInStream,
public ICompressSetOutStream,
public ISequentialOutStream,
public IOutStreamFinish,
public ICompressSetBufSize,
#ifndef Z7_NO_CRYPTO
public ICryptoSetPassword,
public ICryptoProperties,
#endif
#ifndef Z7_EXTRACT_ONLY
public ICompressSetCoderProperties,
public ICompressWriteCoderProperties,
public ICompressSetCoderPropertiesOpt,
// public ICryptoResetSalt,
public ICryptoResetInitVector,
#endif
public ICompressSetDecoderProperties2,
public CMyUnknownImp,
public CAlignedMidBuffer
{
UInt32 _bufSize;
UInt32 _inBufSize;
UInt32 _outBufSize;
bool _encodeMode;
bool _outSize_Defined;
UInt64 _outSize;
UInt64 _nowPos64;
CMyComPtr<ISequentialInStream> _inStream;
CMyComPtr<ISequentialOutStream> _outStream;
UInt32 _bufPos;
UInt32 _convPos; // current pos in buffer for converted data
UInt32 _convSize; // size of converted data starting from _convPos
void InitSpecVars()
{
_bufPos = 0;
_convPos = 0;
_convSize = 0;
_outSize_Defined = false;
_outSize = 0;
_nowPos64 = 0;
}
HRESULT Alloc();
HRESULT Init_and_Alloc();
HRESULT Flush2();
#ifndef Z7_NO_CRYPTO
CMyComPtr<ICryptoSetPassword> _setPassword;
CMyComPtr<ICryptoProperties> _cryptoProperties;
#endif
#ifndef Z7_EXTRACT_ONLY
CMyComPtr<ICompressSetCoderProperties> _setCoderProperties;
CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
CMyComPtr<ICompressSetCoderPropertiesOpt> _setCoderPropertiesOpt;
// CMyComPtr<ICryptoResetSalt> _cryptoResetSalt;
CMyComPtr<ICryptoResetInitVector> _cryptoResetInitVector;
#endif
CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties2;
public:
CMyComPtr<ICompressFilter> Filter;
CFilterCoder(bool encodeMode);
struct C_InStream_Releaser
{
CFilterCoder *FilterCoder;
C_InStream_Releaser(): FilterCoder(NULL) {}
~C_InStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
};
struct C_OutStream_Releaser
{
CFilterCoder *FilterCoder;
C_OutStream_Releaser(): FilterCoder(NULL) {}
~C_OutStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
};
struct C_Filter_Releaser
{
CFilterCoder *FilterCoder;
C_Filter_Releaser(): FilterCoder(NULL) {}
~C_Filter_Releaser() { if (FilterCoder) FilterCoder->Filter.Release(); }
};
private:
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
Z7_COM_QI_ENTRY(ICompressInitEncoder)
Z7_COM_QI_ENTRY(ICompressSetInStream)
Z7_COM_QI_ENTRY(ISequentialInStream)
Z7_COM_QI_ENTRY(ICompressSetOutStream)
Z7_COM_QI_ENTRY(ISequentialOutStream)
Z7_COM_QI_ENTRY(IOutStreamFinish)
Z7_COM_QI_ENTRY(ICompressSetBufSize)
#ifndef Z7_NO_CRYPTO
Z7_COM_QI_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword)
Z7_COM_QI_ENTRY_AG(ICryptoProperties, Filter, _cryptoProperties)
#endif
#ifndef Z7_EXTRACT_ONLY
Z7_COM_QI_ENTRY_AG(ICompressSetCoderProperties, Filter, _setCoderProperties)
Z7_COM_QI_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties)
Z7_COM_QI_ENTRY_AG(ICompressSetCoderPropertiesOpt, Filter, _setCoderPropertiesOpt)
// Z7_COM_QI_ENTRY_AG(ICryptoResetSalt, Filter, _cryptoResetSalt)
Z7_COM_QI_ENTRY_AG(ICryptoResetInitVector, Filter, _cryptoResetInitVector)
#endif
Z7_COM_QI_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties2)
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
public:
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
Z7_IFACE_COM7_IMP(ICompressInitEncoder)
Z7_IFACE_COM7_IMP(ICompressSetInStream)
private:
Z7_IFACE_COM7_IMP(ISequentialInStream)
public:
Z7_IFACE_COM7_IMP(ICompressSetOutStream)
private:
Z7_IFACE_COM7_IMP(ISequentialOutStream)
public:
Z7_IFACE_COM7_IMP(IOutStreamFinish)
private:
Z7_IFACE_COM7_IMP(ICompressSetBufSize)
#ifndef Z7_NO_CRYPTO
Z7_IFACE_COM7_IMP(ICryptoSetPassword)
Z7_IFACE_COM7_IMP(ICryptoProperties)
#endif
#ifndef Z7_EXTRACT_ONLY
Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties)
Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt)
// Z7_IFACE_COM7_IMP(ICryptoResetSalt)
Z7_IFACE_COM7_IMP(ICryptoResetInitVector)
#endif
public:
Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
HRESULT Init_NoSubFilterInit();
};
#endif
+182
View File
@@ -0,0 +1,182 @@
// InBuffer.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "InBuffer.h"
CInBufferBase::CInBufferBase() throw():
_buf(NULL),
_bufLim(NULL),
_bufBase(NULL),
_stream(NULL),
_processedSize(0),
_bufSize(0),
_wasFinished(false),
NumExtraBytes(0)
{}
bool CInBuffer::Create(size_t bufSize) throw()
{
const unsigned kMinBlockSize = 1;
if (bufSize < kMinBlockSize)
bufSize = kMinBlockSize;
if (_bufBase != NULL && _bufSize == bufSize)
return true;
Free();
_bufSize = bufSize;
_bufBase = (Byte *)::MidAlloc(bufSize);
return (_bufBase != NULL);
}
void CInBuffer::Free() throw()
{
::MidFree(_bufBase);
_bufBase = NULL;
}
void CInBufferBase::Init() throw()
{
_processedSize = 0;
_buf = _bufBase;
_bufLim = _buf;
_wasFinished = false;
#ifdef Z7_NO_EXCEPTIONS
ErrorCode = S_OK;
#endif
NumExtraBytes = 0;
}
bool CInBufferBase::ReadBlock()
{
#ifdef Z7_NO_EXCEPTIONS
if (ErrorCode != S_OK)
return false;
#endif
if (_wasFinished)
return false;
_processedSize += (size_t)(_buf - _bufBase);
_buf = _bufBase;
_bufLim = _bufBase;
UInt32 processed;
// FIX_ME: we can improve it to support (_bufSize >= (1 << 32))
const HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed);
#ifdef Z7_NO_EXCEPTIONS
ErrorCode = result;
#else
if (result != S_OK)
throw CInBufferException(result);
#endif
_bufLim = _buf + processed;
_wasFinished = (processed == 0);
return !_wasFinished;
}
bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
{
if (!ReadBlock())
{
// 22.00: we don't increment (NumExtraBytes) here
// NumExtraBytes++;
b = 0xFF;
return false;
}
b = *_buf++;
return true;
}
Byte CInBufferBase::ReadByte_FromNewBlock()
{
if (!ReadBlock())
{
NumExtraBytes++;
return 0xFF;
}
return *_buf++;
}
size_t CInBufferBase::ReadBytesPart(Byte *buf, size_t size)
{
if (size == 0)
return 0;
size_t rem = (size_t)(_bufLim - _buf);
if (rem == 0)
{
if (!ReadBlock())
return 0;
rem = (size_t)(_bufLim - _buf);
}
if (size > rem)
size = rem;
memcpy(buf, _buf, size);
_buf += size;
return size;
}
size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)
{
size_t num = 0;
for (;;)
{
const size_t rem = (size_t)(_bufLim - _buf);
if (size <= rem)
{
if (size != 0)
{
memcpy(buf, _buf, size);
_buf += size;
num += size;
}
return num;
}
if (rem != 0)
{
memcpy(buf, _buf, rem);
_buf += rem;
buf += rem;
num += rem;
size -= rem;
}
if (!ReadBlock())
return num;
}
/*
if ((size_t)(_bufLim - _buf) >= size)
{
const Byte *src = _buf;
for (size_t i = 0; i < size; i++)
buf[i] = src[i];
_buf += size;
return size;
}
for (size_t i = 0; i < size; i++)
{
if (_buf >= _bufLim)
if (!ReadBlock())
return i;
buf[i] = *_buf++;
}
return size;
*/
}
size_t CInBufferBase::Skip(size_t size)
{
size_t processed = 0;
for (;;)
{
const size_t rem = (size_t)(_bufLim - _buf);
if (rem >= size)
{
_buf += size;
return processed + size;
}
_buf += rem;
processed += rem;
size -= rem;
if (!ReadBlock())
return processed;
}
}
+121
View File
@@ -0,0 +1,121 @@
// InBuffer.h
#ifndef ZIP7_INC_IN_BUFFER_H
#define ZIP7_INC_IN_BUFFER_H
#include "../../Common/MyException.h"
#include "../IStream.h"
#ifndef Z7_NO_EXCEPTIONS
struct CInBufferException: public CSystemException
{
CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
};
#endif
class CInBufferBase
{
protected:
Byte *_buf;
Byte *_bufLim;
Byte *_bufBase;
ISequentialInStream *_stream;
UInt64 _processedSize;
size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger
// only up to 32-bits values now are supported!
bool _wasFinished;
bool ReadBlock();
bool ReadByte_FromNewBlock(Byte &b);
Byte ReadByte_FromNewBlock();
public:
#ifdef Z7_NO_EXCEPTIONS
HRESULT ErrorCode;
#endif
UInt32 NumExtraBytes;
CInBufferBase() throw();
// the size of portion of data in real stream that was already read from this object
// it doesn't include unused data in buffer
// it doesn't include virtual Extra bytes after the end of real stream data
UInt64 GetStreamSize() const { return _processedSize + (size_t)(_buf - _bufBase); }
// the size of virtual data that was read from this object
// it doesn't include unused data in buffers
// it includes any virtual Extra bytes after the end of real data
UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (size_t)(_buf - _bufBase); }
bool WasFinished() const { return _wasFinished; }
void SetStream(ISequentialInStream *stream) { _stream = stream; }
void ClearStreamPtr() { _stream = NULL; }
void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos)
{
_bufBase = buf;
_bufSize = bufSize;
_processedSize = 0;
_buf = buf + pos;
_bufLim = buf + end;
_wasFinished = false;
#ifdef Z7_NO_EXCEPTIONS
ErrorCode = S_OK;
#endif
NumExtraBytes = 0;
}
void Init() throw();
Z7_FORCE_INLINE
bool ReadByte(Byte &b)
{
if (_buf >= _bufLim)
return ReadByte_FromNewBlock(b);
b = *_buf++;
return true;
}
Z7_FORCE_INLINE
bool ReadByte_FromBuf(Byte &b)
{
if (_buf >= _bufLim)
return false;
b = *_buf++;
return true;
}
Z7_FORCE_INLINE
Byte ReadByte()
{
if (_buf >= _bufLim)
return ReadByte_FromNewBlock();
return *_buf++;
}
size_t ReadBytesPart(Byte *buf, size_t size);
size_t ReadBytes(Byte *buf, size_t size);
const Byte *Lookahead(size_t &rem)
{
rem = (size_t)(_bufLim - _buf);
if (!rem)
{
ReadBlock();
rem = (size_t)(_bufLim - _buf);
}
return _buf;
}
size_t Skip(size_t size);
};
class CInBuffer: public CInBufferBase
{
public:
~CInBuffer() { Free(); }
bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported!
void Free() throw();
};
#endif
@@ -0,0 +1,237 @@
// InOutTempBuffer.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "InOutTempBuffer.h"
#include "StreamUtils.h"
#ifdef USE_InOutTempBuffer_FILE
#include "../../../C/7zCrc.h"
#define kTempFilePrefixString FTEXT("7zt")
/*
Total buffer size limit, if we use temp file scheme:
32-bit: 16 MiB = 1 MiB * 16 buffers
64-bit: 4 GiB = 1 MiB * 4096 buffers
*/
static const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4);
#endif
static const size_t kBufSize = (size_t)1 << 20;
CInOutTempBuffer::CInOutTempBuffer():
_size(0),
_bufs(NULL),
_numBufs(0),
_numFilled(0)
{
#ifdef USE_InOutTempBuffer_FILE
_tempFile_Created = false;
_useMemOnly = false;
_crc = CRC_INIT_VAL;
#endif
}
CInOutTempBuffer::~CInOutTempBuffer()
{
for (size_t i = 0; i < _numBufs; i++)
MyFree(_bufs[i]);
MyFree(_bufs);
}
void *CInOutTempBuffer::GetBuf(size_t index)
{
if (index >= _numBufs)
{
const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2);
void **p = (void **)MyRealloc(_bufs, num * sizeof(void *));
if (!p)
return NULL;
_bufs = p;
memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *));
_numBufs = num;
}
void *buf = _bufs[index];
if (!buf)
{
buf = MyAlloc(kBufSize);
if (buf)
_bufs[index] = buf;
}
return buf;
}
HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size)
{
if (size == 0)
return S_OK;
#ifdef USE_InOutTempBuffer_FILE
if (!_tempFile_Created)
#endif
for (;;) // loop for additional attemp to allocate memory after file creation error
{
#ifdef USE_InOutTempBuffer_FILE
bool allocError = false;
#endif
for (;;) // loop for writing to buffers
{
const size_t index = (size_t)(_size / kBufSize);
#ifdef USE_InOutTempBuffer_FILE
if (index >= kNumBufsMax && !_useMemOnly)
break;
#endif
void *buf = GetBuf(index);
if (!buf)
{
#ifdef USE_InOutTempBuffer_FILE
if (!_useMemOnly)
{
allocError = true;
break;
}
#endif
return E_OUTOFMEMORY;
}
const size_t offset = (size_t)(_size) & (kBufSize - 1);
size_t cur = kBufSize - offset;
if (cur > size)
cur = size;
memcpy((Byte *)buf + offset, data, cur);
_size += cur;
if (index >= _numFilled)
_numFilled = index + 1;
data = (const void *)((const Byte *)data + cur);
size -= (UInt32)cur;
if (size == 0)
return S_OK;
}
#ifdef USE_InOutTempBuffer_FILE
#ifndef _WIN32
_outFile.mode_for_Create = 0600; // only owner will have the rights to access this file
#endif
if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
{
_tempFile_Created = true;
break;
}
_useMemOnly = true;
if (allocError)
return GetLastError_noZero_HRESULT();
#endif
}
#ifdef USE_InOutTempBuffer_FILE
if (!_outFile.WriteFull(data, size))
return GetLastError_noZero_HRESULT();
_crc = CrcUpdate(_crc, data, size);
_size += size;
return S_OK;
#endif
}
HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
{
UInt64 rem = _size;
// if (rem == 0) return S_OK;
const size_t numFilled = _numFilled;
_numFilled = 0;
for (size_t i = 0; i < numFilled; i++)
{
if (rem == 0)
return E_FAIL;
size_t cur = kBufSize;
if (cur > rem)
cur = (size_t)rem;
RINOK(WriteStream(stream, _bufs[i], cur))
rem -= cur;
#ifdef USE_InOutTempBuffer_FILE
// we will use _bufs[0] later for writing from temp file
if (i != 0 || !_tempFile_Created)
#endif
{
MyFree(_bufs[i]);
_bufs[i] = NULL;
}
}
#ifdef USE_InOutTempBuffer_FILE
if (rem == 0)
return _tempFile_Created ? E_FAIL : S_OK;
if (!_tempFile_Created)
return E_FAIL;
if (!_outFile.Close())
return GetLastError_noZero_HRESULT();
HRESULT hres;
void *buf = GetBuf(0); // index
if (!buf)
hres = E_OUTOFMEMORY;
else
{
NWindows::NFile::NIO::CInFile inFile;
if (!inFile.Open(_tempFile.GetPath()))
hres = GetLastError_noZero_HRESULT();
else
{
UInt32 crc = CRC_INIT_VAL;
for (;;)
{
size_t processed;
if (!inFile.ReadFull(buf, kBufSize, processed))
{
hres = GetLastError_noZero_HRESULT();
break;
}
if (processed == 0)
{
// we compare crc without CRC_GET_DIGEST
hres = (_crc == crc ? S_OK : E_FAIL);
break;
}
size_t n = processed;
if (n > rem)
n = (size_t)rem;
hres = WriteStream(stream, buf, n);
if (hres != S_OK)
break;
crc = CrcUpdate(crc, buf, n);
rem -= n;
if (n != processed)
{
hres = E_FAIL;
break;
}
}
}
}
// _tempFile.DisableDeleting(); // for debug
_tempFile.Remove();
RINOK(hres)
#endif
return rem == 0 ? S_OK : E_FAIL;
}
@@ -0,0 +1,45 @@
// InOutTempBuffer.h
#ifndef ZIP7_INC_IN_OUT_TEMP_BUFFER_H
#define ZIP7_INC_IN_OUT_TEMP_BUFFER_H
// #ifdef _WIN32
#define USE_InOutTempBuffer_FILE
// #endif
#ifdef USE_InOutTempBuffer_FILE
#include "../../Windows/FileDir.h"
#endif
#include "../IStream.h"
class CInOutTempBuffer
{
UInt64 _size;
void **_bufs;
size_t _numBufs;
size_t _numFilled;
#ifdef USE_InOutTempBuffer_FILE
bool _tempFile_Created;
bool _useMemOnly;
UInt32 _crc;
// COutFile object must be declared after CTempFile object for correct destructor order
NWindows::NFile::NDir::CTempFile _tempFile;
NWindows::NFile::NIO::COutFile _outFile;
#endif
void *GetBuf(size_t index);
Z7_CLASS_NO_COPY(CInOutTempBuffer)
public:
CInOutTempBuffer();
~CInOutTempBuffer();
HRESULT Write_HRESULT(const void *data, UInt32 size);
HRESULT WriteToStream(ISequentialOutStream *stream);
UInt64 GetDataSize() const { return _size; }
};
#endif
@@ -0,0 +1,393 @@
// LimitedStreams.cpp
#include "StdAfx.h"
#include <string.h>
#include "LimitedStreams.h"
Z7_COM7F_IMF(CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
UInt32 realProcessedSize = 0;
{
const UInt64 rem = _size - _pos;
if (size > rem)
size = (UInt32)rem;
}
HRESULT result = S_OK;
if (size != 0)
{
result = _stream->Read(data, size, &realProcessedSize);
_pos += realProcessedSize;
if (realProcessedSize == 0)
_wasFinished = true;
}
if (processedSize)
*processedSize = realProcessedSize;
return result;
}
Z7_COM7F_IMF(CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (_virtPos >= _size)
{
// 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
return S_OK;
// return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
}
{
const UInt64 rem = _size - _virtPos;
if (size > rem)
size = (UInt32)rem;
}
UInt64 newPos = _startOffset + _virtPos;
if (newPos != _physPos)
{
_physPos = newPos;
RINOK(SeekToPhys())
}
HRESULT res = _stream->Read(data, size, &size);
if (processedSize)
*processedSize = size;
_physPos += size;
_virtPos += size;
return res;
}
Z7_COM7F_IMF(CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += _size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = _virtPos;
return S_OK;
}
HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
{
*resStream = NULL;
CLimitedInStream *streamSpec = new CLimitedInStream;
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
streamSpec->SetStream(inStream);
RINOK(streamSpec->InitAndSeek(pos, size))
streamSpec->SeekToStart();
*resStream = streamTemp.Detach();
return S_OK;
}
Z7_COM7F_IMF(CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (_virtPos >= Size)
return S_OK;
{
UInt64 rem = Size - _virtPos;
if (size > rem)
size = (UInt32)rem;
}
if (size == 0)
return S_OK;
if (_curRem == 0)
{
const UInt32 blockSize = (UInt32)1 << BlockSizeLog;
const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
const UInt32 phyBlock = Vector[virtBlock];
UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
if (newPos != _physPos)
{
_physPos = newPos;
RINOK(SeekToPhys())
}
_curRem = blockSize - offsetInBlock;
for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
_curRem += (UInt32)1 << BlockSizeLog;
}
if (size > _curRem)
size = _curRem;
HRESULT res = Stream->Read(data, size, &size);
if (processedSize)
*processedSize = size;
_physPos += size;
_virtPos += size;
_curRem -= size;
return res;
}
Z7_COM7F_IMF(CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += Size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
if (_virtPos != (UInt64)offset)
_curRem = 0;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = (UInt64)offset;
return S_OK;
}
Z7_COM7F_IMF(CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
const UInt64 virt = _virtPos;
if (virt >= Extents.Back().Virt)
return S_OK;
if (size == 0)
return S_OK;
unsigned left = _prevExtentIndex;
if (virt < Extents[left].Virt ||
virt >= Extents[left + 1].Virt)
{
left = 0;
unsigned right = Extents.Size() - 1;
for (;;)
{
const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
if (mid == left)
break;
if (virt < Extents[mid].Virt)
right = mid;
else
left = mid;
}
_prevExtentIndex = left;
}
{
const UInt64 rem = Extents[left + 1].Virt - virt;
if (size > rem)
size = (UInt32)rem;
}
const CSeekExtent &extent = Extents[left];
if (extent.Is_ZeroFill())
{
memset(data, 0, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
{
const UInt64 phy = extent.Phy + (virt - extent.Virt);
if (_phyPos != phy)
{
_phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
RINOK(InStream_SeekSet(Stream, phy))
_phyPos = phy;
}
}
const HRESULT res = Stream->Read(data, size, &size);
_virtPos += size;
if (res == S_OK)
_phyPos += size;
else
_phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
if (processedSize)
*processedSize = size;
return res;
}
Z7_COM7F_IMF(CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += Extents.Back().Virt; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = _virtPos;
return S_OK;
}
Z7_COM7F_IMF(CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
HRESULT result = S_OK;
if (processedSize)
*processedSize = 0;
if (size > _size)
{
if (_size == 0)
{
_overflow = true;
if (!_overflowIsAllowed)
return E_FAIL;
if (processedSize)
*processedSize = size;
return S_OK;
}
size = (UInt32)_size;
}
if (_stream)
result = _stream->Write(data, size, &size);
_size -= size;
if (processedSize)
*processedSize = size;
return result;
}
Z7_COM7F_IMF(CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
UInt32 cur;
HRESULT res = Stream->Read(data, size, &cur);
if (processedSize)
*processedSize = cur;
_virtPos += cur;
return res;
}
Z7_COM7F_IMF(CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END:
{
UInt64 pos = 0;
RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos))
if (pos < Offset)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = pos - Offset;
if (newPosition)
*newPosition = _virtPos;
return S_OK;
}
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = _virtPos;
return InStream_SeekSet(Stream, Offset + _virtPos);
}
Z7_COM7F_IMF(CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (_virtPos >= _size)
{
// 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
return S_OK;
// return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
}
UInt64 rem = _size - _virtPos;
if (rem < size)
size = (UInt32)rem;
UInt64 newPos = _startOffset + _virtPos;
UInt64 offsetInCache = newPos - _cachePhyPos;
HRESULT res = S_OK;
if (newPos >= _cachePhyPos &&
offsetInCache <= _cacheSize &&
size <= _cacheSize - (size_t)offsetInCache)
{
if (size != 0)
memcpy(data, _cache + (size_t)offsetInCache, size);
}
else
{
if (newPos != _physPos)
{
_physPos = newPos;
RINOK(SeekToPhys())
}
res = _stream->Read(data, size, &size);
_physPos += size;
}
if (processedSize)
*processedSize = size;
_virtPos += size;
return res;
}
Z7_COM7F_IMF(CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += _size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = _virtPos;
return S_OK;
}
Z7_COM7F_IMF(CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
UInt32 cur;
HRESULT res = Stream->Write(data, size, &cur);
if (processedSize)
*processedSize = cur;
_virtPos += cur;
if (_virtSize < _virtPos)
_virtSize = _virtPos;
return res;
}
Z7_COM7F_IMF(CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
case STREAM_SEEK_END: offset += _virtSize; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_virtPos = (UInt64)offset;
if (newPosition)
*newPosition = _virtPos;
return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL);
}
Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize))
{
_virtSize = newSize;
return Stream->SetSize(Offset + newSize);
}
@@ -0,0 +1,221 @@
// LimitedStreams.h
#ifndef ZIP7_INC_LIMITED_STREAMS_H
#define ZIP7_INC_LIMITED_STREAMS_H
#include "../../Common/MyBuffer.h"
#include "../../Common/MyCom.h"
#include "../../Common/MyVector.h"
#include "../IStream.h"
#include "StreamUtils.h"
Z7_CLASS_IMP_COM_1(
CLimitedSequentialInStream
, ISequentialInStream
)
CMyComPtr<ISequentialInStream> _stream;
UInt64 _size;
UInt64 _pos;
bool _wasFinished;
public:
void SetStream(ISequentialInStream *stream) { _stream = stream; }
void ReleaseStream() { _stream.Release(); }
void Init(UInt64 streamSize)
{
_size = streamSize;
_pos = 0;
_wasFinished = false;
}
UInt64 GetSize() const { return _pos; }
UInt64 GetRem() const { return _size - _pos; }
bool WasFinished() const { return _wasFinished; }
};
Z7_CLASS_IMP_IInStream(
CLimitedInStream
)
CMyComPtr<IInStream> _stream;
UInt64 _virtPos;
UInt64 _physPos;
UInt64 _size;
UInt64 _startOffset;
HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); }
public:
void SetStream(IInStream *stream) { _stream = stream; }
HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
{
_startOffset = startOffset;
_physPos = startOffset;
_virtPos = 0;
_size = size;
return SeekToPhys();
}
HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
};
HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream);
Z7_CLASS_IMP_IInStream(
CClusterInStream
)
UInt64 _virtPos;
UInt64 _physPos;
UInt32 _curRem;
public:
unsigned BlockSizeLog;
UInt64 Size;
CMyComPtr<IInStream> Stream;
CRecordVector<UInt32> Vector;
UInt64 StartOffset;
HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); }
HRESULT InitAndSeek()
{
_curRem = 0;
_virtPos = 0;
_physPos = StartOffset;
if (Vector.Size() > 0)
{
_physPos = StartOffset + (Vector[0] << BlockSizeLog);
return SeekToPhys();
}
return S_OK;
}
};
const UInt64 k_SeekExtent_Phy_Type_ZeroFill = (UInt64)(Int64)-1;
struct CSeekExtent
{
UInt64 Virt;
UInt64 Phy;
void SetAs_ZeroFill() { Phy = k_SeekExtent_Phy_Type_ZeroFill; }
bool Is_ZeroFill() const { return Phy == k_SeekExtent_Phy_Type_ZeroFill; }
};
Z7_CLASS_IMP_IInStream(
CExtentsStream
)
UInt64 _virtPos;
UInt64 _phyPos;
unsigned _prevExtentIndex;
public:
CMyComPtr<IInStream> Stream;
CRecordVector<CSeekExtent> Extents;
void ReleaseStream() { Stream.Release(); }
void Init()
{
_virtPos = 0;
_phyPos = (UInt64)0 - 1; // we need Seek() for Stream
_prevExtentIndex = 0;
}
};
Z7_CLASS_IMP_COM_1(
CLimitedSequentialOutStream
, ISequentialOutStream
)
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
bool _overflow;
bool _overflowIsAllowed;
public:
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void ReleaseStream() { _stream.Release(); }
void Init(UInt64 size, bool overflowIsAllowed = false)
{
_size = size;
_overflow = false;
_overflowIsAllowed = overflowIsAllowed;
}
bool IsFinishedOK() const { return (_size == 0 && !_overflow); }
UInt64 GetRem() const { return _size; }
};
Z7_CLASS_IMP_IInStream(
CTailInStream
)
UInt64 _virtPos;
public:
CMyComPtr<IInStream> Stream;
UInt64 Offset;
void Init()
{
_virtPos = 0;
}
HRESULT SeekToStart() { return InStream_SeekSet(Stream, Offset); }
};
Z7_CLASS_IMP_IInStream(
CLimitedCachedInStream
)
CMyComPtr<IInStream> _stream;
UInt64 _virtPos;
UInt64 _physPos;
UInt64 _size;
UInt64 _startOffset;
const Byte *_cache;
size_t _cacheSize;
size_t _cachePhyPos;
HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); }
public:
CByteBuffer Buffer;
void SetStream(IInStream *stream) { _stream = stream; }
void SetCache(size_t cacheSize, size_t cachePos)
{
_cache = Buffer;
_cacheSize = cacheSize;
_cachePhyPos = cachePos;
}
HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
{
_startOffset = startOffset;
_physPos = startOffset;
_virtPos = 0;
_size = size;
return SeekToPhys();
}
HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
};
class CTailOutStream Z7_final :
public IOutStream,
public CMyUnknownImp
{
Z7_IFACES_IMP_UNK_2(ISequentialOutStream, IOutStream)
UInt64 _virtPos;
UInt64 _virtSize;
public:
CMyComPtr<IOutStream> Stream;
UInt64 Offset;
void Init()
{
_virtPos = 0;
_virtSize = 0;
}
};
#endif
@@ -0,0 +1,3 @@
// LockedStream.cpp
#include "StdAfx.h"
@@ -0,0 +1,6 @@
// LockedStream.h
#ifndef ZIP7_INC_LOCKED_STREAM_H
#define ZIP7_INC_LOCKED_STREAM_H
#endif
@@ -0,0 +1,215 @@
// MemBlocks.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "MemBlocks.h"
#include "StreamUtils.h"
bool CMemBlockManager::AllocateSpace_bool(size_t numBlocks)
{
FreeSpace();
if (numBlocks == 0)
{
return true;
// return false;
}
if (_blockSize < sizeof(void *))
return false;
const size_t totalSize = numBlocks * _blockSize;
if (totalSize / _blockSize != numBlocks)
return false;
_data = ::MidAlloc(totalSize);
if (!_data)
return false;
Byte *p = (Byte *)_data;
for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize)
*(Byte **)(void *)p = (p + _blockSize);
*(Byte **)(void *)p = NULL;
_headFree = _data;
return true;
}
void CMemBlockManager::FreeSpace()
{
::MidFree(_data);
_data = NULL;
_headFree= NULL;
}
void *CMemBlockManager::AllocateBlock()
{
void *p = _headFree;
if (p)
_headFree = *(void **)p;
return p;
}
void CMemBlockManager::FreeBlock(void *p)
{
if (!p)
return;
*(void **)p = _headFree;
_headFree = p;
}
// #include <stdio.h>
HRESULT CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks)
{
if (numNoLockBlocks > numBlocks)
return E_INVALIDARG;
const size_t numLockBlocks = numBlocks - numNoLockBlocks;
UInt32 maxCount = (UInt32)numLockBlocks;
if (maxCount != numLockBlocks)
return E_OUTOFMEMORY;
if (!CMemBlockManager::AllocateSpace_bool(numBlocks))
return E_OUTOFMEMORY;
// we need (maxCount = 1), if we want to create non-use empty Semaphore
if (maxCount == 0)
maxCount = 1;
// printf("\n Synchro.Create() \n");
WRes wres;
#ifndef _WIN32
Semaphore.Close();
wres = Synchro.Create();
if (wres != 0)
return HRESULT_FROM_WIN32(wres);
wres = Semaphore.Create(&Synchro, (UInt32)numLockBlocks, maxCount);
#else
wres = Semaphore.OptCreateInit((UInt32)numLockBlocks, maxCount);
#endif
return HRESULT_FROM_WIN32(wres);
}
HRESULT CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks)
{
// desiredNumberOfBlocks = 0; // for debug
if (numNoLockBlocks > desiredNumberOfBlocks)
return E_INVALIDARG;
for (;;)
{
// if (desiredNumberOfBlocks == 0) return E_OUTOFMEMORY;
const HRESULT hres = AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks);
if (hres != E_OUTOFMEMORY)
return hres;
if (desiredNumberOfBlocks == numNoLockBlocks)
return E_OUTOFMEMORY;
desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1);
}
}
void CMemBlockManagerMt::FreeSpace()
{
Semaphore.Close();
CMemBlockManager::FreeSpace();
}
void *CMemBlockManagerMt::AllocateBlock()
{
// Semaphore.Lock();
NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
return CMemBlockManager::AllocateBlock();
}
void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode)
{
if (!p)
return;
{
NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
CMemBlockManager::FreeBlock(p);
}
if (lockMode)
Semaphore.Release();
}
void CMemBlocks::Free(CMemBlockManagerMt *manager)
{
while (Blocks.Size() > 0)
{
manager->FreeBlock(Blocks.Back());
Blocks.DeleteBack();
}
TotalSize = 0;
}
void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager)
{
Free(manager);
Blocks.ClearAndFree();
}
HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const
{
UInt64 totalSize = TotalSize;
for (unsigned blockIndex = 0; totalSize > 0; blockIndex++)
{
size_t curSize = blockSize;
if (curSize > totalSize)
curSize = (size_t)totalSize;
if (blockIndex >= Blocks.Size())
return E_FAIL;
RINOK(WriteStream(outStream, Blocks[blockIndex], curSize))
totalSize -= curSize;
}
return S_OK;
}
void CMemLockBlocks::FreeBlock(unsigned index, CMemBlockManagerMt *memManager)
{
memManager->FreeBlock(Blocks[index], LockMode);
Blocks[index] = NULL;
}
void CMemLockBlocks::Free(CMemBlockManagerMt *memManager)
{
while (Blocks.Size() > 0)
{
FreeBlock(Blocks.Size() - 1, memManager);
Blocks.DeleteBack();
}
TotalSize = 0;
}
/*
HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager)
{
if (LockMode)
{
if (Blocks.Size() > 0)
{
RINOK(memManager->ReleaseLockedBlocks(Blocks.Size()));
}
LockMode = false;
}
return 0;
}
*/
void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager)
{
blocks.Free(memManager);
blocks.LockMode = LockMode;
UInt64 totalSize = 0;
const size_t blockSize = memManager->GetBlockSize();
FOR_VECTOR (i, Blocks)
{
if (totalSize < TotalSize)
blocks.Blocks.Add(Blocks[i]);
else
FreeBlock(i, memManager);
Blocks[i] = NULL;
totalSize += blockSize;
}
blocks.TotalSize = TotalSize;
Free(memManager);
}
@@ -0,0 +1,72 @@
// MemBlocks.h
#ifndef ZIP7_INC_MEM_BLOCKS_H
#define ZIP7_INC_MEM_BLOCKS_H
#include "../../Common/MyVector.h"
#include "../../Windows/Synchronization.h"
#include "../IStream.h"
class CMemBlockManager
{
void *_data;
size_t _blockSize;
void *_headFree;
public:
CMemBlockManager(size_t blockSize = (1 << 20)): _data(NULL), _blockSize(blockSize), _headFree(NULL) {}
~CMemBlockManager() { FreeSpace(); }
bool AllocateSpace_bool(size_t numBlocks);
void FreeSpace();
size_t GetBlockSize() const { return _blockSize; }
void *AllocateBlock();
void FreeBlock(void *p);
};
class CMemBlockManagerMt: public CMemBlockManager
{
NWindows::NSynchronization::CCriticalSection _criticalSection;
public:
SYNC_OBJ_DECL(Synchro)
NWindows::NSynchronization::CSemaphore_WFMO Semaphore;
CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {}
~CMemBlockManagerMt() { FreeSpace(); }
HRESULT AllocateSpace(size_t numBlocks, size_t numNoLockBlocks);
HRESULT AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0);
void FreeSpace();
void *AllocateBlock();
void FreeBlock(void *p, bool lockMode = true);
// WRes ReleaseLockedBlocks_WRes(unsigned number) { return Semaphore.Release(number); }
};
class CMemBlocks
{
void Free(CMemBlockManagerMt *manager);
public:
CRecordVector<void *> Blocks;
UInt64 TotalSize;
CMemBlocks(): TotalSize(0) {}
void FreeOpt(CMemBlockManagerMt *manager);
HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const;
};
struct CMemLockBlocks: public CMemBlocks
{
bool LockMode;
CMemLockBlocks(): LockMode(true) {}
void Free(CMemBlockManagerMt *memManager);
void FreeBlock(unsigned index, CMemBlockManagerMt *memManager);
// HRESULT SwitchToNoLockMode(CMemBlockManagerMt *memManager);
void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager);
};
#endif
@@ -0,0 +1,3 @@
// MethodId.cpp
#include "StdAfx.h"
+10
View File
@@ -0,0 +1,10 @@
// MethodId.h
#ifndef ZIP7_INC_7Z_METHOD_ID_H
#define ZIP7_INC_7Z_METHOD_ID_H
#include "../../Common/MyTypes.h"
typedef UInt64 CMethodId;
#endif
@@ -0,0 +1,765 @@
// MethodProps.cpp
#include "StdAfx.h"
#include "../../Common/StringToInt.h"
#include "MethodProps.h"
using namespace NWindows;
UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents)
{
// if (percents == 0) return 0;
const UInt64 q = percents / 100;
const UInt32 r = (UInt32)(percents % 100);
UInt64 res = 0;
if (q != 0)
{
if (val > (UInt64)(Int64)-1 / q)
return (UInt64)(Int64)-1;
res = val * q;
}
if (r != 0)
{
UInt64 v2;
if (val <= (UInt64)(Int64)-1 / r)
v2 = val * r / 100;
else
v2 = val / 100 * r;
res += v2;
if (res < v2)
return (UInt64)(Int64)-1;
}
return res;
}
bool StringToBool(const wchar_t *s, bool &res)
{
if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON"))
{
res = true;
return true;
}
if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF"))
{
res = false;
return true;
}
return false;
}
HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest)
{
switch (prop.vt)
{
case VT_EMPTY: dest = true; return S_OK;
case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK;
case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG;
default: break;
}
return E_INVALIDARG;
}
unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number)
{
const wchar_t *start = srcString;
const wchar_t *end;
number = ConvertStringToUInt32(start, &end);
return (unsigned)(end - start);
}
static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number)
{
const wchar_t *start = srcString;
const wchar_t *end;
number = ConvertStringToUInt64(start, &end);
return (unsigned)(end - start);
}
HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
{
// =VT_UI4
// =VT_EMPTY : it doesn't change (resValue), and returns S_OK
// {stringUInt32}=VT_EMPTY
if (prop.vt == VT_UI4)
{
if (!name.IsEmpty())
return E_INVALIDARG;
resValue = prop.ulVal;
return S_OK;
}
if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
if (name.IsEmpty())
return S_OK;
UInt32 v;
if (ParseStringToUInt32(name, v) != name.Len())
return E_INVALIDARG;
resValue = v;
return S_OK;
}
HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force)
{
force = false;
UString s;
if (name.IsEmpty())
{
if (prop.vt == VT_UI4)
{
numThreads = prop.ulVal;
force = true;
return S_OK;
}
bool val;
HRESULT res = PROPVARIANT_to_bool(prop, val);
if (res == S_OK)
{
if (!val)
{
numThreads = 1;
force = true;
}
// force = true; for debug
// "(VT_BOOL = VARIANT_TRUE)" set "force = false" and doesn't change numThreads
return S_OK;
}
if (prop.vt != VT_BSTR)
return res;
s.SetFromBstr(prop.bstrVal);
if (s.IsEmpty())
return E_INVALIDARG;
}
else
{
if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
s = name;
}
s.MakeLower_Ascii();
const wchar_t *start = s;
UInt32 v = numThreads;
/* we force up, if threads number specified
only `d` will force it down */
bool force_loc = true;
for (;;)
{
const wchar_t c = *start;
if (!c)
break;
if (c == 'd')
{
force_loc = false; // force down
start++;
continue;
}
if (c == 'u')
{
force_loc = true; // force up
start++;
continue;
}
bool isPercent = false;
if (c == 'p')
{
isPercent = true;
start++;
}
const wchar_t *end;
v = ConvertStringToUInt32(start, &end);
if (end == start)
return E_INVALIDARG;
if (isPercent)
v = numThreads * v / 100;
start = end;
}
numThreads = v;
force = force_loc;
return S_OK;
}
static HRESULT SetLogSizeProp(UInt64 number, NCOM::CPropVariant &destProp)
{
if (number >= 64)
return E_INVALIDARG;
UInt32 val32;
if (number < 32)
val32 = (UInt32)1 << (unsigned)number;
/*
else if (number == 32 && reduce_4GB_to_32bits)
val32 = (UInt32)(Int32)-1;
*/
else
{
destProp = (UInt64)((UInt64)1 << (unsigned)number);
return S_OK;
}
destProp = (UInt32)val32;
return S_OK;
}
static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp)
{
/* if (reduce_4GB_to_32bits) we can reduce (4 GiB) property to (4 GiB - 1).
to fit the value to UInt32 for clients that do not support 64-bit values */
const wchar_t *end;
const UInt64 number = ConvertStringToUInt64(s, &end);
const unsigned numDigits = (unsigned)(end - s.Ptr());
if (numDigits == 0 || s.Len() > numDigits + 1)
return E_INVALIDARG;
if (s.Len() == numDigits)
return SetLogSizeProp(number, destProp);
unsigned numBits;
switch (MyCharLower_Ascii(s[numDigits]))
{
case 'b': numBits = 0; break;
case 'k': numBits = 10; break;
case 'm': numBits = 20; break;
case 'g': numBits = 30; break;
default: return E_INVALIDARG;
}
const UInt64 range4g = ((UInt64)1 << (32 - numBits));
if (number < range4g)
destProp = (UInt32)((UInt32)number << numBits);
/*
else if (number == range4g && reduce_4GB_to_32bits)
destProp = (UInt32)(Int32)-1;
*/
else if (numBits == 0)
destProp = (UInt64)number;
else if (number >= ((UInt64)1 << (64 - numBits)))
return E_INVALIDARG;
else
destProp = (UInt64)((UInt64)number << numBits);
return S_OK;
}
static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp)
{
if (prop.vt == VT_UI4)
return SetLogSizeProp(prop.ulVal, destProp);
if (prop.vt == VT_BSTR)
{
UString s;
s = prop.bstrVal;
return StringToDictSize(s, destProp);
}
return E_INVALIDARG;
}
void CProps::AddProp32(PROPID propid, UInt32 val)
{
CProp &prop = Props.AddNew();
prop.IsOptional = true;
prop.Id = propid;
prop.Value = (UInt32)val;
}
void CProps::AddPropBool(PROPID propid, bool val)
{
CProp &prop = Props.AddNew();
prop.IsOptional = true;
prop.Id = propid;
prop.Value = val;
}
class CCoderProps
{
PROPID *_propIDs;
NCOM::CPropVariant *_props;
unsigned _numProps;
unsigned _numPropsMax;
public:
CCoderProps(unsigned numPropsMax):
_propIDs(NULL),
_props(NULL),
_numProps(0),
_numPropsMax(numPropsMax)
{
_propIDs = new PROPID[numPropsMax];
_props = new NCOM::CPropVariant[numPropsMax];
}
~CCoderProps()
{
delete []_propIDs;
delete []_props;
}
void AddProp(const CProp &prop);
HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties)
{
return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps);
}
};
void CCoderProps::AddProp(const CProp &prop)
{
if (_numProps >= _numPropsMax)
throw 1;
_propIDs[_numProps] = prop.Id;
_props[_numProps] = prop.Value;
_numProps++;
}
HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
{
return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL, NULL, NULL);
}
HRESULT CProps::SetCoderProps_DSReduce_Aff(
ICompressSetCoderProperties *scp,
const UInt64 *dataSizeReduce,
const UInt64 *affinity,
const UInt32 *affinityGroup,
const UInt64 *affinityInGroup) const
{
CCoderProps coderProps(Props.Size()
+ (dataSizeReduce ? 1 : 0)
+ (affinity ? 1 : 0)
+ (affinityGroup ? 1 : 0)
+ (affinityInGroup ? 1 : 0)
);
FOR_VECTOR (i, Props)
coderProps.AddProp(Props[i]);
if (dataSizeReduce)
{
CProp prop;
prop.Id = NCoderPropID::kReduceSize;
prop.Value = *dataSizeReduce;
coderProps.AddProp(prop);
}
if (affinity)
{
CProp prop;
prop.Id = NCoderPropID::kAffinity;
prop.Value = *affinity;
coderProps.AddProp(prop);
}
if (affinityGroup)
{
CProp prop;
prop.Id = NCoderPropID::kThreadGroup;
prop.Value = *affinityGroup;
coderProps.AddProp(prop);
}
if (affinityInGroup)
{
CProp prop;
prop.Id = NCoderPropID::kAffinityInGroup;
prop.Value = *affinityInGroup;
coderProps.AddProp(prop);
}
return coderProps.SetProps(scp);
}
int CMethodProps::FindProp(PROPID id) const
{
for (unsigned i = Props.Size(); i != 0;)
if (Props[--i].Id == id)
return (int)i;
return -1;
}
unsigned CMethodProps::GetLevel() const
{
int i = FindProp(NCoderPropID::kLevel);
if (i < 0)
return 5;
if (Props[(unsigned)i].Value.vt != VT_UI4)
return 9;
UInt32 level = Props[(unsigned)i].Value.ulVal;
return level > 9 ? 9 : (unsigned)level;
}
struct CNameToPropID
{
VARTYPE VarType;
const char *Name;
};
// the following are related to NCoderPropID::EEnum values
// NCoderPropID::k_NUM_DEFINED
static const CNameToPropID g_NameToPropID[] =
{
{ VT_UI4, "" },
{ VT_UI4, "d" },
{ VT_UI4, "mem" },
{ VT_UI4, "o" },
{ VT_UI8, "c" },
{ VT_UI4, "pb" },
{ VT_UI4, "lc" },
{ VT_UI4, "lp" },
{ VT_UI4, "fb" },
{ VT_BSTR, "mf" },
{ VT_UI4, "mc" },
{ VT_UI4, "pass" },
{ VT_UI4, "a" },
{ VT_UI4, "mt" },
{ VT_BOOL, "eos" },
{ VT_UI4, "x" },
{ VT_UI8, "reduce" },
{ VT_UI8, "expect" },
{ VT_UI8, "cc" }, // "cc" in v23, "b" in v22.01
{ VT_UI4, "check" },
{ VT_BSTR, "filter" },
{ VT_UI8, "memuse" },
{ VT_UI8, "aff" },
{ VT_UI4, "offset" },
{ VT_UI4, "zhb" }
/*
, { VT_UI4, "tgn" }, // kNumThreadGroups
, { VT_UI4, "tgi" }, // kThreadGroup
, { VT_UI8, "tga" }, // kAffinityInGroup
*/
/*
,
// { VT_UI4, "zhc" },
// { VT_UI4, "zhd" },
// { VT_UI4, "zcb" },
{ VT_UI4, "dc" },
{ VT_UI4, "zx" },
{ VT_UI4, "zf" },
{ VT_UI4, "zmml" },
{ VT_UI4, "zov" },
{ VT_BOOL, "zmfr" },
{ VT_BOOL, "zle" }, // long enable
// { VT_UI4, "zldb" },
{ VT_UI4, "zld" },
{ VT_UI4, "zlhb" },
{ VT_UI4, "zlmml" },
{ VT_UI4, "zlbb" },
{ VT_UI4, "zlhrb" },
{ VT_BOOL, "zwus" },
{ VT_BOOL, "zshp" },
{ VT_BOOL, "zshs" },
{ VT_BOOL, "zshe" },
{ VT_BOOL, "zshg" },
{ VT_UI4, "zpsm" }
*/
// { VT_UI4, "mcb" }, // mc log version
// { VT_UI4, "ztlen" }, // fb ?
};
/*
#if defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 200410L) || (defined(_MSC_VER) && _MSC_VER >= 1600)
#if (defined(__cplusplus) && __cplusplus < 201103L) \
&& defined(__clang__) && __clang_major__ >= 4
#pragma GCC diagnostic ignored "-Wc11-extensions"
#endif
static_assert(Z7_ARRAY_SIZE(g_NameToPropID) == NCoderPropID::k_NUM_DEFINED,
"g_NameToPropID doesn't match NCoderPropID enum");
#endif
*/
static int FindPropIdExact(const UString &name)
{
for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NameToPropID); i++)
if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))
return (int)i;
return -1;
}
static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
{
if (varType == srcProp.vt)
{
destProp = srcProp;
return true;
}
if (varType == VT_UI8 && srcProp.vt == VT_UI4)
{
destProp = (UInt64)srcProp.ulVal;
return true;
}
if (varType == VT_BOOL)
{
bool res;
if (PROPVARIANT_to_bool(srcProp, res) != S_OK)
return false;
destProp = res;
return true;
}
if (srcProp.vt == VT_EMPTY)
{
destProp = srcProp;
return true;
}
return false;
}
static void SplitParams(const UString &srcString, UStringVector &subStrings)
{
subStrings.Clear();
UString s;
unsigned len = srcString.Len();
if (len == 0)
return;
for (unsigned i = 0; i < len; i++)
{
wchar_t c = srcString[i];
if (c == L':')
{
subStrings.Add(s);
s.Empty();
}
else
s += c;
}
subStrings.Add(s);
}
static void SplitParam(const UString &param, UString &name, UString &value)
{
int eqPos = param.Find(L'=');
if (eqPos >= 0)
{
name.SetFrom(param, (unsigned)eqPos);
value = param.Ptr((unsigned)(eqPos + 1));
return;
}
unsigned i;
for (i = 0; i < param.Len(); i++)
{
wchar_t c = param[i];
if (c >= L'0' && c <= L'9')
break;
}
name.SetFrom(param, i);
value = param.Ptr(i);
}
static bool IsLogSizeProp(PROPID propid)
{
switch (propid)
{
case NCoderPropID::kDictionarySize:
case NCoderPropID::kUsedMemorySize:
case NCoderPropID::kBlockSize:
case NCoderPropID::kBlockSize2:
/*
case NCoderPropID::kChainSize:
case NCoderPropID::kLdmWindowSize:
*/
// case NCoderPropID::kReduceSize:
return true;
default: break;
}
return false;
}
HRESULT CMethodProps::SetParam(const UString &name, const UString &value)
{
int index = FindPropIdExact(name);
if (index < 0)
{
// 'b' was used as NCoderPropID::kBlockSize2 before v23
if (!name.IsEqualTo_Ascii_NoCase("b") || value.Find(L':') >= 0)
return E_INVALIDARG;
index = NCoderPropID::kBlockSize2;
}
const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
CProp prop;
prop.Id = (unsigned)index;
if (IsLogSizeProp(prop.Id))
{
RINOK(StringToDictSize(value, prop.Value))
}
else
{
NCOM::CPropVariant propValue;
if (nameToPropID.VarType == VT_BSTR)
propValue = value;
else if (nameToPropID.VarType == VT_BOOL)
{
bool res;
if (!StringToBool(value, res))
return E_INVALIDARG;
propValue = res;
}
else if (!value.IsEmpty())
{
if (nameToPropID.VarType == VT_UI4)
{
UInt32 number;
if (ParseStringToUInt32(value, number) == value.Len())
propValue = number;
else
propValue = value;
}
else if (nameToPropID.VarType == VT_UI8)
{
UInt64 number;
if (ParseStringToUInt64(value, number) == value.Len())
propValue = number;
else
propValue = value;
}
else
propValue = value;
}
if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
return E_INVALIDARG;
}
Props.Add(prop);
return S_OK;
}
HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
{
UStringVector params;
SplitParams(srcString, params);
FOR_VECTOR (i, params)
{
const UString &param = params[i];
UString name, value;
SplitParam(param, name, value);
RINOK(SetParam(name, value))
}
return S_OK;
}
HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
{
if (realName.Len() == 0)
{
// [empty]=method
return E_INVALIDARG;
}
if (value.vt == VT_EMPTY)
{
// {realName}=[empty]
UString name, valueStr;
SplitParam(realName, name, valueStr);
return SetParam(name, valueStr);
}
// {realName}=value
const int index = FindPropIdExact(realName);
if (index < 0)
return E_INVALIDARG;
const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
CProp prop;
prop.Id = (unsigned)index;
if (IsLogSizeProp(prop.Id))
{
RINOK(PROPVARIANT_to_DictSize(value, prop.Value))
}
else
{
if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
return E_INVALIDARG;
}
Props.Add(prop);
return S_OK;
}
static UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads)
{
UInt32 hs = dict - 1;
hs |= (hs >> 1);
hs |= (hs >> 2);
hs |= (hs >> 4);
hs |= (hs >> 8);
hs >>= 1;
if (hs >= (1 << 24))
hs >>= 1;
hs |= (1 << 16) - 1;
// if (numHashBytes >= 5)
if (!isBt)
hs |= (256 << 10) - 1;
hs++;
UInt64 size1 = (UInt64)hs * 4;
size1 += (UInt64)dict * 4;
if (isBt)
size1 += (UInt64)dict * 4;
size1 += (2 << 20);
if (numThreads > 1 && isBt)
size1 += (2 << 20) + (4 << 20);
return size1;
}
static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28;
UInt64 CMethodProps::Get_Lzma_MemUsage(bool addSlidingWindowSize) const
{
const UInt64 dicSize = Get_Lzma_DicSize();
const bool isBt = Get_Lzma_MatchFinder_IsBt();
const UInt32 dict32 = (dicSize >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dicSize);
const UInt32 numThreads = Get_Lzma_NumThreads();
UInt64 size = GetMemoryUsage_LZMA(dict32, isBt, numThreads);
if (addSlidingWindowSize)
{
const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16);
UInt64 blockSize = (UInt64)dict32 + (1 << 16)
+ (numThreads > 1 ? (1 << 20) : 0);
blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2));
if (blockSize >= kBlockSizeMax)
blockSize = kBlockSizeMax;
size += blockSize;
}
return size;
}
HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
{
MethodName.Empty();
int splitPos = s.Find(L':');
{
UString temp = s;
if (splitPos >= 0)
temp.DeleteFrom((unsigned)splitPos);
if (!temp.IsAscii())
return E_INVALIDARG;
MethodName.SetFromWStr_if_Ascii(temp);
}
if (splitPos < 0)
return S_OK;
PropsString = s.Ptr((unsigned)(splitPos + 1));
return ParseParamsFromString(PropsString);
}
HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
{
if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m"))
return ParseParamsFromPROPVARIANT(realName, value);
// -m{N}=method
if (value.vt != VT_BSTR)
return E_INVALIDARG;
UString s;
s = value.bstrVal;
return ParseMethodFromString(s);
}
@@ -0,0 +1,349 @@
// MethodProps.h
#ifndef ZIP7_INC_7Z_METHOD_PROPS_H
#define ZIP7_INC_7Z_METHOD_PROPS_H
#include "../../Common/MyString.h"
#include "../../Common/Defs.h"
#include "../../Windows/Defs.h"
#include "../../Windows/PropVariant.h"
#include "../ICoder.h"
// UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads);
inline UInt64 Calc_From_Val_Percents_Less100(UInt64 val, UInt64 percents)
{
if (percents == 0)
return 0;
if (val <= (UInt64)(Int64)-1 / percents)
return val * percents / 100;
return val / 100 * percents;
}
UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents);
bool StringToBool(const wchar_t *s, bool &res);
HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest);
unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number);
/*
if (name.IsEmpty() && prop.vt == VT_EMPTY), it doesn't change (resValue) and returns S_OK.
So you must set (resValue) for default value before calling */
HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
/* input: (numThreads = the_number_of_processors) */
HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force);
inline HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 numCPUs, UInt32 &numThreads)
{
bool forced = false;
numThreads = numCPUs;
return ParseMtProp2(name, prop, numThreads, forced);
}
struct CProp
{
PROPID Id;
bool IsOptional;
NWindows::NCOM::CPropVariant Value;
CProp(): IsOptional(false) {}
};
struct CProps
{
CObjectVector<CProp> Props;
void Clear() { Props.Clear(); }
bool AreThereNonOptionalProps() const
{
FOR_VECTOR (i, Props)
if (!Props[i].IsOptional)
return true;
return false;
}
void AddProp32(PROPID propid, UInt32 val);
void AddPropBool(PROPID propid, bool val);
void AddProp_Ascii(PROPID propid, const char *s)
{
CProp &prop = Props.AddNew();
prop.IsOptional = true;
prop.Id = propid;
prop.Value = s;
}
HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const;
HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp,
const UInt64 *dataSizeReduce,
const UInt64 *affinity,
const UInt32 *affinityGroup,
const UInt64 *affinityInGroup) const;
};
class CMethodProps: public CProps
{
HRESULT SetParam(const UString &name, const UString &value);
public:
unsigned GetLevel() const;
int Get_NumThreads() const
{
const int i = FindProp(NCoderPropID::kNumThreads);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_UI4)
return (int)val.ulVal;
}
return -1;
}
bool Get_DicSize(UInt64 &res) const
{
res = 0;
const int i = FindProp(NCoderPropID::kDictionarySize);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_UI4)
{
res = val.ulVal;
return true;
}
if (val.vt == VT_UI8)
{
res = val.uhVal.QuadPart;
return true;
}
}
return false;
}
int FindProp(PROPID id) const;
UInt32 Get_Lzma_Algo() const
{
const int i = FindProp(NCoderPropID::kAlgorithm);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_UI4)
return val.ulVal;
}
return GetLevel() >= 5 ? 1 : 0;
}
UInt64 Get_Lzma_DicSize() const
{
UInt64 v;
if (Get_DicSize(v))
return v;
const unsigned level = GetLevel();
const UInt32 dictSize = level <= 4 ?
(UInt32)1 << (level * 2 + 16) :
level <= sizeof(size_t) / 2 + 4 ?
(UInt32)1 << (level + 20) :
(UInt32)1 << (sizeof(size_t) / 2 + 24);
return dictSize;
}
bool Get_Lzma_MatchFinder_IsBt() const
{
const int i = FindProp(NCoderPropID::kMatchFinder);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_BSTR)
return ((val.bstrVal[0] | 0x20) != 'h'); // check for "hc"
}
return GetLevel() >= 5;
}
bool Get_Lzma_Eos() const
{
const int i = FindProp(NCoderPropID::kEndMarker);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_BOOL)
return VARIANT_BOOLToBool(val.boolVal);
}
return false;
}
bool Are_Lzma_Model_Props_Defined() const
{
if (FindProp(NCoderPropID::kPosStateBits) >= 0) return true;
if (FindProp(NCoderPropID::kLitContextBits) >= 0) return true;
if (FindProp(NCoderPropID::kLitPosBits) >= 0) return true;
return false;
}
UInt32 Get_Lzma_NumThreads() const
{
if (Get_Lzma_Algo() == 0)
return 1;
int numThreads = Get_NumThreads();
if (numThreads >= 0)
return numThreads < 2 ? 1 : 2;
return 2;
}
UInt64 Get_Lzma_MemUsage(bool addSlidingWindowSize) const;
/* returns -1, if numThreads is unknown */
int Get_Xz_NumThreads(UInt32 &lzmaThreads) const
{
lzmaThreads = 1;
int numThreads = Get_NumThreads();
if (numThreads >= 0 && numThreads <= 1)
return 1;
if (Get_Lzma_Algo() != 0)
lzmaThreads = 2;
return numThreads;
}
UInt64 GetProp_BlockSize(PROPID id) const
{
const int i = FindProp(id);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_UI4) { return val.ulVal; }
if (val.vt == VT_UI8) { return val.uhVal.QuadPart; }
}
return 0;
}
UInt64 Get_Xz_BlockSize() const
{
{
UInt64 blockSize1 = GetProp_BlockSize(NCoderPropID::kBlockSize);
UInt64 blockSize2 = GetProp_BlockSize(NCoderPropID::kBlockSize2);
UInt64 minSize = MyMin(blockSize1, blockSize2);
if (minSize != 0)
return minSize;
UInt64 maxSize = MyMax(blockSize1, blockSize2);
if (maxSize != 0)
return maxSize;
}
const UInt32 kMinSize = (UInt32)1 << 20;
const UInt32 kMaxSize = (UInt32)1 << 28;
const UInt64 dictSize = Get_Lzma_DicSize();
/* lzma2 code uses fake 4 GiB to calculate ChunkSize. So we do same */
UInt64 blockSize = (UInt64)dictSize << 2;
if (blockSize < kMinSize) blockSize = kMinSize;
if (blockSize > kMaxSize) blockSize = kMaxSize;
if (blockSize < dictSize) blockSize = dictSize;
blockSize += (kMinSize - 1);
blockSize &= ~(UInt64)(kMinSize - 1);
return blockSize;
}
UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const
{
fixedNumber = false;
int numThreads = Get_NumThreads();
if (numThreads >= 0)
{
fixedNumber = true;
if (numThreads < 1) return 1;
const unsigned kNumBZip2ThreadsMax = 64;
if ((unsigned)numThreads > kNumBZip2ThreadsMax) return kNumBZip2ThreadsMax;
return (unsigned)numThreads;
}
return 1;
}
UInt32 Get_BZip2_BlockSize() const
{
const int i = FindProp(NCoderPropID::kDictionarySize);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_UI4)
{
UInt32 blockSize = val.ulVal;
const UInt32 kDicSizeMin = 100000;
const UInt32 kDicSizeMax = 900000;
if (blockSize < kDicSizeMin) blockSize = kDicSizeMin;
if (blockSize > kDicSizeMax) blockSize = kDicSizeMax;
return blockSize;
}
}
const unsigned level = GetLevel();
return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1));
}
UInt64 Get_Ppmd_MemSize() const
{
const int i = FindProp(NCoderPropID::kUsedMemorySize);
if (i >= 0)
{
const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
if (val.vt == VT_UI4)
return val.ulVal;
if (val.vt == VT_UI8)
return val.uhVal.QuadPart;
}
const unsigned level = GetLevel();
const UInt32 mem = (UInt32)1 << (level + 19);
return mem;
}
void AddProp_Level(UInt32 level)
{
AddProp32(NCoderPropID::kLevel, level);
}
void AddProp_NumThreads(UInt32 numThreads)
{
AddProp32(NCoderPropID::kNumThreads, numThreads);
}
void AddProp_EndMarker_if_NotFound(bool eos)
{
if (FindProp(NCoderPropID::kEndMarker) < 0)
AddPropBool(NCoderPropID::kEndMarker, eos);
}
void AddProp_BlockSize2(UInt64 blockSize2)
{
if (FindProp(NCoderPropID::kBlockSize2) < 0)
{
CProp &prop = Props.AddNew();
prop.IsOptional = true;
prop.Id = NCoderPropID::kBlockSize2;
prop.Value = blockSize2;
}
}
HRESULT ParseParamsFromString(const UString &srcString);
HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
};
class COneMethodInfo: public CMethodProps
{
public:
AString MethodName;
UString PropsString;
void Clear()
{
CMethodProps::Clear();
MethodName.Empty();
PropsString.Empty();
}
bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); }
HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
HRESULT ParseMethodFromString(const UString &s);
};
#endif
@@ -0,0 +1,855 @@
// MultiOutStream.cpp
#include "StdAfx.h"
// #define DEBUG_VOLUMES
#ifdef DEBUG_VOLUMES
#include <stdio.h>
#define PRF(x) x;
#else
#define PRF(x)
#endif
#include "../../Common/ComTry.h"
#include "../../Windows/FileDir.h"
#include "../../Windows/FileFind.h"
#include "../../Windows/System.h"
#include "MultiOutStream.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
static const unsigned k_NumVols_MAX = k_VectorSizeMax - 1;
// 2; // for debug
/*
#define UPDATE_HRES(hres, x) \
{ const HRESULT res2 = (x); if (hres == SZ_OK) hres = res2; }
*/
HRESULT CMultiOutStream::Destruct()
{
COM_TRY_BEGIN
HRESULT hres = S_OK;
HRESULT hres3 = S_OK;
while (!Streams.IsEmpty())
{
try
{
HRESULT hres2;
if (NeedDelete)
{
/* we could call OptReOpen_and_SetSize() to test that we try to delete correct file,
but we cannot guarantee that (RealSize) will be correct after Write() or another failures.
And we still want to delete files even for such cases.
So we don't check for OptReOpen_and_SetSize() here: */
// if (OptReOpen_and_SetSize(Streams.Size() - 1, 0) == S_OK)
hres2 = CloseStream_and_DeleteFile(Streams.Size() - 1);
}
else
{
hres2 = CloseStream(Streams.Size() - 1);
}
if (hres == S_OK)
hres = hres2;
}
catch(...)
{
hres3 = E_OUTOFMEMORY;
}
{
/* Stream was released in CloseStream_*() above already, and it was removed from linked list
it's some unexpected case, if Stream is still attached here.
So the following code is optional: */
CVolStream &s = Streams.Back();
if (s.Stream)
{
if (hres3 == S_OK)
hres3 = E_FAIL;
s.Stream.Detach();
/* it will be not failure, even if we call RemoveFromLinkedList()
twice for same CVolStream in this Destruct() function */
RemoveFromLinkedList(Streams.Size() - 1);
}
}
Streams.DeleteBack();
// Delete_LastStream_Records();
}
if (hres == S_OK)
hres = hres3;
if (hres == S_OK && NumListItems != 0)
hres = E_FAIL;
return hres;
COM_TRY_END
}
CMultiOutStream::~CMultiOutStream()
{
// we try to avoid exception in destructors
Destruct();
}
void CMultiOutStream::Init(const CRecordVector<UInt64> &sizes)
{
Streams.Clear();
InitLinkedList();
Sizes = sizes;
NeedDelete = true;
MTime_Defined = false;
FinalVol_WasReopen = false;
NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
_streamIndex = 0;
_offsetPos = 0;
_absPos = 0;
_length = 0;
_absLimit = (UInt64)(Int64)-1;
_restrict_Begin = 0;
_restrict_End = (UInt64)(Int64)-1;
_restrict_Global = 0;
UInt64 sum = 0;
unsigned i = 0;
for (i = 0; i < Sizes.Size(); i++)
{
if (i >= k_NumVols_MAX)
{
_absLimit = sum;
break;
}
const UInt64 size = Sizes[i];
const UInt64 next = sum + size;
if (next < sum)
break;
sum = next;
}
// if (Sizes.IsEmpty()) throw "no volume sizes";
const UInt64 size = Sizes.Back();
if (size == 0)
throw "zero size last volume";
if (i == Sizes.Size())
if ((_absLimit - sum) / size >= (k_NumVols_MAX - i))
_absLimit = sum + (k_NumVols_MAX - i) * size;
}
/* IsRestricted():
we must call only if volume is full (s.RealSize==VolSize) or finished.
the function doesn't use VolSize and it uses s.RealSize instead.
it returns true : if stream is restricted, and we can't close that stream
it returns false : if there is no restriction, and we can close that stream
Note: (RealSize == 0) (empty volume) on restriction bounds are supposed as non-restricted
*/
bool CMultiOutStream::IsRestricted(const CVolStream &s) const
{
if (s.Start < _restrict_Global)
return true;
if (_restrict_Begin == _restrict_End)
return false;
if (_restrict_Begin <= s.Start)
return _restrict_End > s.Start;
return _restrict_Begin < s.Start + s.RealSize;
}
/*
// this function check also _length and volSize
bool CMultiOutStream::IsRestricted_for_Close(unsigned index) const
{
const CVolStream &s = Streams[index];
if (_length <= s.Start) // we don't close streams after the end, because we still can write them later
return true;
// (_length > s.Start)
const UInt64 volSize = GetVolSize_for_Stream(index);
if (volSize == 0)
return IsRestricted_Empty(s);
if (_length - s.Start < volSize)
return true;
return IsRestricted(s);
}
*/
FString CMultiOutStream::GetFilePath(unsigned index)
{
FString name;
name.Add_UInt32((UInt32)(index + 1));
while (name.Len() < 3)
name.InsertAtFront(FTEXT('0'));
name.Insert(0, Prefix);
return name;
}
// we close stream, but we still keep item in Streams[] vector
HRESULT CMultiOutStream::CloseStream(unsigned index)
{
CVolStream &s = Streams[index];
if (s.Stream)
{
RINOK(s.StreamSpec->Close())
// the following two commands must be called together:
s.Stream.Release();
RemoveFromLinkedList(index);
}
return S_OK;
}
// we close stream and delete file, but we still keep item in Streams[] vector
HRESULT CMultiOutStream::CloseStream_and_DeleteFile(unsigned index)
{
PRF(printf("\n====== %u, CloseStream_AndDelete \n", index))
RINOK(CloseStream(index))
FString path = GetFilePath(index);
path += Streams[index].Postfix;
// we can checki that file exist
// if (NFind::DoesFileExist_Raw(path))
if (!DeleteFileAlways(path))
return GetLastError_noZero_HRESULT();
return S_OK;
}
HRESULT CMultiOutStream::CloseStream_and_FinalRename(unsigned index)
{
PRF(printf("\n====== %u, CloseStream_and_FinalRename \n", index))
CVolStream &s = Streams[index];
// HRESULT res = S_OK;
bool mtime_WasSet = false;
if (MTime_Defined && s.Stream)
{
if (s.StreamSpec->SetMTime(&MTime))
mtime_WasSet = true;
// else res = GetLastError_noZero_HRESULT();
}
RINOK(CloseStream(index))
if (s.Postfix.IsEmpty()) // if Postfix is empty, the path is already final
return S_OK;
const FString path = GetFilePath(index);
FString tempPath = path;
tempPath += s.Postfix;
if (MTime_Defined && !mtime_WasSet)
{
if (!SetDirTime(tempPath, NULL, NULL, &MTime))
{
// res = GetLastError_noZero_HRESULT();
}
}
if (!MyMoveFile(tempPath, path))
return GetLastError_noZero_HRESULT();
/* we clear CVolStream::Postfix. So we will not use Temp path
anymore for this stream, and we will work only with final path */
s.Postfix.Empty();
// we can ignore set_mtime error or we can return it
return S_OK;
// return res;
}
HRESULT CMultiOutStream::PrepareToOpenNew()
{
PRF(printf("PrepareToOpenNew NumListItems =%u, NumOpenFiles_AllowedMax = %u \n", NumListItems, NumOpenFiles_AllowedMax))
if (NumListItems < NumOpenFiles_AllowedMax)
return S_OK;
/* when we create zip archive: in most cases we need only starting
data of restricted region for rewriting zip's local header.
So here we close latest created volume (from Head), and we try to
keep oldest volumes that will be used for header rewriting later. */
const int index = Head;
if (index == -1)
return E_FAIL;
PRF(printf("\n== %u, PrepareToOpenNew::CloseStream, NumListItems =%u \n", index, NumListItems))
/* we don't expect non-restricted stream here in normal cases (if _restrict_Global was not changed).
if there was non-restricted stream, it should be closed before */
// if (!IsRestricted_for_Close(index)) return CloseStream_and_FinalRename(index);
return CloseStream((unsigned)index);
}
HRESULT CMultiOutStream::CreateNewStream(UInt64 newSize)
{
PRF(printf("\n== %u, CreateNewStream, size =%u \n", Streams.Size(), (unsigned)newSize))
if (Streams.Size() >= k_NumVols_MAX)
return E_INVALIDARG; // E_OUTOFMEMORY
RINOK(PrepareToOpenNew())
CVolStream s;
s.StreamSpec = new COutFileStream;
s.Stream = s.StreamSpec;
const FString path = GetFilePath(Streams.Size());
if (NFind::DoesFileExist_Raw(path))
return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
if (!CreateTempFile2(path, false, s.Postfix, &s.StreamSpec->File))
return GetLastError_noZero_HRESULT();
s.Start = GetGlobalOffset_for_NewStream();
s.Pos = 0;
s.RealSize = 0;
const unsigned index = Streams.Add(s);
InsertToLinkedList(index);
if (newSize != 0)
return s.SetSize2(newSize);
return S_OK;
}
HRESULT CMultiOutStream::CreateStreams_If_Required(unsigned streamIndex)
{
// UInt64 lastStreamSize = 0;
for (;;)
{
const unsigned numStreamsBefore = Streams.Size();
if (streamIndex < numStreamsBefore)
return S_OK;
UInt64 newSize;
if (streamIndex == numStreamsBefore)
{
// it's final volume that will be used for real writing.
/* SetSize(_offsetPos) is not required,
because the file Size will be set later by calling Seek() with Write() */
newSize = 0; // lastStreamSize;
}
else
{
// it's intermediate volume. So we need full volume size
newSize = GetVolSize_for_Stream(numStreamsBefore);
}
RINOK(CreateNewStream(newSize))
// optional check
if (numStreamsBefore + 1 != Streams.Size()) return E_FAIL;
if (streamIndex != numStreamsBefore)
{
// it's intermediate volume. So we can close it, if it's non-restricted
bool isRestricted;
{
const CVolStream &s = Streams[numStreamsBefore];
if (newSize == 0)
isRestricted = IsRestricted_Empty(s);
else
isRestricted = IsRestricted(s);
}
if (!isRestricted)
{
RINOK(CloseStream_and_FinalRename(numStreamsBefore))
}
}
}
}
HRESULT CMultiOutStream::ReOpenStream(unsigned streamIndex)
{
PRF(printf("\n====== %u, ReOpenStream \n", streamIndex))
RINOK(PrepareToOpenNew())
CVolStream &s = Streams[streamIndex];
FString path = GetFilePath(streamIndex);
path += s.Postfix;
s.StreamSpec = new COutFileStream;
s.Stream = s.StreamSpec;
s.Pos = 0;
HRESULT hres;
if (s.StreamSpec->Open_EXISTING(path))
{
if (s.Postfix.IsEmpty())
{
/* it's unexpected case that we open finished volume.
It can mean that the code for restriction is incorrect */
FinalVol_WasReopen = true;
}
UInt64 realSize = 0;
hres = s.StreamSpec->GetSize(&realSize);
if (hres == S_OK)
{
if (realSize == s.RealSize)
{
PRF(printf("\n ReOpenStream OK realSize = %u\n", (unsigned)realSize))
InsertToLinkedList(streamIndex);
return S_OK;
}
// file size was changed between Close() and ReOpen()
// we must release Stream to be consistent with linked list
hres = E_FAIL;
}
}
else
hres = GetLastError_noZero_HRESULT();
s.Stream.Release();
s.StreamSpec = NULL;
return hres;
}
/* Sets size of stream, if new size is not equal to old size (RealSize).
If stream was closed and size change is required, it reopens the stream. */
HRESULT CMultiOutStream::OptReOpen_and_SetSize(unsigned index, UInt64 size)
{
CVolStream &s = Streams[index];
if (size == s.RealSize)
return S_OK;
if (!s.Stream)
{
RINOK(ReOpenStream(index))
}
PRF(printf("\n== %u, OptReOpen_and_SetSize, size =%u RealSize = %u\n", index, (unsigned)size, (unsigned)s.RealSize))
// comment it to debug tail after data
return s.SetSize2(size);
}
/*
call Normalize_finalMode(false), if _length was changed.
for all streams starting after _length:
- it sets zero size
- it still keeps file open
Note: after _length reducing with CMultiOutStream::SetSize() we can
have very big number of empty streams at the end of Streams[] list.
And Normalize_finalMode() will runs all these empty streams of Streams[] vector.
So it can be ineffective, if we call Normalize_finalMode() many
times after big reducing of (_length).
call Normalize_finalMode(true) to set final presentations of all streams
for all streams starting after _length:
- it sets zero size
- it removes file
- it removes CVolStream object from Streams[] vector
Note: we don't remove zero sized first volume, if (_length == 0)
*/
HRESULT CMultiOutStream::Normalize_finalMode(bool finalMode)
{
PRF(printf("\n== Normalize_finalMode: _length =%d \n", (unsigned)_length))
unsigned i = Streams.Size();
UInt64 offset = 0;
/* At first we normalize (reduce or increase) the sizes of all existing
streams in Streams[] that can be affected by changed _length.
And we remove tailing zero-size streams, if (finalMode == true) */
while (i != 0)
{
offset = Streams[--i].Start; // it's last item in Streams[]
// we don't want to remove first volume
if (offset < _length || i == 0)
{
const UInt64 volSize = GetVolSize_for_Stream(i);
UInt64 size = _length - offset; // (size != 0) here
if (size > volSize)
size = volSize;
RINOK(OptReOpen_and_SetSize(i, size))
if (_length - offset <= volSize)
return S_OK;
// _length - offset > volSize
offset += volSize;
// _length > offset
break;
// UPDATE_HRES(res, OptReOpen_and_SetSize(i, size));
}
/* we Set Size of stream to zero even for (finalMode==true), although
that stream will be deleted in next commands */
// UPDATE_HRES(res, OptReOpen_and_SetSize(i, 0));
RINOK(OptReOpen_and_SetSize(i, 0))
if (finalMode)
{
RINOK(CloseStream_and_DeleteFile(i))
/* CVolStream::Stream was released above already, and it was
removed from linked list. So we don't need to update linked list
structure, when we delete last item in Streams[] */
Streams.DeleteBack();
// Delete_LastStream_Records();
}
}
/* now we create new zero-filled streams to cover all data up to _length */
if (_length == 0)
return S_OK;
// (offset) is start offset of next stream after existing Streams[]
for (;;)
{
// _length > offset
const UInt64 volSize = GetVolSize_for_Stream(Streams.Size());
UInt64 size = _length - offset; // (size != 0) here
if (size > volSize)
size = volSize;
RINOK(CreateNewStream(size))
if (_length - offset <= volSize)
return S_OK;
// _length - offset > volSize)
offset += volSize;
// _length > offset
}
}
HRESULT CMultiOutStream::FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes)
{
// at first we remove unused zero-sized streams after _length
HRESULT res = Normalize_finalMode(true);
numTotalVolumesRes = Streams.Size();
FOR_VECTOR (i, Streams)
{
const HRESULT res2 = CloseStream_and_FinalRename(i);
if (res == S_OK)
res = res2;
}
if (NumListItems != 0 && res == S_OK)
res = E_FAIL;
return res;
}
bool CMultiOutStream::SetMTime_Final(const CFiTime &mTime)
{
// we will set mtime only if new value differs from previous
if (!FinalVol_WasReopen && MTime_Defined && Compare_FiTime(&MTime, &mTime) == 0)
return true;
bool res = true;
FOR_VECTOR (i, Streams)
{
CVolStream &s = Streams[i];
if (s.Stream)
{
if (!s.StreamSpec->SetMTime(&mTime))
res = false;
}
else
{
if (!SetDirTime(GetFilePath(i), NULL, NULL, &mTime))
res = false;
}
}
return res;
}
Z7_COM7F_IMF(CMultiOutStream::SetSize(UInt64 newSize))
{
COM_TRY_BEGIN
if ((Int64)newSize < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
if (newSize > _absLimit)
{
/* big seek value was sent to SetSize() or to Seek()+Write().
It can mean one of two situations:
1) some incorrect code called it with big seek value.
2) volume size was small, and we have too big number of volumes
*/
/* in Windows SetEndOfFile() can return:
ERROR_NEGATIVE_SEEK: for >= (1 << 63)
ERROR_INVALID_PARAMETER: for > (16 TiB - 64 KiB)
ERROR_DISK_FULL: for <= (16 TiB - 64 KiB)
*/
// return E_FAIL;
// return E_OUTOFMEMORY;
return E_INVALIDARG;
}
if (newSize > _length)
{
// we don't expect such case. So we just define global restriction */
_restrict_Global = newSize;
}
else if (newSize < _restrict_Global)
_restrict_Global = newSize;
PRF(printf("\n== CMultiOutStream::SetSize, size =%u \n", (unsigned)newSize))
_length = newSize;
return Normalize_finalMode(false);
COM_TRY_END
}
Z7_COM7F_IMF(CMultiOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
COM_TRY_BEGIN
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
PRF(printf("\n -- CMultiOutStream::Write() : _absPos = %6u, size =%6u \n",
(unsigned)_absPos, (unsigned)size))
if (_absPos > _length)
{
// it create data only up to _absPos.
// but we still can need additional new streams, if _absPos at range of volume
RINOK(SetSize(_absPos))
}
while (size != 0)
{
UInt64 volSize;
{
if (_streamIndex < Sizes.Size() - 1)
{
volSize = Sizes[_streamIndex];
if (_offsetPos >= volSize)
{
_offsetPos -= volSize;
_streamIndex++;
continue;
}
}
else
{
volSize = Sizes[Sizes.Size() - 1];
if (_offsetPos >= volSize)
{
const UInt64 v = _offsetPos / volSize;
if (v >= ((UInt32)(Int32)-1) - _streamIndex)
return E_INVALIDARG;
// throw 202208;
_streamIndex += (unsigned)v;
_offsetPos -= (unsigned)v * volSize;
}
if (_streamIndex >= k_NumVols_MAX)
return E_INVALIDARG;
}
}
// (_offsetPos < volSize) here
/* we can need to create one or more streams here,
vol_size for some streams is allowed to be 0.
Also we close some new created streams, if they are non-restricted */
// file Size will be set later by calling Seek() with Write()
/* the case (_absPos > _length) was processed above with SetSize(_absPos),
so here it's expected. that we can create optional zero-size streams and then _streamIndex */
RINOK(CreateStreams_If_Required(_streamIndex))
CVolStream &s = Streams[_streamIndex];
PRF(printf("\n%d, == Write : Pos = %u, RealSize = %u size =%u \n",
_streamIndex, (unsigned)s.Pos, (unsigned)s.RealSize, size))
if (!s.Stream)
{
RINOK(ReOpenStream(_streamIndex))
}
if (_offsetPos != s.Pos)
{
RINOK(s.Stream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL))
s.Pos = _offsetPos;
}
UInt32 curSize = size;
{
const UInt64 rem = volSize - _offsetPos;
if (curSize > rem)
curSize = (UInt32)rem;
}
// curSize != 0
UInt32 realProcessed = 0;
HRESULT hres = s.Stream->Write(data, curSize, &realProcessed);
data = (const void *)((const Byte *)data + realProcessed);
size -= realProcessed;
s.Pos += realProcessed;
_offsetPos += realProcessed;
_absPos += realProcessed;
if (_length < _absPos)
_length = _absPos;
if (s.RealSize < _offsetPos)
s.RealSize = _offsetPos;
if (processedSize)
*processedSize += realProcessed;
if (s.Pos == volSize)
{
bool isRestricted;
if (volSize == 0)
isRestricted = IsRestricted_Empty(s);
else
isRestricted = IsRestricted(s);
if (!isRestricted)
{
const HRESULT res2 = CloseStream_and_FinalRename(_streamIndex);
if (hres == S_OK)
hres = res2;
}
_streamIndex++;
_offsetPos = 0;
}
RINOK(hres)
if (realProcessed == 0 && curSize != 0)
return E_FAIL;
// break;
}
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CMultiOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
PRF(printf("\n-- CMultiOutStream::Seek seekOrigin=%u Seek =%u\n", seekOrigin, (unsigned)offset))
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _absPos; break;
case STREAM_SEEK_END: offset += _length; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
if ((UInt64)offset != _absPos)
{
_absPos = (UInt64)offset;
_offsetPos = (UInt64)offset;
_streamIndex = 0;
}
if (newPosition)
*newPosition = (UInt64)offset;
return S_OK;
}
// result value will be saturated to (UInt32)(Int32)-1
unsigned CMultiOutStream::GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const
{
const unsigned last = Sizes.Size() - 1;
for (unsigned i = 0; i < last; i++)
{
const UInt64 size = Sizes[i];
if (offset < size)
{
relOffset = offset;
return i;
}
offset -= size;
}
const UInt64 size = Sizes[last];
const UInt64 v = offset / size;
if (v >= ((UInt32)(Int32)-1) - last)
return (unsigned)(int)-1; // saturation
relOffset = offset - (unsigned)v * size;
return last + (unsigned)(v);
}
Z7_COM7F_IMF(CMultiOutStream::SetRestriction(UInt64 begin, UInt64 end))
{
COM_TRY_BEGIN
// begin = end = 0; // for debug
PRF(printf("\n==================== CMultiOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end))
if (begin > end)
{
// these value are FAILED values.
return E_FAIL;
// return E_INVALIDARG;
/*
// or we can ignore error with 3 ways: no change, non-restricted, saturation:
end = begin; // non-restricted
end = (UInt64)(Int64)-1; // saturation:
return S_OK;
*/
}
UInt64 b = _restrict_Begin;
UInt64 e = _restrict_End;
_restrict_Begin = begin;
_restrict_End = end;
if (b == e) // if there were no restriction before
return S_OK; // no work to derestrict now.
/* [b, e) is previous restricted region. So all volumes that
intersect that [b, e) region are candidats for derestriction */
if (begin != end) // if there is new non-empty restricted region
{
/* Now we will try to reduce or change (b) and (e) bounds
to reduce main loop that checks volumes for derestriction.
We still use one big derestriction region in main loop, although
in some cases we could have two smaller derestriction regions.
Also usually restriction region cannot move back from previous start position,
so (b <= begin) is expected here for normal cases */
if (b == begin) // if same low bounds
b = end; // we need to derestrict only after the end of new restricted region
if (e == end) // if same high bounds
e = begin; // we need to derestrict only before the begin of new restricted region
}
if (b > e) // || b == (UInt64)(Int64)-1
return S_OK;
/* Here we close finished volumes that are not restricted anymore.
We close (low number) volumes at first. */
UInt64 offset;
unsigned index = GetStreamIndex_for_Offset(b, offset);
for (; index < Streams.Size(); index++)
{
{
const CVolStream &s = Streams[index];
if (_length <= s.Start)
break; // we don't close streams after _length
// (_length > s.Start)
const UInt64 volSize = GetVolSize_for_Stream(index);
if (volSize == 0)
{
if (e < s.Start)
break;
// we don't close empty stream, if next byte [s.Start, s.Start] is restricted
if (IsRestricted_Empty(s))
continue;
}
else
{
if (e <= s.Start)
break;
// we don't close non full streams
if (_length - s.Start < volSize)
break;
// (volSize == s.RealSize) is expected here. So no need to check it
// if (volSize != s.RealSize) break;
if (IsRestricted(s))
continue;
}
}
RINOK(CloseStream_and_FinalRename(index))
}
return S_OK;
COM_TRY_END
}
@@ -0,0 +1,160 @@
// MultiOutStream.h
#ifndef ZIP7_INC_MULTI_OUT_STREAM_H
#define ZIP7_INC_MULTI_OUT_STREAM_H
#include "FileStreams.h"
Z7_CLASS_IMP_COM_2(
CMultiOutStream
, IOutStream
, IStreamSetRestriction
)
Z7_IFACE_COM7_IMP(ISequentialOutStream)
Z7_CLASS_NO_COPY(CMultiOutStream)
struct CVolStream
{
COutFileStream *StreamSpec;
CMyComPtr<IOutStream> Stream;
UInt64 Start; // start pos of current Stream in global stream
UInt64 Pos; // pos in current Stream
UInt64 RealSize;
int Next; // next older
int Prev; // prev newer
AString Postfix;
HRESULT SetSize2(UInt64 size)
{
const HRESULT res = Stream->SetSize(size);
if (res == SZ_OK)
RealSize = size;
return res;
}
};
unsigned _streamIndex; // (_streamIndex >= Stream.Size()) is allowed in some internal code
UInt64 _offsetPos; // offset relative to Streams[_streamIndex] volume. (_offsetPos >= volSize is allowed)
UInt64 _absPos;
UInt64 _length; // virtual Length
UInt64 _absLimit;
CObjectVector<CVolStream> Streams;
CRecordVector<UInt64> Sizes;
UInt64 _restrict_Begin;
UInt64 _restrict_End;
UInt64 _restrict_Global;
unsigned NumOpenFiles_AllowedMax;
// ----- Double Linked List -----
unsigned NumListItems;
int Head; // newest
int Tail; // oldest
void InitLinkedList()
{
Head = -1;
Tail = -1;
NumListItems = 0;
}
void InsertToLinkedList(unsigned index)
{
{
CVolStream &node = Streams[index];
node.Next = Head;
node.Prev = -1;
}
if (Head != -1)
Streams[(unsigned)Head].Prev = (int)index;
else
{
// if (Tail != -1) throw 1;
Tail = (int)index;
}
Head = (int)index;
NumListItems++;
}
void RemoveFromLinkedList(unsigned index)
{
CVolStream &s = Streams[index];
if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev;
if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next;
s.Next = -1; // optional
s.Prev = -1; // optional
NumListItems--;
}
/*
void Delete_LastStream_Records()
{
if (Streams.Back().Stream)
RemoveFromLinkedList(Streams.Size() - 1);
Streams.DeleteBack();
}
*/
UInt64 GetVolSize_for_Stream(unsigned i) const
{
const unsigned last = Sizes.Size() - 1;
return Sizes[i < last ? i : last];
}
UInt64 GetGlobalOffset_for_NewStream() const
{
return Streams.Size() == 0 ? 0:
Streams.Back().Start +
GetVolSize_for_Stream(Streams.Size() - 1);
}
unsigned GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const;
bool IsRestricted(const CVolStream &s) const;
bool IsRestricted_Empty(const CVolStream &s) const
{
// (s) must be stream that has (VolSize == 0).
// we treat empty stream as restricted, if next byte is restricted.
if (s.Start < _restrict_Global)
return true;
return
(_restrict_Begin != _restrict_End)
&& (_restrict_Begin <= s.Start)
&& (_restrict_Begin == s.Start || _restrict_End > s.Start);
}
// bool IsRestricted_for_Close(unsigned index) const;
FString GetFilePath(unsigned index);
HRESULT CloseStream(unsigned index);
HRESULT CloseStream_and_DeleteFile(unsigned index);
HRESULT CloseStream_and_FinalRename(unsigned index);
HRESULT PrepareToOpenNew();
HRESULT CreateNewStream(UInt64 newSize);
HRESULT CreateStreams_If_Required(unsigned streamIndex);
HRESULT ReOpenStream(unsigned streamIndex);
HRESULT OptReOpen_and_SetSize(unsigned index, UInt64 size);
HRESULT Normalize_finalMode(bool finalMode);
public:
FString Prefix;
CFiTime MTime;
bool MTime_Defined;
bool FinalVol_WasReopen;
bool NeedDelete;
CMultiOutStream() {}
~CMultiOutStream();
void Init(const CRecordVector<UInt64> &sizes);
bool SetMTime_Final(const CFiTime &mTime);
UInt64 GetSize() const { return _length; }
/* it makes final flushing, closes open files and renames to final name if required
but it still keeps Streams array of all closed files.
So we still can delete all files later, if required */
HRESULT FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes);
// Destruct object without exceptions
HRESULT Destruct();
};
#endif
@@ -0,0 +1,37 @@
// OffsetStream.cpp
#include "StdAfx.h"
#include "OffsetStream.h"
HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)
{
_offset = offset;
_stream = stream;
return _stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL);
}
Z7_COM7F_IMF(COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
return _stream->Write(data, size, processedSize);
}
Z7_COM7F_IMF(COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
if (seekOrigin == STREAM_SEEK_SET)
{
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
offset += _offset;
}
UInt64 absoluteNewPosition = 0; // =0 for gcc-10
const HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);
if (newPosition)
*newPosition = absoluteNewPosition - _offset;
return result;
}
Z7_COM7F_IMF(COffsetOutStream::SetSize(UInt64 newSize))
{
return _stream->SetSize(_offset + newSize);
}
@@ -0,0 +1,22 @@
// OffsetStream.h
#ifndef ZIP7_INC_OFFSET_STREAM_H
#define ZIP7_INC_OFFSET_STREAM_H
#include "../../Common/MyCom.h"
#include "../IStream.h"
Z7_CLASS_IMP_NOQIB_1(
COffsetOutStream
, IOutStream
)
Z7_IFACE_COM7_IMP(ISequentialOutStream)
CMyComPtr<IOutStream> _stream;
UInt64 _offset;
public:
HRESULT Init(IOutStream *stream, UInt64 offset);
};
#endif
@@ -0,0 +1,111 @@
// OutBuffer.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "OutBuffer.h"
bool COutBuffer::Create(UInt32 bufSize) throw()
{
const UInt32 kMinBlockSize = 1;
if (bufSize < kMinBlockSize)
bufSize = kMinBlockSize;
if (_buf && _bufSize == bufSize)
return true;
Free();
_bufSize = bufSize;
_buf = (Byte *)::MidAlloc(bufSize);
return (_buf != NULL);
}
void COutBuffer::Free() throw()
{
::MidFree(_buf);
_buf = NULL;
}
void COutBuffer::Init() throw()
{
_streamPos = 0;
_limitPos = _bufSize;
_pos = 0;
_processedSize = 0;
_overDict = false;
#ifdef Z7_NO_EXCEPTIONS
ErrorCode = S_OK;
#endif
}
UInt64 COutBuffer::GetProcessedSize() const throw()
{
UInt64 res = _processedSize + _pos - _streamPos;
if (_streamPos > _pos)
res += _bufSize;
return res;
}
HRESULT COutBuffer::FlushPart() throw()
{
// _streamPos < _bufSize
UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos);
HRESULT result = S_OK;
#ifdef Z7_NO_EXCEPTIONS
result = ErrorCode;
#endif
if (_buf2)
{
memcpy(_buf2, _buf + _streamPos, size);
_buf2 += size;
}
if (_stream
#ifdef Z7_NO_EXCEPTIONS
&& (ErrorCode == S_OK)
#endif
)
{
UInt32 processedSize = 0;
result = _stream->Write(_buf + _streamPos, size, &processedSize);
size = processedSize;
}
_streamPos += size;
if (_streamPos == _bufSize)
_streamPos = 0;
if (_pos == _bufSize)
{
_overDict = true;
_pos = 0;
}
_limitPos = (_streamPos > _pos) ? _streamPos : _bufSize;
_processedSize += size;
return result;
}
HRESULT COutBuffer::Flush() throw()
{
#ifdef Z7_NO_EXCEPTIONS
if (ErrorCode != S_OK)
return ErrorCode;
#endif
while (_streamPos != _pos)
{
const HRESULT result = FlushPart();
if (result != S_OK)
return result;
}
return S_OK;
}
void COutBuffer::FlushWithCheck()
{
const HRESULT result = Flush();
#ifdef Z7_NO_EXCEPTIONS
ErrorCode = result;
#else
if (result != S_OK)
throw COutBufferException(result);
#endif
}
+133
View File
@@ -0,0 +1,133 @@
// OutBuffer.h
#ifndef ZIP7_INC_OUT_BUFFER_H
#define ZIP7_INC_OUT_BUFFER_H
#include "../IStream.h"
#include "../../Common/MyCom.h"
#include "../../Common/MyException.h"
#ifndef Z7_NO_EXCEPTIONS
struct COutBufferException: public CSystemException
{
COutBufferException(HRESULT errorCode): CSystemException(errorCode) {}
};
#endif
class COutBuffer
{
protected:
Byte *_buf;
UInt32 _pos;
UInt32 _limitPos;
UInt32 _streamPos;
UInt32 _bufSize;
ISequentialOutStream *_stream;
UInt64 _processedSize;
Byte *_buf2;
bool _overDict;
HRESULT FlushPart() throw();
public:
#ifdef Z7_NO_EXCEPTIONS
HRESULT ErrorCode;
#endif
COutBuffer(): _buf(NULL), _pos(0), _stream(NULL), _buf2(NULL) {}
~COutBuffer() { Free(); }
bool Create(UInt32 bufSize) throw();
void Free() throw();
void SetMemStream(Byte *buf) { _buf2 = buf; }
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void Init() throw();
HRESULT Flush() throw();
void FlushWithCheck();
Z7_FORCE_INLINE
void WriteByte(Byte b)
{
UInt32 pos = _pos;
_buf[pos] = b;
pos++;
_pos = pos;
if (pos == _limitPos)
FlushWithCheck();
}
void WriteBytes(const void *data, size_t size)
{
while (size)
{
UInt32 pos = _pos;
size_t cur = (size_t)(_limitPos - pos);
if (cur >= size)
cur = size;
size -= cur;
Byte *dest = _buf + pos;
pos += (UInt32)cur;
_pos = pos;
#if 0
memcpy(dest, data, cur);
data = (const void *)((const Byte *)data + cur);
#else
const Byte * const lim = (const Byte *)data + cur;
do
{
*dest++ = *(const Byte *)data;
data = (const void *)((const Byte *)data + 1);
}
while (data != lim);
#endif
if (pos == _limitPos)
FlushWithCheck();
}
}
Byte *GetOutBuffer(size_t &avail)
{
const UInt32 pos = _pos;
avail = (size_t)(_limitPos - pos);
return _buf + pos;
}
void SkipWrittenBytes(size_t num)
{
const UInt32 pos = _pos;
const UInt32 rem = _limitPos - pos;
if (rem > num)
{
_pos = pos + (UInt32)num;
return;
}
// (rem <= num)
// the caller must not call it with (rem < num)
// so (rem == num)
_pos = _limitPos;
FlushWithCheck();
}
/*
void WriteBytesBig(const void *data, size_t size)
{
while (size)
{
UInt32 pos = _pos;
UInt32 rem = _limitPos - pos;
if (rem > size)
{
_pos = pos + size;
memcpy(_buf + pos, data, size);
return;
}
memcpy(_buf + pos, data, rem);
_pos = pos + rem;
FlushWithCheck();
}
}
*/
UInt64 GetProcessedSize() const throw();
};
#endif
@@ -0,0 +1,158 @@
// OutMemStream.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "OutMemStream.h"
void COutMemStream::Free()
{
Blocks.Free(_memManager);
Blocks.LockMode = true;
}
void COutMemStream::Init()
{
WriteToRealStreamEvent.Reset();
_unlockEventWasSent = false;
_realStreamMode = false;
Free();
_curBlockPos = 0;
_curBlockIndex = 0;
}
void COutMemStream::DetachData(CMemLockBlocks &blocks)
{
Blocks.Detach(blocks, _memManager);
Free();
}
HRESULT COutMemStream::WriteToRealStream()
{
RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream))
Blocks.Free(_memManager);
return S_OK;
}
Z7_COM7F_IMF(COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
if (_realStreamMode)
return OutSeqStream->Write(data, size, processedSize);
if (processedSize)
*processedSize = 0;
while (size != 0)
{
if (_curBlockIndex < Blocks.Blocks.Size())
{
Byte *p = (Byte *)Blocks.Blocks[_curBlockIndex] + _curBlockPos;
size_t curSize = _memManager->GetBlockSize() - _curBlockPos;
if (size < curSize)
curSize = size;
memcpy(p, data, curSize);
if (processedSize)
*processedSize += (UInt32)curSize;
data = (const void *)((const Byte *)data + curSize);
size -= (UInt32)curSize;
_curBlockPos += curSize;
const UInt64 pos64 = GetPos();
if (pos64 > Blocks.TotalSize)
Blocks.TotalSize = pos64;
if (_curBlockPos == _memManager->GetBlockSize())
{
_curBlockIndex++;
_curBlockPos = 0;
}
continue;
}
const NWindows::NSynchronization::CHandle_WFMO events[3] =
{ StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore };
const DWORD waitResult = NWindows::NSynchronization::WaitForMultiObj_Any_Infinite(
((Blocks.LockMode /* && _memManager->Semaphore.IsCreated() */) ? 3 : 2), events);
// printf("\n 1- outMemStream %d\n", waitResult - WAIT_OBJECT_0);
switch (waitResult)
{
case (WAIT_OBJECT_0 + 0):
return StopWriteResult;
case (WAIT_OBJECT_0 + 1):
{
_realStreamMode = true;
RINOK(WriteToRealStream())
UInt32 processedSize2;
const HRESULT res = OutSeqStream->Write(data, size, &processedSize2);
if (processedSize)
*processedSize += processedSize2;
return res;
}
case (WAIT_OBJECT_0 + 2):
{
// it has bug: no write.
/*
if (!Blocks.SwitchToNoLockMode(_memManager))
return E_FAIL;
*/
break;
}
default:
{
if (waitResult == WAIT_FAILED)
{
const DWORD res = ::GetLastError();
if (res != 0)
return HRESULT_FROM_WIN32(res);
}
return E_FAIL;
}
}
void *p = _memManager->AllocateBlock();
if (!p)
return E_FAIL;
Blocks.Blocks.Add(p);
}
return S_OK;
}
Z7_COM7F_IMF(COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
if (_realStreamMode)
{
if (!OutStream)
return E_FAIL;
return OutStream->Seek(offset, seekOrigin, newPosition);
}
if (seekOrigin == STREAM_SEEK_CUR)
{
if (offset != 0)
return E_NOTIMPL;
}
else if (seekOrigin == STREAM_SEEK_SET)
{
if (offset != 0)
return E_NOTIMPL;
_curBlockIndex = 0;
_curBlockPos = 0;
}
else
return E_NOTIMPL;
if (newPosition)
*newPosition = GetPos();
return S_OK;
}
Z7_COM7F_IMF(COutMemStream::SetSize(UInt64 newSize))
{
if (_realStreamMode)
{
if (!OutStream)
return E_FAIL;
return OutStream->SetSize(newSize);
}
Blocks.TotalSize = newSize;
return S_OK;
}
@@ -0,0 +1,104 @@
// OutMemStream.h
#ifndef ZIP7_INC_OUT_MEM_STREAM_H
#define ZIP7_INC_OUT_MEM_STREAM_H
#include "../../Common/MyCom.h"
#include "MemBlocks.h"
Z7_CLASS_IMP_NOQIB_1(
COutMemStream
, IOutStream
)
Z7_IFACE_COM7_IMP(ISequentialOutStream)
CMemBlockManagerMt *_memManager;
size_t _curBlockPos;
unsigned _curBlockIndex;
bool _realStreamMode;
bool _unlockEventWasSent;
NWindows::NSynchronization::CAutoResetEvent_WFMO StopWritingEvent;
NWindows::NSynchronization::CAutoResetEvent_WFMO WriteToRealStreamEvent;
// NWindows::NSynchronization::CAutoResetEvent NoLockEvent;
HRESULT StopWriteResult;
CMemLockBlocks Blocks;
CMyComPtr<ISequentialOutStream> OutSeqStream;
CMyComPtr<IOutStream> OutStream;
UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; }
public:
HRESULT CreateEvents(SYNC_PARAM_DECL(synchro))
{
WRes wres = StopWritingEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro));
if (wres == 0)
wres = WriteToRealStreamEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro));
return HRESULT_FROM_WIN32(wres);
}
void SetOutStream(IOutStream *outStream)
{
OutStream = outStream;
OutSeqStream = outStream;
}
void SetSeqOutStream(ISequentialOutStream *outStream)
{
OutStream = NULL;
OutSeqStream = outStream;
}
void ReleaseOutStream()
{
OutStream.Release();
OutSeqStream.Release();
}
COutMemStream(CMemBlockManagerMt *memManager):
_memManager(memManager)
{
/*
#ifndef _WIN32
StopWritingEvent._sync =
WriteToRealStreamEvent._sync = &memManager->Synchro;
#endif
*/
}
~COutMemStream() { Free(); }
void Free();
void Init();
HRESULT WriteToRealStream();
void DetachData(CMemLockBlocks &blocks);
bool WasUnlockEventSent() const { return _unlockEventWasSent; }
void SetRealStreamMode()
{
_unlockEventWasSent = true;
WriteToRealStreamEvent.Set();
}
/*
void SetNoLockMode()
{
_unlockEventWasSent = true;
NoLockEvent.Set();
}
*/
void StopWriting(HRESULT res)
{
StopWriteResult = res;
StopWritingEvent.Set();
}
};
#endif
@@ -0,0 +1,53 @@
// ProgressMt.h
#include "StdAfx.h"
#include "ProgressMt.h"
void CMtCompressProgressMixer::Init(unsigned numItems, ICompressProgressInfo *progress)
{
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
InSizes.Clear();
OutSizes.Clear();
for (unsigned i = 0; i < numItems; i++)
{
InSizes.Add(0);
OutSizes.Add(0);
}
TotalInSize = 0;
TotalOutSize = 0;
_progress = progress;
}
void CMtCompressProgressMixer::Reinit(unsigned index)
{
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
InSizes[index] = 0;
OutSizes[index] = 0;
}
HRESULT CMtCompressProgressMixer::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize)
{
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
if (inSize)
{
const UInt64 diff = *inSize - InSizes[index];
InSizes[index] = *inSize;
TotalInSize += diff;
}
if (outSize)
{
const UInt64 diff = *outSize - OutSizes[index];
OutSizes[index] = *outSize;
TotalOutSize += diff;
}
if (_progress)
return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize);
return S_OK;
}
Z7_COM7F_IMF(CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
{
return _progress->SetRatioInfo(_index, inSize, outSize);
}
@@ -0,0 +1,43 @@
// ProgressMt.h
#ifndef ZIP7_INC_PROGRESSMT_H
#define ZIP7_INC_PROGRESSMT_H
#include "../../Common/MyCom.h"
#include "../../Common/MyVector.h"
#include "../../Windows/Synchronization.h"
#include "../ICoder.h"
#include "../IProgress.h"
class CMtCompressProgressMixer
{
CMyComPtr<ICompressProgressInfo> _progress;
CRecordVector<UInt64> InSizes;
CRecordVector<UInt64> OutSizes;
UInt64 TotalInSize;
UInt64 TotalOutSize;
public:
NWindows::NSynchronization::CCriticalSection CriticalSection;
void Init(unsigned numItems, ICompressProgressInfo *progress);
void Reinit(unsigned index);
HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize);
};
Z7_CLASS_IMP_NOQIB_1(
CMtCompressProgress
, ICompressProgressInfo
)
unsigned _index;
CMtCompressProgressMixer *_progress;
public:
void Init(CMtCompressProgressMixer *progress, unsigned index)
{
_progress = progress;
_index = index;
}
void Reinit() { _progress->Reinit(_index); }
};
#endif
@@ -0,0 +1,51 @@
// ProgressUtils.cpp
#include "StdAfx.h"
#include "ProgressUtils.h"
CLocalProgress::CLocalProgress():
SendRatio(true),
SendProgress(true),
ProgressOffset(0),
InSize(0),
OutSize(0)
{}
void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)
{
_ratioProgress.Release();
_progress = progress;
_progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);
_inSizeIsMain = inSizeIsMain;
}
Z7_COM7F_IMF(CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
{
UInt64 inSize2 = InSize;
UInt64 outSize2 = OutSize;
if (inSize)
inSize2 += (*inSize);
if (outSize)
outSize2 += (*outSize);
if (SendRatio && _ratioProgress)
{
RINOK(_ratioProgress->SetRatioInfo(&inSize2, &outSize2))
}
if (SendProgress)
{
inSize2 += ProgressOffset;
outSize2 += ProgressOffset;
return _progress->SetCompleted(_inSizeIsMain ? &inSize2 : &outSize2);
}
return S_OK;
}
HRESULT CLocalProgress::SetCur()
{
return SetRatioInfo(NULL, NULL);
}
@@ -0,0 +1,33 @@
// ProgressUtils.h
#ifndef ZIP7_INC_PROGRESS_UTILS_H
#define ZIP7_INC_PROGRESS_UTILS_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../IProgress.h"
Z7_CLASS_IMP_COM_1(
CLocalProgress
, ICompressProgressInfo
)
public:
bool SendRatio;
bool SendProgress;
private:
bool _inSizeIsMain;
CMyComPtr<IProgress> _progress;
CMyComPtr<ICompressProgressInfo> _ratioProgress;
public:
UInt64 ProgressOffset;
UInt64 InSize;
UInt64 OutSize;
CLocalProgress();
void Init(IProgress *progress, bool inSizeIsMain);
HRESULT SetCur();
};
#endif
+117
View File
@@ -0,0 +1,117 @@
// PropId.cpp
#include "StdAfx.h"
#include "../../Common/MyWindows.h"
#include "../PropID.h"
// VARTYPE
const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] =
{
VT_EMPTY,
VT_UI4,
VT_UI4,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_BOOL,
VT_UI8,
VT_UI8,
VT_UI4,
VT_FILETIME,
VT_FILETIME,
VT_FILETIME,
VT_BOOL,
VT_BOOL,
VT_BOOL,
VT_BOOL,
VT_BOOL,
VT_UI4,
VT_UI4,
VT_BSTR,
VT_BOOL,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_UI8,
VT_BSTR,
VT_UI8,
VT_BSTR,
VT_UI8,
VT_UI8,
VT_BSTR, // or VT_UI8 kpidUnpackVer
VT_UI4, // or VT_UI8 kpidVolume
VT_BOOL,
VT_UI8,
VT_UI8,
VT_UI8,
VT_UI8,
VT_UI4,
VT_BOOL,
VT_BOOL,
VT_BSTR,
VT_UI8,
VT_UI8,
VT_UI4, // kpidChecksum
VT_BSTR,
VT_UI8,
VT_BSTR, // or VT_UI8 kpidId
VT_BSTR,
VT_BSTR,
VT_UI4,
VT_UI4,
VT_BSTR,
VT_BSTR,
VT_UI8,
VT_UI8,
VT_UI4,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_BSTR, // kpidNtSecure
VT_BOOL,
VT_BOOL,
VT_BOOL,
VT_BOOL,
VT_BSTR, // SHA-1
VT_BSTR, // SHA-256
VT_BSTR,
VT_UI8,
VT_UI4,
VT_UI4,
VT_BSTR,
VT_UI8,
VT_UI8,
VT_UI8,
VT_UI8,
VT_UI8,
VT_UI8,
VT_UI8,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_BOOL,
VT_BOOL,
VT_BOOL,
VT_UI8,
VT_UI8,
VT_BSTR, // kpidNtReparse
VT_BSTR,
VT_UI8,
VT_UI8,
VT_BOOL,
VT_BSTR,
VT_BSTR,
VT_BSTR,
VT_BOOL,
VT_FILETIME, // kpidChangeTime
VT_UI4,
VT_UI4,
VT_UI4,
VT_UI4,
VT_UI4,
VT_UI4 // kpidDevMinor
};
@@ -0,0 +1,80 @@
// RegisterArc.h
#ifndef ZIP7_INC_REGISTER_ARC_H
#define ZIP7_INC_REGISTER_ARC_H
#include "../Archive/IArchive.h"
struct CArcInfo
{
UInt32 Flags;
Byte Id;
Byte SignatureSize;
UInt16 SignatureOffset;
const Byte *Signature;
const char *Name;
const char *Ext;
const char *AddExt;
UInt32 TimeFlags;
Func_CreateInArchive CreateInArchive;
Func_CreateOutArchive CreateOutArchive;
Func_IsArc IsArc;
bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; }
};
void RegisterArc(const CArcInfo *arcInfo) throw();
#define IMP_CreateArcIn_2(c) \
static IInArchive *CreateArc() { return new c; }
#define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler())
#ifdef Z7_EXTRACT_ONLY
#define IMP_CreateArcOut
#define CreateArcOut NULL
#else
#define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); }
#endif
#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, tf, crIn, crOut, isArc } ; \
#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
REGISTER_ARC_V (n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \
static CRegisterArc g_RegisterArc;
#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \
IMP_CreateArcIn_2(cls) \
REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, 0, CreateArc, NULL, isArc)
#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \
IMP_CreateArcIn_2(cls) \
REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, 0, CreateArc, NULL, isArc)
#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \
REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc)
#define REGISTER_ARC_I_NO_SIG(n, e, ae, id, offs, flags, isArc) \
REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc)
#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, tf, isArc) \
IMP_CreateArcIn \
IMP_CreateArcOut \
REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc)
#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, tf, isArc) \
IMP_CreateArcIn \
IMP_CreateArcOut \
REGISTER_ARC_V(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) \
struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \
static CRegisterArcDecSig g_RegisterArc;
#endif
@@ -0,0 +1,106 @@
// RegisterCodec.h
#ifndef ZIP7_INC_REGISTER_CODEC_H
#define ZIP7_INC_REGISTER_CODEC_H
#include "../Common/MethodId.h"
#include "../ICoder.h"
typedef void * (*CreateCodecP)();
struct CCodecInfo
{
CreateCodecP CreateDecoder;
CreateCodecP CreateEncoder;
CMethodId Id;
const char *Name;
UInt32 NumStreams;
bool IsFilter;
};
void RegisterCodec(const CCodecInfo *codecInfo) throw();
#define REGISTER_CODEC_CREATE_2(name, cls, i) static void *name() { return (void *)(i *)(new cls); }
#define REGISTER_CODEC_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressCoder)
#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x
#define REGISTER_CODEC_VAR(x) static const CCodecInfo g_CodecInfo_ ## x =
#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo_ ## x); }}; \
static REGISTER_CODEC_NAME(x) g_RegisterCodec_ ## x;
#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
#define REGISTER_CODECS_VAR static const CCodecInfo g_CodecsInfo[] =
#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CodecsInfo); i++) \
RegisterCodec(&g_CodecsInfo[i]); }}; \
static REGISTER_CODECS_NAME(x) g_RegisterCodecs;
#define REGISTER_CODEC_2(x, crDec, crEnc, id, name) \
REGISTER_CODEC_VAR(x) \
{ crDec, crEnc, id, name, 1, false }; \
REGISTER_CODEC(x)
#ifdef Z7_EXTRACT_ONLY
#define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \
REGISTER_CODEC_CREATE(CreateDec, clsDec) \
REGISTER_CODEC_2(x, CreateDec, NULL, id, name)
#else
#define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \
REGISTER_CODEC_CREATE(CreateDec, clsDec) \
REGISTER_CODEC_CREATE(CreateEnc, clsEnc) \
REGISTER_CODEC_2(x, CreateDec, CreateEnc, id, name)
#endif
#define REGISTER_FILTER_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressFilter)
#define REGISTER_FILTER_ITEM(crDec, crEnc, id, name) \
{ crDec, crEnc, id, name, 1, true }
#define REGISTER_FILTER(x, crDec, crEnc, id, name) \
REGISTER_CODEC_VAR(x) \
REGISTER_FILTER_ITEM(crDec, crEnc, id, name); \
REGISTER_CODEC(x)
#ifdef Z7_EXTRACT_ONLY
#define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \
REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \
REGISTER_FILTER(x, x ## _CreateDec, NULL, id, name)
#else
#define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \
REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \
REGISTER_FILTER_CREATE(x ## _CreateEnc, clsEnc) \
REGISTER_FILTER(x, x ## _CreateDec, x ## _CreateEnc, id, name)
#endif
struct CHasherInfo
{
IHasher * (*CreateHasher)();
CMethodId Id;
const char *Name;
UInt32 DigestSize;
};
void RegisterHasher(const CHasherInfo *hasher) throw();
#define REGISTER_HASHER_NAME(x) CRegHasher_ ## x
#define REGISTER_HASHER(cls, id, name, size) \
Z7_COM7F_IMF2(UInt32, cls::GetDigestSize()) { return size; } \
static IHasher *CreateHasherSpec() { return new cls(); } \
static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \
struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
static REGISTER_HASHER_NAME(cls) g_RegisterHasher;
#endif
+11
View File
@@ -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
@@ -0,0 +1,151 @@
// StreamBinder.cpp
#include "StdAfx.h"
#include "../../Common/MyCom.h"
#include "StreamBinder.h"
Z7_CLASS_IMP_COM_1(
CBinderInStream
, ISequentialInStream
)
CStreamBinder *_binder;
public:
~CBinderInStream() { _binder->CloseRead_CallOnce(); }
CBinderInStream(CStreamBinder *binder): _binder(binder) {}
};
Z7_COM7F_IMF(CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{ return _binder->Read(data, size, processedSize); }
Z7_CLASS_IMP_COM_1(
CBinderOutStream
, ISequentialOutStream
)
CStreamBinder *_binder;
public:
~CBinderOutStream() { _binder->CloseWrite(); }
CBinderOutStream(CStreamBinder *binder): _binder(binder) {}
};
Z7_COM7F_IMF(CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{ return _binder->Write(data, size, processedSize); }
static HRESULT Event_Create_or_Reset(NWindows::NSynchronization::CAutoResetEvent &event)
{
const WRes wres = event.CreateIfNotCreated_Reset();
return HRESULT_FROM_WIN32(wres);
}
HRESULT CStreamBinder::Create_ReInit()
{
RINOK(Event_Create_or_Reset(_canRead_Event))
// RINOK(Event_Create_or_Reset(_canWrite_Event))
// _canWrite_Semaphore.Close();
// we need at least 3 items of maxCount: 1 for normal unlock in Read(), 2 items for unlock in CloseRead_CallOnce()
_canWrite_Semaphore.OptCreateInit(0, 3);
// _readingWasClosed = false;
_readingWasClosed2 = false;
_waitWrite = true;
_bufSize = 0;
_buf = NULL;
ProcessedSize = 0;
// WritingWasCut = false;
return S_OK;
}
void CStreamBinder::CreateStreams2(CMyComPtr<ISequentialInStream> &inStream, CMyComPtr<ISequentialOutStream> &outStream)
{
inStream = new CBinderInStream(this);
outStream = new CBinderOutStream(this);
}
// (_canRead_Event && _bufSize == 0) means that stream is finished.
HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (size != 0)
{
if (_waitWrite)
{
WRes wres = _canRead_Event.Lock();
if (wres != 0)
return HRESULT_FROM_WIN32(wres);
_waitWrite = false;
}
if (size > _bufSize)
size = _bufSize;
if (size != 0)
{
memcpy(data, _buf, size);
_buf = ((const Byte *)_buf) + size;
ProcessedSize += size;
if (processedSize)
*processedSize = size;
_bufSize -= size;
/*
if (_bufSize == 0), then we have read whole buffer
we have two ways here:
- if we check (_bufSize == 0) here, we unlock Write only after full data Reading - it reduces the number of syncs
- if we don't check (_bufSize == 0) here, we unlock Write after partial data Reading
*/
if (_bufSize == 0)
{
_waitWrite = true;
// _canWrite_Event.Set();
_canWrite_Semaphore.Release();
}
}
}
return S_OK;
}
HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
if (!_readingWasClosed2)
{
_buf = data;
_bufSize = size;
_canRead_Event.Set();
/*
_canWrite_Event.Lock();
if (_readingWasClosed)
_readingWasClosed2 = true;
*/
_canWrite_Semaphore.Lock();
// _bufSize : is remain size that was not read
size -= _bufSize;
// size : is size of data that was read
if (size != 0)
{
// if some data was read, then we report that size and return
if (processedSize)
*processedSize = size;
return S_OK;
}
_readingWasClosed2 = true;
}
// WritingWasCut = true;
return k_My_HRESULT_WritingWasCut;
}
@@ -0,0 +1,78 @@
// StreamBinder.h
#ifndef ZIP7_INC_STREAM_BINDER_H
#define ZIP7_INC_STREAM_BINDER_H
#include "../../Windows/Synchronization.h"
#include "../IStream.h"
/*
We can use one from two code versions here: with Event or with Semaphore to unlock Writer thread
The difference for cases where Reading must be closed before Writing closing
1) Event Version: _canWrite_Event
We call _canWrite_Event.Set() without waiting _canRead_Event in CloseRead() function.
The writer thread can get (_readingWasClosed) status in one from two iterations.
It's ambiguity of processing flow. But probably it's SAFE to use, if Event functions provide memory barriers.
reader thread:
_canWrite_Event.Set();
_readingWasClosed = true;
_canWrite_Event.Set();
writer thread:
_canWrite_Event.Wait()
if (_readingWasClosed)
2) Semaphore Version: _canWrite_Semaphore
writer thread always will detect closing of reading in latest iteration after all data processing iterations
*/
class CStreamBinder
{
NWindows::NSynchronization::CAutoResetEvent _canRead_Event;
// NWindows::NSynchronization::CAutoResetEvent _canWrite_Event;
NWindows::NSynchronization::CSemaphore _canWrite_Semaphore;
// bool _readingWasClosed; // set it in reader thread and check it in write thread
bool _readingWasClosed2; // use it in writer thread
// bool WritingWasCut;
bool _waitWrite; // use it in reader thread
UInt32 _bufSize;
const void *_buf;
public:
UInt64 ProcessedSize; // the size that was read by reader thread
void CreateStreams2(CMyComPtr<ISequentialInStream> &inStream, CMyComPtr<ISequentialOutStream> &outStream);
HRESULT Create_ReInit();
HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);
void CloseRead_CallOnce()
{
// call it only once: for example, in destructor
/*
_readingWasClosed = true;
_canWrite_Event.Set();
*/
/*
We must relase Semaphore only once !!!
we must release at least 2 items of Semaphore:
one item to unlock partial Write(), if Read() have read some items
then additional item to stop writing (_bufSize will be 0)
*/
_canWrite_Semaphore.Release(2);
}
void CloseWrite()
{
_buf = NULL;
_bufSize = 0;
_canRead_Event.Set();
}
};
#endif
@@ -0,0 +1,290 @@
// StreamObjects.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "StreamObjects.h"
Z7_COM7F_IMF(CBufferInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
if (_pos >= Buf.Size())
return S_OK;
size_t rem = Buf.Size() - (size_t)_pos;
if (rem > size)
rem = (size_t)size;
memcpy(data, (const Byte *)Buf + (size_t)_pos, rem);
_pos += rem;
if (processedSize)
*processedSize = (UInt32)rem;
return S_OK;
}
Z7_COM7F_IMF(CBufferInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _pos; break;
case STREAM_SEEK_END: offset += Buf.Size(); break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_pos = (UInt64)offset;
if (newPosition)
*newPosition = (UInt64)offset;
return S_OK;
}
Z7_COM7F_IMF(CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
if (_pos >= _size)
return S_OK;
size_t rem = _size - (size_t)_pos;
if (rem > size)
rem = (size_t)size;
memcpy(data, _data + (size_t)_pos, rem);
_pos += rem;
if (processedSize)
*processedSize = (UInt32)rem;
return S_OK;
}
Z7_COM7F_IMF(CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _pos; break;
case STREAM_SEEK_END: offset += _size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_pos = (UInt64)offset;
if (newPosition)
*newPosition = (UInt64)offset;
return S_OK;
}
void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream)
{
*stream = NULL;
CBufInStream *inStreamSpec = new CBufInStream;
CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
inStreamSpec->Init((const Byte *)data, size, ref);
*stream = streamTemp.Detach();
}
void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream)
{
*stream = NULL;
CBufferInStream *inStreamSpec = new CBufferInStream;
CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
inStreamSpec->Buf.CopyFrom((const Byte *)data, size);
inStreamSpec->Init();
*stream = streamTemp.Detach();
}
void CByteDynBuffer::Free() throw()
{
MyFree(_buf);
_buf = NULL;
_capacity = 0;
}
bool CByteDynBuffer::EnsureCapacity(size_t cap) throw()
{
if (cap <= _capacity)
return true;
const size_t cap2 = _capacity + _capacity / 4;
if (cap < cap2)
cap = cap2;
Byte *buf = (Byte *)MyRealloc(_buf, cap);
if (!buf)
return false;
_buf = buf;
_capacity = cap;
return true;
}
Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
{
addSize += _size;
if (addSize < _size)
return NULL;
if (!_buffer.EnsureCapacity(addSize))
return NULL;
return (Byte *)_buffer + _size;
}
void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
{
dest.CopyFrom((const Byte *)_buffer, _size);
}
Z7_COM7F_IMF(CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
Byte *buf = GetBufPtrForWriting(size);
if (!buf)
return E_OUTOFMEMORY;
memcpy(buf, data, size);
UpdateSize(size);
if (processedSize)
*processedSize = size;
return S_OK;
}
Z7_COM7F_IMF(CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
size_t rem = _size - _pos;
if (rem > size)
rem = (size_t)size;
if (rem != 0)
{
memcpy(_buffer + _pos, data, rem);
_pos += rem;
}
if (processedSize)
*processedSize = (UInt32)rem;
return (rem != 0 || size == 0) ? S_OK : E_FAIL;
}
Z7_COM7F_IMF(CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
UInt32 realProcessedSize;
HRESULT result = _stream->Write(data, size, &realProcessedSize);
_size += realProcessedSize;
if (processedSize)
*processedSize = realProcessedSize;
return result;
}
static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
void CCachedInStream::Free() throw()
{
MyFree(_tags);
_tags = NULL;
MidFree(_data);
_data = NULL;
}
bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw()
{
unsigned sizeLog = blockSizeLog + numBlocksLog;
if (sizeLog >= sizeof(size_t) * 8)
return false;
size_t dataSize = (size_t)1 << sizeLog;
if (!_data || dataSize != _dataSize)
{
MidFree(_data);
_data = (Byte *)MidAlloc(dataSize);
if (!_data)
return false;
_dataSize = dataSize;
}
if (!_tags || numBlocksLog != _numBlocksLog)
{
MyFree(_tags);
_tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
if (!_tags)
return false;
_numBlocksLog = numBlocksLog;
}
_blockSizeLog = blockSizeLog;
return true;
}
void CCachedInStream::Init(UInt64 size) throw()
{
_size = size;
_pos = 0;
const size_t numBlocks = (size_t)1 << _numBlocksLog;
for (size_t i = 0; i < numBlocks; i++)
_tags[i] = kEmptyTag;
}
Z7_COM7F_IMF(CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
if (_pos >= _size)
return S_OK;
{
const UInt64 rem = _size - _pos;
if (size > rem)
size = (UInt32)rem;
}
while (size != 0)
{
const UInt64 cacheTag = _pos >> _blockSizeLog;
const size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
Byte *p = _data + (cacheIndex << _blockSizeLog);
if (_tags[cacheIndex] != cacheTag)
{
_tags[cacheIndex] = kEmptyTag;
const UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
size_t blockSize = (size_t)1 << _blockSizeLog;
if (blockSize > remInBlock)
blockSize = (size_t)remInBlock;
RINOK(ReadBlock(cacheTag, p, blockSize))
_tags[cacheIndex] = cacheTag;
}
const size_t kBlockSize = (size_t)1 << _blockSizeLog;
const size_t offset = (size_t)_pos & (kBlockSize - 1);
UInt32 cur = size;
const size_t rem = kBlockSize - offset;
if (cur > rem)
cur = (UInt32)rem;
memcpy(data, p + offset, cur);
if (processedSize)
*processedSize += cur;
data = (void *)((const Byte *)data + cur);
_pos += cur;
size -= cur;
}
return S_OK;
}
Z7_COM7F_IMF(CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
switch (seekOrigin)
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _pos; break;
case STREAM_SEEK_END: offset += _size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
_pos = (UInt64)offset;
if (newPosition)
*newPosition = (UInt64)offset;
return S_OK;
}
@@ -0,0 +1,146 @@
// StreamObjects.h
#ifndef ZIP7_INC_STREAM_OBJECTS_H
#define ZIP7_INC_STREAM_OBJECTS_H
#include "../../Common/MyBuffer.h"
#include "../../Common/MyCom.h"
#include "../../Common/MyVector.h"
#include "../IStream.h"
Z7_CLASS_IMP_IInStream(
CBufferInStream
)
UInt64 _pos;
public:
CByteBuffer Buf;
void Init() { _pos = 0; }
};
Z7_CLASS_IMP_COM_0(
CReferenceBuf
)
public:
CByteBuffer Buf;
};
Z7_CLASS_IMP_IInStream(
CBufInStream
)
const Byte *_data;
UInt64 _pos;
size_t _size;
CMyComPtr<IUnknown> _ref;
public:
void Init(const Byte *data, size_t size, IUnknown *ref = NULL)
{
_data = data;
_size = size;
_pos = 0;
_ref = ref;
}
void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); }
// Seek() is allowed here. So reading order could be changed
bool WasFinished() const { return _pos == _size; }
};
void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream);
void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream);
inline void Create_BufInStream_WithNewBuffer(const CByteBuffer &buf, ISequentialInStream **stream)
{ Create_BufInStream_WithNewBuffer(buf, buf.Size(), stream); }
class CByteDynBuffer Z7_final
{
size_t _capacity;
Byte *_buf;
Z7_CLASS_NO_COPY(CByteDynBuffer)
public:
CByteDynBuffer(): _capacity(0), _buf(NULL) {}
// there is no copy constructor. So don't copy this object.
~CByteDynBuffer() { Free(); }
void Free() throw();
size_t GetCapacity() const { return _capacity; }
operator Byte*() const { return _buf; }
operator const Byte*() const { return _buf; }
bool EnsureCapacity(size_t capacity) throw();
};
Z7_CLASS_IMP_COM_1(
CDynBufSeqOutStream
, ISequentialOutStream
)
CByteDynBuffer _buffer;
size_t _size;
public:
CDynBufSeqOutStream(): _size(0) {}
void Init() { _size = 0; }
size_t GetSize() const { return _size; }
const Byte *GetBuffer() const { return _buffer; }
void CopyToBuffer(CByteBuffer &dest) const;
Byte *GetBufPtrForWriting(size_t addSize);
void UpdateSize(size_t addSize) { _size += addSize; }
};
Z7_CLASS_IMP_COM_1(
CBufPtrSeqOutStream
, ISequentialOutStream
)
Byte *_buffer;
size_t _size;
size_t _pos;
public:
void Init(Byte *buffer, size_t size)
{
_buffer = buffer;
_pos = 0;
_size = size;
}
size_t GetPos() const { return _pos; }
};
Z7_CLASS_IMP_COM_1(
CSequentialOutStreamSizeCount
, ISequentialOutStream
)
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
public:
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void Init() { _size = 0; }
UInt64 GetSize() const { return _size; }
};
class CCachedInStream:
public IInStream,
public CMyUnknownImp
{
Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream)
UInt64 *_tags;
Byte *_data;
size_t _dataSize;
unsigned _blockSizeLog;
unsigned _numBlocksLog;
UInt64 _size;
UInt64 _pos;
protected:
virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0;
public:
CCachedInStream(): _tags(NULL), _data(NULL) {}
virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (Release() calls it) !!!
void Free() throw();
bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw();
void Init(UInt64 size) throw();
};
#endif
@@ -0,0 +1,101 @@
// StreamUtils.cpp
#include "StdAfx.h"
#include "../../Common/MyCom.h"
#include "StreamUtils.h"
static const UInt32 kBlockSize = ((UInt32)1 << 31);
HRESULT InStream_SeekToBegin(IInStream *stream) throw()
{
return InStream_SeekSet(stream, 0);
}
HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &sizeRes) throw()
{
#ifdef _WIN32
{
Z7_DECL_CMyComPtr_QI_FROM(
IStreamGetSize,
streamGetSize, stream)
if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK)
return S_OK;
}
#endif
const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes);
const HRESULT hres2 = InStream_SeekToBegin(stream);
return hres != S_OK ? hres : hres2;
}
HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw()
{
RINOK(InStream_GetPos(stream, curPosRes))
#ifdef _WIN32
{
Z7_DECL_CMyComPtr_QI_FROM(
IStreamGetSize,
streamGetSize, stream)
if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK)
return S_OK;
}
#endif
const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes);
const HRESULT hres2 = InStream_SeekSet(stream, curPosRes);
return hres != S_OK ? hres : hres2;
}
HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw()
{
size_t size = *processedSize;
*processedSize = 0;
while (size != 0)
{
UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
UInt32 processedSizeLoc;
HRESULT res = stream->Read(data, curSize, &processedSizeLoc);
*processedSize += processedSizeLoc;
data = (void *)((Byte *)data + processedSizeLoc);
size -= processedSizeLoc;
RINOK(res)
if (processedSizeLoc == 0)
return S_OK;
}
return S_OK;
}
HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw()
{
size_t processedSize = size;
RINOK(ReadStream(stream, data, &processedSize))
return (size == processedSize) ? S_OK : S_FALSE;
}
HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw()
{
size_t processedSize = size;
RINOK(ReadStream(stream, data, &processedSize))
return (size == processedSize) ? S_OK : E_FAIL;
}
HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw()
{
while (size != 0)
{
UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
UInt32 processedSizeLoc;
HRESULT res = stream->Write(data, curSize, &processedSizeLoc);
data = (const void *)((const Byte *)data + processedSizeLoc);
size -= processedSizeLoc;
RINOK(res)
if (processedSizeLoc == 0)
return E_FAIL;
}
return S_OK;
}
@@ -0,0 +1,31 @@
// StreamUtils.h
#ifndef ZIP7_INC_STREAM_UTILS_H
#define ZIP7_INC_STREAM_UTILS_H
#include "../IStream.h"
inline HRESULT InStream_SeekSet(IInStream *stream, UInt64 offset) throw()
{ return stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL); }
inline HRESULT InStream_GetPos(IInStream *stream, UInt64 &curPosRes) throw()
{ return stream->Seek(0, STREAM_SEEK_CUR, &curPosRes); }
inline HRESULT InStream_GetSize_SeekToEnd(IInStream *stream, UInt64 &sizeRes) throw()
{ return stream->Seek(0, STREAM_SEEK_END, &sizeRes); }
HRESULT InStream_SeekToBegin(IInStream *stream) throw();
HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &size) throw();
HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw();
inline HRESULT InStream_GetSize_SeekToBegin(IInStream *stream, UInt64 &sizeRes) throw()
{
RINOK(InStream_SeekToBegin(stream))
return InStream_AtBegin_GetSize(stream, sizeRes);
}
HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw();
HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw();
HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw();
HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw();
#endif
@@ -0,0 +1,57 @@
// UniqBlocks.cpp
#include "StdAfx.h"
#include <string.h>
#include "UniqBlocks.h"
unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)
{
unsigned left = 0, right = Sorted.Size();
while (left != right)
{
const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
const unsigned index = Sorted[mid];
const CByteBuffer &buf = Bufs[index];
const size_t sizeMid = buf.Size();
if (size < sizeMid)
right = mid;
else if (size > sizeMid)
left = mid + 1;
else
{
if (size == 0)
return index;
const int cmp = memcmp(data, buf, size);
if (cmp == 0)
return index;
if (cmp < 0)
right = mid;
else
left = mid + 1;
}
}
unsigned index = Bufs.Size();
Sorted.Insert(left, index);
Bufs.AddNew().CopyFrom(data, size);
return index;
}
UInt64 CUniqBlocks::GetTotalSizeInBytes() const
{
UInt64 size = 0;
FOR_VECTOR (i, Bufs)
size += Bufs[i].Size();
return size;
}
void CUniqBlocks::GetReverseMap()
{
unsigned num = Sorted.Size();
BufIndexToSortedIndex.ClearAndSetSize(num);
unsigned *p = &BufIndexToSortedIndex[0];
const unsigned *sorted = &Sorted[0];
for (unsigned i = 0; i < num; i++)
p[sorted[i]] = i;
}
@@ -0,0 +1,41 @@
// UniqBlocks.h
#ifndef ZIP7_INC_UNIQ_BLOCKS_H
#define ZIP7_INC_UNIQ_BLOCKS_H
#include "../../Common/MyBuffer.h"
#include "../../Common/MyString.h"
struct C_UInt32_UString_Map
{
CRecordVector<UInt32> Numbers;
UStringVector Strings;
void Add_UInt32(const UInt32 n)
{
Numbers.AddToUniqueSorted(n);
}
int Find(const UInt32 n)
{
return Numbers.FindInSorted(n);
}
};
struct CUniqBlocks
{
CObjectVector<CByteBuffer> Bufs;
CUIntVector Sorted;
CUIntVector BufIndexToSortedIndex;
unsigned AddUniq(const Byte *data, size_t size);
UInt64 GetTotalSizeInBytes() const;
void GetReverseMap();
bool IsOnlyEmpty() const
{
return (Bufs.Size() == 0 || (Bufs.Size() == 1 && Bufs[0].Size() == 0));
}
};
#endif
@@ -0,0 +1,47 @@
// VirtThread.cpp
#include "StdAfx.h"
#include "VirtThread.h"
static THREAD_FUNC_DECL CoderThread(void *p)
{
for (;;)
{
CVirtThread *t = (CVirtThread *)p;
t->StartEvent.Lock();
if (t->Exit)
return THREAD_FUNC_RET_ZERO;
t->Execute();
t->FinishedEvent.Set();
}
}
WRes CVirtThread::Create()
{
RINOK_WRes(StartEvent.CreateIfNotCreated_Reset())
RINOK_WRes(FinishedEvent.CreateIfNotCreated_Reset())
// StartEvent.Reset();
// FinishedEvent.Reset();
Exit = false;
if (Thread.IsCreated())
return S_OK;
return Thread.Create(CoderThread, this);
}
WRes CVirtThread::Start()
{
Exit = false;
return StartEvent.Set();
}
void CVirtThread::WaitThreadFinish()
{
Exit = true;
if (StartEvent.IsCreated())
StartEvent.Set();
if (Thread.IsCreated())
{
Thread.Wait_Close();
}
}
@@ -0,0 +1,24 @@
// VirtThread.h
#ifndef ZIP7_INC_VIRT_THREAD_H
#define ZIP7_INC_VIRT_THREAD_H
#include "../../Windows/Synchronization.h"
#include "../../Windows/Thread.h"
struct CVirtThread
{
NWindows::NSynchronization::CAutoResetEvent StartEvent;
NWindows::NSynchronization::CAutoResetEvent FinishedEvent;
NWindows::CThread Thread;
bool Exit;
virtual ~CVirtThread() { WaitThreadFinish(); }
void WaitThreadFinish(); // call it in destructor of child class !
WRes Create();
WRes Start();
virtual void Execute() = 0;
WRes WaitExecuteFinish() { return FinishedEvent.Lock(); }
};
#endif