text: ﻿//========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose:
  //
  // $NoKeywords: $
  //=============================================================================
  
  #include "stdafx.h"
  
  // memdbgon must be the last include file in a .cpp file!!!
  #include "tier0/memdbgon.h"
  
  namespace GCSDK {
  
  //-----------------------------------------------------------------------------
  // Purpose: Destructor
  //-----------------------------------------------------------------------------
      CRecordBase::~CRecordBase() {
          Cleanup();
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Copy constructor
  // Input:	that -			CRecord to copy from
  //-----------------------------------------------------------------------------
      CRecordBase::CRecordBase(const CRecordBase &that) {
          *this = that;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Assignment operator - COPIES the record data
  // Input:	that -			CRecord to copy from
  //-----------------------------------------------------------------------------
      CRecordBase &CRecordBase::operator=(const CRecordBase &that) {
          Assert(GetITable() == that.GetITable());
  
          // COPY that record
          Copy(that);
  
          return *this;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Copies the data in the record. This is overridden by CRecordVar and
  //			CRecordExternal
  // Input:	that -			CRecord to copy from
  //-----------------------------------------------------------------------------
      void CRecordBase::Copy(const CRecordBase &that) {
          Cleanup();
          Q_memcpy(PubRecordFixed(), that.PubRecordFixed(), GetPSchema()->CubRecordFixed());
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Return the record info for this record's schema
  //-----------------------------------------------------------------------------
      const CRecordInfo *CRecordBase::GetPRecordInfo() const {
          return GetPSchema()->GetRecordInfo();
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Copies the data in the var record.
  // Input:	that -			CRecord to copy from
  //-----------------------------------------------------------------------------
      void CRecordVar::Copy(const CRecordBase &baseThat) {
          const CRecordVar &that = (const CRecordVar &) baseThat;
  
          // COPY that record
          Cleanup();
          m_pSchema = that.m_pSchema;
          Q_memcpy(PubRecordFixed(), that.PubRecordFixed(), GetPSchema()->CubRecordFixed());
  
          SetFlag(k_EAllocatedVarBlock, false);
          if (VarFieldBlockInfo_t * pVarBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord(PubRecordFixed())) {
              if (pVarBlockInfo->m_cubBlock) {
                  void *pvNewBlock = malloc(pVarBlockInfo->m_cubBlock);
                  Q_memcpy(pvNewBlock, pVarBlockInfo->m_pubBlock, pVarBlockInfo->m_cubBlock);
                  pVarBlockInfo->m_pubBlock = (uint8 *) pvNewBlock;
                  SetFlag(k_EAllocatedVarBlock, true);
              }
          }
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Copies the data in the var record.
  // Input:	that -			CRecord to copy from
  //-----------------------------------------------------------------------------
      void CRecordExternal::Copy(const CRecordBase &baseThat) {
          const CRecordExternal &that = (const CRecordExternal &) baseThat;
  
          Cleanup();
          m_pSchema = that.m_pSchema;
  
          m_pubRecordFixedExternal = (uint8 *) malloc(m_pSchema->CubRecordFixed());
          Q_memcpy(m_pubRecordFixedExternal, that.PubRecordFixed(), m_pSchema->CubRecordFixed());
          SetFlag(k_EAllocatedFixed, true);
  
          SetFlag(k_EAllocatedVarBlock, false);
          if (VarFieldBlockInfo_t * pVarBlockInfo = m_pSchema->PVarFieldBlockInfoFromRecord(PubRecordFixed())) {
              if (pVarBlockInfo->m_cubBlock) {
                  void *pvNewBlock = malloc(pVarBlockInfo->m_cubBlock);
                  Q_memcpy(pvNewBlock, pVarBlockInfo->m_pubBlock, pVarBlockInfo->m_cubBlock);
                  pVarBlockInfo->m_pubBlock = (uint8 *) pvNewBlock;
                  SetFlag(k_EAllocatedVarBlock, true);
              }
          }
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Initialize to an empty record
  // Input:	pSchema -			Schema for the record this will hold
  //-----------------------------------------------------------------------------
      void CRecordExternal::Init(CSchema *pSchema) {
          Cleanup();
          m_pSchema = pSchema;
          m_pubRecordFixedExternal = (uint8 *) malloc(m_pSchema->CubRecordFixed());
          Q_memset(m_pubRecordFixedExternal, 0, m_pSchema->CubRecordFixed());
          SetFlag(k_EAllocatedFixed, true);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Initialize pointing to a record expanded in memory
  // Input:	pSchema -			Schema for the record this will hold
  //			pubRecord -			Pointer to fixed record data
  //			bTakeOwnership -	Should we delete the record when destroyed
  // Output:	Size of the record's data
  //-----------------------------------------------------------------------------
      int CRecordBase::InitFromBytes(uint8 *pubRecord) {
          Cleanup();
  
          Q_memcpy(PubRecordFixed(), pubRecord, GetPSchema()->CubRecordFixed());
          int cubRead = GetPSchema()->CubRecordFixed();
          return cubRead;
      }
  
      int CRecordVar::InitFromBytes(uint8 *pubRecord) {
          Cleanup();
  
          Q_memcpy(PubRecordFixed(), pubRecord, GetPSchema()->CubRecordFixed());
          int cubRead = GetPSchema()->CubRecordFixed();
          if (VarFieldBlockInfo_t * pVarBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord(PubRecordFixed())) {
              if (pVarBlockInfo->m_cubBlock) {
                  void *pvNewBlock = malloc(pVarBlockInfo->m_cubBlock);
                  Q_memcpy(pvNewBlock, pVarBlockInfo->m_pubBlock, pVarBlockInfo->m_cubBlock);
                  pVarBlockInfo->m_pubBlock = (uint8 *) pvNewBlock;
                  SetFlag(k_EAllocatedVarBlock, true);
                  cubRead += pVarBlockInfo->m_cubBlock;
              }
          }
  
          return cubRead;
      }
  
  
      int CRecordExternal::Init(CSchema *pSchema, uint8 *pubRecord, bool bTakeOwnership) {
          m_pSchema = pSchema;
          m_pubRecordFixedExternal = pubRecord;
          SetFlag(k_EAllocatedFixed, bTakeOwnership);
          SetFlag(k_EAllocatedVarBlock, bTakeOwnership);
          int cubRead = m_pSchema->CubRecordFixed() + CubRecordVarBlock();
  
          return cubRead;
      }
  
      CSchema *CRecordBase::GetPSchema() {
          return GetPSchemaImpl();
      }
  
      CSchema *CRecordBase::GetPSchemaImpl() {
          CSchema *pSchema = NULL;
          int i = GetITable();
          if (i != -1)
              pSchema = &GSchemaFull().GetSchema(i);
          return pSchema;
      }
  
  //-----------------------------------------------------------------------------
  // Purpose: Render a field to a buffer
  // Input:	unColumn - field to render
  //			cchBuffer - size of render buffer
  //			pchBuffer - buffer to render into
  //-----------------------------------------------------------------------------
      void CRecordBase::RenderField(uint32 unColumn, int cchBuffer, char *pchBuffer) const {
          Q_strncpy(pchBuffer, "", cchBuffer);
  
          uint8 *pubData;
          uint32 cubData;
          if (!BGetField(unColumn, &pubData, &cubData))
              return;
  
          // Get the column info and figure out how to interpret the data
          ConvertFieldToText(GetPRecordInfo()->GetColumnInfo(unColumn).GetType(), pubData, cubData, pchBuffer, cchBuffer,
                             false);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Reset to base state, freeing any memory we are responsible for
  //-----------------------------------------------------------------------------
      void CRecordBase::Cleanup() {
      }
  
      void CRecordVar::Cleanup() {
          // Must do this before freeing memory that encloses it
          // (eg releasing the net packet)
          if (BFlagSet(k_EAllocatedVarBlock)) {
              void *pvVarBlock = m_pSchema->PVarFieldBlockInfoFromRecord(PubRecordFixed())->m_pubBlock;
              free(pvVarBlock);
              m_pSchema->PVarFieldBlockInfoFromRecord(PubRecordFixed())->m_pubBlock = NULL;
              SetFlag(k_EAllocatedVarBlock, false);
          }
      }
  
      void CRecordExternal::Cleanup() {
          // clean up the variable-length memory we might have allocated
          if (BFlagSet(k_EAllocatedVarBlock)) {
              void *pvVarBlock = m_pSchema->PVarFieldBlockInfoFromRecord(PubRecordFixed())->m_pubBlock;
              free(pvVarBlock);
              m_pSchema->PVarFieldBlockInfoFromRecord(PubRecordFixed())->m_pubBlock = NULL;
              SetFlag(k_EAllocatedVarBlock, false);
          }
  
          // clean up the external memory we might have allocated
          if (BFlagSet(k_EAllocatedFixed))
              free(m_pubRecordFixedExternal);
          SetFlag(k_EAllocatedFixed, false);
          m_pubRecordFixedExternal = NULL;
  
          // clean up the lowest layer, not calling CRecordVar
          CRecordBase::Cleanup();
      }
  
  //-----------------------------------------------------------------------------
  // Purpose:	Deserializes a block of memory into this record
  // Input:	pubData -		Memory block to deserialize from
  //-----------------------------------------------------------------------------
      void CRecordExternal::DeSerialize(uint8 *pubData) {
          InitFromBytes(pubData);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose:	Calculates the size of this record when serialized
  // Output:	Size of serialized message
  //-----------------------------------------------------------------------------
      uint32 CRecordBase::CubSerialized() {
          return CubRecordFixed() + CubRecordVarBlock();
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get pointer to fixed part of record
  // Output:	pubRecordFixed
  //-----------------------------------------------------------------------------
      uint8 *CRecordBase::PubRecordFixed() {
          return (uint8 *) (this + 1);
      }
  
      uint8 *CRecordExternal::PubRecordFixed() {
          Assert(m_pubRecordFixedExternal);
          return m_pubRecordFixedExternal;
      }
  
      uint8 *CRecordVar::PubRecordFixed() {
          return (uint8 *) (this + 1);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get pointer to fixed part of record
  // Output:	pubRecordFixed
  //-----------------------------------------------------------------------------
      const uint8 *CRecordBase::PubRecordFixed() const {
          return const_cast<CRecordBase *>( this )->PubRecordFixed();
      }
  
      const uint8 *CRecordVar::PubRecordFixed() const {
          return const_cast<CRecordVar *>( this )->PubRecordFixed();
      }
  
      const uint8 *CRecordExternal::PubRecordFixed() const {
          return const_cast<CRecordExternal *>( this )->PubRecordFixed();
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get size of fixed part of record
  // Output:	size in bytes of fixed part
  //-----------------------------------------------------------------------------
      uint32 CRecordBase::CubRecordFixed() const {
          return GetPSchema()->CubRecordFixed();
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get pointer to variable part of record
  // Output:	Pointer to variable-length block -- may be NULL if this record
  //			has no var-length fields or they are all empty
  //-----------------------------------------------------------------------------
      uint8 *CRecordBase::PubRecordVarBlock() {
          VarFieldBlockInfo_t *pVarFieldBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord(PubRecordFixed());
          if (pVarFieldBlockInfo) {
              return pVarFieldBlockInfo->m_pubBlock;
          } else {
              return NULL;
          }
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get pointer to variable part of record
  // Output:	Pointer to variable-length block -- may be NULL if this record
  //			has no var-length fields or they are all empty
  //-----------------------------------------------------------------------------
      const uint8 *CRecordBase::PubRecordVarBlock() const {
          return const_cast<CRecordBase *>( this )->PubRecordVarBlock();
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get size of variable part of record
  // Output:	Size in bytes of var-length block - may be zero if this record
  //			has no var-length fields or they are all empty
  //-----------------------------------------------------------------------------
      uint32 CRecordBase::CubRecordVarBlock() const {
          VarFieldBlockInfo_t *pVarFieldBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord(PubRecordFixed());
          if (pVarFieldBlockInfo) {
              return pVarFieldBlockInfo->m_cubBlock;
          } else {
              return 0;
          }
      }
  
  //-----------------------------------------------------------------------------
  // Purpose: Get size of variable part of record
  // Output:	Size in bytes of var-length block - may be zero if this record
  //			has no var-length fields or they are all empty
  //-----------------------------------------------------------------------------
      bool CRecordBase::BAssureRecordVarStorage(uint32 cVariableBytes) {
          // get the variable field block
          VarFieldBlockInfo_t *pVarFieldBlockInfo = GetPSchema()->PVarFieldBlockInfoFromRecord(PubRecordFixed());
          if (pVarFieldBlockInfo) {
              // if we have it, see if it's got enough storage
              if (pVarFieldBlockInfo->m_cubBlock >= cVariableBytes) {
                  // already there
                  return true;
              }
  
              // allocate it
              uint8 *pubData = (uint8 *) malloc(cVariableBytes);
              if (pubData == NULL)
                  return false;
  
              // do we have something right now?
              if (pVarFieldBlockInfo->m_cubBlock != 0) {
                  // sure do. copy it over.
                  Q_memcpy(pubData, pVarFieldBlockInfo->m_pubBlock, pVarFieldBlockInfo->m_cubBlock);
  
                  // free what was there
                  free(pVarFieldBlockInfo->m_pubBlock);
              }
  
              // hook up our buffer
              pVarFieldBlockInfo->m_cubBlockFree = cVariableBytes - pVarFieldBlockInfo->m_cubBlock;
              pVarFieldBlockInfo->m_cubBlock = cVariableBytes;
              pVarFieldBlockInfo->m_pubBlock = pubData;
  
              return true;
          } else {
              // we don't have one;
              // we've got no variable length fields, and so can't preallocate for them!
              return false;
          }
      }
  
  //-----------------------------------------------------------------------------
  // Purpose: Initialize this whole record to random data
  // Input:	unPrimaryIndex -		Primary index to set
  //-----------------------------------------------------------------------------
      void CRecordExternal::InitRecordRandom(uint32 unPrimaryIndex) {
          bool bRealloced = false;
          GetPSchema()->InitRecordRandom(PubRecordFixed(), unPrimaryIndex, &bRealloced, BFlagSet(k_EAllocatedVarBlock));
  
          if (bRealloced)
              SetFlag(k_EAllocatedVarBlock, true);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Set a field in this record to random bits
  // Input:	iField -			Field to set
  //-----------------------------------------------------------------------------
      void CRecordExternal::SetFieldRandom(int iField) {
          bool bRealloced = false;
          GetPSchema()->SetFieldRandom(PubRecordFixed(), iField, &bRealloced, BFlagSet(k_EAllocatedVarBlock));
  
          if (bRealloced)
              SetFlag(k_EAllocatedVarBlock, true);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get a field (var or fixed) from this record
  // Input:	iField -			Field to set
  //			ppubData -			Receives pointer to fields data
  //			pcubField -			Receives count of bytes of data (will count the null for strings)
  // Output:	true if succeeds
  //-----------------------------------------------------------------------------
      bool CRecordBase::BGetField(int iField, uint8 **ppubData, uint32 *pcubField) const {
          return GetPSchema()->BGetFieldData(PubRecordFixed(), iField, ppubData, pcubField);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Sets the data for a field, whether fixed or variable length
  // Input:	iField -			index of field to set
  //			pubData -			pointer to field data to copy from
  //			cubData -			size in bytes of that data
  // Output:	true if successful
  //-----------------------------------------------------------------------------
      bool CRecordBase::BSetField(int iField, void *pvData, uint32 cubData) {
          bool bRealloced = false;
          bool bResult = BSetField(iField, pvData, cubData, &bRealloced);
          Assert(!bRealloced);
  
          return bResult;
      }
  
      bool CRecordBase::BSetField(int iField, void *pvData, uint32 cubData, bool *pbRealloced) {
          uint8 *pubData = reinterpret_cast<uint8 *>( pvData );
  
          if (!GetPSchema()->BSetFieldData(PubRecordFixed(), iField, pubData, cubData, pbRealloced))
              return false;
  
          return true;
      }
  
      bool CRecordVar::BSetField(int iField, void *pvData, uint32 cubData) {
          bool bRealloced = false;
          bool bResult = CRecordBase::BSetField(iField, pvData, cubData, &bRealloced);
  
          if (bRealloced)
              SetFlag(k_EAllocatedVarBlock, true);
          return bResult;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Erases a field, setting it to 0 length (if possible) and filling with nulls
  // Input:	iField -			index of field to wipe
  // NOTE:	This relies on CSchema::BSetFieldData nulling out the rest of a field when it is set to 0 length!
  //-----------------------------------------------------------------------------
      void CRecordBase::WipeField(int iField) {
          bool bRealloced = false;
  
          // Empty Data
          uint32 un = 0;
  
          // Length should be 0, except for non-variable length strings where length should be 1 (for an empty string "")
          int cub = 0;
          Field_t &field = GetPSchema()->GetField(iField);
          Assert(!field.BIsVariableLength());
          if (field.BIsStringType())
              cub = 1;
  
          GetPSchema()->BSetFieldData(PubRecordFixed(), iField, (uint8 *) &un, cub, &bRealloced);
  
          Assert(!bRealloced);
      }
  
      void CRecordVar::WipeField(int iField) {
          bool bRealloced = false;
  
          // Empty Data
          uint32 un = 0;
  
          // Length should be 0, except for non-variable length strings where length should be 1 (for an empty string "")
          int cub = 0;
          Field_t &field = GetPSchema()->GetField(iField);
          if (field.BIsStringType() && !field.BIsVariableLength())
              cub = 1;
  
          GetPSchema()->BSetFieldData(PubRecordFixed(), iField, (uint8 *) &un, cub, &bRealloced);
  
          if (bRealloced)
              SetFlag(k_EAllocatedVarBlock, true);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get a string field - will return empty string instead of NULL if field has no datas
  // Input:	iField -			Field to get
  //			pcubField -			Receives count of bytes of data (will count the null for strings)
  // Output:	const pointer to string data (to an empty string if no data)
  //-----------------------------------------------------------------------------
      const char *CRecordBase::GetStringField(int iField, uint32 *pcubField) {
          uint8 *pubData = NULL;
          *pcubField = 0;
  
          if (BGetField(iField, &pubData, pcubField) && *pcubField > 0)
              return (const char *) pubData;
          else
              return "";
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get an int field
  // Input:	iField -			Field to get
  // Output:	Int (0 if no data)
  //-----------------------------------------------------------------------------
      int CRecordBase::GetInt(int iField) {
          return (int) GetUint32(iField);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get a uint16 field
  // Input:	iField -			Field to get
  // Output:	uint16 (0 if no data)
  //-----------------------------------------------------------------------------
      uint16 CRecordBase::GetUint16(int iField) {
          uint8 *pubData = NULL;
          uint32 cubField = 0;
  
          DbgVerify(BGetField(iField, &pubData, &cubField));
          Assert(0 < cubField);
  
          if (NULL != pubData)
              return *(uint16 *) pubData;
          else
              return 0;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get a uint32 field
  // Input:	iField -			Field to get
  // Output:	uint32 (0 if no data)
  //-----------------------------------------------------------------------------
      uint32 CRecordBase::GetUint32(int iField) {
          uint8 *pubData = NULL;
          uint32 cubField = 0;
  
          DbgVerify(BGetField(iField, &pubData, &cubField));
          Assert(0 < cubField);
  
          if (NULL != pubData)
              return *(uint32 *) pubData;
          else
              return 0;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get a uint64 field
  // Input:	iField -			Field to get
  // Output:	uint64 (0 if no data)
  //-----------------------------------------------------------------------------
      uint64 CRecordBase::GetUint64(int iField) {
          uint8 *pubData = NULL;
          uint32 cubField = 0;
  
          DbgVerify(BGetField(iField, &pubData, &cubField));
          Assert(0 < cubField);
  
          if (NULL != pubData)
              return *(uint64 *) pubData;
          else
              return 0;
      }
  
  
      const char *CRecordBase::ReadVarCharField(const CVarCharField &field) const {
          Assert(false);
          return NULL;
      }
  
      const uint8 *CRecordBase::ReadVarDataField(const CVarField &field, uint32 *pcubField) const {
          Assert(false);
          return NULL;
      }
  
  // These may cause a realloc
      bool CRecordBase::SetVarCharField(CVarCharField &field, const char *pchString, bool bTruncate, int32 iField) {
          Assert(false);
          return false;
      }
  
      void CRecordBase::SetVarDataField(CVarField &field, const void *pvData, uint32 cubData) {
          Assert(false);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Read data from a varchar field
  // Input:	field -				opaque field object to read from
  // Output:	pointer to data - may be NULL if that field is empty.
  //-----------------------------------------------------------------------------
      const char *CRecordVar::ReadVarCharField(const CVarCharField &field) const {
          Assert(GetPSchema()->BHasVariableFields());
  
          uint8 *pubData;
          uint32 cubData;
          if (GetPSchema()->BGetVarField(PubRecordFixed(), &field, &pubData, &cubData))
              return (const char *) pubData;
          else
              return "";
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Read data from a vardata field
  // Input:	field -				opaque field object to read from
  // Output:	pointer to data - may be NULL if that field is empty.
  //-----------------------------------------------------------------------------
      const uint8 *CRecordVar::ReadVarDataField(const CVarField &field, uint32 *pcubField) const {
          Assert(GetPSchema()->BHasVariableFields());
  
          uint8 *pubData;
          *pcubField = 0;
          if (GetPSchema()->BGetVarField(PubRecordFixed(), &field, &pubData, pcubField))
              return pubData;
          else
              return NULL;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Update (in memory) a varchar field
  // Input:	field -				opaque field object to update
  //			pchString -			string data to set
  //-----------------------------------------------------------------------------
      bool CRecordVar::SetVarCharField(CVarCharField &field, const char *pchString, bool bTruncate, int32 iField) {
          Assert(GetPSchema()->BHasVariableFields());
          if (iField < 0) {
              AssertMsg1(false, "Encountered a bad call to SetVarCharField with an invalid field specified: %d", iField);
              return false;
          }
  
          bool bTruncated = false;
          int cchLen = Q_strlen(pchString) + 1;
  
          // since we're a VARCHAR field, cbMaxLength is the length in characters
          const int cchMaxLength = m_pSchema->GetField(iField).m_cchMaxLength;
          if ((cchMaxLength > 0) && (cchLen > cchMaxLength)) {
              if (bTruncate) {
                  bTruncated = true;
                  cchLen = cchMaxLength;
              } else {
                  // caller should check his data and not pass stuff that wont fit
                  AssertMsg4(false, "Overflow in SetVarCharField (%u > %u) for column %s in table %s", cchLen,
                             cchMaxLength, m_pSchema->GetField(iField).m_rgchName, m_pSchema->GetPchName());
                  return false;
              }
          }
  
          bool bRealloced = false;
          bool fSuccess = GetPSchema()->BSetVarField(PubRecordFixed(), &field, pchString, cchLen, &bRealloced,
                                                     BFlagSet(k_EAllocatedVarBlock));
          if (fSuccess && bTruncated) {
              //make sure the last character is NULL if we truncated
              VarFieldBlockInfo_t *pBlock = GetPSchema()->PVarFieldBlockInfoFromRecord(PubRecordFixed());
              uint8 *pubVarBlock = pBlock->m_pubBlock;
              char *pField = (char *) (pubVarBlock + field.m_dubOffset);
              pField[cchLen - 1] = '\0';
          }
  
          if (bRealloced)
              SetFlag(k_EAllocatedVarBlock, true);
          return fSuccess;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Update (in memory) a vardata field
  // Input:	field -				opaque field object to update
  //			pvData -			pointer to data to put there
  //			cubData -			size in bytes of the data
  //-----------------------------------------------------------------------------
      void CRecordVar::SetVarDataField(CVarField &field, const void *pvData, uint32 cubData) {
          Assert(GetPSchema()->BHasVariableFields());
  
          bool bRealloced = false;
          GetPSchema()->BSetVarField(PubRecordFixed(), &field, pvData, cubData, &bRealloced,
                                     BFlagSet(k_EAllocatedVarBlock));
  
          if (bRealloced)
              SetFlag(k_EAllocatedVarBlock, true);
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Set or clear the specified flag in m_nFlags
  // Input:	eFlag -				flag (single bit) to change
  //			bSet -				Set it, else clear it
  //-----------------------------------------------------------------------------
      void CRecordVar::SetFlag(int eFlag, bool bSet) {
          if (bSet)
              m_nFlags |= eFlag;
          else
              m_nFlags &= ~eFlag;
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Get the state of the specified flag
  // Input:	eFlag -				flag (single bit) to check
  //-----------------------------------------------------------------------------
      bool CRecordVar::BFlagSet(int eFlag) const {
          return 0 != (m_nFlags & eFlag);
      }
  
  
  #ifdef DBGFLAG_VALIDATE
      //-----------------------------------------------------------------------------
      // Purpose: Run a global validation pass on all of our data structures and memory
      //			allocations.
      // Input:	validator -		Our global validator object
      //			pchName -		Our name (typically a member var in our container)
      //-----------------------------------------------------------------------------
      void CRecordBase::Validate( CValidator &validator, const char *pchName )
      {
          VALIDATE_SCOPE();
      }
  
      void CRecordVar::Validate( CValidator &validator, const char *pchName )
      {
          VALIDATE_SCOPE();
  
          if ( BFlagSet( k_EAllocatedVarBlock ) )
          {
              validator.ClaimMemory( GetPSchema()->PVarFieldBlockInfoFromRecord( PubRecordFixed() )->m_pubBlock );
          }
  
      }
  
      void CRecordExternal::Validate( CValidator &validator, const char *pchName )
      {
          if ( BFlagSet( k_EAllocatedFixed ) )
          {
              validator.ClaimMemory( m_pubRecordFixedExternal );
          }
  
          CRecordBase::Validate( validator, pchName );
      }
  
      void CRecordBase::ValidateStatics( CValidator &validator, const char *pchName )
      {
          VALIDATE_SCOPE_STATIC( "CRecordBase class statics" );
      }
  
  #endif // DBGFLAG_VALIDATE
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Return the schema for this record type
  //-----------------------------------------------------------------------------
      CSchema *CRecordType::GetSchema() const {
          return &GSchemaFull().GetSchema(GetITable());
      }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Return the CRecordInfo for this record type
  //-----------------------------------------------------------------------------
      CRecordInfo *CRecordType::GetRecordInfo() const {
          return GetSchema()->GetRecordInfo();
      }
  
  } // namespace GCSDK
  