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