]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
* Truckload of changes. Parsing of header is barely functional
[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 #include <map>
13 #include <sstream>
14 #include "gdcmUtil.h"
15
16 #define LGR_ENTETE_A_LIRE 256 // on ne lit plus que le debut
17
18 //FIXME: this looks dirty to me...
19 #define str2num(str, typeNum) *((typeNum *)(str))
20
21 VRHT * gdcmHeader::dicom_vr = (VRHT*)0;
22 gdcmDictSet* gdcmHeader::Dicts = new gdcmDictSet();
23
24 void gdcmHeader::Initialise(void) {
25         if (!gdcmHeader::dicom_vr)
26                 InitVRDict();
27         bool grPixelTrouve = false;
28         PixelPosition = (size_t)0;
29         PixelsTrouves = false;
30         RefPubDict = gdcmHeader::Dicts->GetDefaultPublicDict();
31         RefShaDict = (gdcmDict*)0;
32 }
33
34 gdcmHeader::gdcmHeader (char* InFilename) {
35         filename = InFilename;
36         Initialise();
37         fp=fopen(InFilename,"rw");
38         dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", InFilename);
39         BuildHeader();
40         fclose(fp);
41 }
42
43 gdcmHeader::~gdcmHeader (void) {
44         return;
45 }
46
47 void gdcmHeader::InitVRDict (void) {
48         if (dicom_vr) {
49                 dbg.Verbose(0, "gdcmHeader::InitVRDict:", "VR dictionary allready set");
50                 return;
51         }
52         VRHT *vr = new VRHT;
53         (*vr)["AE"] = "Application Entity";       // 16 car max
54         (*vr)["AS"] = "Age String";               // 4 car fixe
55         (*vr)["AT"] = "Attribute Tag";            // 2 unsigned short int
56         (*vr)["CS"] = "Code String";              // 16 car max
57         (*vr)["DA"] = "Date";                     // 8 car fixe
58         (*vr)["DS"] = "Decimal String";           // Decimal codé Binaire 16 max
59         (*vr)["DT"] = "Date Time";                // 26 car max
60         (*vr)["FL"] = "Floating Point Single";    // 4 octets IEEE 754:1985
61         (*vr)["FD"] = "Floating Point Double";    // 8 octets IEEE 754:1985
62         (*vr)["IS"] = "Integer String";           // en format externe 12 max
63         (*vr)["LO"] = "Long String";              // 64 octets max
64         (*vr)["LT"] = "Long Text";                // 10240 max
65         (*vr)["OB"] = "Other Byte String";
66         (*vr)["OW"] = "Other Word String";
67         (*vr)["PN"] = "Person Name";
68         (*vr)["SH"] = "Short String";             // 16 car max
69         (*vr)["SL"] = "Signed Long";
70         (*vr)["SQ"] = "Sequence of Items";        // Not Applicable
71         (*vr)["SS"] = "Signed Short";             // 2 octets
72         (*vr)["ST"] = "Short Text";               // 1024 car max
73         (*vr)["TM"] = "Time";                     // 16 car max
74         (*vr)["UI"] = "Unique Identifier";        // 64 car max
75         (*vr)["UN"] = "Unknown";
76         (*vr)["UT"] = "Unlimited Text";           //  2 puissance 32 -1 car max
77         (*vr)["UL"] = "Unsigned Long ";           // 4 octets fixe
78         (*vr)["US"] = "Unsigned Short ";          // 2 octets fixe
79    dicom_vr = vr;       
80 }
81
82 /**
83  * \ingroup gdcmHeader
84  * \brief   La seule maniere sure que l'on aie pour determiner 
85  *          si on est en   LITTLE_ENDIAN,       BIG-ENDIAN, 
86  *          BAD-LITTLE-ENDIAN, BAD-BIG-ENDIAN
87  *          est de trouver l'element qui donne la longueur d'un 'GROUP'
88  *          (on sait que la longueur de cet element vaut 0x00000004)
89  *          et de regarder comment cette longueur est codee en memoire  
90  *          
91  *          Le probleme vient de ce que parfois, il n'y en a pas ...
92  *          
93  *          On fait alors le pari qu'on a a faire a du LITTLE_ENDIAN propre.
94  *          (Ce qui est la norme -pas respectee- depuis ACR-NEMA)
95  *          Si ce n'est pas le cas, on ne peut rien faire.
96  *
97  *          (il faudrait avoir des fonctions auxquelles 
98  *          on passe le code Swap en parametre, pour faire des essais 'manuels')
99  */
100 void gdcmHeader::CheckSwap()
101 {
102         guint32  s;
103         guint32  x=4;  // x : pour ntohs
104         bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
105          
106         int lgrLue;
107         char * entCur;
108         char deb[LGR_ENTETE_A_LIRE];
109          
110         // On teste le processeur
111         if (x==ntohs(x)) {
112                 net2host = true;
113         } else {
114                 net2host = false;
115         }
116         
117         // On commence par verifier si c'est du DICOM 'actuel'
118         //                                      -------------
119         lgrLue = fread(deb,1,LGR_ENTETE_A_LIRE, fp);
120         
121         entCur = deb+128;
122         if(memcmp(entCur, "DICM", (size_t)4) == 0) {
123                 filetype = TrueDicom;
124                 dbg.Verbose(0, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
125         } else {
126                 filetype = Unknown;
127                 dbg.Verbose(0, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
128         }
129
130         if(filetype == TrueDicom) {
131                 // on saute le File Preamble (souvent a ZERO) : 128 Octets
132                 // + le DICM (4), et le (0002, 0000) soit 4 (136 = 128 + 4 + 4)
133                 entCur = deb+136;
134                 if(memcmp(entCur, "UL", (size_t)2) == 0) {
135                         // les 2 premiers octets de la lgr peuvent valoir UL --> Explicit VR
136                         filetype = ExplicitVR;
137                         dbg.Verbose(0, "gdcmHeader::CheckSwap:",
138                                     "explicit Value Representation");
139                 } else {
140                         filetype = ImplicitVR;
141                         dbg.Verbose(0, "gdcmHeader::CheckSwap:",
142                                     "not an explicit Value Representation");
143                 }
144                 
145                 if (net2host) { // HostByteOrder is different from NetworkByteOrder
146                         sw = 0;    // on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire
147                         dbg.Verbose(0, "gdcmHeader::CheckSwap:",
148                                        "HostByteOrder = NetworkByteOrder");
149                 } else {    /* on est sur une Sun ou une SGI */
150                         sw = 4321;
151                         dbg.Verbose(0, "gdcmHeader::CheckSwap:",
152                                        "HostByteOrder != NetworkByteOrder");
153                 }
154                 
155                 rewind(fp);
156                 fseek (fp, 132L, SEEK_SET); //On se positionne sur le debut des info
157                 offsetCourant=132;
158         } // End of TrueDicom
159
160         // Pas du TrueDicom : permiere hypothese c'est de l'ACR 'propre', auquel
161         // cas la lgr du premier element du groupe est FORCEMENT 4
162         entCur=deb + 4;
163         s=str2num(entCur,int);
164         
165         switch (s) {
166         case 0x00040000 :
167                 sw=3412;
168                 filetype = ACR;
169                 break;
170         case 0x04000000 :
171                 sw=4321;
172                 filetype = ACR;
173                 break;
174         case 0x00000400 :
175                 sw=2143;
176                         filetype = ACR;
177                 break;
178         case 0x00000004 :
179                 sw=0;
180                 filetype = ACR;
181                 break;
182         default :
183                 sw = -1;
184                 dbg.Verbose(0, "gdcmHeader::CheckSwap:",
185                                "unfound swap info (time to raise bets)");
186         }
187         if(sw!=-1) {
188                 rewind(fp);    // les info commencent au debut
189                 offsetCourant=0;
190                 return;
191         }
192
193         // Deuxieme hypothese : c'est de l'ACR 'pas propre' i.e. il manque
194         // la lgr du groupe
195         
196         // On n'a pas trouve l'info de swap.
197         // Si c'est du VRAI ACR NEMA et
198         //  * si on est sur une DEC ou un PC alors swap=0,
199         //  * si on est sur SUN ou SGI,      alors swap=4321
200         // Si c'est du RAW, ca degagera + tard
201         dbg.Verbose(0, "gdcmHeader::CheckSwap:",
202                        "time for wild guesses...");
203         
204         if (x!=ntohs(x)) // HostByteOrder is different from NetworkByteOrder
205                 // on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire
206                 sw = 0;
207         else
208                 // on est sur Sun ou SGI
209                 sw = 4321;
210         rewind(fp);    // les info commencent au debut
211         offsetCourant=0;
212         return;
213 }
214
215 /**
216  * \ingroup gdcmHeader
217  * \brief   Pour les fichiers non TrueDicom, si le recognition
218  *          code (0008,0010) s'avere etre "ACR_LIBIDO", alors
219  *          valide la reconnaissance du fichier en positionnant
220  *          filetype.
221  */
222 void gdcmHeader::setAcrLibido() {
223         string RecCode;
224         
225         if ( filetype != TrueDicom) {
226                 printf("_setAcrLibido expects a presumably ACR file\n");
227                 // Recognition Code  --> n'existe plus en DICOM V3 ...
228                 RecCode = GetPubElValByNumber(0x0008, 0x0010);
229                 // FIXME NOW
230                 if (RecCode == "ACRNEMA_LIBIDO" ||
231                     RecCode == "CANRME_AILIBOD" )
232                         filetype = ACR_LIBIDO;
233                 else
234                         filetype = ACR;
235         }
236         return;
237 }
238
239 /**
240  * \ingroup   gdcmHeader
241  * \brief     recupere la longueur d'un champ DICOM.
242  *            Preconditions:
243  *            1/ le fichier doit deja avoir ete ouvert,
244  *            2/ CheckSwap() doit avoir ete appele
245  *            3/ la  partie 'group'  ainsi que la  partie 'elem' 
246  *               de l'acr_element doivent avoir ete lues.
247  *
248  *            ACR-NEMA : we allways get
249  *                 GroupNumber   (2 Octets) 
250  *                 ElementNumber (2 Octets) 
251  *                 ElementSize   (4 Octets)
252  *            DICOM en implicit Value Representation :
253  *                 GroupNumber   (2 Octets) 
254  *                 ElementNumber (2 Octets) 
255  *                 ElementSize   (4 Octets)
256  *
257  *            DICOM en explicit Value Representation :
258  *                 GroupNumber         (2 Octets) 
259  *                 ElementNumber       (2 Octets) 
260  *                 ValueRepresentation (2 Octets) 
261  *                 ElementSize         (2 Octets)
262  *
263  *            ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN
264  *                 GroupNumber         (2 Octets) 
265  *                 ElementNumber       (2 Octets) 
266  *                 ValueRepresentation (2 Octets)
267  *                 zone reservee       (2 Octets) 
268  *                 ElementSize         (4 Octets)
269  *
270  * @param sw  code swap
271  * @param skippedLength  pointeur sur nombre d'octets que l'on a saute qd
272  *                       la lecture est finie
273  * @param longueurLue    pointeur sur longueur (en nombre d'octets) 
274  *                       effectivement lue
275  * @return               longueur retenue pour le champ 
276  */
277
278 long int gdcmHeader::RecupLgr( ElValue *pleCourant, int *skippedLength) {
279         guint32 l_gr; 
280         unsigned short int l_gr_2;
281         int i;
282         char VR[5];
283         int lgrLue;
284         
285         //  FIX ME
286         //   ATTENTION : nbCode correspond au nombre d'elements dans la table
287         //               de type DICOM_VR. A nettoyer.
288         //
289         int nbCode=26;
290         
291         if (filetype == ExplicitVR) {
292                 lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
293                 VR[2]=0;
294                 
295                 // Warning: we believe this is explicit VR (Value Representation) because
296                 // we used a heuristic that found "UL" in the first tag. Alas this
297                 // doesn't guarantee that all the tags will be in explicit VR. In some
298                 // cases (see e-film filtered files) one finds implicit VR tags mixed
299                 // within an explicit VR file. Hence we make sure the present tag
300                 // is in explicit VR and try to fix things if it happens not to be
301                 // the case.
302
303                 // FIXME There should be only one occurence returned. Avoid the
304                 // first extraction by calling proper method.
305                 VRAtr FoundVR = dicom_vr->find(string(VR))->first;
306                 if (FoundVR.empty()) {
307                         pleCourant->SetVR(FoundVR);
308                 } else {
309                         
310                         // On est mal : implicit VR repere
311                         // mais ce n'est pas un code connu ...
312                         // On reconstitue la longueur
313                         
314                         dbg.Verbose(1, "gdcmHeader::RecupLgr:",
315                                                         "Explicit VR, but no known code");
316                         memcpy(&l_gr, VR,(size_t)2);
317                         lgrLue=fread ( ((char*)&l_gr)+2, (size_t)2, (size_t)1, fp);
318                         l_gr = SwapLong((guint32)l_gr);
319                         pleCourant->SetLgrLue(l_gr);
320                         if ( (int)l_gr == -1)
321                                 l_gr=0;
322                          
323                         *skippedLength = 4; 
324                         return(l_gr);
325                 }
326                 
327                 // On repart dans la sequence 'sensee'
328                 if ( (!memcmp( VR,"OB",(size_t)2 )) || 
329                      (!memcmp( VR,"OW",(size_t)2 )) || 
330                      (!memcmp( VR,"SQ",(size_t)2 )) ||
331                      (!memcmp( VR,"UN",(size_t)2 )) ) {
332                         
333                         // les 2 octets suivants sont reserves: on les saute
334                         fseek(fp, 2L,SEEK_CUR);
335                         
336                         //on lit la lgr sur QUATRE octets
337                         lgrLue=fread (&l_gr, (size_t)4,(size_t)1, fp);
338                         l_gr = SwapLong((guint32)l_gr);
339                         *skippedLength = 8;
340                 
341                 } else {
342                         //on lit la lgr sur DEUX octets
343                         lgrLue=fread (&l_gr_2, (size_t)2,(size_t)1, fp);
344                         
345                         if(sw) l_gr_2 = SwapShort((unsigned short)l_gr_2);
346                         
347                         pleCourant->SetLgrLue(l_gr_2);
348                         
349                         if ( l_gr_2 == 0xffff) {
350                                 l_gr = 0;
351                         } else {
352                                 l_gr = l_gr_2;
353                         }
354                         *skippedLength = 4;
355                 }
356         } else {
357                 // Explicit VR = 0
358                 //on lit la lgr sur QUATRE octets
359                 
360                 lgrLue=fread (&l_gr, (size_t)4,(size_t)1, fp);
361                 
362                 l_gr= SwapLong((long)l_gr);
363                 *skippedLength = 4;
364         }
365         
366         pleCourant->SetLgrLue(l_gr);
367         
368         // Traitement des curiosites sur la longueur
369         
370         if ( (int)l_gr == 0xffffffff)
371                 l_gr=0; 
372         
373         if(!memcmp( VR,"SQ",(size_t)2 )) { // ca annonce une SEQUENCE d'items ?!
374                 l_gr=0;                         // on lira donc les items de la sequence 
375         }
376         
377         return(l_gr);
378 }
379
380 /**
381  * \ingroup gdcmHeader
382  * \brief   remet les octets dans un ordre compatible avec celui du processeur
383
384  * @return  longueur retenue pour le champ 
385  */
386 guint32 gdcmHeader::SwapLong(guint32 a) {
387         // FIXME: il pourrait y avoir un pb pour les entiers negatifs ...
388         switch (sw) {
389         case    0 :
390                 break;
391         case 4321 :
392                 a=(   ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
393                       ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
394                 break;
395         
396         case 3412 :
397                 a=(   ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
398                 break;
399         
400         case 2143 :
401                 a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
402                 break;
403         default :
404                 dbg.Error(" gdcmHeader::SwapLong : unset swap code");
405                 a=0;
406         }
407         return(a);
408 }
409
410 /**
411  * \ingroup gdcmHeader
412  * \brief   remet les octets dans un ordre compatible avec celui du processeur
413
414  * @return  longueur retenue pour le champ 
415  */
416 short int gdcmHeader::SwapShort(short int a) {
417         if ( (sw==4321)  || (sw==2143) )
418                 a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
419         return (a);
420 }
421
422 /**
423  * \ingroup       gdcmHeader
424  * \brief         lit le dicom_element suivant.
425  *                      (le fichier doit deja avoir ete ouvert,
426  *                       _IdAcrCheckSwap(ID_DCM_HDR *e) avoir ete appele)
427  * @param e      ID_DCM_HDR  dans lequel effectuer la recherche.
428  * @param sw            code swap.
429  * @return              En cas de succes, 1 
430  *                      0 en cas d'echec.
431  */
432
433 ElValue * gdcmHeader::ReadNextElement(void) {
434         unsigned short g;
435         unsigned short n;
436         guint32 l;
437         long int posFich;
438         int skL;
439         size_t lgrLue;
440         //CLEANME DICOM_ELEMENTS *t;
441         ElValue * nouvDcmElem;
442         
443         // FIXME la probabilte pour depasser sans s'en rendre compte
444         // est grande avec le test d'egalite' suivant !
445         if(offsetCourant == taille_fich) { // On a atteint la fin du fichier
446                 dbg.Verbose(1, "ReadNextElement: EOF reached");
447                 return(NULL);
448         }
449         
450         // ------------------------- Lecture Num group : g
451         lgrLue=fread (&g, (size_t)2,(size_t)1, fp);
452         
453         if (feof(fp))  {
454                 dbg.Verbose(1, "ReadNextElement: EOF encountered");
455                 return (NULL);
456         }
457         if (ferror(fp)){
458                 dbg.Verbose(1, "ReadNextElement: failed to read NumGr");
459                 return (NULL);
460         }
461         
462         if (sw) g= SwapShort(((short)g));
463         
464         // ------------------------- Lecture Num Elem : n
465         lgrLue=fread (&n, (size_t)2,(size_t)1, fp);
466         
467         if (feof(fp))  {
468                 dbg.Verbose(1, "ReadNextElement: EOF encountered");
469                 return (NULL);
470         }
471         if (ferror(fp)){
472                 dbg.Verbose(1, "ReadNextElement: failed to read NumElem");
473                 return (NULL);
474         }
475         
476         if(sw) n= SwapShort(((short)n));
477
478         // Find out if the tag we encountered is in the dictionaries:
479         gdcmDictEntry * NewTag = IsInDicts(g, n);
480         if (!NewTag)
481                 NewTag = new gdcmDictEntry(g, n, "Unknown", "Unknown", "Unkown");
482
483         nouvDcmElem = new ElValue(NewTag);
484         if (!nouvDcmElem) {
485                 dbg.Verbose(1, "ReadNextElement: failed to allocate ElValue");
486                 return(NULL);
487         }
488
489         // ------------------------- Lecture longueur element : l
490         
491         l = RecupLgr(nouvDcmElem, &skL);
492         
493         if(g==0xfffe) l=0;  // pour sauter les indicateurs de 'SQ'
494         
495         nouvDcmElem->LgrElem=l;
496         
497         // ------------------------- Lecture Valeur element 
498         
499         // FIXME The exact size should be l if we move to strings or whatever
500         // CLEAN ME NEWValue used to be nouvDcmElem->valeurElem
501         char* NewValue = (char*)g_malloc(l+1);
502         if(NewValue) {
503                 NewValue[l]= 0;
504         } else {
505                 return (NULL);
506         }
507         
508         // FIXME les elements trop long (seuil a fixer a la main) ne devraient
509         // pas etre charge's !!!! Voir TODO.
510         lgrLue=fread (NewValue, (size_t)l,(size_t)1, fp);
511         
512         offsetCourant +=  2 + 2 + skL; // gr +  num + lgr
513         nouvDcmElem->Offset = offsetCourant;
514         offsetCourant += l;            // debut elem suivant
515
516         // ------------------------- Doit-on le Swapper ?
517         
518         if ((n==0) && sw)  {  // n=0 : lgr du groupe : guint32
519                 *(guint32 *) NewValue = SwapLong ((*(guint32 *) NewValue));  
520         } else {
521                 if(sw) {
522                         if ( (g/2)*2-g==0) { /* on ne teste pas les groupes impairs */
523                                 
524                                 if ((l==4)||(l==2)) {  // pour eviter de swapper les chaines 
525                                                             // de lgr 2 ou 4
526                                         
527                                         // FIXME make reference to nouvDcmElem->GetTag
528                                         string VR = NewTag->GetVR();
529                                         if (   (VR == "UL") || (VR == "US")
530                                             || (VR == "SL") || (VR == "SS")
531                                             || (g == 0x0028 && ( n == 0x0005 || n == 0x0200) )) {
532                                                 // seuls (28,5) de vr RET et (28,200) sont des entiers
533                                                 // ... jusqu'a preuve du contraire
534                                                 
535                                                 if(l==4) { 
536                                                         *(guint32 *) NewValue =
537                                                             SwapLong  ((*(guint32 *) NewValue)); 
538                                                 } else {
539                                                         if(l==2) 
540                                                     *(unsigned short *) NewValue =
541                                                         SwapShort ((*(unsigned short *)NewValue));
542                                                  }
543                                         }
544                                 } /* fin if l==2 ==4 */
545                         } /* fin if g pair */
546                 } /* fin sw */  
547         }
548         nouvDcmElem->value = NewValue;
549         // CLEAN ME: simply trash the following line and postpone the process !
550         // SetAsidePixelData(nouvDcmElem);
551         return nouvDcmElem;
552 }
553
554 /**
555  * \ingroup gdcmHeader
556  * \brief   If we encountered the offset of the pixels in the file
557  *          (Pixel Data) then keep the info aside.
558  */
559 void gdcmHeader::SetAsidePixelData(ElValue* elem) {
560           /// FIXME this wall process is bizarre:
561           // on peut pas lire pixel data et pixel location puis
562           // a la fin de la lecture aller interpreter ce qui existe ?
563           // penser a nettoyer les variables globales associes genre
564           // PixelsTrouve ou grPixelTrouve...
565           //
566         // They are two cases :
567         // * the pixel data (i.e. the image or the volume) is pointed by it's
568         //   default official tag (0x7fe0,0x0010),
569         // * the writer of this file decided to put the image "address" (i.e the
570         //   offset from the begining of the file) at a different tag.
571         //   Then the "Pixel Data" offset might be found by indirection through
572         //   the "Image Location" tag (0x0028,  0x0200). In other terms the Image
573         //   Location tag contains the group where the "Pixel Data" offset is and
574         //   inside this group the element is conventionally at element 0x0010
575         //   (when the norm is respected).
576         // 
577         // Hence getting our hands on the Pixel Data is a two stage process:
578         //  1/ * find if the "Pixel Data" tag exists.
579         //     * if it does not exist, look for the "Pixel Location" tag.
580         //  2/ look at the proper tag ("Pixel Data" or "Pixel Location" when
581         //     it exists) what the offset it.
582         guint16 g;
583         guint16 n;
584         g = elem->GetGroup();
585         n = elem->GetElement();
586         if (!grPixelTrouve) {   // on n a pas encore trouve les pixels
587                 if (g > 0x0028) {
588                         if (n > 0x0200 || g == 0x7FE0 ) {  // on a depasse (28,200)
589                                 grPixel  = 0x7FE0;
590                                 numPixel = 0x0010;
591                                 grPixelTrouve = true;
592                         }
593                 } else {         // on est sur (28,200)
594                         if (g == 0x0028) {
595                                 if (n == 0x0200) {
596                                         grPixelTrouve = 1;
597                                         char* NewValue = (char*)g_malloc(elem->GetLgrElem()+1);
598                                         // FIXME: not very elegant conversion
599                                         for(int i=0;i<4;i++)
600                                                 *((char*)(&grPixel)+i) = *(NewValue+i); 
601                                         elem->SetValue(NewValue);
602                                         
603                                         if (grPixel != 0x7FE0)   // Vieux pb Philips
604                                                 numPixel = 0x1010;    // encore utile ??
605                                         else
606                                                 numPixel = 0x0010;
607                                 }
608                         }
609                 }
610         } else {     // on vient de trouver les pixels
611                 if (g == grPixel) {
612                         if (n == numPixel) {
613                                 PixelPosition = elem->Offset; 
614                                 PixelsTrouves = true;
615                                 dbg.Verbose(0, "gdcmHeader::SetAsidePixelData:",
616                                             "Pixel data found");
617                         }
618                 }
619         }
620 }
621
622 gdcmDictEntry * gdcmHeader::IsInDicts(guint32 group, guint32 element) {
623         gdcmDictEntry * found = (gdcmDictEntry*)0;
624         if (!RefPubDict && !RefShaDict) {
625                 //FIXME build a default dictionary !
626                 printf("FIXME in gdcmHeader::IsInDicts\n");
627         }
628         if (RefPubDict) {
629                 found = RefPubDict->GetTag(group, element);
630                 if (found)
631                         return found;
632         }
633         if (RefShaDict) {
634                 found = RefShaDict->GetTag(group, element);
635                 if (found)
636                         return found;
637         }
638         return found;
639 }
640
641 string gdcmHeader::GetPubElValByNumber(unsigned short, unsigned short) {
642 }
643
644 /**
645  * \ingroup       gdcmHeader
646  * \brief         renvoie un pointeur sur le ID_DCM_HDR correspondant au fichier
647  * @param filename      Nom du fichier ACR / LibIDO / DICOM
648  * @return       le ID_DCM_HDR 
649  */
650  
651 void gdcmHeader::BuildHeader(void) {
652         ElValue * newElValue = (ElValue *)0;
653         
654         rewind(fp);
655         fseek(fp, 0L, SEEK_END);
656         /*
657          * obtains the current value of the file-position    
658          * indicator for the stream pointed to by stream      
659          */
660         taille_fich = ftell(fp);
661         rewind(fp);
662         CheckSwap();
663         while ( (newElValue = ReadNextElement()) ) {
664                 PubElVals.Add(newElValue);
665         }
666         setAcrLibido();
667 }
668
669 int gdcmHeader::PrintPubElVal(ostream & os) {
670         return PubElVals.Print(os);
671 }
672
673 void gdcmHeader::PrintPubDict(ostream & os) {
674         RefPubDict->Print(os);
675 }