Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages
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 #include "csqint.h" 00032 00033 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5))) 00034 00035 struct csEndianSwap4 00036 { 00037 unsigned char b1, b2, b3, b4; 00038 }; 00039 00040 struct csEndianSwap8 00041 { 00042 unsigned char b1, b2, b3, b4, 00043 b5, b6, b7, b8; 00044 }; 00045 00046 #ifdef CS_BIG_ENDIAN 00047 # define csBigEndianLongLong(x) x 00048 # define csBigEndianLong(x) x 00049 # define csBigEndianShort(x) x 00050 # define csBigEndianFloat(x) x 00051 #else 00052 00054 static inline uint64 csBigEndianLongLong (uint64 l) 00055 { 00056 uint64 r; 00057 csEndianSwap8 *p1 = (csEndianSwap8 *)&l; 00058 csEndianSwap8 *p2 = (csEndianSwap8 *)&r; 00059 p2->b1 = p1->b8; 00060 p2->b2 = p1->b7; 00061 p2->b3 = p1->b6; 00062 p2->b4 = p1->b5; 00063 p2->b5 = p1->b4; 00064 p2->b6 = p1->b3; 00065 p2->b7 = p1->b2; 00066 p2->b8 = p1->b1; 00067 return r; 00068 } 00069 00070 00072 static inline uint32 csBigEndianLong (uint32 l) 00073 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); } 00074 00076 static inline uint16 csBigEndianShort (uint16 s) 00077 { return uint16((s >> 8) | (s << 8)); } 00078 00080 static inline float csBigEndianFloat (float f) 00081 { 00082 //@@WARNING: Should be removed -- use csFloatToLong instead 00083 unsigned char tmp; 00084 csEndianSwap4 *pf = (csEndianSwap4 *)&f; 00085 tmp = pf->b1; pf->b1 = pf->b4; pf->b4 = tmp; 00086 tmp = pf->b2; pf->b2 = pf->b3; pf->b3 = tmp; 00087 return f; 00088 } 00089 00090 #endif // CS_BIG_ENDIAN 00091 00092 #ifdef CS_LITTLE_ENDIAN 00093 # define csLittleEndianLongLong(x) x 00094 # define csLittleEndianLong(x) x 00095 # define csLittleEndianShort(x) x 00096 # define csLittleEndianFloat(x) x 00097 #else 00098 00100 static inline uint64 csLittleEndianLongLong (uint64 l) 00101 { 00102 uint64 r; 00103 csEndianSwap8 *p1 = (csEndianSwap8 *)&l; 00104 csEndianSwap8 *p2 = (csEndianSwap8 *)&r; 00105 p2->b1 = p1->b8; 00106 p2->b2 = p1->b7; 00107 p2->b3 = p1->b6; 00108 p2->b4 = p1->b5; 00109 p2->b5 = p1->b4; 00110 p2->b6 = p1->b3; 00111 p2->b7 = p1->b2; 00112 p2->b8 = p1->b1; 00113 return r; 00114 } 00115 00117 static inline uint32 csLittleEndianLong (uint32 l) 00118 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); } 00119 00121 static inline uint16 csLittleEndianShort (uint16 s) 00122 { return (s >> 8) | (s << 8); } 00123 00125 static inline float csLittleEndianFloat (float f) 00126 { 00127 unsigned char tmp; 00128 csEndianSwap4 *pf = (csEndianSwap4 *)&f; 00129 tmp = pf->b1; pf->b1 = pf->b4; pf->b4 = tmp; 00130 tmp = pf->b2; pf->b2 = pf->b3; pf->b3 = tmp; 00131 return f; 00132 } 00133 00134 #endif // CS_LITTLE_ENDIAN 00135 00136 /* 00137 To be able to painlessly transfer files betwen platforms, we should 00138 avoid using native floating-point format. Here are a couple of routines 00139 that are guaranteed to work on all platforms. 00140 00141 The floating point is converted to a fixed 1.7.25 bits format 00142 (one bit sign, 7 bits exponent, 25 bits mantissa) and back, 00143 so that we can binary store floating-point number without 00144 cross-platform problems. If you wonder why 1+7+25 = 33 while we 00145 only have 32 bits, we'll ommit the most significant bit of mantissa 00146 since it is always 1 (we use normalized numbers). This increases the 00147 precision twice. 00148 00149 For double, we use one bit sign, 15 bits exponent, 49 bits mantissa. 00150 */ 00151 00156 static inline int32 csFloatToLong (float f) 00157 { 00158 int exp; 00159 int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000); 00160 int32 sign = mant & 0x80000000; 00161 if (mant < 0) mant = -mant; 00162 if (exp > 63) exp = 63; else if (exp < -64) exp = -64; 00163 return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff); 00164 } 00165 00167 static inline float csLongToFloat (int32 l) 00168 { 00169 int exp = (l >> 24) & 0x7f; 00170 if (exp & 0x40) exp = exp | ~0x7f; 00171 float mant = float (l & 0x00ffffff) / 0x1000000; 00172 if (l & 0x80000000) mant = -mant; 00173 return (float) ldexp (mant, exp); 00174 } 00175 00176 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble() 00177 * 00178 * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++ 00179 * under -ansi -pedantic, and we want this header to be useful to external 00180 * projects which use -ansi -pedantic. Instead, we use bit shifts, such as (1 00181 * << 59), and construct `mask' manually. 00182 */ 00183 00185 static inline int64 csDoubleToLongLong (double d) 00186 { 00187 int exp; 00188 int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48)); 00189 int64 sign = mant & ((int64)1 << 59); 00190 if (mant < 0) mant = -mant; 00191 if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768; 00192 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00193 return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask); 00194 } 00195 00197 static inline double csLongLongToDouble (int64 i) 00198 { 00199 int exp = (i >> 48) & 0x7fff; 00200 if (exp & 0x4000) exp = exp | ~0x7fff; 00201 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00202 double mant = double (i & mask) / ((int64)1 << 48); 00203 if (i & ((int64)1 << 59)) mant = -mant; 00204 return ldexp (mant, exp); 00205 } 00206 00216 00217 static inline short csFloatToShort (float f) 00218 { 00219 int exp; 00220 long mant = csQroundSure (frexp (f, &exp) * 0x1000); 00221 long sign = mant & 0x8000; 00222 if (mant < 0) mant = -mant; 00223 if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8; 00224 return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff)); 00225 } 00226 00228 static inline float csShortToFloat (short s) 00229 { 00230 int exp = (s >> 11) & 0xf; 00231 if (exp & 0x8) exp = exp | ~0xf; 00232 float mant = float ((s & 0x07ff) | 0x0800) / 0x1000; 00233 if (s & 0x8000) mant = -mant; 00234 return (float) ldexp (mant, exp); 00235 } 00236 00239 00240 static inline uint64 csConvertEndian (uint64 l) 00241 { return csLittleEndianLongLong (l); } 00242 00244 static inline int64 csConvertEndian (int64 l) 00245 { return csLittleEndianLongLong (l); } 00246 00248 static inline uint32 csConvertEndian (uint32 l) 00249 { return csLittleEndianLong (l); } 00250 00252 static inline int32 csConvertEndian (int32 l) 00253 { return csLittleEndianLong (l); } 00254 00256 static inline int16 csConvertEndian (int16 s) 00257 { return csLittleEndianShort (s); } 00258 00260 static inline uint16 csConvertEndian (uint16 s) 00261 { return csLittleEndianShort (s); } 00262 00264 static inline float csConvertEndian (float f) 00265 { return csLittleEndianFloat (f); } 00266 00268 inline uint16 csGetLittleEndianShort (const void *buff) 00269 { 00270 #ifdef CS_STRICT_ALIGNMENT 00271 uint16 s; memcpy (&s, buff, sizeof (s)); 00272 return csLittleEndianShort (s); 00273 #else 00274 return csLittleEndianShort (*(uint16 *)buff); 00275 #endif 00276 } 00277 00279 inline uint32 csGetLittleEndianLong (const void *buff) 00280 { 00281 #ifdef CS_STRICT_ALIGNMENT 00282 uint32 l; memcpy (&l, buff, sizeof (l)); 00283 return csLittleEndianLong (l); 00284 #else 00285 return csLittleEndianLong (*(uint32 *)buff); 00286 #endif 00287 } 00288 00290 inline float csGetLittleEndianFloat32 (const void *buff) 00291 { uint32 l = csGetLittleEndianLong (buff); return csLongToFloat (l); } 00292 00294 inline float csGetLittleEndianFloat16 (const void *buff) 00295 { uint16 s = csGetLittleEndianShort (buff); return csShortToFloat (s); } 00296 00298 inline void csSetLittleEndianShort (void *buff, uint16 s) 00299 { 00300 #ifdef CS_STRICT_ALIGNMENT 00301 s = csLittleEndianShort (s); 00302 memcpy (buff, &s, sizeof (s)); 00303 #else 00304 *((uint16 *)buff) = csLittleEndianShort (s); 00305 #endif 00306 } 00307 00309 inline void csSetLittleEndianLong (void *buff, uint32 l) 00310 { 00311 #ifdef CS_STRICT_ALIGNMENT 00312 l = csLittleEndianLong (l); 00313 memcpy (buff, &l, sizeof (l)); 00314 #else 00315 *((uint32 *)buff) = csLittleEndianLong (l); 00316 #endif 00317 } 00318 00320 inline void csSetLittleEndianFloat32 (void *buff, float f) 00321 { csSetLittleEndianLong (buff, csFloatToLong (f)); } 00322 00324 inline void csSetLittleEndianFloat16 (void *buff, float f) 00325 { csSetLittleEndianShort (buff, csFloatToShort (f)); } 00326 00327 00329 inline uint16 csGetBigEndianShort (const void *buff) 00330 { 00331 #ifdef CS_STRICT_ALIGNMENT 00332 uint16 s; memcpy (&s, buff, sizeof (s)); 00333 return csBigEndianShort (s); 00334 #else 00335 return csBigEndianShort (*(uint16 *)buff); 00336 #endif 00337 } 00338 00340 inline uint32 csGetBigEndianLong (const void *buff) 00341 { 00342 #ifdef CS_STRICT_ALIGNMENT 00343 uint32 l; memcpy (&l, buff, sizeof (l)); 00344 return csBigEndianLong (l); 00345 #else 00346 return csBigEndianLong (*(uint32 *)buff); 00347 #endif 00348 } 00349 00351 inline float csGetBigEndianFloat32 (const void *buff) 00352 { uint32 l = csGetBigEndianLong (buff); return csLongToFloat (l); } 00353 00355 inline float csGetBigEndianFloat16 (const void *buff) 00356 { uint16 s = csGetBigEndianShort (buff); return csShortToFloat (s); } 00357 00359 inline void csSetBigEndianShort (void *buff, uint16 s) 00360 { 00361 #ifdef CS_STRICT_ALIGNMENT 00362 s = csBigEndianShort (s); 00363 memcpy (buff, &s, sizeof (s)); 00364 #else 00365 *((uint16 *)buff) = csBigEndianShort (s); 00366 #endif 00367 } 00368 00370 inline void csSetBigEndianLong (void *buff, uint32 l) 00371 { 00372 #ifdef CS_STRICT_ALIGNMENT 00373 l = csBigEndianLong (l); 00374 memcpy (buff, &l, sizeof (l)); 00375 #else 00376 *((uint32 *)buff) = csBigEndianLong (l); 00377 #endif 00378 } 00379 00381 inline void csSetBigEndianFloat32 (void *buff, float f) 00382 { csSetBigEndianLong (buff, csFloatToLong (f)); } 00383 00385 inline void csSetBigEndianFloat16 (void *buff, float f) 00386 { csSetBigEndianShort (buff, csFloatToShort (f)); } 00387 00390 #endif // __CS_CSENDIAN_H__
Generated for Crystal Space by doxygen 1.3.9.1