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:
@@ -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;
|
||||
}
|
||||
*/
|
||||
@@ -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 gid_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;
|
||||
uid_t _uid; // uid_t can be unsigned or signed int
|
||||
gid_t _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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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 ¶m, 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 ¶m = 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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user