1 /*=========================================================================
4 Module: $RCSfile: gdcmDataEntry.cxx,v $
6 Date: $Date: 2005/10/21 15:16:52 $
7 Version: $Revision: 1.7 $
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.
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.
17 =========================================================================*/
19 #include "gdcmDataEntry.h"
22 #include "gdcmGlobal.h"
24 #include "gdcmDebug.h"
30 //-----------------------------------------------------------------------------
31 #define MAX_SIZE_PRINT_ELEMENT_VALUE 0x7fffffff
32 uint32_t DataEntry::MaxSizePrintEntry = MAX_SIZE_PRINT_ELEMENT_VALUE;
34 //-----------------------------------------------------------------------------
35 // Constructor / Destructor
37 * \brief Constructor for a given DictEntry
38 * @param e Pointer to existing dictionary entry
40 DataEntry::DataEntry(DictEntry *e)
51 * \brief Constructor for a given DocEntry
52 * @param e Pointer to existing Doc entry
54 DataEntry::DataEntry(DocEntry *e)
55 : DocEntry(e->GetDictEntry())
65 * \brief Canonical destructor.
67 DataEntry::~DataEntry ()
72 //-----------------------------------------------------------------------------
75 //-----------------------------------------------------------------------------
78 * \brief Sets the value (non string) of the current Dicom Header Entry
80 void DataEntry::SetBinArea( uint8_t *area, bool self )
90 void DataEntry::CopyBinArea( uint8_t *area, uint32_t length )
94 uint32_t lgh = length + length%2;
97 if( area && length > 0 )
100 memcpy(BinArea,area,length);
104 State = STATE_LOADED;
108 void DataEntry::SetValue(const uint32_t &id,const double &val)
112 State = STATE_LOADED;
114 if( id > GetValueCount() )
116 gdcmErrorMacro("Index (" << id << ")is greater than the data size");
120 const VRKey &vr = GetVR();
121 if( vr == "US" || vr == "SS" )
123 uint16_t *data = (uint16_t *)BinArea;
124 data[id] = (uint16_t)val;
126 else if( vr == "UL" || vr == "SL" )
128 uint32_t *data = (uint32_t *)BinArea;
129 data[id] = (uint32_t)val;
131 else if( vr == "FL" )
133 float *data = (float *)BinArea;
134 data[id] = (float)val;
136 else if( vr == "FD" )
138 double *data = (double *)BinArea;
139 data[id] = (double)val;
141 else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
143 gdcmErrorMacro("SetValue on String representable not implemented yet");
147 BinArea[id] = (uint8_t)val;
151 double DataEntry::GetValue(const uint32_t &id) const
155 gdcmErrorMacro("BinArea not set. Can't get the value");
159 uint32_t count = GetValueCount();
162 gdcmErrorMacro("Index (" << id << ")is greater than the data size");
166 const VRKey &vr = GetVR();
167 if( vr == "US" || vr == "SS" )
168 return ((uint16_t *)BinArea)[id];
169 else if( vr == "UL" || vr == "SL" )
170 return ((uint32_t *)BinArea)[id];
171 else if( vr == "FL" )
172 return ((float *)BinArea)[id];
173 else if( vr == "FD" )
174 return ((double *)BinArea)[id];
175 else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
179 // Don't use std::string to accelerate processing
181 char *tmp = new char[GetLength()+1];
182 memcpy(tmp,BinArea,GetLength());
193 for(uint32_t i=0;i<GetLength();i++)
222 bool DataEntry::IsValueCountValid() const
226 const std::string &strVM = GetVM();
229 // make sure it is at least one ??? FIXME
230 valid = GetValueCount() >= 1;
234 std::istringstream os;
237 valid = vm == GetValueCount();
242 uint32_t DataEntry::GetValueCount(void) const
244 const VRKey &vr = GetVR();
245 if( vr == "US" || vr == "SS" )
246 return GetLength()/sizeof(uint16_t);
247 else if( vr == "UL" || vr == "SL" )
248 return GetLength()/sizeof(uint32_t);
249 else if( vr == "FL" )
250 return GetLength()/sizeof(float);
251 else if( vr == "FD" )
252 return GetLength()/sizeof(double);
253 else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
255 // Don't use std::string to accelerate processing
257 for(uint32_t i=0;i<GetLength();i++)
259 if( BinArea[i] == '\\')
268 void DataEntry::SetString(std::string const &value)
272 const VRKey &vr = GetVR();
273 if ( vr == "US" || vr == "SS" )
275 std::vector<std::string> tokens;
276 Util::Tokenize (value, tokens, "\\");
277 SetLength(tokens.size()*sizeof(uint16_t));
280 uint16_t *data = (uint16_t *)BinArea;
281 for (unsigned int i=0; i<tokens.size();i++)
282 data[i] = atoi(tokens[i].c_str());
285 else if ( vr == "UL" || vr == "SL" )
287 std::vector<std::string> tokens;
288 Util::Tokenize (value, tokens, "\\");
289 SetLength(tokens.size()*sizeof(uint32_t));
292 uint32_t *data = (uint32_t *)BinArea;
293 for (unsigned int i=0; i<tokens.size();i++)
294 data[i] = atoi(tokens[i].c_str());
297 else if ( vr == "FL" )
299 std::vector<std::string> tokens;
300 Util::Tokenize (value, tokens, "\\");
301 SetLength(tokens.size()*sizeof(float));
304 float *data = (float *)BinArea;
305 for (unsigned int i=0; i<tokens.size();i++)
306 data[i] = (float)atof(tokens[i].c_str());
309 else if ( vr == "FD" )
311 std::vector<std::string> tokens;
312 Util::Tokenize (value, tokens, "\\");
313 SetLength(tokens.size()*sizeof(double));
316 double *data = (double *)BinArea;
317 for (unsigned int i=0; i<tokens.size();i++)
318 data[i] = atof(tokens[i].c_str());
323 if( value.size() > 0 )
325 std::string finalVal = Util::DicomString( value.c_str() );
326 SetLength(finalVal.size());
329 memcpy(BinArea, &(finalVal[0]), finalVal.size());
332 State = STATE_LOADED;
335 std::string const &DataEntry::GetString() const
337 static std::ostringstream s;
338 const VRKey &vr = GetVR();
346 if( vr == "US" || vr == "SS" )
348 uint16_t *data=(uint16_t *)BinArea;
350 for (unsigned int i=0; i < GetValueCount(); i++)
358 // See above comment on multiple integers (mutatis mutandis).
359 else if( vr == "UL" || vr == "SL" )
361 uint32_t *data=(uint32_t *)BinArea;
363 for (unsigned int i=0; i < GetValueCount(); i++)
371 else if( vr == "FL" )
373 float *data=(float *)BinArea;
375 for (unsigned int i=0; i < GetValueCount(); i++)
383 else if( vr == "FD" )
385 double *data=(double *)BinArea;
387 for (unsigned int i=0; i < GetValueCount(); i++)
396 StrArea.append((const char *)BinArea,GetLength());
401 void DataEntry::Copy(DocEntry *doc)
405 DataEntry *entry = dynamic_cast<DataEntry *>(doc);
408 State = entry->State;
410 CopyBinArea(entry->BinArea,entry->GetLength());
414 void DataEntry::WriteContent(std::ofstream *fp, FileType filetype)
416 DocEntry::WriteContent(fp, filetype);
418 if ( GetGroup() == 0xfffe )
420 return; //delimitors have NO value
423 uint8_t *binArea8 = BinArea; //safe notation
424 size_t lgr = GetLength();
425 if (BinArea) // the binArea was *actually* loaded
428 // The same operation should be done if we wanted
429 // to write image with Big Endian Transfer Syntax,
430 // while working on Little Endian Processor
431 // --> forget Big Endian Transfer Syntax writting!
432 // Next DICOM version will give it up ...
435 // The stuff looks nice, but it's probably bugged,
436 // since troubles occur on big endian processors (SunSparc, Motorola)
437 // while reading the pixels of a
438 // gdcm-written Little-Endian 16 bits per pixel image
440 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
442 /// \todo FIXME : Right now, we only care of Pixels element
443 /// we should deal with *all* the BinEntries
444 /// Well, not really since we are not interpreting values read...
446 // 8 Bits Pixels *are* OB, 16 Bits Pixels *are* OW
447 // -value forced while Reading process-
450 // --> the following lines *looked* very clever,
451 // --> but they don't work on big endian processors.
452 // --> since I've no access for the moment to a big endian proc :-(
453 // --> I comment them out, to see the result on the dash board
456 // --> Revert to initial code : TestWriteSimple hangs on Darwin :-(
457 if (GetGroup() == 0x7fe0 && GetVR() == "OW")
459 uint16_t *binArea16 = (uint16_t*)binArea8;
460 binary_write (*fp, binArea16, lgr );
464 // For any other VR, DataEntry is re-written as-is
465 binary_write (*fp, binArea8, lgr );
469 // --> remove the following line, an uncomment the previous ones,
470 // --> if it doesn't work better
472 /*binary_write ( *fp, binArea8, lgr ); // Elem value*/
475 binary_write ( *fp, binArea8, lgr ); // Elem value
476 #endif //GDCM_WORDS_BIGENDIAN
480 // nothing was loaded, but we need to skip space on disc
482 // --> WARNING : nothing is written;
483 // --> the initial data (on the the source image) is lost
484 // --> user is *not* informed !
486 fp->seekp(lgr, std::ios::cur);
490 //-----------------------------------------------------------------------------
492 void DataEntry::NewBinArea(void)
495 if( GetLength() > 0 )
496 BinArea = new uint8_t[GetLength()];
500 void DataEntry::DeleteBinArea(void)
502 if (BinArea && SelfArea)
509 //-----------------------------------------------------------------------------
512 //-----------------------------------------------------------------------------
515 * \brief Prints a DataEntry (Dicom entry)
516 * @param os ostream we want to print in
517 * @param indent Indentation string to be prepended during printing
519 void DataEntry::Print(std::ostream &os, std::string const & )
524 uint16_t g = GetGroup();
525 if (g == 0xfffe) // delimiters have NO value
527 return; // just to avoid identing all the remaining code
530 std::ostringstream s;
536 const VRKey &vr = GetVR();
538 if( vr == "US" || vr == "SS" )
539 s << " [" << GetString() << "]";
540 else if( vr == "UL" || vr == "SL" )
541 s << " [" << GetString() << "]";
542 else if ( vr == "FL" )
543 s << " [" << GetString() << "]";
544 else if ( vr == "FD" )
545 s << " [" << GetString() << "]";
548 if(Global::GetVR()->IsVROfStringRepresentable(vr))
550 std::string cleanString = Util::CreateCleanString(v); // replace non printable characters by '.'
551 if ( cleanString.length() <= GetMaxSizePrintEntry()
555 s << " [" << cleanString << "]";
559 s << " [gdcm::too long for print (" << cleanString.length() << ") ]";
564 if ( Util::IsCleanArea( GetBinArea(),GetLength() ) )
566 std::string cleanString =
567 Util::CreateCleanString( BinArea,GetLength() );
568 s << " [" << cleanString << "]";
572 s << " [" << GDCM_BINLOADED << ";"
573 << "length = " << GetLength() << "]";
581 s << " [" << GDCM_NOTLOADED << "]";
582 else if( IsUnfound() )
583 s << " [" << GDCM_UNFOUND << "]";
584 else if( IsUnread() )
585 s << " [" << GDCM_UNREAD << "]";
586 else if ( GetLength() == 0 )
591 s << " (" << GDCM_PIXELDATA << ")";
593 // Display the UID value (instead of displaying only the rough code)
594 // First 'clean' trailing character (space or zero)
597 const uint16_t &gr = GetGroup();
598 const uint16_t &elt = GetElement();
599 TS *ts = Global::GetTS();
603 // Any more to be displayed ?
604 if ( elt == 0x0010 || elt == 0x0002 )
606 if ( v.length() != 0 ) // for brain damaged headers
608 if ( ! isdigit((unsigned char)v[v.length()-1]) )
610 v.erase(v.length()-1, 1);
613 s << " ==>\t[" << ts->GetValue(v) << "]";
616 else if (gr == 0x0008)
618 if ( elt == 0x0016 || elt == 0x1150 )
620 if ( v.length() != 0 ) // for brain damaged headers
622 if ( ! isdigit((unsigned char)v[v.length()-1]) )
624 v.erase(v.length()-1, 1);
627 s << " ==>\t[" << ts->GetValue(v) << "]";
630 else if (gr == 0x0004)
632 if ( elt == 0x1510 || elt == 0x1512 )
634 if ( v.length() != 0 ) // for brain damaged headers
636 if ( ! isdigit((unsigned char)v[v.length()-1]) )
638 v.erase(v.length()-1, 1);
641 s << " ==>\t[" << ts->GetValue(v) << "]";
649 //-----------------------------------------------------------------------------
650 } // end namespace gdcm