libtins  3.4
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Pages
endianness.h
1 /*
2  * Copyright (c) 2016, Matias Fontanini
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #ifndef TINS_ENDIANNESS_H
31 #define TINS_ENDIANNESS_H
32 
33 #include <stdint.h>
34 #include "macros.h"
35 
36 #if defined(__APPLE__)
37  #include <sys/types.h>
38  #define TINS_IS_LITTLE_ENDIAN (BYTE_ORDER == LITTLE_ENDIAN)
39  #define TINS_IS_BIG_ENDIAN (BYTE_ORDER == BIG_ENDIAN)
40 #elif defined(BSD)
41  #include <sys/endian.h>
42  #define TINS_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
43  #define TINS_IS_BIG_ENDIAN (_BYTE_ORDER == _BIG_ENDIAN)
44 #elif defined(_WIN32)
45  #include <cstdlib>
46  // Assume windows == little endian. fixme later
47  #define TINS_IS_LITTLE_ENDIAN 1
48  #define TINS_IS_BIG_ENDIAN 0
49 #else
50  #include <endian.h>
51  #define TINS_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
52  #define TINS_IS_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
53 #endif
54 
55 // Define macros to swap bytes using compiler intrinsics when possible
56 #if defined(_MSC_VER)
57  #define TINS_BYTE_SWAP_16(data) _byteswap_ushort(data)
58  #define TINS_BYTE_SWAP_32(data) _byteswap_ulong(data)
59  #define TINS_BYTE_SWAP_64(data) _byteswap_uint64(data)
60 #elif defined(TINS_HAVE_GCC_BUILTIN_SWAP)
61  #define TINS_BYTE_SWAP_16(data) __builtin_bswap16(data)
62  #define TINS_BYTE_SWAP_32(data) __builtin_bswap32(data)
63  #define TINS_BYTE_SWAP_64(data) __builtin_bswap64(data)
64 #else
65  #define TINS_NO_BYTE_SWAP_INTRINSICS
66 #endif
67 
68 namespace Tins {
69 namespace Endian {
70 
77 inline uint8_t do_change_endian(uint8_t data) {
78  return data;
79 }
80 
86 inline uint16_t do_change_endian(uint16_t data) {
87  #ifdef TINS_NO_BYTE_SWAP_INTRINSICS
88  return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
89  #else
90  return TINS_BYTE_SWAP_16(data);
91  #endif
92 }
93 
99 inline uint32_t do_change_endian(uint32_t data) {
100  #ifdef TINS_NO_BYTE_SWAP_INTRINSICS
101  return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
102  ((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
103  #else
104  return TINS_BYTE_SWAP_32(data);
105  #endif
106 }
107 
113  inline uint64_t do_change_endian(uint64_t data) {
114  #ifdef TINS_NO_BYTE_SWAP_INTRINSICS
115  return (((uint64_t)(do_change_endian((uint32_t)(data & 0xffffffff))) << 32) |
116  (do_change_endian(((uint32_t)(data >> 32)))));
117  #else
118  return TINS_BYTE_SWAP_64(data);
119  #endif
120  }
121 
126 // Helpers to convert
127 template<typename T>
128 struct conversion_dispatch_helper {
129  static T dispatch(T data) {
130  return do_change_endian(data);
131  }
132 };
133 
134 
135 template<size_t>
136 struct conversion_dispatcher;
137 
138 template<>
139 struct conversion_dispatcher<sizeof(uint8_t)>
140 : public conversion_dispatch_helper<uint8_t> { };
141 
142 template<>
143 struct conversion_dispatcher<sizeof(uint16_t)>
144 : public conversion_dispatch_helper<uint16_t> { };
145 
146 template<>
147 struct conversion_dispatcher<sizeof(uint32_t)>
148 : public conversion_dispatch_helper<uint32_t> { };
149 
150 template<>
151 struct conversion_dispatcher<sizeof(uint64_t)>
152 : public conversion_dispatch_helper<uint64_t> { };
153 
165  template<typename T>
166  inline T change_endian(T data) {
167  return conversion_dispatcher<sizeof(T)>::dispatch(data);
168  }
169 
170 #if TINS_IS_LITTLE_ENDIAN
171 
176  template<typename T>
177  inline T host_to_be(T data) {
178  return change_endian(data);
179  }
180 
188  template<typename T>
189  inline T host_to_le(T data) {
190  return data;
191  }
192 
198  template<typename T>
199  inline T be_to_host(T data) {
200  return change_endian(data);
201  }
202 
208  template<typename T>
209  inline T le_to_host(T data) {
210  return data;
211  }
212 #elif TINS_IS_BIG_ENDIAN
213 
218  template<typename T>
219  inline T host_to_be(T data) {
220  return data;
221  }
222 
230  template<typename T>
231  inline T host_to_le(T data) {
232  return change_endian(data);
233  }
234 
240  template<typename T>
241  inline T be_to_host(T data) {
242  return data;
243  }
244 
250  template<typename T>
251  inline T le_to_host(T data) {
252  return change_endian(data);
253  }
254 #endif
255 
256 } // Endian
257 } // Tins
258 
259 #endif // TINS_ENDIANNESS_H