]> Creatis software - gdcm.git/blob - src/gdcmDataEntry.cxx
BUG: map<>::mapped_type is not part of the STL. Should fix issue on VS* compiler
[gdcm.git] / src / gdcmDataEntry.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDataEntry.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/09/28 14:16:09 $
7   Version:   $Revision: 1.50 $
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   s2 << std::hex;
549   
550   if( vr == "US" )
551   {
552      uint16_t *data=(uint16_t *)BinArea;
553      for (unsigned int i=0; i < GetValueCount(); i++)
554      {
555         s2  << std::setw( 2 ) << std::setfill( '0' );     
556         if( i!=0 )
557            s2 << '\\';
558         s2 << data[i];
559      }
560      *StrHexaArea=s2.str();
561   }
562   else if (vr == "SS" )
563   {
564      int16_t *data=(int16_t *)BinArea;
565      for (unsigned int i=0; i < GetValueCount(); i++)
566      {
567         s2  << std::setw( 4 ) << std::setfill( '0' );
568         if( i!=0 )
569            s2 << '\\';
570         s2  << data[i];
571      }
572      *StrHexaArea=s2.str();
573   }      // See above comment on multiple short integers (mutatis mutandis).
574   else if( vr == "UL" )
575   {
576      uint32_t *data=(uint32_t *)BinArea;
577      for (unsigned int i=0; i < GetValueCount(); i++)
578      {
579         s2  << std::setw( 4 ) << std::setfill( '0' );
580         if( i!=0 ) 
581            s2  << '\\';
582         s2 << data[i];
583      }
584      *StrHexaArea=s2.str();
585   }
586   else if( vr == "SL" )
587   {
588      int32_t *data=(int32_t *)BinArea;
589      for (unsigned int i=0; i < GetValueCount(); i++)
590      {
591         s2  << std::setw( 4 ) << std::setfill( '0' );
592          if( i!=0 )
593            s2  << '\\';
594         s2 << data[i];
595      }
596      *StrHexaArea=s2.str();
597   }    else if( vr == "FL" )
598   {
599      float *data=(float *)BinArea;
600      for (unsigned int i=0; i < GetValueCount(); i++)
601      {
602         s2  << std::setw( 4 ) << std::setfill( '0' );
603          if( i!=0 )
604            s2 << '\\';
605         s2 << data[i];
606      }
607      *StrHexaArea=s2.str();
608   }
609   else if( vr == "FD" )
610   {
611      double *data=(double *)BinArea;
612      for (unsigned int i=0; i < GetValueCount(); i++)
613      {
614         s2  << std::setw( 8 ) << std::setfill( '0' );
615          if( i!=0 )
616            s2 << '\\';
617         s2 << data[i];
618      }
619      *StrHexaArea=s2.str();
620   }
621   else
622   {
623      unsigned int l = (Length > GDCM_MAX_LENGTH_TO_CONVERT_TO_HEXA) ? GDCM_MAX_LENGTH_TO_CONVERT_TO_HEXA : Length;
624      uint8_t *data=(uint8_t *)BinArea;
625      for (unsigned int i=0; i < l; i++)
626      {
627         if( i!=0 )
628            s2 << '\\';
629         s2 << std::setw( 2 ) << (int)(data[i]);
630      }
631      if (Length > 16)
632         s2 << "\\...";
633      *StrHexaArea=s2.str();
634    }
635   return *StrHexaArea;
636 }
637
638 /**
639  * \brief Copies all the attributes from an other DocEntry 
640  * @param doc entry to copy from
641  * @remarks The content BinArea is copied too (StrArea is not)
642  */
643 void DataEntry::Copy(DocEntry *doc)
644 {
645    DocEntry::Copy(doc);
646
647    DataEntry *entry = dynamic_cast<DataEntry *>(doc);
648    if ( entry )
649    {
650       State = entry->State;
651       Flag = entry->Flag;
652       CopyBinArea(entry->BinArea,entry->GetLength());      
653    }
654 }
655
656 /**
657  * \brief   Writes the 'common part' + the 'value' area of a DataEntry
658  * @param fp already open ofstream pointer
659  * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...)
660  */
661 void DataEntry::WriteContent(std::ofstream *fp, FileType filetype, 
662                                                       bool insideMetaElements, bool insideSequence)
663
664    // writes the 'common part'
665    DocEntry::WriteContent(fp, filetype, insideMetaElements, insideSequence);
666
667    if ( GetGroup() == 0xfffe )
668    {
669       return; //delimitors have NO value
670    }
671    
672    // --> We only deal with Little Endian writting.
673    // --> forget Big Endian Transfer Syntax writting!
674    //     Next DICOM version will give it up ...
675  
676    // WARNING - For Implicit VR private element,
677    //           we have *no choice* but considering them as
678    //           something like 'OB' values.
679    //           we rewrite them as we found them on disc.
680    //           Some trouble will occur if element was 
681    //           *actually* OW, if image was produced 
682    //           on Big endian based processor, read and writen 
683    //           on Little endian based processor
684    //           and, later on, somebody needs
685    //           this 'OW' Implicit VR private element (?!?)
686    //           (Same stuff, mutatis mutandis, for Little/Big)
687  
688    // 8/16 bits Pixels problem should be solved automatiquely,
689    // since we ensure the VR (OB vs OW) is conform to Pixel size.
690         
691    uint8_t *data = BinArea; //safe notation
692    size_t l = GetLength(); 
693 //   gdcmDebugMacro("in DataEntry::WriteContent " << GetKey() << " AtomicLength: "
694 //              << Global::GetVR()->GetAtomicElementLength(this->GetVR() ) // << " BinArea in :" << &BinArea
695 //             );
696    if (BinArea) // the binArea was *actually* loaded
697    {
698 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
699       unsigned short vrLgth = 
700                         Global::GetVR()->GetAtomicElementLength(this->GetVR());
701       unsigned int i;
702       switch(vrLgth)
703       {
704          case 1:
705          {
706             binary_write (*fp, data, l );           
707             break;
708          }     
709          case 2:
710          {
711             uint16_t *data16 = (uint16_t *)data;
712             for(i=0;i<l/vrLgth;i++)
713                binary_write( *fp, data16[i]);
714             break;
715          }
716          case 4:
717          {
718             uint32_t *data32 = (uint32_t *)data;
719             for(i=0;i<l/vrLgth;i++)
720                binary_write( *fp, data32[i]);
721             break;
722          }
723          case 8:
724          {
725             double *data64 = (double *)data;
726             for(i=0;i<l/vrLgth;i++)
727                binary_write( *fp, data64[i]);
728             break;
729          }
730       }
731 #else
732    binary_write (*fp, data, l );
733 #endif //GDCM_WORDS_BIGENDIAN
734
735    }
736    else
737    {
738       // nothing was loaded, but we need to skip space on disc     
739       if (l != 0)
740       {
741       //  --> WARNING : nothing is written; 
742       //  --> the initial data (on the the source image) is lost
743       //  --> user is *not* informed !      
744          gdcmDebugMacro ("Nothing was loaded, but we need to skip space on disc. "
745                       << "Length =" << l << " for " << GetKey() );   
746          fp->seekp(l, std::ios::cur); // At Write time, for unloaded elems
747       }
748    }
749    // to avoid gdcm to propagate oddities
750    // (length was already modified)  
751    if (l%2)
752       fp->seekp(1, std::ios::cur);  // At Write time, for non even length elems
753 }
754
755 /**
756  * \brief   Compute the full length of the elementary DataEntry (not only value
757  *          length) depending on the VR.
758  */
759 uint32_t DataEntry::ComputeFullLength()
760 {
761    return GetFullLength();
762 }
763
764 //-----------------------------------------------------------------------------
765 // Protected
766
767 /// \brief Creates a DataEntry owned BinArea 
768 ///       (remove previous one if any and relevant StrArea if any)
769 void DataEntry::NewBinArea( )
770 {
771    DeleteBinArea();
772    if( GetLength() > 0 )
773       BinArea = new uint8_t[GetLength()];
774    SelfArea = true;
775 }
776 /// \brief Removes the BinArea, if owned by the DataEntry, 
777 ///        and the relevant StrArea if any
778 void DataEntry::DeleteBinArea(void)
779 {
780    if (BinArea && SelfArea)
781    {
782       delete[] BinArea;
783       BinArea = NULL;
784    }
785    if (StrArea)
786    {
787       delete StrArea;
788       StrArea = 0;
789    }
790    if (StrArea)
791    {
792       delete StrHexaArea;
793       StrHexaArea = 0;
794    }   
795 }
796
797 //-----------------------------------------------------------------------------
798 // Private
799
800 //-----------------------------------------------------------------------------
801 // Print
802 /**
803  * \brief   Prints a DataEntry (Dicom entry)
804  * @param   os ostream we want to print in
805  * @param indent Indentation string to be prepended during printing
806  */
807 void DataEntry::Print(std::ostream &os, std::string const & )
808 {
809    //os << "D ";
810    
811    // First, Print the common part (vr [length offset] name).
812    DocEntry::Print(os);
813
814    uint16_t g = GetGroup();
815    if (g == 0xfffe) // delimiters have NO value
816    {          
817       return; // just to avoid identing all the remaining code 
818    }
819
820    std::ostringstream s;
821    TSAtr v;
822
823    if( BinArea )
824    {
825       v = GetString();
826       const VRKey &vr = GetVR();
827
828       if( vr == "US" || vr == "SS" || vr == "UL" || vr == "SL" 
829        || vr == "FL" || vr == "FD")
830          s << " [" << GetString() << "] =0x(" << GetHexaRepresentation() << ")";
831       else
832       { 
833          if(Global::GetVR()->IsVROfStringRepresentable(vr))
834          {
835             // replace non printable characters by '.'
836             std::string cleanString = Util::CreateCleanString(v);
837             if ( cleanString.length() <= GetMaxSizePrintEntry()
838               || PrintLevel >= 3
839               || IsNotLoaded() )
840            // FIXME : when IsNotLoaded(), you create a Clean String ?!?
841            // FIXME : PrintLevel<2 *does* print the values 
842            //        (3 is only for extra offsets printing)
843            // What do you wanted to do ? JPR
844             {
845                s << " [" << cleanString << "]";
846             }
847             else
848             {
849                s << " [GDCM_NAME_SPACE::too long for print (" << cleanString.length() << ") ]";
850             }
851          }
852          else
853          {
854             // A lot of Private elements (with no VR) contain actually 
855             // only printable characters;
856             // Let's deal with them as is they were VR std::string representable
857     
858             if ( Util::IsCleanArea( GetBinArea(), GetLength()  ) )
859             {
860                // FIXME : since the 'Area' *is* clean, just use
861                //         a 'CreateString' method, to save CPU time.
862                std::string cleanString = 
863                      Util::CreateCleanString( BinArea,GetLength()  );
864                s << " [" << cleanString << "]";
865             }
866             else
867             {
868                s << " [" << GDCM_BINLOADED << ";"
869                << "length = " << GetLength() << "] =0x(" << GetHexaRepresentation() << ")";      
870             }
871          }
872       }
873    }
874    else
875    {
876       if( IsNotLoaded() )
877          s << " [" << GDCM_NOTLOADED << "]";
878       else if( IsUnfound() )
879          s << " [" << GDCM_UNFOUND << "]";
880       else if( IsUnread() )
881          s << " [" << GDCM_UNREAD << "]";
882       else if ( GetLength() == 0 )
883          s << " []";
884    }
885
886    if( IsPixelData() )
887       s << " (" << GDCM_PIXELDATA << ")";
888
889    // Display the UID value (instead of displaying only the rough code)
890    // First 'clean' trailing character (space or zero) 
891    if(BinArea)
892    {
893       const uint16_t &gr = GetGroup();
894       const uint16_t &elt = GetElement();
895       TS *ts = Global::GetTS();
896
897       if (gr == 0x0002)
898       {
899          // Any more to be displayed ?
900          if ( elt == 0x0010 || elt == 0x0002 )
901          {
902             if ( v.length() != 0 )  // for brain damaged headers
903             {
904                if ( ! isdigit((unsigned char)v[v.length()-1]) )
905                {
906                   v.erase(v.length()-1, 1);
907                }
908             }
909             s << "  ==>\t[" << ts->GetValue(v) << "]";
910          }
911       }
912       else if (gr == 0x0008)
913       {
914          if ( elt == 0x0016 || elt == 0x1150 )
915          {
916             if ( v.length() != 0 )  // for brain damaged headers
917             {
918                if ( ! isdigit((unsigned char)v[v.length()-1]) )
919                {
920                   v.erase(v.length()-1, 1);
921                }
922             }
923             s << "  ==>\t[" << ts->GetValue(v) << "]";
924          }
925       }
926       else if (gr == 0x0004)
927       {
928          if ( elt == 0x1510 || elt == 0x1512  )
929          {
930             if ( v.length() != 0 )  // for brain damaged headers  
931             {
932                if ( ! isdigit((unsigned char)v[v.length()-1]) )
933                {
934                   v.erase(v.length()-1, 1);  
935                }
936             }
937             s << "  ==>\t[" << ts->GetValue(v) << "]";
938          }
939       }
940    }
941
942    os << s.str();
943 }
944
945 //-----------------------------------------------------------------------------
946 } // end namespace gdcm
947