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