Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
5.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=======================================================================================//
  4. #include "baserecordingsessionblock.h"
  5. #include "replay/replayutils.h"
  6. #include "replay/ireplaycontext.h"
  7. #include "replay/irecordingsessionmanager.h"
  8. #include "replay/shared_defs.h"
  9. #include "KeyValues.h"
  10. #include "qlimits.h"
  11. #include "utlbuffer.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. //----------------------------------------------------------------------------------------
  15. CBaseRecordingSessionBlock::CBaseRecordingSessionBlock( IReplayContext *pContext )
  16. : m_pContext( pContext ),
  17. m_nRemoteStatus( STATUS_INVALID ),
  18. m_nHttpError( ERROR_NONE ),
  19. m_hSession( REPLAY_HANDLE_INVALID ),
  20. m_bHashValid( false ),
  21. m_iReconstruction( -1 ),
  22. m_uFileSize( 0 ),
  23. m_uUncompressedSize( 0 ),
  24. m_nCompressorType( COMPRESSORTYPE_INVALID )
  25. {
  26. m_szFullFilename[ 0 ] = '\0';
  27. V_memset( m_aHash, 0, sizeof( m_aHash ) );
  28. }
  29. const char *CBaseRecordingSessionBlock::GetSubKeyTitle() const
  30. {
  31. CBaseRecordingSession *pOwnerSession = m_pContext->GetRecordingSessionManager()->FindSession( m_hSession );
  32. if ( !pOwnerSession )
  33. {
  34. AssertMsg( 0, "Owner session not found" );
  35. return "";
  36. }
  37. return Replay_va( "%s_part_%i", pOwnerSession->m_strName.Get(), m_iReconstruction );
  38. }
  39. const char *CBaseRecordingSessionBlock::GetPath() const
  40. {
  41. return Replay_va( "%s%s%c", m_pContext->GetBaseDir(), SUBDIR_BLOCKS, CORRECT_PATH_SEPARATOR );
  42. }
  43. bool CBaseRecordingSessionBlock::Read( KeyValues *pIn )
  44. {
  45. if ( !BaseClass::Read( pIn ) )
  46. return false;
  47. m_nRemoteStatus = (RemoteStatus_t)pIn->GetInt( "remote_status", (int)STATUS_INVALID ); Assert( m_nRemoteStatus != STATUS_INVALID );
  48. m_nHttpError = (Error_t)pIn->GetInt( "error", (int)ERROR_NONE );
  49. m_iReconstruction = pIn->GetInt( "recon_index", -1 ); Assert( m_iReconstruction >= 0 );
  50. m_hSession = (ReplayHandle_t)pIn->GetInt( "session", REPLAY_HANDLE_INVALID ); Assert( m_hSession != REPLAY_HANDLE_INVALID );
  51. m_uFileSize = pIn->GetInt( "size", 0 ); Assert( m_uFileSize > 0 );
  52. m_uUncompressedSize = pIn->GetInt( "usize", 0 );
  53. m_nCompressorType = (CompressorType_t)pIn->GetInt( "compressor", 0 );
  54. ReadHash( pIn, "hash" );
  55. return true;
  56. }
  57. void CBaseRecordingSessionBlock::Write( KeyValues *pOut )
  58. {
  59. BaseClass::Write( pOut );
  60. pOut->SetInt( "remote_status", (int)m_nRemoteStatus );
  61. pOut->SetInt( "error", (int)m_nHttpError );
  62. pOut->SetInt( "recon_index", m_iReconstruction );
  63. pOut->SetInt( "session", (int)m_hSession );
  64. pOut->SetInt( "size", m_uFileSize );
  65. pOut->SetInt( "usize", m_uUncompressedSize );
  66. pOut->SetInt( "compressor", (int)m_nCompressorType );
  67. WriteHash( pOut, "hash" );
  68. // NOTE: Filename written in subclasses, since it's handled differently for client vs. server
  69. }
  70. void CBaseRecordingSessionBlock::OnDelete()
  71. {
  72. BaseClass::OnDelete();
  73. // NOTE: The actual .block files get deleted in subclasses, since each handle the case differently.
  74. }
  75. bool CBaseRecordingSessionBlock::ReadHash( KeyValues *pIn, const char *pHashName )
  76. {
  77. const char *pHashStr = pIn->GetString( pHashName );
  78. bool bResult = false;
  79. if ( V_strlen( pHashStr ) > 0 )
  80. {
  81. int iHash = 0;
  82. char *p = strtok( const_cast< char * >( pHashStr ), " " );
  83. while ( p )
  84. {
  85. // Should have no more than 3 characters
  86. if ( V_strlen( p ) > 3 )
  87. {
  88. break;
  89. }
  90. m_aHash[ iHash++ ] = (uint8)atoi( p );
  91. p = strtok( NULL, " " );
  92. bResult = true;
  93. }
  94. }
  95. // Keep track of whether we have a valid hash or not
  96. m_bHashValid = bResult;
  97. AssertMsg( bResult, "Invalid hash string" );
  98. return bResult;
  99. }
  100. void CBaseRecordingSessionBlock::WriteHash( KeyValues *pOut, const char *pHashName ) const
  101. {
  102. CFmtStr fmtHash( "%03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i %03i",
  103. m_aHash[0], m_aHash[1], m_aHash[2], m_aHash[3], m_aHash[4], m_aHash[5], m_aHash[6], m_aHash[7],
  104. m_aHash[8], m_aHash[9], m_aHash[10], m_aHash[11], m_aHash[12], m_aHash[13], m_aHash[14], m_aHash[15]
  105. );
  106. pOut->SetString( pHashName, fmtHash.Access() );
  107. }
  108. bool CBaseRecordingSessionBlock::HasValidHash() const
  109. {
  110. return m_bHashValid;
  111. }
  112. void CBaseRecordingSessionBlock::WriteSessionInfoDataToBuffer( CUtlBuffer &buf ) const
  113. {
  114. RecordingSessionBlockSpec_t blob;
  115. blob.m_iReconstruction = (int32)m_iReconstruction;
  116. blob.m_uRemoteStatus = (uint8)m_nRemoteStatus;
  117. blob.m_uFileSize = m_uFileSize;
  118. blob.m_nCompressorType = (int8)m_nCompressorType; // Can be COMPRESSORTYPE_INVALID if not compressed
  119. blob.m_uUncompressedSize = m_uUncompressedSize; // Can be 0 if not compressed
  120. V_memcpy( blob.m_aHash, m_aHash, sizeof( m_aHash ) );
  121. // Write the blob at the appropriate position in the buffer
  122. Assert( m_iReconstruction >= 0 );
  123. buf.SeekPut( CUtlBuffer::SEEK_HEAD, m_iReconstruction * sizeof( blob ) );
  124. buf.Put( &blob, sizeof( RecordingSessionBlockSpec_t ) );
  125. }
  126. //----------------------------------------------------------------------------------------
  127. /*static*/ const char *CBaseRecordingSessionBlock::GetRemoteStatusStringSafe( RemoteStatus_t nStatus )
  128. {
  129. switch ( nStatus )
  130. {
  131. case STATUS_INVALID: return "invalid";
  132. case STATUS_ERROR: return "error";
  133. case STATUS_WRITING: return "writing";
  134. case STATUS_READYFORDOWNLOAD: return "ready for download";
  135. default: return "unknown";
  136. }
  137. }
  138. //----------------------------------------------------------------------------------------