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