summaryrefslogtreecommitdiff
path: root/replay/baserecordingsessionblock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'replay/baserecordingsessionblock.cpp')
-rw-r--r--replay/baserecordingsessionblock.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/replay/baserecordingsessionblock.cpp b/replay/baserecordingsessionblock.cpp
new file mode 100644
index 0000000..dbc5fdc
--- /dev/null
+++ b/replay/baserecordingsessionblock.cpp
@@ -0,0 +1,168 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//=======================================================================================//
+
+#include "baserecordingsessionblock.h"
+#include "replay/replayutils.h"
+#include "replay/ireplaycontext.h"
+#include "replay/irecordingsessionmanager.h"
+#include "replay/shared_defs.h"
+#include "KeyValues.h"
+#include "qlimits.h"
+#include "utlbuffer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//----------------------------------------------------------------------------------------
+
+CBaseRecordingSessionBlock::CBaseRecordingSessionBlock( IReplayContext *pContext )
+: m_pContext( pContext ),
+ m_nRemoteStatus( STATUS_INVALID ),
+ m_nHttpError( ERROR_NONE ),
+ m_hSession( REPLAY_HANDLE_INVALID ),
+ m_bHashValid( false ),
+ m_iReconstruction( -1 ),
+ m_uFileSize( 0 ),
+ m_uUncompressedSize( 0 ),
+ m_nCompressorType( COMPRESSORTYPE_INVALID )
+{
+ m_szFullFilename[ 0 ] = '\0';
+ V_memset( m_aHash, 0, sizeof( m_aHash ) );
+}
+
+const char *CBaseRecordingSessionBlock::GetSubKeyTitle() const
+{
+ CBaseRecordingSession *pOwnerSession = m_pContext->GetRecordingSessionManager()->FindSession( m_hSession );
+ if ( !pOwnerSession )
+ {
+ AssertMsg( 0, "Owner session not found" );
+ return "";
+ }
+ return Replay_va( "%s_part_%i", pOwnerSession->m_strName.Get(), m_iReconstruction );
+}
+
+const char *CBaseRecordingSessionBlock::GetPath() const
+{
+ return Replay_va( "%s%s%c", m_pContext->GetBaseDir(), SUBDIR_BLOCKS, CORRECT_PATH_SEPARATOR );
+}
+
+bool CBaseRecordingSessionBlock::Read( KeyValues *pIn )
+{
+ if ( !BaseClass::Read( pIn ) )
+ return false;
+
+ m_nRemoteStatus = (RemoteStatus_t)pIn->GetInt( "remote_status", (int)STATUS_INVALID ); Assert( m_nRemoteStatus != STATUS_INVALID );
+ m_nHttpError = (Error_t)pIn->GetInt( "error", (int)ERROR_NONE );
+ m_iReconstruction = pIn->GetInt( "recon_index", -1 ); Assert( m_iReconstruction >= 0 );
+ m_hSession = (ReplayHandle_t)pIn->GetInt( "session", REPLAY_HANDLE_INVALID ); Assert( m_hSession != REPLAY_HANDLE_INVALID );
+ m_uFileSize = pIn->GetInt( "size", 0 ); Assert( m_uFileSize > 0 );
+ m_uUncompressedSize = pIn->GetInt( "usize", 0 );
+ m_nCompressorType = (CompressorType_t)pIn->GetInt( "compressor", 0 );
+
+ ReadHash( pIn, "hash" );
+
+ return true;
+}
+
+
+void CBaseRecordingSessionBlock::Write( KeyValues *pOut )
+{
+ BaseClass::Write( pOut );
+
+ pOut->SetInt( "remote_status", (int)m_nRemoteStatus );
+ pOut->SetInt( "error", (int)m_nHttpError );
+ pOut->SetInt( "recon_index", m_iReconstruction );
+ pOut->SetInt( "session", (int)m_hSession );
+ pOut->SetInt( "size", m_uFileSize );
+ pOut->SetInt( "usize", m_uUncompressedSize );
+ pOut->SetInt( "compressor", (int)m_nCompressorType );
+
+ WriteHash( pOut, "hash" );
+
+ // NOTE: Filename written in subclasses, since it's handled differently for client vs. server
+}
+
+void CBaseRecordingSessionBlock::OnDelete()
+{
+ BaseClass::OnDelete();
+
+ // NOTE: The actual .block files get deleted in subclasses, since each handle the case differently.
+}
+
+bool CBaseRecordingSessionBlock::ReadHash( KeyValues *pIn, const char *pHashName )
+{
+ const char *pHashStr = pIn->GetString( pHashName );
+ bool bResult = false;
+ if ( V_strlen( pHashStr ) > 0 )
+ {
+ int iHash = 0;
+ char *p = strtok( const_cast< char * >( pHashStr ), " " );
+ while ( p )
+ {
+ // Should have no more than 3 characters
+ if ( V_strlen( p ) > 3 )
+ {
+ break;
+ }
+
+ m_aHash[ iHash++ ] = (uint8)atoi( p );
+ p = strtok( NULL, " " );
+
+ bResult = true;
+ }
+ }
+
+ // Keep track of whether we have a valid hash or not
+ m_bHashValid = bResult;
+
+ AssertMsg( bResult, "Invalid hash string" );
+ return bResult;
+}
+
+void CBaseRecordingSessionBlock::WriteHash( KeyValues *pOut, const char *pHashName ) const
+{
+ CFmtStr fmtHash( "%03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i",
+ m_aHash[0], m_aHash[1], m_aHash[2], m_aHash[3], m_aHash[4], m_aHash[5], m_aHash[6], m_aHash[7],
+ m_aHash[8], m_aHash[9], m_aHash[10], m_aHash[11], m_aHash[12], m_aHash[13], m_aHash[14], m_aHash[15]
+ );
+ pOut->SetString( pHashName, fmtHash.Access() );
+}
+
+bool CBaseRecordingSessionBlock::HasValidHash() const
+{
+ return m_bHashValid;
+}
+
+void CBaseRecordingSessionBlock::WriteSessionInfoDataToBuffer( CUtlBuffer &buf ) const
+{
+ RecordingSessionBlockSpec_t blob;
+
+ blob.m_iReconstruction = (int32)m_iReconstruction;
+ blob.m_uRemoteStatus = (uint8)m_nRemoteStatus;
+ blob.m_uFileSize = m_uFileSize;
+ blob.m_nCompressorType = (int8)m_nCompressorType; // Can be COMPRESSORTYPE_INVALID if not compressed
+ blob.m_uUncompressedSize = m_uUncompressedSize; // Can be 0 if not compressed
+ V_memcpy( blob.m_aHash, m_aHash, sizeof( m_aHash ) );
+
+ // Write the blob at the appropriate position in the buffer
+ Assert( m_iReconstruction >= 0 );
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, m_iReconstruction * sizeof( blob ) );
+ buf.Put( &blob, sizeof( RecordingSessionBlockSpec_t ) );
+}
+
+//----------------------------------------------------------------------------------------
+
+/*static*/ const char *CBaseRecordingSessionBlock::GetRemoteStatusStringSafe( RemoteStatus_t nStatus )
+{
+ switch ( nStatus )
+ {
+ case STATUS_INVALID: return "invalid";
+ case STATUS_ERROR: return "error";
+ case STATUS_WRITING: return "writing";
+ case STATUS_READYFORDOWNLOAD: return "ready for download";
+ default: return "unknown";
+ }
+}
+
+//----------------------------------------------------------------------------------------