mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 11:14:58 -06:00
285 lines
5.7 KiB
C++
Executable File
285 lines
5.7 KiB
C++
Executable File
// InMemStream.h
|
|
|
|
#ifndef __IN_MEM_STREAM_H
|
|
#define __IN_MEM_STREAM_H
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "../../../C/Alloc.h"
|
|
|
|
#include "../../Common/MyCom.h"
|
|
|
|
#include "MemBlocks.h"
|
|
|
|
class CIntListCheck
|
|
{
|
|
protected:
|
|
int *_data;
|
|
public:
|
|
CIntListCheck(): _data(0) {}
|
|
~CIntListCheck() { FreeList(); }
|
|
|
|
bool AllocateList(int numItems)
|
|
{
|
|
FreeList();
|
|
if (numItems == 0)
|
|
return true;
|
|
_data = (int *)::MyAlloc(numItems * sizeof(int));
|
|
return (_data != 0);
|
|
}
|
|
|
|
void FreeList()
|
|
{
|
|
::MyFree(_data);
|
|
_data = 0;
|
|
}
|
|
};
|
|
|
|
|
|
class CResourceList : public CIntListCheck
|
|
{
|
|
int _headFree;
|
|
public:
|
|
CResourceList(): _headFree(-1) {}
|
|
|
|
bool AllocateList(int numItems)
|
|
{
|
|
FreeList();
|
|
if (numItems == 0)
|
|
return true;
|
|
if (!CIntListCheck::AllocateList(numItems))
|
|
return false;
|
|
for (int i = 0; i < numItems; i++)
|
|
_data[i] = i + 1;
|
|
_data[numItems - 1] = -1;
|
|
_headFree = 0;
|
|
return true;
|
|
}
|
|
|
|
void FreeList()
|
|
{
|
|
CIntListCheck::FreeList();
|
|
_headFree = -1;
|
|
}
|
|
|
|
int AllocateItem()
|
|
{
|
|
int res = _headFree;
|
|
if (res >= 0)
|
|
_headFree = _data[res];
|
|
return res;
|
|
}
|
|
|
|
void FreeItem(int index)
|
|
{
|
|
if (index < 0)
|
|
return;
|
|
_data[index] = _headFree;
|
|
_headFree = index;
|
|
}
|
|
};
|
|
|
|
class CResourceListMt: public CResourceList
|
|
{
|
|
NWindows::NSynchronization::CCriticalSection _criticalSection;
|
|
public:
|
|
NWindows::NSynchronization::CSemaphore Semaphore;
|
|
|
|
HRes AllocateList(int numItems)
|
|
{
|
|
if (!CResourceList::AllocateList(numItems))
|
|
return E_OUTOFMEMORY;
|
|
Semaphore.Close();
|
|
return Semaphore.Create(numItems, numItems);
|
|
}
|
|
|
|
int AllocateItem()
|
|
{
|
|
Semaphore.Lock();
|
|
_criticalSection.Enter();
|
|
int res = CResourceList::AllocateItem();
|
|
_criticalSection.Leave();
|
|
return res;
|
|
}
|
|
|
|
void FreeItem(int index)
|
|
{
|
|
if (index < 0)
|
|
return;
|
|
_criticalSection.Enter();
|
|
CResourceList::FreeItem(index);
|
|
_criticalSection.Leave();
|
|
Semaphore.Release();
|
|
}
|
|
};
|
|
|
|
class CIntQueueMt: public CIntListCheck
|
|
{
|
|
int _numItems;
|
|
int _head;
|
|
int _cur;
|
|
public:
|
|
CIntQueueMt(): _numItems(0), _head(0), _cur(0) {}
|
|
NWindows::NSynchronization::CSemaphore Semaphore;
|
|
|
|
HRes AllocateList(int numItems)
|
|
{
|
|
FreeList();
|
|
if (numItems == 0)
|
|
return S_OK;
|
|
if (!CIntListCheck::AllocateList(numItems))
|
|
return E_OUTOFMEMORY;
|
|
_numItems = numItems;
|
|
return Semaphore.Create(0, numItems);
|
|
}
|
|
|
|
void FreeList()
|
|
{
|
|
CIntListCheck::FreeList();
|
|
_numItems = 0;
|
|
_head = 0;
|
|
_cur = 0;
|
|
}
|
|
|
|
void AddItem(int value)
|
|
{
|
|
_data[_head++] = value;
|
|
if (_head == _numItems)
|
|
_head = 0;
|
|
Semaphore.Release();
|
|
// printf("\nRelease prev = %d\n", previousCount);
|
|
}
|
|
|
|
int GetItem()
|
|
{
|
|
// Semaphore.Lock();
|
|
int res = _data[_cur++];
|
|
if (_cur == _numItems)
|
|
_cur = 0;
|
|
return res;
|
|
}
|
|
};
|
|
|
|
struct IInMemStreamMtCallback
|
|
{
|
|
// must be same for all calls
|
|
virtual size_t GetBlockSize() = 0;
|
|
|
|
// Out:
|
|
// result != S_OK stops Reading
|
|
// if *p = 0, result must be != S_OK;
|
|
// Locking is allowed
|
|
virtual HRESULT AllocateBlock(void **p) = 0;
|
|
|
|
virtual void FreeBlock(void *p) = 0;
|
|
|
|
// It must allow to add at least numSubStreams + 1 ,
|
|
// where numSubStreams is value from CInMemStreamMt::Create
|
|
// value -1 means End of stream
|
|
// Locking is not allowed
|
|
virtual void AddStreamIndexToQueue(int index) = 0;
|
|
};
|
|
|
|
struct CStreamInfo
|
|
{
|
|
CRecordVector<void *> Blocks;
|
|
|
|
int LastBlockIndex;
|
|
size_t LastBlockPos;
|
|
bool StreamWasFinished;
|
|
|
|
int CurBlockIndex;
|
|
size_t CurBlockPos;
|
|
|
|
NWindows::NSynchronization::CCriticalSection *Cs;
|
|
NWindows::NSynchronization::CManualResetEvent *CanReadEvent;
|
|
|
|
HRESULT ExitResult;
|
|
|
|
CStreamInfo(): Cs(0), CanReadEvent(0), StreamWasFinished(false) { }
|
|
~CStreamInfo()
|
|
{
|
|
delete Cs;
|
|
delete CanReadEvent;
|
|
// Free();
|
|
}
|
|
void Create()
|
|
{
|
|
Cs = new NWindows::NSynchronization::CCriticalSection;
|
|
CanReadEvent = new NWindows::NSynchronization::CManualResetEvent;
|
|
}
|
|
|
|
void Free(IInMemStreamMtCallback *callback);
|
|
void Init()
|
|
{
|
|
LastBlockIndex = CurBlockIndex = 0;
|
|
CurBlockPos = LastBlockPos = 0;
|
|
StreamWasFinished = false;
|
|
ExitResult = S_OK;
|
|
}
|
|
|
|
// res must be != S_OK
|
|
void Exit(HRESULT res)
|
|
{
|
|
ExitResult = res;
|
|
CanReadEvent->Set();
|
|
}
|
|
};
|
|
|
|
|
|
class CInMemStreamMt
|
|
{
|
|
CMyComPtr<ISequentialInStream> _stream;
|
|
NWindows::NSynchronization::CCriticalSection CS;
|
|
CObjectVector<CStreamInfo> _streams;
|
|
int _nextFreeStreamIndex;
|
|
int _currentStreamIndex;
|
|
UInt64 _subStreamSize;
|
|
|
|
CResourceListMt _streamIndexAllocator;
|
|
|
|
// bool _stopReading;
|
|
|
|
public:
|
|
HRESULT Read();
|
|
HRESULT ReadResult;
|
|
IInMemStreamMtCallback *Callback;
|
|
void FreeSubStream(int subStreamIndex);
|
|
HRESULT ReadSubStream(int subStreamIndex, void *data, UInt32 size, UInt32 *processedSize, bool keepData);
|
|
|
|
// numSubStreams: min = 1, good min = numThreads
|
|
bool Create(int numSubStreams, UInt64 subStreamSize);
|
|
~CInMemStreamMt() { Free(); }
|
|
void SetStream(ISequentialInStream *stream) { _stream = stream; }
|
|
|
|
// to stop reading you must implement
|
|
// returning Error in IInMemStreamMtCallback::AllocateBlock
|
|
// and then you must free at least one substream
|
|
HRes StartReadThread();
|
|
|
|
void Free();
|
|
|
|
// you must free at least one substream after that function to unlock waiting.
|
|
// void StopReading() { _stopReading = true; }
|
|
};
|
|
|
|
class CInMemStream:
|
|
public ISequentialInStream,
|
|
public CMyUnknownImp
|
|
{
|
|
UInt64 _size;
|
|
bool _keepData;
|
|
public:
|
|
int Index;
|
|
CInMemStreamMt *mtStream;
|
|
void Init(bool keepData = false)
|
|
{
|
|
_size = 0; _keepData = keepData ;
|
|
}
|
|
MY_UNKNOWN_IMP
|
|
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
|
UInt64 GetSize() const { return _size; }
|
|
};
|
|
|
|
#endif
|