Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/EndianUtils.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/* Functions for reading and writing integers in various endiannesses. */
8
9
/*
10
 * The classes LittleEndian and BigEndian expose static methods for
11
 * reading and writing 16-, 32-, and 64-bit signed and unsigned integers
12
 * in their respective endianness.  The addresses read from or written
13
 * to may be misaligned (although misaligned accesses may incur
14
 * architecture-specific performance costs).  The naming scheme is:
15
 *
16
 * {Little,Big}Endian::{read,write}{Uint,Int}<bitsize>
17
 *
18
 * For instance, LittleEndian::readInt32 will read a 32-bit signed
19
 * integer from memory in little endian format.  Similarly,
20
 * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory
21
 * in big-endian format.
22
 *
23
 * The class NativeEndian exposes methods for conversion of existing
24
 * data to and from the native endianness.  These methods are intended
25
 * for cases where data needs to be transferred, serialized, etc.
26
 * swap{To,From}{Little,Big}Endian byteswap a single value if necessary.
27
 * Bulk conversion functions are also provided which optimize the
28
 * no-conversion-needed case:
29
 *
30
 * - copyAndSwap{To,From}{Little,Big}Endian;
31
 * - swap{To,From}{Little,Big}EndianInPlace.
32
 *
33
 * The *From* variants are intended to be used for reading data and the
34
 * *To* variants for writing data.
35
 *
36
 * Methods on NativeEndian work with integer data of any type.
37
 * Floating-point data is not supported.
38
 *
39
 * For clarity in networking code, "Network" may be used as a synonym
40
 * for "Big" in any of the above methods or class names.
41
 *
42
 * As an example, reading a file format header whose fields are stored
43
 * in big-endian format might look like:
44
 *
45
 * class ExampleHeader
46
 * {
47
 * private:
48
 *   uint32_t mMagic;
49
 *   uint32_t mLength;
50
 *   uint32_t mTotalRecords;
51
 *   uint64_t mChecksum;
52
 *
53
 * public:
54
 *   ExampleHeader(const void* data)
55
 *   {
56
 *     const uint8_t* ptr = static_cast<const uint8_t*>(data);
57
 *     mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
58
 *     mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
59
 *     mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
60
 *     mChecksum = BigEndian::readUint64(ptr);
61
 *   }
62
 *   ...
63
 * };
64
 */
65
66
#ifndef mozilla_EndianUtils_h
67
#define mozilla_EndianUtils_h
68
69
#include "mozilla/Assertions.h"
70
#include "mozilla/Attributes.h"
71
#include "mozilla/Compiler.h"
72
#include "mozilla/DebugOnly.h"
73
#include "mozilla/TypeTraits.h"
74
75
#include <stdint.h>
76
#include <string.h>
77
78
#if defined(_MSC_VER)
79
#  include <stdlib.h>
80
#  pragma intrinsic(_byteswap_ushort)
81
#  pragma intrinsic(_byteswap_ulong)
82
#  pragma intrinsic(_byteswap_uint64)
83
#endif
84
85
#if defined(_WIN64)
86
#  if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
87
#    define MOZ_LITTLE_ENDIAN 1
88
#  elif defined(_M_ARM64)
89
#    define MOZ_LITTLE_ENDIAN 1
90
#  else
91
#    error "CPU type is unknown"
92
#  endif
93
#elif defined(_WIN32)
94
#  if defined(_M_IX86)
95
#    define MOZ_LITTLE_ENDIAN 1
96
#  elif defined(_M_ARM)
97
#    define MOZ_LITTLE_ENDIAN 1
98
#  else
99
#    error "CPU type is unknown"
100
#  endif
101
#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__)
102
#  if __LITTLE_ENDIAN__
103
#    define MOZ_LITTLE_ENDIAN 1
104
#  elif __BIG_ENDIAN__
105
#    define MOZ_BIG_ENDIAN 1
106
#  endif
107
#elif defined(__GNUC__) && \
108
      defined(__BYTE_ORDER__) && \
109
      defined(__ORDER_LITTLE_ENDIAN__) && \
110
      defined(__ORDER_BIG_ENDIAN__)
111
   /*
112
    * Some versions of GCC provide architecture-independent macros for
113
    * this.  Yes, there are more than two values for __BYTE_ORDER__.
114
    */
115
#  if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
116
#    define MOZ_LITTLE_ENDIAN 1
117
#  elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
118
#    define MOZ_BIG_ENDIAN 1
119
#  else
120
#    error "Can't handle mixed-endian architectures"
121
#  endif
122
/*
123
 * We can't include useful headers like <endian.h> or <sys/isa_defs.h>
124
 * here because they're not present on all platforms.  Instead we have
125
 * this big conditional that ideally will catch all the interesting
126
 * cases.
127
 */
128
#elif defined(__sparc) || defined(__sparc__) || \
129
      defined(_POWER) || defined(__hppa) || \
130
      defined(_MIPSEB) || defined(__ARMEB__) || \
131
      defined(__s390__) || defined(__AARCH64EB__) || \
132
      (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \
133
      (defined(__ia64) && defined(__BIG_ENDIAN__))
134
#  define MOZ_BIG_ENDIAN 1
135
#elif defined(__i386) || defined(__i386__) || \
136
      defined(__x86_64) || defined(__x86_64__) || \
137
      defined(_MIPSEL) || defined(__ARMEL__) || \
138
      defined(__alpha__) || defined(__AARCH64EL__) || \
139
      (defined(__sh__) && defined(__BIG_ENDIAN__)) || \
140
      (defined(__ia64) && !defined(__BIG_ENDIAN__))
141
#  define MOZ_LITTLE_ENDIAN 1
142
#endif
143
144
#if MOZ_BIG_ENDIAN
145
#  define MOZ_LITTLE_ENDIAN 0
146
#elif MOZ_LITTLE_ENDIAN
147
0
#  define MOZ_BIG_ENDIAN 0
148
#else
149
#  error "Cannot determine endianness"
150
#endif
151
152
#if defined(__clang__)
153
#  if __has_builtin(__builtin_bswap16)
154
39
#    define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
155
#  endif
156
#elif defined(__GNUC__)
157
#  define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
158
#elif defined(_MSC_VER)
159
#  define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort
160
#endif
161
162
namespace mozilla {
163
164
namespace detail {
165
166
/*
167
 * We need wrappers here because free functions with default template
168
 * arguments and/or partial specialization of function templates are not
169
 * supported by all the compilers we use.
170
 */
171
template<typename T, size_t Size = sizeof(T)>
172
struct Swapper;
173
174
template<typename T>
175
struct Swapper<T, 2>
176
{
177
  static T swap(T aValue)
178
39
  {
179
39
#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16)
180
39
    return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue);
181
#else
182
    return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8));
183
#endif
184
  }
Unexecuted instantiation: mozilla::detail::Swapper<char16_t, 2ul>::swap(char16_t)
mozilla::detail::Swapper<unsigned short, 2ul>::swap(unsigned short)
Line
Count
Source
178
39
  {
179
39
#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16)
180
39
    return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue);
181
#else
182
    return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8));
183
#endif
184
  }
Unexecuted instantiation: mozilla::detail::Swapper<short, 2ul>::swap(short)
185
};
186
187
template<typename T>
188
struct Swapper<T, 4>
189
{
190
  static T swap(T aValue)
191
3.99k
  {
192
3.99k
#if defined(__clang__) || defined(__GNUC__)
193
3.99k
    return T(__builtin_bswap32(aValue));
194
#elif defined(_MSC_VER)
195
    return T(_byteswap_ulong(aValue));
196
#else
197
    return T(((aValue & 0x000000ffU) << 24) |
198
             ((aValue & 0x0000ff00U) << 8) |
199
             ((aValue & 0x00ff0000U) >> 8) |
200
             ((aValue & 0xff000000U) >> 24));
201
#endif
202
  }
mozilla::detail::Swapper<unsigned int, 4ul>::swap(unsigned int)
Line
Count
Source
191
3.99k
  {
192
3.99k
#if defined(__clang__) || defined(__GNUC__)
193
3.99k
    return T(__builtin_bswap32(aValue));
194
#elif defined(_MSC_VER)
195
    return T(_byteswap_ulong(aValue));
196
#else
197
    return T(((aValue & 0x000000ffU) << 24) |
198
             ((aValue & 0x0000ff00U) << 8) |
199
             ((aValue & 0x00ff0000U) >> 8) |
200
             ((aValue & 0xff000000U) >> 24));
201
#endif
202
  }
Unexecuted instantiation: mozilla::detail::Swapper<int, 4ul>::swap(int)
203
};
204
205
template<typename T>
206
struct Swapper<T, 8>
207
{
208
  static inline T swap(T aValue)
209
0
  {
210
0
#if defined(__clang__) || defined(__GNUC__)
211
0
    return T(__builtin_bswap64(aValue));
212
#elif defined(_MSC_VER)
213
    return T(_byteswap_uint64(aValue));
214
#else
215
    return T(((aValue & 0x00000000000000ffULL) << 56) |
216
             ((aValue & 0x000000000000ff00ULL) << 40) |
217
             ((aValue & 0x0000000000ff0000ULL) << 24) |
218
             ((aValue & 0x00000000ff000000ULL) << 8) |
219
             ((aValue & 0x000000ff00000000ULL) >> 8) |
220
             ((aValue & 0x0000ff0000000000ULL) >> 24) |
221
             ((aValue & 0x00ff000000000000ULL) >> 40) |
222
             ((aValue & 0xff00000000000000ULL) >> 56));
223
#endif
224
  }
Unexecuted instantiation: mozilla::detail::Swapper<unsigned long, 8ul>::swap(unsigned long)
Unexecuted instantiation: mozilla::detail::Swapper<long, 8ul>::swap(long)
225
};
226
227
enum Endianness { Little, Big };
228
229
#if MOZ_BIG_ENDIAN
230
#  define MOZ_NATIVE_ENDIANNESS detail::Big
231
#else
232
#  define MOZ_NATIVE_ENDIANNESS detail::Little
233
#endif
234
235
class EndianUtils
236
{
237
  /**
238
   * Assert that the memory regions [aDest, aDest+aCount) and
239
   * [aSrc, aSrc+aCount] do not overlap.  aCount is given in bytes.
240
   */
241
  static void assertNoOverlap(const void* aDest, const void* aSrc,
242
                              size_t aCount)
243
0
  {
244
0
    DebugOnly<const uint8_t*> byteDestPtr = static_cast<const uint8_t*>(aDest);
245
0
    DebugOnly<const uint8_t*> byteSrcPtr = static_cast<const uint8_t*>(aSrc);
246
0
    MOZ_ASSERT((byteDestPtr <= byteSrcPtr &&
247
0
                byteDestPtr + aCount <= byteSrcPtr) ||
248
0
               (byteSrcPtr <= byteDestPtr &&
249
0
                byteSrcPtr + aCount <= byteDestPtr));
250
0
  }
Unexecuted instantiation: mozilla::detail::EndianUtils::assertNoOverlap(void const*, void const*, unsigned long)
Unexecuted instantiation: mozilla::detail::EndianUtils::assertNoOverlap(void const*, void const*, unsigned long)
251
252
  template<typename T>
253
  static void assertAligned(T* aPtr)
254
0
  {
255
0
    MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!");
256
0
  }
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<char16_t>(char16_t*)
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<char16_t const>(char16_t const*)
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<unsigned int>(unsigned int*)
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<unsigned short>(unsigned short*)
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<int>(int*)
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<unsigned int const>(unsigned int const*)
Unexecuted instantiation: void mozilla::detail::EndianUtils::assertAligned<unsigned long>(unsigned long*)
257
258
protected:
259
  /**
260
   * Return |aValue| converted from SourceEndian encoding to DestEndian
261
   * encoding.
262
   */
263
  template<Endianness SourceEndian, Endianness DestEndian, typename T>
264
  static inline T maybeSwap(T aValue)
265
9.17k
  {
266
9.17k
    if (SourceEndian == DestEndian) {
267
5.14k
      return aValue;
268
5.14k
    }
269
4.02k
    return Swapper<T>::swap(aValue);
270
4.02k
  }
unsigned int mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, unsigned int>(unsigned int)
Line
Count
Source
265
3.99k
  {
266
3.99k
    if (SourceEndian == DestEndian) {
267
0
      return aValue;
268
0
    }
269
3.99k
    return Swapper<T>::swap(aValue);
270
3.99k
  }
unsigned int mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned int>(unsigned int)
Line
Count
Source
265
4.45k
  {
266
4.45k
    if (SourceEndian == DestEndian) {
267
4.45k
      return aValue;
268
4.45k
    }
269
0
    return Swapper<T>::swap(aValue);
270
0
  }
unsigned short mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, unsigned short>(unsigned short)
Line
Count
Source
265
39
  {
266
39
    if (SourceEndian == DestEndian) {
267
0
      return aValue;
268
0
    }
269
39
    return Swapper<T>::swap(aValue);
270
39
  }
Unexecuted instantiation: unsigned long mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, unsigned long>(unsigned long)
Unexecuted instantiation: char16_t mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, char16_t>(char16_t)
Unexecuted instantiation: unsigned short mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, unsigned short>(unsigned short)
Unexecuted instantiation: unsigned int mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, unsigned int>(unsigned int)
Unexecuted instantiation: unsigned long mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, unsigned long>(unsigned long)
Unexecuted instantiation: short mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, short>(short)
Unexecuted instantiation: short mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, short>(short)
Unexecuted instantiation: int mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, int>(int)
Unexecuted instantiation: int mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, int>(int)
Unexecuted instantiation: long mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, long>(long)
unsigned short mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned short>(unsigned short)
Line
Count
Source
265
130
  {
266
130
    if (SourceEndian == DestEndian) {
267
130
      return aValue;
268
130
    }
269
0
    return Swapper<T>::swap(aValue);
270
0
  }
Unexecuted instantiation: char16_t mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, char16_t>(char16_t)
Unexecuted instantiation: short mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, short>(short)
Unexecuted instantiation: long mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, long>(long)
Unexecuted instantiation: long mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, long>(long)
unsigned long mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned long>(unsigned long)
Line
Count
Source
265
560
  {
266
560
    if (SourceEndian == DestEndian) {
267
560
      return aValue;
268
560
    }
269
0
    return Swapper<T>::swap(aValue);
270
0
  }
Unexecuted instantiation: char16_t mozilla::detail::EndianUtils::maybeSwap<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, char16_t>(char16_t)
271
272
  /**
273
   * Convert |aCount| elements at |aPtr| from SourceEndian encoding to
274
   * DestEndian encoding.
275
   */
276
  template<Endianness SourceEndian, Endianness DestEndian, typename T>
277
  static inline void maybeSwapInPlace(T* aPtr, size_t aCount)
278
0
  {
279
0
    assertAligned(aPtr);
280
0
281
0
    if (SourceEndian == DestEndian) {
282
0
      return;
283
0
    }
284
0
    for (size_t i = 0; i < aCount; i++) {
285
0
      aPtr[i] = Swapper<T>::swap(aPtr[i]);
286
0
    }
287
0
  }
Unexecuted instantiation: void mozilla::detail::EndianUtils::maybeSwapInPlace<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, char16_t>(char16_t*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::maybeSwapInPlace<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned int>(unsigned int*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::maybeSwapInPlace<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned short>(unsigned short*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::maybeSwapInPlace<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, int>(int*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::maybeSwapInPlace<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned long>(unsigned long*, unsigned long)
288
289
  /**
290
   * Write |aCount| elements to the unaligned address |aDest| in DestEndian
291
   * format, using elements found at |aSrc| in SourceEndian format.
292
   */
293
  template<Endianness SourceEndian, Endianness DestEndian, typename T>
294
  static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount)
295
0
  {
296
0
    assertNoOverlap(aDest, aSrc, aCount * sizeof(T));
297
0
    assertAligned(aSrc);
298
0
299
0
    if (SourceEndian == DestEndian) {
300
0
      memcpy(aDest, aSrc, aCount * sizeof(T));
301
0
      return;
302
0
    }
303
0
304
0
    uint8_t* byteDestPtr = static_cast<uint8_t*>(aDest);
305
0
    for (size_t i = 0; i < aCount; ++i) {
306
0
      union
307
0
      {
308
0
        T mVal;
309
0
        uint8_t mBuffer[sizeof(T)];
310
0
      } u;
311
0
      u.mVal = maybeSwap<SourceEndian, DestEndian>(aSrc[i]);
312
0
      memcpy(byteDestPtr, u.mBuffer, sizeof(T));
313
0
      byteDestPtr += sizeof(T);
314
0
    }
315
0
  }
Unexecuted instantiation: void mozilla::detail::EndianUtils::copyAndSwapTo<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, char16_t>(void*, char16_t const*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::copyAndSwapTo<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, unsigned int>(void*, unsigned int const*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::copyAndSwapTo<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)1, unsigned int>(void*, unsigned int const*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::copyAndSwapTo<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, char16_t>(void*, char16_t const*, unsigned long)
316
317
  /**
318
   * Write |aCount| elements to |aDest| in DestEndian format, using elements
319
   * found at the unaligned address |aSrc| in SourceEndian format.
320
   */
321
  template<Endianness SourceEndian, Endianness DestEndian, typename T>
322
  static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount)
323
0
  {
324
0
    assertNoOverlap(aDest, aSrc, aCount * sizeof(T));
325
0
    assertAligned(aDest);
326
0
327
0
    if (SourceEndian == DestEndian) {
328
0
      memcpy(aDest, aSrc, aCount * sizeof(T));
329
0
      return;
330
0
    }
331
0
332
0
    const uint8_t* byteSrcPtr = static_cast<const uint8_t*>(aSrc);
333
0
    for (size_t i = 0; i < aCount; ++i) {
334
0
      union
335
0
      {
336
0
        T mVal;
337
0
        uint8_t mBuffer[sizeof(T)];
338
0
      } u;
339
0
      memcpy(u.mBuffer, byteSrcPtr, sizeof(T));
340
0
      aDest[i] = maybeSwap<SourceEndian, DestEndian>(u.mVal);
341
0
      byteSrcPtr += sizeof(T);
342
0
    }
343
0
  }
Unexecuted instantiation: void mozilla::detail::EndianUtils::copyAndSwapFrom<(mozilla::detail::Endianness)1, (mozilla::detail::Endianness)0, char16_t>(char16_t*, void const*, unsigned long)
Unexecuted instantiation: void mozilla::detail::EndianUtils::copyAndSwapFrom<(mozilla::detail::Endianness)0, (mozilla::detail::Endianness)0, char16_t>(char16_t*, void const*, unsigned long)
344
};
345
346
template<Endianness ThisEndian>
347
class Endian : private EndianUtils
348
{
349
protected:
350
  /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */
351
  static MOZ_MUST_USE uint16_t readUint16(const void* aPtr)
352
0
  {
353
0
    return read<uint16_t>(aPtr);
354
0
  }
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)1>::readUint16(void const*)
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)0>::readUint16(void const*)
355
356
  /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */
357
  static MOZ_MUST_USE uint32_t readUint32(const void* aPtr)
358
0
  {
359
0
    return read<uint32_t>(aPtr);
360
0
  }
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)0>::readUint32(void const*)
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)1>::readUint32(void const*)
361
362
  /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */
363
  static MOZ_MUST_USE uint64_t readUint64(const void* aPtr)
364
0
  {
365
0
    return read<uint64_t>(aPtr);
366
0
  }
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)1>::readUint64(void const*)
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)0>::readUint64(void const*)
367
368
  /** Read a uintptr_t in ThisEndian endianness from |aPtr| and return it. */
369
  static MOZ_MUST_USE uintptr_t readUintptr(const void* aPtr)
370
  {
371
    return read<uintptr_t>(aPtr);
372
  }
373
374
  /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */
375
  static MOZ_MUST_USE int16_t readInt16(const void* aPtr)
376
0
  {
377
0
    return read<int16_t>(aPtr);
378
0
  }
379
380
  /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */
381
  static MOZ_MUST_USE int32_t readInt32(const void* aPtr)
382
0
  {
383
0
    return read<uint32_t>(aPtr);
384
0
  }
385
386
  /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */
387
  static MOZ_MUST_USE int64_t readInt64(const void* aPtr)
388
0
  {
389
0
    return read<int64_t>(aPtr);
390
0
  }
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)1>::readInt64(void const*)
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)0>::readInt64(void const*)
391
392
  /** Read an intptr_t in ThisEndian endianness from |aPtr| and return it. */
393
  static MOZ_MUST_USE intptr_t readIntptr(const void* aPtr)
394
  {
395
    return read<intptr_t>(aPtr);
396
  }
397
398
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
399
  static void writeUint16(void* aPtr, uint16_t aValue)
400
130
  {
401
130
    write(aPtr, aValue);
402
130
  }
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)1>::writeUint16(void*, unsigned short)
mozilla::detail::Endian<(mozilla::detail::Endianness)0>::writeUint16(void*, unsigned short)
Line
Count
Source
400
130
  {
401
130
    write(aPtr, aValue);
402
130
  }
403
404
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
405
  static void writeUint32(void* aPtr, uint32_t aValue)
406
8.44k
  {
407
8.44k
    write(aPtr, aValue);
408
8.44k
  }
mozilla::detail::Endian<(mozilla::detail::Endianness)0>::writeUint32(void*, unsigned int)
Line
Count
Source
406
4.45k
  {
407
4.45k
    write(aPtr, aValue);
408
4.45k
  }
mozilla::detail::Endian<(mozilla::detail::Endianness)1>::writeUint32(void*, unsigned int)
Line
Count
Source
406
3.99k
  {
407
3.99k
    write(aPtr, aValue);
408
3.99k
  }
409
410
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
411
  static void writeUint64(void* aPtr, uint64_t aValue)
412
6
  {
413
6
    write(aPtr, aValue);
414
6
  }
Unexecuted instantiation: mozilla::detail::Endian<(mozilla::detail::Endianness)1>::writeUint64(void*, unsigned long)
mozilla::detail::Endian<(mozilla::detail::Endianness)0>::writeUint64(void*, unsigned long)
Line
Count
Source
412
6
  {
413
6
    write(aPtr, aValue);
414
6
  }
415
416
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
417
  static void writeUintptr(void* aPtr, uintptr_t aValue)
418
530
  {
419
530
    write(aPtr, aValue);
420
530
  }
421
422
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
423
  static void writeInt16(void* aPtr, int16_t aValue)
424
  {
425
    write(aPtr, aValue);
426
  }
427
428
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
429
  static void writeInt32(void* aPtr, int32_t aValue)
430
0
  {
431
0
    write(aPtr, aValue);
432
0
  }
433
434
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
435
  static void writeInt64(void* aPtr, int64_t aValue)
436
0
  {
437
0
    write(aPtr, aValue);
438
0
  }
439
440
  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
441
  static void writeIntptr(void* aPtr, intptr_t aValue)
442
  {
443
    write(aPtr, aValue);
444
  }
445
446
  /*
447
   * Converts a value of type T to little-endian format.
448
   *
449
   * This function is intended for cases where you have data in your
450
   * native-endian format and you need it to appear in little-endian
451
   * format for transmission.
452
   */
453
  template<typename T>
454
  MOZ_MUST_USE static T swapToLittleEndian(T aValue)
455
6
  {
456
6
    return maybeSwap<ThisEndian, Little>(aValue);
457
6
  }
Unexecuted instantiation: unsigned int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndian<unsigned int>(unsigned int)
unsigned long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndian<unsigned long>(unsigned long)
Line
Count
Source
455
6
  {
456
6
    return maybeSwap<ThisEndian, Little>(aValue);
457
6
  }
Unexecuted instantiation: long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndian<long>(long)
Unexecuted instantiation: unsigned short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndian<unsigned short>(unsigned short)
458
459
  /*
460
   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
461
   * them to little-endian format if ThisEndian is Big.
462
   * As with memcpy, |aDest| and |aSrc| must not overlap.
463
   */
464
  template<typename T>
465
  static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc,
466
                                        size_t aCount)
467
0
  {
468
0
    copyAndSwapTo<ThisEndian, Little>(aDest, aSrc, aCount);
469
0
  }
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::copyAndSwapToLittleEndian<unsigned int>(void*, unsigned int const*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::copyAndSwapToLittleEndian<char16_t>(void*, char16_t const*, unsigned long)
470
471
  /*
472
   * Likewise, but converts values in place.
473
   */
474
  template<typename T>
475
  static void swapToLittleEndianInPlace(T* aPtr, size_t aCount)
476
0
  {
477
0
    maybeSwapInPlace<ThisEndian, Little>(aPtr, aCount);
478
0
  }
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndianInPlace<unsigned int>(unsigned int*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndianInPlace<unsigned short>(unsigned short*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToLittleEndianInPlace<int>(int*, unsigned long)
479
480
  /*
481
   * Converts a value of type T to big-endian format.
482
   */
483
  template<typename T>
484
  MOZ_MUST_USE static T swapToBigEndian(T aValue)
485
39
  {
486
39
    return maybeSwap<ThisEndian, Big>(aValue);
487
39
  }
Unexecuted instantiation: unsigned int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToBigEndian<unsigned int>(unsigned int)
unsigned short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToBigEndian<unsigned short>(unsigned short)
Line
Count
Source
485
39
  {
486
39
    return maybeSwap<ThisEndian, Big>(aValue);
487
39
  }
Unexecuted instantiation: unsigned long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToBigEndian<unsigned long>(unsigned long)
Unexecuted instantiation: short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToBigEndian<short>(short)
Unexecuted instantiation: int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapToBigEndian<int>(int)
488
489
  /*
490
   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
491
   * them to big-endian format if ThisEndian is Little.
492
   * As with memcpy, |aDest| and |aSrc| must not overlap.
493
   */
494
  template<typename T>
495
  static void copyAndSwapToBigEndian(void* aDest, const T* aSrc,
496
                                     size_t aCount)
497
0
  {
498
0
    copyAndSwapTo<ThisEndian, Big>(aDest, aSrc, aCount);
499
0
  }
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::copyAndSwapToBigEndian<char16_t>(void*, char16_t const*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::copyAndSwapToBigEndian<unsigned int>(void*, unsigned int const*, unsigned long)
500
501
  /*
502
   * Likewise, but converts values in place.
503
   */
504
  template<typename T>
505
  static void swapToBigEndianInPlace(T* aPtr, size_t aCount)
506
0
  {
507
0
    maybeSwapInPlace<ThisEndian, Big>(aPtr, aCount);
508
0
  }
509
510
  /*
511
   * Synonyms for the big-endian functions, for better readability
512
   * in network code.
513
   */
514
515
  template<typename T>
516
  MOZ_MUST_USE static T swapToNetworkOrder(T aValue)
517
  {
518
    return swapToBigEndian(aValue);
519
  }
520
521
  template<typename T>
522
  static void
523
  copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount)
524
  {
525
    copyAndSwapToBigEndian(aDest, aSrc, aCount);
526
  }
527
528
  template<typename T>
529
  static void
530
  swapToNetworkOrderInPlace(T* aPtr, size_t aCount)
531
  {
532
    swapToBigEndianInPlace(aPtr, aCount);
533
  }
534
535
  /*
536
   * Converts a value of type T from little-endian format.
537
   */
538
  template<typename T>
539
  MOZ_MUST_USE static T swapFromLittleEndian(T aValue)
540
18
  {
541
18
    return maybeSwap<Little, ThisEndian>(aValue);
542
18
  }
Unexecuted instantiation: unsigned int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromLittleEndian<unsigned int>(unsigned int)
unsigned long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromLittleEndian<unsigned long>(unsigned long)
Line
Count
Source
540
18
  {
541
18
    return maybeSwap<Little, ThisEndian>(aValue);
542
18
  }
Unexecuted instantiation: long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromLittleEndian<long>(long)
543
544
  /*
545
   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
546
   * them to little-endian format if ThisEndian is Big.
547
   * As with memcpy, |aDest| and |aSrc| must not overlap.
548
   */
549
  template<typename T>
550
  static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc,
551
                                          size_t aCount)
552
0
  {
553
0
    copyAndSwapFrom<Little, ThisEndian>(aDest, aSrc, aCount);
554
0
  }
555
556
  /*
557
   * Likewise, but converts values in place.
558
   */
559
  template<typename T>
560
  static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount)
561
0
  {
562
0
    maybeSwapInPlace<Little, ThisEndian>(aPtr, aCount);
563
0
  }
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromLittleEndianInPlace<unsigned short>(unsigned short*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromLittleEndianInPlace<unsigned int>(unsigned int*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromLittleEndianInPlace<unsigned long>(unsigned long*, unsigned long)
564
565
  /*
566
   * Converts a value of type T from big-endian format.
567
   */
568
  template<typename T>
569
  MOZ_MUST_USE static T swapFromBigEndian(T aValue)
570
0
  {
571
0
    return maybeSwap<Big, ThisEndian>(aValue);
572
0
  }
Unexecuted instantiation: unsigned short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromBigEndian<unsigned short>(unsigned short)
Unexecuted instantiation: unsigned int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromBigEndian<unsigned int>(unsigned int)
Unexecuted instantiation: unsigned long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromBigEndian<unsigned long>(unsigned long)
Unexecuted instantiation: short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromBigEndian<short>(short)
Unexecuted instantiation: int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::swapFromBigEndian<int>(int)
573
574
  /*
575
   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
576
   * them to big-endian format if ThisEndian is Little.
577
   * As with memcpy, |aDest| and |aSrc| must not overlap.
578
   */
579
  template<typename T>
580
  static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc,
581
                                       size_t aCount)
582
0
  {
583
0
    copyAndSwapFrom<Big, ThisEndian>(aDest, aSrc, aCount);
584
0
  }
585
586
  /*
587
   * Likewise, but converts values in place.
588
   */
589
  template<typename T>
590
  static void swapFromBigEndianInPlace(T* aPtr, size_t aCount)
591
  {
592
    maybeSwapInPlace<Big, ThisEndian>(aPtr, aCount);
593
  }
594
595
  /*
596
   * Synonyms for the big-endian functions, for better readability
597
   * in network code.
598
   */
599
  template<typename T>
600
  MOZ_MUST_USE static T swapFromNetworkOrder(T aValue)
601
  {
602
    return swapFromBigEndian(aValue);
603
  }
604
605
  template<typename T>
606
  static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc,
607
                                          size_t aCount)
608
  {
609
    copyAndSwapFromBigEndian(aDest, aSrc, aCount);
610
  }
611
612
  template<typename T>
613
  static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount)
614
  {
615
    swapFromBigEndianInPlace(aPtr, aCount);
616
  }
617
618
private:
619
  /**
620
   * Read a value of type T, encoded in endianness ThisEndian from |aPtr|.
621
   * Return that value encoded in native endianness.
622
   */
623
  template<typename T>
624
  static T read(const void* aPtr)
625
0
  {
626
0
    union
627
0
    {
628
0
      T mVal;
629
0
      uint8_t mBuffer[sizeof(T)];
630
0
    } u;
631
0
    memcpy(u.mBuffer, aPtr, sizeof(T));
632
0
    return maybeSwap<ThisEndian, MOZ_NATIVE_ENDIANNESS>(u.mVal);
633
0
  }
Unexecuted instantiation: unsigned int mozilla::detail::Endian<(mozilla::detail::Endianness)0>::read<unsigned int>(void const*)
Unexecuted instantiation: unsigned short mozilla::detail::Endian<(mozilla::detail::Endianness)1>::read<unsigned short>(void const*)
Unexecuted instantiation: unsigned int mozilla::detail::Endian<(mozilla::detail::Endianness)1>::read<unsigned int>(void const*)
Unexecuted instantiation: unsigned long mozilla::detail::Endian<(mozilla::detail::Endianness)1>::read<unsigned long>(void const*)
Unexecuted instantiation: long mozilla::detail::Endian<(mozilla::detail::Endianness)1>::read<long>(void const*)
Unexecuted instantiation: unsigned short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::read<unsigned short>(void const*)
Unexecuted instantiation: short mozilla::detail::Endian<(mozilla::detail::Endianness)0>::read<short>(void const*)
Unexecuted instantiation: long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::read<long>(void const*)
Unexecuted instantiation: unsigned long mozilla::detail::Endian<(mozilla::detail::Endianness)0>::read<unsigned long>(void const*)
634
635
  /**
636
   * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian
637
   * endianness.
638
   */
639
  template<typename T>
640
  static void write(void* aPtr, T aValue)
641
9.11k
  {
642
9.11k
    T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
643
9.11k
    memcpy(aPtr, &tmp, sizeof(T));
644
9.11k
  }
void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::write<unsigned int>(void*, unsigned int)
Line
Count
Source
641
4.45k
  {
642
4.45k
    T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
643
4.45k
    memcpy(aPtr, &tmp, sizeof(T));
644
4.45k
  }
void mozilla::detail::Endian<(mozilla::detail::Endianness)1>::write<unsigned int>(void*, unsigned int)
Line
Count
Source
641
3.99k
  {
642
3.99k
    T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
643
3.99k
    memcpy(aPtr, &tmp, sizeof(T));
644
3.99k
  }
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)1>::write<unsigned long>(void*, unsigned long)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)1>::write<unsigned short>(void*, unsigned short)
void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::write<unsigned short>(void*, unsigned short)
Line
Count
Source
641
130
  {
642
130
    T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
643
130
    memcpy(aPtr, &tmp, sizeof(T));
644
130
  }
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)1>::write<int>(void*, int)
Unexecuted instantiation: void mozilla::detail::Endian<(mozilla::detail::Endianness)1>::write<long>(void*, long)
void mozilla::detail::Endian<(mozilla::detail::Endianness)0>::write<unsigned long>(void*, unsigned long)
Line
Count
Source
641
536
  {
642
536
    T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
643
536
    memcpy(aPtr, &tmp, sizeof(T));
644
536
  }
645
646
  Endian() = delete;
647
  Endian(const Endian& aTther) = delete;
648
  void operator=(const Endian& aOther) = delete;
649
};
650
651
template<Endianness ThisEndian>
652
class EndianReadWrite : public Endian<ThisEndian>
653
{
654
private:
655
  typedef Endian<ThisEndian> super;
656
657
public:
658
  using super::readUint16;
659
  using super::readUint32;
660
  using super::readUint64;
661
  using super::readUintptr;
662
  using super::readInt16;
663
  using super::readInt32;
664
  using super::readInt64;
665
  using super::readIntptr;
666
  using super::writeUint16;
667
  using super::writeUint32;
668
  using super::writeUint64;
669
  using super::writeUintptr;
670
  using super::writeInt16;
671
  using super::writeInt32;
672
  using super::writeInt64;
673
  using super::writeIntptr;
674
};
675
676
} /* namespace detail */
677
678
class LittleEndian final : public detail::EndianReadWrite<detail::Little>
679
{};
680
681
class BigEndian final : public detail::EndianReadWrite<detail::Big>
682
{};
683
684
typedef BigEndian NetworkEndian;
685
686
class NativeEndian final : public detail::Endian<MOZ_NATIVE_ENDIANNESS>
687
{
688
private:
689
  typedef detail::Endian<MOZ_NATIVE_ENDIANNESS> super;
690
691
public:
692
  /*
693
   * These functions are intended for cases where you have data in your
694
   * native-endian format and you need the data to appear in the appropriate
695
   * endianness for transmission, serialization, etc.
696
   */
697
  using super::swapToLittleEndian;
698
  using super::copyAndSwapToLittleEndian;
699
  using super::swapToLittleEndianInPlace;
700
  using super::swapToBigEndian;
701
  using super::copyAndSwapToBigEndian;
702
  using super::swapToBigEndianInPlace;
703
  using super::swapToNetworkOrder;
704
  using super::copyAndSwapToNetworkOrder;
705
  using super::swapToNetworkOrderInPlace;
706
707
  /*
708
   * These functions are intended for cases where you have data in the
709
   * given endianness (e.g. reading from disk or a file-format) and you
710
   * need the data to appear in native-endian format for processing.
711
   */
712
  using super::swapFromLittleEndian;
713
  using super::copyAndSwapFromLittleEndian;
714
  using super::swapFromLittleEndianInPlace;
715
  using super::swapFromBigEndian;
716
  using super::copyAndSwapFromBigEndian;
717
  using super::swapFromBigEndianInPlace;
718
  using super::swapFromNetworkOrder;
719
  using super::copyAndSwapFromNetworkOrder;
720
  using super::swapFromNetworkOrderInPlace;
721
};
722
723
#undef MOZ_NATIVE_ENDIANNESS
724
725
} /* namespace mozilla */
726
727
#endif /* mozilla_EndianUtils_h */