]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
modif in Header printing
[gdcm.git] / src / gdcmHeader.cxx
1 // gdcmHeader.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmHeader.h"
4
5 #include <stdio.h>
6 #include <cerrno>
7 // For nthos:
8 #ifdef _MSC_VER
9 #include <winsock.h>
10 #else
11 #include <netinet/in.h>
12 #endif
13 #include <cctype>    // for isalpha
14
15 #ifdef GDCM_NO_ANSI_STRING_STREAM
16 #  include <strstream>
17 #  define  ostringstream ostrstream
18 # else
19 #  include <sstream>
20 #endif
21
22 #include "gdcmUtil.h"
23 #include "gdcmTS.h"
24
25 //-----------------------------------------------------------------------------
26 // Refer to gdcmHeader::CheckSwap()
27 const unsigned int gdcmHeader::HEADER_LENGTH_TO_READ = 256;
28
29 // Refer to gdcmHeader::SetMaxSizeLoadElementValue()
30 const unsigned int gdcmHeader::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096;
31
32 //-----------------------------------------------------------------------------
33 // Constructor / Destructor
34 /**
35  * \ingroup gdcmHeader
36  * \brief   
37  * @param   InFilename
38  * @param   exception_on_error
39  * @param   enable_sequences = true to allow the header 
40  *          to be parsed *inside* the SeQuences, 
41  *          when they have an actual length 
42  */
43 gdcmHeader::gdcmHeader(const char *InFilename, 
44                        bool exception_on_error,
45                        bool enable_sequences ) {
46    if (enable_sequences)
47       enableSequences = 1;
48    else
49       enableSequences = 0;
50    
51    SetMaxSizeLoadElementValue(MAX_SIZE_LOAD_ELEMENT_VALUE);
52    filename = InFilename;
53    Initialise();
54    if ( !OpenFile(exception_on_error))
55       return;
56    ParseHeader();
57    LoadHeaderEntries();
58    CloseFile();
59 }
60
61 /**
62  * \ingroup gdcmHeader
63  * \brief   
64  * @param   exception_on_error
65  */
66 gdcmHeader::gdcmHeader(bool exception_on_error) {
67   SetMaxSizeLoadElementValue(MAX_SIZE_LOAD_ELEMENT_VALUE);
68   Initialise();
69 }
70
71 /**
72  * \ingroup gdcmHeader
73  * \brief   Canonical destructor.
74  */
75 gdcmHeader::~gdcmHeader (void) {
76   dicom_vr =   (gdcmVR*)0; 
77   Dicts    =   (gdcmDictSet*)0;
78   RefPubDict = (gdcmDict*)0;
79   RefShaDict = (gdcmDict*)0;
80   return;
81 }
82
83 //-----------------------------------------------------------------------------
84 // Print
85
86 /**
87   * \ingroup gdcmHeader
88   * \brief
89   * @return
90   */ 
91 void gdcmHeader::PrintPubEntry(std::ostream & os) {
92    PubEntrySet.Print(os);
93 }
94
95 /**
96   * \ingroup gdcmHeader
97   * \brief 
98   * @return
99   */  
100 void gdcmHeader::PrintPubDict(std::ostream & os) {
101    RefPubDict->Print(os);
102 }
103
104 //-----------------------------------------------------------------------------
105 // Public
106 /**
107  * \ingroup gdcmHeader
108  * \brief  This predicate, based on hopefully reasonable heuristics,
109  *         decides whether or not the current gdcmHeader was properly parsed
110  *         and contains the mandatory information for being considered as
111  *         a well formed and usable image.
112  * @return true when gdcmHeader is the one of a reasonable Dicom file,
113  *         false otherwise. 
114  */
115 bool gdcmHeader::IsReadable(void) {
116    std::string res = GetEntryByNumber(0x0028, 0x0005);
117    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) {
118       return false; // Image Dimensions
119    }
120
121    if ( !GetHeaderEntryByNumber(0x0028, 0x0100) )
122       return false; // "Bits Allocated"
123    if ( !GetHeaderEntryByNumber(0x0028, 0x0101) )
124       return false; // "Bits Stored"
125    if ( !GetHeaderEntryByNumber(0x0028, 0x0102) )
126       return false; // "High Bit"
127    if ( !GetHeaderEntryByNumber(0x0028, 0x0103) )
128       return false; // "Pixel Representation"
129    return true;
130 }
131
132 /**
133  * \ingroup gdcmHeader
134  * \brief   Determines if the Transfer Syntax was already encountered
135  *          and if it corresponds to a ImplicitVRLittleEndian one.
136  *
137  * @return  True when ImplicitVRLittleEndian found. False in all other cases.
138  */
139 bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) {
140    gdcmHeaderEntry *Element = GetHeaderEntryByNumber(0x0002, 0x0010);
141    if ( !Element )
142       return false;
143    LoadHeaderEntrySafe(Element);
144
145    std::string Transfer = Element->GetValue();
146    if ( Transfer == "1.2.840.10008.1.2" )
147       return true;
148    return false;
149 }
150
151 /**
152  * \ingroup gdcmHeader
153  * \brief   Determines if the Transfer Syntax was already encountered
154  *          and if it corresponds to a ExplicitVRLittleEndian one.
155  *
156  * @return  True when ExplicitVRLittleEndian found. False in all other cases.
157  */
158 bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) {
159    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
160    if ( !Element )
161       return false;
162    LoadHeaderEntrySafe(Element);
163
164    std::string Transfer = Element->GetValue();
165    if ( Transfer == "1.2.840.10008.1.2.1" )
166       return true;
167    return false;
168 }
169
170 /**
171  * \ingroup gdcmHeader
172  * \brief   Determines if the Transfer Syntax was already encountered
173  *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
174  *
175  * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
176  */
177 bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
178    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
179    if ( !Element )
180       return false;
181    LoadHeaderEntrySafe(Element);
182
183    std::string Transfer = Element->GetValue();
184    if ( Transfer == "1.2.840.10008.1.2.1.99" )
185       return true;
186    return false;
187 }
188
189 /**
190  * \ingroup gdcmHeader
191  * \brief   Determines if the Transfer Syntax was already encountered
192  *          and if it corresponds to a Explicit VR Big Endian one.
193  *
194  * @return  True when big endian found. False in all other cases.
195  */
196 bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) {
197    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
198    if ( !Element )
199       return false;
200    LoadHeaderEntrySafe(Element);
201
202    std::string Transfer = Element->GetValue();
203    if ( Transfer == "1.2.840.10008.1.2.2" )  //1.2.2 ??? A verifier !
204       return true;
205    return false;
206 }
207
208 /**
209  * \ingroup gdcmHeader
210  * \brief   Determines if the Transfer Syntax was already encountered
211  *          and if it corresponds to a JPEGBaseLineProcess1 one.
212  *
213  * @return  True when JPEGBaseLineProcess1found. False in all other cases.
214  */
215 bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
216    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
217    if ( !Element )
218       return false;
219    LoadHeaderEntrySafe(Element);
220
221    std::string Transfer = Element->GetValue();
222    if ( Transfer == "1.2.840.10008.1.2.4.50" )
223       return true;
224    return false;
225 }
226
227 /**
228  * \ingroup gdcmHeader
229  * \brief   Determines if the Transfer Syntax was already encountered
230  *          and if it corresponds to a JPEGExtendedProcess2-4 one.
231  *
232  * @return  True when JPEGExtendedProcess2-4 found. False in all other cases.
233  */
234 bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
235    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
236    if ( !Element )
237       return false;
238    LoadHeaderEntrySafe(Element);
239
240    std::string Transfer = Element->GetValue();
241    if ( Transfer == "1.2.840.10008.1.2.4.51" )
242       return true;
243    return false;
244 }
245
246 /**
247  * \ingroup gdcmHeader
248  * \brief   Determines if the Transfer Syntax was already encountered
249  *          and if it corresponds to a JPEGExtendeProcess3-5 one.
250  *
251  * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
252  */
253 bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
254    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
255    if ( !Element )
256       return false;
257    LoadHeaderEntrySafe(Element);
258
259    std::string Transfer = Element->GetValue();
260    if ( Transfer == "1.2.840.10008.1.2.4.52" )
261       return true;
262    return false;
263 }
264
265 /**
266  * \ingroup gdcmHeader
267  * \brief   Determines if the Transfer Syntax was already encountered
268  *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
269  *
270  * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all
271  *          other cases.
272  */
273 bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
274    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
275    if ( !Element )
276       return false;
277    LoadHeaderEntrySafe(Element);
278
279    std::string Transfer = Element->GetValue();
280    if ( Transfer == "1.2.840.10008.1.2.4.53" )
281       return true;
282    return false;
283 }
284
285 /**
286  * \ingroup gdcmHeader
287  * \brief   Determines if the Transfer Syntax was already encountered
288  *          and if it corresponds to a RLE Lossless one.
289  *
290  * @return  True when RLE Lossless found. False in all
291  *          other cases.
292  */
293 bool gdcmHeader::IsRLELossLessTransferSyntax(void) {
294    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
295    if ( !Element )
296       return false;
297    LoadHeaderEntrySafe(Element);
298
299    std::string Transfer = Element->GetValue();
300    if ( Transfer == "1.2.840.10008.1.2.5" )
301       return true;
302    return false;
303 }
304
305 /**
306  * \ingroup gdcmHeader
307  * \brief   
308  *
309  * @return 
310  */
311 bool gdcmHeader::IsJPEGLossless(void) {
312    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
313     // faire qq chose d'intelligent a la place de Ã§a
314    if ( !Element )
315       return false;
316    LoadHeaderEntrySafe(Element);
317
318    const char * Transfert = Element->GetValue().c_str();
319    if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true;
320    if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true;
321    if (Element->GetValue() == "1.2.840.10008.1.2.4.57")   return true;
322
323    return false;
324 }
325
326 /**
327  * \ingroup gdcmHeader
328  * \brief   Determines if the Transfer Syntax was already encountered
329  *          and if it corresponds to a JPEG200 one.0
330  *
331  * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
332  *          other cases.
333  */
334 bool gdcmHeader::IsJPEG2000(void) {
335    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
336    if ( !Element )
337       return false;
338    LoadHeaderEntrySafe(Element);
339
340    std::string Transfer = Element->GetValue();
341    if (    (Transfer == "1.2.840.10008.1.2.4.90") 
342         || (Transfer == "1.2.840.10008.1.2.4.91") )
343       return true;
344    return false;
345 }
346
347 /**
348  * \ingroup gdcmHeader
349  * \brief   Predicate for dicom version 3 file.
350  * @return  True when the file is a dicom version 3.
351  */
352 bool gdcmHeader::IsDicomV3(void) {
353    if (   (filetype == ExplicitVR)
354        || (filetype == ImplicitVR) )
355       return true;
356    return false;
357 }
358
359 /**
360  * \ingroup gdcmHeader
361  * \brief  
362  * @return 
363  */
364 FileType gdcmHeader::GetFileType(void)
365 {
366    return(filetype);
367 }
368
369 /**
370  * \ingroup gdcmHeader
371  * \brief   Retrieve the number of columns of image.
372  * @return  The encountered size when found, 0 by default.
373  */
374 int gdcmHeader::GetXSize(void) {
375    // We cannot check for "Columns" because the "Columns" tag is present
376    // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary.
377    std::string StrSize = GetEntryByNumber(0x0028,0x0011);
378    if (StrSize == GDCM_UNFOUND)
379       return 0;
380    return atoi(StrSize.c_str());
381 }
382
383 /**
384  * \ingroup gdcmHeader
385  * \brief   Retrieve the number of lines of image.
386  * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize()
387  * @return  The encountered size when found, 1 by default.
388  */
389 int gdcmHeader::GetYSize(void) {
390    // We cannot check for "Rows" because the "Rows" tag is present
391    // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary.
392    std::string StrSize = GetEntryByNumber(0x0028,0x0010);
393    if (StrSize != GDCM_UNFOUND)
394       return atoi(StrSize.c_str());
395    if ( IsDicomV3() )
396       return 0;
397    else
398       // The Rows (0028,0010) entry is optional for ACR/NEMA. It might
399       // hence be a signal (1d image). So we default to 1:
400       return 1;
401 }
402
403 /**
404  * \ingroup gdcmHeader
405  * \brief   Retrieve the number of planes of volume or the number
406  *          of frames of a multiframe.
407  * \warning When present we consider the "Number of Frames" as the third
408  *          dimension. When absent we consider the third dimension as
409  *          being the "Planes" tag content.
410  * @return  The encountered size when found, 1 by default.
411  */
412 int gdcmHeader::GetZSize(void) {
413    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
414    // as the third dimension.
415    std::string StrSize = GetEntryByNumber(0x0028,0x0008);
416    if (StrSize != GDCM_UNFOUND)
417       return atoi(StrSize.c_str());
418
419    // We then consider the "Planes" entry as the third dimension [we
420    // cannot retrieve by name since "Planes tag is present both in
421    // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. 
422    StrSize = GetEntryByNumber(0x0028,0x0012);
423    if (StrSize != GDCM_UNFOUND)
424       return atoi(StrSize.c_str());
425    return 1;
426 }
427
428 /**
429  * \ingroup gdcmHeader
430  * \brief   Retrieve the number of Bits Stored
431  *          (as opposite to number of Bits Allocated)
432  * 
433  * @return  The encountered number of Bits Stored, 0 by default.
434  */
435 int gdcmHeader::GetBitsStored(void) { 
436    std::string StrSize = GetEntryByNumber(0x0028,0x0101);
437    if (StrSize == GDCM_UNFOUND)
438       return 1;
439    return atoi(StrSize.c_str());
440 }
441
442 /**
443  * \ingroup gdcmHeader
444  * \brief   Retrieve the number of Bits Allocated
445  *          (8, 12 -compacted ACR-NEMA files, 16, ...)
446  * 
447  * @return  The encountered number of Bits Allocated, 0 by default.
448  */
449 int gdcmHeader::GetBitsAllocated(void) { 
450    std::string StrSize = GetEntryByNumber(0x0028,0x0100);
451    if (StrSize == GDCM_UNFOUND)
452       return 1;
453    return atoi(StrSize.c_str());
454 }
455
456 /**
457  * \ingroup gdcmHeader
458  * \brief   Retrieve the number of Samples Per Pixel
459  *          (1 : gray level, 3 : RGB -1 or 3 Planes-)
460  * 
461  * @return  The encountered number of Samples Per Pixel, 1 by default.
462  */
463 int gdcmHeader::GetSamplesPerPixel(void) { 
464    std::string StrSize = GetEntryByNumber(0x0028,0x0002);
465    if (StrSize == GDCM_UNFOUND)
466       return 1; // Well, it's supposed to be mandatory ...
467    return atoi(StrSize.c_str());
468 }
469
470 /**
471  * \ingroup gdcmHeader
472  * \brief   Retrieve the Planar Configuration for RGB images
473  *          (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane)
474  * 
475  * @return  The encountered Planar Configuration, 0 by default.
476  */
477 int gdcmHeader::GetPlanarConfiguration(void) { 
478    std::string StrSize = GetEntryByNumber(0x0028,0x0006);
479    if (StrSize == GDCM_UNFOUND)
480       return 0;
481    return atoi(StrSize.c_str());
482 }
483
484 /**
485  * \ingroup gdcmHeader
486  * \brief   Return the size (in bytes) of a single pixel of data.
487  * @return  The size in bytes of a single pixel of data.
488  *
489  */
490 int gdcmHeader::GetPixelSize(void) {
491    std::string PixelType = GetPixelType();
492    if (PixelType == "8U"  || PixelType == "8S")
493       return 1;
494    if (PixelType == "16U" || PixelType == "16S")
495       return 2;
496    if (PixelType == "32U" || PixelType == "32S")
497       return 4;
498    dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
499    return 0;
500 }
501
502 /**
503  * \ingroup gdcmHeader
504  * \brief   Build the Pixel Type of the image.
505  *          Possible values are:
506  *          - 8U  unsigned  8 bit,
507  *          - 8S    signed  8 bit,
508  *          - 16U unsigned 16 bit,
509  *          - 16S   signed 16 bit,
510  *          - 32U unsigned 32 bit,
511  *          - 32S   signed 32 bit,
512  * \warning 12 bit images appear as 16 bit.
513  * \        24 bit images appear as 8 bit
514  * @return  
515  */
516 std::string gdcmHeader::GetPixelType(void) {
517    std::string BitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated
518    if (BitsAlloc == GDCM_UNFOUND) {
519       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
520       BitsAlloc = std::string("16");
521    }
522    if (BitsAlloc == "12")            // It will be unpacked
523       BitsAlloc = std::string("16");
524    else if (BitsAlloc == "24")       // (in order no to be messed up
525       BitsAlloc = std::string("8");  // by old RGB images)
526      
527    std::string Signed = GetEntryByNumber(0x0028, 0x0103); // "Pixel Representation"
528    if (Signed == GDCM_UNFOUND) {
529       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
530       BitsAlloc = std::string("0");
531    }
532    if (Signed == "0")
533       Signed = std::string("U");
534    else
535       Signed = std::string("S");
536
537    return( BitsAlloc + Signed);
538 }
539
540 /**
541  * \ingroup gdcmHeader
542  * \brief   Recover the offset (from the beginning of the file) of the pixels.
543  */
544 size_t gdcmHeader::GetPixelOffset(void) {
545    // If this file complies with the norm we should encounter the
546    // "Image Location" tag (0x0028,  0x0200). This tag contains the
547    // the group that contains the pixel data (hence the "Pixel Data"
548    // is found by indirection through the "Image Location").
549    // Inside the group pointed by "Image Location" the searched element
550    // is conventionally the element 0x0010 (when the norm is respected).
551    // When the "Image Location" is absent we default to group 0x7fe0.
552    guint16 grPixel;
553    guint16 numPixel;
554    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
555
556    if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
557       grPixel = 0x7fe0;
558    } else {
559       grPixel = (guint16) atoi( ImageLocation.c_str() );
560    }
561    if (grPixel != 0x7fe0)
562       // This is a kludge for old dirty Philips imager.
563       numPixel = 0x1010;
564    else
565       numPixel = 0x0010;
566          
567    gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
568    if (PixelElement)
569       return PixelElement->GetOffset();
570    else
571       return 0;
572 }
573
574 /**
575  * \ingroup gdcmHeader
576  * \brief   Recover the pixel area length (in Bytes) .
577  */
578 size_t gdcmHeader::GetPixelAreaLength(void) {
579    // If this file complies with the norm we should encounter the
580    // "Image Location" tag (0x0028,  0x0200). This tag contains the
581    // the group that contains the pixel data (hence the "Pixel Data"
582    // is found by indirection through the "Image Location").
583    // Inside the group pointed by "Image Location" the searched element
584    // is conventionally the element 0x0010 (when the norm is respected).
585    // When the "Image Location" is absent we default to group 0x7fe0.
586    guint16 grPixel;
587    guint16 numPixel;
588    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
589    if ( ImageLocation == GDCM_UNFOUND ) {
590       grPixel = 0x7fe0;
591    } else {
592       grPixel = (guint16) atoi( ImageLocation.c_str() );
593    }
594    if (grPixel != 0x7fe0)
595       // This is a kludge for old dirty Philips imager.
596       numPixel = 0x1010;
597    else
598       numPixel = 0x0010;
599          
600    gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
601    if (PixelElement)
602       return PixelElement->GetLength();
603    else
604       return 0;
605 }
606
607 /**
608   * \ingroup gdcmHeader
609   * \brief tells us if LUT are used
610   * \warning Right now, Segmented xxx Palette Color Lookup Table Data
611   * \        are NOT considered as LUT, since nobody knows
612   *\         how to deal with them
613   * @return int acts as a Boolean 
614   */
615 bool gdcmHeader::HasLUT(void) {
616
617    // Check the presence of the LUT Descriptors 
618    if ( !GetHeaderEntryByNumber(0x0028,0x1101) )
619       return false;
620    // LutDescriptorGreen 
621    if ( !GetHeaderEntryByNumber(0x0028,0x1102) )
622       return false;
623    // LutDescriptorBlue 
624    if ( !GetHeaderEntryByNumber(0x0028,0x1103) )
625       return false;
626    //  It is not enough
627    // we check also 
628    if ( !GetHeaderEntryByNumber(0x0028,0x1201) )
629       return false;  
630    if ( !GetHeaderEntryByNumber(0x0028,0x1202) )
631       return false;
632    if ( !GetHeaderEntryByNumber(0x0028,0x1203) )
633       return false;   
634    return true;
635 }
636
637 /**
638   * \ingroup gdcmHeader
639   * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
640   * \           else 0
641   * @return Lookup Table nBit 
642   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] 
643   */
644 int gdcmHeader::GetLUTNbits(void) {
645    std::vector<std::string> tokens;
646    //int LutLength;
647    //int LutDepth;
648    int LutNbits;
649    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue
650    // Consistency already checked in GetLUTLength
651    std::string LutDescription = GetEntryByNumber(0x0028,0x1101);
652    if (LutDescription == GDCM_UNFOUND)
653       return 0;
654    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
655    Tokenize (LutDescription, tokens, "\\");
656    //LutLength=atoi(tokens[0].c_str());
657    //LutDepth=atoi(tokens[1].c_str());
658    LutNbits=atoi(tokens[2].c_str());
659    tokens.clear();
660    return LutNbits;
661 }
662
663 /**
664   * \ingroup gdcmHeader
665   * \brief builts Red/Green/Blue/Alpha LUT from Header
666   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
667   * \        and (0028,1101),(0028,1102),(0028,1102)  
668   * \          - xxx Palette Color Lookup Table Descriptor - are found
669   * \        and (0028,1201),(0028,1202),(0028,1202) 
670   * \          - xxx Palette Color Lookup Table Data - are found 
671   * \warning does NOT deal with :
672   * \ 0028 1100 Gray Lookup Table Descriptor (Retired)
673   * \ 0028 1221 Segmented Red Palette Color Lookup Table Data
674   * \ 0028 1222 Segmented Green Palette Color Lookup Table Data
675   * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data 
676   * \ no known Dicom reader deails with them :-(
677   * @return Lookup Table RGBA
678   */ 
679 unsigned char * gdcmHeader::GetLUTRGBA(void) {
680 // Not so easy : see 
681 // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
682 // and  OT-PAL-8-face.dcm
683
684 //  if Photometric Interpretation # PALETTE COLOR, no LUT to be done
685    if (gdcmHeader::GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") {
686         return NULL;
687    }  
688
689    int lengthR, debR, nbitsR;
690    int lengthG, debG, nbitsG;
691    int lengthB, debB, nbitsB;
692    
693 // Get info from Lut Descriptors
694 // (the 3 LUT descriptors may be different)    
695    std::string LutDescriptionR = GetEntryByNumber(0x0028,0x1101);
696    if (LutDescriptionR == GDCM_UNFOUND)
697       return NULL;
698    std::string LutDescriptionG = GetEntryByNumber(0x0028,0x1102);
699    if (LutDescriptionG == GDCM_UNFOUND)
700       return NULL;   
701    std::string LutDescriptionB = GetEntryByNumber(0x0028,0x1103);
702    if (LutDescriptionB == GDCM_UNFOUND)
703       return NULL;
704       
705    std::vector<std::string> tokens;
706       
707    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
708    Tokenize (LutDescriptionR, tokens, "\\");
709    lengthR=atoi(tokens[0].c_str()); // Red LUT length in Bytes
710    debR   =atoi(tokens[1].c_str()); // subscript of the first Lut Value
711    nbitsR =atoi(tokens[2].c_str()); // Lut item size (in Bits)
712    tokens.clear();
713    
714    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
715    Tokenize (LutDescriptionG, tokens, "\\");
716    lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes
717    debG   =atoi(tokens[1].c_str());
718    nbitsG =atoi(tokens[2].c_str());
719    tokens.clear();  
720    
721    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
722    Tokenize (LutDescriptionB, tokens, "\\");
723    lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes
724    debB   =atoi(tokens[1].c_str());
725    nbitsB =atoi(tokens[2].c_str());
726    tokens.clear();
727  
728 // Load LUTs into memory, (as they were stored on disk)
729    unsigned char *lutR = (unsigned char *)
730                          GetPubEntryVoidAreaByNumber(0x0028,0x1201);
731    unsigned char *lutG = (unsigned char *)
732                          GetPubEntryVoidAreaByNumber(0x0028,0x1202);
733    unsigned char *lutB = (unsigned char *)
734                          GetPubEntryVoidAreaByNumber(0x0028,0x1203); 
735    
736    if (!lutR || !lutG || !lutB ) {
737         return NULL;
738    } 
739  // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT 
740    
741   unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) 
742   if (!LUTRGBA) {
743      return NULL;
744   }
745   memset(LUTRGBA, 0, 1024);
746         // Bits Allocated
747    int nb;
748    std::string str_nb = GetEntryByNumber(0x0028,0x0100);
749    if (str_nb == GDCM_UNFOUND ) {
750       nb = 16;
751    } else {
752       nb = atoi(str_nb.c_str() );
753    }  
754   int mult;
755   
756   if (nbitsR==16 && nb==8) // when LUT item size is different than pixel size
757      mult=2;               // high byte must be = low byte 
758   else                     // See PS 3.3-2003 C.11.1.1.2 p 619
759      mult=1; 
760  
761    // if we get a black image, let's just remove the '+1'
762    // from 'i*mult+1' and check again 
763    // if it works, we shall have to check the 3 Palettes
764    // to see which byte is ==0 (first one, or second one)
765    // and fix the code
766    // We give up the checking to avoid some overhead 
767   unsigned char *a;      
768   int i;
769
770   a = LUTRGBA+0;
771   for(i=0;i<lengthR;i++) {
772      *a = lutR[i*mult+1]; 
773      a+=4;       
774   }        
775   a = LUTRGBA+1;
776   for(i=0;i<lengthG;i++) {
777      *a = lutG[i*mult+1]; 
778      a+=4;       
779   }  
780   a = LUTRGBA+2;
781   for(i=0;i<lengthB;i++) {
782      *a = lutB[i*mult+1]; 
783      a+=4;       
784   }  
785   a = LUTRGBA+3;
786   for(i=0;i<256;i++) {
787      *a = 1; // Alpha component
788      a+=4; 
789   } 
790       
791 //How to free the now useless LUTs?
792
793 //free(LutR); free(LutB); free(LutG);
794   return(LUTRGBA);   
795
796
797 /**
798  * \ingroup gdcmHeader
799  * \brief gets the info from 0002,0010 : Transfert Syntax
800  * \      else 1.
801  * @return Transfert Syntax Name (as oposite to Transfert Syntax UID)
802  */
803 std::string gdcmHeader::GetTransfertSyntaxName(void) { 
804    // use the gdcmTS (TS : Transfert Syntax)
805    std::string TransfertSyntax = GetEntryByNumber(0x0002,0x0010);
806    if (TransfertSyntax == GDCM_UNFOUND) {
807       dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName: unfound Transfert Syntax (0002,0010)");
808       return "Uncompressed ACR-NEMA";
809    }
810    // we do it only when we need it
811    gdcmTS * ts = gdcmGlobal::GetTS();
812    std::string tsName=ts->GetValue(TransfertSyntax);
813    //delete ts; // Seg Fault when deleted ?!
814    return tsName;
815 }
816
817 /**
818  * \ingroup gdcmHeader
819  * \brief   Searches within the public dictionary for element value of
820  *          a given tag.
821  * @param   tagName name of the searched element.
822  * @return  Corresponding element value when it exists, and the string
823  *          GDCM_UNFOUND ("gdcm::Unfound") otherwise.
824  */
825 std::string gdcmHeader::GetPubEntryByName(std::string tagName) {
826    gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); 
827    if( dictEntry == NULL)
828       return GDCM_UNFOUND;
829
830    return(GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));  
831 }
832
833 /**
834  * \ingroup gdcmHeader
835  * \brief   Searches within the elements parsed with the public dictionary for
836  *          the element value representation of a given tag.
837  *
838  *          Obtaining the VR (Value Representation) might be needed by caller
839  *          to convert the string typed content to caller's native type 
840  *          (think of C++ vs Python). The VR is actually of a higher level
841  *          of semantics than just the native C++ type.
842  * @param   tagName name of the searched element.
843  * @return  Corresponding element value representation when it exists,
844  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
845  */
846 std::string gdcmHeader::GetPubEntryVRByName(std::string tagName) {
847    gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); 
848    if( dictEntry == NULL)
849       return GDCM_UNFOUND;
850
851    gdcmHeaderEntry* elem =  GetHeaderEntryByNumber(dictEntry->GetGroup(),
852                                                    dictEntry->GetElement());                                    
853    return elem->GetVR();
854 }
855
856 /**
857  * \ingroup gdcmHeader
858  * \brief   Searches within the public dictionary for element value of
859  *          a given tag.
860  * @param   group Group of the researched tag.
861  * @param   element Element of the researched tag.
862  * @return  Corresponding element value when it exists, and the string
863  *          GDCM_UNFOUND ("gdcm::Unfound") otherwise.
864  */
865 std::string gdcmHeader::GetPubEntryByNumber(guint16 group, guint16 element) {
866    return PubEntrySet.GetEntryByNumber(group, element);
867 }
868
869 /**
870  * \ingroup gdcmHeader
871  * \brief   Searches within the public dictionary for element value
872  *          representation of a given tag.
873  *
874  *          Obtaining the VR (Value Representation) might be needed by caller
875  *          to convert the string typed content to caller's native type 
876  *          (think of C++ vs Python). The VR is actually of a higher level
877  *          of semantics than just the native C++ type.
878  * @param   group Group of the researched tag.
879  * @param   element Element of the researched tag.
880  * @return  Corresponding element value representation when it exists,
881  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
882  */
883 std::string gdcmHeader::GetPubEntryVRByNumber(guint16 group, guint16 element) {
884    gdcmHeaderEntry* elem =  GetHeaderEntryByNumber(group, element);
885    if ( !elem )
886       return GDCM_UNFOUND;
887    return elem->GetVR();
888 }
889
890 /**
891  * \ingroup gdcmHeader
892  * \brief   Accesses an existing gdcmHeaderEntry in the PubHeaderEntrySet of this instance
893  *          through tag name and modifies it's content with the given value.
894  * @param   content new value to substitute with
895  * @param   tagName name of the tag to be modified
896  */
897 bool gdcmHeader::SetPubEntryByName(std::string content, std::string tagName) {
898    //return (  PubHeaderEntrySet.SetHeaderEntryByName (content, tagName) );
899    gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); 
900    if( dictEntry == NULL)
901       return false;
902    return(PubEntrySet.SetEntryByNumber(content,
903                                        dictEntry->GetGroup(),
904                                        dictEntry->GetElement()));   
905 }
906
907 /**
908  * \ingroup gdcmHeader
909  * \brief   Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element)
910  *          in the PubHeaderEntrySet of this instance
911  *          through it's (group, element) and modifies it's content with
912  *          the given value.
913  * @param   content new value to substitute with
914  * @param   group   group of the Dicom Element to modify
915  * @param   element element of the Dicom Element to modify
916  */
917 bool gdcmHeader::SetPubEntryByNumber(std::string content, guint16 group,
918                                     guint16 element)
919                                     
920 //TODO  : homogeneiser les noms : SetPubElValByNumber   
921 //                    qui appelle PubHeaderEntrySet.SetHeaderEntryByNumber 
922 //        pourquoi pas            SetPubHeaderEntryByNumber ??
923 {
924    return ( PubEntrySet.SetEntryByNumber (content, group, element) );
925 }
926
927 /**
928  * \ingroup gdcmHeader
929  * \brief   Accesses an existing gdcmHeaderEntry in the PubHeaderEntrySet of this instance
930  *          through it's (group, element) and modifies it's length with
931  *          the given value.
932  * \warning Use with extreme caution.
933  * @param   length new length to substitute with
934  * @param   group   group of the ElVal to modify
935  * @param   element element of the ElVal to modify
936  * @return  1 on success, 0 otherwise.
937  */
938
939 bool gdcmHeader::SetPubEntryLengthByNumber(guint32 length, guint16 group,
940                                     guint16 element) {
941         return (  PubEntrySet.SetEntryLengthByNumber (length, group, element) );
942 }
943
944 /**
945  * \ingroup gdcmHeader
946  * \brief   Searches within elements parsed with the public dictionary 
947  *          and then within the elements parsed with the shadow dictionary
948  *          for the element value of a given tag.
949  * @param   tagName name of the searched element.
950  * @return  Corresponding element value when it exists,
951  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
952  */
953 std::string gdcmHeader::GetEntryByName(std::string tagName) {
954    return GetPubEntryByName(tagName);
955 }
956
957 /**
958  * \ingroup gdcmHeader
959  * \brief   Searches within elements parsed with the public dictionary 
960  *          and then within the elements parsed with the shadow dictionary
961  *          for the element value representation of a given tag.
962  *
963  *          Obtaining the VR (Value Representation) might be needed by caller
964  *          to convert the string typed content to caller's native type 
965  *          (think of C++ vs Python). The VR is actually of a higher level
966  *          of semantics than just the native C++ type.
967  * @param   tagName name of the searched element.
968  * @return  Corresponding element value representation when it exists,
969  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
970  */
971 std::string gdcmHeader::GetEntryVRByName(std::string tagName) {
972    return GetPubEntryVRByName(tagName);
973 }
974
975 /**
976  * \ingroup gdcmHeader
977  * \brief   Searches within elements parsed with the public dictionary 
978  *          and then within the elements parsed with the shadow dictionary
979  *          for the element value of a given tag.
980  * @param   group Group of the searched tag.
981  * @param   element Element of the searched tag.
982  * @return  Corresponding element value representation when it exists,
983  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
984  */
985 std::string gdcmHeader::GetEntryByNumber(guint16 group, guint16 element) {
986    return GetPubEntryByNumber(group, element);
987 }
988
989 /**
990  * \ingroup gdcmHeader
991  * \brief   Searches within elements parsed with the public dictionary 
992  *          and then within the elements parsed with the shadow dictionary
993  *          for the element value representation of a given tag.
994  *
995  *          Obtaining the VR (Value Representation) might be needed by caller
996  *          to convert the string typed content to caller's native type 
997  *          (think of C++ vs Python). The VR is actually of a higher level
998  *          of semantics than just the native C++ type.
999  * @param   group Group of the searched tag.
1000  * @param   element Element of the searched tag.
1001  * @return  Corresponding element value representation when it exists,
1002  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
1003  */
1004 std::string gdcmHeader::GetEntryVRByNumber(guint16 group, guint16 element) {
1005    return GetPubEntryVRByNumber(group, element);
1006 }
1007
1008 /**
1009  * \ingroup gdcmHeader
1010  * \brief  Sets the value (string) of the target Dicom Element
1011  * @param   content string value of the Dicom Element
1012  * @param   tagName name of the searched Dicom Element.
1013  * @return  true when found
1014  */
1015 bool gdcmHeader::SetEntryByName(std::string content,std::string tagName) {
1016    gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); 
1017    if( dictEntry == NULL)
1018       return false;                                 
1019                                                                                                     
1020                                     
1021    TagKey key = gdcmDictEntry::TranslateToKey(dictEntry->GetGroup(), 
1022                                               dictEntry->GetElement());
1023    if ( PubEntrySet.GetTagHT().count(key) == 0 )
1024       return false;
1025    int l = content.length();
1026    if(l%2) {  // Odd length are padded with a space (020H).
1027       l++;
1028       content = content + '\0';
1029    }
1030       
1031    //tagHt[key]->SetValue(content);   
1032    gdcmHeaderEntry * a;
1033    IterHT p;
1034    TagHeaderEntryHT::iterator p2;
1035    // DO NOT remove the following lines : they explain the stuff   
1036    //p= tagHt.equal_range(key); // get a pair of iterators first-last synonym
1037    //p2=p.first;                // iterator on the first synonym 
1038    //a=p2->second;              // H Table target column (2-nd col)
1039     
1040    // or, easier :
1041    a = ((PubEntrySet.GetTagHT().equal_range(key)).first)->second; 
1042        
1043    a-> SetValue(content); 
1044    
1045    //std::string vr = tagHt[key]->GetVR();
1046    std::string vr = a->GetVR();
1047    
1048    guint32 lgr;
1049    if( (vr == "US") || (vr == "SS") ) 
1050       lgr = 2;
1051    else if( (vr == "UL") || (vr == "SL") )
1052       lgr = 4;
1053    else
1054       lgr = l;     
1055    //tagHt[key]->SetLength(lgr);
1056    a->SetLength(lgr);   
1057    return true;
1058 }
1059
1060 /**
1061  * \ingroup gdcmHeader
1062  * \brief   
1063  * @param   exception_on_error
1064  * @return  
1065  */
1066 FILE *gdcmHeader::OpenFile(bool exception_on_error)
1067   throw(gdcmFileError) {
1068   fp=fopen(filename.c_str(),"rb");
1069   if(exception_on_error) {
1070     if(!fp)
1071       throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)");
1072   }
1073
1074   if ( fp ) {
1075      guint16 zero;
1076      fread(&zero,  (size_t)2, (size_t)1, fp);
1077
1078     //ACR -- or DICOM with no Preamble
1079     if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200)
1080        return(fp);
1081
1082     //DICOM
1083     fseek(fp, 126L, SEEK_CUR);
1084     char dicm[4];
1085     fread(dicm,  (size_t)4, (size_t)1, fp);
1086     if( memcmp(dicm, "DICM", 4) == 0 )
1087        return(fp);
1088
1089     fclose(fp);
1090     dbg.Verbose(0, "gdcmHeader::gdcmHeader not DICOM/ACR", filename.c_str());
1091   }
1092   else {
1093     dbg.Verbose(0, "gdcmHeader::gdcmHeader cannot open file", filename.c_str());
1094   }
1095   return(NULL);
1096 }
1097
1098 /**
1099  * \ingroup gdcmHeader
1100  * \brief   
1101  * @return  TRUE if the close was successfull 
1102  */
1103 bool gdcmHeader::CloseFile(void) {
1104   int closed = fclose(fp);
1105   fp = (FILE *)0;
1106   if (! closed)
1107      return false;
1108   return true;
1109 }
1110
1111 /**
1112  * \ingroup gdcmHeader
1113  * \brief   Parses the header of the file but WITHOUT loading element values.
1114  */
1115 void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) {
1116    gdcmHeaderEntry * newHeaderEntry = (gdcmHeaderEntry *)0;
1117    
1118    rewind(fp);
1119    CheckSwap();
1120    while ( (newHeaderEntry = ReadNextHeaderEntry()) ) { 
1121       SkipHeaderEntry(newHeaderEntry);
1122       PubEntrySet.Add(newHeaderEntry);
1123    }
1124 }
1125
1126 /**
1127  * \ingroup gdcmHeader
1128  * \brief
1129  * @return integer, acts as a Boolean
1130  */ 
1131 bool gdcmHeader::Write(FILE * fp, FileType type) {
1132
1133    // TODO : move the following lines (and a lot of others, to be written)
1134    // to a future function CheckAndCorrectHeader
1135
1136    if (type == ImplicitVR) {
1137       std::string implicitVRTransfertSyntax = "1.2.840.10008.1.2";
1138       ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010);
1139       
1140       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
1141       //      values with a VR of UI shall be padded with a single trailing null
1142       //      Dans le cas suivant on doit pader manuellement avec un 0
1143       
1144       PubEntrySet.SetEntryLengthByNumber(18, 0x0002, 0x0010);
1145    } 
1146
1147    if (type == ExplicitVR) {
1148       std::string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1";
1149       ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010);
1150       
1151       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
1152       //      values with a VR of UI shall be padded with a single trailing null
1153       //      Dans le cas suivant on doit pader manuellement avec un 0
1154       
1155       PubEntrySet.SetEntryLengthByNumber(20, 0x0002, 0x0010);
1156    }
1157
1158    return PubEntrySet.Write(fp, type);
1159 }
1160
1161 /**
1162  * \ingroup   gdcmFile
1163  * \brief Sets the Pixel Area size in the Header
1164  *        --> not-for-rats function
1165  * 
1166  * \warning WARNING doit-etre etre publique ? 
1167  * TODO : y aurait il un inconvenient Ã  fusionner ces 2 fonctions
1168  *
1169  * @param ImageDataSize new Pixel Area Size
1170  *        warning : nothing else is checked
1171  */
1172 void gdcmHeader::SetImageDataSize(size_t ImageDataSize) {
1173    std::string content1;
1174    char car[20];        
1175    // Assumes HeaderEntry (0x7fe0, 0x0010) exists ...   
1176    sprintf(car,"%d",ImageDataSize);
1177  
1178    gdcmHeaderEntry *a = GetHeaderEntryByNumber(0x7fe0, 0x0010);
1179    a->SetLength(ImageDataSize);
1180                 
1181    ImageDataSize+=8;
1182    sprintf(car,"%d",ImageDataSize);
1183    content1=car;        
1184    SetPubEntryByNumber(content1, 0x7fe0, 0x0000);
1185 }
1186
1187 /**
1188  * \ingroup gdcmHeader
1189  * \brief   TODO
1190  * @param   Value
1191  * @param   Group
1192  * @param   Elem
1193  * \return integer acts as a boolean
1194  */
1195 bool gdcmHeader::ReplaceOrCreateByNumber(std::string Value, 
1196                                         guint16 Group, guint16 Elem ) {
1197         // TODO : FIXME JPRx
1198         // curieux, non ?
1199         // on (je) cree une HeaderEntry ne contenant pas de valeur
1200         // on l'ajoute au HeaderEntrySet
1201         // on affecte une valeur a cette HeaderEntry a l'interieur du HeaderEntrySet
1202         // --> devrait pouvoir etre fait + simplement ???
1203    if (CheckIfExistByNumber(Group, Elem) == 0) {
1204       gdcmHeaderEntry* a =NewHeaderEntryByNumber(Group, Elem);
1205       if (a == NULL) 
1206          return false;
1207       PubEntrySet.Add(a);
1208    }   
1209    PubEntrySet.SetEntryByNumber(Value, Group, Elem);
1210    return(true);
1211 }   
1212
1213 /**
1214  * \ingroup gdcmHeader
1215  * \brief   Modify (or Creates if not found) an element
1216  * @param   Value new value
1217  * @param   Group
1218  * @param   Elem
1219  * \return integer acts as a boolean 
1220  * 
1221  */
1222 bool gdcmHeader::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) {
1223
1224    gdcmHeaderEntry* nvHeaderEntry=NewHeaderEntryByNumber(Group, Elem);
1225    // TODO : check if fails
1226    PubEntrySet.Add(nvHeaderEntry);
1227    std::string v = Value;       
1228    PubEntrySet.SetEntryByNumber(v, Group, Elem);
1229    return(true);
1230 }  
1231
1232 /**
1233  * \ingroup gdcmHeader
1234  * \brief   Set a new value if the invoked element exists
1235  *          Seems to be useless !!!
1236  * @param   Value
1237  * @param   Group
1238  * @param   Elem
1239  * \return integer acts as a boolean 
1240  */
1241 bool gdcmHeader::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) {
1242
1243    //gdcmHeaderEntry* HeaderEntry = PubHeaderEntrySet.GetElementByNumber(Group, Elem);
1244    std::string v = Value;       
1245    PubEntrySet.SetEntryByNumber(v, Group, Elem);
1246    return true;
1247
1248
1249 /**
1250  * \ingroup gdcmHeader
1251  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
1252  *          processor order.
1253  * @return  The properly swaped 32 bits integer.
1254  */
1255 guint32 gdcmHeader::SwapLong(guint32 a) {
1256    switch (sw) {
1257    case    0 :
1258       break;
1259    case 4321 :
1260       a=(   ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
1261             ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
1262       break;
1263    
1264    case 3412 :
1265       a=(   ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
1266       break;
1267    
1268    case 2143 :
1269       a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
1270       break;
1271    default :
1272       dbg.Error(" gdcmHeader::SwapLong : unset swap code");
1273       a=0;
1274    }
1275    return(a);
1276 }
1277
1278 /**
1279  * \ingroup gdcmHeader
1280  * \brief   Swaps the bytes so they agree with the processor order
1281  * @return  The properly swaped 16 bits integer.
1282  */
1283 guint16 gdcmHeader::SwapShort(guint16 a) {
1284    if ( (sw==4321)  || (sw==2143) )
1285       a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
1286    return (a);
1287 }
1288
1289 //-----------------------------------------------------------------------------
1290 // Protected
1291 /**
1292  * \ingroup gdcmHeader
1293  * \brief   
1294  *
1295  * @return 
1296  */
1297 gdcmHeaderEntry *gdcmHeader::GetHeaderEntryByNumber(guint16 Group, guint16 Elem) {
1298    gdcmHeaderEntry *HeaderEntry = PubEntrySet.GetHeaderEntryByNumber(Group, Elem);       
1299    if (!HeaderEntry) {
1300       dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber",
1301                   "failed to Locate gdcmHeaderEntry");
1302       return NULL;
1303    }
1304    return HeaderEntry;
1305 }
1306
1307 /**
1308  * \ingroup gdcmHeader
1309  * \brief   Searches within the public dictionary for a Dicom Element of
1310  *          a given tag.
1311  * @param   tagName name of the searched Dicom Element.
1312  * @return  Corresponding Dicom Element when it exists, and NULL
1313  *          otherwise.
1314  */
1315  gdcmHeaderEntry *gdcmHeader::GetHeaderEntryByName(std::string tagName) {
1316    gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); 
1317    if( dictEntry == NULL)
1318       return NULL;
1319
1320   return(GetHeaderEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));
1321 }
1322
1323 /**
1324  * \ingroup gdcmHeader
1325  * \brief   Checks if a given HeaderEntry (group,number) 
1326  * \ exists in the Public HeaderEntrySet
1327  * @param   Group
1328  * @param   Elem
1329  * @return  integer acts as a boolean  
1330  */
1331 bool gdcmHeader::CheckIfExistByNumber(guint16 Group, guint16 Elem ) {
1332    return (PubEntrySet.CheckIfExistByNumber(Group, Elem)>0);
1333 }
1334
1335 /**
1336  * \ingroup gdcmHeader
1337  * \brief   Gets (from Header) the offset  of a 'non string' element value 
1338  * \        (LoadElementValue has already be executed)
1339  * @param   Group
1340  * @param   Elem
1341  * @return File Offset of the Element Value 
1342  */
1343 size_t gdcmHeader::GetPubEntryOffsetByNumber(guint16 Group, guint16 Elem) {
1344    gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem);         
1345    if (!Entry) {
1346       dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber",
1347                       "failed to Locate gdcmHeaderEntry");
1348       return (size_t)0;
1349    }
1350    return Entry->GetOffset();
1351 }
1352
1353 /**
1354  * \ingroup gdcmHeader
1355  * \brief   Gets (from Header) a 'non string' element value 
1356  * \        (LoadElementValue has already be executed)  
1357  * @param   Group
1358  * @param   Elem
1359  * @return Pointer to the 'non string' area
1360  */
1361 void * gdcmHeader::GetPubEntryVoidAreaByNumber(guint16 Group, guint16 Elem) {
1362    gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem);         
1363    if (!Entry) {
1364       dbg.Verbose(1, "gdcmHeader::GetHeaderEntryByNumber",
1365                   "failed to Locate gdcmHeaderEntry");
1366       return (NULL);
1367    }
1368    return Entry->GetVoidArea();
1369 }
1370
1371 /**
1372  * \ingroup       gdcmHeader
1373  * \brief         Loads (from disk) the element content 
1374  *                when a string is not suitable
1375  */
1376 void * gdcmHeader::LoadEntryVoidArea(guint16 Group, guint16 Elem) {
1377    gdcmHeaderEntry * Element= GetHeaderEntryByNumber(Group, Elem);
1378    if ( !Element )
1379       return NULL;
1380    size_t o =(size_t)Element->GetOffset();
1381    fseek(fp, o, SEEK_SET);
1382    int l=Element->GetLength();
1383    void * a = malloc(l);
1384    if(!a) {
1385         return NULL;
1386    }  
1387    
1388    PubEntrySet.SetVoidAreaByNumber(a, Group, Elem);
1389    // TODO check the result 
1390    size_t l2 = fread(a, 1, l ,fp);
1391    if(l != l2) {
1392         free(a);
1393         return NULL;
1394    }
1395    return a;  
1396 }
1397
1398 //-----------------------------------------------------------------------------
1399 // Private
1400 /**
1401  * \ingroup gdcmHeader
1402  * \brief   Loads the element values of all the elements present in the
1403  *          public tag based hash table.
1404  */
1405 void gdcmHeader::LoadHeaderEntries(void) {
1406    rewind(fp);
1407    
1408    // We don't use any longer the HashTable, since a lot a stuff is missing
1409    // when SeQuences were encountered 
1410    //  
1411    //TagHeaderEntryHT ht = PubHeaderEntrySet.GetTagHT();
1412    //for (TagHeaderEntryHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) {
1413    //     LoadElementValue(tag->second);
1414    //}
1415    
1416      for (ListTag::iterator i = GetPubListEntry().begin();  
1417            i != GetPubListEntry().end();
1418            ++i){
1419         LoadHeaderEntry(*i);   
1420      }    
1421     
1422    rewind(fp);
1423
1424    // Load 'non string' values   
1425    std::string PhotometricInterpretation = GetPubEntryByNumber(0x0028,0x0004);   
1426    if( PhotometricInterpretation == "PALETTE COLOR " ){ 
1427       LoadEntryVoidArea(0x0028,0x1200);  // gray LUT   
1428       LoadEntryVoidArea(0x0028,0x1201);  // R    LUT
1429       LoadEntryVoidArea(0x0028,0x1202);  // G    LUT
1430       LoadEntryVoidArea(0x0028,0x1203);  // B    LUT
1431       
1432       LoadEntryVoidArea(0x0028,0x1221);  // Segmented Red   Palette Color LUT Data
1433       LoadEntryVoidArea(0x0028,0x1222);  // Segmented Green Palette Color LUT Data
1434       LoadEntryVoidArea(0x0028,0x1223);  // Segmented Blue  Palette Color LUT Data
1435    }
1436
1437    // --------------------------------------------------------------
1438    // Special Patch to allow gdcm to read ACR-LibIDO formated images
1439    //
1440    // if recognition code tells us we deal with a LibIDO image
1441    // we switch lineNumber and columnNumber
1442    //
1443    std::string RecCode; 
1444    RecCode = GetPubEntryByNumber(0x0008, 0x0010);
1445    if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
1446        RecCode == "CANRME_AILIBOD1_1." ) {
1447          filetype = ACR_LIBIDO; 
1448          std::string rows    = GetPubEntryByNumber(0x0028, 0x0010);
1449          std::string columns = GetPubEntryByNumber(0x0028, 0x0011);
1450          SetPubEntryByNumber(columns, 0x0028, 0x0010);
1451          SetPubEntryByNumber(rows   , 0x0028, 0x0011);
1452    }
1453    // ----------------- End of Special Patch ----------------
1454 }
1455
1456 /**
1457  * \ingroup       gdcmHeader
1458  * \brief         Loads the element content if it's length is not bigger
1459  *                than the value specified with
1460  *                gdcmHeader::SetMaxSizeLoadElementValue()
1461  * @param        ElVal string value of the Dicom Element
1462  */
1463 void gdcmHeader::LoadHeaderEntry(gdcmHeaderEntry * ElVal) {
1464    size_t item_read;
1465    guint16 group  = ElVal->GetGroup();
1466    std::string  vr= ElVal->GetVR();
1467    guint32 length = ElVal->GetLength();
1468    bool SkipLoad  = false;
1469
1470    fseek(fp, (long)ElVal->GetOffset(), SEEK_SET);
1471    
1472    // the test was commented out to 'go inside' the SeQuences
1473    // we don't any longer skip them !
1474     
1475    // if( vr == "SQ" )  
1476    //    SkipLoad = true;
1477
1478    // A SeQuence "contains" a set of Elements.  
1479    //          (fffe e000) tells us an Element is beginning
1480    //          (fffe e00d) tells us an Element just ended
1481    //          (fffe e0dd) tells us the current SeQuence just ended
1482    if( group == 0xfffe )
1483       SkipLoad = true;
1484
1485    if ( SkipLoad ) {
1486       ElVal->SetLength(0);
1487       ElVal->SetValue("gdcm::Skipped");
1488       return;
1489    }
1490
1491    // When the length is zero things are easy:
1492    if ( length == 0 ) {
1493       ElVal->SetValue("");
1494       return;
1495    }
1496
1497    // The elements whose length is bigger than the specified upper bound
1498    // are not loaded. Instead we leave a short notice of the offset of
1499    // the element content and it's length.
1500    if (length > MaxSizeLoadElementValue) {
1501       std::ostringstream s;
1502       s << "gdcm::NotLoaded.";
1503       s << " Address:" << (long)ElVal->GetOffset();
1504       s << " Length:"  << ElVal->GetLength();
1505       s << " x(" << std::hex << ElVal->GetLength() << ")";
1506       ElVal->SetValue(s.str());
1507       return;
1508    }
1509    
1510    // When an integer is expected, read and convert the following two or
1511    // four bytes properly i.e. as an integer as opposed to a string.
1512         
1513         // Actually, elements with Value Multiplicity > 1
1514         // contain a set of integers (not a single one)         
1515         // Any compacter code suggested (?)
1516    if ( IsHeaderEntryAnInteger(ElVal) ) {
1517       guint32 NewInt;
1518       std::ostringstream s;
1519       int nbInt;
1520       if (vr == "US" || vr == "SS") {
1521          nbInt = length / 2;
1522          NewInt = ReadInt16();
1523          s << NewInt;
1524          if (nbInt > 1) {
1525             for (int i=1; i < nbInt; i++) {
1526                s << '\\';
1527                NewInt = ReadInt16();
1528                s << NewInt;
1529             }
1530          }
1531                         
1532       } else if (vr == "UL" || vr == "SL") {
1533          nbInt = length / 4;
1534          NewInt = ReadInt32();
1535          s << NewInt;
1536          if (nbInt > 1) {
1537             for (int i=1; i < nbInt; i++) {
1538                s << '\\';
1539                NewInt = ReadInt32();
1540                s << NewInt;
1541             }
1542          }
1543       }                                 
1544 #ifdef GDCM_NO_ANSI_STRING_STREAM
1545       s << std::ends; // to avoid oddities on Solaris
1546 #endif //GDCM_NO_ANSI_STRING_STREAM
1547       ElVal->SetValue(s.str());
1548       return;   
1549    }
1550    
1551    // We need an additional byte for storing \0 that is not on disk
1552    char* NewValue = (char*)malloc(length+1);
1553    if( !NewValue) {
1554       dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
1555       return;
1556    }
1557    NewValue[length]= 0;
1558    
1559    item_read = fread(NewValue, (size_t)length, (size_t)1, fp);
1560    if ( item_read != 1 ) {
1561       free(NewValue);
1562       dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value");
1563       ElVal->SetValue("gdcm::UnRead");
1564       return;
1565    }
1566    ElVal->SetValue(NewValue);
1567    free(NewValue);
1568 }
1569
1570 /**
1571  * \ingroup       gdcmHeader
1572  * \brief         Loads the element while preserving the current
1573  *                underlying file position indicator as opposed to
1574  *                to LoadElementValue that modifies it.
1575  * @param ElVal   Element whose value shall be loaded. 
1576  * @return  
1577  */
1578 void gdcmHeader::LoadHeaderEntrySafe(gdcmHeaderEntry * ElVal) {
1579    long PositionOnEntry = ftell(fp);
1580    LoadHeaderEntry(ElVal);
1581    fseek(fp, PositionOnEntry, SEEK_SET);
1582 }
1583
1584 /**
1585  * \ingroup gdcmHeader
1586  * \brief   
1587  *
1588  * @return 
1589  */
1590  void gdcmHeader::FindHeaderEntryLength (gdcmHeaderEntry * ElVal) {
1591    guint16 element = ElVal->GetElement();
1592    guint16 group   = ElVal->GetGroup();
1593    std::string  vr = ElVal->GetVR();
1594    guint16 length16;
1595    if( (element == 0x0010) && (group == 0x7fe0) ) {
1596       dbg.SetDebug(-1);
1597       dbg.Verbose(2, "gdcmHeader::FindLength: ",
1598                      "we reached 7fe0 0010");
1599    }   
1600    
1601    if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) {
1602       if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) {
1603       
1604          // The following reserved two bytes (see PS 3.5-2001, section
1605          // 7.1.2 Data element structure with explicit vr p27) must be
1606          // skipped before proceeding on reading the length on 4 bytes.
1607          fseek(fp, 2L, SEEK_CUR);
1608
1609          guint32 length32 = ReadInt32();
1610
1611          if ( (vr == "OB") && (length32 == 0xffffffff) ) {
1612             ElVal->SetLength(FindHeaderEntryLengthOB());
1613             return;
1614          }
1615          FixHeaderEntryFoundLength(ElVal, length32); 
1616          return;
1617       }
1618
1619       // Length is encoded on 2 bytes.
1620       length16 = ReadInt16();
1621       
1622       // We can tell the current file is encoded in big endian (like
1623       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
1624       // and it's value is the one of the encoding of a big endian file.
1625       // In order to deal with such big endian encoded files, we have
1626       // (at least) two strategies:
1627       // * when we load the "Transfer Syntax" tag with value of big endian
1628       //   encoding, we raise the proper flags. Then we wait for the end
1629       //   of the META group (0x0002) among which is "Transfer Syntax",
1630       //   before switching the swap code to big endian. We have to postpone
1631       //   the switching of the swap code since the META group is fully encoded
1632       //   in little endian, and big endian coding only starts at the next
1633       //   group. The corresponding code can be hard to analyse and adds
1634       //   many additional unnecessary tests for regular tags.
1635       // * the second strategy consists in waiting for trouble, that shall
1636       //   appear when we find the first group with big endian encoding. This
1637       //   is easy to detect since the length of a "Group Length" tag (the
1638       //   ones with zero as element number) has to be of 4 (0x0004). When we
1639       //   encounter 1024 (0x0400) chances are the encoding changed and we
1640       //   found a group with big endian encoding.
1641       // We shall use this second strategy. In order to make sure that we
1642       // can interpret the presence of an apparently big endian encoded
1643       // length of a "Group Length" without committing a big mistake, we
1644       // add an additional check: we look in the already parsed elements
1645       // for the presence of a "Transfer Syntax" whose value has to be "big
1646       // endian encoding". When this is the case, chances are we have got our
1647       // hands on a big endian encoded file: we switch the swap code to
1648       // big endian and proceed...
1649       if ( (element  == 0x0000) && (length16 == 0x0400) ) {
1650          if ( ! IsExplicitVRBigEndianTransferSyntax() ) {
1651             dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR");
1652             errno = 1;
1653             return;
1654          }
1655          length16 = 4;
1656          SwitchSwapToBigEndian();
1657          // Restore the unproperly loaded values i.e. the group, the element
1658          // and the dictionary entry depending on them.
1659          guint16 CorrectGroup   = SwapShort(ElVal->GetGroup());
1660          guint16 CorrectElem    = SwapShort(ElVal->GetElement());
1661          gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup,
1662                                                        CorrectElem);
1663          if (!NewTag) {
1664             // This correct tag is not in the dictionary. Create a new one.
1665             NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem);
1666          }
1667          // FIXME this can create a memory leaks on the old entry that be
1668          // left unreferenced.
1669          ElVal->SetDictEntry(NewTag);
1670       }
1671        
1672       // Heuristic: well some files are really ill-formed.
1673       if ( length16 == 0xffff) {
1674          length16 = 0;
1675          //dbg.Verbose(0, "gdcmHeader::FindLength",
1676          //            "Erroneous element length fixed.");
1677          // Actually, length= 0xffff means that we deal with
1678          // Unknown Sequence Length 
1679       }
1680
1681       FixHeaderEntryFoundLength(ElVal, (guint32)length16);
1682       return;
1683    }
1684
1685    // Either implicit VR or a non DICOM conformal (see not below) explicit
1686    // VR that ommited the VR of (at least) this element. Farts happen.
1687    // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
1688    // on Data elements "Implicit and Explicit VR Data Elements shall
1689    // not coexist in a Data Set and Data Sets nested within it".]
1690    // Length is on 4 bytes.
1691    FixHeaderEntryFoundLength(ElVal, ReadInt32());
1692    return;
1693 }
1694
1695 /**
1696  * \ingroup   gdcmHeader
1697  * \brief     Find the value representation of the current tag.
1698  * @param ElVal
1699  */
1700 void gdcmHeader::FindHeaderEntryVR( gdcmHeaderEntry *ElVal) {
1701    if (filetype != ExplicitVR)
1702       return;
1703
1704    char VR[3];
1705    std::string vr;
1706    int lgrLue;
1707    char msg[100]; // for sprintf. Sorry
1708
1709    long PositionOnEntry = ftell(fp);
1710    // Warning: we believe this is explicit VR (Value Representation) because
1711    // we used a heuristic that found "UL" in the first tag. Alas this
1712    // doesn't guarantee that all the tags will be in explicit VR. In some
1713    // cases (see e-film filtered files) one finds implicit VR tags mixed
1714    // within an explicit VR file. Hence we make sure the present tag
1715    // is in explicit VR and try to fix things if it happens not to be
1716    // the case.
1717    bool RealExplicit = true;
1718    
1719    lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
1720    VR[2]=0;
1721    vr = std::string(VR);
1722       
1723    // Assume we are reading a falsely explicit VR file i.e. we reached
1724    // a tag where we expect reading a VR but are in fact we read the
1725    // first to bytes of the length. Then we will interogate (through find)
1726    // the dicom_vr dictionary with oddities like "\004\0" which crashes
1727    // both GCC and VC++ implementations of the STL map. Hence when the
1728    // expected VR read happens to be non-ascii characters we consider
1729    // we hit falsely explicit VR tag.
1730
1731    if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) )
1732       RealExplicit = false;
1733
1734    // CLEANME searching the dicom_vr at each occurence is expensive.
1735    // PostPone this test in an optional integrity check at the end
1736    // of parsing or only in debug mode.
1737    if ( RealExplicit && !dicom_vr->Count(vr) )
1738       RealExplicit= false;
1739
1740    if ( RealExplicit ) {
1741       if ( ElVal->IsVRUnknown() ) {
1742          // When not a dictionary entry, we can safely overwrite the vr.
1743          ElVal->SetVR(vr);
1744          return; 
1745       }
1746       if ( ElVal->GetVR() == vr ) {
1747          // The vr we just read and the dictionary agree. Nothing to do.
1748          return;
1749       }
1750       // The vr present in the file and the dictionary disagree. We assume
1751       // the file writer knew best and use the vr of the file. Since it would
1752       // be unwise to overwrite the vr of a dictionary (since it would
1753       // compromise it's next user), we need to clone the actual DictEntry
1754       // and change the vr for the read one.
1755       gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(),
1756                                  ElVal->GetElement(),
1757                                  vr,
1758                                  "FIXME",
1759                                  ElVal->GetName());
1760       ElVal->SetDictEntry(NewTag);
1761       return; 
1762    }
1763    
1764    // We thought this was explicit VR, but we end up with an
1765    // implicit VR tag. Let's backtrack.   
1766    
1767       sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", 
1768                    ElVal->GetGroup(),ElVal->GetElement());
1769       dbg.Verbose(1, "gdcmHeader::FindVR: ",msg);
1770    
1771    fseek(fp, PositionOnEntry, SEEK_SET);
1772    // When this element is known in the dictionary we shall use, e.g. for
1773    // the semantics (see the usage of IsAnInteger), the vr proposed by the
1774    // dictionary entry. Still we have to flag the element as implicit since
1775    // we know now our assumption on expliciteness is not furfilled.
1776    // avoid  .
1777    if ( ElVal->IsVRUnknown() )
1778       ElVal->SetVR("Implicit");
1779    ElVal->SetImplicitVr();
1780 }
1781
1782 /**
1783  * \ingroup gdcmHeader
1784  * \brief   
1785  * @param ElVal 
1786  * @return 
1787  */
1788 void gdcmHeader::SkipHeaderEntry(gdcmHeaderEntry * ElVal) {
1789     SkipBytes(ElVal->GetLength());
1790 }
1791
1792 /**
1793  * \ingroup gdcmHeader
1794  * \brief   When the length of an element value is obviously wrong (because
1795  *          the parser went Jabberwocky) one can hope improving things by
1796  *          applying this heuristic.
1797  */
1798 void gdcmHeader::FixHeaderEntryFoundLength(gdcmHeaderEntry * ElVal, guint32 FoundLength) {
1799
1800    ElVal->SetReadLength(FoundLength); // will be updated only if a bug is found
1801                      
1802    if ( FoundLength == 0xffffffff) {  
1803       FoundLength = 0;
1804    }
1805       
1806       // Sorry for the patch!  
1807       // XMedCom did the trick to read some nasty GE images ...
1808    else if (FoundLength == 13) {
1809       // The following 'if' will be removed when there is no more
1810       // images on Creatis HDs with a 13 length for Manufacturer...
1811       if ( (ElVal->GetGroup() != 0x0008) ||  
1812            ( (ElVal->GetElement() != 0x0070) && (ElVal->GetElement() != 0x0080) ) ) {
1813       // end of remove area
1814          FoundLength =10;
1815          ElVal->SetReadLength(10); // a bug is to be fixed
1816       }
1817    } 
1818      // to fix some garbage 'Leonardo' Siemens images
1819      // May be commented out to avoid overhead
1820    else if ( (ElVal->GetGroup() == 0x0009) &&
1821        ( (ElVal->GetElement() == 0x1113) || (ElVal->GetElement() == 0x1114) ) ){
1822       FoundLength =4;
1823       ElVal->SetReadLength(4); // a bug is to be fixed 
1824    } 
1825      // end of fix
1826          
1827    // to try to 'go inside' SeQuences (with length), and not to skip them        
1828    else if ( ElVal->GetVR() == "SQ") { 
1829       if (enableSequences)    // only if the user does want to !
1830          FoundLength =0;         
1831    } 
1832     
1833
1834     // a SeQuence Element is beginning                                          
1835     // Let's forget it's length                                                 
1836     // (we want to 'go inside')  
1837     
1838     // Pb : *normaly*  fffe|e000 is just a marker, its length *should be* zero
1839     // in gdcm-MR-PHILIPS-16-Multi-Seq.dcm we find lengthes as big as 28800
1840     // if we set the length to zero IsAnInteger() breaks...
1841     // if we don't, we lost 28800 characters from the Header :-(
1842                                                  
1843    else if(ElVal->GetGroup() == 0xfffe){ 
1844       //printf("========================= %08x %d\n",FoundLength,FoundLength);
1845                          // sometimes, length seems to be wrong                                      
1846       //FoundLength =0;  // some more clever checking to be done !                                                     
1847    }     
1848     
1849    ElVal->SetUsableLength(FoundLength);
1850 }
1851
1852 /**
1853  * \ingroup gdcmHeader
1854  * \brief   Apply some heuristics to predict wether the considered 
1855  *          element value contains/represents an integer or not.
1856  * @param   ElVal The element value on which to apply the predicate.
1857  * @return  The result of the heuristical predicate.
1858  */
1859 bool gdcmHeader::IsHeaderEntryAnInteger(gdcmHeaderEntry * ElVal) {
1860    guint16 element = ElVal->GetElement();
1861    guint16 group   = ElVal->GetGroup();
1862    std::string  vr = ElVal->GetVR();
1863    guint32 length  = ElVal->GetLength();
1864
1865    // When we have some semantics on the element we just read, and if we
1866    // a priori know we are dealing with an integer, then we shall be
1867    // able to swap it's element value properly.
1868    if ( element == 0 )  {  // This is the group length of the group
1869       if (length == 4)
1870          return true;
1871       else {
1872          std::ostringstream s;
1873          s << "Erroneous Group Length element length  on :" \
1874            << std::hex << group << " , " << element;
1875          dbg.Error("gdcmHeader::IsAnInteger",
1876             s.str().c_str());     
1877       }
1878    }
1879    if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
1880       return true;
1881    
1882    return false;
1883 }
1884
1885 /**
1886  * \ingroup gdcmHeader
1887  * \brief   
1888  *
1889  * @return 
1890  */
1891  guint32 gdcmHeader::FindHeaderEntryLengthOB(void) {
1892    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
1893    guint16 g;
1894    guint16 n; 
1895    long PositionOnEntry = ftell(fp);
1896    bool FoundSequenceDelimiter = false;
1897    guint32 TotalLength = 0;
1898    guint32 ItemLength;
1899
1900    while ( ! FoundSequenceDelimiter) {
1901       g = ReadInt16();
1902       n = ReadInt16();   
1903       if (errno == 1)
1904          return 0;
1905       TotalLength += 4;  // We even have to decount the group and element 
1906      
1907       if ( g != 0xfffe && g!=0xb00c ) /*for bogus header */ {
1908          char msg[100]; // for sprintf. Sorry
1909          sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n);
1910          dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg); 
1911          errno = 1;
1912          return 0;
1913       }
1914       if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) /* for bogus header  */ 
1915          FoundSequenceDelimiter = true;
1916       else if ( n != 0xe000 ){
1917          char msg[100];  // for sprintf. Sorry
1918          sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n",
1919                       n, g,n);
1920          dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",msg);
1921          errno = 1;
1922          return 0;
1923       }
1924       ItemLength = ReadInt32();
1925       TotalLength += ItemLength + 4;  // We add 4 bytes since we just read
1926                                       // the ItemLength with ReadInt32                                     
1927       SkipBytes(ItemLength);
1928    }
1929    fseek(fp, PositionOnEntry, SEEK_SET);
1930    return TotalLength;
1931 }
1932
1933 /**
1934  * \ingroup gdcmHeader
1935  * \brief Reads a supposed to be 16 Bits integer
1936  * \     (swaps it depending on processor endianity) 
1937  *
1938  * @return integer acts as a boolean
1939  */
1940 guint16 gdcmHeader::ReadInt16(void) {
1941    guint16 g;
1942    size_t item_read;
1943    item_read = fread (&g, (size_t)2,(size_t)1, fp);
1944    if ( item_read != 1 ) {
1945       // dbg.Verbose(0, "gdcmHeader::ReadInt16", " Failed to read :");
1946       // if(feof(fp)) 
1947       //    dbg.Verbose(0, "gdcmHeader::ReadInt16", " End of File encountered");
1948       if(ferror(fp)) 
1949          dbg.Verbose(0, "gdcmHeader::ReadInt16", " File Error");
1950       errno = 1;
1951       return 0;
1952    }
1953    errno = 0;
1954    g = SwapShort(g);
1955    return g;
1956 }
1957
1958 /**
1959  * \ingroup gdcmHeader
1960  * \brief  Reads a supposed to be 32 Bits integer
1961  * \       (swaps it depending on processor endianity)  
1962  *
1963  * @return 
1964  */
1965 guint32 gdcmHeader::ReadInt32(void) {
1966    guint32 g;
1967    size_t item_read;
1968    item_read = fread (&g, (size_t)4,(size_t)1, fp);
1969    if ( item_read != 1 ) { 
1970       //dbg.Verbose(0, "gdcmHeader::ReadInt32", " Failed to read :");
1971       //if(feof(fp)) 
1972       //   dbg.Verbose(0, "gdcmHeader::ReadInt32", " End of File encountered");
1973      if(ferror(fp)) 
1974          dbg.Verbose(0, "gdcmHeader::ReadInt32", " File Error");   
1975       errno = 1;
1976       return 0;
1977    }
1978    errno = 0;   
1979    g = SwapLong(g);
1980    return g;
1981 }
1982
1983 /**
1984  * \ingroup gdcmHeader
1985  * \brief   
1986  *
1987  * @return 
1988  */
1989 void gdcmHeader::SkipBytes(guint32 NBytes) {
1990    //FIXME don't dump the returned value
1991    (void)fseek(fp, (long)NBytes, SEEK_CUR);
1992 }
1993
1994 /**
1995  * \ingroup gdcmHeader
1996  * \brief   
1997  */
1998 void gdcmHeader::Initialise(void) {
1999    dicom_vr = gdcmGlobal::GetVR();
2000    dicom_ts = gdcmGlobal::GetTS();
2001    Dicts    = gdcmGlobal::GetDicts();
2002    RefPubDict = Dicts->GetDefaultPubDict();
2003    RefShaDict = (gdcmDict*)0;
2004 }
2005
2006 /**
2007  * \ingroup gdcmHeader
2008  * \brief   Discover what the swap code is (among little endian, big endian,
2009  *          bad little endian, bad big endian).
2010  *
2011  */
2012 void gdcmHeader::CheckSwap()
2013 {
2014    // Fourth semantics:
2015    //
2016    // ---> Warning : This fourth field is NOT part 
2017    //                of the 'official' Dicom Dictionnary
2018    //                and should NOT be used.
2019    //                (Not defined for all the groups
2020    //                 may be removed in a future release)
2021    //
2022    // CMD      Command        
2023    // META     Meta Information 
2024    // DIR      Directory
2025    // ID
2026    // PAT      Patient
2027    // ACQ      Acquisition
2028    // REL      Related
2029    // IMG      Image
2030    // SDY      Study
2031    // VIS      Visit 
2032    // WAV      Waveform
2033    // PRC
2034    // DEV      Device
2035    // NMI      Nuclear Medicine
2036    // MED
2037    // BFS      Basic Film Session
2038    // BFB      Basic Film Box
2039    // BIB      Basic Image Box
2040    // BAB
2041    // IOB
2042    // PJ
2043    // PRINTER
2044    // RT       Radio Therapy
2045    // DVH   
2046    // SSET
2047    // RES      Results
2048    // CRV      Curve
2049    // OLY      Overlays
2050    // PXL      Pixels
2051    // DL       Delimiters
2052    //
2053
2054    // The only guaranted way of finding the swap code is to find a
2055    // group tag since we know it's length has to be of four bytes i.e.
2056    // 0x00000004. Finding the swap code in then straigthforward. Trouble
2057    // occurs when we can't find such group...
2058    guint32  s;
2059    guint32  x=4;  // x : for ntohs
2060    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
2061     
2062    int lgrLue;
2063    char * entCur;
2064    char deb[HEADER_LENGTH_TO_READ];
2065     
2066    // First, compare HostByteOrder and NetworkByteOrder in order to
2067    // determine if we shall need to swap bytes (i.e. the Endian type).
2068    if (x==ntohs(x))
2069       net2host = true;
2070    else
2071       net2host = false; 
2072     //cout << net2host << endl;
2073          
2074    // The easiest case is the one of a DICOM header, since it possesses a
2075    // file preamble where it suffice to look for the string "DICM".
2076    lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp);
2077    
2078    entCur = deb + 128;
2079    if(memcmp(entCur, "DICM", (size_t)4) == 0) {
2080       dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
2081       // Next, determine the value representation (VR). Let's skip to the
2082       // first element (0002, 0000) and check there if we find "UL" 
2083       // - or "OB" if the 1st one is (0002,0001) -,
2084       // in which case we (almost) know it is explicit VR.
2085       // WARNING: if it happens to be implicit VR then what we will read
2086       // is the length of the group. If this ascii representation of this
2087       // length happens to be "UL" then we shall believe it is explicit VR.
2088       // FIXME: in order to fix the above warning, we could read the next
2089       // element value (or a couple of elements values) in order to make
2090       // sure we are not commiting a big mistake.
2091       // We need to skip :
2092       // * the 128 bytes of File Preamble (often padded with zeroes),
2093       // * the 4 bytes of "DICM" string,
2094       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
2095       // i.e. a total of  136 bytes.
2096       entCur = deb + 136;
2097       // FIXME
2098       // Use gdcmHeader::dicom_vr to test all the possibilities
2099       // instead of just checking for UL, OB and UI !?
2100       if(  (memcmp(entCur, "UL", (size_t)2) == 0) ||
2101            (memcmp(entCur, "OB", (size_t)2) == 0) ||
2102            (memcmp(entCur, "UI", (size_t)2) == 0) )   
2103       {
2104          filetype = ExplicitVR;
2105          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
2106                      "explicit Value Representation");
2107       } else {
2108          filetype = ImplicitVR;
2109          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
2110                      "not an explicit Value Representation");
2111       }
2112       if (net2host) {
2113          sw = 4321;
2114          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
2115                         "HostByteOrder != NetworkByteOrder");
2116       } else {
2117          sw = 0;
2118          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
2119                         "HostByteOrder = NetworkByteOrder");
2120       }
2121       
2122       // Position the file position indicator at first tag (i.e.
2123       // after the file preamble and the "DICM" string).
2124       rewind(fp);
2125       fseek (fp, 132L, SEEK_SET);
2126       return;
2127    } // End of DicomV3
2128
2129    // Alas, this is not a DicomV3 file and whatever happens there is no file
2130    // preamble. We can reset the file position indicator to where the data
2131    // is (i.e. the beginning of the file).
2132     dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
2133    rewind(fp);
2134
2135    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
2136    // By clean we mean that the length of the first tag is written down.
2137    // If this is the case and since the length of the first group HAS to be
2138    // four (bytes), then determining the proper swap code is straightforward.
2139
2140    entCur = deb + 4;
2141    // We assume the array of char we are considering contains the binary
2142    // representation of a 32 bits integer. Hence the following dirty
2143    // trick :
2144    s = *((guint32 *)(entCur));
2145    
2146    switch (s) {
2147    case 0x00040000 :
2148       sw = 3412;
2149       filetype = ACR;
2150       return;
2151    case 0x04000000 :
2152       sw = 4321;
2153       filetype = ACR;
2154       return;
2155    case 0x00000400 :
2156       sw = 2143;
2157       filetype = ACR;
2158       return;
2159    case 0x00000004 :
2160       sw = 0;
2161       filetype = ACR;
2162       return;
2163    default :
2164       dbg.Verbose(0, "gdcmHeader::CheckSwap:",
2165                      "ACR/NEMA unfound swap info (time to raise bets)");
2166    }
2167
2168    // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
2169    // It is time for despaired wild guesses. So, let's assume this file
2170    // happens to be 'dirty' ACR/NEMA, i.e. the length of the group is
2171    // not present. Then the only info we have is the net2host one.
2172    filetype = Unknown;
2173    if (! net2host )
2174       sw = 0;
2175    else
2176       sw = 4321;
2177    return;
2178 }
2179
2180 /**
2181  * \ingroup gdcmHeader
2182  * \brief   
2183  */
2184 void gdcmHeader::SwitchSwapToBigEndian(void) {
2185    dbg.Verbose(1, "gdcmHeader::SwitchSwapToBigEndian",
2186                   "Switching to BigEndian mode.");
2187    if ( sw == 0    ) {
2188       sw = 4321;
2189       return;
2190    }
2191    if ( sw == 4321 ) {
2192       sw = 0;
2193       return;
2194    }
2195    if ( sw == 3412 ) {
2196       sw = 2143;
2197       return;
2198    }
2199    if ( sw == 2143 )
2200       sw = 3412;
2201 }
2202
2203 /**
2204  * \ingroup gdcmHeader
2205  * \brief   
2206  * @param NewSize
2207  * @return 
2208  */
2209 void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) {
2210    if (NewSize < 0)
2211       return;
2212    if ((guint32)NewSize >= (guint32)0xffffffff) {
2213       MaxSizeLoadElementValue = 0xffffffff;
2214       return;
2215    }
2216    MaxSizeLoadElementValue = NewSize;
2217 }
2218
2219 /**
2220  * \ingroup gdcmHeader
2221  * \brief   Searches both the public and the shadow dictionary (when they
2222  *          exist) for the presence of the DictEntry with given
2223  *          group and element. The public dictionary has precedence on the
2224  *          shadow one.
2225  * @param   group   group of the searched DictEntry
2226  * @param   element element of the searched DictEntry
2227  * @return  Corresponding DictEntry when it exists, NULL otherwise.
2228  */
2229 gdcmDictEntry * gdcmHeader::GetDictEntryByNumber(guint16 group,
2230                                                  guint16 element) {
2231    gdcmDictEntry * found = (gdcmDictEntry*)0;
2232    if (!RefPubDict && !RefShaDict) {
2233       dbg.Verbose(0, "gdcmHeader::GetDictEntry",
2234                      "we SHOULD have a default dictionary");
2235    }
2236    if (RefPubDict) {
2237       found = RefPubDict->GetTagByNumber(group, element);
2238       if (found)
2239          return found;
2240    }
2241    if (RefShaDict) {
2242       found = RefShaDict->GetTagByNumber(group, element);
2243       if (found)
2244          return found;
2245    }
2246    return found;
2247 }
2248
2249 /**
2250  * \ingroup gdcmHeader
2251  * \brief   Searches both the public and the shadow dictionary (when they
2252  *          exist) for the presence of the DictEntry with given name.
2253  *          The public dictionary has precedence on the shadow one.
2254  * @param   Name name of the searched DictEntry
2255  * @return  Corresponding DictEntry when it exists, NULL otherwise.
2256  */
2257 gdcmDictEntry * gdcmHeader::GetDictEntryByName(std::string Name) {
2258    gdcmDictEntry * found = (gdcmDictEntry*)0;
2259    if (!RefPubDict && !RefShaDict) {
2260       dbg.Verbose(0, "gdcmHeader::GetDictEntry",
2261                      "we SHOULD have a default dictionary");
2262    }
2263    if (RefPubDict) {
2264       found = RefPubDict->GetTagByName(Name);
2265       if (found)
2266          return found;
2267    }
2268    if (RefShaDict) {
2269       found = RefShaDict->GetTagByName(Name);
2270       if (found)
2271          return found;
2272    }
2273    return found;
2274 }
2275
2276 /**
2277  * \ingroup gdcmHeader
2278  * \brief   Read the next tag but WITHOUT loading it's value
2279  * @return  On succes the newly created HeaderEntry, NULL on failure.      
2280  */
2281 gdcmHeaderEntry * gdcmHeader::ReadNextHeaderEntry(void) {
2282   
2283    guint16 g,n;
2284    gdcmHeaderEntry * NewElVal;
2285    
2286    g = ReadInt16();
2287    n = ReadInt16();
2288       
2289    if (errno == 1)
2290       // We reached the EOF (or an error occured) and header parsing
2291       // has to be considered as finished.
2292       return (gdcmHeaderEntry *)0;
2293    
2294    NewElVal = NewHeaderEntryByNumber(g, n);
2295    FindHeaderEntryVR(NewElVal);
2296    FindHeaderEntryLength(NewElVal);
2297         
2298    if (errno == 1) {
2299       // Call it quits
2300       return (gdcmHeaderEntry *)0;
2301    }
2302    NewElVal->SetOffset(ftell(fp));  
2303    //if ( (g==0x7fe0) && (n==0x0010) ) 
2304    return NewElVal;
2305 }
2306
2307 /**
2308  * \ingroup gdcmHeader
2309  * \brief   Build a new Element Value from all the low level arguments. 
2310  *          Check for existence of dictionary entry, and build
2311  *          a default one when absent.
2312  * @param   Name    Name of the underlying DictEntry
2313  */
2314 gdcmHeaderEntry* gdcmHeader::NewHeaderEntryByName(std::string Name) {
2315
2316    gdcmDictEntry * NewTag = GetDictEntryByName(Name);
2317    if (!NewTag)
2318       NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
2319
2320    gdcmHeaderEntry* NewElVal = new gdcmHeaderEntry(NewTag);
2321    if (!NewElVal) {
2322       dbg.Verbose(1, "gdcmHeader::ObtainHeaderEntryByName",
2323                   "failed to allocate gdcmHeaderEntry");
2324       return (gdcmHeaderEntry*)0;
2325    }
2326    return NewElVal;
2327 }  
2328
2329 /**
2330  * \ingroup gdcmHeader
2331  * \brief   Build a new Element Value from all the low level arguments. 
2332  *          Check for existence of dictionary entry, and build
2333  *          a default one when absent.
2334  * @param   Group group   of the underlying DictEntry
2335  * @param   Elem  element of the underlying DictEntry
2336  */
2337 gdcmHeaderEntry* gdcmHeader::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) {
2338    // Find out if the tag we encountered is in the dictionaries:
2339    gdcmDictEntry * NewTag = GetDictEntryByNumber(Group, Elem);
2340    if (!NewTag)
2341       NewTag = new gdcmDictEntry(Group, Elem);
2342
2343    gdcmHeaderEntry* NewElVal = new gdcmHeaderEntry(NewTag);
2344    if (!NewElVal) {
2345       dbg.Verbose(1, "gdcmHeader::NewHeaderEntryByNumber",
2346                   "failed to allocate gdcmHeaderEntry");
2347       return (gdcmHeaderEntry*)0;
2348    }
2349    return NewElVal;
2350 }
2351
2352 /**
2353  * \ingroup gdcmHeader
2354  * \brief   Small utility function that creates a new manually crafted
2355  *          (as opposed as read from the file) gdcmHeaderEntry with user
2356  *          specified name and adds it to the public tag hash table.
2357  * \note    A fake TagKey is generated so the PubDict can keep it's coherence.
2358  * @param   NewTagName The name to be given to this new tag.
2359  * @param   VR The Value Representation to be given to this new tag.
2360  * @ return The newly hand crafted Element Value.
2361  */
2362 gdcmHeaderEntry* gdcmHeader::NewManualHeaderEntryToPubDict(std::string NewTagName, 
2363                                                            std::string VR) {
2364    gdcmHeaderEntry* NewElVal = (gdcmHeaderEntry*)0;
2365    guint32 StuffGroup = 0xffff;   // Group to be stuffed with additional info
2366    guint32 FreeElem = 0;
2367    gdcmDictEntry* NewEntry = (gdcmDictEntry*)0;
2368
2369    FreeElem = PubEntrySet.GenerateFreeTagKeyInGroup(StuffGroup);
2370    if (FreeElem == UINT32_MAX) {
2371       dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict",
2372                      "Group 0xffff in Public Dict is full");
2373       return (gdcmHeaderEntry*)0;
2374    }
2375    NewEntry = new gdcmDictEntry(StuffGroup, FreeElem,
2376                                 VR, "GDCM", NewTagName);
2377    NewElVal = new gdcmHeaderEntry(NewEntry);
2378    PubEntrySet.Add(NewElVal);
2379    return NewElVal;
2380 }
2381
2382 //-----------------------------------------------------------------------------