/*========================================================================= Program: Visualization Toolkit Module: vtkByteSwap.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkByteSwap.h" #include "vtkEndian.h" #include "vtkObjectFactory.h" #include #include vtkStandardNewMacro(vtkByteSwap); //------------------------------------------------------------------------------ void vtkByteSwap::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ vtkByteSwap::vtkByteSwap() = default; //------------------------------------------------------------------------------ vtkByteSwap::~vtkByteSwap() = default; //------------------------------------------------------------------------------ // Define swap functions for each type size. template struct vtkByteSwapper; template <> struct vtkByteSwapper<1> { static inline void Swap(char*) {} }; template <> struct vtkByteSwapper<2> { static inline void Swap(char* data) { const uint16_t& ref16 = *reinterpret_cast(data); *reinterpret_cast(data) = (ref16 >> 8) | (ref16 << 8); } }; template <> struct vtkByteSwapper<4> { static inline void Swap(char* data) { const uint32_t& ref32 = *reinterpret_cast(data); *reinterpret_cast(data) = (ref32 >> 24) | (ref32 << 24) | ((ref32 & 0x00ff0000) >> 8) | ((ref32 & 0x0000ff00) << 8); } }; template <> struct vtkByteSwapper<8> { static inline void Swap(char* data) { const uint64_t& ref64 = *reinterpret_cast(data); *reinterpret_cast(data) = (ref64 >> 56) | (ref64 << 56) | ((ref64 & 0x00ff000000000000) >> 40) | ((ref64 & 0x000000000000ff00) << 40) | ((ref64 & 0x0000ff0000000000) >> 24) | ((ref64 & 0x0000000000ff0000) << 24) | ((ref64 & 0x000000ff00000000) >> 8) | ((ref64 & 0x00000000ff000000) << 8); } }; //------------------------------------------------------------------------------ // Define range swap functions. template inline void vtkByteSwapRange(T* first, size_t num) { // Swap one value at a time. T* last = first + num; for (T* p = first; p != last; ++p) { vtkByteSwapper::Swap(reinterpret_cast(p)); } } inline bool vtkByteSwapRangeWrite(const char* first, size_t num, FILE* f, int) { // No need to swap segments of 1 byte. size_t status = fwrite(first, sizeof(char), static_cast(num), f); return status == static_cast(num); } inline bool vtkByteSwapRangeWrite(const signed char* first, size_t num, FILE* f, int) { // No need to swap segments of 1 byte. size_t status = fwrite(first, sizeof(signed char), static_cast(num), f); return status == static_cast(num); } inline bool vtkByteSwapRangeWrite(const unsigned char* first, size_t num, FILE* f, int) { // No need to swap segments of 1 byte. size_t status = fwrite(first, sizeof(unsigned char), static_cast(num), f); return status == static_cast(num); } template inline bool vtkByteSwapRangeWrite(const T* first, size_t num, FILE* f, long) { // Swap and write one value at a time. We do not need to do this in // blocks because the file stream is already buffered. const T* last = first + num; bool result = true; for (const T* p = first; p != last && result; ++p) { // Use a union to avoid breaking C++ aliasing rules. union { T value; char data[sizeof(T)]; } temp = { *p }; vtkByteSwapper::Swap(temp.data); size_t status = fwrite(temp.data, sizeof(T), 1, f); result = status == 1; } return result; } inline void vtkByteSwapRangeWrite(const char* first, size_t num, ostream* os, int) { // No need to swap segments of 1 byte. os->write(first, num * static_cast(sizeof(char))); } inline void vtkByteSwapRangeWrite(const signed char* first, size_t num, ostream* os, int) { // No need to swap segments of 1 byte. os->write(reinterpret_cast(first), num * static_cast(sizeof(signed char))); } inline void vtkByteSwapRangeWrite(const unsigned char* first, size_t num, ostream* os, int) { // No need to swap segments of 1 byte. os->write(reinterpret_cast(first), num * static_cast(sizeof(unsigned char))); } template inline void vtkByteSwapRangeWrite(const T* first, size_t num, ostream* os, long) { // Swap and write one value at a time. We do not need to do this in // blocks because the file stream is already buffered. const T* last = first + num; for (const T* p = first; p != last; ++p) { // Use a union to avoid breaking C++ aliasing rules. union { T value; char data[sizeof(T)]; } temp = { *p }; vtkByteSwapper::Swap(temp.data); os->write(temp.data, sizeof(T)); } } //------------------------------------------------------------------------------ // Define swap functions for each endian-ness. #if defined(VTK_WORDS_BIGENDIAN) template inline void vtkByteSwapBE(T*) { } template inline void vtkByteSwapBERange(T*, size_t) { } template inline bool vtkByteSwapBERangeWrite(const T* p, size_t num, FILE* f) { size_t status = fwrite(p, sizeof(T), static_cast(num), f); return status == static_cast(num); } template inline void vtkByteSwapBERangeWrite(const T* p, size_t num, ostream* os) { os->write((char*)p, sizeof(T) * num); } template inline void vtkByteSwapLE(T* p) { vtkByteSwapper::Swap(reinterpret_cast(p)); } template inline void vtkByteSwapLERange(T* p, size_t num) { vtkByteSwapRange(p, num); } template inline bool vtkByteSwapLERangeWrite(const T* p, size_t num, FILE* f) { return vtkByteSwapRangeWrite(p, num, f, 1); } template inline void vtkByteSwapLERangeWrite(const T* p, size_t num, ostream* os) { vtkByteSwapRangeWrite(p, num, os, 1); } #else template inline void vtkByteSwapBE(T* p) { vtkByteSwapper::Swap(reinterpret_cast(p)); } template inline void vtkByteSwapBERange(T* p, size_t num) { vtkByteSwapRange(p, num); } template inline bool vtkByteSwapBERangeWrite(const T* p, size_t num, FILE* f) { return vtkByteSwapRangeWrite(p, num, f, 1); } template inline void vtkByteSwapBERangeWrite(const T* p, size_t num, ostream* os) { vtkByteSwapRangeWrite(p, num, os, 1); } template inline void vtkByteSwapLE(T*) { } template inline void vtkByteSwapLERange(T*, size_t) { } template inline bool vtkByteSwapLERangeWrite(const T* p, size_t num, FILE* f) { size_t status = fwrite(p, sizeof(T), static_cast(num), f); return status == static_cast(num); } template inline void vtkByteSwapLERangeWrite(const T* p, size_t num, ostream* os) { os->write(reinterpret_cast(p), static_cast(sizeof(T)) * num); } #endif //------------------------------------------------------------------------------ #define VTK_BYTE_SWAP_IMPL(T) \ void vtkByteSwap::SwapLE(T* p) { vtkByteSwapLE(p); } \ void vtkByteSwap::SwapBE(T* p) { vtkByteSwapBE(p); } \ void vtkByteSwap::SwapLERange(T* p, size_t num) { vtkByteSwapLERange(p, num); } \ void vtkByteSwap::SwapBERange(T* p, size_t num) { vtkByteSwapBERange(p, num); } \ bool vtkByteSwap::SwapLERangeWrite(const T* p, size_t num, FILE* file) \ { \ return vtkByteSwapLERangeWrite(p, num, file); \ } \ bool vtkByteSwap::SwapBERangeWrite(const T* p, size_t num, FILE* file) \ { \ return vtkByteSwapBERangeWrite(p, num, file); \ } \ void vtkByteSwap::SwapLERangeWrite(const T* p, size_t num, ostream* os) \ { \ vtkByteSwapLERangeWrite(p, num, os); \ } \ void vtkByteSwap::SwapBERangeWrite(const T* p, size_t num, ostream* os) \ { \ vtkByteSwapBERangeWrite(p, num, os); \ } VTK_BYTE_SWAP_IMPL(float) VTK_BYTE_SWAP_IMPL(double) VTK_BYTE_SWAP_IMPL(char) VTK_BYTE_SWAP_IMPL(short) VTK_BYTE_SWAP_IMPL(int) VTK_BYTE_SWAP_IMPL(long) VTK_BYTE_SWAP_IMPL(long long) VTK_BYTE_SWAP_IMPL(signed char) VTK_BYTE_SWAP_IMPL(unsigned char) VTK_BYTE_SWAP_IMPL(unsigned short) VTK_BYTE_SWAP_IMPL(unsigned int) VTK_BYTE_SWAP_IMPL(unsigned long) VTK_BYTE_SWAP_IMPL(unsigned long long) #undef VTK_BYTE_SWAP_IMPL #if VTK_SIZEOF_SHORT == 2 typedef short vtkByteSwapType2; #else #error "..." #endif #if VTK_SIZEOF_INT == 4 typedef int vtkByteSwapType4; #else #error "..." #endif #if VTK_SIZEOF_DOUBLE == 8 typedef double vtkByteSwapType8; #else #error "..." #endif //------------------------------------------------------------------------------ #define VTK_BYTE_SWAP_SIZE(S) \ void vtkByteSwap::Swap##S##LE(void* p) \ { \ vtkByteSwap::SwapLE(static_cast(p)); \ } \ void vtkByteSwap::Swap##S##BE(void* p) \ { \ vtkByteSwap::SwapBE(static_cast(p)); \ } \ void vtkByteSwap::Swap##S##LERange(void* p, size_t n) \ { \ vtkByteSwap::SwapLERange(static_cast(p), n); \ } \ void vtkByteSwap::Swap##S##BERange(void* p, size_t n) \ { \ vtkByteSwap::SwapBERange(static_cast(p), n); \ } \ bool vtkByteSwap::SwapWrite##S##LERange(void const* p, size_t n, FILE* f) \ { \ return vtkByteSwap::SwapLERangeWrite(static_cast(p), n, f); \ } \ bool vtkByteSwap::SwapWrite##S##BERange(void const* p, size_t n, FILE* f) \ { \ return vtkByteSwap::SwapBERangeWrite(static_cast(p), n, f); \ } \ void vtkByteSwap::SwapWrite##S##LERange(void const* p, size_t n, ostream* os) \ { \ vtkByteSwap::SwapLERangeWrite(static_cast(p), n, os); \ } \ void vtkByteSwap::SwapWrite##S##BERange(void const* p, size_t n, ostream* os) \ { \ vtkByteSwap::SwapBERangeWrite(static_cast(p), n, os); \ } VTK_BYTE_SWAP_SIZE(2) VTK_BYTE_SWAP_SIZE(4) VTK_BYTE_SWAP_SIZE(8) #undef VTK_BYTE_SWAP_SIZE //------------------------------------------------------------------------------ // Swaps the bytes of a buffer. Uses an arbitrary word size, but // assumes the word size is divisible by two. void vtkByteSwap::SwapVoidRange(void* buffer, size_t numWords, size_t wordSize) { unsigned char temp, *out, *buf; size_t idx1, idx2, inc, half; half = wordSize / 2; inc = wordSize - 1; buf = static_cast(buffer); for (idx1 = 0; idx1 < numWords; ++idx1) { out = buf + inc; for (idx2 = 0; idx2 < half; ++idx2) { temp = *out; *out = *buf; *buf = temp; ++buf; --out; } buf += half; } }