EndianUtils.h 19 KB

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