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