michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Functions for reading and writing integers in various endiannesses. */ michael@0: michael@0: /* michael@0: * The classes LittleEndian and BigEndian expose static methods for michael@0: * reading and writing 16-, 32-, and 64-bit signed and unsigned integers michael@0: * in their respective endianness. The naming scheme is: michael@0: * michael@0: * {Little,Big}Endian::{read,write}{Uint,Int} michael@0: * michael@0: * For instance, LittleEndian::readInt32 will read a 32-bit signed michael@0: * integer from memory in little endian format. Similarly, michael@0: * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory michael@0: * in big-endian format. michael@0: * michael@0: * The class NativeEndian exposes methods for conversion of existing michael@0: * data to and from the native endianness. These methods are intended michael@0: * for cases where data needs to be transferred, serialized, etc. michael@0: * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. michael@0: * Bulk conversion functions are also provided which optimize the michael@0: * no-conversion-needed case: michael@0: * michael@0: * - copyAndSwap{To,From}{Little,Big}Endian; michael@0: * - swap{To,From}{Little,Big}EndianInPlace. michael@0: * michael@0: * The *From* variants are intended to be used for reading data and the michael@0: * *To* variants for writing data. michael@0: * michael@0: * Methods on NativeEndian work with integer data of any type. michael@0: * Floating-point data is not supported. michael@0: * michael@0: * For clarity in networking code, "Network" may be used as a synonym michael@0: * for "Big" in any of the above methods or class names. michael@0: * michael@0: * As an example, reading a file format header whose fields are stored michael@0: * in big-endian format might look like: michael@0: * michael@0: * class ExampleHeader michael@0: * { michael@0: * private: michael@0: * uint32_t magic; michael@0: * uint32_t length; michael@0: * uint32_t totalRecords; michael@0: * uint64_t checksum; michael@0: * michael@0: * public: michael@0: * ExampleHeader(const void* data) { michael@0: * const uint8_t* ptr = static_cast(data); michael@0: * magic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); michael@0: * length = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); michael@0: * totalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); michael@0: * checksum = BigEndian::readUint64(ptr); michael@0: * } michael@0: * ... michael@0: * }; michael@0: */ michael@0: michael@0: #ifndef mozilla_Endian_h michael@0: #define mozilla_Endian_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Compiler.h" michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #if defined(_MSC_VER) && _MSC_VER >= 1300 michael@0: # include michael@0: # pragma intrinsic(_byteswap_ushort) michael@0: # pragma intrinsic(_byteswap_ulong) michael@0: # pragma intrinsic(_byteswap_uint64) michael@0: #endif michael@0: michael@0: #if defined(_WIN64) michael@0: # if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) michael@0: # define MOZ_LITTLE_ENDIAN 1 michael@0: # else michael@0: # error "CPU type is unknown" michael@0: # endif michael@0: #elif defined(_WIN32) michael@0: # if defined(_M_IX86) michael@0: # define MOZ_LITTLE_ENDIAN 1 michael@0: # else michael@0: # error "CPU type is unknown" michael@0: # endif michael@0: #elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) michael@0: # if __LITTLE_ENDIAN__ michael@0: # define MOZ_LITTLE_ENDIAN 1 michael@0: # elif __BIG_ENDIAN__ michael@0: # define MOZ_BIG_ENDIAN 1 michael@0: # endif michael@0: #elif defined(__GNUC__) && \ michael@0: defined(__BYTE_ORDER__) && \ michael@0: defined(__ORDER_LITTLE_ENDIAN__) && \ michael@0: defined(__ORDER_BIG_ENDIAN__) michael@0: /* michael@0: * Some versions of GCC provide architecture-independent macros for michael@0: * this. Yes, there are more than two values for __BYTE_ORDER__. michael@0: */ michael@0: # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ michael@0: # define MOZ_LITTLE_ENDIAN 1 michael@0: # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ michael@0: # define MOZ_BIG_ENDIAN 1 michael@0: # else michael@0: # error "Can't handle mixed-endian architectures" michael@0: # endif michael@0: /* michael@0: * We can't include useful headers like or michael@0: * here because they're not present on all platforms. Instead we have michael@0: * this big conditional that ideally will catch all the interesting michael@0: * cases. michael@0: */ michael@0: #elif defined(__sparc) || defined(__sparc__) || \ michael@0: defined(_POWER) || defined(__hppa) || \ michael@0: defined(_MIPSEB) || defined(__ARMEB__) || \ michael@0: defined(__s390__) || defined(__AARCH64EB__) || \ michael@0: (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ michael@0: (defined(__ia64) && defined(__BIG_ENDIAN__)) michael@0: # define MOZ_BIG_ENDIAN 1 michael@0: #elif defined(__i386) || defined(__i386__) || \ michael@0: defined(__x86_64) || defined(__x86_64__) || \ michael@0: defined(_MIPSEL) || defined(__ARMEL__) || \ michael@0: defined(__alpha__) || defined(__AARCH64EL__) || \ michael@0: (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ michael@0: (defined(__ia64) && !defined(__BIG_ENDIAN__)) michael@0: # define MOZ_LITTLE_ENDIAN 1 michael@0: #endif michael@0: michael@0: #if MOZ_BIG_ENDIAN michael@0: # define MOZ_LITTLE_ENDIAN 0 michael@0: #elif MOZ_LITTLE_ENDIAN michael@0: # define MOZ_BIG_ENDIAN 0 michael@0: #else michael@0: # error "Cannot determine endianness" michael@0: #endif michael@0: michael@0: #if defined(__clang__) michael@0: # if __has_builtin(__builtin_bswap16) michael@0: # define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 michael@0: # endif michael@0: #elif defined(__GNUC__) michael@0: # if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) michael@0: # define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 michael@0: # endif michael@0: #elif defined(_MSC_VER) michael@0: # define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace detail { michael@0: michael@0: /* michael@0: * We need wrappers here because free functions with default template michael@0: * arguments and/or partial specialization of function templates are not michael@0: * supported by all the compilers we use. michael@0: */ michael@0: template michael@0: struct Swapper; michael@0: michael@0: template michael@0: struct Swapper michael@0: { michael@0: static T swap(T value) michael@0: { michael@0: #if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) michael@0: return MOZ_HAVE_BUILTIN_BYTESWAP16(value); michael@0: #else michael@0: return T(((value & 0x00ff) << 8) | ((value & 0xff00) >> 8)); michael@0: #endif michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct Swapper michael@0: { michael@0: static T swap(T value) michael@0: { michael@0: #if defined(__clang__) || defined(__GNUC__) michael@0: return T(__builtin_bswap32(value)); michael@0: #elif defined(_MSC_VER) michael@0: return T(_byteswap_ulong(value)); michael@0: #else michael@0: return T(((value & 0x000000ffU) << 24) | michael@0: ((value & 0x0000ff00U) << 8) | michael@0: ((value & 0x00ff0000U) >> 8) | michael@0: ((value & 0xff000000U) >> 24)); michael@0: #endif michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct Swapper michael@0: { michael@0: static inline T swap(T value) michael@0: { michael@0: #if defined(__clang__) || defined(__GNUC__) michael@0: return T(__builtin_bswap64(value)); michael@0: #elif defined(_MSC_VER) michael@0: return T(_byteswap_uint64(value)); michael@0: #else michael@0: return T(((value & 0x00000000000000ffULL) << 56) | michael@0: ((value & 0x000000000000ff00ULL) << 40) | michael@0: ((value & 0x0000000000ff0000ULL) << 24) | michael@0: ((value & 0x00000000ff000000ULL) << 8) | michael@0: ((value & 0x000000ff00000000ULL) >> 8) | michael@0: ((value & 0x0000ff0000000000ULL) >> 24) | michael@0: ((value & 0x00ff000000000000ULL) >> 40) | michael@0: ((value & 0xff00000000000000ULL) >> 56)); michael@0: #endif michael@0: } michael@0: }; michael@0: michael@0: enum Endianness { Little, Big }; michael@0: michael@0: #if MOZ_BIG_ENDIAN michael@0: # define MOZ_NATIVE_ENDIANNESS detail::Big michael@0: #else michael@0: # define MOZ_NATIVE_ENDIANNESS detail::Little michael@0: #endif michael@0: michael@0: class EndianUtils michael@0: { michael@0: /** michael@0: * Assert that the memory regions [dest, dest+count) and [src, src+count] michael@0: * do not overlap. count is given in bytes. michael@0: */ michael@0: static void assertNoOverlap(const void* dest, const void* src, size_t count) michael@0: { michael@0: DebugOnly byteDestPtr = static_cast(dest); michael@0: DebugOnly byteSrcPtr = static_cast(src); michael@0: MOZ_ASSERT((byteDestPtr <= byteSrcPtr && michael@0: byteDestPtr + count <= byteSrcPtr) || michael@0: (byteSrcPtr <= byteDestPtr && michael@0: byteSrcPtr + count <= byteDestPtr)); michael@0: } michael@0: michael@0: template michael@0: static void assertAligned(T* ptr) michael@0: { michael@0: MOZ_ASSERT((uintptr_t(ptr) % sizeof(T)) == 0, "Unaligned pointer!"); michael@0: } michael@0: michael@0: protected: michael@0: /** michael@0: * Return |value| converted from SourceEndian encoding to DestEndian michael@0: * encoding. michael@0: */ michael@0: template michael@0: static inline T maybeSwap(T value) michael@0: { michael@0: if (SourceEndian == DestEndian) michael@0: return value; michael@0: michael@0: return Swapper::swap(value); michael@0: } michael@0: michael@0: /** michael@0: * Convert |count| elements at |ptr| from SourceEndian encoding to michael@0: * DestEndian encoding. michael@0: */ michael@0: template michael@0: static inline void maybeSwapInPlace(T* ptr, size_t count) michael@0: { michael@0: assertAligned(ptr); michael@0: michael@0: if (SourceEndian == DestEndian) michael@0: return; michael@0: michael@0: for (size_t i = 0; i < count; i++) michael@0: ptr[i] = Swapper::swap(ptr[i]); michael@0: } michael@0: michael@0: /** michael@0: * Write |count| elements to the unaligned address |dest| in DestEndian michael@0: * format, using elements found at |src| in SourceEndian format. michael@0: */ michael@0: template michael@0: static void copyAndSwapTo(void* dest, const T* src, size_t count) michael@0: { michael@0: assertNoOverlap(dest, src, count * sizeof(T)); michael@0: assertAligned(src); michael@0: michael@0: if (SourceEndian == DestEndian) { michael@0: memcpy(dest, src, count * sizeof(T)); michael@0: return; michael@0: } michael@0: michael@0: uint8_t* byteDestPtr = static_cast(dest); michael@0: for (size_t i = 0; i < count; ++i) { michael@0: union { michael@0: T val; michael@0: uint8_t buffer[sizeof(T)]; michael@0: } u; michael@0: u.val = maybeSwap(src[i]); michael@0: memcpy(byteDestPtr, u.buffer, sizeof(T)); michael@0: byteDestPtr += sizeof(T); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Write |count| elements to |dest| in DestEndian format, using elements michael@0: * found at the unaligned address |src| in SourceEndian format. michael@0: */ michael@0: template michael@0: static void copyAndSwapFrom(T* dest, const void* src, size_t count) michael@0: { michael@0: assertNoOverlap(dest, src, count * sizeof(T)); michael@0: assertAligned(dest); michael@0: michael@0: if (SourceEndian == DestEndian) { michael@0: memcpy(dest, src, count * sizeof(T)); michael@0: return; michael@0: } michael@0: michael@0: const uint8_t* byteSrcPtr = static_cast(src); michael@0: for (size_t i = 0; i < count; ++i) { michael@0: union { michael@0: T val; michael@0: uint8_t buffer[sizeof(T)]; michael@0: } u; michael@0: memcpy(u.buffer, byteSrcPtr, sizeof(T)); michael@0: dest[i] = maybeSwap(u.val); michael@0: byteSrcPtr += sizeof(T); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class Endian : private EndianUtils michael@0: { michael@0: protected: michael@0: /** Read a uint16_t in ThisEndian endianness from |p| and return it. */ michael@0: static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* p) { michael@0: return read(p); michael@0: } michael@0: michael@0: /** Read a uint32_t in ThisEndian endianness from |p| and return it. */ michael@0: static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* p) { michael@0: return read(p); michael@0: } michael@0: michael@0: /** Read a uint64_t in ThisEndian endianness from |p| and return it. */ michael@0: static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* p) { michael@0: return read(p); michael@0: } michael@0: michael@0: /** Read an int16_t in ThisEndian endianness from |p| and return it. */ michael@0: static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* p) { michael@0: return read(p); michael@0: } michael@0: michael@0: /** Read an int32_t in ThisEndian endianness from |p| and return it. */ michael@0: static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* p) { michael@0: return read(p); michael@0: } michael@0: michael@0: /** Read an int64_t in ThisEndian endianness from |p| and return it. */ michael@0: static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* p) { michael@0: return read(p); michael@0: } michael@0: michael@0: /** Write |val| to |p| using ThisEndian endianness. */ michael@0: static void writeUint16(void* p, uint16_t val) { michael@0: write(p, val); michael@0: } michael@0: /** Write |val| to |p| using ThisEndian endianness. */ michael@0: static void writeUint32(void* p, uint32_t val) { michael@0: write(p, val); michael@0: } michael@0: /** Write |val| to |p| using ThisEndian endianness. */ michael@0: static void writeUint64(void* p, uint64_t val) { michael@0: write(p, val); michael@0: } michael@0: michael@0: /** Write |val| to |p| using ThisEndian endianness. */ michael@0: static void writeInt16(void* p, int16_t val) { michael@0: write(p, val); michael@0: } michael@0: /** Write |val| to |p| using ThisEndian endianness. */ michael@0: static void writeInt32(void* p, int32_t val) { michael@0: write(p, val); michael@0: } michael@0: /** Write |val| to |p| using ThisEndian endianness. */ michael@0: static void writeInt64(void* p, int64_t val) { michael@0: write(p, val); michael@0: } michael@0: michael@0: /* michael@0: * Converts a value of type T to little-endian format. michael@0: * michael@0: * This function is intended for cases where you have data in your michael@0: * native-endian format and you need it to appear in little-endian michael@0: * format for transmission. michael@0: */ michael@0: template michael@0: MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T value) { michael@0: return maybeSwap(value); michael@0: } michael@0: /* michael@0: * Copies count values of type T starting at src to dest, converting michael@0: * them to little-endian format if ThisEndian is Big. michael@0: * As with memcpy, dest and src must not overlap. michael@0: */ michael@0: template michael@0: static void copyAndSwapToLittleEndian(void* dest, const T* src, michael@0: size_t count) { michael@0: copyAndSwapTo(dest, src, count); michael@0: } michael@0: /* michael@0: * Likewise, but converts values in place. michael@0: */ michael@0: template michael@0: static void swapToLittleEndianInPlace(T* p, size_t count) { michael@0: maybeSwapInPlace(p, count); michael@0: } michael@0: michael@0: /* michael@0: * Converts a value of type T to big-endian format. michael@0: */ michael@0: template michael@0: MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T value) { michael@0: return maybeSwap(value); michael@0: } michael@0: /* michael@0: * Copies count values of type T starting at src to dest, converting michael@0: * them to big-endian format if ThisEndian is Little. michael@0: * As with memcpy, dest and src must not overlap. michael@0: */ michael@0: template michael@0: static void copyAndSwapToBigEndian(void* dest, const T* src, size_t count) { michael@0: copyAndSwapTo(dest, src, count); michael@0: } michael@0: /* michael@0: * Likewise, but converts values in place. michael@0: */ michael@0: template michael@0: static void swapToBigEndianInPlace(T* p, size_t count) { michael@0: maybeSwapInPlace(p, count); michael@0: } michael@0: michael@0: /* michael@0: * Synonyms for the big-endian functions, for better readability michael@0: * in network code. michael@0: */ michael@0: template michael@0: MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T value) { michael@0: return swapToBigEndian(value); michael@0: } michael@0: template michael@0: static void michael@0: copyAndSwapToNetworkOrder(void* dest, const T* src, size_t count) { michael@0: copyAndSwapToBigEndian(dest, src, count); michael@0: } michael@0: template michael@0: static void michael@0: swapToNetworkOrderInPlace(T* p, size_t count) { michael@0: swapToBigEndianInPlace(p, count); michael@0: } michael@0: michael@0: /* michael@0: * Converts a value of type T from little-endian format. michael@0: */ michael@0: template michael@0: MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T value) { michael@0: return maybeSwap(value); michael@0: } michael@0: /* michael@0: * Copies count values of type T starting at src to dest, converting michael@0: * them to little-endian format if ThisEndian is Big. michael@0: * As with memcpy, dest and src must not overlap. michael@0: */ michael@0: template michael@0: static void copyAndSwapFromLittleEndian(T* dest, const void* src, michael@0: size_t count) { michael@0: copyAndSwapFrom(dest, src, count); michael@0: } michael@0: /* michael@0: * Likewise, but converts values in place. michael@0: */ michael@0: template michael@0: static void swapFromLittleEndianInPlace(T* p, size_t count) { michael@0: maybeSwapInPlace(p, count); michael@0: } michael@0: michael@0: /* michael@0: * Converts a value of type T from big-endian format. michael@0: */ michael@0: template michael@0: MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T value) { michael@0: return maybeSwap(value); michael@0: } michael@0: /* michael@0: * Copies count values of type T starting at src to dest, converting michael@0: * them to big-endian format if ThisEndian is Little. michael@0: * As with memcpy, dest and src must not overlap. michael@0: */ michael@0: template michael@0: static void copyAndSwapFromBigEndian(T* dest, const void* src, michael@0: size_t count) { michael@0: copyAndSwapFrom(dest, src, count); michael@0: } michael@0: /* michael@0: * Likewise, but converts values in place. michael@0: */ michael@0: template michael@0: static void swapFromBigEndianInPlace(T* p, size_t count) { michael@0: maybeSwapInPlace(p, count); michael@0: } michael@0: michael@0: /* michael@0: * Synonyms for the big-endian functions, for better readability michael@0: * in network code. michael@0: */ michael@0: template michael@0: MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T value) { michael@0: return swapFromBigEndian(value); michael@0: } michael@0: template michael@0: static void copyAndSwapFromNetworkOrder(T* dest, const void* src, michael@0: size_t count) { michael@0: copyAndSwapFromBigEndian(dest, src, count); michael@0: } michael@0: template michael@0: static void swapFromNetworkOrderInPlace(T* p, size_t count) { michael@0: swapFromBigEndianInPlace(p, count); michael@0: } michael@0: michael@0: private: michael@0: /** michael@0: * Read a value of type T, encoded in endianness ThisEndian from |p|. michael@0: * Return that value encoded in native endianness. michael@0: */ michael@0: template michael@0: static T read(const void* p) { michael@0: union { michael@0: T val; michael@0: uint8_t buffer[sizeof(T)]; michael@0: } u; michael@0: memcpy(u.buffer, p, sizeof(T)); michael@0: return maybeSwap(u.val); michael@0: } michael@0: michael@0: /** michael@0: * Write a value of type T, in native endianness, to |p|, in ThisEndian michael@0: * endianness. michael@0: */ michael@0: template michael@0: static void write(void* p, T value) { michael@0: T tmp = maybeSwap(value); michael@0: memcpy(p, &tmp, sizeof(T)); michael@0: } michael@0: michael@0: Endian() MOZ_DELETE; michael@0: Endian(const Endian& other) MOZ_DELETE; michael@0: void operator=(const Endian& other) MOZ_DELETE; michael@0: }; michael@0: michael@0: template michael@0: class EndianReadWrite : public Endian michael@0: { michael@0: private: michael@0: typedef Endian super; michael@0: michael@0: public: michael@0: using super::readUint16; michael@0: using super::readUint32; michael@0: using super::readUint64; michael@0: using super::readInt16; michael@0: using super::readInt32; michael@0: using super::readInt64; michael@0: using super::writeUint16; michael@0: using super::writeUint32; michael@0: using super::writeUint64; michael@0: using super::writeInt16; michael@0: using super::writeInt32; michael@0: using super::writeInt64; michael@0: }; michael@0: michael@0: } /* namespace detail */ michael@0: michael@0: class LittleEndian MOZ_FINAL : public detail::EndianReadWrite michael@0: {}; michael@0: michael@0: class BigEndian MOZ_FINAL : public detail::EndianReadWrite michael@0: {}; michael@0: michael@0: typedef BigEndian NetworkEndian; michael@0: michael@0: class NativeEndian MOZ_FINAL : public detail::Endian michael@0: { michael@0: private: michael@0: typedef detail::Endian super; michael@0: michael@0: public: michael@0: /* michael@0: * These functions are intended for cases where you have data in your michael@0: * native-endian format and you need the data to appear in the appropriate michael@0: * endianness for transmission, serialization, etc. michael@0: */ michael@0: using super::swapToLittleEndian; michael@0: using super::copyAndSwapToLittleEndian; michael@0: using super::swapToLittleEndianInPlace; michael@0: using super::swapToBigEndian; michael@0: using super::copyAndSwapToBigEndian; michael@0: using super::swapToBigEndianInPlace; michael@0: using super::swapToNetworkOrder; michael@0: using super::copyAndSwapToNetworkOrder; michael@0: using super::swapToNetworkOrderInPlace; michael@0: michael@0: /* michael@0: * These functions are intended for cases where you have data in the michael@0: * given endianness (e.g. reading from disk or a file-format) and you michael@0: * need the data to appear in native-endian format for processing. michael@0: */ michael@0: using super::swapFromLittleEndian; michael@0: using super::copyAndSwapFromLittleEndian; michael@0: using super::swapFromLittleEndianInPlace; michael@0: using super::swapFromBigEndian; michael@0: using super::copyAndSwapFromBigEndian; michael@0: using super::swapFromBigEndianInPlace; michael@0: using super::swapFromNetworkOrder; michael@0: using super::copyAndSwapFromNetworkOrder; michael@0: using super::swapFromNetworkOrderInPlace; michael@0: }; michael@0: michael@0: #undef MOZ_NATIVE_ENDIANNESS michael@0: michael@0: } /* namespace mozilla */ michael@0: michael@0: #endif /* mozilla_Endian_h */