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 00032 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5))) 00033 00037 struct csSwapBytes 00038 { 00039 private: 00040 struct Swap8 00041 { 00042 uint8 b1, b2, b3, b4, b5, b6, b7, b8; 00043 }; 00044 public: 00046 00047 static CS_FORCEINLINE uint16 Swap (uint16 s) 00048 { return (s >> 8) | (s << 8); } 00049 static CS_FORCEINLINE int16 Swap (int16 s) 00050 { return (int16)Swap ((uint16)s); } 00051 static CS_FORCEINLINE uint32 Swap (uint32 l) 00052 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); } 00053 static CS_FORCEINLINE int32 Swap (int32 l) 00054 { return (int32)Swap ((uint32)l); } 00055 static CS_FORCEINLINE uint64 Swap (uint64 l) 00056 { 00057 uint64 r; 00058 Swap8 *p1 = (Swap8 *)&l; 00059 Swap8 *p2 = (Swap8 *)&r; 00060 p2->b1 = p1->b8; 00061 p2->b2 = p1->b7; 00062 p2->b3 = p1->b6; 00063 p2->b4 = p1->b5; 00064 p2->b5 = p1->b4; 00065 p2->b6 = p1->b3; 00066 p2->b7 = p1->b2; 00067 p2->b8 = p1->b1; 00068 return r; 00069 } 00070 static CS_FORCEINLINE int64 Swap (int64 l) 00071 { return (int64)Swap ((uint64)l); } 00072 00073 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Swap (x); } 00074 static CS_FORCEINLINE int16 Int16 (int16 x) { return Swap (x); } 00075 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Swap (x); } 00076 static CS_FORCEINLINE int32 Int32 (int32 x) { return Swap (x); } 00077 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Swap (x); } 00078 static CS_FORCEINLINE int64 Int64 (int64 x) { return Swap (x); } 00080 }; 00081 00082 #ifdef CS_BIG_ENDIAN 00083 struct csBigEndian 00084 #else 00090 struct csLittleEndian 00091 #endif 00092 { 00094 00095 static CS_FORCEINLINE uint16 Convert (uint16 x) { return x; } 00096 static CS_FORCEINLINE int16 Convert (int16 x) { return x; } 00097 static CS_FORCEINLINE uint32 Convert (uint32 x) { return x; } 00098 static CS_FORCEINLINE int32 Convert (int32 x) { return x; } 00099 static CS_FORCEINLINE uint64 Convert (uint64 x) { return x; } 00100 static CS_FORCEINLINE int64 Convert (int64 x) { return x; } 00101 00102 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00103 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00104 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00105 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00106 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00107 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00109 }; 00110 00111 #ifdef CS_LITTLE_ENDIAN 00112 00117 struct csBigEndian 00118 #else 00119 struct csLittleEndian 00120 #endif 00121 { 00122 public: 00124 00125 static CS_FORCEINLINE uint16 Convert (uint16 s) 00126 { return csSwapBytes::Swap (s); } 00127 static CS_FORCEINLINE int16 Convert (int16 s) 00128 { return csSwapBytes::Swap (s); } 00129 static CS_FORCEINLINE uint32 Convert (uint32 l) 00130 { return csSwapBytes::Swap (l); } 00131 static CS_FORCEINLINE int32 Convert (int32 l) 00132 { return csSwapBytes::Swap (l); } 00133 static CS_FORCEINLINE uint64 Convert (uint64 l) 00134 { return csSwapBytes::Swap (l); } 00135 static CS_FORCEINLINE int64 Convert (int64 l) 00136 { return csSwapBytes::Swap (l); } 00137 00138 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00139 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00140 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00141 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00142 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00143 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00145 }; 00146 00150 struct csIEEEfloat 00151 { 00152 #ifdef CS_IEEE_DOUBLE_FORMAT 00153 00154 static CS_FORCEINLINE uint32 FromNative (float f) 00155 { return *(uint32*)&f; } 00157 static CS_FORCEINLINE float ToNative (uint32 f) 00158 { return *(float*)&f; } 00159 #else 00160 #error Do not know how to convert to IEEE floats 00161 #endif 00162 }; 00163 00172 struct csGetFromAddress 00173 { 00175 00176 static CS_FORCEINLINE uint16 UInt16 (const void *buff) 00177 { 00178 #ifdef CS_STRICT_ALIGNMENT 00179 uint16 s; memcpy (&s, buff, sizeof (s)); 00180 return s; 00181 #else 00182 return *(uint16 *)buff; 00183 #endif 00184 } 00185 static CS_FORCEINLINE int16 Int16 (const void *buff) 00186 { return (int16)UInt16 (buff); } 00187 static CS_FORCEINLINE uint32 UInt32 (const void *buff) 00188 { 00189 #ifdef CS_STRICT_ALIGNMENT 00190 uint32 s; memcpy (&s, buff, sizeof (s)); 00191 return s; 00192 #else 00193 return *(uint32 *)buff; 00194 #endif 00195 } 00196 static CS_FORCEINLINE int32 Int32 (const void *buff) 00197 { return (int32)UInt32 (buff); } 00198 static CS_FORCEINLINE uint64 UInt64 (const void *buff) 00199 { 00200 #ifdef CS_STRICT_ALIGNMENT 00201 uint64 s; memcpy (&s, buff, sizeof (s)); 00202 return s; 00203 #else 00204 return *(uint64 *)buff; 00205 #endif 00206 } 00207 static CS_FORCEINLINE int64 Int64 (const void *buff) 00208 { return (int64)UInt64 (buff); } 00210 }; 00211 00220 struct csSetToAddress 00221 { 00223 00224 static CS_FORCEINLINE void UInt16 (void *buff, uint16 s) 00225 { 00226 #ifdef CS_STRICT_ALIGNMENT 00227 memcpy (buff, &s, sizeof (s)); 00228 #else 00229 *((uint16 *)buff) = s; 00230 #endif 00231 } 00232 static CS_FORCEINLINE void Int16 (void *buff, int16 s) 00233 { UInt16 (buff, (uint16)s); } 00234 static CS_FORCEINLINE void UInt32 (void *buff, uint32 s) 00235 { 00236 #ifdef CS_STRICT_ALIGNMENT 00237 memcpy (buff, &s, sizeof (s)); 00238 #else 00239 *((uint32 *)buff) = s; 00240 #endif 00241 } 00242 static CS_FORCEINLINE void Int32 (void *buff, int32 s) 00243 { UInt32 (buff, (uint32)s); } 00244 static CS_FORCEINLINE void UInt64 (void *buff, uint64 s) 00245 { 00246 #ifdef CS_STRICT_ALIGNMENT 00247 memcpy (buff, &s, sizeof (s)); 00248 #else 00249 *((uint64 *)buff) = s; 00250 #endif 00251 } 00252 static CS_FORCEINLINE void Int64 (void *buff, int64 s) 00253 { UInt64 (buff, (uint64)s); } 00255 }; 00256 00262 00263 static inline uint64 csBigEndianLongLong (uint64 l) 00264 { return csBigEndian::Convert (l); } 00265 00267 static inline uint32 csBigEndianLong (uint32 l) 00268 { return csBigEndian::Convert (l); } 00269 00271 static inline uint16 csBigEndianShort (uint16 s) 00272 { return csBigEndian::Convert (s); } 00273 00275 static inline float csBigEndianFloat (float f) 00276 { 00277 uint32 u = csBigEndian::Convert (*(uint32*)&f); 00278 return *(float*)&u; 00279 } 00280 00282 static inline uint64 csLittleEndianLongLong (uint64 l) 00283 { return csLittleEndian::Convert (l); } 00284 00286 static inline uint32 csLittleEndianLong (uint32 l) 00287 { return csLittleEndian::Convert (l); } 00288 00290 static inline uint16 csLittleEndianShort (uint16 s) 00291 { return csLittleEndian::Convert (s); } 00292 00294 static inline float csLittleEndianFloat (float f) 00295 { 00296 uint32 u = csLittleEndian::Convert (*(uint32*)&f); 00297 return *(float*)&u; 00298 } 00299 00300 /* 00301 To be able to painlessly transfer files betwen platforms, we should 00302 avoid using native floating-point format. Here are a couple of routines 00303 that are guaranteed to work on all platforms. 00304 00305 The floating point is converted to a fixed 1.7.25 bits format 00306 (one bit sign, 7 bits exponent, 25 bits mantissa) and back, 00307 so that we can binary store floating-point number without 00308 cross-platform problems. If you wonder why 1+7+25 = 33 while we 00309 only have 32 bits, we'll ommit the most significant bit of mantissa 00310 since it is always 1 (we use normalized numbers). This increases the 00311 precision twice. 00312 00313 For double, we use one bit sign, 15 bits exponent, 49 bits mantissa. 00314 */ 00315 00320 static inline int32 csFloatToLong (float f) 00321 { 00322 int exp; 00323 int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000); 00324 int32 sign = mant & 0x80000000; 00325 if (mant < 0) mant = -mant; 00326 if (exp > 63) exp = 63; else if (exp < -64) exp = -64; 00327 return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff); 00328 } 00329 00334 static inline float csLongToFloat (int32 l) 00335 { 00336 int exp = (l >> 24) & 0x7f; 00337 if (exp & 0x40) exp = exp | ~0x7f; 00338 float mant = float (l & 0x00ffffff) / 0x1000000; 00339 if (l & 0x80000000) mant = -mant; 00340 return (float) ldexp (mant, exp); 00341 } 00342 00343 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble() 00344 * 00345 * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++ 00346 * under -ansi -pedantic, and we want this header to be useful to external 00347 * projects which use -ansi -pedantic. Instead, we use bit shifts, such as (1 00348 * << 59), and construct `mask' manually. 00349 */ 00350 00355 static inline int64 csDoubleToLongLong (double d) 00356 { 00357 int exp; 00358 int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48)); 00359 int64 sign = mant & ((int64)1 << 59); 00360 if (mant < 0) mant = -mant; 00361 if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768; 00362 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00363 return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask); 00364 } 00365 00370 static inline double csLongLongToDouble (int64 i) 00371 { 00372 int exp = (i >> 48) & 0x7fff; 00373 if (exp & 0x4000) exp = exp | ~0x7fff; 00374 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00375 double mant = double (i & mask) / ((int64)1 << 48); 00376 if (i & ((int64)1 << 59)) mant = -mant; 00377 return ldexp (mant, exp); 00378 } 00379 00380 /* *\name Floating point conversions 00381 * These routines are used for converting floating-point numbers 00382 * into 16-bit shorts and back. This is useful for low-precision data. 00383 * They use the 1.4.12 format. The range of numbers that can be represented 00384 * in this format is from 2^-8 to 2^7. The precision for numbers near to 00385 * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03. 00386 * @{ */ 00387 00392 static inline short csFloatToShort (float f) 00393 { 00394 int exp; 00395 long mant = csQroundSure (frexp (f, &exp) * 0x1000); 00396 long sign = mant & 0x8000; 00397 if (mant < 0) mant = -mant; 00398 if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8; 00399 return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff)); 00400 } 00401 00406 static inline float csShortToFloat (short s) 00407 { 00408 int exp = (s >> 11) & 0xf; 00409 if (exp & 0x8) exp = exp | ~0xf; 00410 float mant = float ((s & 0x07ff) | 0x0800) / 0x1000; 00411 if (s & 0x8000) mant = -mant; 00412 return (float) ldexp (mant, exp); 00413 } 00414 00417 00418 static inline uint64 csConvertEndian (uint64 l) 00419 { return csLittleEndianLongLong (l); } 00420 00422 static inline int64 csConvertEndian (int64 l) 00423 { return csLittleEndianLongLong (l); } 00424 00426 static inline uint32 csConvertEndian (uint32 l) 00427 { return csLittleEndianLong (l); } 00428 00430 static inline int32 csConvertEndian (int32 l) 00431 { return csLittleEndianLong (l); } 00432 00434 static inline int16 csConvertEndian (int16 s) 00435 { return csLittleEndianShort (s); } 00436 00438 static inline uint16 csConvertEndian (uint16 s) 00439 { return csLittleEndianShort (s); } 00440 00442 static inline float csConvertEndian (float f) 00443 { return csLittleEndianFloat (f); } 00444 00446 inline uint16 csGetLittleEndianShort (const void *buff) 00447 { 00448 return csLittleEndian::Convert (csGetFromAddress::UInt16 (buff)); 00449 } 00450 00452 inline uint32 csGetLittleEndianLong (const void *buff) 00453 { 00454 return csLittleEndian::Convert (csGetFromAddress::UInt32 (buff)); 00455 } 00456 00458 inline float csGetLittleEndianFloat32 (const void *buff) 00459 { uint32 l = csGetLittleEndianLong (buff); return csLongToFloat (l); } 00460 00462 inline float csGetLittleEndianFloat16 (const void *buff) 00463 { uint16 s = csGetLittleEndianShort (buff); return csShortToFloat (s); } 00464 00469 #endif // __CS_CSENDIAN_H__
Generated for Crystal Space by doxygen 1.4.6