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: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Endian.h" michael@0: michael@0: #include michael@0: michael@0: using mozilla::BigEndian; michael@0: using mozilla::LittleEndian; michael@0: using mozilla::NativeEndian; michael@0: michael@0: template michael@0: void michael@0: TestSingleSwap(T value, T swappedValue) michael@0: { michael@0: #if MOZ_LITTLE_ENDIAN michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapToBigEndian(value) == swappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapFromBigEndian(value) == swappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapToNetworkOrder(value) == swappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapFromNetworkOrder(value) == swappedValue); michael@0: #else michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapToLittleEndian(value) == swappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapFromLittleEndian(value) == swappedValue); michael@0: #endif michael@0: } michael@0: michael@0: template michael@0: void michael@0: TestSingleNoSwap(T value, T notSwappedValue) michael@0: { michael@0: #if MOZ_LITTLE_ENDIAN michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapToLittleEndian(value) == notSwappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapFromLittleEndian(value) == notSwappedValue); michael@0: #else michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapToBigEndian(value) == notSwappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapFromBigEndian(value) == notSwappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapToNetworkOrder(value) == notSwappedValue); michael@0: MOZ_RELEASE_ASSERT(NativeEndian::swapFromNetworkOrder(value) == notSwappedValue); michael@0: #endif michael@0: } michael@0: michael@0: // Endian.h functions are declared as protected in an base class and michael@0: // then re-exported as public in public derived classes. The michael@0: // standardese around explicit instantiation of templates is not clear michael@0: // in such cases. Provide these wrappers to make things more explicit. michael@0: // For your own enlightenment, you may wish to peruse: michael@0: // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56152 and subsequently michael@0: // http://j.mp/XosS6S . michael@0: #define WRAP_COPYTO(NAME) \ michael@0: template \ michael@0: void \ michael@0: NAME(void* dst, const T* src, size_t count) \ michael@0: { \ michael@0: NativeEndian::NAME(dst, src, count); \ michael@0: } michael@0: michael@0: WRAP_COPYTO(copyAndSwapToLittleEndian) michael@0: WRAP_COPYTO(copyAndSwapToBigEndian) michael@0: WRAP_COPYTO(copyAndSwapToNetworkOrder) michael@0: michael@0: #define WRAP_COPYFROM(NAME) \ michael@0: template \ michael@0: void \ michael@0: NAME(T* dst, const void* src, size_t count) \ michael@0: { \ michael@0: NativeEndian::NAME(dst, src, count); \ michael@0: } michael@0: michael@0: WRAP_COPYFROM(copyAndSwapFromLittleEndian) michael@0: WRAP_COPYFROM(copyAndSwapFromBigEndian) michael@0: WRAP_COPYFROM(copyAndSwapFromNetworkOrder) michael@0: michael@0: #define WRAP_IN_PLACE(NAME) \ michael@0: template \ michael@0: void \ michael@0: NAME(T* p, size_t count) \ michael@0: { \ michael@0: NativeEndian::NAME(p, count); \ michael@0: } michael@0: WRAP_IN_PLACE(swapToLittleEndianInPlace) michael@0: WRAP_IN_PLACE(swapFromLittleEndianInPlace) michael@0: WRAP_IN_PLACE(swapToBigEndianInPlace) michael@0: WRAP_IN_PLACE(swapFromBigEndianInPlace) michael@0: WRAP_IN_PLACE(swapToNetworkOrderInPlace) michael@0: WRAP_IN_PLACE(swapFromNetworkOrderInPlace) michael@0: michael@0: enum SwapExpectation { michael@0: Swap, michael@0: NoSwap michael@0: }; michael@0: michael@0: template michael@0: void michael@0: TestBulkSwapToSub(enum SwapExpectation expectSwap, michael@0: const T (&values)[Count], michael@0: void (*swapperFunc)(void*, const T*, size_t), michael@0: T (*readerFunc)(const void*)) michael@0: { michael@0: const size_t arraySize = 2 * Count; michael@0: const size_t bufferSize = arraySize * sizeof(T); michael@0: static uint8_t buffer[bufferSize]; michael@0: const uint8_t fillValue = 0xa5; michael@0: static uint8_t checkBuffer[bufferSize]; michael@0: michael@0: MOZ_RELEASE_ASSERT(bufferSize > 2 * sizeof(T)); michael@0: michael@0: memset(checkBuffer, fillValue, bufferSize); michael@0: michael@0: for (size_t startPosition = 0; startPosition < sizeof(T); ++startPosition) { michael@0: for (size_t nValues = 0; nValues < Count; ++nValues) { michael@0: memset(buffer, fillValue, bufferSize); michael@0: swapperFunc(buffer + startPosition, values, nValues); michael@0: michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition) == 0); michael@0: size_t valuesEndPosition = startPosition + sizeof(T) * nValues; michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition, michael@0: checkBuffer + valuesEndPosition, michael@0: bufferSize - valuesEndPosition) == 0); michael@0: if (expectSwap == NoSwap) { michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, values, michael@0: nValues * sizeof(T)) == 0); michael@0: } michael@0: for (size_t i = 0; i < nValues; ++i) { michael@0: MOZ_RELEASE_ASSERT(readerFunc(buffer + startPosition + sizeof(T) * i) == michael@0: values[i]); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: template michael@0: void michael@0: TestBulkSwapFromSub(enum SwapExpectation expectSwap, michael@0: const T (&values)[Count], michael@0: void (*swapperFunc)(T*, const void*, size_t), michael@0: T (*readerFunc)(const void*)) michael@0: { michael@0: const size_t arraySize = 2 * Count; michael@0: const size_t bufferSize = arraySize * sizeof(T); michael@0: static T buffer[arraySize]; michael@0: const uint8_t fillValue = 0xa5; michael@0: static T checkBuffer[arraySize]; michael@0: michael@0: memset(checkBuffer, fillValue, bufferSize); michael@0: michael@0: for (size_t startPosition = 0; startPosition < Count; ++startPosition) { michael@0: for (size_t nValues = 0; nValues < (Count - startPosition); ++nValues) { michael@0: memset(buffer, fillValue, bufferSize); michael@0: swapperFunc(buffer + startPosition, values, nValues); michael@0: michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0); michael@0: size_t valuesEndPosition = startPosition + nValues; michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition, michael@0: checkBuffer + valuesEndPosition, michael@0: (arraySize - valuesEndPosition) * sizeof(T)) == 0); michael@0: if (expectSwap == NoSwap) { michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, values, michael@0: nValues * sizeof(T)) == 0); michael@0: } michael@0: for (size_t i = 0; i < nValues; ++i) michael@0: MOZ_RELEASE_ASSERT(readerFunc(buffer + startPosition + i) == values[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: template michael@0: void michael@0: TestBulkInPlaceSub(enum SwapExpectation expectSwap, michael@0: const T (&values)[Count], michael@0: void (*swapperFunc)(T* p, size_t), michael@0: T (*readerFunc)(const void*)) michael@0: { michael@0: const size_t bufferCount = 4 * Count; michael@0: const size_t bufferSize = bufferCount * sizeof(T); michael@0: static T buffer[bufferCount]; michael@0: const T fillValue = 0xa5; michael@0: static T checkBuffer[bufferCount]; michael@0: michael@0: MOZ_RELEASE_ASSERT(bufferSize > 2 * sizeof(T)); michael@0: michael@0: memset(checkBuffer, fillValue, bufferSize); michael@0: michael@0: for (size_t startPosition = 0; startPosition < Count; ++startPosition) { michael@0: for (size_t nValues = 0; nValues < Count; ++nValues) { michael@0: memset(buffer, fillValue, bufferSize); michael@0: memcpy(buffer + startPosition, values, nValues * sizeof(T)); michael@0: swapperFunc(buffer + startPosition, nValues); michael@0: michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0); michael@0: size_t valuesEndPosition = startPosition + nValues; michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition, michael@0: checkBuffer + valuesEndPosition, michael@0: bufferSize - valuesEndPosition * sizeof(T)) == 0); michael@0: if (expectSwap == NoSwap) { michael@0: MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, values, michael@0: nValues * sizeof(T)) == 0); michael@0: } michael@0: for (size_t i = 0; i < nValues; ++i) michael@0: MOZ_RELEASE_ASSERT(readerFunc(buffer + startPosition + i) == values[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: template michael@0: struct Reader michael@0: { michael@0: }; michael@0: michael@0: #define SPECIALIZE_READER(TYPE, READ_FUNC) \ michael@0: template<> \ michael@0: struct Reader \ michael@0: { \ michael@0: static TYPE readLE(const void* p) { return LittleEndian::READ_FUNC(p); } \ michael@0: static TYPE readBE(const void* p) { return BigEndian::READ_FUNC(p); } \ michael@0: }; michael@0: michael@0: SPECIALIZE_READER(uint16_t, readUint16) michael@0: SPECIALIZE_READER(uint32_t, readUint32) michael@0: SPECIALIZE_READER(uint64_t, readUint64) michael@0: SPECIALIZE_READER(int16_t, readInt16) michael@0: SPECIALIZE_READER(int32_t, readInt32) michael@0: SPECIALIZE_READER(int64_t, readInt64) michael@0: michael@0: template michael@0: void michael@0: TestBulkSwap(const T (&bytes)[Count]) michael@0: { michael@0: #if MOZ_LITTLE_ENDIAN michael@0: TestBulkSwapToSub(Swap, bytes, copyAndSwapToBigEndian, Reader::readBE); michael@0: TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromBigEndian, Reader::readBE); michael@0: TestBulkSwapToSub(Swap, bytes, copyAndSwapToNetworkOrder, Reader::readBE); michael@0: TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromNetworkOrder, Reader::readBE); michael@0: #else michael@0: TestBulkSwapToSub(Swap, bytes, copyAndSwapToLittleEndian, Reader::readLE); michael@0: TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromLittleEndian, Reader::readLE); michael@0: #endif michael@0: } michael@0: michael@0: template michael@0: void michael@0: TestBulkNoSwap(const T (&bytes)[Count]) michael@0: { michael@0: #if MOZ_LITTLE_ENDIAN michael@0: TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToLittleEndian, Reader::readLE); michael@0: TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromLittleEndian, Reader::readLE); michael@0: #else michael@0: TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToBigEndian, Reader::readBE); michael@0: TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromBigEndian, Reader::readBE); michael@0: TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToNetworkOrder, Reader::readBE); michael@0: TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromNetworkOrder, Reader::readBE); michael@0: #endif michael@0: } michael@0: michael@0: template michael@0: void michael@0: TestBulkInPlaceSwap(const T (&bytes)[Count]) michael@0: { michael@0: #if MOZ_LITTLE_ENDIAN michael@0: TestBulkInPlaceSub(Swap, bytes, swapToBigEndianInPlace, Reader::readBE); michael@0: TestBulkInPlaceSub(Swap, bytes, swapFromBigEndianInPlace, Reader::readBE); michael@0: TestBulkInPlaceSub(Swap, bytes, swapToNetworkOrderInPlace, Reader::readBE); michael@0: TestBulkInPlaceSub(Swap, bytes, swapFromNetworkOrderInPlace, Reader::readBE); michael@0: #else michael@0: TestBulkInPlaceSub(Swap, bytes, swapToLittleEndianInPlace, Reader::readLE); michael@0: TestBulkInPlaceSub(Swap, bytes, swapFromLittleEndianInPlace, Reader::readLE); michael@0: #endif michael@0: } michael@0: michael@0: template michael@0: void michael@0: TestBulkInPlaceNoSwap(const T (&bytes)[Count]) michael@0: { michael@0: #if MOZ_LITTLE_ENDIAN michael@0: TestBulkInPlaceSub(NoSwap, bytes, swapToLittleEndianInPlace, Reader::readLE); michael@0: TestBulkInPlaceSub(NoSwap, bytes, swapFromLittleEndianInPlace, Reader::readLE); michael@0: #else michael@0: TestBulkInPlaceSub(NoSwap, bytes, swapToBigEndianInPlace, Reader::readBE); michael@0: TestBulkInPlaceSub(NoSwap, bytes, swapFromBigEndianInPlace, Reader::readBE); michael@0: TestBulkInPlaceSub(NoSwap, bytes, swapToNetworkOrderInPlace, Reader::readBE); michael@0: TestBulkInPlaceSub(NoSwap, bytes, swapFromNetworkOrderInPlace, Reader::readBE); michael@0: #endif michael@0: } michael@0: michael@0: int michael@0: main() michael@0: { michael@0: static const uint8_t unsigned_bytes[16] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, michael@0: 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 }; michael@0: static const int8_t signed_bytes[16] = { -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08, michael@0: -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08 }; michael@0: static const uint16_t uint16_values[8] = { 0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708 }; michael@0: static const int16_t int16_values[8] = { int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8), michael@0: int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8) }; michael@0: static const uint32_t uint32_values[4] = { 0x1020304, 0x5060708, 0x1020304, 0x5060708 }; michael@0: static const int32_t int32_values[4] = { int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8), michael@0: int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8) }; michael@0: static const uint64_t uint64_values[2] = { 0x102030405060708, 0x102030405060708 }; michael@0: static const int64_t int64_values[2] = { int64_t(0xf1f2f3f4f5f6f7f8), michael@0: int64_t(0xf1f2f3f4f5f6f7f8) }; michael@0: uint8_t buffer[8]; michael@0: michael@0: MOZ_RELEASE_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201); michael@0: MOZ_RELEASE_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102); michael@0: michael@0: MOZ_RELEASE_ASSERT(LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U); michael@0: MOZ_RELEASE_ASSERT(BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U); michael@0: michael@0: MOZ_RELEASE_ASSERT(LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL); michael@0: MOZ_RELEASE_ASSERT(BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL); michael@0: michael@0: LittleEndian::writeUint16(&buffer[0], 0x201); michael@0: MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0); michael@0: BigEndian::writeUint16(&buffer[0], 0x102); michael@0: MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0); michael@0: michael@0: LittleEndian::writeUint32(&buffer[0], 0x4030201U); michael@0: MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0); michael@0: BigEndian::writeUint32(&buffer[0], 0x1020304U); michael@0: MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0); michael@0: michael@0: LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL); michael@0: MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0); michael@0: BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL); michael@0: MOZ_RELEASE_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0); michael@0: michael@0: MOZ_RELEASE_ASSERT(LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1)); michael@0: MOZ_RELEASE_ASSERT(BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2)); michael@0: michael@0: MOZ_RELEASE_ASSERT(LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1)); michael@0: MOZ_RELEASE_ASSERT(BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4)); michael@0: michael@0: MOZ_RELEASE_ASSERT(LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL)); michael@0: MOZ_RELEASE_ASSERT(BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL)); michael@0: michael@0: LittleEndian::writeInt16(&buffer[0], 0xf2f1); michael@0: MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0); michael@0: BigEndian::writeInt16(&buffer[0], 0xf1f2); michael@0: MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0); michael@0: michael@0: LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1); michael@0: MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0); michael@0: BigEndian::writeInt32(&buffer[0], 0xf1f2f3f4); michael@0: MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0); michael@0: michael@0: LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL); michael@0: MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0); michael@0: BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL); michael@0: MOZ_RELEASE_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0); michael@0: michael@0: TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2)); michael@0: TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4)); michael@0: TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8)); michael@0: michael@0: TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2)); michael@0: TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4)); michael@0: TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8)); michael@0: michael@0: TestSingleNoSwap(uint16_t(0xf2f1), uint16_t(0xf2f1)); michael@0: TestSingleNoSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf4f3f2f1)); michael@0: TestSingleNoSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf8f7f6f5f4f3f2f1)); michael@0: michael@0: TestSingleNoSwap(int16_t(0xf2f1), int16_t(0xf2f1)); michael@0: TestSingleNoSwap(int32_t(0xf4f3f2f1), int32_t(0xf4f3f2f1)); michael@0: TestSingleNoSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf8f7f6f5f4f3f2f1)); michael@0: michael@0: TestBulkSwap(uint16_values); michael@0: TestBulkSwap(int16_values); michael@0: TestBulkSwap(uint32_values); michael@0: TestBulkSwap(int32_values); michael@0: TestBulkSwap(uint64_values); michael@0: TestBulkSwap(int64_values); michael@0: michael@0: TestBulkNoSwap(uint16_values); michael@0: TestBulkNoSwap(int16_values); michael@0: TestBulkNoSwap(uint32_values); michael@0: TestBulkNoSwap(int32_values); michael@0: TestBulkNoSwap(uint64_values); michael@0: TestBulkNoSwap(int64_values); michael@0: michael@0: TestBulkInPlaceSwap(uint16_values); michael@0: TestBulkInPlaceSwap(int16_values); michael@0: TestBulkInPlaceSwap(uint32_values); michael@0: TestBulkInPlaceSwap(int32_values); michael@0: TestBulkInPlaceSwap(uint64_values); michael@0: TestBulkInPlaceSwap(int64_values); michael@0: michael@0: TestBulkInPlaceNoSwap(uint16_values); michael@0: TestBulkInPlaceNoSwap(int16_values); michael@0: TestBulkInPlaceNoSwap(uint32_values); michael@0: TestBulkInPlaceNoSwap(int32_values); michael@0: TestBulkInPlaceNoSwap(uint64_values); michael@0: TestBulkInPlaceNoSwap(int64_values); michael@0: michael@0: return 0; michael@0: }