BVB Source Codes

CRYENGINE Show XMLCPB_ZLibCompressor.cpp Source code

Return Download CRYENGINE: download XMLCPB_ZLibCompressor.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /*************************************************************************
  4. *************************************************************************/
  5.  
  6. #include "StdAfx.h"
  7. #include "XMLCPB_ZLibCompressor.h"
  8. #include "CryActionCVars.h"
  9. #include <CryThreading/IThreadManager.h>
  10. #include <CrySystem/ZLib/IZLibCompressor.h>
  11.  
  12. namespace XMLCPB
  13. {
  14.  
  15. class CFile
  16. {
  17.         friend class CCompressorThread;
  18.  
  19. public:
  20.  
  21.         CFile(CZLibCompressor* pCompressor, const char* pFileName, CryEvent& event)
  22.                 : m_pCompressor(pCompressor)
  23.                 , m_bytesWrittenIntoFile(0)
  24.                 , m_bytesWrittenIntoFileUncompressed(0)
  25.                 , m_bClosed(false)
  26.                 , m_event(event)
  27.         {
  28.                 m_startingTime = gEnv->pTimer->GetAsyncTime().GetMilliSeconds();
  29.  
  30. #ifdef XMLCPB_CHECK_FILE_INTEGRITY
  31.                 m_pICompressor = GetISystem()->GetIZLibCompressor();
  32.  
  33.                 if (m_pICompressor)
  34.                 {
  35.                         m_pICompressor->MD5Init(&m_MD5Context);
  36.                 }
  37.  
  38. #endif
  39.                
  40.                 m_pPlatformOSSaveWriter = gEnv->pSystem->GetPlatformOS()->SaveGetWriter(pFileName);
  41.         }
  42.  
  43.         ~CFile()
  44.         {
  45.                 delete m_pCompressor;
  46.         }
  47.  
  48.         void Close()
  49.         {
  50.                 m_bClosed = true;
  51.                 m_event.Set();
  52.         }
  53.  
  54.         void Finish()
  55.         {
  56. #ifdef XMLCPB_CHECK_FILE_INTEGRITY
  57.                 if (m_pICompressor)
  58.                 {
  59.                         m_pICompressor->MD5Update(&m_MD5Context, (const char*)(&m_pCompressor->m_fileHeader), sizeof(m_pCompressor->m_fileHeader));
  60.                         m_pICompressor->MD5Final(&m_MD5Context, m_pCompressor->m_fileHeader.m_MD5Signature);
  61.                 }
  62.                 else
  63.                 {
  64.                         memset(&m_pCompressor->m_fileHeader.m_MD5Signature, 0, sizeof(m_pCompressor->m_fileHeader.m_MD5Signature));
  65.                 }
  66. #endif
  67.  
  68.                 Write(&m_pCompressor->m_fileHeader, sizeof(m_pCompressor->m_fileHeader));
  69.  
  70.                 m_pPlatformOSSaveWriter->Close();
  71.  
  72.                 float finalTime = gEnv->pTimer->GetAsyncTime().GetMilliSeconds();
  73.  
  74.                 CryLog("[SAVE GAME] Binary saveload: After writing, result: %s   filesize/uncompressed: %u/%u (%u kb / %u kb)   generation time: %d ms ",
  75.                        (m_pCompressor->m_errorWritingIntoFile) ? "FAIL" : "SUCCESS", m_bytesWrittenIntoFile, m_bytesWrittenIntoFileUncompressed, m_bytesWrittenIntoFile / 1024, m_bytesWrittenIntoFileUncompressed / 1024, int(finalTime - m_startingTime));
  76.         }
  77.  
  78.         bool Write(void* pSrc, uint32 numBytes)
  79.         {
  80. #ifdef XMLCPB_CHECK_FILE_INTEGRITY
  81.                 if (m_pICompressor)
  82.                 {
  83.                         m_pICompressor->MD5Update(&m_MD5Context, (const char*)pSrc, numBytes);
  84.                 }
  85. #endif
  86.  
  87.                 IPlatformOS::EFileOperationCode code = m_pPlatformOSSaveWriter->AppendBytes(pSrc, numBytes);
  88.                 bool ok = (code == IPlatformOS::eFOC_Success);
  89.                 assert(ok);
  90.                 if (ok)
  91.                 {
  92.                         m_bytesWrittenIntoFile += numBytes;
  93.                         return true;
  94.                 }
  95.                 CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "CCompressorThread::WriteDataIntoFileInternal ERROR: failed to AppendBytes");
  96.                 return false;
  97.         }
  98.  
  99.         void AddBlock(SZLibBlock* block)
  100.         {
  101.                 m_blocks.push(block);
  102.                 m_event.Set();
  103.         }
  104.  
  105.         bool Closed() const { return m_bClosed; }
  106.  
  107. private:
  108.  
  109. #ifdef XMLCPB_CHECK_FILE_INTEGRITY
  110.         SMD5Context m_MD5Context;
  111.         IZLibCompressor* m_pICompressor;
  112. #endif
  113.         CZLibCompressor * m_pCompressor;
  114.         CryEvent&                                m_event;
  115.         IPlatformOS::ISaveWriterPtr              m_pPlatformOSSaveWriter;
  116.         CryMT::CLocklessPointerQueue<SZLibBlock> m_blocks;
  117.         uint32 m_bytesWrittenIntoFile;                                    // used for statistics only
  118.         uint32 m_bytesWrittenIntoFileUncompressed;                        // used for statistics only
  119.         float  m_startingTime;
  120.         bool   m_bClosed;
  121. };
  122.  
  123. class CCompressorThread : public IThread
  124. {
  125. public:
  126.  
  127.         CCompressorThread()
  128.                 : m_bCancelled(false), m_nBlockCount(0), m_nMaxQueuedBlocks(CCryActionCVars::Get().g_XMLCPBBlockQueueLimit)
  129.         {
  130.         }
  131.  
  132.         ~CCompressorThread()
  133.         {
  134.                 SignalStopWork();
  135.                 gEnv->pThreadManager->JoinThread(this, eJM_Join);
  136.         }
  137.  
  138.         // Start accepting work on thread
  139.         virtual void ThreadEntry()
  140.         {
  141.                 while (!m_bCancelled || !m_files.empty())
  142.                 {
  143.                         m_event.Wait();
  144.  
  145.                         uint8* pZLibCompressedBuffer = AllocateBlock();
  146.  
  147.                         while (!m_files.empty())
  148.                         {
  149.                                 CFile* pFile = m_files.pop();
  150.                                 assert(pFile);
  151.                                 PREFAST_ASSUME(pFile);
  152.  
  153.                                 while (!pFile->Closed() || !pFile->m_blocks.empty())
  154.                                 {
  155.                                         if (pFile->m_blocks.empty())
  156.                                         {
  157.                                                 CrySleep(1); // yield to give other threads a chance to do some work
  158.                                         }
  159.  
  160.                                         while (!pFile->m_blocks.empty())
  161.                                         {
  162.                                                 SZLibBlock* block = pFile->m_blocks.pop();
  163.                                                 assert(block);
  164.                                                 PREFAST_ASSUME(block);
  165.  
  166.                                                 if (pFile->m_pCompressor->m_bUseZLibCompression)
  167.                                                 {
  168.                                                         size_t compressedLength = XMLCPB_ZLIB_BUFFER_SIZE;
  169.                                                         bool compressionOk = gEnv->pSystem->CompressDataBlock(block->m_pZLibBuffer, block->m_ZLibBufferSizeUsed, pZLibCompressedBuffer, compressedLength);
  170.  
  171.                                                         SZLibBlockHeader zlibHeader;
  172.                                                         zlibHeader.m_compressedSize = compressionOk ? compressedLength : SZLibBlockHeader::NO_ZLIB_USED;
  173.                                                         zlibHeader.m_uncompressedSize = block->m_ZLibBufferSizeUsed;
  174.                                                         pFile->m_bytesWrittenIntoFileUncompressed += block->m_ZLibBufferSizeUsed;
  175.  
  176.                                                         pFile->Write(&zlibHeader, sizeof(SZLibBlockHeader));
  177.                                                         if (compressionOk)
  178.                                                                 pFile->Write(pZLibCompressedBuffer, compressedLength);
  179.                                                         else
  180.                                                                 pFile->Write(block->m_pZLibBuffer, block->m_ZLibBufferSizeUsed);
  181.                                                 }
  182.                                                 else
  183.                                                 {
  184.                                                         pFile->Write(block->m_pZLibBuffer, block->m_ZLibBufferSizeUsed);
  185.                                                 }
  186.  
  187.                                                 delete block;
  188.                                         }
  189.                                 }
  190.  
  191.                                 pFile->Finish();
  192.                                 delete pFile;
  193.                         }
  194.  
  195.                         FreeBlock(pZLibCompressedBuffer);
  196.                 }
  197.         }
  198.  
  199.         // Signals the thread that it should not accept anymore work and exit
  200.         void SignalStopWork()
  201.         {
  202.                 m_bCancelled = true;
  203.                 m_event.Set();
  204.         }
  205.  
  206.         CFile* CreateFile(CZLibCompressor* pCompressor, const char* pFileName)
  207.         {
  208.                 CFile* pFile = new CFile(pCompressor, pFileName, m_event);
  209.                 m_files.push(pFile);
  210.                 return pFile;
  211.         }
  212.  
  213.         void IncreaseBlockCount()
  214.         {
  215.                 if (m_nMaxQueuedBlocks <= 0)
  216.                         return;
  217.  
  218.                 m_bufferAvailableLock.Lock();
  219.  
  220.                 while (m_nBlockCount >= m_nMaxQueuedBlocks)
  221.                         m_bufferAvailableCond.Wait(m_bufferAvailableLock);
  222.  
  223.                 m_nBlockCount++;
  224.  
  225.                 m_bufferAvailableLock.Unlock();
  226.         }
  227.  
  228.         void DecreaseBlockCount()
  229.         {
  230.                 if (m_nMaxQueuedBlocks <= 0)
  231.                         return;
  232.  
  233.                 m_bufferAvailableLock.Lock();
  234.  
  235.                 if (m_nBlockCount > 0)
  236.                         m_nBlockCount--;
  237.  
  238.                 m_bufferAvailableCond.Notify();
  239.  
  240.                 m_bufferAvailableLock.Unlock();
  241.         }
  242.  
  243.         static uint8* AllocateBlock()
  244.         {
  245.                 return new uint8[XMLCPB_ZLIB_BUFFER_SIZE];
  246.         }
  247.  
  248.         static void FreeBlock(uint8* pBlock)
  249.         {
  250.                 delete[] pBlock;
  251.         }
  252.  
  253. private:
  254.  
  255.         CryMT::CLocklessPointerQueue<CFile> m_files;
  256.         CryEvent                            m_event;
  257.         CryConditionVariable                m_bufferAvailableCond;
  258.         CryMutex                            m_bufferAvailableLock;
  259.         const int                           m_nMaxQueuedBlocks;
  260.         int m_nBlockCount;
  261.         bool                                m_bCancelled;
  262. };
  263.  
  264. static CCompressorThread* s_pCompressorThread;
  265.  
  266. bool InitializeCompressorThread()
  267. {
  268.         if (s_pCompressorThread)
  269.                 return false;
  270.  
  271.         s_pCompressorThread = new CCompressorThread;
  272.  
  273.         if (!gEnv->pThreadManager->SpawnThread(s_pCompressorThread, "ZLibCompressor"))
  274.         {
  275.                 CRY_ASSERT_MESSAGE(false, "Error spawning \"ZLibCompressor\" thread.");
  276.                 delete s_pCompressorThread;
  277.                 s_pCompressorThread = NULL;
  278.                 return false;
  279.         }
  280.  
  281.         return true;
  282. }
  283.  
  284. void ShutdownCompressorThread()
  285. {
  286.         if (s_pCompressorThread != NULL)
  287.         {
  288.                 s_pCompressorThread->SignalStopWork();
  289.                 gEnv->pThreadManager->JoinThread(s_pCompressorThread, eJM_Join);
  290.                 delete s_pCompressorThread;
  291.                 s_pCompressorThread = NULL;
  292.         }
  293. }
  294.  
  295. SZLibBlock::SZLibBlock(CZLibCompressor* pCompressor)
  296.         : m_pCompressor(pCompressor)
  297.         , m_ZLibBufferSizeUsed(0)
  298. {
  299.         s_pCompressorThread->IncreaseBlockCount();
  300.         m_pZLibBuffer = CCompressorThread::AllocateBlock();
  301. }
  302.  
  303. SZLibBlock::~SZLibBlock()
  304. {
  305.         CCompressorThread::FreeBlock(m_pZLibBuffer);
  306.         s_pCompressorThread->DecreaseBlockCount();
  307. }
  308.  
  309. CZLibCompressor::CZLibCompressor(const char* pFileName)
  310.         : m_bUseZLibCompression(!!CCryActionCVars::Get().g_XMLCPBUseExtraZLibCompression)
  311.         , m_errorWritingIntoFile(false)
  312. {
  313.         m_currentZlibBlock = new SZLibBlock(this);
  314.         m_pFile = s_pCompressorThread->CreateFile(this, pFileName);
  315. }
  316.  
  317. CZLibCompressor::~CZLibCompressor()
  318. {
  319.         delete m_currentZlibBlock;
  320. }
  321.  
  322. void CZLibCompressor::WriteDataIntoFile(void* pSrc, uint32 numBytes)
  323. {
  324.         uint32 numBytesLeft = numBytes;
  325.         uint8* pNextData = (uint8*)pSrc;
  326.         do
  327.         {
  328.                 AddDataToZLibBuffer(pNextData, numBytesLeft);
  329.         }
  330.         while (numBytesLeft > 0 && !m_errorWritingIntoFile);
  331. }
  332.  
  333. //////////////////////////////////////////////////////////////////////////
  334. // adds data to the to-compress buffer, and calls for compression+writing when the buffer is filled
  335.  
  336. void CZLibCompressor::AddDataToZLibBuffer(uint8*& pSrc, uint32& numBytes)
  337. {
  338.         uint32 bytesFree = XMLCPB_ZLIB_BUFFER_SIZE - m_currentZlibBlock->m_ZLibBufferSizeUsed;
  339.         uint32 bytesToCopy = min(bytesFree, numBytes);
  340.         memcpy(m_currentZlibBlock->m_pZLibBuffer + m_currentZlibBlock->m_ZLibBufferSizeUsed, pSrc, bytesToCopy);
  341.         m_currentZlibBlock->m_ZLibBufferSizeUsed += bytesToCopy;
  342.  
  343.         if (m_currentZlibBlock->m_ZLibBufferSizeUsed == XMLCPB_ZLIB_BUFFER_SIZE)
  344.                 CompressAndWriteZLibBufferIntoFile(false);
  345.  
  346.         pSrc += bytesToCopy;
  347.         numBytes -= bytesToCopy;
  348. }
  349.  
  350. //////////////////////////////////////////////////////////////////////////
  351. void CZLibCompressor::CompressAndWriteZLibBufferIntoFile(bool bFlush)
  352. {
  353.         if (m_currentZlibBlock->m_ZLibBufferSizeUsed > 0)
  354.         {
  355.                 m_pFile->AddBlock(m_currentZlibBlock);
  356.                 if (bFlush)
  357.                         m_currentZlibBlock = NULL;
  358.                 else
  359.                         m_currentZlibBlock = new SZLibBlock(this);
  360.         }
  361.         else if (bFlush)
  362.         {
  363.                 delete m_currentZlibBlock;
  364.                 m_currentZlibBlock = NULL;
  365.         }
  366. }
  367.  
  368. //////////////////////////////////////////////////////////////////////////
  369. // forces a compress + writeintofile of the remaining data in the to-compress zlib buffer
  370.  
  371. void CZLibCompressor::FlushZLibBuffer()
  372. {
  373.         CompressAndWriteZLibBufferIntoFile(true); // to flush the not-yet saved data
  374.         if (m_pFile)
  375.         {
  376.                 m_pFile->Close();
  377.                 m_pFile = NULL;
  378.         }
  379. }
  380.  
  381. } // namespace XMLCPB
  382.  
downloadXMLCPB_ZLibCompressor.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top