]> Creatis software - gdcm.git/blob - src/orig/dcmutil.c
Start of dispatching dcmutil.c (see src/orig) to gdcmHeader.cxx.
[gdcm.git] / src / orig / dcmutil.c
1
2 #include <idio.h>
3 #include <iddicom.h>
4 #include <iddcm-restricted.h>
5 #include <iderr.h>
6 //#include <idprint.h>
7 #include <string.h>
8 #include <stdlib.h>
9
10 #include <idliste.h>
11
12 #ifdef _MSC_VER
13 #include <winsock.h>            // Pour ntohs - BigEndianeries -
14 #else
15 #include <netinet/in.h>         // Pour ntohs - BigEndianeries -
16 #endif
17                                                                         
18 #define LGR_ENTETE_A_LIRE 256                           // on ne lit plus que le debut
19  
20 #define DEBUG 0
21
22 static char * var_itoa(void * , int );
23
24 static guint32  _IdDcmRecupLgr(ID_DCM_HDR *, int, int*, int *);
25 static int      _IdDcmCheckSwap(ID_DCM_HDR *);
26 static int      _IdDcmLireEtStockerElement(ID_DCM_HDR *, char **, int,
27                                  int, char *, int);
28 static char **  _IdDcmInquireImageInfoXXX (ID_DCM_HDR *, char **);    
29
30 static void _setAcrLibido(ID_DCM_HDR *);
31
32 // -----------------------------------------------------------------
33
34 /**
35  * \ingroup       dcm
36  * \brief         Alloue un ID_DCM_HDR
37  * @return        Pointeur sur structure Allouée, NULL si échec 
38  */
39         
40 ID_DCM_HDR * IdDcmHdrAlloc () {
41         ID_DCM_HDR *e = (ID_DCM_HDR *) g_malloc0 (sizeof(ID_DCM_HDR));
42         if (!e) return e;
43         
44         e->deb = (char *) g_malloc(LGR_ENTETE_A_LIRE);
45         if (!e->deb) { 
46                 g_free(e);
47                 printf("Echec alloc ID_DCM_HDR\n");
48         }
49         
50         e->plist = IdLstAlloc();
51
52         if (!e->plist) {
53                 g_free(e->deb);
54                 g_free(e);
55                 printf("Echec alloc ID_DCM_HDR->deb\n");
56                 return (ID_DCM_HDR *)NULL;
57         }       
58         return(e);
59 }
60
61 // ------------------------------------------------------------------
62 /**
63  * \ingroup       dcm
64  * \brief         Libere un ID_DCM_HDR
65  * @param e      pointeur sur le ID_DCM_HDR a liberer.
66  * @return        void 
67  */
68
69 void IdDcmHdrFree (ID_DCM_HDR * e) {
70
71         if (e) {
72                 if (e->deb) g_free(e->deb);
73                 if (e->deb) g_free(e->plist); // LIBERER LES ELEMENTS DE LA LISTE AVANT
74                 g_free(e);
75         }
76 }
77
78 /* =======================================================================
79  *      _IdDcmSWAP_SHORT
80  *              remet les octets dans un ordre compatible avec celui du processeur
81  *  ======================================================================= */
82
83 short int _IdDcmSWAP_SHORT(short int a,int sw) {
84         if ( (sw==4321)  || (sw==2143) )  
85                 a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
86         return (a);
87 }
88
89 /* =======================================================================
90  *      _IdDcmSWAP_LONG
91  *              remet les octets dans un ordre compatible avec celui du processeur
92  *  ======================================================================= */
93
94 guint32 _IdDcmSWAP_LONG(guint32 a, int sw) {
95 /*       ATTENTION: il pourrait y avoir un pb pour les entiers negatifs ...
96  *                                                              
97  */
98    switch (sw) {
99         case 4321 :
100                 a=(     ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
101                         ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
102                 break;
103
104         case 3412 :
105                 a=(     ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
106                 break;
107
108         case 2143 :
109                 a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
110                 break;
111         default :
112                 printf("\n\n\n *******\n erreur code swap ?!?\n\n\n");
113                 a=0;
114    }
115   return(a);
116 }
117
118 // -----------------------------------------------------------------------------------
119 /**
120  * \ingroup       dcm
121  * \brief         renvoie un pointeur sur le ID_DCM_HDR correspondant au fichier
122  * @param filename      Nom du fichier ACR / LibIDO / DICOM
123  * @return       le ID_DCM_HDR 
124  */
125  
126 ID_DCM_HDR * IdDcmGetHeader(char *filename) {
127
128 ID_DCM_HDR *e=NULL;
129 _ID_DCM_ELEM * ple;
130
131         e = IdDcmHdrAlloc();
132         if(!e) {
133                 printf("echec alloc HDR \n");
134                 return(NULL);
135         }
136         
137         if((e->fp=fopen(filename,ID_RFILE_BIN))==0) {           // OK
138                 // IdDcmHdrAFree(e);
139                 printf ("echec ouverture  %s\n",filename);
140                 return (NULL);
141         }
142         
143         e->filename = strdup(filename);
144          
145         fseek(e->fp, 0L, SEEK_END);
146         /*
147          * obtains the current value of the file-position    
148          * indicator for the stream pointed to by stream      
149          */
150         e->taille_fich = ftell(e->fp);
151         
152         if(DEBUG) printf("IdDcmGetHeader : lgr fich %f\n",(float)e->taille_fich); // FORMAT IMPRESSION long int ???
153         
154         rewind(e->fp);
155                 
156         e->sw= _IdDcmCheckSwap(e);
157         e->__NumeroGroupePrecedent = 0; // Pour etre sur que le premier sera + grand
158         e->grPixelTrouve = 0;
159         e->PixelsTrouves = 0;
160
161         
162         while ( (ple=_IdDcmReadNextElement(e,e->sw)) ) {
163                 IdLstAddLast(e->plist, ple);
164         }
165         
166         // Positionnement ACR_LIBIDO
167         
168         _setAcrLibido(e);
169                 
170         fclose(e->fp);
171         return (e);
172 }
173
174 static void _setAcrLibido(ID_DCM_HDR *e) {
175
176 _ID_DCM_ELEM * ple;
177 PLIST_ELEMENT plelem;
178 PLIST pl;
179
180         // Positionnement ACR_LIBIDO
181         if(DEBUG) printf("Entree ds _setAcrLibido\n");
182
183         e->ACR_LIBIDO = 0;
184         if ( e->__TrueDicom == 0) {
185                 // Recognition Code  --> n'existe plus en DICOM V3 ...
186                 
187                 pl = e->plist;
188                 plelem = IdLstFirst(pl);
189                 while (plelem) {
190                         ple= IdLstPtrObj(plelem);
191                         if(DEBUG) printf("gr %04x Num %04x\n", ple->Gr, ple->Num);
192                         if(ple->Gr >  0x0008) break;            // On a depasse
193                         if(ple->Gr == 0x0008) {
194                                 if(ple->Num >  0x0010) break;   // On a depasse
195                                 if(ple->Num == 0x0010) {
196                                         if (  (memcmp(ple->valeurElem,"ACRNEMA_LIBIDO",14)==0)
197                                                 // si c'est egal
198                                                 || (memcmp(ple->valeurElem,"CANRME_AILIBOD",14)==0)) {
199                                                 // en cas d'objet ACRLibido fait sr 1 autre machine) 
200                                                 e->ACR_LIBIDO =1;       
201                                         }  // fin if memcmp
202                                         break;          
203                                 } // fin if ple->Num==0x0010
204                         } // fin ple->Gr==0x0008
205                         plelem = IdLstNext(plelem);
206                 } // fin while 
207         } // fin if TrueDicom
208         
209                 if(DEBUG) printf("ACR_LIBIDO = %d\n", e->ACR_LIBIDO);
210         return;
211 }
212 /* ======================================================================= 
213 *       _IdDcmRecupLgr
214 *
215 *       ACR-NEMA :      On a toujours 
216 *                               GroupNumber   (2 Octets) 
217 *                               ElementNumber (2 Octets) 
218 *                               ElementSize   (4 Octets)
219 *
220 *
221 *       DICOM :         On peut avoir (implicit Value Representation)
222 *                               GroupNumber   (2 Octets) 
223 *                               ElementNumber (2 Octets) 
224 *                               ElementSize   (4 Octets)
225 *
226 *                       On peut avoir (explicit Value Representation)
227 *                               GroupNumber         (2 Octets) 
228 *                               ElementNumber       (2 Octets) 
229 *                               ValueRepresentation (2 Octets) 
230 *                               ElementSize         (2 Octets)
231 *
232 *                       ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN
233 *                               GroupNumber         (2 Octets) 
234 *                               ElementNumber       (2 Octets) 
235 *                               ValueRepresentation (2 Octets)
236 *                               zone reservee       (2 Octets) 
237 *                               ElementSize         (4 Octets)
238 *
239 *
240 *   ======================================================================= */
241 /**
242  * \ingroup       dcm
243  * \brief         recupere la longueur d'un champ DICOM.
244  *                      (le fichier doit deja avoir ete ouvert,
245  *                       _IdAcrCheckSwap(ID_DCM_HDR *e) avoir ete appele)
246  *                      et la  partie 'group'  ainsi que la  partie 'elem' 
247  *                      de l'acr_element doivent avoir ete lues.
248  * @param sw                            code swap
249  * @param skippedLength     pointeur sur nombre d'octets que l'on a saute qd la lecture est finie
250  * @param longueurLue       pointeur sur longueur (en nombre d'octets) effectivement lue
251
252  * @return                              longueur retenue pour le champ 
253  */
254
255 static guint32 _IdDcmRecupLgr(ID_DCM_HDR *e, int sw, int *skippedLength, int *longueurLue) {
256 guint32 l_gr; 
257 unsigned short int l_gr_2;
258 int i, trouve;
259 char VR[5];
260 int lgrLue;
261
262 /*
263  *   ATTENTION :
264 */
265
266 int nbCode=26; // nombre d'elements dans la table de type DICOM_VR definie dans dicom.c
267
268 /* ================ */
269
270 // ID_DCM_HDR *e sert uniquement de passe-plat pour  __ExplicitVR
271
272
273 if (e->__ExplicitVR == 1) {
274         lgrLue=fread (&VR, (size_t)2,(size_t)1, e->fp);
275         VR[2]=0;
276
277         // ATTENTION :
278         // Ce n'est pas parce qu'on a trouve UL la premiere fois qu'on respecte 
279         // Explicit VR tout le temps
280         // (cf e=film ...)
281
282         for(i=0,trouve=0;i<nbCode;i++) {
283                 if(memcmp(_ID_dicom_vr[i].dicom_VR,VR,(size_t)2)==0) {
284                         (e->pleCourant)->VR=_ID_dicom_vr[i].dicom_VR;
285                         trouve=1;       
286                         break;
287                 }
288         }
289
290         if ( trouve == 0) {
291
292                 // On est mal : implicit VR repere
293                 // mais ce n'est pas un code connu ...
294                 // On reconstitue la longueur
295                 
296                 if(DEBUG) printf("IdDcmRecupLgr : Explicit VR, mais pas trouve de code connu\n");
297                 memcpy(&l_gr, VR,(size_t)2);
298
299                 lgrLue=fread ( ((char*)&l_gr)+2, (size_t)2, (size_t)1, e->fp);
300
301                 if(sw) l_gr = _IdDcmSWAP_LONG(((guint32)l_gr),sw);
302                 
303                 if(DEBUG) printf("IdDcmRecupLgr : lgr deduite : %08x , %d\n",l_gr,l_gr);
304                 
305                 *longueurLue=l_gr;
306                 if ( (int)l_gr == -1) { 
307                         l_gr=0;
308                 }
309                 *skippedLength = 4; 
310                 if (DEBUG) printf(" 1 : lgr %08x (%d )skippedLength %d\n",l_gr,l_gr, *skippedLength);
311                 return(l_gr);
312         }
313
314         // On repart dans la sequence 'sensee'
315
316         if(DEBUG) printf("VR : [%01x , %01x] (%c%c) en position %d du tableau\n", VR[0],VR[1],VR[0],VR[1],i);
317         //printf(" %d , %s\n", i,_ID_dicom_vr[i].dicom_VR);
318         
319         if (    
320            (!memcmp( VR,"OB",(size_t)2 )) || 
321            (!memcmp( VR,"OW",(size_t)2 )) || 
322            (!memcmp( VR,"SQ",(size_t)2 )) ||
323            (!memcmp( VR,"UN",(size_t)2 )) ) {
324
325         // les 2 octets suivants sont reserves
326
327                 if(DEBUG) printf("IdDcmRecupLgr : les 2 octets suivants sont reserves\n");
328                                         //on les saute          
329                 fseek(e->fp, 2L,SEEK_CUR);
330                 
331                                         //on lit la lgr sur QUATRE octets
332
333                 lgrLue=fread (&l_gr, (size_t)4,(size_t)1, e->fp);
334
335                 if(sw) l_gr = _IdDcmSWAP_LONG(((guint32)l_gr),sw);
336                 *skippedLength = 8;
337
338         } else {
339                                         //on lit la lgr sur DEUX octets
340
341                 lgrLue=fread (&l_gr_2, (size_t)2,(size_t)1, e->fp);
342
343                 if(sw) l_gr_2 = _IdDcmSWAP_SHORT((unsigned short)l_gr_2,sw);
344                 
345                 *longueurLue=l_gr_2;
346
347                 
348                 if ( l_gr_2 == 0xffff) {
349                         l_gr = 0;       
350                 } else {
351                         l_gr = l_gr_2;
352                 }
353                 *skippedLength = 4;
354         }       
355   } else {      // Explicit VR = 0      
356
357                                 //on lit la lgr sur QUATRE octets
358
359         lgrLue=fread (&l_gr, (size_t)4,(size_t)1, e->fp);
360
361         if(sw)l_gr=_IdDcmSWAP_LONG(((long)l_gr),sw);
362         *skippedLength = 4;
363   }
364   
365   *longueurLue=l_gr;
366   
367   // Traitement des curiosites sur la longueur
368   
369   if ( (int)l_gr == 0xffffffff)
370         l_gr=0; 
371         
372   if(!memcmp( VR,"SQ",(size_t)2 )) {    // ca annonce une SEQUENCE d'items ?!
373         l_gr=0;                                                 // on lira donc les items de la sequence 
374         if (DEBUG) printf(" SQ trouve : lgr %d \n",l_gr);
375   }
376         
377 if (DEBUG) printf(" 2 : lgr %08x (%d) skippedLength %d\n",l_gr,l_gr, *skippedLength);
378   return(l_gr);
379 }
380
381 /* =======================================================================
382         _IdDcmReadNextElement
383
384                         lit l'acr_element courant 
385                         le fichier doit deja avoir ete ouvert, 
386                  
387    ======================================================================= */
388
389 /**
390  * \ingroup       dcm
391  * \brief         lit le dicom_element suivant.
392  *                      (le fichier doit deja avoir ete ouvert,
393  *                       _IdAcrCheckSwap(ID_DCM_HDR *e) avoir ete appele)
394  * @param e      ID_DCM_HDR  dans lequel effectuer la recherche.
395  * @param sw            code swap.
396  * @return              En cas de succes, 1 
397  *                      0 en cas d'echec.
398  */
399
400 _ID_DCM_ELEM * _IdDcmReadNextElement(ID_DCM_HDR * e, int sw) {
401 unsigned short g;
402 unsigned short n;
403 guint32 l;
404 long int posFich;
405 int skL;
406 size_t lgrLue;
407 int i;
408 DICOM_ELEMENTS *t;
409 _ID_DCM_ELEM *nouvDcmElem;
410
411         if (DEBUG) printf(" ===> entree ds _IdDcmReadNextElement\n");
412                 
413         if(e->offsetCourant ==  e->taille_fich) { // On a atteint la fin du fichier
414                 if (DEBUG) printf(" On a atteint la fin du fichier\n");
415                 return(NULL);
416         } else {
417                 if (DEBUG) {
418                                 posFich = ftell(e->fp);
419                                 printf("lgrFich %f positionDsFich %f offset courant %f\n", 
420                                                         (float)e->taille_fich,
421                                                         (float)posFich,
422                                                         (float)e->offsetCourant);
423                 }
424         } 
425         
426         nouvDcmElem = (_ID_DCM_ELEM *)g_malloc(sizeof(_ID_DCM_ELEM));
427         if (!nouvDcmElem) {
428                 printf("Echec alloc _ID_DCM_ELEM *nouvDcmElem\n");
429                 return(NULL);
430         }
431         
432         e->pleCourant = nouvDcmElem;
433         
434         // ------------------------- Lecture Num group : g
435
436         lgrLue=fread (&g, (size_t)2,(size_t)1, e->fp);
437         
438         if (feof(e->fp))  {
439                 if (DEBUG) printf("_IdDcmReadNextElement : eof trouve\n");                      
440                 return (NULL);
441         }
442         if (ferror(e->fp)){
443                 if (DEBUG) printf(" IdDcmReadNextElement : echec lecture NumGr\n");
444                 return (NULL);
445         }
446
447         if (DEBUG) printf("_IdDcmReadNextElement : "
448                                         " gr  %04x\n",g );
449                                                 
450         if (sw) g=_IdDcmSWAP_SHORT(((short)g),sw);
451         
452         nouvDcmElem->Gr=g;
453         e->__NumeroGroupePrecedent =g;
454         
455         // ------------------------- Lecture Num Elem : n
456
457         lgrLue=fread (&n, (size_t)2,(size_t)1, e->fp);
458         
459         if (feof(e->fp))  {
460                 if (DEBUG) printf("_IdDcmReadNextElement : eof trouve\n");                      
461                 return (NULL);
462         }
463         if (ferror(e->fp)){
464                 if (DEBUG) printf(" IdDcmReadNextElement : echec lecture NumElem\n");
465                 return (NULL);
466         }
467         
468         if (DEBUG) printf("_IdDcmReadNextElement : "
469                                         " num %04x\n",n );
470
471         if(sw)n=_IdDcmSWAP_SHORT(((short)n),sw);
472         nouvDcmElem->Num=n;
473
474         // ------------------------- Lecture longueur element : l
475                                                                 
476         l = _IdDcmRecupLgr(e, sw, &skL, &nouvDcmElem->LgrLueElem);
477                         
478         if(g==0xfffe) l=0;  // pour sauter les indicateurs de 'SQ'
479
480         nouvDcmElem->LgrElem=l;
481
482         if (DEBUG) if (n!=0) printf("_IdDcmReadNextElement : "
483                                         " gr %04x\tnum %04x\tlong %08x (%d)\n",
484                                         g,n,l,l);                               
485                                         
486         // ------------------------- Lecture Valeur element 
487                 
488         nouvDcmElem->valeurElem = g_malloc(l+1);
489         if(nouvDcmElem->valeurElem) {
490                 nouvDcmElem->valeurElem[l]= 0;
491         } else {        
492                 if (DEBUG) printf(" IdDcmReadNextElement : echec Alloc valeurElem lgr : %d\n",l);
493                 return (NULL);
494         }       
495         
496                 // ------------------------ On n'amene pas en mémoire les Elem 'trop longs'
497                         
498         lgrLue=fread (nouvDcmElem->valeurElem, (size_t)l,(size_t)1, e->fp);     
499         
500         e->offsetCourant +=  2 + 2 + skL; // gr +  num + lgr
501         nouvDcmElem->Offset = e->offsetCourant;
502         e->offsetCourant += l;                                                  // debut elem suivant
503         
504
505         // ------------------------- Doit-on le Swapper ?
506         
507
508         if ((n==0) && sw)  {    // n=0 : lgr du groupe : guint32
509                         *(guint32 *) nouvDcmElem->valeurElem =
510                                         _IdDcmSWAP_LONG  ((*(guint32 *) nouvDcmElem->valeurElem),sw);  
511                         nouvDcmElem->Swap = 1;
512         } else {
513                 if(sw) {
514                         if ( (g/2)*2-g==0) { /* on ne teste pas les groupes impairs */
515
516                                 if ((l==4)||(l==2)) {  /*pour eviter de swapper les chaines 
517                                                                                 de lgr 2 ou 4 */
518                                         if (DEBUG) 
519                                                 printf("Consultation Dictionary DICOM g %04x n %0xx l %d\n",
520                                                                 g,n,l);
521
522                                         for (t=_ID_dicom_elements; t->dicom_group!=0xffff; t++) {
523                                                 if( (t->dicom_group==g) && (t->dicom_elem==n) ) {
524                                                                 nouvDcmElem->VR= t->dicom_type;
525                                                                 break;
526                                                 }
527                                         }
528                                         if (    (strcmp(t->dicom_type,"UL") ==0) 
529                                                  || (strcmp(t->dicom_type,"US") ==0)
530                                                  || (strcmp(t->dicom_type,"SL") ==0) 
531                                                  || (strcmp(t->dicom_type,"SS") ==0) 
532                                                  || (g == 0x0028 && 
533                                                    ( n == 0x0005 || n == 0x0200) )      ) { // seuls (28,5) de vr RET
534                                                                                                                                 //  et (28,200) sont des entiers
535                                                                                                                                 // ... jusqu'a preuve du contraire
536                                                 nouvDcmElem->Swap = 1;
537
538                                                 if(l==4) { 
539                                                         *(guint32 *) nouvDcmElem->valeurElem=
540                                                                 _IdDcmSWAP_LONG  ((*(guint32 *) nouvDcmElem->valeurElem),sw); 
541                                                         nouvDcmElem->valInt =
542                                                                 _IdDcmSWAP_LONG  ((*(guint32 *) nouvDcmElem->valeurElem),sw);           
543                                                 } else {
544                                                         if(l==2) 
545                                                     *(unsigned short *)   nouvDcmElem->valeurElem=
546                                                         _IdDcmSWAP_SHORT ((*(unsigned short *)nouvDcmElem->valeurElem),sw);
547                                                         nouvDcmElem->valShort =
548                                                         _IdDcmSWAP_SHORT ((*(unsigned short *)nouvDcmElem->valeurElem),sw);
549                                                  }
550                                         }
551                                 } /* fin if l==2 ==4 */
552                         } /* fin if g pair */
553                 } /* fin sw */  
554         }
555         
556         
557         // ------------------------- A-t-on trouve l'info donnant le 'num groupe' des Pixels ?
558         
559                                                                 
560         if (!e->grPixelTrouve) {                        // on n a pas encore trouve les pixels
561                 if (g > 0x0028) {
562                                 if (n > 0x0200 || g == 0x7FE0 ) {  // on a depasse (28,200)
563                                         e->grPixel  = 0x7FE0;
564                                         e->numPixel = 0x0010;
565                                         e->grPixelTrouve = 1;
566                                         if (DEBUG) printf("------------------------grPixel %04x numPixel %04x\n",
567                                                                                 e->grPixel,e->numPixel);
568                                 }
569                                                 
570                 } else {                                        // on est sur (28,200)
571                         if (g == 0x0028) {
572                                 if (n == 0x0200) {
573                                         e->grPixelTrouve = 1;
574                                         for(i=0;i<4;i++)
575                                                 *((char*)(&e->grPixel)+i) = *(nouvDcmElem->valeurElem+i); 
576                                         
577                                         
578                                         if (DEBUG) printf("------------------------GrPixel %04x\n",
579                                                                                 e->grPixel);
580                                         
581                                         if (e->grPixel != 0x7FE0)               // Vieux pb Philips
582                                                 e->numPixel = 0x1010;           // encore utile ??
583                                         else
584                                                 e->numPixel = 0x0010;
585                                                 if (DEBUG) printf("------------------------grPixel %04x numPixel %04x\n",
586                                                                                         e->grPixel,e->numPixel);
587                                 }
588                         }       
589                 }       
590         } else {                                        // on vient de trouver les pixels
591                 if (g == e->grPixel) {
592                         if (n == e->numPixel) {
593                                 e->PixelPosition = nouvDcmElem->Offset; 
594                                 e->PixelsTrouves = 1;
595                         if (DEBUG) printf(" \t===> Pixels Trouves\n");                                  
596                         }       
597                 }
598         }
599                 
600         e->nbElem ++;
601         //printf("nb Elem %d\n",e->nbElem);
602         return(nouvDcmElem);
603 }
604  
605
606 /* =======================================================================
607
608         _IdDcmCheckSwap
609                 La seule maniere sure que l'on aie pour determiner 
610                 si on est en    LITTLE_ENDIAN,     BIG-ENDIAN, 
611                                                 BAD-LITTLE-ENDIAN, BAD-BIG-ENDIAN
612                 est de trouver l'element qui donne la longueur d'un 'GROUP'
613                 (on sait que la longueur de cet element vaut 0x00000004)
614                 et de regarder comment cette longueur est codee en memoire  
615
616                 Le probleme vient de ce que parfois, il n'y en a pas ...
617
618                 On fait alors le pari qu'on a a faire a du LITTLE_ENDIAN propre.
619                 (Ce qui est la norme -pas respectee- depuis ACR-NEMA)
620                 Si ce n'est pas le cas, on ne peut rien faire.
621
622                 (il faudrait avoir des fonctions auxquelles 
623                  on passe le code Swap en parametre, pour faire des essais 'manuels')
624
625    ======================================================================= */
626
627 static int
628 _IdDcmCheckSwap(ID_DCM_HDR * e) {
629 guint32  s, x=4;  // x : pour ntohs
630
631 int sw;
632 int lgrLue;
633 char * entCur;
634 char deb[LGR_ENTETE_A_LIRE];
635
636
637 // On teste le processeur
638
639         if (x==ntohs(x)) {      /* si le HostByteOrder est le meme que le NetworkByteOrder  */ 
640                 e->net2host = 1;
641         } else {
642                 e->net2host = 0;
643         }
644         
645         //printf("\t\t\t\te->net2host %d \n",e->net2host);
646         
647 /* On commence par verifier si c'est du DICOM 'actuel' */
648 /*                                      -------------  */
649
650         lgrLue = fread(deb,1,LGR_ENTETE_A_LIRE,e->fp);
651
652         entCur = deb+128;
653         if(memcmp(entCur, "DICM", (size_t)4) == 0) {
654                 e->__TrueDicom=1;
655                 if (DEBUG) printf ("_IdDcmCheckSwap : C est du DICOM actuel \n");
656         } else {
657                 e->__TrueDicom=0;
658                 if (DEBUG) printf ("_IdDcmCheckSwap : Ce n'est PAS du DICOM actuel\n"); 
659         }
660
661         if(e->__TrueDicom) {
662                 entCur = deb+136;       /* on saute le File Preamble (souvent a ZERO) : 128 Octets */
663                                                         /* le DICM, et le 0002, 0000                                */
664                 if(memcmp(entCur, "UL", (size_t)2) == 0) {
665                         /* les 2 premiers octets de la lgr peuvent valoir UL --> Explicit VR */
666                         e->__ExplicitVR = 1;
667                         if (DEBUG)      printf ("_IdDcmCheckSwap : Explicit VR\n");
668                         } else {
669                                 e->__ExplicitVR = 0;
670                         if (DEBUG)      printf ("_IdDcmCheckSwap : PAS Explicit VR\n");
671                         }
672
673                 if (e->net2host == 0) { /* si le HostByteOrder est different du NetworkByteOrder  */ 
674                         sw = 0;                 /* on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire */
675                         if (DEBUG) printf("HostByteOrder = NetworkByteOrder\n");
676         
677                 } else {                /* on est sur une Sun ou une SGI        */
678                         sw = 4321;
679                         if (DEBUG) printf("HostByteOrder != NetworkByteOrder\n");
680                 }
681                  
682                 rewind(e->fp);
683                 fseek (e->fp, 132L, SEEK_SET); //On se positionne sur le debut des info
684                 e->offsetCourant=132;
685                 return sw;
686
687         } /* fin TrueDicom */
688         
689 /* -----  SINON ----- */
690         
691 /* Si c'est de l'ACR 'propre', la lgr du premier element du groupe est FORCEMENT 4 */
692
693         entCur=deb + 4;
694         s=str2num(entCur,int);
695                  
696         switch (s) {
697                 case 0x00040000 :
698                         sw=3412; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
699                         break;
700                 case 0x04000000 :
701                         sw=4321; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
702                         break;
703                 case 0x00000400 :
704                         sw=2143; if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
705                         break;
706                 case 0x00000004 :
707                         sw=0;    if(DEBUG) printf("s : %08x sw : %d\n",s,sw);
708                         break;
709                 default :
710                         sw = -1;
711                         if (DEBUG) printf (" Pas trouve l info de Swap; On va parier\n");
712         }
713                 
714 /* Si c'est de l'ACR 'pas propre', il manque la lgr du groupe           */
715                                 
716         if(sw==-1) {                                            
717                 /* On n'a pas trouve l'info de swap     28/11/2000 JPR                                          */
718                 /* Si c'est du VRAI ACR NEMA  si on est sur une DEC ou un PC swap=0, SUN ou SGI SWAP=4321       */
719                 /* si c'est du RAW, ca degagera + tard                                                          */
720           
721                 if (DEBUG) printf("On force la chance \n");
722
723                 if (x!=ntohs(x))        /* si le HostByteOrder est different du NetworkByteOrder  */ 
724                         sw = 0;                 /* on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire */
725                 else
726                         sw = 4321; /* on est sur Sun ou SGI */          
727
728         }
729         rewind(e->fp);          // les info commencent au debut
730         e->offsetCourant=0;
731         return (sw);
732 }
733
734
735 //
736 /* ================================================================== */
737 //
738
739 /**
740  * \ingroup       dcm
741  * \brief       renvoie dans un tableau de chaines de caracteres
742                 la description des info pertinentes d'une image ACR /DCM
743                 (la soixantaine de champs utiles)
744                 a partir du nom du fichier
745  * 
746  * @param filename      Nom du fichier.
747  * @return              ID_DCM_HDR
748  * 
749  * 
750  * Pour avoir la liste a jour des elements renvoyes dans ce tableau,
751  * Consulter src/idacr.h et src/dicom.c
752  * 
753 */
754 /* Pour rajouter une entree ici,
755
756         penser a modifier le fichier dicom.c
757         penser a modifier la fonction idacr.h
758
759         pour maintenir la coherence.
760 */
761
762 char **
763 IdDcmInquireImageInfoFromFile(char *filename) {
764
765         ID_DCM_HDR *e;
766         char **imageInfo;
767
768         e = IdDcmGetHeader(filename);
769
770         if (!e) {
771                 printf("fichier %s : gros problème :\n", filename);
772                 IdErrno = IDERR_NON_ACR_FILE;
773                 return (0);
774         }
775
776         imageInfo = _IdDcmInquireImageInfoXXX(e, NULL);
777         
778         // LIBERER LE HEADER
779
780         return (imageInfo);
781 }
782
783
784 //
785 /* ================================================================== */
786 //
787
788 /**
789  * \ingroup       dcm
790  * \brief       renvoie dans un tableau de chaines de caracteres
791  *              la description des info pertinentes d'une image ACR /DCM
792  *              a partir d'un ID_DCM_HDR deja fabrique  
793  *
794  * @param e     ID_DCM_HDR de l'image
795  * @return      Tableau :
796  *
797  * Pour avoir la liste a jour des elements renvoyes dans ce tableau,
798  * Consulter src/idacr.h et src/dicom.c
799  * 
800 */
801
802
803 /* Pour rajouter une entree ici,
804
805         penser a modifier le fichier dicom.c
806         penser a modifier la fonction idacr.h
807
808         pour maintenir la coherence.
809 */
810
811 char **
812 IdDcmInquireImageInfoFromDcmHdr(ID_DCM_HDR *e)
813 {
814         char **imageInfo;
815
816         if (!e) {
817                 printf("ID_DCM_HDR pas alloue\n");
818                 IdErrno = IDERR_NON_ACR_FILE;
819                 return (0);
820         }
821
822         imageInfo = _IdDcmInquireImageInfoXXX(e, NULL);
823
824         return (imageInfo);
825 }
826
827 /* ----------------------------------------------------------------------- */
828
829 static char **
830 _IdDcmInquireImageInfoXXX(ID_DCM_HDR *e, char **imageInfo)
831 {
832
833 int boolTrouveQqChose=0,trouv,k;
834
835 DICOM_INFO *t;
836 t = _ID_dicom_info;
837         
838         if (!imageInfo)
839                 imageInfo =
840                     (char **) g_malloc0((_ID_Number_of_Items + 1) *
841                                         sizeof(char *));
842
843         for(k=0;k<_ID_Number_of_Items;k++) {
844                 trouv=_IdDcmLireEtStockerElement(e, imageInfo,t[k].dicom_group, t[k].dicom_elem,
845                                    t[k].dicom_info_libelle, t[k].dicom_info_ind);
846                 if(trouv) boolTrouveQqChose=1;
847         }
848
849         if(boolTrouveQqChose)
850                 return (imageInfo);
851         else
852                 return(0);
853 }
854
855 /* -----------------------------------------------------------------------
856 *       ID_DCM_HDR *e :                  doit avoir ete cree   dans l'appelant
857 *        char **TableauImageInfo : doit avoir ete alloue dans l'appelant; 
858 *                                ses elements sont alloues dans la fonction
859 *       int numGroupe :          gr et el du Tag DICOM
860 *       int numElem
861 *       char *nomElem :          libelle imprime si element pas trouve
862 *       int position :           indice dans TableauImageInfo
863   -----------------------------------------------------------------------*/
864 static int 
865 _IdDcmLireEtStockerElement(ID_DCM_HDR *e, char **TableauImageInfo, int numGroupe,
866                         int numElem, char *nomElem, int position) {
867         int z;
868         char *chaine;
869
870         /*
871          * Lecture Element 
872          */
873          //if (!( chaine = _IdDcmReadElement(numGroupe, numElem, e) )) {
874         if (!( chaine = _IdDcmReadElementNoSQ(numGroupe, numElem, e) )) {
875
876                 if (DEBUG)
877                         printf
878                             ("%d : _IdDcmLireEtStockerElement : "
879                              "%s (%04x,%04x) pas trouve \n",
880                              position, nomElem, numGroupe, numElem);
881
882                 return (0);
883         } else {
884                 if (DEBUG)
885                         printf
886                             ("%d : _IdDcmLireEtStockerElement : "
887                              "%s (%04x,%04x) \t[%s] \n",
888                              position, nomElem, numGroupe, numElem,chaine);
889
890                 z = strlen(chaine);
891                 while (chaine[z] == ' ') {
892                         chaine[z] = 0;
893                         z--;
894                 }
895
896                 TableauImageInfo[position] =
897                     (char *) g_malloc(1 + strlen(chaine));
898                 strcpy(TableauImageInfo[position], chaine);
899                 if (DEBUG)
900                         printf
901                             ("%d : %s (_IdDcmLireEtStockerElement : "
902                              "%04x,%04x)\t[%s]\n",
903                              position, nomElem, numGroupe, numElem,
904                              chaine);
905
906                 return (1);
907         }
908 }
909
910 // Converts an integer represented with num_byte bytes within the
911 // buffer buff to a string.
912 // Refer to comp.lang.faq FAQ, question 12.21 : How can I tell how much
913 // destination buffer space I'll need for an arbitrary sprintf call? How can
914 // I avoid overflowing the destination buffer with sprintf? 
915
916 static char * var_itoa(void * buff, int num_byte)
917 {
918         char * retbuf;
919
920         // We double the recommended value since we also have to deal
921         // with long integers. Pfff...
922         retbuf = g_malloc(2 * ( (sizeof(int) * CHAR_BIT + 2) / 3 + 1 + 1));
923         switch (num_byte) {
924         case 2:
925                 sprintf(retbuf, "%d",  *((int*)buff));
926                 break;
927         case 4:
928                 sprintf(retbuf, "%dl", *((int*)buff));
929                 break;
930         default:
931                 sprintf(retbuf, "var_itoa?????");
932         }
933         return retbuf;
934 }
935
936
937 /* =======================================================================
938         int _IdStrGetDicomTag(char * label, int *gr, int * num, char *vr)
939
940                      recherche le Dicom tag d'un libelle donne
941                         par inspection du Dictionnaire DICOM
942                           (retourne 0 si pas trouve)                        
943    ======================================================================= */
944    
945
946
947 static int _IdStrGetDcmTag (char* libelle, unsigned long *gr, unsigned long *num, char **vr) {
948
949 DICOM_ELEMENTS *t;
950 int i;
951
952 t=_ID_dicom_elements;
953
954 for (i=0; t[i].dicom_group != 0xffff; i++) {
955         if( strcmp(t[i].dicom_libelle, libelle) ==0 )
956
957          {
958                 *gr= t[i].dicom_group;
959                 *num=t[i].dicom_elem;
960                  *vr =t[i].dicom_type;
961                 return(1);
962         }
963 }
964 return(0);
965
966 }
967
968
969 /**
970  * \ingroup       dcm
971  * \brief         Tente de lire un dicom_element a partir de son libelle. Le
972  *                resultat est range dans buff.
973  * @param libelle Libelle de l'acr_element a lire. Il s'agit du dernier
974  *                champ de la variable globale _ID_dicom_elements, tel que
975  *                "Group Length", "Priority" ou encore "AE Title".
976  * @param e      ID_DCM_HDR dans lequel effectuer la recherche.
977  * @param vr      DICOM_VR (cf la variable globale _ID_dicom_vr) retourne',
978  *                pour permettre a l'appelant d'interpreter le contenu de buff.
979  * @param buff    Ou placer l'acr_element en cas de succes. Si NULL, 
980  *                l'allocation est faite localement.
981  * @return        En cas de succes, le contenu de l'acr_element lu. Null
982  *                en cas d'echec.
983  */
984  
985  
986 char *
987 _IdDcmReadElementFromLabel(char *libelle, ID_DCM_HDR *e, char * vr, void *buff) { 
988         
989         int i;
990         unsigned long gr;
991         unsigned long num;
992         char * caster;
993         
994         i = _IdStrGetDcmTag (libelle, &gr, &num, &vr);
995         
996         if (i == 0) {
997                 if (DEBUG) printf("champ [%s] pas trouve\n",libelle);
998                 caster = g_malloc(4);
999                 sprintf(caster, "???");
1000                 return (caster);
1001                 //return (NULL);
1002         }
1003         buff = _IdDcmReadElement(gr, num, e);
1004         if (buff == 0) {
1005                 caster = g_malloc(4);
1006                 sprintf(caster, "???");
1007                 return (caster);
1008         }
1009         if ( (strcmp(vr,"UL") != 0)
1010           && (strcmp(vr,"US") != 0)
1011           && (strcmp(vr,"SL") != 0)
1012           && (strcmp(vr,"SS") != 0)
1013           && (gr != 0x0028 || 
1014                 ( num != 0x0005 && num != 0x0200) ) ) { 
1015                                                                 // les champs de vr RET sont des caract
1016                                                         // sauf (28,5) et (28,200) Pixel Location
1017                 return((void *) strdup(buff));
1018         }
1019         if ( (strcmp(vr, "US") == 0)
1020           || (strcmp(vr, "SS") == 0)
1021           || (gr == 0x0028 && 
1022                 (num == 0x0005  || num == 0x0200) )     ) {     // les champs de vr RET sont des caract
1023                                                                                         // sauf (28,5) et (28,200) Pixel Location
1024                 // Buff should contain an int16
1025                 caster = var_itoa(buff, 2);
1026                 return(caster);
1027         }
1028         if ( (strcmp(vr,"UL") == 0)
1029           || (strcmp(vr,"SL") == 0) ) {
1030                 // Buff should contain a guint32
1031                 caster = var_itoa(buff, 2);
1032                 return(caster);
1033         }
1034         if (DEBUG) printf("impossible de passer ici, mais le compilo rale\n");
1035         return (NULL);
1036
1037 }
1038
1039
1040 //
1041 /* ============================================================================= */
1042 //
1043
1044
1045
1046 /* ----------------------------------------------------------------------- */
1047 static void 
1048 _IdImprimerElement(char **TableauImageInfo, int numGroupe,
1049                        int numElem, char *nomElem, int position)
1050 {
1051         if (!TableauImageInfo[position])
1052                 printf("%d : %s \t(%04x,%04x)  pas trouve \n", position,
1053                          nomElem, numGroupe, numElem);
1054         else
1055                 printf("%d : %s \t(%04x,%04x)\t[%s]\n", position,
1056                          nomElem, numGroupe, numElem,
1057                          TableauImageInfo[position]);
1058 }
1059
1060 /* ----------------------------------------------------------------------- */
1061
1062 /**
1063 * \ingroup       dcm
1064 * \brief        imprime la description des info 'pertinentes' d'une image DICOM
1065 *               obtenue par IdDcmInquireImageInfoFromXXX (File/DcmHdr)
1066 *
1067 * @param TableauImageInfo       Tableau des info.
1068
1069 * Pour avoir la liste a jour des DICOM Elements renvoyes par IdDcmInquireImageInfo
1070 * Consultez le fichier src/dicom.c
1071 *
1072 * @return               1 : OK
1073 *                       0 : pointeur sur Tableau NULL
1074 */
1075
1076 int
1077 IdDcmPrintImageInfo(char **TableauImageInfo) {
1078
1079 int k;
1080 DICOM_INFO *t;
1081 t = _ID_dicom_info;
1082
1083         if (!TableauImageInfo) return(0);
1084
1085         for(k=0;k<_ID_Number_of_Items;k++) {
1086                 _IdImprimerElement(TableauImageInfo, t[k].dicom_group, 
1087                                                 t[k].dicom_elem, 
1088                                                 t[k].dicom_info_libelle, 
1089                                                 t[k].dicom_info_ind);
1090         }
1091         return (1);
1092 }
1093
1094
1095
1096 /* ----------------------------------------------------------------------- */
1097
1098
1099 void IdDcmAffDcmHdr(ID_DCM_HDR *e, int npriv, int noffset) {
1100
1101
1102 DICOM_ELEMENTS *t = NULL;
1103 PLIST pl;
1104 PLIST_ELEMENT plelem; 
1105 _ID_DCM_ELEM *ple;
1106
1107         /* MANQUE le retrait, avant impression en %s, des caract non ASCII */
1108         
1109         pl=e->plist;
1110         plelem = IdLstFirst(pl);
1111
1112         while (plelem) {
1113         
1114                 ple= IdLstPtrObj(plelem);       // le _ID_DCM_ELEM  pointé par le PLIST_ELEMENT
1115
1116                 if (ple->Num==0) { 
1117                         if(!npriv) printf("\n"); 
1118                  } else { 
1119                         for (t=_ID_dicom_elements; t->dicom_group!=0xffff; t++) {
1120                                 if( (t->dicom_group==ple->Gr) && (t->dicom_elem==ple->Num) ) break;
1121                         }
1122                 }
1123                 if(!(ple->Gr%2) || !npriv) {
1124
1125                         if (noffset) 
1126                                 printf(" gr %04x  num %04x  long %d",
1127                                          ple->Gr, ple->Num, ple->LgrLueElem);
1128                         else
1129                                 printf(" gr %04x  num %04x  long %d  _offset %d",
1130                                         ple->Gr, ple->Num, ple->LgrLueElem, ple->Offset);
1131                 }
1132
1133                 if (ple->Num!=0) { 
1134                 
1135                         if(ple->VR == NULL) {
1136                                 if(!(ple->Gr%2) || !npriv) printf("\t%s\t%s\t\t",  
1137                                                         t->dicom_type, t->dicom_libelle);
1138                                 } else {
1139                                 if(!(ple->Gr%2) || !npriv) printf("\t%s\t%s\t\t",  
1140                                                         ple->VR, t->dicom_libelle);                             
1141                                 }
1142                 } 
1143                 
1144                 if (ple->Num==0) {      
1145                         if(!(ple->Gr%2) || !npriv){
1146                                         printf("   lgr du grp = %d\n   -------\n",
1147                                                 str2num(ple->valeurElem,int) );
1148                         }
1149                 } else {        
1150                         switch (ple->LgrElem) { 
1151                         
1152                         case 2:                                         // LGR = 2
1153
1154                                 if (     (strcmp(t->dicom_type, "US") == 0)
1155                                           || (strcmp(t->dicom_type, "SS") == 0) 
1156                                           || (t->dicom_group == 0x0028 
1157                                           && 
1158                                                 (       t->dicom_elem == 0x0005  
1159                                                   || t->dicom_elem == 0x0200) ) ) {
1160    
1161                                                 if(!(ple->Gr%2) || !npriv) { 
1162                                                         printf("\t  \t \t %d \tx(%04x)\n",
1163                                                                 str2num(ple->valeurElem,unsigned short int),
1164                                                                 str2num(ple->valeurElem,unsigned short int) );  
1165                                                 }
1166                                 } else {
1167
1168                                         if(!(ple->Gr%2) || !npriv){ 
1169                                                 printf("\t[%s]  \t %d \tx(%04x)\n", 
1170                                                         ple->valeurElem,
1171                                                         str2num(ple->valeurElem,unsigned short int), 
1172                                                         str2num(ple->valeurElem,unsigned short int));
1173                                         }
1174                                 }
1175                                 break;          
1176                 
1177                         case 4 :                        // LGR = 4
1178  
1179                                 if (   (strcmp(t->dicom_type,"UL") == 0)
1180                                     || (strcmp(t->dicom_type,"SL") == 0) ) {
1181                                                 if(!(ple->Gr%2) || !npriv) { 
1182                                                         printf("\t  \t \t %d \tx(%08x)\n", 
1183                                                                 str2num(ple->valeurElem,int), 
1184                                                                 str2num(ple->valeurElem,int));
1185                                                 }       
1186                                 } else {
1187                                         if(!(ple->Gr%2) || !npriv) { 
1188                                                 printf("\t[%s]  \t %d \tx(%08x)\n", 
1189                                                         ple->valeurElem,
1190                                                         str2num(ple->valeurElem,int), 
1191                                                         str2num(ple->valeurElem,int));
1192                                         }
1193                                 }
1194                                 break;
1195                         
1196                         default :                                                               // AUTRES LGR
1197
1198                                 if (ple->LgrElem > 5000) { 
1199                                         if(!(ple->Gr%2) || !npriv) 
1200                                                 printf(" --> Too Long. Not Printed...\n");
1201                                 } else {
1202                                         if(!(ple->Gr%2) || !npriv) 
1203                                                 printf(" \t[%s]\n",ple->valeurElem);
1204                                 }
1205                         }
1206                 }
1207         plelem = IdLstNext(plelem);
1208         }
1209 }
1210
1211 // -----------------------------------------------------------------------------------------------
1212
1213 /**
1214  * \ingroup        dcm
1215  * \brief          Verifie le caractère Acr/Dcm/LibIdo d'un fichier.
1216  *
1217  * @param filename      Nom du Fichier
1218  * @return              ID_DCM_HDR (ca sera fait pour plus tard) si lisible
1219  *                      O sinon.
1220  *
1221  */
1222
1223 ID_DCM_HDR * IdDcmIsDcmReadable(char * filename) {
1224    
1225    return IdDcmReadFile(filename, 0xFFFF);
1226 }
1227
1228
1229 // ----------------------------------------------------------------------------------------------
1230  
1231  
1232  /**
1233  * \ingroup        dcm
1234  * \brief          Verifie le caractère Jpeg Lossless d'un fichier, a partir du DCM_HDR.
1235  *
1236  * @param e             ID_DCM_HDR  deja cree   
1237  * @return              1 si Jpeg Losless
1238  *                      O sinon.
1239  *
1240  */
1241  
1242 int IdDcmIsJpegLossless (ID_DCM_HDR * e) {
1243 char * Derivation_Description;
1244 char * Transfert_Syntax_UID;
1245 char * valeur = "Compress BN JPEG Lossless";
1246
1247         if (!e) 
1248                 return (0);
1249                 
1250         Transfert_Syntax_UID = _IdDcmReadElement(0x0002, 0x0010, e);
1251         if (Transfert_Syntax_UID != NULL) {
1252                 if ( (memcmp(Transfert_Syntax_UID + strlen(Transfert_Syntax_UID)-2, "70", 2) == 0)
1253                         ||
1254                          (memcmp(Transfert_Syntax_UID + strlen(Transfert_Syntax_UID)-2, "55", 2) == 0) ) {
1255                          return (1);
1256                  } else {       
1257                                 Derivation_Description = _IdDcmReadElement(0x0008, 0x2111, e);
1258                                 if (Derivation_Description != NULL) {
1259                                         if (memcmp (Derivation_Description, valeur, strlen(valeur)) == 0)
1260                                                 return (1);
1261                                 }       
1262                 }
1263         }
1264         return (0);
1265 }
1266