Google

Main Page   Class Hierarchy   Compound List   File List   Compound Members  

csendian.h

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 __CSENDIAN_H__
00020 #define __CSENDIAN_H__
00021 
00022 #include <math.h>
00023 #include "cstypes.h"
00024 #include "qint.h"
00025 
00026 /*
00027  * This is a bit of overkill but if you're sure your CPU doesn't require
00028  * strict alignment add your CPU to the !defined below to get slightly
00029  * smaller and faster code in some cases.
00030  */
00031 #if !defined (PROC_X86)
00032 #  define PROC_NEEDS_STRICT_ALIGNMENT
00033 #endif
00034 
00035 struct swap_4
00036 {
00037   unsigned char b1, b2, b3, b4;
00038 };
00039 
00040 #ifdef CS_BIG_ENDIAN
00041 #  define big_endian_long(x)  x
00042 #  define big_endian_short(x) x
00043 #  define big_endian_float(x) x
00044 #else
00045 
00047 static inline uint32 big_endian_long (uint32 l)
00048 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); }
00049 
00051 static inline uint16 big_endian_short (uint16 s)
00052 { return (s >> 8) | (s << 8); }
00053 
00055 //@@WARNING: Should be removed -- use float2long instead
00056 static inline float big_endian_float (float f)
00057 {
00058   unsigned char tmp;
00059   swap_4 *pf = (swap_4 *)&f;
00060   tmp = pf->b1; pf->b1 = pf->b4; pf->b4 = tmp;
00061   tmp = pf->b2; pf->b2 = pf->b3; pf->b3 = tmp;
00062   return f;
00063 }
00064 
00065 #endif // CS_BIG_ENDIAN
00066 
00067 #ifdef CS_LITTLE_ENDIAN
00068 #  define little_endian_long(x)  x
00069 #  define little_endian_short(x) x
00070 #  define little_endian_float(x) x
00071 #else
00072 
00074 static inline uint32 little_endian_long (uint32 l)
00075 { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); }
00076 
00078 static inline uint16 little_endian_short (uint16 s)
00079 { return (s >> 8) | (s << 8); }
00080 
00082 static inline float little_endian_float (float f)
00083 {
00084   unsigned char tmp;
00085   swap_4 *pf = (swap_4 *)&f;
00086   tmp = pf->b1; pf->b1 = pf->b4; pf->b4 = tmp;
00087   tmp = pf->b2; pf->b2 = pf->b3; pf->b3 = tmp;
00088   return f;
00089 }
00090 
00091 #endif // CS_LITTLE_ENDIAN
00092 
00093 /*
00094     To be able to painlessly transfer files betwen platforms, we should
00095     avoid using native floating-point format. Here are a couple of routines
00096     that are guaranteed to work on all platforms.
00097 
00098     The floating point is converted to a fixed 1.7.25 bits format
00099     (one bit sign, 7 bits exponent, 25 bits mantissa) and back,
00100     so that we can binary store floating-point number without
00101     cross-platform problems. If you wonder why 1+7+25 = 33 while we
00102     only have 32 bits, we'll ommit the most significant bit of mantissa
00103     since it is always 1 (we use normalized numbers). This increases the
00104     precision twice.
00105 */
00106 
00108 static inline long float2long (float f)
00109 {
00110   int exp;
00111   long mant = QRound (frexp (f, &exp) * 0x1000000);
00112   long sign = mant & 0x80000000;
00113   if (mant < 0) mant = -mant;
00114   if (exp > 63) exp = 63; else if (exp < -64) exp = -64;
00115   return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff);
00116 }
00117 
00119 static inline float long2float (long l)
00120 {
00121   int exp = (l >> 24) & 0x7f;
00122   if (exp & 0x40) exp = exp | ~0x7f;
00123   float mant = float (l & 0x00ffffff) / 0x1000000;
00124   if (l & 0x80000000) mant = -mant;
00125   return (float) ldexp (mant, exp);
00126 }
00127 
00136 
00137 static inline short float2short (float f)
00138 {
00139   int exp;
00140   long mant = QRound (frexp (f, &exp) * 0x1000);
00141   long sign = mant & 0x8000;
00142   if (mant < 0) mant = -mant;
00143   if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8;
00144   return sign | ((exp & 0xf) << 11) | (mant & 0x7ff);
00145 }
00146 
00148 static inline float short2float (short s)
00149 {
00150   int exp = (s >> 11) & 0xf;
00151   if (exp & 0x8) exp = exp | ~0xf;
00152   float mant = float ((s & 0x07ff) | 0x0800) / 0x1000;
00153   if (s & 0x8000) mant = -mant;
00154   return (float) ldexp (mant, exp);
00155 }
00156 
00158 static inline uint32 convert_endian (uint32 l)
00159 { return little_endian_long (l); }
00160 
00162 static inline int32 convert_endian (int32 l)
00163 { return little_endian_long (l); }
00164 
00166 static inline int16 convert_endian (int16 s)
00167 { return little_endian_short (s); }
00168 
00170 static inline uint16 convert_endian (uint16 s)
00171 { return little_endian_short (s); }
00172 
00174 static inline float convert_endian (float f)
00175 { return little_endian_float (f); }
00176 
00178 inline uint16 get_le_short (void *buff)
00179 {
00180 #ifdef PROC_NEEDS_STRICT_ALIGNMENT
00181   uint16 s; memcpy (&s, buff, sizeof (s));
00182   return little_endian_short (s);
00183 #else
00184   return little_endian_short (*(uint16 *)buff);
00185 #endif
00186 }
00187 
00189 inline uint32 get_le_long (void *buff)
00190 {
00191 #ifdef PROC_NEEDS_STRICT_ALIGNMENT
00192   uint32 l; memcpy (&l, buff, sizeof (l));
00193   return little_endian_long (l);
00194 #else
00195   return little_endian_long (*(uint32 *)buff);
00196 #endif
00197 }
00198 
00200 inline float get_le_float32 (void *buff)
00201 { uint32 l = get_le_long (buff); return long2float (l); }
00202 
00204 inline float get_le_float16 (void *buff)
00205 { uint16 s = get_le_short (buff); return short2float (s); }
00206 
00208 inline void set_le_short (void *buff, uint16 s)
00209 {
00210 #ifdef PROC_NEEDS_STRICT_ALIGNMENT
00211   s = little_endian_short (s);
00212   memcpy (buff, &s, sizeof (s));
00213 #else
00214   *((uint16 *)buff) = little_endian_short (s);
00215 #endif
00216 }
00217 
00219 inline void set_le_long (void *buff, uint32 l)
00220 {
00221 #ifdef PROC_NEEDS_STRICT_ALIGNMENT
00222   l = little_endian_long (l);
00223   memcpy (buff, &l, sizeof (l));
00224 #else
00225   *((uint32 *)buff) = little_endian_long (l);
00226 #endif
00227 }
00228 
00230 inline void set_le_float32 (void *buff, float f)
00231 { set_le_long (buff, float2long (f)); }
00232 
00234 inline void set_le_float16 (void *buff, float f)
00235 { set_le_short (buff, float2short (f)); }
00236 
00237 #endif // __CSENDIAN_H__

Generated for Crystal Space by doxygen 1.2.5 written by Dimitri van Heesch, ©1997-2000