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