csutil/csendian.h
Go to the documentation of this file.00001 /* 00002 Copyright (C) 1998 by Jorrit Tyberghein 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CS_CSENDIAN_H__ 00020 #define __CS_CSENDIAN_H__ 00021 00029 #include <math.h> 00030 #include "cstypes.h" 00031 #if defined(CS_HAVE_BYTESWAP_H) 00032 #include <byteswap.h> 00033 #endif 00034 00035 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5))) 00036 00040 struct csSwapBytes 00041 { 00042 public: 00044 00045 static CS_FORCEINLINE uint16 Swap (uint16 s) 00046 { 00047 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00048 return _byteswap_ushort (s); 00049 #elif defined(CS_HAVE_BYTESWAP_H) 00050 return bswap_16 (s); 00051 #else 00052 return (s >> 8) | (s << 8); 00053 #endif 00054 } 00055 static CS_FORCEINLINE int16 Swap (int16 s) 00056 { return (int16)Swap ((uint16)s); } 00057 static CS_FORCEINLINE uint32 Swap (uint32 l) 00058 { 00059 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00060 return _byteswap_ulong (l); 00061 #elif defined(CS_HAVE_BYTESWAP_H) 00062 return bswap_32 (l); 00063 #else 00064 return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); 00065 #endif 00066 } 00067 static CS_FORCEINLINE int32 Swap (int32 l) 00068 { return (int32)Swap ((uint32)l); } 00069 static CS_FORCEINLINE uint64 Swap (uint64 l) 00070 { 00071 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00072 return _byteswap_uint64 (l); 00073 #elif defined(CS_HAVE_BYTESWAP_H) && !defined(__STRICT_ANSI__) 00074 return bswap_64 (l); 00075 #else 00076 union 00077 { 00078 uint64 ui64; 00079 uint32 ui32[2]; 00080 } u1, u2; 00081 u1.ui64 = l; 00082 u2.ui32[0] = Swap (u1.ui32[1]); 00083 u2.ui32[1] = Swap (u1.ui32[0]); 00084 return u2.ui64; 00085 #endif 00086 } 00087 static CS_FORCEINLINE int64 Swap (int64 l) 00088 { return (int64)Swap ((uint64)l); } 00089 00090 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Swap (x); } 00091 static CS_FORCEINLINE int16 Int16 (int16 x) { return Swap (x); } 00092 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Swap (x); } 00093 static CS_FORCEINLINE int32 Int32 (int32 x) { return Swap (x); } 00094 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Swap (x); } 00095 static CS_FORCEINLINE int64 Int64 (int64 x) { return Swap (x); } 00097 }; 00098 00099 #ifdef CS_BIG_ENDIAN 00100 struct csBigEndian 00101 #else 00107 struct csLittleEndian 00108 #endif 00109 { 00111 00112 static CS_FORCEINLINE uint16 Convert (uint16 x) { return x; } 00113 static CS_FORCEINLINE int16 Convert (int16 x) { return x; } 00114 static CS_FORCEINLINE uint32 Convert (uint32 x) { return x; } 00115 static CS_FORCEINLINE int32 Convert (int32 x) { return x; } 00116 static CS_FORCEINLINE uint64 Convert (uint64 x) { return x; } 00117 static CS_FORCEINLINE int64 Convert (int64 x) { return x; } 00118 00119 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00120 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00121 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00122 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00123 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00124 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00126 }; 00127 00128 #ifdef CS_LITTLE_ENDIAN 00129 00134 struct csBigEndian 00135 #else 00136 struct csLittleEndian 00137 #endif 00138 { 00139 public: 00141 00142 static CS_FORCEINLINE uint16 Convert (uint16 s) 00143 { return csSwapBytes::Swap (s); } 00144 static CS_FORCEINLINE int16 Convert (int16 s) 00145 { return csSwapBytes::Swap (s); } 00146 static CS_FORCEINLINE uint32 Convert (uint32 l) 00147 { return csSwapBytes::Swap (l); } 00148 static CS_FORCEINLINE int32 Convert (int32 l) 00149 { return csSwapBytes::Swap (l); } 00150 static CS_FORCEINLINE uint64 Convert (uint64 l) 00151 { return csSwapBytes::Swap (l); } 00152 static CS_FORCEINLINE int64 Convert (int64 l) 00153 { return csSwapBytes::Swap (l); } 00154 00155 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00156 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00157 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00158 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00159 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00160 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00162 }; 00163 00167 struct csIEEEfloat 00168 { 00169 /* \todo It would be even better if we also check for sizeof (float) 00170 * in configure or so. */ 00171 #ifdef CS_IEEE_DOUBLE_FORMAT 00173 static CS_FORCEINLINE uint32 FromNative (float f) 00174 { 00175 union 00176 { 00177 float f; 00178 uint32 ui32; 00179 } u; 00180 u.f = f; 00181 return u.ui32; 00182 } 00184 static CS_FORCEINLINE float ToNative (uint32 f) 00185 { 00186 union 00187 { 00188 float f; 00189 uint32 ui32; 00190 } u; 00191 u.ui32 = f; 00192 return u.f; 00193 } 00194 #else 00195 #error Do not know how to convert to IEEE floats 00196 #endif 00197 }; 00198 00207 struct csGetFromAddress 00208 { 00210 00211 static CS_FORCEINLINE uint16 UInt16 (const void *buff) 00212 { 00213 #ifdef CS_STRICT_ALIGNMENT 00214 uint16 s; memcpy (&s, buff, sizeof (s)); 00215 return s; 00216 #else 00217 return *(uint16 *)buff; 00218 #endif 00219 } 00220 static CS_FORCEINLINE int16 Int16 (const void *buff) 00221 { return (int16)UInt16 (buff); } 00222 static CS_FORCEINLINE uint32 UInt32 (const void *buff) 00223 { 00224 #ifdef CS_STRICT_ALIGNMENT 00225 uint32 s; memcpy (&s, buff, sizeof (s)); 00226 return s; 00227 #else 00228 return *(uint32 *)buff; 00229 #endif 00230 } 00231 static CS_FORCEINLINE int32 Int32 (const void *buff) 00232 { return (int32)UInt32 (buff); } 00233 static CS_FORCEINLINE uint64 UInt64 (const void *buff) 00234 { 00235 #ifdef CS_STRICT_ALIGNMENT 00236 uint64 s; memcpy (&s, buff, sizeof (s)); 00237 return s; 00238 #else 00239 return *(uint64 *)buff; 00240 #endif 00241 } 00242 static CS_FORCEINLINE int64 Int64 (const void *buff) 00243 { return (int64)UInt64 (buff); } 00245 }; 00246 00255 struct csSetToAddress 00256 { 00258 00259 static CS_FORCEINLINE void UInt16 (void *buff, uint16 s) 00260 { 00261 #ifdef CS_STRICT_ALIGNMENT 00262 memcpy (buff, &s, sizeof (s)); 00263 #else 00264 *((uint16 *)buff) = s; 00265 #endif 00266 } 00267 static CS_FORCEINLINE void Int16 (void *buff, int16 s) 00268 { UInt16 (buff, (uint16)s); } 00269 static CS_FORCEINLINE void UInt32 (void *buff, uint32 s) 00270 { 00271 #ifdef CS_STRICT_ALIGNMENT 00272 memcpy (buff, &s, sizeof (s)); 00273 #else 00274 *((uint32 *)buff) = s; 00275 #endif 00276 } 00277 static CS_FORCEINLINE void Int32 (void *buff, int32 s) 00278 { UInt32 (buff, (uint32)s); } 00279 static CS_FORCEINLINE void UInt64 (void *buff, uint64 s) 00280 { 00281 #ifdef CS_STRICT_ALIGNMENT 00282 memcpy (buff, &s, sizeof (s)); 00283 #else 00284 *((uint64 *)buff) = s; 00285 #endif 00286 } 00287 static CS_FORCEINLINE void Int64 (void *buff, int64 s) 00288 { UInt64 (buff, (uint64)s); } 00290 }; 00291 00297 00298 CS_DEPRECATED_METHOD static inline uint64 csBigEndianLongLong (uint64 l) 00299 { return csBigEndian::Convert (l); } 00300 00302 CS_DEPRECATED_METHOD static inline uint32 csBigEndianLong (uint32 l) 00303 { return csBigEndian::Convert (l); } 00304 00306 CS_DEPRECATED_METHOD static inline uint16 csBigEndianShort (uint16 s) 00307 { return csBigEndian::Convert (s); } 00308 00310 CS_DEPRECATED_METHOD static inline float csBigEndianFloat (float f) 00311 { 00312 union 00313 { 00314 float f; 00315 uint32 ui32; 00316 } u; 00317 u.f = f; 00318 u.ui32 = csBigEndian::Convert (u.ui32); 00319 return u.f; 00320 } 00321 00323 CS_DEPRECATED_METHOD static inline uint64 csLittleEndianLongLong (uint64 l) 00324 { return csLittleEndian::Convert (l); } 00325 00327 CS_DEPRECATED_METHOD static inline uint32 csLittleEndianLong (uint32 l) 00328 { return csLittleEndian::Convert (l); } 00329 00331 CS_DEPRECATED_METHOD static inline uint16 csLittleEndianShort (uint16 s) 00332 { return csLittleEndian::Convert (s); } 00333 00335 CS_DEPRECATED_METHOD static inline float csLittleEndianFloat (float f) 00336 { 00337 union 00338 { 00339 float f; 00340 uint32 ui32; 00341 } u; 00342 u.f = f; 00343 u.ui32 = csLittleEndian::Convert (u.ui32); 00344 return u.f; 00345 } 00346 00347 /* 00348 To be able to painlessly transfer files betwen platforms, we should 00349 avoid using native floating-point format. Here are a couple of routines 00350 that are guaranteed to work on all platforms. 00351 00352 The floating point is converted to a fixed 1.7.25 bits format 00353 (one bit sign, 7 bits exponent, 25 bits mantissa) and back, 00354 so that we can binary store floating-point number without 00355 cross-platform problems. If you wonder why 1+7+25 = 33 while we 00356 only have 32 bits, we'll ommit the most significant bit of mantissa 00357 since it is always 1 (we use normalized numbers). This increases the 00358 precision twice. 00359 00360 For double, we use one bit sign, 15 bits exponent, 49 bits mantissa. 00361 */ 00362 00367 /*CS_DEPRECATED_METHOD*/ static inline int32 csFloatToLong (float f) 00368 { 00369 int exp; 00370 int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000); 00371 int32 sign = mant & 0x80000000; 00372 if (mant < 0) mant = -mant; 00373 if (exp > 63) exp = 63; else if (exp < -64) exp = -64; 00374 return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff); 00375 } 00376 00381 /*CS_DEPRECATED_METHOD*/ static inline float csLongToFloat (int32 l) 00382 { 00383 int exp = (l >> 24) & 0x7f; 00384 if (exp & 0x40) exp = exp | ~0x7f; 00385 float mant = float (l & 0x00ffffff) / 0x1000000; 00386 if (l & 0x80000000) mant = -mant; 00387 return (float) ldexp (mant, exp); 00388 } 00389 00390 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble() 00391 * 00392 * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++ 00393 * under -ansi -pedantic, and we want this header to be useful to external 00394 * projects which use -ansi -pedantic. Instead, we use bit shifts, such as (1 00395 * << 59), and construct `mask' manually. 00396 */ 00397 00402 /*CS_DEPRECATED_METHOD*/ static inline int64 csDoubleToLongLong (double d) 00403 { 00404 int exp; 00405 int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48)); 00406 int64 sign = mant & ((int64)1 << 59); 00407 if (mant < 0) mant = -mant; 00408 if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768; 00409 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00410 return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask); 00411 } 00412 00417 /*CS_DEPRECATED_METHOD*/ static inline double csLongLongToDouble (int64 i) 00418 { 00419 int exp = (i >> 48) & 0x7fff; 00420 if (exp & 0x4000) exp = exp | ~0x7fff; 00421 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00422 double mant = double (i & mask) / ((int64)1 << 48); 00423 if (i & ((int64)1 << 59)) mant = -mant; 00424 return ldexp (mant, exp); 00425 } 00426 00427 /* *\name Floating point conversions 00428 * These routines are used for converting floating-point numbers 00429 * into 16-bit shorts and back. This is useful for low-precision data. 00430 * They use the 1.4.12 format. The range of numbers that can be represented 00431 * in this format is from 2^-8 to 2^7. The precision for numbers near to 00432 * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03. 00433 * @{ */ 00434 00439 /*CS_DEPRECATED_METHOD*/ static inline short csFloatToShort (float f) 00440 { 00441 int exp; 00442 long mant = csQroundSure (frexp (f, &exp) * 0x1000); 00443 long sign = mant & 0x8000; 00444 if (mant < 0) mant = -mant; 00445 if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8; 00446 return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff)); 00447 } 00448 00453 /*CS_DEPRECATED_METHOD*/ static inline float csShortToFloat (short s) 00454 { 00455 int exp = (s >> 11) & 0xf; 00456 if (exp & 0x8) exp = exp | ~0xf; 00457 float mant = float ((s & 0x07ff) | 0x0800) / 0x1000; 00458 if (s & 0x8000) mant = -mant; 00459 return (float) ldexp (mant, exp); 00460 } 00461 00464 00465 CS_DEPRECATED_METHOD static inline uint64 csConvertEndian (uint64 l) 00466 { return csLittleEndian::Convert (l); } 00467 00469 CS_DEPRECATED_METHOD static inline int64 csConvertEndian (int64 l) 00470 { return csLittleEndian::Convert (l); } 00471 00473 CS_DEPRECATED_METHOD static inline uint32 csConvertEndian (uint32 l) 00474 { return csLittleEndian::Convert (l); } 00475 00477 CS_DEPRECATED_METHOD static inline int32 csConvertEndian (int32 l) 00478 { return csLittleEndian::Convert (l); } 00479 00481 CS_DEPRECATED_METHOD static inline int16 csConvertEndian (int16 s) 00482 { return csLittleEndian::Convert (s); } 00483 00485 CS_DEPRECATED_METHOD static inline uint16 csConvertEndian (uint16 s) 00486 { return csLittleEndian::Convert (s); } 00487 00489 CS_DEPRECATED_METHOD static inline float csConvertEndian (float f) 00490 { 00491 union 00492 { 00493 float f; 00494 uint32 ui32; 00495 } u; 00496 u.f = f; 00497 u.ui32 = csLittleEndian::Convert (u.ui32); 00498 return u.f; 00499 } 00500 00502 CS_DEPRECATED_METHOD inline uint16 csGetLittleEndianShort (const void *buff) 00503 { 00504 return csLittleEndian::Convert (csGetFromAddress::UInt16 (buff)); 00505 } 00506 00508 CS_DEPRECATED_METHOD inline uint32 csGetLittleEndianLong (const void *buff) 00509 { 00510 return csLittleEndian::Convert (csGetFromAddress::UInt32 (buff)); 00511 } 00512 00514 CS_DEPRECATED_METHOD inline float csGetLittleEndianFloat32 (const void *buff) 00515 { 00516 uint32 l = csLittleEndian::Convert (csGetFromAddress::UInt32 (buff)); 00517 return csLongToFloat (l); 00518 } 00519 00521 CS_DEPRECATED_METHOD inline float csGetLittleEndianFloat16 (const void *buff) 00522 { 00523 uint16 s = csLittleEndian::Convert (csGetFromAddress::UInt16 (buff)); 00524 return csShortToFloat (s); 00525 } 00526 00531 #endif // __CS_CSENDIAN_H__
Generated for Crystal Space by doxygen 1.4.7