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