1 /*=========================================================================
2 
3   Program: GDCM (Grassroots DICOM). A DICOM library
4 
5   Copyright (c) 2006-2011 Mathieu Malaterre
6   All rights reserved.
7   See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 #ifndef GDCMBYTESWAP_TXX
15 #define GDCMBYTESWAP_TXX
16 
17 #include "gdcmByteSwap.h"
18 #include <iostream>
19 
20 #include <stdlib.h> // abort
21 
22 namespace gdcm
23 {
24 
25 /*
26   template (class T)
27 {
28 void bswap(inout T i)
29 {
30 byte* p = cast(byte*)&i;
31 for (int b = 0; b < T.size/2; ++b)
32 instance swap(byte).swap(p[b], p[T.size-1-b]);
33 }
34 }
35 */
36 
37 
38 // Machine definitions
39 #ifdef GDCM_WORDS_BIGENDIAN
40 template <class T>
SystemIsBigEndian()41 bool ByteSwap<T>::SystemIsBigEndian() { return true; }
42 template <class T>
SystemIsLittleEndian()43 bool ByteSwap<T>::SystemIsLittleEndian() { return false; }
44 #else
45 template <class T>
46 bool ByteSwap<T>::SystemIsBigEndian() { return false; }
47 template <class T>
48 bool ByteSwap<T>::SystemIsLittleEndian() { return true; }
49 #endif
50 
51 template <class T>
Swap(T & p)52 void ByteSwap<T>::Swap(T &p)
53 {
54 #ifdef GDCM_WORDS_BIGENDIAN
55     ByteSwap<T>::SwapFromSwapCodeIntoSystem(p, SwapCode::LittleEndian);
56 #else
57     ByteSwap<T>::SwapFromSwapCodeIntoSystem(p, SwapCode::BigEndian);
58 #endif
59 }
60 
61 // Swaps the bytes so they agree with the processor order
62 template <class T>
SwapFromSwapCodeIntoSystem(T & a,SwapCode const & swapcode)63 void ByteSwap<T>::SwapFromSwapCodeIntoSystem(T &a, SwapCode const &swapcode)
64 {
65   //std::cerr << "sizeof(T)= " << sizeof(T) << " " << (int)a << std::endl;
66   switch(sizeof(T))
67     {
68   case 1:
69     break;
70   case 2:
71     Swap4(a, swapcode);
72     break;
73   case 4:
74     Swap8(a, swapcode);
75     break;
76   default:
77     std::cerr << "Impossible" << std::endl;
78     abort();
79     }
80 }
81 
82 template <class T>
SwapRange(T * p,unsigned int num)83 void ByteSwap<T>::SwapRange(T *p, unsigned int num)
84 {
85   for(unsigned int i=0; i<num; i++)
86     {
87     ByteSwap<T>::Swap(p[i]);
88     }
89 }
90 
91 template <class T>
SwapRangeFromSwapCodeIntoSystem(T * p,SwapCode const & sc,std::streamoff num)92 void ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem(T *p, SwapCode const &sc,
93   std::streamoff num)
94 {
95   for( std::streamoff i=0; i<num; i++)
96     {
97     ByteSwap<T>::SwapFromSwapCodeIntoSystem(p[i], sc);
98     }
99 }
100 
101 // Private:
102 //
103 
104 template<class T>
Swap4(T & a,SwapCode const & swapcode)105 void Swap4(T &a, SwapCode const &swapcode)
106 {
107 #ifndef GDCM_WORDS_BIGENDIAN
108   if ( swapcode == 4321 || swapcode == 2143 )
109     a = (T)(( a << 8 ) | ( a >> 8 ));
110 #else
111   if ( swapcode == 1234 || swapcode == 3412 )
112     a = ( a << 8 ) | ( a >> 8 );
113   // On big endian as long as the SwapCode is Unknown let's pretend we were
114   // on a LittleEndian system (might introduce overhead on those system).
115   else if ( swapcode == SwapCode::Unknown )
116     a = ( a << 8 ) | ( a >> 8 );
117 #endif
118 }
119 
120 //note: according to http://www.parashift.com/c++-faq-lite/templates.html#faq-35.8
121 //the inlining of the template class means that the specialization doesn't cause linker errors
122 template<class T>
Swap8(T & a,SwapCode const & swapcode)123 inline void Swap8(T &a, SwapCode const &swapcode)
124 {
125   switch (swapcode)
126     {
127   case SwapCode::Unknown:
128 #ifdef GDCM_WORDS_BIGENDIAN
129     a= (( a<<24) | ((a<<8)  & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) );
130 #endif
131     break;
132   case 1234 :
133 #ifdef GDCM_WORDS_BIGENDIAN
134     a= (( a<<24) | ((a<<8)  & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) );
135 #endif
136     break;
137   case 4321 :
138 #ifndef GDCM_WORDS_BIGENDIAN
139     a= (( a<<24) | ((a<<8)  & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) );
140 #endif
141     break;
142   case 3412 :
143     a= ((a<<16) | (a>>16)  );
144     break;
145   case 2143 :
146     a= (((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) );
147     break;
148   default :
149     std::cerr << "Unexpected swap code:" << swapcode;
150     }
151 }
152 
153 template <>
Swap8(uint16_t & a,SwapCode const & swapcode)154 inline void Swap8<uint16_t>(uint16_t &a, SwapCode const &swapcode)
155 {
156   switch (swapcode)
157     {
158   case SwapCode::Unknown:
159 #ifdef GDCM_WORDS_BIGENDIAN
160     a= (( a<<24) | ((a<<8)  & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) );
161 #endif
162     break;
163   case 1234 :
164 #ifdef GDCM_WORDS_BIGENDIAN
165     a= (( a<<24) | ((a<<8)  & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) );
166 #endif
167     break;
168   case 4321 :
169 #ifndef GDCM_WORDS_BIGENDIAN
170 //    probably not really useful since the lowest 0x0000 are what's used in unsigned shorts
171 //    a= (( a<<24) | ((a<<8)  & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) );
172 #endif
173     break;
174   case 3412 :
175     //a= ((a<<16) | (a>>16)  );//do nothing, a = a
176     break;
177   case 2143 :
178     a= (uint16_t)(((a<< 8) & 0xff00) | ((a>>8) & 0x00ff) );
179     break;
180   default :
181     std::cerr << "Unexpected swap code:" << swapcode;
182     }
183 }
184 
185 
186 } // end namespace gdcm
187 
188 #endif // GDCMBYTESWAP_TXX
189