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