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