Counter Strike : Global Offensive Source Code
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.

268 lines
8.8 KiB

  1. //========= Copyright � 1996-2006, Valve LLC, All rights reserved. ============
  2. //
  3. // Purpose: Low level byte swapping routines.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #ifndef BYTESWAP_H
  8. #define BYTESWAP_H
  9. #if defined(_WIN32)
  10. #pragma once
  11. #endif
  12. #include "tier0/dbg.h"
  13. #include "datamap.h" // needed for typedescription_t. note datamap.h is tier1 as well.
  14. class CByteswap
  15. {
  16. public:
  17. CByteswap()
  18. {
  19. // Default behavior sets the target endian to match the machine native endian (no swap).
  20. SetTargetBigEndian( IsMachineBigEndian() );
  21. }
  22. //-----------------------------------------------------------------------------
  23. // Write a single field.
  24. //-----------------------------------------------------------------------------
  25. void SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField );
  26. //-----------------------------------------------------------------------------
  27. // Write a block of fields. Works a bit like the saverestore code.
  28. //-----------------------------------------------------------------------------
  29. void SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap );
  30. // Swaps fields for the templated type to the output buffer.
  31. template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, void *pBaseData, unsigned int objectCount = 1 )
  32. {
  33. for ( unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer )
  34. {
  35. SwapFieldsToTargetEndian( (void*)pOutputBuffer, pBaseData, &T::m_DataMap );
  36. pBaseData = (byte*)pBaseData + sizeof(T);
  37. }
  38. }
  39. // Swaps fields for the templated type in place.
  40. template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, unsigned int objectCount = 1 )
  41. {
  42. SwapFieldsToTargetEndian<T>( pOutputBuffer, (void*)pOutputBuffer, objectCount );
  43. }
  44. //-----------------------------------------------------------------------------
  45. // True if the current machine is detected as big endian.
  46. // (Endienness is effectively detected at compile time when optimizations are
  47. // enabled)
  48. //-----------------------------------------------------------------------------
  49. static bool IsMachineBigEndian()
  50. {
  51. short nIsBigEndian = 1;
  52. // if we are big endian, the first byte will be a 0, if little endian, it will be a one.
  53. return (bool)(0 == *(char *)&nIsBigEndian );
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Sets the target byte ordering we are swapping to or from.
  57. //
  58. // Braindead Endian Reference:
  59. // x86 is LITTLE Endian
  60. // PowerPC is BIG Endian
  61. //-----------------------------------------------------------------------------
  62. inline void SetTargetBigEndian( bool bigEndian )
  63. {
  64. m_bBigEndian = bigEndian;
  65. m_bSwapBytes = IsMachineBigEndian() != bigEndian;
  66. }
  67. // Changes target endian
  68. inline void FlipTargetEndian( void )
  69. {
  70. m_bSwapBytes = !m_bSwapBytes;
  71. m_bBigEndian = !m_bBigEndian;
  72. }
  73. // Forces byte swapping state, regardless of endianess
  74. inline void ActivateByteSwapping( bool bActivate )
  75. {
  76. SetTargetBigEndian( IsMachineBigEndian() != bActivate );
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Returns true if the target machine is the same as this one in endianness.
  80. //
  81. // Used to determine when a byteswap needs to take place.
  82. //-----------------------------------------------------------------------------
  83. inline bool IsSwappingBytes( void ) // Are bytes being swapped?
  84. {
  85. return m_bSwapBytes;
  86. }
  87. inline bool IsTargetBigEndian( void ) // What is the current target endian?
  88. {
  89. return m_bBigEndian;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // IsByteSwapped()
  93. //
  94. // When supplied with a chunk of input data and a constant or magic number
  95. // (in native format) determines the endienness of the current machine in
  96. // relation to the given input data.
  97. //
  98. // Returns:
  99. // 1 if input is the same as nativeConstant.
  100. // 0 if input is byteswapped relative to nativeConstant.
  101. // -1 if input is not the same as nativeConstant and not byteswapped either.
  102. //
  103. // ( This is useful for detecting byteswapping in magic numbers in structure
  104. // headers for example. )
  105. //-----------------------------------------------------------------------------
  106. template<typename T> inline int SourceIsNativeEndian( T input, T nativeConstant )
  107. {
  108. // If it's the same, it isn't byteswapped:
  109. if( input == nativeConstant )
  110. return 1;
  111. int output;
  112. LowLevelByteSwap<T>( &output, &input );
  113. if( output == nativeConstant )
  114. return 0;
  115. Assert( 0 ); // if we get here, input is neither a swapped nor unswapped version of nativeConstant.
  116. return -1;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Swaps an input buffer full of type T into the given output buffer.
  120. //
  121. // Swaps [count] items from the inputBuffer to the outputBuffer.
  122. // If inputBuffer is omitted or NULL, then it is assumed to be the same as
  123. // outputBuffer - effectively swapping the contents of the buffer in place.
  124. //-----------------------------------------------------------------------------
  125. template<typename T> inline void SwapBuffer( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
  126. {
  127. Assert( count >= 0 );
  128. Assert( outputBuffer );
  129. // Fail gracefully in release:
  130. if( count <=0 || !outputBuffer )
  131. return;
  132. // Optimization for the case when we are swapping in place.
  133. if( inputBuffer == NULL )
  134. {
  135. inputBuffer = outputBuffer;
  136. }
  137. // Swap everything in the buffer:
  138. for( int i = 0; i < count; i++ )
  139. {
  140. LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
  141. }
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Swaps an input buffer full of type T into the given output buffer.
  145. //
  146. // Swaps [count] items from the inputBuffer to the outputBuffer.
  147. // If inputBuffer is omitted or NULL, then it is assumed to be the same as
  148. // outputBuffer - effectively swapping the contents of the buffer in place.
  149. //-----------------------------------------------------------------------------
  150. template<typename T> inline void SwapBufferToTargetEndian( T* outputBuffer, T* inputBuffer = NULL, int count = 1 )
  151. {
  152. Assert( count >= 0 );
  153. Assert( outputBuffer );
  154. // Fail gracefully in release:
  155. if( count <=0 || !outputBuffer )
  156. return;
  157. // Optimization for the case when we are swapping in place.
  158. if( inputBuffer == NULL )
  159. {
  160. inputBuffer = outputBuffer;
  161. }
  162. // Are we already the correct endienness? ( or are we swapping 1 byte items? )
  163. if( !m_bSwapBytes || ( sizeof(T) == 1 ) )
  164. {
  165. // If we were just going to swap in place then return.
  166. if( !inputBuffer )
  167. return;
  168. // Otherwise copy the inputBuffer to the outputBuffer:
  169. if ( outputBuffer != inputBuffer )
  170. memcpy( outputBuffer, inputBuffer, count * sizeof( T ) );
  171. return;
  172. }
  173. // Swap everything in the buffer:
  174. for( int i = 0; i < count; i++ )
  175. {
  176. LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] );
  177. }
  178. }
  179. private:
  180. //-----------------------------------------------------------------------------
  181. // The lowest level byte swapping workhorse of doom. output always contains the
  182. // swapped version of input. ( Doesn't compare machine to target endianness )
  183. //-----------------------------------------------------------------------------
  184. template<typename T> static void LowLevelByteSwap( T *output, T *input )
  185. {
  186. T temp = *output;
  187. #if defined( _X360 )
  188. // Intrinsics need the source type to be fixed-point
  189. DWORD* word = (DWORD*)input;
  190. switch( sizeof(T) )
  191. {
  192. case 8:
  193. {
  194. __storewordbytereverse( *(word+1), 0, &temp );
  195. __storewordbytereverse( *(word+0), 4, &temp );
  196. }
  197. break;
  198. case 4:
  199. __storewordbytereverse( *word, 0, &temp );
  200. break;
  201. case 2:
  202. __storeshortbytereverse( *input, 0, &temp );
  203. break;
  204. case 1:
  205. Q_memcpy( &temp, input, 1 );
  206. break;
  207. default:
  208. Assert( "Invalid size in CByteswap::LowLevelByteSwap" && 0 );
  209. }
  210. #else
  211. for( unsigned int i = 0; i < sizeof(T); i++ )
  212. {
  213. ((unsigned char* )&temp)[i] = ((unsigned char*)input)[sizeof(T)-(i+1)];
  214. }
  215. #endif
  216. Q_memcpy( output, &temp, sizeof(T) );
  217. }
  218. #if defined( _X360 )
  219. // specialized for void * to get 360 XDK compile working despite changelist 281331
  220. //-----------------------------------------------------------------------------
  221. // The lowest level byte swapping workhorse of doom. output always contains the
  222. // swapped version of input. ( Doesn't compare machine to target endianness )
  223. //-----------------------------------------------------------------------------
  224. template<> static void LowLevelByteSwap( void **output, void **input )
  225. {
  226. AssertMsgOnce( sizeof(void *) == sizeof(unsigned int) , "void *'s on this platform are not four bytes!" );
  227. __storewordbytereverse( *reinterpret_cast<unsigned int *>(input), 0, output );
  228. }
  229. #endif
  230. unsigned int m_bSwapBytes : 1;
  231. unsigned int m_bBigEndian : 1;
  232. };
  233. #endif /* !BYTESWAP_H */