CrystalSpace

Public API Reference

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 
00029 #include <math.h>
00030 #include "cstypes.h"
00031 
00032 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5)))
00033 
00037 struct csSwapBytes
00038 {
00039 private:
00040   struct Swap8
00041   {
00042     uint8 b1, b2, b3, b4, b5, b6, b7, b8;
00043   };
00044 public:
00046 
00047   static CS_FORCEINLINE uint16 Swap (uint16 s) 
00048   { return (s >> 8) | (s << 8); }
00049   static CS_FORCEINLINE int16  Swap (int16 s)
00050   { return (int16)Swap ((uint16)s); }
00051   static CS_FORCEINLINE uint32 Swap (uint32 l)
00052   { return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); }
00053   static CS_FORCEINLINE int32  Swap (int32 l)
00054   { return (int32)Swap ((uint32)l); }
00055   static CS_FORCEINLINE uint64 Swap (uint64 l)
00056   {
00057     uint64 r;
00058     Swap8 *p1 = (Swap8 *)&l;
00059     Swap8 *p2 = (Swap8 *)&r;
00060     p2->b1 = p1->b8;
00061     p2->b2 = p1->b7;
00062     p2->b3 = p1->b6;
00063     p2->b4 = p1->b5;
00064     p2->b5 = p1->b4;
00065     p2->b6 = p1->b3;
00066     p2->b7 = p1->b2;
00067     p2->b8 = p1->b1;
00068     return r;
00069   }
00070   static CS_FORCEINLINE int64  Swap (int64 l)
00071   { return (int64)Swap ((uint64)l); }
00072   
00073   static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Swap (x); }
00074   static CS_FORCEINLINE int16  Int16  (int16 x)  { return Swap (x); }
00075   static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Swap (x); }
00076   static CS_FORCEINLINE int32  Int32  (int32 x)  { return Swap (x); }
00077   static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Swap (x); }
00078   static CS_FORCEINLINE int64  Int64  (int64 x)  { return Swap (x); }
00080 };
00081 
00082 #ifdef CS_BIG_ENDIAN
00083 struct csBigEndian
00084 #else
00090 struct csLittleEndian
00091 #endif
00092 {
00094 
00095   static CS_FORCEINLINE uint16 Convert (uint16 x) { return x; }
00096   static CS_FORCEINLINE int16  Convert (int16 x)  { return x; }
00097   static CS_FORCEINLINE uint32 Convert (uint32 x) { return x; }
00098   static CS_FORCEINLINE int32  Convert (int32 x)  { return x; }
00099   static CS_FORCEINLINE uint64 Convert (uint64 x) { return x; }
00100   static CS_FORCEINLINE int64  Convert (int64 x)  { return x; }
00101   
00102   static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); }
00103   static CS_FORCEINLINE int16  Int16  (int16 x)  { return Convert (x); }
00104   static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); }
00105   static CS_FORCEINLINE int32  Int32  (int32 x)  { return Convert (x); }
00106   static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); }
00107   static CS_FORCEINLINE int64  Int64  (int64 x)  { return Convert (x); }
00109 };
00110 
00111 #ifdef CS_LITTLE_ENDIAN
00112 
00117 struct csBigEndian
00118 #else
00119 struct csLittleEndian
00120 #endif
00121 {
00122 public:
00124 
00125   static CS_FORCEINLINE uint16 Convert (uint16 s) 
00126   { return csSwapBytes::Swap (s); }
00127   static CS_FORCEINLINE int16  Convert (int16 s)
00128   { return csSwapBytes::Swap (s); }
00129   static CS_FORCEINLINE uint32 Convert (uint32 l)
00130   { return csSwapBytes::Swap (l); }
00131   static CS_FORCEINLINE int32  Convert (int32 l)
00132   { return csSwapBytes::Swap (l); }
00133   static CS_FORCEINLINE uint64 Convert (uint64 l)
00134   { return csSwapBytes::Swap (l); }
00135   static CS_FORCEINLINE int64  Convert (int64 l)
00136   { return csSwapBytes::Swap (l); }
00137   
00138   static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); }
00139   static CS_FORCEINLINE int16  Int16  (int16 x)  { return Convert (x); }
00140   static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); }
00141   static CS_FORCEINLINE int32  Int32  (int32 x)  { return Convert (x); }
00142   static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); }
00143   static CS_FORCEINLINE int64  Int64  (int64 x)  { return Convert (x); }
00145 };
00146 
00150 struct csIEEEfloat
00151 {
00152 #ifdef CS_IEEE_DOUBLE_FORMAT
00153 
00154   static CS_FORCEINLINE uint32 FromNative (float f)
00155   { return *(uint32*)&f; }
00157   static CS_FORCEINLINE float ToNative (uint32 f)
00158   { return *(float*)&f; }
00159 #else
00160   #error Do not know how to convert to IEEE floats
00161 #endif
00162 };
00163 
00172 struct csGetFromAddress
00173 {
00175 
00176   static CS_FORCEINLINE uint16 UInt16 (const void *buff)
00177   {
00178   #ifdef CS_STRICT_ALIGNMENT
00179     uint16 s; memcpy (&s, buff, sizeof (s));
00180     return s;
00181   #else
00182     return *(uint16 *)buff;
00183   #endif
00184   }
00185   static CS_FORCEINLINE int16  Int16 (const void *buff)
00186   { return (int16)UInt16 (buff); }
00187   static CS_FORCEINLINE uint32 UInt32 (const void *buff)
00188   {
00189   #ifdef CS_STRICT_ALIGNMENT
00190     uint32 s; memcpy (&s, buff, sizeof (s));
00191     return s;
00192   #else
00193     return *(uint32 *)buff;
00194   #endif
00195   }
00196   static CS_FORCEINLINE int32  Int32 (const void *buff)
00197   { return (int32)UInt32 (buff); }
00198   static CS_FORCEINLINE uint64 UInt64 (const void *buff)
00199   {
00200   #ifdef CS_STRICT_ALIGNMENT
00201     uint64 s; memcpy (&s, buff, sizeof (s));
00202     return s;
00203   #else
00204     return *(uint64 *)buff;
00205   #endif
00206   }
00207   static CS_FORCEINLINE int64  Int64 (const void *buff)
00208   { return (int64)UInt64 (buff); }
00210 };
00211 
00220 struct csSetToAddress
00221 {
00223 
00224   static CS_FORCEINLINE void UInt16 (void *buff, uint16 s)
00225   {
00226   #ifdef CS_STRICT_ALIGNMENT
00227     memcpy (buff, &s, sizeof (s));
00228   #else
00229     *((uint16 *)buff) = s;
00230   #endif
00231   }
00232   static CS_FORCEINLINE void Int16  (void *buff, int16 s)
00233   { UInt16 (buff, (uint16)s); }
00234   static CS_FORCEINLINE void UInt32 (void *buff, uint32 s)
00235   {
00236   #ifdef CS_STRICT_ALIGNMENT
00237     memcpy (buff, &s, sizeof (s));
00238   #else
00239     *((uint32 *)buff) = s;
00240   #endif
00241   }
00242   static CS_FORCEINLINE void Int32  (void *buff, int32 s)
00243   { UInt32 (buff, (uint32)s); }
00244   static CS_FORCEINLINE void UInt64 (void *buff, uint64 s)
00245   {
00246   #ifdef CS_STRICT_ALIGNMENT
00247     memcpy (buff, &s, sizeof (s));
00248   #else
00249     *((uint64 *)buff) = s;
00250   #endif
00251   }
00252   static CS_FORCEINLINE void Int64  (void *buff, int64 s)
00253   { UInt64 (buff, (uint64)s); }
00255 };
00256 
00262 
00263 static inline uint64 csBigEndianLongLong (uint64 l)
00264 { return csBigEndian::Convert (l); }
00265 
00267 static inline uint32 csBigEndianLong (uint32 l)
00268 { return csBigEndian::Convert (l); }
00269 
00271 static inline uint16 csBigEndianShort (uint16 s)
00272 { return csBigEndian::Convert (s); }
00273 
00275 static inline float csBigEndianFloat (float f)
00276 { 
00277   uint32 u = csBigEndian::Convert (*(uint32*)&f); 
00278   return *(float*)&u;
00279 }
00280 
00282 static inline uint64 csLittleEndianLongLong (uint64 l)
00283 { return csLittleEndian::Convert (l); }
00284 
00286 static inline uint32 csLittleEndianLong (uint32 l)
00287 { return csLittleEndian::Convert (l); }
00288 
00290 static inline uint16 csLittleEndianShort (uint16 s)
00291 { return csLittleEndian::Convert (s); }
00292 
00294 static inline float csLittleEndianFloat (float f)
00295 {
00296   uint32 u = csLittleEndian::Convert (*(uint32*)&f); 
00297   return *(float*)&u;
00298 }
00299 
00300 /*
00301     To be able to painlessly transfer files betwen platforms, we should
00302     avoid using native floating-point format. Here are a couple of routines
00303     that are guaranteed to work on all platforms.
00304 
00305     The floating point is converted to a fixed 1.7.25 bits format
00306     (one bit sign, 7 bits exponent, 25 bits mantissa) and back,
00307     so that we can binary store floating-point number without
00308     cross-platform problems. If you wonder why 1+7+25 = 33 while we
00309     only have 32 bits, we'll ommit the most significant bit of mantissa
00310     since it is always 1 (we use normalized numbers). This increases the
00311     precision twice.
00312 
00313     For double, we use one bit sign, 15 bits exponent, 49 bits mantissa.
00314 */
00315 
00320 static inline int32 csFloatToLong (float f)
00321 {
00322   int exp;
00323   int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000);
00324   int32 sign = mant & 0x80000000;
00325   if (mant < 0) mant = -mant;
00326   if (exp > 63) exp = 63; else if (exp < -64) exp = -64;
00327   return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff);
00328 }
00329 
00334 static inline float csLongToFloat (int32 l)
00335 {
00336   int exp = (l >> 24) & 0x7f;
00337   if (exp & 0x40) exp = exp | ~0x7f;
00338   float mant = float (l & 0x00ffffff) / 0x1000000;
00339   if (l & 0x80000000) mant = -mant;
00340   return (float) ldexp (mant, exp);
00341 }
00342 
00343 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble()
00344  *
00345  * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++
00346  * under -ansi -pedantic, and we want this header to be useful to external
00347  * projects which use -ansi -pedantic.  Instead, we use bit shifts, such as (1
00348  * << 59), and construct `mask' manually.
00349  */
00350 
00355 static inline int64 csDoubleToLongLong (double d)
00356 {
00357   int exp;
00358   int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48));
00359   int64 sign = mant & ((int64)1 << 59);
00360   if (mant < 0) mant = -mant;
00361   if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768;
00362   int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff;
00363   return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask);
00364 }
00365 
00370 static inline double csLongLongToDouble (int64 i)
00371 {
00372   int exp = (i >> 48) & 0x7fff;
00373   if (exp & 0x4000) exp = exp | ~0x7fff;
00374   int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff;
00375   double mant = double (i & mask) / ((int64)1 << 48);
00376   if (i & ((int64)1 << 59)) mant = -mant;
00377   return ldexp (mant, exp);
00378 }
00379 
00380 /* *\name Floating point conversions
00381  * These routines are used for converting floating-point numbers
00382  * into 16-bit shorts and back. This is useful for low-precision data.
00383  * They use the 1.4.12 format. The range of numbers that can be represented
00384  * in this format is from 2^-8 to 2^7. The precision for numbers near to
00385  * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03.
00386  * @{ */
00387 
00392 static inline short csFloatToShort (float f)
00393 {
00394   int exp;
00395   long mant = csQroundSure (frexp (f, &exp) * 0x1000);
00396   long sign = mant & 0x8000;
00397   if (mant < 0) mant = -mant;
00398   if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8;
00399   return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff));
00400 }
00401 
00406 static inline float csShortToFloat (short s)
00407 {
00408   int exp = (s >> 11) & 0xf;
00409   if (exp & 0x8) exp = exp | ~0xf;
00410   float mant = float ((s & 0x07ff) | 0x0800) / 0x1000;
00411   if (s & 0x8000) mant = -mant;
00412   return (float) ldexp (mant, exp);
00413 }
00414 
00417 
00418 static inline uint64 csConvertEndian (uint64 l)
00419 { return csLittleEndianLongLong (l); }
00420 
00422 static inline int64 csConvertEndian (int64 l)
00423 { return csLittleEndianLongLong (l); }
00424 
00426 static inline uint32 csConvertEndian (uint32 l)
00427 { return csLittleEndianLong (l); }
00428 
00430 static inline int32 csConvertEndian (int32 l)
00431 { return csLittleEndianLong (l); }
00432 
00434 static inline int16 csConvertEndian (int16 s)
00435 { return csLittleEndianShort (s); }
00436 
00438 static inline uint16 csConvertEndian (uint16 s)
00439 { return csLittleEndianShort (s); }
00440 
00442 static inline float csConvertEndian (float f)
00443 { return csLittleEndianFloat (f); }
00444 
00446 inline uint16 csGetLittleEndianShort (const void *buff)
00447 {
00448   return csLittleEndian::Convert (csGetFromAddress::UInt16 (buff));
00449 }
00450 
00452 inline uint32 csGetLittleEndianLong (const void *buff)
00453 {
00454   return csLittleEndian::Convert (csGetFromAddress::UInt32 (buff));
00455 }
00456 
00458 inline float csGetLittleEndianFloat32 (const void *buff)
00459 { uint32 l = csGetLittleEndianLong (buff); return csLongToFloat (l); }
00460 
00462 inline float csGetLittleEndianFloat16 (const void *buff)
00463 { uint16 s = csGetLittleEndianShort (buff); return csShortToFloat (s); }
00464 
00469 #endif // __CS_CSENDIAN_H__

Generated for Crystal Space by doxygen 1.4.6