EndianUtils.h 19 KB

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