示例#1
0
CCompressionProcessor::EStatus CZipCompressor::Process(
    const char* in_buf,  size_t  in_len,
    char*       out_buf, size_t  out_size,
    /* out */            size_t* in_avail,
    /* out */            size_t* out_avail)
{
    *out_avail = 0;
    if (in_len > kMax_UInt) {
        SetError(Z_STREAM_ERROR, "size of the source buffer is too big");
        ERR_COMPRESS(61, FormatErrorMessage("CZipCompressor::Process", GetProcessedSize()));
        return eStatus_Error;
    }
    if ( !out_size ) {
        return eStatus_Overflow;
    }
    LIMIT_SIZE_PARAM_U(out_size);

    size_t header_len = 0;

    // Write gzip file header
    if ( F_ISSET(fWriteGZipFormat)  &&  m_NeedWriteHeader ) {
        header_len = s_WriteGZipHeader(out_buf, out_size, &m_FileInfo);
        if (!header_len) {
            SetError(-1, "Cannot write gzip header");
            ERR_COMPRESS(62, FormatErrorMessage("CZipCompressor::Process", GetProcessedSize()));
            return eStatus_Error;
        }
        m_NeedWriteHeader = false;
    }
    STREAM->next_in   = (unsigned char*)const_cast<char*>(in_buf);
    STREAM->avail_in  = (unsigned int)in_len;
    STREAM->next_out  = (unsigned char*)out_buf + header_len;
    STREAM->avail_out = (unsigned int)(out_size - header_len);

    int errcode = deflate(STREAM, Z_NO_FLUSH);
    SetError(errcode, zError(errcode));
    *in_avail  = STREAM->avail_in;
    *out_avail = out_size - STREAM->avail_out;
    IncreaseProcessedSize((unsigned long)(in_len - *in_avail));
    IncreaseOutputSize((unsigned long)(*out_avail));

    // If we writing in gzip file format
    if ( F_ISSET(fWriteGZipFormat) ) {
        // Update the CRC32 for processed data
        m_CRC32 = crc32(m_CRC32, (unsigned char*)in_buf,
                        (unsigned int)(in_len - *in_avail));
    }
    if ( errcode == Z_OK ) {
        return eStatus_Success;
    }
    ERR_COMPRESS(63, FormatErrorMessage("CZipCompressor::Process", GetProcessedSize()));
    return eStatus_Error;
}
示例#2
0
CCompressionProcessor::EStatus CZipCompressor::Finish(
    char* out_buf, size_t  out_size,
    /* out */      size_t* out_avail)
{
    *out_avail = 0;
    if ( !out_size ) {
        return eStatus_Overflow;
    }
    LIMIT_SIZE_PARAM_U(out_size);

    // Default behavior on empty data -- don't write header/footer
    if ( !GetProcessedSize()  &&  !F_ISSET(fAllowEmptyData) ) {
        return eStatus_EndOfData;
    }

    // Write gzip file header if not done yet
    size_t header_len = 0;
    if ( F_ISSET(fWriteGZipFormat)  &&  m_NeedWriteHeader ) {
        header_len = s_WriteGZipHeader(out_buf, out_size, &m_FileInfo);
        if (!header_len) {
            SetError(-1, "Cannot write gzip header");
            return eStatus_Overflow;
        }
        // IncreaseOutputSize()
        // -- will be called below, and it will count 'header_len'
        m_NeedWriteHeader = false;
    }

    // Finish compression
    STREAM->next_in   = 0;
    STREAM->avail_in  = 0;
    STREAM->next_out  = (unsigned char*)out_buf + header_len;
    STREAM->avail_out = (unsigned int)(out_size - header_len);

    int errcode = deflate(STREAM, Z_FINISH);
    SetError(errcode, zError(errcode));
    *out_avail = out_size - STREAM->avail_out;
    IncreaseOutputSize((unsigned long)(*out_avail));

    switch (errcode) {
    case Z_OK:
        return eStatus_Overflow;
    case Z_STREAM_END:
        // Write .gz file footer
        if ( F_ISSET(fWriteGZipFormat) ) {
            size_t footer_len =
                s_WriteGZipFooter(out_buf + *out_avail, STREAM->avail_out,
                                  GetProcessedSize(), m_CRC32);
            if ( !footer_len ) {
                SetError(-1, "Cannot write gzip footer");
                return eStatus_Overflow;
            }
            IncreaseOutputSize((unsigned long)footer_len);
            *out_avail += footer_len;
        }
        return eStatus_EndOfData;
    }
    ERR_COMPRESS(66, FormatErrorMessage("CZipCompressor::Finish", GetProcessedSize()));
    return eStatus_Error;
}
示例#3
0
CCompressionProcessor::EStatus CZipCompressor::Init(void)
{
    if ( IsBusy() ) {
        // Abnormal previous session termination
        End();
    }
    // Initialize members
    Reset();
    SetBusy();

    m_CRC32 = 0;
    m_NeedWriteHeader = true;
    m_Cache.erase();

    // Initialize the compressor stream structure
    memset(STREAM, 0, sizeof(z_stream));
    // Create a compressor stream
    int errcode = deflateInit2_(STREAM, GetLevel(), Z_DEFLATED,
                                F_ISSET(fWriteGZipFormat) ? -m_WindowBits :
                                m_WindowBits,
                                m_MemLevel, m_Strategy,
                                ZLIB_VERSION, (int)sizeof(z_stream));
    SetError(errcode, zError(errcode));
    if ( errcode == Z_OK ) {
        return eStatus_Success;
    }
    ERR_COMPRESS(60, FormatErrorMessage("CZipCompressor::Init", GetProcessedSize()));
    return eStatus_Error;
}
示例#4
0
CCompressionProcessor::EStatus CZipDecompressor::Init(void)
{
    // Initialize members
    Reset();
    SetBusy();
    m_NeedCheckHeader = true;
    m_IsGZ = false;
    m_SkipInput = 0;
    m_Cache.erase();
    m_Cache.reserve(kMaxHeaderSize);

    // Initialize the compressor stream structure
    memset(STREAM, 0, sizeof(z_stream));
    // Create a compressor stream
    int errcode = inflateInit2_(STREAM, m_WindowBits,
                                ZLIB_VERSION, (int)sizeof(z_stream));

    SetError(errcode, zError(errcode));

    if ( errcode == Z_OK ) {
        return eStatus_Success;
    }
    ERR_COMPRESS(68, FormatErrorMessage("CZipDecompressor::Init", GetProcessedSize()));
    return eStatus_Error;
}
示例#5
0
CCompressionProcessor::EStatus CZipCompressor::Flush(
    char* out_buf, size_t  out_size,
    /* out */      size_t* out_avail)
{
    *out_avail = 0;
    if ( !out_size ) {
        return eStatus_Overflow;
    }
    LIMIT_SIZE_PARAM_U(out_size);

    STREAM->next_in   = 0;
    STREAM->avail_in  = 0;
    STREAM->next_out  = (unsigned char*)out_buf;
    STREAM->avail_out = (unsigned int)out_size;

    int errcode = deflate(STREAM, Z_SYNC_FLUSH);
    SetError(errcode, zError(errcode));
    *out_avail = out_size - STREAM->avail_out;
    IncreaseOutputSize((unsigned long)(*out_avail));

    if ( errcode == Z_OK  ||  errcode == Z_BUF_ERROR ) {
        if ( STREAM->avail_out == 0) {
            return eStatus_Overflow;
        }
        return eStatus_Success;
    }
    ERR_COMPRESS(64, FormatErrorMessage("CZipCompressor::Flush", GetProcessedSize()));
    return eStatus_Error;
}
void AcceptCompleteOperation::Complete( AsyncOperationType )
{
	//accept connection
	while(true)
	{
		sockaddr_in addr;
		socklen_t addrLen = sizeof(addr);
		int newSock= accept( m_ListenSock, (sockaddr *)&addr, &addrLen );
		if( -1 == newSock )
		{
			int errNum = errno;
			if( EWOULDBLOCK == errNum )
			{
				return;
			}

			LOG_ERROR( logger, __FUNCTION__ << " failed to accept, " << FormatErrorMessage( errNum ) );
			return;
		}

		char ip[INET_ADDRSTRLEN];
		if( NULL == inet_ntop( AF_INET, &addr.sin_addr, ip, sizeof(ip) ) )
		{
			LOG_ERROR( logger, __FUNCTION__ << " failed to get ip in inet_ntop()!" );
		}

		//add this session
		Session* pSession = s_SessionMgr.CreateSession( newSock, ip, addr.sin_port );
		if( NULL == pSession )
		{
			LOG_ERROR( logger, __FUNCTION__ << " failed to create session!" );
		}

		//notify accept
		MsgType type;
		if ( ACCEPT_EXTERNAL == m_AcceptType )
		{
			type = MSG_ACCEPT_EXTERNAL;
		}
		else
		{
			type = MSG_ACCEPT_INTERNAL;
		}
		s_MsgQueue.InsertSimpleMsg( type, pSession->GetID(), pSession );

		//add sock to epoll set
		if( !s_Dispatcher.RegisterSocket( newSock, pSession->GetAsyncCompleteOperation() ) )
		{
			LOG_ERROR( logger, __FUNCTION__ << " failed to register sock!" );
			return;
		}
	}
}
示例#7
0
CCompressionProcessor::EStatus CZipDecompressor::End(int abandon)
{
    int errcode = inflateEnd(STREAM);
    SetBusy(false);
    if ( abandon ||
            m_DecompressMode == eMode_TransparentRead   ||
            errcode == Z_OK ) {
        return eStatus_Success;
    }
    ERR_COMPRESS(71, FormatErrorMessage("CZipDecompressor::End", GetProcessedSize()));
    return eStatus_Error;
}
示例#8
0
文件: Semaph.cpp 项目: mjssw/crux-net
void Semaph::Post()
{
	if( 0 == ReleaseSemaphore(
		m_Sem,
		1,
		NULL
		)
		)
	{
		LOG_ERROR( logger, __FUNCTION__ << " failed ReleaseSemaphore(), " << FormatErrorMessage( GetLastError() ) );
	}
}
示例#9
0
void WorkerThread::Run()
{
	BOOL ret = FALSE;
	DWORD bytesTransferred = 0;
	AsyncCompleteOperation* pCompleteOperation = NULL;
	void* pCompletionKey = NULL;

	while( Runnable() )
	{
		ret = GetQueuedCompletionStatus(
			s_Dispatcher.GetIOCPHandle(),
			&bytesTransferred,
			(PULONG_PTR)&pCompletionKey,
			(LPOVERLAPPED*)&pCompleteOperation,
			INFINITE
			);

		if ( FALSE == ret )
		{
			LOG_ERROR( logger, __FUNCTION__ << " failed GetQueuedCompletionStatus(), " << FormatErrorMessage( WSAGetLastError() ) );

			if ( NULL != pCompletionKey )
			{
				pCompleteOperation->Close( static_cast<Session*>( pCompletionKey ) );
			}
			continue;
		}
		
 		if ( 0 == bytesTransferred )
 		{
			//if NULL == pCompletionKey and NULL == pCompleteOperation,
			//	it means worker thread is being stopped.
			if ( !Runnable() && NULL == pCompletionKey && NULL == pCompleteOperation )
			{
				break;				
			}

			//if NULL != pCompletionKey, the pCompletionKey points to a Session
			//if NULL == pCompletionKey, the asynchronous operation is an accept complete operation, 
			//	we should use Complete operation to accept this new session, not Close
			if ( NULL != pCompletionKey )
			{
				pCompleteOperation->Close( static_cast<Session*>( pCompletionKey ) );
				continue;
			}
 		}

		pCompleteOperation->Complete( static_cast<Session*>( pCompletionKey ) );
	}

	LOG_INFO( logger, "exit thread" );
}
示例#10
0
文件: Semaph.cpp 项目: mjssw/crux-net
Semaph::Semaph()
{
	//the initial value of the semaphore is 0
	m_Sem = CreateSemaphore(
		NULL,
		0,
		(std::numeric_limits<long>::max)(),
		NULL
		);
	if ( NULL == m_Sem )
	{
		LOG_ERROR( logger, __FUNCTION__ << " failed CreateSemaphore(), " << FormatErrorMessage( GetLastError() ) );
	}
}
示例#11
0
CCompressionProcessor::EStatus CZipCompressor::End(int abandon)
{
    int errcode = deflateEnd(STREAM);
    SetBusy(false);
    if (abandon) {
        // Ignore result of deflateEnd(), because it can return an error code for empty data
        return eStatus_Success;
    }
    SetError(errcode, zError(errcode));
    if ( errcode == Z_OK ) {
        return eStatus_Success;
    }
    ERR_COMPRESS(67, FormatErrorMessage("CZipCompressor::End", GetProcessedSize()));
    return eStatus_Error;
}
示例#12
0
void SessionMgr::DestroyAllSessions()
{
	SESSION_MAP::iterator it = m_Sessions.begin();
	SESSION_MAP::iterator end = m_Sessions.end();
	for (; end != it; ++it )
	{
		if ( NULL != it->second )
		{
			if( SessionActive( it->second->GetID() ) )
			{
#ifdef WIN32
				if( SOCKET_ERROR == closesocket( it->second->GetSock() ) )
				{
					int errNum = WSAGetLastError();
#elif defined(LINUX)
				if( -1 == close( it->second->GetSock() ) )
				{
					int errNum = errno;
#endif
					LOG_INFO( logger, __FUNCTION__ 
							<< " failed to close socket, session id:" << it->second->GetID()
							<< ", socket: " << it->second->GetSock()
							<< ", " << FormatErrorMessage( errNum )
						   	);
				}

			}
			DestroySession( it->second );
		}
	}	
}

int SessionMgr::GenerateSessionID()
{
	MutexGuard guard( m_pMutex );

	int sessionID = 0;
	if( !m_pFreeSessionID->Top( sessionID ) )
	{
		return 0;
	}

	SetSessionActiveImpl( sessionID, true );

	m_pFreeSessionID->Pop();

	return sessionID;
}
		//****************************************************************
		// Classic BioSIM DoSimulation
		DllExport int RunModelFile(char * infoFilePath, char errorMessage[1024])
		{
			ERMsg msg;

			CBioSIMModelBase* pModel = CModelFactory::CreateObject();
			ASSERT(pModel);

			try
			{
				msg = pModel->Init(infoFilePath);

				if (msg)
				{
					//msg = pModel->OpenOutputFile();

					//if( msg )
					//{
					msg = pModel->Execute();
					if (msg&&pModel->HaveOutput())
						pModel->SaveOutputFile();

					//pModel->CloseOutputFile();
					//}
				}
			}
			catch (ERMsg e)
			{
				msg = e;
			}
			catch (...)
			{
				msg = GetErrorMessage(0);
			}


			delete pModel; pModel = NULL;
			return FormatErrorMessage(msg, errorMessage);
		}
		DllExport  bool __cdecl InitSimulatedAnnealing(__int32 sessionId, IGenericStream* pStream, char* errorMessage)
		{
			ERMsg msg = BeginSession(NULL, sessionId, -1, pStream);
			return FormatErrorMessage(msg, errorMessage);
		}
示例#15
0
bool CZipCompression::DecompressBuffer(
    const void* src_buf, size_t  src_len,
    void*       dst_buf, size_t  dst_size,
    /* out */            size_t* dst_len)
{
    *dst_len = 0;

    // Check parameters
    if ( !src_len ) {
        if ( F_ISSET(fAllowEmptyData) ) {
            SetError(Z_OK);
            return true;
        }
        src_buf = NULL;
    }
    if ( !src_buf ) {
        SetError(Z_STREAM_ERROR, "bad argument");
        ERR_COMPRESS(55, FormatErrorMessage("CZipCompression::DecompressBuffer"));
        return false;
    }
    if ( !dst_buf || !dst_len ) {
        SetError(Z_STREAM_ERROR, "bad argument");
        ERR_COMPRESS(55, FormatErrorMessage("CZipCompression::DecompressBuffer"));
        return false;
    }
    if (src_len > kMax_UInt) {
        SetError(Z_STREAM_ERROR, "size of the source buffer is too big");
        ERR_COMPRESS(56, FormatErrorMessage("CZipCompression::DecompressBuffer"));
        return false;
    }
    LIMIT_SIZE_PARAM_U(dst_size);

    //
    bool is_gzip = false;
    bool check_header = true;
    int  errcode = Z_OK;

    // Pointers to current positions in src and dst buffers
    unsigned char* src = (unsigned char*)src_buf;
    unsigned char* dst = (unsigned char*)dst_buf;

    do {
        // Check file header
        size_t header_len = 0;
        if ( F_ISSET(fCheckFileHeader)  &&  check_header) {
            // Check gzip header in the buffer
            header_len = s_CheckGZipHeader(src_buf, src_len);
            src += header_len;
            src_len -= header_len;
        }
        STREAM->next_in   = src;
        STREAM->avail_in  = (unsigned int)src_len;
        STREAM->next_out  = dst;
        STREAM->avail_out = (unsigned int)dst_size;
        STREAM->zalloc    = (alloc_func)0;
        STREAM->zfree     = (free_func)0;

        // "window bits" is passed < 0 to tell that there is no zlib header.
        // Note that in this case inflate *requires* an extra "dummy" byte
        // after the compressed stream in order to complete decompression and
        // return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
        // present after the compressed stream.

        errcode = inflateInit2_(STREAM, header_len ? -m_WindowBits :m_WindowBits,
                                ZLIB_VERSION, (int)sizeof(z_stream));

        if (errcode != Z_OK) {
            break;
        }
        errcode = inflate(STREAM, Z_FINISH);
        *dst_len += STREAM->total_out;

        // Is decompresion sucess?
        if (errcode == Z_STREAM_END) {
            is_gzip = (header_len > 0);
            check_header = F_ISSET(fCheckFileHeader | fAllowConcatenatedGZip);
            if ( check_header ) {
                src      = STREAM->next_in + 8;
                src_len  = (STREAM->avail_in < 8) ? 0 : (STREAM->avail_in - 8);
                dst      += STREAM->total_out;
                dst_size = STREAM->avail_out;
            } else {
                src_len = 0;
            }
            errcode = inflateEnd(STREAM);
        } else {
            // Error -- end decompression
            inflateEnd(STREAM);
            if ( errcode == Z_OK ) {
                // Possible incomplete input data
                errcode = Z_BUF_ERROR;
            } else {
                // Decompression error
                if (!is_gzip  &&  F_ISSET(fAllowTransparentRead)) {
                    // But transparent read is allowed
                    *dst_len = (dst_size < src_len) ? dst_size : src_len;
                    memcpy(dst_buf, src_buf, *dst_len);
                    return (dst_size >= src_len);
                }
                // Error
                break;
            }
        }
    } while (is_gzip  &&  src_len);

    // Decompression results processing
    SetError(errcode, zError(errcode));
    if ( errcode != Z_OK ) {
        ERR_COMPRESS(59, FormatErrorMessage
                     ("CZipCompression::DecompressBuffer", (unsigned long)
                      (STREAM->next_in - (unsigned char*) src_buf)));
        return false;
    }
    return true;
}
示例#16
0
bool CZipCompression::CompressBuffer(
    const void* src_buf, size_t  src_len,
    void*       dst_buf, size_t  dst_size,
    /* out */            size_t* dst_len)
{
    *dst_len = 0;

    // Check parameters
    if ( !src_len ) {
        if (!F_ISSET(fAllowEmptyData)) {
            src_buf = NULL;
        }
    }
    if ( !src_buf ) {
        SetError(Z_STREAM_ERROR, "bad argument");
        ERR_COMPRESS(48, FormatErrorMessage("CZipCompression::CompressBuffer"));
        return false;
    }
    if ( !dst_buf || !dst_len ) {
        SetError(Z_STREAM_ERROR, "bad argument");
        ERR_COMPRESS(48, FormatErrorMessage("CZipCompression::CompressBuffer"));
        return false;
    }
    if (src_len > kMax_UInt) {
        SetError(Z_STREAM_ERROR, "size of the source buffer is too big");
        ERR_COMPRESS(49, FormatErrorMessage("CZipCompression::CompressBuffer"));
        return false;
    }
    LIMIT_SIZE_PARAM_U(dst_size);

    size_t header_len = 0;
    int    errcode    = Z_OK;

    // Write gzip file header
    if ( F_ISSET(fWriteGZipFormat) ) {
        header_len = s_WriteGZipHeader(dst_buf, dst_size);
        if (!header_len) {
            SetError(Z_STREAM_ERROR, "Cannot write gzip header");
            ERR_COMPRESS(50, FormatErrorMessage("CZipCompression::CompressBuffer"));
            return false;
        }
    }

    STREAM->next_in  = (unsigned char*)src_buf;
    STREAM->avail_in = (unsigned int)src_len;
#ifdef MAXSEG_64K
    // Check for source > 64K on 16-bit machine:
    if ( STREAM->avail_in != src_len ) {
        SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR));
        ERR_COMPRESS(51, FormatErrorMessage("CZipCompression::CompressBuffer"));
        return false;
    }
#endif
    STREAM->next_out = (unsigned char*)dst_buf + header_len;
    STREAM->avail_out = (unsigned int)(dst_size - header_len);
    if ( STREAM->avail_out != dst_size - header_len ) {
        SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR));
        ERR_COMPRESS(52, FormatErrorMessage("CZipCompression::CompressBuffer"));
        return false;
    }

    STREAM->zalloc = (alloc_func)0;
    STREAM->zfree  = (free_func)0;
    STREAM->opaque = (voidpf)0;

    errcode = deflateInit2_(STREAM, GetLevel(), Z_DEFLATED,
                            header_len ? -m_WindowBits : m_WindowBits,
                            m_MemLevel, m_Strategy,
                            ZLIB_VERSION, (int)sizeof(z_stream));
    if (errcode == Z_OK) {
        errcode = deflate(STREAM, Z_FINISH);
        *dst_len = STREAM->total_out + header_len;
        if (errcode == Z_STREAM_END) {
            errcode = deflateEnd(STREAM);
        } else {
            if ( errcode == Z_OK ) {
                errcode = Z_BUF_ERROR;
            }
            deflateEnd(STREAM);
        }
    }
    SetError(errcode, zError(errcode));
    if ( errcode != Z_OK ) {
        ERR_COMPRESS(53, FormatErrorMessage("CZipCompression::CompressBuffer"));
        return false;
    }

    // Write gzip file footer
    if ( F_ISSET(fWriteGZipFormat) ) {
        unsigned long crc = crc32(0L, (unsigned char*)src_buf,
                                  (unsigned int)src_len);
        size_t footer_len = s_WriteGZipFooter(
                                (char*)dst_buf + *dst_len, dst_size, (unsigned long)src_len, crc);
        if ( !footer_len ) {
            SetError(-1, "Cannot write gzip footer");
            ERR_COMPRESS(54, FormatErrorMessage("CZipCompressor::CompressBuffer"));
            return false;
        }
        *dst_len += footer_len;
    }
    return true;
}
示例#17
0
std::string JSONReader::GetErrorMessage() const
{
    return FormatErrorMessage(error_line_, error_col_,
                              ErrorCodeToString(error_code_));
}
示例#18
0
CCompressionProcessor::EStatus CZipDecompressor::Process(
    const char* in_buf,  size_t  in_len,
    char*       out_buf, size_t  out_size,
    /* out */            size_t* in_avail,
    /* out */            size_t* out_avail)
{
    *out_avail = 0;
    if (in_len > kMax_UInt) {
        SetError(Z_STREAM_ERROR, "size of the source buffer is too big");
        ERR_COMPRESS(69, FormatErrorMessage("CZipDecompressor::Process", GetProcessedSize()));
        return eStatus_Error;
    }
    if ( !out_size ) {
        return eStatus_Overflow;
    }
    LIMIT_SIZE_PARAM_U(out_size);

    // By default we consider that data is compressed
    if ( m_DecompressMode == eMode_Unknown  &&
            !F_ISSET(fAllowTransparentRead) ) {
        m_DecompressMode = eMode_Decompress;
    }

    char*  x_in_buf = const_cast<char*>(in_buf);
    size_t x_in_len = in_len;

    // If data is compressed, or the read mode is undefined yet
    if ( m_DecompressMode != eMode_TransparentRead ) {

        // Need to skip some bytes from input stream?
        // (in case of concatenated .gz files only)
        if ( m_SkipInput ) {
            // Skip from cache if present
            if ( m_Cache.size() ) {
                size_t n = min(m_Cache.size(), m_SkipInput);
                m_Cache.erase(0, n);
                m_SkipInput -= n;
                IncreaseProcessedSize((unsigned long)n);
            }
            // And/or from input stream also
            if ( m_SkipInput ) {
                size_t n = min(x_in_len, m_SkipInput);
                x_in_buf += n;
                x_in_len -= n;
                m_SkipInput -= n;
                IncreaseProcessedSize((unsigned long)n);
                if ( m_SkipInput ) {
                    // Data block is very small... and was skipped.
                    *in_avail  = x_in_len;
                    *out_avail = 0;
                    return eStatus_Success;
                }
            }
        }

        bool   from_cache   = false;
        size_t old_avail_in = 0;

        // Check file header
        if ( F_ISSET(fCheckFileHeader) ) {
            size_t header_len = 0;
            if ( m_NeedCheckHeader ) {
                if (!x_in_buf  &&  !m_Cache.size()) {
                    // Possible Flush(), but we should refill the cache
                    // to perform header check -- so, just ignore.
                    *in_avail  = 0;
                    *out_avail = 0;
                    return eStatus_Success;
                }
                if (x_in_buf  &&  m_Cache.size() < kMaxHeaderSize) {
                    size_t n = min(kMaxHeaderSize - m_Cache.size(), x_in_len);
                    m_Cache.append(x_in_buf, n);
                    x_in_buf += n;
                    x_in_len -= n;
                    if (m_Cache.size() < kMaxHeaderSize) {
                        // Data block is very small and was fully cached.
                        *in_avail  = 0;
                        *out_avail = 0;
                        return eStatus_Success;
                    }
                }
                // Check gzip header in the buffer
                header_len = s_CheckGZipHeader(m_Cache.data(), m_Cache.size());
                _ASSERT(header_len < kMaxHeaderSize);

                // If gzip header found, skip it
                if ( header_len ) {
                    m_Cache.erase(0, header_len);
                    IncreaseProcessedSize((unsigned long)header_len);
                    m_DecompressMode = eMode_Decompress;
                    m_IsGZ = true;
                }
                // Reinit decompression stream
                inflateEnd(STREAM);
                int errcode = inflateInit2_(STREAM,
                                            m_IsGZ ? -m_WindowBits : m_WindowBits,
                                            ZLIB_VERSION,
                                            (int)sizeof(z_stream));
                SetError(errcode, zError(errcode));
                if ( errcode != Z_OK ) {
                    return eStatus_Error;
                }
                // Already skipped, or we don't have header here
                m_NeedCheckHeader = false;
            }
        }

        // Prepare STREAM for decompressing
        if ( m_Cache.size() ) {
            // Possible, we have some unprocessed data in the cache
            STREAM->next_in   = (unsigned char*)(m_Cache.data());
            STREAM->avail_in  = (unsigned int)m_Cache.size();
            STREAM->next_out  = (unsigned char*)out_buf;
            STREAM->avail_out = (unsigned int)out_size;
            from_cache        = true;
            old_avail_in      = STREAM->avail_in; // = m_Cache.size()
        } else {
            STREAM->next_in   = (unsigned char*)x_in_buf;
            STREAM->avail_in  = (unsigned int)x_in_len;
            STREAM->next_out  = (unsigned char*)out_buf;
            STREAM->avail_out = (unsigned int)out_size;
        }

        // Try to decompress data
        int errcode = inflate(STREAM, Z_SYNC_FLUSH);

        if ( m_DecompressMode == eMode_Unknown ) {
            // The flag fAllowTransparentRead is set
            _ASSERT(F_ISSET(fAllowTransparentRead));
            // Determine decompression mode for following operations
            if (errcode == Z_OK  ||  errcode == Z_STREAM_END) {
                m_DecompressMode = eMode_Decompress;
            } else {
                m_DecompressMode = eMode_TransparentRead;
            }
        }
        if ( m_DecompressMode == eMode_Decompress ) {
            SetError(errcode, zError(errcode));

            // Concatenated file? Try to process next .gz chunk, if present
            if ((errcode == Z_STREAM_END)  &&  m_IsGZ) {
                // Skip .gz file footer (8 bytes)
                if (STREAM->avail_in < 8) {
                    m_SkipInput = 8 - STREAM->avail_in;
                    STREAM->avail_in = 0;
                } else {
                    STREAM->avail_in -= 8;
                }
                if ( F_ISSET(fAllowConcatenatedGZip) ) {
                    m_NeedCheckHeader = true;
                    errcode = Z_OK;
                }
            }
            // Update count of processed data
            if ( from_cache ) {
                m_Cache.erase(0, old_avail_in - STREAM->avail_in);
                *in_avail = x_in_len;
                IncreaseProcessedSize((unsigned long)(old_avail_in - STREAM->avail_in));
            } else {
                *in_avail = STREAM->avail_in;
                IncreaseProcessedSize((unsigned long)(x_in_len - *in_avail));
                x_in_len = *in_avail;
            }
            // In case of concatenated .gz files:
            // Possible, we already skipped some bytes from cache,
            // and it should be empty now. If needed, try to skip some
            // bytes from the input stream also.
            if ( m_SkipInput ) {
                _ASSERT(m_Cache.size() == 0);
                size_t n = min(x_in_len, m_SkipInput);
                if ( n ) {
                    x_in_len -= n;
                    m_SkipInput -= n;
                    *in_avail = x_in_len;
                    IncreaseProcessedSize((unsigned long)n);
                }
            }
            *out_avail = out_size - STREAM->avail_out;
            IncreaseOutputSize((unsigned long)(*out_avail));

            // Analyze decompressor status
            switch (errcode) {
            case Z_OK:
                if ( from_cache  &&
                        STREAM->avail_in > 0  &&  *out_avail == 0) {
                    return m_NeedCheckHeader ? eStatus_Repeat : eStatus_Overflow;
                }
                return eStatus_Success;
            case Z_STREAM_END:
                return eStatus_EndOfData;
            }
            ERR_COMPRESS(70, FormatErrorMessage("CZipDecompressor::Process", GetProcessedSize()));
            return eStatus_Error;
        }
        /* else: eMode_ThansparentRead (see below) */
    }

    // Transparent read

    _ASSERT(m_DecompressMode == eMode_TransparentRead);
    size_t total = 0;
    if ( m_Cache.size() ) {
        total = min(m_Cache.size(), out_size);
        memcpy(out_buf, m_Cache.data(), total);
        m_Cache.erase(0, total);
        out_size -= total;
    }
    if (x_in_len  &&  out_size)  {
        size_t n = min(x_in_len, out_size);
        memcpy(out_buf + total, x_in_buf, n);
        total += n;
        x_in_len -= n;
    }
    *in_avail  = x_in_len;
    *out_avail = total;
    IncreaseProcessedSize((unsigned long)total);
    IncreaseOutputSize((unsigned long)total);
    return eStatus_Success;
}