]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
6899e505b07794f68160c6c6f4b8c995733f406c
[gdcm.git] / src / gdcmHeader.cxx
1 #include "gdcmlib.h"
2 extern "C" {
3 #include "glib.h"
4 }
5 #include <stdio.h>
6 // For nthos:
7 #ifdef _MSC_VER
8 #include <winsock.h>
9 #else
10 #include <netinet/in.h>
11 #endif
12
13 #define LGR_ENTETE_A_LIRE 256 // on ne lit plus que le debut
14 #define DEBUG 1
15
16 //FIXME: this looks dirty to me...
17 #define str2num(str, typeNum) *((typeNum *)(str))
18
19 /**
20  * \ingroup gdcmHeader
21  * \brief   La seule maniere sure que l'on aie pour determiner 
22  *          si on est en   LITTLE_ENDIAN,       BIG-ENDIAN, 
23  *          BAD-LITTLE-ENDIAN, BAD-BIG-ENDIAN
24  *          est de trouver l'element qui donne la longueur d'un 'GROUP'
25  *          (on sait que la longueur de cet element vaut 0x00000004)
26  *          et de regarder comment cette longueur est codee en memoire  
27  *          
28  *          Le probleme vient de ce que parfois, il n'y en a pas ...
29  *          
30  *          On fait alors le pari qu'on a a faire a du LITTLE_ENDIAN propre.
31  *          (Ce qui est la norme -pas respectee- depuis ACR-NEMA)
32  *          Si ce n'est pas le cas, on ne peut rien faire.
33  *
34  *          (il faudrait avoir des fonctions auxquelles 
35  *          on passe le code Swap en parametre, pour faire des essais 'manuels')
36  */
37 void gdcmHeader::CheckSwap()
38 {
39         guint32  s;
40         guint32  x=4;  // x : pour ntohs
41         bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
42          
43         int lgrLue;
44         char * entCur;
45         char deb[LGR_ENTETE_A_LIRE];
46          
47         // On teste le processeur
48         if (x==ntohs(x)) {
49                 net2host = true;
50         } else {
51                 net2host = false;
52         }
53         
54         // On commence par verifier si c'est du DICOM 'actuel'
55         //                                      -------------
56         lgrLue = fread(deb,1,LGR_ENTETE_A_LIRE, fp);
57         
58         entCur = deb+128;
59         if(memcmp(entCur, "DICM", (size_t)4) == 0) {
60                 filetype = TrueDicom;
61                 if (DEBUG) printf ("_IdDcmCheckSwap : C est du DICOM actuel \n");
62         } else {
63                 filetype = Unknown;
64                 if (DEBUG) printf ("_IdDcmCheckSwap : Ce n'est PAS du DICOM actuel\n");
65         }
66
67         if(filetype == TrueDicom) {
68                 // on saute le File Preamble (souvent a ZERO) : 128 Octets
69                 // + le DICM (4), et le (0002, 0000) soit 4 (136 = 128 + 4 + 4)
70                 entCur = deb+136;
71                 if(memcmp(entCur, "UL", (size_t)2) == 0) {
72                         // les 2 premiers octets de la lgr peuvent valoir UL --> Explicit VR
73                         filetype = ExplicitVR;
74                         if (DEBUG)  printf ("_IdDcmCheckSwap : Explicit VR\n");
75                 } else {
76                         filetype = ImplicitVR;
77                         if (DEBUG)  printf ("_IdDcmCheckSwap : PAS Explicit VR\n");
78                 }
79                 
80                 if (net2host) { // HostByteOrder is different from NetworkByteOrder
81                         sw = 0;    // on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire
82                         if (DEBUG) printf("HostByteOrder = NetworkByteOrder\n");
83                 } else {    /* on est sur une Sun ou une SGI */
84                         sw = 4321;
85                         if (DEBUG) printf("HostByteOrder != NetworkByteOrder\n");
86                 }
87                 
88                 rewind(fp);
89                 fseek (fp, 132L, SEEK_SET); //On se positionne sur le debut des info
90                 offsetCourant=132;
91         } // End of TrueDicom
92
93         // Pas du TrueDicom : permiere hypothese c'est de l'ACR 'propre', auquel
94         // cas la lgr du premier element du groupe est FORCEMENT 4
95         entCur=deb + 4;
96         s=str2num(entCur,int);
97         
98         switch (s) {
99         case 0x00040000 :
100                 sw=3412; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
101                 filetype = ACR;
102                 break;
103         case 0x04000000 :
104                 sw=4321; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
105                 filetype = ACR;
106                 break;
107         case 0x00000400 :
108                 sw=2143; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
109                         filetype = ACR;
110                 break;
111         case 0x00000004 :
112                 sw=0;    if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
113                 filetype = ACR;
114                 break;
115         default :
116                 sw = -1;
117                 if (DEBUG) printf (" Pas trouve l info de Swap; On va parier\n");
118         }
119         if(sw!=-1) {
120                 rewind(fp);    // les info commencent au debut
121                 offsetCourant=0;
122                 return;
123         }
124
125         // Deuxieme hypothese : c'est de l'ACR 'pas propre' i.e. il manque
126         // la lgr du groupe
127         
128         // On n'a pas trouve l'info de swap.
129         // Si c'est du VRAI ACR NEMA et
130         //  * si on est sur une DEC ou un PC alors swap=0,
131         //  * si on est sur SUN ou SGI,      alors swap=4321
132         // Si c'est du RAW, ca degagera + tard
133         if (DEBUG) printf("On force la chance \n");
134         
135         if (x!=ntohs(x)) // HostByteOrder is different from NetworkByteOrder
136                 // on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire
137                 sw = 0;
138         else
139                 // on est sur Sun ou SGI
140                 sw = 4321;
141         rewind(fp);    // les info commencent au debut
142         offsetCourant=0;
143         return;
144 }
145
146 /**
147  * \ingroup gdcmHeader
148  * \brief   Pour les fichiers non TrueDicom, si le recognition
149  *          code (0008,0010) s'avere etre "ACR_LIBIDO", alors
150  *          valide la reconnaissance du fichier en positionnant
151  *          filetype.
152  */
153 void gdcmHeader::setAcrLibido() {
154         string RecCode;
155         
156         if ( filetype != TrueDicom) {
157                 printf("_setAcrLibido expects a presumably ACR file\n");
158                 // Recognition Code  --> n'existe plus en DICOM V3 ...
159                 RecCode = GetPubElValByNumber(0x0008, 0x0010);
160                 // FIXME NOW
161                 if (RecCode == "ACRNEMA_LIBIDO" ||
162                     RecCode == "CANRME_AILIBOD" )
163                         filetype = ACR_LIBIDO;
164                 else
165                         filetype = ACR;
166         }
167         return;
168 }
169
170 /**
171  * \ingroup   gdcmHeader
172  * \brief     recupere la longueur d'un champ DICOM.
173  *            Preconditions:
174  *            1/ le fichier doit deja avoir ete ouvert,
175  *            2/ CheckSwap() doit avoir ete appele
176  *            3/ la  partie 'group'  ainsi que la  partie 'elem' 
177  *               de l'acr_element doivent avoir ete lues.
178  *
179  *            ACR-NEMA : we allways get
180  *                 GroupNumber   (2 Octets) 
181  *                 ElementNumber (2 Octets) 
182  *                 ElementSize   (4 Octets)
183  *            DICOM en implicit Value Representation :
184  *                 GroupNumber   (2 Octets) 
185  *                 ElementNumber (2 Octets) 
186  *                 ElementSize   (4 Octets)
187  *
188  *            DICOM en explicit Value Representation :
189  *                 GroupNumber         (2 Octets) 
190  *                 ElementNumber       (2 Octets) 
191  *                 ValueRepresentation (2 Octets) 
192  *                 ElementSize         (2 Octets)
193  *
194  *            ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN
195  *                 GroupNumber         (2 Octets) 
196  *                 ElementNumber       (2 Octets) 
197  *                 ValueRepresentation (2 Octets)
198  *                 zone reservee       (2 Octets) 
199  *                 ElementSize         (4 Octets)
200  *
201  * @param sw  code swap
202  * @param skippedLength  pointeur sur nombre d'octets que l'on a saute qd
203  *                       la lecture est finie
204  * @param longueurLue    pointeur sur longueur (en nombre d'octets) 
205  *                       effectivement lue
206  * @return               longueur retenue pour le champ 
207  */
208
209 // FIXME sw n'est plus un argument necessaire
210 long int gdcmHeader::RecupLgr(
211         _ID_DCM_ELEM *pleCourant, int sw, int *skippedLength, int *longueurLue)
212 {
213         guint32 l_gr; 
214         unsigned short int l_gr_2;
215         int i, trouve;
216         char VR[5];
217         int lgrLue;
218         
219         //  FIX ME
220         //   ATTENTION : nbCode correspond au nombre d'elements dans la table
221         //               de type DICOM_VR. A nettoyer.
222         //
223         int nbCode=26;
224         
225         if (filetype == ExplicitVR) {
226                 lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
227                 VR[2]=0;
228                 
229                 // ATTENTION :
230                 // Ce n'est pas parce qu'on a trouve UL la premiere fois qu'on respecte 
231                 // Explicit VR tout le temps (cf e=film ...)
232                 
233                 for(i=0,trouve=0;i<nbCode;i++) {
234                         if(memcmp(_ID_dicom_vr[i].dicom_VR,VR,(size_t)2)==0) {
235                                 (pleCourant)->VR=_ID_dicom_vr[i].dicom_VR;
236                                 trouve=1;
237                                 break;
238                         }
239                 }
240                 
241                 if ( trouve == 0) {
242                         
243                         // On est mal : implicit VR repere
244                         // mais ce n'est pas un code connu ...
245                         // On reconstitue la longueur
246                         
247                         if(DEBUG)
248                                 printf("IdDcmRecupLgr : Explicit VR, mais pas de code connu\n");
249                         memcpy(&l_gr, VR,(size_t)2);
250                         
251                         lgrLue=fread ( ((char*)&l_gr)+2, (size_t)2, (size_t)1, fp);
252                         
253                         l_gr = SWAP_LONG((guint32)l_gr);
254                         
255                         if(DEBUG)
256                                 printf("IdDcmRecupLgr : lgr deduite : %08x , %d\n",l_gr,l_gr);
257                         
258                         *longueurLue=l_gr;
259                         if ( (int)l_gr == -1)
260                                 l_gr=0;
261                          
262                         *skippedLength = 4; 
263                         if (DEBUG)
264                                 printf(" 1 : lgr %08x (%d )skippedLength %d\n",
265                                        l_gr,l_gr, *skippedLength);
266                         return(l_gr);
267                 }
268                 
269                 // On repart dans la sequence 'sensee'
270                 
271                 if(DEBUG)
272                         printf("VR : [%01x , %01x] (%c%c) en position %d du tableau\n",
273                                 VR[0],VR[1],VR[0],VR[1],i);
274                 
275                 if ( (!memcmp( VR,"OB",(size_t)2 )) || 
276                      (!memcmp( VR,"OW",(size_t)2 )) || 
277                      (!memcmp( VR,"SQ",(size_t)2 )) ||
278                      (!memcmp( VR,"UN",(size_t)2 )) ) {
279                         
280                         // les 2 octets suivants sont reserves: on les saute
281                         if(DEBUG)
282                                 printf("IdDcmRecupLgr : les 2 octets suivants sont reserves\n");
283                         fseek(fp, 2L,SEEK_CUR);
284                         
285                         //on lit la lgr sur QUATRE octets
286                         lgrLue=fread (&l_gr, (size_t)4,(size_t)1, fp);
287                         l_gr = SWAP_LONG((guint32)l_gr);
288                         *skippedLength = 8;
289                 
290                 } else {
291                         //on lit la lgr sur DEUX octets
292                         lgrLue=fread (&l_gr_2, (size_t)2,(size_t)1, fp);
293                         
294                         if(sw) l_gr_2 = _IdDcmSWAP_SHORT((unsigned short)l_gr_2,sw);
295                         
296                         *longueurLue=l_gr_2;
297                         
298                         
299                         if ( l_gr_2 == 0xffff) {
300                                 l_gr = 0;
301                         } else {
302                                 l_gr = l_gr_2;
303                         }
304                         *skippedLength = 4;
305                 }
306         } else {
307                 // Explicit VR = 0
308                 //on lit la lgr sur QUATRE octets
309                 
310                 lgrLue=fread (&l_gr, (size_t)4,(size_t)1, fp);
311                 
312                 l_gr= SWAP_LONG((long)l_gr);
313                 *skippedLength = 4;
314         }
315         
316         *longueurLue=l_gr;
317         
318         // Traitement des curiosites sur la longueur
319         
320         if ( (int)l_gr == 0xffffffff)
321                 l_gr=0; 
322         
323         if(!memcmp( VR,"SQ",(size_t)2 )) { // ca annonce une SEQUENCE d'items ?!
324                 l_gr=0;                         // on lira donc les items de la sequence 
325                 if (DEBUG) printf(" SQ trouve : lgr %d \n",l_gr);
326         }
327         
328         if (DEBUG)
329                 printf(" 2 : lgr %08x (%d) skippedLength %d\n",l_gr,l_gr, *skippedLength);
330         return(l_gr);
331 }
332
333 /**
334  * \ingroup gdcmHeader
335  * \brief   remet les octets dans un ordre compatible avec celui du processeur
336
337  * @return  longueur retenue pour le champ 
338  */
339
340 guint32 gdcmHeader::SWAP_LONG(guint32 a) {
341         // FIXME: il pourrait y avoir un pb pour les entiers negatifs ...
342         switch (sw) {
343         case 4321 :
344                 a=(   ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
345                       ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
346                 break;
347         
348         case 3412 :
349                 a=(   ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
350                 break;
351         
352         case 2143 :
353                 a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
354                 break;
355         default :
356                 printf("\n\n\n *******\n erreur code swap ?!?\n\n\n");
357                 a=0;
358         }
359         return(a);
360 }