1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkByteSwap.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkByteSwap.h"
16 #include <memory.h>
17 #include "vtkObjectFactory.h"
18 
19 vtkStandardNewMacro(vtkByteSwap);
20 
21 //----------------------------------------------------------------------------
vtkByteSwap()22 vtkByteSwap::vtkByteSwap()
23 {
24 }
25 
26 //----------------------------------------------------------------------------
~vtkByteSwap()27 vtkByteSwap::~vtkByteSwap()
28 {
29 }
30 
31 //----------------------------------------------------------------------------
32 // Define swap functions for each type size.
33 template <size_t s> struct vtkByteSwapper;
34 VTK_TEMPLATE_SPECIALIZE struct vtkByteSwapper<1>
35 {
SwapvtkByteSwapper36   static inline void Swap(char*) {}
37 };
38 VTK_TEMPLATE_SPECIALIZE struct vtkByteSwapper<2>
39 {
SwapvtkByteSwapper40   static inline void Swap(char* data)
41     {
42     char one_byte;
43     one_byte = data[0]; data[0] = data[1]; data[1] = one_byte;
44     }
45 };
46 VTK_TEMPLATE_SPECIALIZE struct vtkByteSwapper<4>
47 {
SwapvtkByteSwapper48   static inline void Swap(char* data)
49     {
50     char one_byte;
51     one_byte = data[0]; data[0] = data[3]; data[3] = one_byte;
52     one_byte = data[1]; data[1] = data[2]; data[2] = one_byte;
53     }
54 };
55 VTK_TEMPLATE_SPECIALIZE struct vtkByteSwapper<8>
56 {
SwapvtkByteSwapper57   static inline void Swap(char* data)
58     {
59     char one_byte;
60     one_byte = data[0]; data[0] = data[7]; data[7] = one_byte;
61     one_byte = data[1]; data[1] = data[6]; data[6] = one_byte;
62     one_byte = data[2]; data[2] = data[5]; data[5] = one_byte;
63     one_byte = data[3]; data[3] = data[4]; data[4] = one_byte;
64     }
65 };
66 
67 //----------------------------------------------------------------------------
68 // Define range swap functions.
vtkByteSwapRange(T * first,size_t num)69 template <class T> inline void vtkByteSwapRange(T* first, size_t num)
70 {
71   // Swap one value at a time.
72   T* last = first + num;
73   for(T* p=first; p != last; ++p)
74     {
75     vtkByteSwapper<sizeof(T)>::Swap(reinterpret_cast<char*>(p));
76     }
77 }
vtkByteSwapRangeWrite(const char * first,size_t num,FILE * f,int)78 inline bool vtkByteSwapRangeWrite(const char* first, size_t num,
79                                   FILE* f, int)
80 {
81   // No need to swap segments of 1 byte.
82   size_t status=fwrite(first, sizeof(char), static_cast<size_t>(num), f);
83   return status==static_cast<size_t>(num);
84 }
vtkByteSwapRangeWrite(const signed char * first,size_t num,FILE * f,int)85 inline bool vtkByteSwapRangeWrite(const signed char* first, size_t num,
86                                   FILE* f, int)
87 {
88   // No need to swap segments of 1 byte.
89   size_t status=fwrite(first, sizeof(signed char),static_cast<size_t>(num),f);
90   return status==static_cast<size_t>(num);
91 }
vtkByteSwapRangeWrite(const unsigned char * first,size_t num,FILE * f,int)92 inline bool vtkByteSwapRangeWrite(const unsigned char* first, size_t num,
93                                   FILE* f, int)
94 {
95   // No need to swap segments of 1 byte.
96   size_t status=fwrite(first,sizeof(unsigned char),static_cast<size_t>(num),f);
97   return status==static_cast<size_t>(num);
98 }
99 template <class T>
vtkByteSwapRangeWrite(const T * first,size_t num,FILE * f,long)100 inline bool vtkByteSwapRangeWrite(const T* first, size_t num, FILE* f, long)
101 {
102   // Swap and write one value at a time.  We do not need to do this in
103   // blocks because the file stream is already buffered.
104   const T* last = first + num;
105   bool result=true;
106   for(const T* p=first; p != last && result; ++p)
107     {
108     // Use a union to avoid breaking C++ aliasing rules.
109     union { T value; char data[sizeof(T)]; } temp = {*p};
110     vtkByteSwapper<sizeof(T)>::Swap(temp.data);
111     size_t status=fwrite(temp.data, sizeof(T), 1, f);
112     result=status==1;
113     }
114   return result;
115 }
vtkByteSwapRangeWrite(const char * first,size_t num,ostream * os,int)116 inline void vtkByteSwapRangeWrite(const char* first, size_t num,
117                                   ostream* os, int)
118 {
119   // No need to swap segments of 1 byte.
120   os->write(first, num*static_cast<size_t>(sizeof(char)));
121 }
vtkByteSwapRangeWrite(const signed char * first,size_t num,ostream * os,int)122 inline void vtkByteSwapRangeWrite(const signed char* first, size_t num,
123                                   ostream* os, int)
124 {
125   // No need to swap segments of 1 byte.
126   os->write(reinterpret_cast<const char*>(first),
127             num*static_cast<size_t>(sizeof(signed char)));
128 }
vtkByteSwapRangeWrite(const unsigned char * first,size_t num,ostream * os,int)129 inline void vtkByteSwapRangeWrite(const unsigned char* first, size_t num,
130                                   ostream* os, int)
131 {
132   // No need to swap segments of 1 byte.
133   os->write(reinterpret_cast<const char*>(first),
134             num*static_cast<size_t>(sizeof(unsigned char)));
135 }
136 template <class T>
vtkByteSwapRangeWrite(const T * first,size_t num,ostream * os,long)137 inline void vtkByteSwapRangeWrite(const T* first, size_t num,
138                                   ostream* os, long)
139 {
140   // Swap and write one value at a time.  We do not need to do this in
141   // blocks because the file stream is already buffered.
142   const T* last = first + num;
143   for(const T* p=first; p != last; ++p)
144     {
145     // Use a union to avoid breaking C++ aliasing rules.
146     union { T value; char data[sizeof(T)]; } temp = {*p};
147     vtkByteSwapper<sizeof(T)>::Swap(temp.data);
148     os->write(temp.data, sizeof(T));
149     }
150 }
151 
152 //----------------------------------------------------------------------------
153 // Define swap functions for each endian-ness.
154 #if defined(VTK_WORDS_BIGENDIAN)
vtkByteSwapBE(T *)155 template <class T> inline void vtkByteSwapBE(T*) {}
vtkByteSwapBERange(T *,size_t)156 template <class T> inline void vtkByteSwapBERange(T*, size_t) {}
157 template <class T>
vtkByteSwapBERangeWrite(const T * p,size_t num,FILE * f)158 inline bool vtkByteSwapBERangeWrite(const T* p, size_t num, FILE* f)
159 {
160   size_t status=fwrite(p, sizeof(T), static_cast<size_t>(num), f);
161   return status==static_cast<size_t>(num);
162 }
163 template <class T>
vtkByteSwapBERangeWrite(const T * p,size_t num,ostream * os)164 inline void vtkByteSwapBERangeWrite(const T* p, size_t num, ostream* os)
165 {
166   os->write((char*)p, sizeof(T)*num);
167 }
vtkByteSwapLE(T * p)168 template <class T> inline void vtkByteSwapLE(T* p)
169 {
170   vtkByteSwapper<sizeof(T)>::Swap(reinterpret_cast<char*>(p));
171 }
vtkByteSwapLERange(T * p,size_t num)172 template <class T> inline void vtkByteSwapLERange(T* p, size_t num)
173 {
174   vtkByteSwapRange(p, num);
175 }
176 template <class T>
vtkByteSwapLERangeWrite(const T * p,size_t num,FILE * f)177 inline bool vtkByteSwapLERangeWrite(const T* p, size_t num, FILE* f)
178 {
179   return vtkByteSwapRangeWrite(p, num, f, 1);
180 }
181 template <class T>
vtkByteSwapLERangeWrite(const T * p,size_t num,ostream * os)182 inline void vtkByteSwapLERangeWrite(const T* p, size_t num, ostream* os)
183 {
184   vtkByteSwapRangeWrite(p, num, os, 1);
185 }
186 #else
vtkByteSwapBE(T * p)187 template <class T> inline void vtkByteSwapBE(T* p)
188 {
189   vtkByteSwapper<sizeof(T)>::Swap(reinterpret_cast<char*>(p));
190 }
vtkByteSwapBERange(T * p,size_t num)191 template <class T> inline void vtkByteSwapBERange(T* p, size_t num)
192 {
193   vtkByteSwapRange(p, num);
194 }
195 template <class T>
vtkByteSwapBERangeWrite(const T * p,size_t num,FILE * f)196 inline bool vtkByteSwapBERangeWrite(const T* p, size_t num, FILE* f)
197 {
198   return vtkByteSwapRangeWrite(p, num, f, 1);
199 }
200 template <class T>
vtkByteSwapBERangeWrite(const T * p,size_t num,ostream * os)201 inline void vtkByteSwapBERangeWrite(const T* p, size_t num, ostream* os)
202 {
203   vtkByteSwapRangeWrite(p, num, os, 1);
204 }
vtkByteSwapLE(T *)205 template <class T> inline void vtkByteSwapLE(T*) {}
vtkByteSwapLERange(T *,size_t)206 template <class T> inline void vtkByteSwapLERange(T*, size_t) {}
207 template <class T>
vtkByteSwapLERangeWrite(const T * p,size_t num,FILE * f)208 inline bool vtkByteSwapLERangeWrite(const T* p, size_t num, FILE* f)
209 {
210   size_t status=fwrite(p, sizeof(T), static_cast<size_t>(num), f);
211   return status==static_cast<size_t>(num);
212 }
213 template <class T>
vtkByteSwapLERangeWrite(const T * p,size_t num,ostream * os)214 inline void vtkByteSwapLERangeWrite(const T* p, size_t num, ostream* os)
215 {
216   os->write(reinterpret_cast<const char*>(p),
217             static_cast<size_t>(sizeof(T))*num);
218 }
219 #endif
220 
221 //----------------------------------------------------------------------------
222 #define VTK_BYTE_SWAP_IMPL(T)                                             \
223   void vtkByteSwap::SwapLE(T* p) { vtkByteSwapLE(p); }                    \
224   void vtkByteSwap::SwapBE(T* p) { vtkByteSwapBE(p); }                    \
225   void vtkByteSwap::SwapLERange(T* p, size_t num)                         \
226     { vtkByteSwapLERange(p, num); }                                       \
227   void vtkByteSwap::SwapBERange(T* p, size_t num)                         \
228     { vtkByteSwapBERange(p, num); }                                       \
229   bool vtkByteSwap::SwapLERangeWrite(const T* p, size_t num, FILE* file)  \
230     { return vtkByteSwapLERangeWrite(p, num, file); }                     \
231   bool vtkByteSwap::SwapBERangeWrite(const T* p, size_t num, FILE* file)  \
232     { return vtkByteSwapBERangeWrite(p, num, file); }                     \
233   void vtkByteSwap::SwapLERangeWrite(const T* p, size_t num, ostream* os) \
234     { vtkByteSwapLERangeWrite(p, num, os); }                              \
235   void vtkByteSwap::SwapBERangeWrite(const T* p, size_t num, ostream* os) \
236     { vtkByteSwapBERangeWrite(p, num, os); }
237 VTK_BYTE_SWAP_IMPL(float)
238 VTK_BYTE_SWAP_IMPL(double)
239 VTK_BYTE_SWAP_IMPL(char)
240 VTK_BYTE_SWAP_IMPL(short)
241 VTK_BYTE_SWAP_IMPL(int)
242 VTK_BYTE_SWAP_IMPL(long)
243 VTK_BYTE_SWAP_IMPL(signed char)
244 VTK_BYTE_SWAP_IMPL(unsigned char)
245 VTK_BYTE_SWAP_IMPL(unsigned short)
246 VTK_BYTE_SWAP_IMPL(unsigned int)
247 VTK_BYTE_SWAP_IMPL(unsigned long)
248 #if defined(VTK_IMPL_USE_LONG_LONG)
249 VTK_BYTE_SWAP_IMPL(long long)
250 VTK_BYTE_SWAP_IMPL(unsigned long long)
251 #endif
252 #if defined(VTK_IMPL_USE___INT64)
253 VTK_BYTE_SWAP_IMPL(__int64)
254 VTK_BYTE_SWAP_IMPL(unsigned __int64)
255 #endif
256 #undef VTK_BYTE_SWAP_IMPL
257 
258 #if VTK_SIZEOF_SHORT == 2
259 typedef short vtkByteSwapType2;
260 #else
261 # error "..."
262 #endif
263 
264 #if VTK_SIZEOF_INT == 4
265 typedef int vtkByteSwapType4;
266 #else
267 # error "..."
268 #endif
269 
270 #if VTK_SIZEOF_DOUBLE == 8
271 typedef double vtkByteSwapType8;
272 #else
273 # error "..."
274 #endif
275 
276 //----------------------------------------------------------------------------
277 #define VTK_BYTE_SWAP_SIZE(S)                                                   \
278   void vtkByteSwap::Swap##S##LE(void* p)                                        \
279     { vtkByteSwap::SwapLE(static_cast<vtkByteSwapType##S*>(p)); }               \
280   void vtkByteSwap::Swap##S##BE(void* p)                                        \
281     { vtkByteSwap::SwapBE(static_cast<vtkByteSwapType##S*>(p)); }               \
282   void vtkByteSwap::Swap##S##LERange(void* p, size_t n)                         \
283     { vtkByteSwap::SwapLERange(static_cast<vtkByteSwapType##S*>(p), n); }       \
284   void vtkByteSwap::Swap##S##BERange(void* p, size_t n)                         \
285     { vtkByteSwap::SwapBERange(static_cast<vtkByteSwapType##S*>(p), n); }       \
286   bool vtkByteSwap::SwapWrite##S##LERange(void const* p, size_t n, FILE* f)     \
287     { return vtkByteSwap::SwapLERangeWrite(                                     \
288        static_cast<const vtkByteSwapType##S*>(p), n, f); }                      \
289   bool vtkByteSwap::SwapWrite##S##BERange(void const* p, size_t n, FILE* f)     \
290     { return vtkByteSwap::SwapBERangeWrite(                                     \
291         static_cast<const vtkByteSwapType##S*>(p), n, f); }                     \
292   void vtkByteSwap::SwapWrite##S##LERange(void const* p, size_t n, ostream* os) \
293     { vtkByteSwap::SwapLERangeWrite(                                            \
294         static_cast<const vtkByteSwapType##S*>(p), n, os); }                    \
295   void vtkByteSwap::SwapWrite##S##BERange(void const* p, size_t n, ostream* os) \
296     { vtkByteSwap::SwapBERangeWrite(                                            \
297         static_cast<const vtkByteSwapType##S*>(p), n, os); }
298 VTK_BYTE_SWAP_SIZE(2)
299 VTK_BYTE_SWAP_SIZE(4)
300 VTK_BYTE_SWAP_SIZE(8)
301 #undef VTK_BYTE_SWAP_SIZE
302 
303 //----------------------------------------------------------------------------
304 // Swaps the bytes of a buffer.  Uses an arbitrary word size, but
305 // assumes the word size is divisible by two.
SwapVoidRange(void * buffer,size_t numWords,size_t wordSize)306 void vtkByteSwap::SwapVoidRange(void *buffer, size_t numWords, size_t wordSize)
307 {
308   unsigned char temp, *out, *buf;
309   size_t idx1, idx2, inc, half;
310 
311   half = wordSize / 2;
312   inc = wordSize - 1;
313   buf = static_cast<unsigned char *>(buffer);
314 
315   for (idx1 = 0; idx1 < numWords; ++idx1)
316     {
317       out = buf + inc;
318       for (idx2 = 0; idx2 < half; ++idx2)
319         {
320           temp = *out;
321           *out = *buf;
322           *buf = temp;
323           ++buf;
324           --out;
325         }
326       buf += half;
327     }
328 }
329