CrystalSpace

Public API Reference

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