/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ /*========================================================================= * * Portions of this file are subject to the VTK Toolkit Version 3 copyright. * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * * For complete copyright, license and disclaimer of warranty information * please refer to the NOTICE file at the top of the ITK source tree. * *=========================================================================*/ #ifndef itkByteSwapper_hxx #define itkByteSwapper_hxx #include "itkMakeUniqueForOverwrite.h" #include // For swap. #include #include namespace itk { // The following are the public methods -------------------------------- // // Machine definitions #ifdef CMAKE_WORDS_BIGENDIAN template bool ByteSwapper::SystemIsBigEndian() { return true; } template bool ByteSwapper::SystemIsLittleEndian() { return false; } #else template bool ByteSwapper::SystemIsBigEndian() { return false; } template bool ByteSwapper::SystemIsLittleEndian() { return true; } #endif //------Big Endian methods---------------------------------------------- // Use different swap methods based on type #ifdef CMAKE_WORDS_BIGENDIAN template void ByteSwapper::SwapFromSystemToBigEndian(T *) {} #else template void ByteSwapper::SwapFromSystemToBigEndian(T * p) { switch (sizeof(T)) { case 1: return; case 2: Self::Swap2(p); return; case 4: Self::Swap4(p); return; case 8: Self::Swap8(p); return; default: itkGenericExceptionMacro("Cannot swap number of bytes requested"); } } #endif #ifdef CMAKE_WORDS_BIGENDIAN template void ByteSwapper::SwapRangeFromSystemToBigEndian(T *, BufferSizeType) { // nothing needs to be done here... } #else # ifdef __INTEL_COMPILER # pragma warning disable 280 // remark #280: selector expression is constant # endif template void ByteSwapper::SwapRangeFromSystemToBigEndian(T * p, BufferSizeType num) { switch (sizeof(T)) { case 1: return; case 2: Self::Swap2Range(p, num); return; case 4: Self::Swap4Range(p, num); return; case 8: Self::Swap8Range(p, num); return; default: itkGenericExceptionMacro("Cannot swap number of bytes requested"); } } #endif #ifdef CMAKE_WORDS_BIGENDIAN template void ByteSwapper::SwapWriteRangeFromSystemToBigEndian(const T * p, int num, OStreamType * fp) { num *= sizeof(T); fp->write(reinterpret_cast(p), num); } #else template void ByteSwapper::SwapWriteRangeFromSystemToBigEndian(const T * p, int num, OStreamType * fp) { switch (sizeof(T)) { case 1: return; case 2: Self::SwapWrite2Range(p, num, fp); return; case 4: Self::SwapWrite4Range(p, num, fp); return; case 8: Self::SwapWrite8Range(p, num, fp); return; default: itkGenericExceptionMacro("Cannot swap number of bytes requested"); } } #endif //------Little Endian methods---------------------------------------------- #ifdef CMAKE_WORDS_BIGENDIAN template void ByteSwapper::SwapFromSystemToLittleEndian(T * p) { switch (sizeof(T)) { case 1: return; case 2: Self::Swap2(p); return; case 4: Self::Swap4(p); return; case 8: Self::Swap8(p); return; default: itkGenericExceptionMacro("Cannot swap number of bytes requested"); } } #else template void ByteSwapper::SwapFromSystemToLittleEndian(T *) {} #endif #ifdef CMAKE_WORDS_BIGENDIAN template void ByteSwapper::SwapRangeFromSystemToLittleEndian(T * p, BufferSizeType num) { switch (sizeof(T)) { case 1: return; case 2: Self::Swap2Range(p, num); return; case 4: Self::Swap4Range(p, num); return; case 8: Self::Swap8Range(p, num); return; default: itkGenericExceptionMacro("Cannot swap number of bytes requested"); } } #else template void ByteSwapper::SwapRangeFromSystemToLittleEndian(T *, BufferSizeType) {} #endif #ifdef CMAKE_WORDS_BIGENDIAN template void ByteSwapper::SwapWriteRangeFromSystemToLittleEndian(const T * p, int num, OStreamType * fp) { switch (sizeof(T)) { case 1: return; case 2: Self::SwapWrite2Range(p, num, fp); return; case 4: Self::SwapWrite4Range(p, num, fp); return; case 8: Self::SwapWrite8Range(p, num, fp); return; default: itkGenericExceptionMacro("Cannot swap number of bytes requested"); } } #else template void ByteSwapper::SwapWriteRangeFromSystemToLittleEndian(const T * p, int num, OStreamType * fp) { num *= sizeof(T); fp->write(reinterpret_cast(p), num); } #endif // The following are the protected methods ------------------------- // //------2-byte methods---------------------------------------------- // Swap 2 byte word. template void ByteSwapper::Swap2(void * pin) { auto * p = static_cast(pin); std::swap(p[0], p[1]); } // Swap bunch of bytes. Num is the number of two byte words to swap. template void ByteSwapper::Swap2Range(void * ptr, BufferSizeType num) { auto * pos = static_cast(ptr); for (BufferSizeType i = 0; i < num; ++i) { Self::Swap2(pos); pos = pos + 2; } } // Swap bunch of bytes. Num is the number of four byte words to swap. template void ByteSwapper::SwapWrite2Range(const void * ptr, BufferSizeType num, OStreamType * fp) { BufferSizeType chunkSize = 1000000; if (num < chunkSize) { chunkSize = num; } const auto cpy = make_unique_for_overwrite(chunkSize * 2); while (num) { memcpy(cpy.get(), ptr, chunkSize * 2); Self::Swap2Range(cpy.get(), num); fp->write(cpy.get(), static_cast(2 * chunkSize)); ptr = static_cast(ptr) + chunkSize * 2; num -= chunkSize; if (num < chunkSize) { chunkSize = num; } } } //------4-byte methods---------------------------------------------- // Swap four byte word. template void ByteSwapper::Swap4(void * ptr) { auto * p = static_cast(ptr); std::swap(p[0], p[3]); std::swap(p[1], p[2]); } // Swap bunch of bytes. Num is the number of four byte words to swap. template void ByteSwapper::Swap4Range(void * ptr, BufferSizeType num) { auto * pos = static_cast(ptr); for (BufferSizeType i = 0; i < num; ++i) { Self::Swap4(pos); pos = pos + 4; } } // Swap bunch of bytes. Num is the number of four byte words to swap. template void ByteSwapper::SwapWrite4Range(const void * ptr, BufferSizeType num, OStreamType * fp) { BufferSizeType chunkSize = 1000000; if (num < chunkSize) { chunkSize = num; } const auto cpy = make_unique_for_overwrite(chunkSize * 4); while (num) { memcpy(cpy.get(), ptr, chunkSize * 4); Self::Swap4Range(cpy.get(), num); fp->write(cpy.get(), static_cast(4 * chunkSize)); ptr = static_cast(ptr) + chunkSize * 4; num -= chunkSize; if (num < chunkSize) { chunkSize = num; } } } //------8-byte methods---------------------------------------------- // Swap 8 byte double precision template void ByteSwapper::Swap8(void * ptr) { auto * p = static_cast(ptr); std::swap(p[0], p[7]); std::swap(p[1], p[6]); std::swap(p[2], p[5]); std::swap(p[3], p[4]); } // Swap bunch of bytes. Num is the number of eight byte words to swap. template void ByteSwapper::Swap8Range(void * ptr, BufferSizeType num) { auto * pos = static_cast(ptr); for (BufferSizeType i = 0; i < num; ++i) { Self::Swap8(pos); pos = pos + 8; } } // Swap bunch of bytes. Num is the number of four byte words to swap. template void ByteSwapper::SwapWrite8Range(const void * ptr, BufferSizeType num, OStreamType * fp) { BufferSizeType chunkSize = 1000000; if (num < chunkSize) { chunkSize = num; } const auto cpy = make_unique_for_overwrite(chunkSize * 8); while (num) { memcpy(cpy.get(), ptr, chunkSize * 8); Self::Swap8Range(cpy.get(), chunkSize); fp->write(cpy.get(), static_cast(8 * chunkSize)); ptr = static_cast(ptr) + chunkSize * 8; num -= chunkSize; if (num < chunkSize) { chunkSize = num; } } } } // end namespace itk #endif