CrystalSpace

Public API Reference

Main Page   Modules   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

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 
00031 #include <math.h>
00032 #include "cstypes.h"
00033 #include "qint.h"
00034 
00035 struct swap_4
00036 {
00037   unsigned char b1, b2, b3, b4;
00038 };
00039 
00040 struct swap_8
00041 {
00042   unsigned char b1, b2, b3, b4,
00043                 b5, b6, b7, b8;
00044 };
00045 
00046 #ifdef CS_BIG_ENDIAN
00047 #  define big_endian_longlong(x) x
00048 #  define big_endian_long(x)  x
00049 #  define big_endian_short(x) x
00050 #  define big_endian_float(x) x
00051 #else
00052 
00054 static inline uint64 big_endian_longlong (uint64 l)
00055 {
00056   uint64 r;
00057   swap_8 *p1 = (swap_8 *)&l;
00058   swap_8 *p2 = (swap_8 *)&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 big_endian_long (uint32 l)
00073 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); }
00074 
00076 static inline uint16 big_endian_short (uint16 s)
00077 { return uint16((s >> 8) | (s << 8)); }
00078 
00080 //@@WARNING: Should be removed -- use float2long instead
00081 static inline float big_endian_float (float f)
00082 {
00083   unsigned char tmp;
00084   swap_4 *pf = (swap_4 *)&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 little_endian_longlong(x) x
00094 #  define little_endian_long(x)  x
00095 #  define little_endian_short(x) x
00096 #  define little_endian_float(x) x
00097 #else
00098 
00100 static inline uint64 little_endian_longlong (uint64 l)
00101 {
00102   uint64 r;
00103   swap_8 *p1 = (swap_8 *)&l;
00104   swap_8 *p2 = (swap_8 *)&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 little_endian_long (uint32 l)
00118 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); }
00119 
00121 static inline uint16 little_endian_short (uint16 s)
00122 { return (s >> 8) | (s << 8); }
00123 
00125 static inline float little_endian_float (float f)
00126 {
00127   unsigned char tmp;
00128   swap_4 *pf = (swap_4 *)&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 
00153 static inline int32 float2long (float f)
00154 {
00155   int exp;
00156   int32 mant = QRound (frexp (f, &exp) * 0x1000000);
00157   int32 sign = mant & 0x80000000;
00158   if (mant < 0) mant = -mant;
00159   if (exp > 63) exp = 63; else if (exp < -64) exp = -64;
00160   return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff);
00161 }
00162 
00164 static inline float long2float (int32 l)
00165 {
00166   int exp = (l >> 24) & 0x7f;
00167   if (exp & 0x40) exp = exp | ~0x7f;
00168   float mant = float (l & 0x00ffffff) / 0x1000000;
00169   if (l & 0x80000000) mant = -mant;
00170   return (float) ldexp (mant, exp);
00171 }
00172 
00174 static inline int64 double2longlong (double d)
00175 {
00176   int exp;
00177   int64 mant = (int64) (frexp (d, &exp) * CONST_INT64(0x1000000000000));
00178   int64 sign = mant & CONST_INT64(0x800000000000000);
00179   if (mant < 0) mant = -mant;
00180   if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768;
00181   return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & CONST_INT64(0xffffffffffff));
00182 }
00183 
00185 static inline double longlong2double (int64 i)
00186 {
00187   int exp = (i >> 48) & 0x7fff;
00188   if (exp & 0x4000) exp = exp | ~0x7fff;
00189   double mant = double (i & CONST_INT64(0xffffffffffff)) / CONST_INT64(0x1000000000000);
00190   if (i & CONST_INT64(0x8000000000000000)) mant = -mant;
00191   return ldexp (mant, exp);
00192 }
00193 
00202 
00203 static inline short float2short (float f)
00204 {
00205   int exp;
00206   long mant = QRound (frexp (f, &exp) * 0x1000);
00207   long sign = mant & 0x8000;
00208   if (mant < 0) mant = -mant;
00209   if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8;
00210   return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff));
00211 }
00212 
00214 static inline float short2float (short s)
00215 {
00216   int exp = (s >> 11) & 0xf;
00217   if (exp & 0x8) exp = exp | ~0xf;
00218   float mant = float ((s & 0x07ff) | 0x0800) / 0x1000;
00219   if (s & 0x8000) mant = -mant;
00220   return (float) ldexp (mant, exp);
00221 }
00222 
00224 static inline uint64 convert_endian (uint64 l)
00225 { return little_endian_long (l); }
00226 
00228 static inline int64 convert_endian (int64 l)
00229 { return little_endian_long (l); }
00230 
00232 static inline uint32 convert_endian (uint32 l)
00233 { return little_endian_long (l); }
00234 
00236 static inline int32 convert_endian (int32 l)
00237 { return little_endian_long (l); }
00238 
00240 static inline int16 convert_endian (int16 s)
00241 { return little_endian_short (s); }
00242 
00244 static inline uint16 convert_endian (uint16 s)
00245 { return little_endian_short (s); }
00246 
00248 static inline float convert_endian (float f)
00249 { return little_endian_float (f); }
00250 
00252 inline uint16 get_le_short (void *buff)
00253 {
00254 #ifdef CS_STRICT_ALIGNMENT
00255   uint16 s; memcpy (&s, buff, sizeof (s));
00256   return little_endian_short (s);
00257 #else
00258   return little_endian_short (*(uint16 *)buff);
00259 #endif
00260 }
00261 
00263 inline uint32 get_le_long (void *buff)
00264 {
00265 #ifdef CS_STRICT_ALIGNMENT
00266   uint32 l; memcpy (&l, buff, sizeof (l));
00267   return little_endian_long (l);
00268 #else
00269   return little_endian_long (*(uint32 *)buff);
00270 #endif
00271 }
00272 
00274 inline float get_le_float32 (void *buff)
00275 { uint32 l = get_le_long (buff); return long2float (l); }
00276 
00278 inline float get_le_float16 (void *buff)
00279 { uint16 s = get_le_short (buff); return short2float (s); }
00280 
00282 inline void set_le_short (void *buff, uint16 s)
00283 {
00284 #ifdef CS_STRICT_ALIGNMENT
00285   s = little_endian_short (s);
00286   memcpy (buff, &s, sizeof (s));
00287 #else
00288   *((uint16 *)buff) = little_endian_short (s);
00289 #endif
00290 }
00291 
00293 inline void set_le_long (void *buff, uint32 l)
00294 {
00295 #ifdef CS_STRICT_ALIGNMENT
00296   l = little_endian_long (l);
00297   memcpy (buff, &l, sizeof (l));
00298 #else
00299   *((uint32 *)buff) = little_endian_long (l);
00300 #endif
00301 }
00302 
00304 inline void set_le_float32 (void *buff, float f)
00305 { set_le_long (buff, float2long (f)); }
00306 
00308 inline void set_le_float16 (void *buff, float f)
00309 { set_le_short (buff, float2short (f)); }
00310 
00315 #endif // __CS_CSENDIAN_H__

Generated for Crystal Space by doxygen 1.2.18