mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-16 05:37:00 +00:00
1
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Low level byte swapping routines.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
#ifndef BYTESWAP_H
|
||||
#define BYTESWAP_H
|
||||
#if defined(_WIN32)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "datamap.h" // Needed for typedescription_t. Note datamap.h is tier1 as well.
|
||||
|
||||
class CByteswap
|
||||
{
|
||||
public:
|
||||
CByteswap()
|
||||
{
|
||||
// Default behavior sets the target endian to match the machine native endian (no swap).
|
||||
SetTargetBigEndian( IsMachineBigEndian() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write a single field.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write a block of fields. Works a bit like the saverestore code.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap );
|
||||
|
||||
// Swaps fields for the templated type to the output buffer.
|
||||
template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, void *pBaseData, unsigned int objectCount = 1 )
|
||||
{
|
||||
for ( unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer )
|
||||
{
|
||||
SwapFieldsToTargetEndian( (void*)pOutputBuffer, pBaseData, &T::m_DataMap );
|
||||
pBaseData = (byte*)pBaseData + sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
// Swaps fields for the templated type in place.
|
||||
template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, unsigned int objectCount = 1 )
|
||||
{
|
||||
SwapFieldsToTargetEndian<T>( pOutputBuffer, (void*)pOutputBuffer, objectCount );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// True if the current machine is detected as big endian.
|
||||
// (Endienness is effectively detected at compile time when optimizations are
|
||||
// enabled)
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool IsMachineBigEndian()
|
||||
{
|
||||
short nIsBigEndian = 1;
|
||||
|
||||
// if we are big endian, the first byte will be a 0, if little endian, it will be a one.
|
||||
return (bool)(0 == *(char *)&nIsBigEndian );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets the target byte ordering we are swapping to or from.
|
||||
//
|
||||
// Braindead Endian Reference:
|
||||
// x86 is LITTLE Endian
|
||||
// PowerPC is BIG Endian
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void SetTargetBigEndian( bool bigEndian )
|
||||
{
|
||||
m_bBigEndian = bigEndian;
|
||||
m_bSwapBytes = IsMachineBigEndian() != bigEndian;
|
||||
}
|
||||
|
||||
// Changes target endian
|
||||
inline void FlipTargetEndian( void )
|
||||
{
|
||||
m_bSwapBytes = !m_bSwapBytes;
|
||||
m_bBigEndian = !m_bBigEndian;
|
||||
}
|
||||
|
||||
// Forces byte swapping state, regardless of endianess
|
||||
inline void ActivateByteSwapping( bool bActivate )
|
||||
{
|
||||
SetTargetBigEndian( IsMachineBigEndian() != bActivate );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns true if the target machine is the same as this one in endianness.
|
||||
//
|
||||
// Used to determine when a byteswap needs to take place.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool IsSwappingBytes( void ) // Are bytes being swapped?
|
||||
{
|
||||
return m_bSwapBytes;
|
||||
}
|
||||
|
||||
inline bool IsTargetBigEndian( void ) // What is the current target endian?
|
||||
{
|
||||
return m_bBigEndian;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// IsByteSwapped()
|
||||
//
|
||||
// When supplied with a chunk of input data and a constant or magic number
|
||||
// (in native format) determines the endienness of the current machine in
|
||||
// relation to the given input data.
|
||||
//
|
||||
// Returns:
|
||||
// 1 if input is the same as nativeConstant.
|
||||
// 0 if input is byteswapped relative to nativeConstant.
|
||||
// -1 if input is not the same as nativeConstant and not byteswapped either.
|
||||
//
|
||||
// ( This is useful for detecting byteswapping in magic numbers in structure
|
||||
// headers for example. )
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> inline int SourceIsNativeEndian( T input, T nativeConstant )
|
||||
{
|
||||
// If it's the same, it isn't byteswapped:
|
||||
if( input == nativeConstant )
|
||||
return 1;
|
||||
|
||||
int output;
|
||||
LowLevelByteSwap<T>( &output, &input );
|
||||
if( output == nativeConstant )
|
||||
return 0;
|
||||
|
||||
assert( 0 ); // if we get here, input is neither a swapped nor unswapped version of nativeConstant.
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Swaps an input buffer full of type T into the given output buffer.
|
||||
//
|
||||
// Swaps [count] items from the inputBuffer to the outputBuffer.
|
||||
// If inputBuffer is omitted or NULL, then it is assumed to be the same as
|
||||
// outputBuffer - effectively swapping the contents of the buffer in place.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> inline void SwapBuffer( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
|
||||
{
|
||||
assert( count >= 0 );
|
||||
assert( outputBuffer );
|
||||
|
||||
// Fail gracefully in release:
|
||||
if( count <=0 || !outputBuffer )
|
||||
return;
|
||||
|
||||
// Optimization for the case when we are swapping in place.
|
||||
if( inputBuffer == NULL )
|
||||
{
|
||||
inputBuffer = outputBuffer;
|
||||
}
|
||||
|
||||
// Swap everything in the buffer:
|
||||
for( int i = 0; i < count; i++ )
|
||||
{
|
||||
LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Swaps an input buffer full of type T into the given output buffer.
|
||||
//
|
||||
// Swaps [count] items from the inputBuffer to the outputBuffer.
|
||||
// If inputBuffer is omitted or NULL, then it is assumed to be the same as
|
||||
// outputBuffer - effectively swapping the contents of the buffer in place.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> inline void SwapBufferToTargetEndian( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
|
||||
{
|
||||
assert( count >= 0 );
|
||||
assert( outputBuffer );
|
||||
|
||||
// Fail gracefully in release:
|
||||
if( count <=0 || !outputBuffer )
|
||||
return;
|
||||
|
||||
// Optimization for the case when we are swapping in place.
|
||||
if( inputBuffer == NULL )
|
||||
{
|
||||
inputBuffer = outputBuffer;
|
||||
}
|
||||
|
||||
// Are we already the correct endienness? ( or are we swapping 1 byte items? )
|
||||
if( !m_bSwapBytes || ( sizeof(T) == 1 ) )
|
||||
{
|
||||
// If we were just going to swap in place then return.
|
||||
if( !inputBuffer )
|
||||
return;
|
||||
|
||||
// Otherwise copy the inputBuffer to the outputBuffer:
|
||||
memcpy( outputBuffer, inputBuffer, count * sizeof( T ) );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Swap everything in the buffer:
|
||||
for( int i = 0; i < count; i++ )
|
||||
{
|
||||
LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//-----------------------------------------------------------------------------
|
||||
// The lowest level byte swapping workhorse of doom. output always contains the
|
||||
// swapped version of input. ( Doesn't compare machine to target endianness )
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename T> static void LowLevelByteSwap( T *output, T *input )
|
||||
{
|
||||
T temp = *output;
|
||||
#if defined( _X360 )
|
||||
// Intrinsics need the source type to be fixed-point
|
||||
DWORD* word = (DWORD*)input;
|
||||
switch( sizeof(T) )
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
__storewordbytereverse( *word, 0, &temp );
|
||||
__storewordbytereverse( *(word+1), 4, &temp );
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
__storewordbytereverse( *word, 0, &temp );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
__storeshortbytereverse( *input, 0, &temp );
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert( "Invalid size in CByteswap::LowLevelByteSwap" && 0 );
|
||||
}
|
||||
#else
|
||||
for( size_t i = 0; i < sizeof(T); i++ )
|
||||
{
|
||||
((unsigned char* )&temp)[i] = ((unsigned char*)input)[sizeof(T)-(i+1)];
|
||||
}
|
||||
#endif
|
||||
Q_memcpy( output, &temp, sizeof(T) );
|
||||
}
|
||||
|
||||
unsigned int m_bSwapBytes : 1;
|
||||
unsigned int m_bBigEndian : 1;
|
||||
};
|
||||
|
||||
#endif /* !BYTESWAP_H */
|
||||
Reference in New Issue
Block a user