Crystal Space: csutil/csendian.h Source File (Crystal Space Public API Reference)

| ## Public API Reference

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# 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 #if defined(CS_HAVE_BYTESWAP_H)
    00032 #include <byteswap.h>
    00033 #endif
    00034
    00035 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5)))
    00036
    00040 struct csSwapBytes
    00041 {
    00042 public:
    00044
    00045   static CS_FORCEINLINE uint16 Swap (uint16 s)
    00046   {
    00047   #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300)
    00048     return _byteswap_ushort (s);
    00049   #elif defined(CS_HAVE_BYTESWAP_H)
    00050     return bswap_16 (s);
    00051   #else
    00052     return (s >> 8) | (s << 8);
    00053   #endif
    00054   }
    00055   static CS_FORCEINLINE int16  Swap (int16 s)
    00056   { return (int16)Swap ((uint16)s); }
    00057   static CS_FORCEINLINE uint32 Swap (uint32 l)
    00058   {
    00059   #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300)
    00060     return _byteswap_ulong (l);
    00061   #elif defined(CS_HAVE_BYTESWAP_H)
    00062     return bswap_32 (l);
    00063   #else
    00064     return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24);
    00065   #endif
    00066   }
    00067   static CS_FORCEINLINE int32  Swap (int32 l)
    00068   { return (int32)Swap ((uint32)l); }
    00069   static CS_FORCEINLINE uint64 Swap (uint64 l)
    00070   {
    00071   #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300)
    00072     return _byteswap_uint64 (l);
    00073   #elif defined(CS_HAVE_BYTESWAP_H) && !defined(__STRICT_ANSI__)
    00074     return bswap_64 (l);
    00075   #else
    00076     union
    00077     {
    00078       uint64 ui64;
    00079       uint32 ui32[2];
    00080     } u1, u2;
    00081     u1.ui64 = l;
    00082     u2.ui32[0] = Swap (u1.ui32[1]);
    00083     u2.ui32[1] = Swap (u1.ui32[0]);
    00084     return u2.ui64;
    00085   #endif
    00086   }
    00087   static CS_FORCEINLINE int64  Swap (int64 l)
    00088   { return (int64)Swap ((uint64)l); }
    00089
    00090   static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Swap (x); }
    00091   static CS_FORCEINLINE int16  Int16  (int16 x)  { return Swap (x); }
    00092   static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Swap (x); }
    00093   static CS_FORCEINLINE int32  Int32  (int32 x)  { return Swap (x); }
    00094   static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Swap (x); }
    00095   static CS_FORCEINLINE int64  Int64  (int64 x)  { return Swap (x); }
    00097 };
    00098
    00099 #ifdef CS_BIG_ENDIAN
    00100 struct csBigEndian
    00101 #else
    00107 struct csLittleEndian
    00108 #endif
    00109 {
    00111
    00112   static CS_FORCEINLINE uint16 Convert (uint16 x) { return x; }
    00113   static CS_FORCEINLINE int16  Convert (int16 x)  { return x; }
    00114   static CS_FORCEINLINE uint32 Convert (uint32 x) { return x; }
    00115   static CS_FORCEINLINE int32  Convert (int32 x)  { return x; }
    00116   static CS_FORCEINLINE uint64 Convert (uint64 x) { return x; }
    00117   static CS_FORCEINLINE int64  Convert (int64 x)  { return x; }
    00118
    00119   static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); }
    00120   static CS_FORCEINLINE int16  Int16  (int16 x)  { return Convert (x); }
    00121   static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); }
    00122   static CS_FORCEINLINE int32  Int32  (int32 x)  { return Convert (x); }
    00123   static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); }
    00124   static CS_FORCEINLINE int64  Int64  (int64 x)  { return Convert (x); }
    00126 };
    00127
    00128 #ifdef CS_LITTLE_ENDIAN
    00129
    00134 struct csBigEndian
    00135 #else
    00136 struct csLittleEndian
    00137 #endif
    00138 {
    00139 public:
    00141
    00142   static CS_FORCEINLINE uint16 Convert (uint16 s)
    00143   { return csSwapBytes::Swap (s); }
    00144   static CS_FORCEINLINE int16  Convert (int16 s)
    00145   { return csSwapBytes::Swap (s); }
    00146   static CS_FORCEINLINE uint32 Convert (uint32 l)
    00147   { return csSwapBytes::Swap (l); }
    00148   static CS_FORCEINLINE int32  Convert (int32 l)
    00149   { return csSwapBytes::Swap (l); }
    00150   static CS_FORCEINLINE uint64 Convert (uint64 l)
    00151   { return csSwapBytes::Swap (l); }
    00152   static CS_FORCEINLINE int64  Convert (int64 l)
    00153   { return csSwapBytes::Swap (l); }
    00154
    00155   static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); }
    00156   static CS_FORCEINLINE int16  Int16  (int16 x)  { return Convert (x); }
    00157   static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); }
    00158   static CS_FORCEINLINE int32  Int32  (int32 x)  { return Convert (x); }
    00159   static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); }
    00160   static CS_FORCEINLINE int64  Int64  (int64 x)  { return Convert (x); }
    00162 };
    00163
    00167 struct csIEEEfloat
    00168 {
    00169   /* \todo It would be even better if we also check for sizeof (float)
    00170    * in configure or so. */
    00171 #ifdef CS_IEEE_DOUBLE_FORMAT
    00173   static CS_FORCEINLINE uint32 FromNative (float f)
    00174   {
    00175     union
    00176     {
    00177       float f;
    00178       uint32 ui32;
    00179     } u;
    00180     u.f = f;
    00181     return u.ui32;
    00182   }
    00184   static CS_FORCEINLINE float ToNative (uint32 f)
    00185   {
    00186     union
    00187     {
    00188       float f;
    00189       uint32 ui32;
    00190     } u;
    00191     u.ui32 = f;
    00192     return u.f;
    00193   }
    00194 #else
    00195   #error Do not know how to convert to IEEE floats
    00196 #endif
    00197 };
    00198
    00207 struct csGetFromAddress
    00208 {
    00210
    00211   static CS_FORCEINLINE uint16 UInt16 (const void *buff)
    00212   {
    00213   #ifdef CS_STRICT_ALIGNMENT
    00214     uint16 s; memcpy (&s, buff, sizeof (s));
    00215     return s;
    00216   #else
    00217     return *(uint16 *)buff;
    00218   #endif
    00219   }
    00220   static CS_FORCEINLINE int16  Int16 (const void *buff)
    00221   { return (int16)UInt16 (buff); }
    00222   static CS_FORCEINLINE uint32 UInt32 (const void *buff)
    00223   {
    00224   #ifdef CS_STRICT_ALIGNMENT
    00225     uint32 s; memcpy (&s, buff, sizeof (s));
    00226     return s;
    00227   #else
    00228     return *(uint32 *)buff;
    00229   #endif
    00230   }
    00231   static CS_FORCEINLINE int32  Int32 (const void *buff)
    00232   { return (int32)UInt32 (buff); }
    00233   static CS_FORCEINLINE uint64 UInt64 (const void *buff)
    00234   {
    00235   #ifdef CS_STRICT_ALIGNMENT
    00236     uint64 s; memcpy (&s, buff, sizeof (s));
    00237     return s;
    00238   #else
    00239     return *(uint64 *)buff;
    00240   #endif
    00241   }
    00242   static CS_FORCEINLINE int64  Int64 (const void *buff)
    00243   { return (int64)UInt64 (buff); }
    00245 };
    00246
    00255 struct csSetToAddress
    00256 {
    00258
    00259   static CS_FORCEINLINE void UInt16 (void *buff, uint16 s)
    00260   {
    00261   #ifdef CS_STRICT_ALIGNMENT
    00262     memcpy (buff, &s, sizeof (s));
    00263   #else
    00264     *((uint16 *)buff) = s;
    00265   #endif
    00266   }
    00267   static CS_FORCEINLINE void Int16  (void *buff, int16 s)
    00268   { UInt16 (buff, (uint16)s); }
    00269   static CS_FORCEINLINE void UInt32 (void *buff, uint32 s)
    00270   {
    00271   #ifdef CS_STRICT_ALIGNMENT
    00272     memcpy (buff, &s, sizeof (s));
    00273   #else
    00274     *((uint32 *)buff) = s;
    00275   #endif
    00276   }
    00277   static CS_FORCEINLINE void Int32  (void *buff, int32 s)
    00278   { UInt32 (buff, (uint32)s); }
    00279   static CS_FORCEINLINE void UInt64 (void *buff, uint64 s)
    00280   {
    00281   #ifdef CS_STRICT_ALIGNMENT
    00282     memcpy (buff, &s, sizeof (s));
    00283   #else
    00284     *((uint64 *)buff) = s;
    00285   #endif
    00286   }
    00287   static CS_FORCEINLINE void Int64  (void *buff, int64 s)
    00288   { UInt64 (buff, (uint64)s); }
    00290 };
    00291
    00297
    00298 CS_DEPRECATED_METHOD static inline uint64 csBigEndianLongLong (uint64 l)
    00299 { return csBigEndian::Convert (l); }
    00300
    00302 CS_DEPRECATED_METHOD static inline uint32 csBigEndianLong (uint32 l)
    00303 { return csBigEndian::Convert (l); }
    00304
    00306 CS_DEPRECATED_METHOD static inline uint16 csBigEndianShort (uint16 s)
    00307 { return csBigEndian::Convert (s); }
    00308
    00310 CS_DEPRECATED_METHOD static inline float csBigEndianFloat (float f)
    00311 {
    00312   union
    00313   {
    00314     float f;
    00315     uint32 ui32;
    00316   } u;
    00317   u.f = f;
    00318   u.ui32 = csBigEndian::Convert (u.ui32);
    00319   return u.f;
    00320 }
    00321
    00323 CS_DEPRECATED_METHOD static inline uint64 csLittleEndianLongLong (uint64 l)
    00324 { return csLittleEndian::Convert (l); }
    00325
    00327 CS_DEPRECATED_METHOD static inline uint32 csLittleEndianLong (uint32 l)
    00328 { return csLittleEndian::Convert (l); }
    00329
    00331 CS_DEPRECATED_METHOD static inline uint16 csLittleEndianShort (uint16 s)
    00332 { return csLittleEndian::Convert (s); }
    00333
    00335 CS_DEPRECATED_METHOD static inline float csLittleEndianFloat (float f)
    00336 {
    00337   union
    00338   {
    00339     float f;
    00340     uint32 ui32;
    00341   } u;
    00342   u.f = f;
    00343   u.ui32 = csLittleEndian::Convert (u.ui32);
    00344   return u.f;
    00345 }
    00346
    00347 /*
    00348     To be able to painlessly transfer files betwen platforms, we should
    00349     avoid using native floating-point format. Here are a couple of routines
    00350     that are guaranteed to work on all platforms.
    00351
    00352     The floating point is converted to a fixed 1.7.25 bits format
    00353     (one bit sign, 7 bits exponent, 25 bits mantissa) and back,
    00354     so that we can binary store floating-point number without
    00355     cross-platform problems. If you wonder why 1+7+25 = 33 while we
    00356     only have 32 bits, we'll ommit the most significant bit of mantissa
    00357     since it is always 1 (we use normalized numbers). This increases the
    00358     precision twice.
    00359
    00360     For double, we use one bit sign, 15 bits exponent, 49 bits mantissa.
    00361 */
    00362
    00367 /*CS_DEPRECATED_METHOD*/ static inline int32 csFloatToLong (float f)
    00368 {
    00369   int exp;
    00370   int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000);
    00371   int32 sign = mant & 0x80000000;
    00372   if (mant < 0) mant = -mant;
    00373   if (exp > 63) exp = 63; else if (exp < -64) exp = -64;
    00374   return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff);
    00375 }
    00376
    00381 /*CS_DEPRECATED_METHOD*/ static inline float csLongToFloat (int32 l)
    00382 {
    00383   int exp = (l >> 24) & 0x7f;
    00384   if (exp & 0x40) exp = exp | ~0x7f;
    00385   float mant = float (l & 0x00ffffff) / 0x1000000;
    00386   if (l & 0x80000000) mant = -mant;
    00387   return (float) ldexp (mant, exp);
    00388 }
    00389
    00390 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble()
    00391  *
    00392  * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++
    00393  * under -ansi -pedantic, and we want this header to be useful to external
    00394  * projects which use -ansi -pedantic.  Instead, we use bit shifts, such as (1
    00395  * << 59), and construct `mask' manually.
    00396  */
    00397
    00402 /*CS_DEPRECATED_METHOD*/ static inline int64 csDoubleToLongLong (double d)
    00403 {
    00404   int exp;
    00405   int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48));
    00406   int64 sign = mant & ((int64)1 << 59);
    00407   if (mant < 0) mant = -mant;
    00408   if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768;
    00409   int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff;
    00410   return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask);
    00411 }
    00412
    00417 /*CS_DEPRECATED_METHOD*/ static inline double csLongLongToDouble (int64 i)
    00418 {
    00419   int exp = (i >> 48) & 0x7fff;
    00420   if (exp & 0x4000) exp = exp | ~0x7fff;
    00421   int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff;
    00422   double mant = double (i & mask) / ((int64)1 << 48);
    00423   if (i & ((int64)1 << 59)) mant = -mant;
    00424   return ldexp (mant, exp);
    00425 }
    00426
    00427 /* *\name Floating point conversions
    00428  * These routines are used for converting floating-point numbers
    00429  * into 16-bit shorts and back. This is useful for low-precision data.
    00430  * They use the 1.4.12 format. The range of numbers that can be represented
    00431  * in this format is from 2^-8 to 2^7. The precision for numbers near to
    00432  * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03.
    00433  * @{ */
    00434
    00439 /*CS_DEPRECATED_METHOD*/ static inline short csFloatToShort (float f)
    00440 {
    00441   int exp;
    00442   long mant = csQroundSure (frexp (f, &exp) * 0x1000);
    00443   long sign = mant & 0x8000;
    00444   if (mant < 0) mant = -mant;
    00445   if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8;
    00446   return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff));
    00447 }
    00448
    00453 /*CS_DEPRECATED_METHOD*/ static inline float csShortToFloat (short s)
    00454 {
    00455   int exp = (s >> 11) & 0xf;
    00456   if (exp & 0x8) exp = exp | ~0xf;
    00457   float mant = float ((s & 0x07ff) | 0x0800) / 0x1000;
    00458   if (s & 0x8000) mant = -mant;
    00459   return (float) ldexp (mant, exp);
    00460 }
    00461
    00464
    00465 CS_DEPRECATED_METHOD static inline uint64 csConvertEndian (uint64 l)
    00466 { return csLittleEndian::Convert (l); }
    00467
    00469 CS_DEPRECATED_METHOD static inline int64 csConvertEndian (int64 l)
    00470 { return csLittleEndian::Convert (l); }
    00471
    00473 CS_DEPRECATED_METHOD static inline uint32 csConvertEndian (uint32 l)
    00474 { return csLittleEndian::Convert (l); }
    00475
    00477 CS_DEPRECATED_METHOD static inline int32 csConvertEndian (int32 l)
    00478 { return csLittleEndian::Convert (l); }
    00479
    00481 CS_DEPRECATED_METHOD static inline int16 csConvertEndian (int16 s)
    00482 { return csLittleEndian::Convert (s); }
    00483
    00485 CS_DEPRECATED_METHOD static inline uint16 csConvertEndian (uint16 s)
    00486 { return csLittleEndian::Convert (s); }
    00487
    00489 CS_DEPRECATED_METHOD static inline float csConvertEndian (float f)
    00490 {
    00491   union
    00492   {
    00493     float f;
    00494     uint32 ui32;
    00495   } u;
    00496   u.f = f;
    00497   u.ui32 = csLittleEndian::Convert (u.ui32);
    00498   return u.f;
    00499 }
    00500
    00502 CS_DEPRECATED_METHOD inline uint16 csGetLittleEndianShort (const void *buff)
    00503 {
    00504   return csLittleEndian::Convert (csGetFromAddress::UInt16 (buff));
    00505 }
    00506
    00508 CS_DEPRECATED_METHOD inline uint32 csGetLittleEndianLong (const void *buff)
    00509 {
    00510   return csLittleEndian::Convert (csGetFromAddress::UInt32 (buff));
    00511 }
    00512
    00514 CS_DEPRECATED_METHOD inline float csGetLittleEndianFloat32 (const void *buff)
    00515 {
    00516   uint32 l = csLittleEndian::Convert (csGetFromAddress::UInt32 (buff));
    00517   return csLongToFloat (l);
    00518 }
    00519
    00521 CS_DEPRECATED_METHOD inline float csGetLittleEndianFloat16 (const void *buff)
    00522 {
    00523   uint16 s = csLittleEndian::Convert (csGetFromAddress::UInt16 (buff));
    00524   return csShortToFloat (s);
    00525 }
    00526
    00531 #endif // __CS_CSENDIAN_H__