You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
7.1 KiB
C++
252 lines
7.1 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : zlib inflate wrapper
|
|
|
|
|
|
#include "CrySystem_precompiled.h"
|
|
|
|
#include "CryZlib.h"
|
|
#include "ZLibDecompressor.h"
|
|
|
|
class CZLibInflateStream
|
|
: public IZLibInflateStream
|
|
{
|
|
public:
|
|
CZLibInflateStream()
|
|
: m_bStreamOpened(false)
|
|
, m_zlibFlush(0)
|
|
, m_currentState(eZInfState_AwaitingInput)
|
|
, m_bytesInput(0)
|
|
, m_bytesOutput(0)
|
|
, m_zSize(0)
|
|
, m_zPeak(0) {}
|
|
|
|
virtual void Release();
|
|
|
|
virtual void SetOutputBuffer(char* pInBuffer, unsigned int inSize);
|
|
virtual unsigned int GetBytesOutput();
|
|
virtual void Input(const char* pInSource, unsigned int inSourceSize);
|
|
virtual void EndInput();
|
|
virtual EZInflateState GetState();
|
|
virtual void GetStats(IZLibInflateStream::SStats* pOutStats);
|
|
|
|
private:
|
|
virtual ~CZLibInflateStream() {}
|
|
|
|
EZInflateState RunInflate();
|
|
|
|
static voidpf ZAlloc(voidpf pInOpaque, uInt inItems, uInt inSize);
|
|
static void ZFree(voidpf pInOpaque, voidpf pInAddress);
|
|
|
|
z_stream m_decompressStream;
|
|
bool m_bStreamOpened;
|
|
int m_zlibFlush;
|
|
EZInflateState m_currentState;
|
|
unsigned int m_bytesInput;
|
|
unsigned int m_bytesOutput;
|
|
unsigned int m_zSize;
|
|
unsigned int m_zPeak;
|
|
};
|
|
|
|
IZLibInflateStream* CZLibDecompressor::CreateInflateStream()
|
|
{
|
|
return new CZLibInflateStream();
|
|
}
|
|
|
|
void CZLibDecompressor::Release()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
void CZLibInflateStream::Release()
|
|
{
|
|
if (m_bStreamOpened)
|
|
{
|
|
int err = inflateEnd(&m_decompressStream);
|
|
if (err != Z_OK)
|
|
{
|
|
CryLog("zlib inflateEnd() error %d returned when closing stream", err);
|
|
}
|
|
}
|
|
|
|
delete this;
|
|
}
|
|
|
|
void CZLibInflateStream::SetOutputBuffer(char* pInBuffer, unsigned int inSize)
|
|
{
|
|
m_bytesOutput += m_decompressStream.total_out;
|
|
|
|
m_decompressStream.next_out = (byte*)pInBuffer;
|
|
m_decompressStream.avail_out = inSize;
|
|
m_decompressStream.total_out = 0;
|
|
}
|
|
|
|
void CZLibInflateStream::GetStats(IZLibInflateStream::SStats* pOutStats)
|
|
{
|
|
pOutStats->bytesInput = m_bytesInput;
|
|
pOutStats->bytesOutput = m_bytesOutput + m_decompressStream.total_out;
|
|
pOutStats->curMemoryUsed = m_zSize;
|
|
pOutStats->peakMemoryUsed = m_zPeak;
|
|
}
|
|
|
|
unsigned int CZLibInflateStream::GetBytesOutput()
|
|
{
|
|
return m_decompressStream.total_out;
|
|
}
|
|
|
|
void CZLibInflateStream::Input(const char* pInSource, unsigned int inSourceSize)
|
|
{
|
|
CRY_ASSERT_MESSAGE(m_currentState == eZInfState_AwaitingInput, "CZLibInflateStream::Input() called when stream is not awaiting input or has finished");
|
|
|
|
m_decompressStream.next_in = (Bytef*)pInSource;
|
|
m_decompressStream.avail_in = inSourceSize;
|
|
m_bytesInput += inSourceSize;
|
|
}
|
|
|
|
void CZLibInflateStream::EndInput()
|
|
{
|
|
CRY_ASSERT_MESSAGE(m_currentState == eZInfState_AwaitingInput, "CZLibInflateStream::EndInput() called when stream is not awaiting input");
|
|
|
|
m_zlibFlush = Z_FINISH;
|
|
}
|
|
|
|
voidpf CZLibInflateStream::ZAlloc(voidpf pInOpaque, uInt inItems, uInt inSize)
|
|
{
|
|
CZLibInflateStream* pStr = reinterpret_cast<CZLibInflateStream*>(pInOpaque);
|
|
|
|
const unsigned int size = inItems * inSize;
|
|
|
|
int* pPtr = (int*)CryModuleMalloc(sizeof(int) + size);
|
|
|
|
if (pPtr)
|
|
{
|
|
*pPtr = inItems * inSize;
|
|
pPtr += 1;
|
|
|
|
const unsigned int newSize = pStr->m_zSize + size;
|
|
pStr->m_zSize = newSize;
|
|
if (newSize > pStr->m_zPeak)
|
|
{
|
|
pStr->m_zPeak = newSize;
|
|
}
|
|
}
|
|
|
|
return pPtr;
|
|
}
|
|
|
|
void CZLibInflateStream::ZFree(voidpf pInOpaque, voidpf pInAddress)
|
|
{
|
|
int* pPtr = reinterpret_cast<int*>(pInAddress);
|
|
|
|
if (pPtr)
|
|
{
|
|
CZLibInflateStream* pStr = reinterpret_cast<CZLibInflateStream*>(pInOpaque);
|
|
pStr->m_zSize -= pPtr[-1];
|
|
CryModuleFree(pPtr - 1);
|
|
}
|
|
}
|
|
|
|
EZInflateState CZLibInflateStream::RunInflate()
|
|
{
|
|
bool runInflate = false;
|
|
bool inputAvailable = (m_decompressStream.avail_in > 0) || (m_zlibFlush == Z_FINISH);
|
|
bool outputAvailable = (m_decompressStream.avail_out > 0);
|
|
|
|
switch (m_currentState)
|
|
{
|
|
case eZInfState_AwaitingInput:
|
|
case eZInfState_ConsumeOutput:
|
|
if (inputAvailable && outputAvailable)
|
|
{
|
|
runInflate = true;
|
|
}
|
|
else if (inputAvailable || !outputAvailable)
|
|
{
|
|
m_currentState = eZInfState_ConsumeOutput;
|
|
}
|
|
else
|
|
{
|
|
m_currentState = eZInfState_AwaitingInput;
|
|
}
|
|
break;
|
|
|
|
case eZInfState_Inflating:
|
|
CRY_ASSERT_MESSAGE(false, "Shouldn't be trying to run inflate whilst a inflate is in progress");
|
|
break;
|
|
|
|
case eZInfState_Error:
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT_MESSAGE(false, "unknown state");
|
|
break;
|
|
}
|
|
|
|
if (runInflate)
|
|
{
|
|
if (!m_bStreamOpened)
|
|
{
|
|
m_bStreamOpened = true;
|
|
|
|
// initializing with inflateInit2 requires that the next_in be initialized
|
|
m_decompressStream.zalloc = &CZLibInflateStream::ZAlloc;
|
|
m_decompressStream.zfree = &CZLibInflateStream::ZFree;
|
|
m_decompressStream.opaque = this;
|
|
|
|
const int error = inflateInit2(&m_decompressStream, -MAX_WBITS);
|
|
if (error != Z_OK)
|
|
{
|
|
m_currentState = eZInfState_Error;
|
|
CryLog("zlib inflateInit2() error, err %d", error);
|
|
}
|
|
}
|
|
|
|
if (m_currentState != eZInfState_Error)
|
|
{
|
|
int error = inflate(&m_decompressStream, m_zlibFlush);
|
|
|
|
if (error == Z_STREAM_END)
|
|
{
|
|
// end of stream has been generated, only produced if we pass Z_FINISH into inflate
|
|
m_currentState = eZInfState_Finished;
|
|
}
|
|
else if ((error == Z_OK && m_decompressStream.avail_out == 0) || (error == Z_BUF_ERROR && m_decompressStream.avail_out == 0))
|
|
{
|
|
// output buffer has been filled
|
|
// data should be available for consumption by caller
|
|
m_currentState = eZInfState_ConsumeOutput;
|
|
}
|
|
else if (m_decompressStream.avail_in == 0)
|
|
{
|
|
// ran out of input data
|
|
// data may be available for consumption - but we need more input right now
|
|
m_currentState = eZInfState_AwaitingInput;
|
|
}
|
|
else
|
|
{
|
|
// some sort of error has occurred
|
|
m_currentState = eZInfState_Error;
|
|
CryLog("zlib inflate() error, err %d", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_currentState;
|
|
}
|
|
|
|
EZInflateState CZLibInflateStream::GetState()
|
|
{
|
|
return RunInflate();
|
|
}
|