CrystalSpace

Public API Reference

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