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