## 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
    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__