]> Creatis software - gdcm.git/blob - src/gdcmDataEntry.cxx
833be232f3c7efc3d1f29f4f3fad5c568ca0987c
[gdcm.git] / src / gdcmDataEntry.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDataEntry.cxx,v $
5   Language:  C++
6   Date:      $Date: 2008/04/10 12:15:35 $
7   Version:   $Revision: 1.54 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmDataEntry.h"
20 #include "gdcmVR.h"
21 #include "gdcmTS.h"
22 #include "gdcmGlobal.h"
23 #include "gdcmUtil.h"
24 #include "gdcmDebug.h"
25
26 #include <fstream>
27
28 #if defined(__BORLANDC__)
29  #include <mem.h>    // for memcpy
30  #include <stdlib.h> // for atof
31  #include <ctype.h>  // for isdigit
32 #endif
33 #include <string.h> // memcpy
34 #include <stdlib.h> // atof
35
36 // Could be defined like MAX_SIZE_LOAD_ELEMENT_VALUE
37 #define GDCM_MAX_LENGTH_TO_CONVERT_TO_HEXA 8
38
39 namespace GDCM_NAME_SPACE 
40 {
41 //-----------------------------------------------------------------------------
42 #define MAX_SIZE_PRINT_ELEMENT_VALUE 0x7fffffff
43 uint32_t DataEntry::MaxSizePrintEntry = MAX_SIZE_PRINT_ELEMENT_VALUE;
44
45 //-----------------------------------------------------------------------------
46 // Constructor / Destructor
47 /**
48  * \brief   Constructor for a given DataEntry
49  * @param   group group number of the Data Entry to be created
50  * @param   elem element number of the Data Entry to be created
51  * @param   vr Value Representation of the Data Entry to be created 
52  */
53 DataEntry::DataEntry(uint16_t group,uint16_t elem,
54                                      VRKey const &vr) 
55             : DocEntry(group,elem,vr)
56 {
57    State = STATE_LOADED;
58    Flag = FLAG_NONE;
59
60    StrArea     = 0;
61    StrHexaArea = 0;   
62    BinArea     = 0;
63    SelfArea    = true;
64 }
65
66 /**
67  * \brief   Constructor for a given DocEntry
68  * @param   e Pointer to existing Doc entry
69  */
70 DataEntry::DataEntry(DocEntry *e)
71             //: DocEntry(e->GetDictEntry())
72             : DocEntry(e->GetGroup(),e->GetElement(), e->GetVR()  )
73 {
74    Flag = FLAG_NONE;
75    BinArea = 0;
76    
77    SelfArea = true;
78
79    Copy(e);
80 }
81
82 /**
83  * \brief   Canonical destructor.
84  */
85 DataEntry::~DataEntry ()
86 {
87    DeleteBinArea();
88    
89 }
90
91 //-----------------------------------------------------------------------------
92 // Public
93 /**
94  * \brief Sets the value (non string) of the current DataEntry
95  * @param area area
96  * @param self self=true : The area : *belongs" to the DataEntry 
97  *                                  : will be delete with the DataEntry
98  *             self=false  The area *is not* deleted with the DataEntry
99  *              
100  */
101 void DataEntry::SetBinArea( uint8_t *area, bool self )  
102
103    DeleteBinArea();
104
105    BinArea = area;
106    SelfArea = self;
107
108    State = STATE_LOADED;
109 }
110 /**
111  * \brief Inserts the value (non string) into the current DataEntry
112  * @param area area
113  * @param length length 
114  */
115 void DataEntry::CopyBinArea( uint8_t *area, uint32_t length )
116 {
117    DeleteBinArea();
118
119    uint32_t lgh = length + length%2;
120    SetLength(lgh);
121
122    if( area && length > 0 )
123    {
124       NewBinArea();
125       memcpy(BinArea,area,length);
126       if( length!=lgh )
127          BinArea[length]=0; // padd with zero
128
129       State = STATE_LOADED;
130    }
131 }
132
133 /**
134  * \brief Inserts the elementary (non string) value into the current DataEntry
135  * @param id index of the elementary value to be set
136  * @param val value, passed as a double 
137  */
138 void DataEntry::SetValue(const uint32_t &id, const double &val)
139 {
140    if( !BinArea )
141       NewBinArea();
142    State = STATE_LOADED;
143
144    if( id > GetValueCount() )
145    {
146       gdcmErrorMacro("Index (" << id << ") is greater than the data size");
147       return;
148    }
149
150    const VRKey &vr = GetVR();
151    if( vr == "US" || vr == "SS" )
152    {
153       uint16_t *data = (uint16_t *)BinArea;
154       data[id] = (uint16_t)val;
155    }
156    else if( vr == "UL" || vr == "SL" )
157    {
158       uint32_t *data = (uint32_t *)BinArea;
159       data[id] = (uint32_t)val;
160    }
161    else if( vr == "FL" )
162    {
163       float *data = (float *)BinArea;
164       data[id] = (float)val;
165    }
166    else if( vr == "FD" )
167    {
168       double *data = (double *)BinArea;
169       data[id] = (double)val;
170    }
171    else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
172    {
173       gdcmErrorMacro("SetValue on String representable not implemented yet");
174    }
175    else
176    {
177       BinArea[id] = (uint8_t)val;
178    }
179 }
180 /**
181  * \brief returns, as a double one of the values 
182  *      (when entry is multivaluated), identified by its index.
183  *      Returns 0.0 if index is wrong
184  * @param id id
185  */
186 double DataEntry::GetValue(const uint32_t &id) const
187 {
188    if( !BinArea )
189    {
190       if (GetLength() != 0) // avoid stupid messages
191    /// \todo warn the user there was a problem !
192          gdcmErrorMacro("BinArea not set " << std::hex 
193                      << GetGroup() << " " << GetElement() 
194                      << " Can't get the value");
195       return 0.0;
196    }
197
198    uint32_t count = GetValueCount();
199    if( id > count )
200    {
201       gdcmErrorMacro("Index (" << id << ") is greater than the data size");
202       return 0.0;
203    }
204
205    // if user *knows* that entry contains a US, 
206    // he just has to cast the double he receives
207    
208    const VRKey &vr = GetVR();
209
210    if( vr == "US" || vr == "SS" )
211       return ((uint16_t *)BinArea)[id];
212    else if( vr == "UL" || vr == "SL" )
213       return ((uint32_t *)BinArea)[id];
214    else if( vr == "FL" )
215       return ((float *)BinArea)[id];
216    else if( vr == "FD" )
217       return ((double *)BinArea)[id];
218    else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
219    {
220       // this is for VR = "DS", ...
221       if( GetLength() )
222       {
223          // Don't use std::string to accelerate processing
224          double val;
225          char *tmp = new char[GetLength()+1];
226          memcpy(tmp,BinArea,GetLength());
227          tmp[GetLength()]=0;
228
229          if( count == 0 )
230          {
231             val = atof(tmp);
232          }
233          else
234          {
235             count = id;
236             char *beg = tmp;
237             for(uint32_t i=0;i<GetLength();i++)
238             {
239                if( tmp[i] == '\\' )
240                {
241                   if( count == 0 )
242                   {
243                      tmp[i] = 0;
244                      break;
245                   }
246                   else
247                   {
248                      count--;
249                      beg = &(tmp[i+1]);
250                   }
251                }
252             }
253             val = atof(beg);
254          }
255
256          delete[] tmp;
257          return val;
258       }
259       else 
260          return 0.0;
261    }
262    else
263       return BinArea[id];
264 }
265
266 /**
267  * \brief Checks if the multiplicity of the value follows Dictionary VM
268  */
269 bool DataEntry::IsValueCountValid() /*const*/
270 {
271   uint32_t vm;
272   const std::string &strVM = GetVM();
273   uint32_t vc = GetValueCount();
274   bool valid = vc == 0;
275   if( valid )
276     return true;
277   
278   // FIXME : what shall we do with VM = "2-n", "3-n", etc
279   
280   if( strVM == "1-n" )
281   {
282     // make sure there is at least one ??? FIXME
283     valid = vc >= 1;
284   }
285   else
286   {
287     std::istringstream os;
288     os.str( strVM );
289     os >> vm;
290     // Two cases:
291     // vm respects the one from the dict
292     // vm is 0 (we need to check if this element is allowed to be empty) FIXME
293
294     // note  (JPR)
295     // ----    
296     // Entries whose type is 1 are mandatory, with a mandatory value.
297     // Entries whose type is 1c are mandatory-inside-a-Sequence,
298     //                          with a mandatory value.
299     // Entries whose type is 2 are mandatory, with an optional value.
300     // Entries whose type is 2c are mandatory-inside-a-Sequence,
301     //                          with an optional value.
302     // Entries whose type is 3 are optional.
303
304     // case vc == 0 is only applicable for 'type 2' entries.
305     // Problem : entry type may depend on the modality and/or the Sequence
306     //           it's embedded in !
307     //          (Get the information in the 'Conformance Statements' ...)  
308     valid = vc == vm;
309   }
310   return valid;
311 }
312
313 /**
314  * \brief returns the number of elementary values
315  */ 
316 uint32_t DataEntry::GetValueCount( ) const
317 {
318    const VRKey &vr = GetVR();
319    if( vr == "US" || vr == "SS" )
320       return GetLength()/sizeof(uint16_t);
321    else if( vr == "UL" || vr == "SL" )
322       return GetLength()/sizeof(uint32_t);
323    else if( vr == "FL" || vr == "OF" )
324       return GetLength()/4 ; // FL has a *4* length! sizeof(float);
325    else if( vr == "FD" )
326       return GetLength()/8;  // FD has a *8* length! sizeof(double);
327    else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
328    {
329       // Some element in DICOM are allowed to be empty
330       if( !GetLength() ) 
331          return 0;
332       // Don't use std::string to accelerate processing
333       uint32_t count = 1;
334       for(uint32_t i=0;i<GetLength();i++)
335       {
336          if( BinArea[i] == '\\')
337             count++;
338       }
339       return count;
340    }
341    return GetLength();
342 }
343
344 /**
345  * \brief Gets a std::vector of 'double' holding the value(s) of a DS DataEntry
346  * @param valueVector std::vector double of value(s)
347  * \return false if VR not "DS" or DataEntry empty
348  */
349  bool DataEntry::GetDSValue(std::vector <double> &valueVector)
350  {
351     /// \todo rewrite the whole method, in order *not to use* std::string !
352     std::vector<std::string> tokens;
353     
354     if (GetVR() != "DS") // never trust a user !
355        return false;    
356        
357     Util::Tokenize ( GetString().c_str(), tokens, "\\" );
358         
359     int nbValues= tokens.size();
360     if (nbValues == 0)
361        return false;
362                
363     for (int loop=0; loop<nbValues; loop++) 
364        valueVector.push_back(atof(tokens[loop].c_str()));
365     
366     return true;  
367  }
368  
369 /**
370  * \brief Sets the 'value' of a DataEntry, passed as a std::string
371  * @param value string representation of the value to be set
372  */ 
373 void DataEntry::SetString(std::string const &value)
374 {
375    DeleteBinArea();
376    const VRKey &vr = GetVR();
377    if ( vr == "US" || vr == "SS" )
378    {
379       std::vector<std::string> tokens;
380       Util::Tokenize (value, tokens, "\\");
381       SetLength(tokens.size()*sizeof(uint16_t));
382       NewBinArea();
383
384       uint16_t *data = (uint16_t *)BinArea;
385       for (unsigned int i=0; i<tokens.size();i++)
386          data[i] = atoi(tokens[i].c_str());
387       tokens.clear();
388    }
389    else if ( vr == "UL" || vr == "SL" )
390    {
391       std::vector<std::string> tokens;
392       Util::Tokenize (value, tokens, "\\");
393       SetLength(tokens.size()*sizeof(uint32_t));
394       NewBinArea();
395
396       uint32_t *data = (uint32_t *)BinArea;
397       for (unsigned int i=0; i<tokens.size();i++)
398          data[i] = atoi(tokens[i].c_str());
399       tokens.clear();
400    }
401    else if ( vr == "FL" )
402    {
403       std::vector<std::string> tokens;
404       Util::Tokenize (value, tokens, "\\");
405       SetLength(tokens.size()*sizeof(float));
406       NewBinArea();
407
408       float *data = (float *)BinArea;
409       for (unsigned int i=0; i<tokens.size();i++)
410          data[i] = (float)atof(tokens[i].c_str());
411       tokens.clear();
412    }
413    else if ( vr == "FD" )
414    {
415       std::vector<std::string> tokens;
416       Util::Tokenize (value, tokens, "\\");
417       SetLength(tokens.size()*sizeof(double));
418       NewBinArea();
419
420       double *data = (double *)BinArea;
421       for (unsigned int i=0; i<tokens.size();i++)
422          data[i] = atof(tokens[i].c_str());
423       tokens.clear();
424    }
425    else
426    {      
427       size_t l =  value.size();    
428       SetLength(l + l%2);
429       NewBinArea();
430       memcpy(BinArea, value.c_str(), l);
431       if (l%2) // padded with blank except for UI
432         {
433         if ( vr == "UI" )
434           BinArea[l] = '\0';
435         else
436           BinArea[l] = ' ';
437         }
438    }
439    State = STATE_LOADED;
440 }
441 /**
442  * \brief   returns as a string (when possible) the value of the DataEntry
443  */
444 std::string const &DataEntry::GetString() const
445 {
446   static std::ostringstream s;
447   const VRKey &vr = GetVR();
448   s.str("");
449   
450   if (!StrArea)
451      StrArea = new std::string();
452   else 
453      *StrArea="";
454
455   if( !BinArea )
456      return *StrArea;
457   // When short integer(s) are stored, convert the following (n * 2) characters
458   // as a displayable string, the values being separated by a back-slash
459   if( vr == "US" )
460   {
461      uint16_t *data=(uint16_t *)BinArea;
462      for (unsigned int i=0; i < GetValueCount(); i++)
463      {
464         if( i!=0 )
465            s << '\\';
466         s << data[i];
467      }
468      *StrArea=s.str();
469   }
470   else if (vr == "SS" )
471   {
472      int16_t *data=(int16_t *)BinArea;
473      for (unsigned int i=0; i < GetValueCount(); i++)
474      {
475         if( i!=0 )
476            s << '\\';
477         s << data[i];
478      }
479      *StrArea=s.str();
480   }      // See above comment on multiple short integers (mutatis mutandis).
481   else if( vr == "UL" )
482   {
483      uint32_t *data=(uint32_t *)BinArea;
484      for (unsigned int i=0; i < GetValueCount(); i++)
485      {
486         if( i!=0 )
487            s << '\\';
488         s << data[i];
489      }
490      *StrArea=s.str();
491   }
492   else if( vr == "SL" )
493   {
494      int32_t *data=(int32_t *)BinArea;
495      for (unsigned int i=0; i < GetValueCount(); i++)
496      {
497         if( i!=0 )
498            s << '\\';
499         s << data[i];
500      }
501      *StrArea=s.str();
502   }     // See above comment on multiple short integers (mutatis mutandis).
503   else if( vr == "FL" )
504   {
505      float *data=(float *)BinArea;
506      for (unsigned int i=0; i < GetValueCount(); i++)
507      {
508         if( i!=0 )
509            s << '\\';
510         s << data[i];
511      }
512      *StrArea=s.str();
513   }     // See above comment on multiple short integers (mutatis mutandis).
514   else if( vr == "FD" )
515   {
516      double *data=(double *)BinArea;
517      for (unsigned int i=0; i < GetValueCount(); i++)
518      {
519         if( i!=0 )
520            s << '\\';
521         s << data[i];
522      }
523      *StrArea=s.str();
524   }
525   else
526   {
527      StrArea->append((const char *)BinArea,GetLength());
528      // to avoid gdcm to propagate oddities in lengthes
529      if ( GetLength()%2)
530         StrArea->append(" ",1);
531    }
532   return *StrArea;
533 }
534
535 /**
536  * \brief   returns an hexadecimal representation of the DataEntry value
537  */
538 std::string const &DataEntry::GetHexaRepresentation() const
539
540   static std::ostringstream s2;
541   const VRKey &vr = GetVR();
542    
543   s2.str("");
544   if (!StrHexaArea)
545      StrHexaArea = new std::string();
546   else 
547      *StrHexaArea="";
548   if( !BinArea )
549      return *StrHexaArea;
550   // When short integer(s) are stored, convert the following (n * 2) characters
551   // as a displayable string, the values being separated by a back-slash
552   
553   s2 << std::hex;
554   
555   if( vr == "US" )
556   {
557      uint16_t *data=(uint16_t *)BinArea;
558      for (unsigned int i=0; i < GetValueCount(); i++)
559      {
560         s2  << std::setw( 2 ) << std::setfill( '0' );     
561         if( i!=0 )
562            s2 << '\\';
563         s2 << data[i];
564      }
565      *StrHexaArea=s2.str();
566   }
567   else if (vr == "SS" )
568   {
569      int16_t *data=(int16_t *)BinArea;
570      for (unsigned int i=0; i < GetValueCount(); i++)
571      {
572         s2  << std::setw( 4 ) << std::setfill( '0' );
573         if( i!=0 )
574            s2 << '\\';
575         s2  << data[i];
576      }
577      *StrHexaArea=s2.str();
578   }      // See above comment on multiple short integers (mutatis mutandis).
579   else if( vr == "UL" )
580   {
581      uint32_t *data=(uint32_t *)BinArea;
582      for (unsigned int i=0; i < GetValueCount(); i++)
583      {
584         s2  << std::setw( 4 ) << std::setfill( '0' );
585         if( i!=0 ) 
586            s2  << '\\';
587         s2 << data[i];
588      }
589      *StrHexaArea=s2.str();
590   }
591   else if( vr == "SL" )
592   {
593      int32_t *data=(int32_t *)BinArea;
594      for (unsigned int i=0; i < GetValueCount(); i++)
595      {
596         s2  << std::setw( 4 ) << std::setfill( '0' );
597          if( i!=0 )
598            s2  << '\\';
599         s2 << data[i];
600      }
601      *StrHexaArea=s2.str();
602   }
603   else if( vr == "FL" )
604   {
605      unsigned char *toto=(unsigned char *)BinArea;
606      for (unsigned int i=0; i < GetValueCount(); i++)
607      {
608          s2.str("");
609          if( i!=0 )
610            s2 << '\\';
611          unsigned int a4;
612          for(int iif=0; iif<4; iif++)
613          {
614             a4=toto[iif];
615             s2 << a4; 
616          }
617      }
618      *StrHexaArea=s2.str();
619   }
620   else if( vr == "FD" )
621   {
622      //double *data=(double *)BinArea;
623      unsigned char *toto=(unsigned char *)BinArea;
624      for (unsigned int i=0; i < GetValueCount(); i++)
625      {
626         s2.str("");
627         if( i!=0 )
628            s2 << '\\';
629         //s2 << data[i];
630
631          unsigned int a4;
632          for(int iid=0; iid<8; iid++)
633          {
634             a4=toto[iid];
635             s2 << a4; 
636          }
637
638      }
639      *StrHexaArea=s2.str();
640   }
641   else
642   {
643      unsigned int l = (Length > GDCM_MAX_LENGTH_TO_CONVERT_TO_HEXA) ? GDCM_MAX_LENGTH_TO_CONVERT_TO_HEXA : Length;
644      uint8_t *data=(uint8_t *)BinArea;
645      for (unsigned int i=0; i < l; i++)
646      {
647         if( i!=0 )
648            s2 << '\\';
649         s2 << std::setw( 2 ) << (int)(data[i]);
650      }
651      if (Length > 16)
652         s2 << "\\...";
653      *StrHexaArea=s2.str();
654    }
655   return *StrHexaArea;
656 }
657
658 /**
659  * \brief Copies all the attributes from an other DocEntry 
660  * @param doc entry to copy from
661  * @remarks The content BinArea is copied too (StrArea is not)
662  */
663 void DataEntry::Copy(DocEntry *doc)
664 {
665    DocEntry::Copy(doc);
666
667    DataEntry *entry = dynamic_cast<DataEntry *>(doc);
668    if ( entry )
669    {
670       State = entry->State;
671       Flag = entry->Flag;
672       CopyBinArea(entry->BinArea,entry->GetLength());      
673    }
674 }
675
676 /**
677  * \brief   Writes the 'common part' + the 'value' area of a DataEntry
678  * @param fp already open ofstream pointer
679  * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...)
680  */
681 void DataEntry::WriteContent(std::ofstream *fp, FileType filetype, 
682                                                       bool insideMetaElements, bool insideSequence)
683
684    // writes the 'common part'
685    DocEntry::WriteContent(fp, filetype, insideMetaElements, insideSequence);
686
687    if ( GetGroup() == 0xfffe )
688    {
689       return; //delimitors have NO value
690    }
691    
692    // --> We only deal with Little Endian writting.
693    // --> forget Big Endian Transfer Syntax writting!
694    //     Next DICOM version will give it up ...
695  
696    // WARNING - For Implicit VR private element,
697    //           we have *no choice* but considering them as
698    //           something like 'OB' values.
699    //           we rewrite them as we found them on disc.
700    //           Some trouble will occur if element was 
701    //           *actually* OW, if image was produced 
702    //           on Big endian based processor, read and writen 
703    //           on Little endian based processor
704    //           and, later on, somebody needs
705    //           this 'OW' Implicit VR private element (?!?)
706    //           (Same stuff, mutatis mutandis, for Little/Big)
707  
708    // 8/16 bits Pixels problem should be solved automatiquely,
709    // since we ensure the VR (OB vs OW) is conform to Pixel size.
710         
711    uint8_t *data = BinArea; //safe notation
712    size_t l = GetLength(); 
713 //   gdcmDebugMacro("in DataEntry::WriteContent " << GetKey() << " AtomicLength: "
714 //              << Global::GetVR()->GetAtomicElementLength(this->GetVR() ) // << " BinArea in :" << &BinArea
715 //             );
716    if (BinArea) // the binArea was *actually* loaded
717    {
718 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
719       unsigned short vrLgth = 
720                         Global::GetVR()->GetAtomicElementLength(this->GetVR());
721       unsigned int i;
722       switch(vrLgth)
723       {
724          case 1:
725          {
726             binary_write (*fp, data, l );           
727             break;
728          }     
729          case 2:
730          {
731             uint16_t *data16 = (uint16_t *)data;
732             for(i=0;i<l/vrLgth;i++)
733                binary_write( *fp, data16[i]);
734             break;
735          }
736          case 4:
737          {
738             uint32_t *data32 = (uint32_t *)data;
739             for(i=0;i<l/vrLgth;i++)
740                binary_write( *fp, data32[i]);
741             break;
742          }
743          case 8:
744          {
745             double *data64 = (double *)data;
746             for(i=0;i<l/vrLgth;i++)
747                binary_write( *fp, data64[i]);
748             break;
749          }
750       }
751 #else
752    binary_write (*fp, data, l );
753 #endif //GDCM_WORDS_BIGENDIAN
754
755    }
756    else
757    {
758       // nothing was loaded, but we need to skip space on disc     
759       if (l != 0)
760       {
761       //  --> WARNING : nothing is written; 
762       //  --> the initial data (on the the source image) is lost
763       //  --> user is *not* informed !      
764          gdcmDebugMacro ("Nothing was loaded, but we need to skip space on disc. "
765                       << "Length =" << l << " for " << GetKey() );   
766          fp->seekp(l, std::ios::cur); // At Write time, for unloaded elems
767       }
768    }
769    // to avoid gdcm to propagate oddities
770    // (length was already modified)  
771    if (l%2)
772       fp->seekp(1, std::ios::cur);  // At Write time, for non even length elems
773 }
774
775 /**
776  * \brief   Compute the full length of the elementary DataEntry (not only value
777  *          length) depending on the VR.
778  */
779 uint32_t DataEntry::ComputeFullLength()
780 {
781    return GetFullLength();
782 }
783
784 //-----------------------------------------------------------------------------
785 // Protected
786
787 /// \brief Creates a DataEntry owned BinArea 
788 ///       (remove previous one if any and relevant StrArea if any)
789 void DataEntry::NewBinArea( )
790 {
791    DeleteBinArea();
792    if( GetLength() > 0 )
793       BinArea = new uint8_t[GetLength()];
794    SelfArea = true;
795 }
796 /// \brief Removes the BinArea, if owned by the DataEntry, 
797 ///        and the relevant StrArea if any
798 void DataEntry::DeleteBinArea(void)
799 {
800    if (BinArea && SelfArea)
801    {
802       delete[] BinArea;
803       BinArea = NULL;
804    }
805    if (StrArea)
806    {
807       delete StrArea;
808       StrArea = 0;
809    }
810    if (StrHexaArea)
811    {
812       delete StrHexaArea;
813       StrHexaArea = 0;
814    }   
815 }
816
817 //-----------------------------------------------------------------------------
818 // Private
819
820 //-----------------------------------------------------------------------------
821 // Print
822 /**
823  * \brief   Prints a DataEntry (Dicom entry)
824  * @param   os ostream we want to print in
825  * @param indent Indentation string to be prepended during printing
826  */
827 void DataEntry::Print(std::ostream &os, std::string const & )
828 {
829    //os << "D ";
830    
831    // First, Print the common part (vr [length offset] name).
832    DocEntry::Print(os);
833
834    uint16_t g = GetGroup();
835    if (g == 0xfffe) // delimiters have NO value
836    {          
837       return; // just to avoid identing all the remaining code 
838    }
839
840    std::ostringstream s;
841    TSAtr v;
842
843    if( BinArea )
844    {
845       v = GetString();
846       const VRKey &vr = GetVR();
847
848       if( vr == "US" || vr == "SS" || vr == "UL" || vr == "SL" 
849        || vr == "FL" || vr == "FD")
850          s << " [" << GetString() << "] =0x(" << GetHexaRepresentation() << ")";
851       else
852       { 
853          if(Global::GetVR()->IsVROfStringRepresentable(vr))
854          {
855             // replace non printable characters by '.'
856             std::string cleanString = Util::CreateCleanString(v);
857             if ( cleanString.length() <= GetMaxSizePrintEntry()
858               || PrintLevel >= 3
859               || IsNotLoaded() )
860            // FIXME : when IsNotLoaded(), you create a Clean String ?!?
861            // FIXME : PrintLevel<2 *does* print the values 
862            //        (3 is only for extra offsets printing)
863            // What do you wanted to do ? JPR
864             {
865                s << " [" << cleanString << "]";
866             }
867             else
868             {
869                s << " [GDCM_NAME_SPACE::too long for print (" << cleanString.length() << ") ]";
870             }
871          }
872          else
873          {
874             // A lot of Private elements (with no VR) contain actually 
875             // only printable characters;
876             // Let's deal with them as is they were VR std::string representable
877     
878             if ( Util::IsCleanArea( GetBinArea(), GetLength()  ) )
879             {
880                // FIXME : since the 'Area' *is* clean, just use
881                //         a 'CreateString' method, to save CPU time.
882                std::string cleanString = 
883                      Util::CreateCleanString( BinArea,GetLength()  );
884                s << " [" << cleanString << "]";
885             }
886             else
887             {
888                s << " [" << GDCM_BINLOADED << ";"
889                << "length = " << GetLength() << "] =0x(" << GetHexaRepresentation() << ")";      
890             }
891          }
892       }
893    }
894    else
895    {
896       if( IsNotLoaded() )
897          s << " [" << GDCM_NOTLOADED << "]";
898       else if( IsUnfound() )
899          s << " [" << GDCM_UNFOUND << "]";
900       else if( IsUnread() )
901          s << " [" << GDCM_UNREAD << "]";
902       else if ( GetLength() == 0 )
903          s << " []";
904    }
905
906    if( IsPixelData() )
907       s << " (" << GDCM_PIXELDATA << ")";
908
909    // Display the UID value (instead of displaying only the rough code)
910    // First 'clean' trailing character (space or zero) 
911    if(BinArea)
912    {
913       const uint16_t &gr = GetGroup();
914       const uint16_t &elt = GetElement();
915       TS *ts = Global::GetTS();
916
917       if (gr == 0x0002)
918       {
919          // Any more to be displayed ?
920          if ( elt == 0x0010 || elt == 0x0002 )
921          {
922             if ( v.length() != 0 )  // for brain damaged headers
923             {
924                if ( ! isdigit((unsigned char)v[v.length()-1]) )
925                {
926                   v.erase(v.length()-1, 1);
927                }
928             }
929             s << "  ==>\t[" << ts->GetValue(v) << "]";
930          }
931       }
932       else if (gr == 0x0008)
933       {
934          if ( elt == 0x0016 || elt == 0x1150 )
935          {
936             if ( v.length() != 0 )  // for brain damaged headers
937             {
938                if ( ! isdigit((unsigned char)v[v.length()-1]) )
939                {
940                   v.erase(v.length()-1, 1);
941                }
942             }
943             s << "  ==>\t[" << ts->GetValue(v) << "]";
944          }
945       }
946       else if (gr == 0x0004)
947       {
948          if ( elt == 0x1510 || elt == 0x1512  )
949          {
950             if ( v.length() != 0 )  // for brain damaged headers  
951             {
952                if ( ! isdigit((unsigned char)v[v.length()-1]) )
953                {
954                   v.erase(v.length()-1, 1);  
955                }
956             }
957             s << "  ==>\t[" << ts->GetValue(v) << "]";
958          }
959       }
960    }
961
962    os << s.str();
963 }
964
965 //-----------------------------------------------------------------------------
966 } // end namespace gdcm
967