|
csendian.h00001 /* 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 |