diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /sp/src/public/tier1/byteswap.h | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/public/tier1/byteswap.h')
| -rw-r--r-- | sp/src/public/tier1/byteswap.h | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/sp/src/public/tier1/byteswap.h b/sp/src/public/tier1/byteswap.h new file mode 100644 index 00000000..c7bc3c87 --- /dev/null +++ b/sp/src/public/tier1/byteswap.h @@ -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( int 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 */
|