1 /*=========================================================================
4 Module: $RCSfile: gdcmDataEntry.cxx,v $
6 Date: $Date: 2005/10/21 15:52:13 $
7 Version: $Revision: 1.9 $
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();
227 uint32_t vc = GetValueCount();
230 // make sure it is at least one ??? FIXME
231 valid = vc >= 1 || vc == 0;
235 std::istringstream os;
239 // vm respect the one from the dict
240 // vm is 0 (we need to check is this element is allowed to be empty) FIXME
241 valid = vc == vm || vc == 0;
246 uint32_t DataEntry::GetValueCount(void) const
248 const VRKey &vr = GetVR();
249 if( vr == "US" || vr == "SS" )
250 return GetLength()/sizeof(uint16_t);
251 else if( vr == "UL" || vr == "SL" )
252 return GetLength()/sizeof(uint32_t);
253 else if( vr == "FL" )
254 return GetLength()/sizeof(float);
255 else if( vr == "FD" )
256 return GetLength()/sizeof(double);
257 else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
259 // Some element in DICOM are allowed to be empty
260 if( !GetLength() ) return 0;
261 // Don't use std::string to accelerate processing
263 for(uint32_t i=0;i<GetLength();i++)
265 if( BinArea[i] == '\\')
274 void DataEntry::SetString(std::string const &value)
278 const VRKey &vr = GetVR();
279 if ( vr == "US" || vr == "SS" )
281 std::vector<std::string> tokens;
282 Util::Tokenize (value, tokens, "\\");
283 SetLength(tokens.size()*sizeof(uint16_t));
286 uint16_t *data = (uint16_t *)BinArea;
287 for (unsigned int i=0; i<tokens.size();i++)
288 data[i] = atoi(tokens[i].c_str());
291 else if ( vr == "UL" || vr == "SL" )
293 std::vector<std::string> tokens;
294 Util::Tokenize (value, tokens, "\\");
295 SetLength(tokens.size()*sizeof(uint32_t));
298 uint32_t *data = (uint32_t *)BinArea;
299 for (unsigned int i=0; i<tokens.size();i++)
300 data[i] = atoi(tokens[i].c_str());
303 else if ( vr == "FL" )
305 std::vector<std::string> tokens;
306 Util::Tokenize (value, tokens, "\\");
307 SetLength(tokens.size()*sizeof(float));
310 float *data = (float *)BinArea;
311 for (unsigned int i=0; i<tokens.size();i++)
312 data[i] = (float)atof(tokens[i].c_str());
315 else if ( vr == "FD" )
317 std::vector<std::string> tokens;
318 Util::Tokenize (value, tokens, "\\");
319 SetLength(tokens.size()*sizeof(double));
322 double *data = (double *)BinArea;
323 for (unsigned int i=0; i<tokens.size();i++)
324 data[i] = atof(tokens[i].c_str());
329 if( value.size() > 0 )
331 std::string finalVal = Util::DicomString( value.c_str() );
332 SetLength(finalVal.size());
335 memcpy(BinArea, &(finalVal[0]), finalVal.size());
338 State = STATE_LOADED;
341 std::string const &DataEntry::GetString() const
343 static std::ostringstream s;
344 const VRKey &vr = GetVR();
352 if( vr == "US" || vr == "SS" )
354 uint16_t *data=(uint16_t *)BinArea;
356 for (unsigned int i=0; i < GetValueCount(); i++)
364 // See above comment on multiple integers (mutatis mutandis).
365 else if( vr == "UL" || vr == "SL" )
367 uint32_t *data=(uint32_t *)BinArea;
369 for (unsigned int i=0; i < GetValueCount(); i++)
377 else if( vr == "FL" )
379 float *data=(float *)BinArea;
381 for (unsigned int i=0; i < GetValueCount(); i++)
389 else if( vr == "FD" )
391 double *data=(double *)BinArea;
393 for (unsigned int i=0; i < GetValueCount(); i++)
402 StrArea.append((const char *)BinArea,GetLength());
407 void DataEntry::Copy(DocEntry *doc)
411 DataEntry *entry = dynamic_cast<DataEntry *>(doc);
414 State = entry->State;
416 CopyBinArea(entry->BinArea,entry->GetLength());
420 void DataEntry::WriteContent(std::ofstream *fp, FileType filetype)
422 DocEntry::WriteContent(fp, filetype);
424 if ( GetGroup() == 0xfffe )
426 return; //delimitors have NO value
429 uint8_t *binArea8 = BinArea; //safe notation
430 size_t lgr = GetLength();
431 if (BinArea) // the binArea was *actually* loaded
434 // The same operation should be done if we wanted
435 // to write image with Big Endian Transfer Syntax,
436 // while working on Little Endian Processor
437 // --> forget Big Endian Transfer Syntax writting!
438 // Next DICOM version will give it up ...
441 // The stuff looks nice, but it's probably bugged,
442 // since troubles occur on big endian processors (SunSparc, Motorola)
443 // while reading the pixels of a
444 // gdcm-written Little-Endian 16 bits per pixel image
446 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
448 /// \todo FIXME : Right now, we only care of Pixels element
449 /// we should deal with *all* the BinEntries
450 /// Well, not really since we are not interpreting values read...
452 // 8 Bits Pixels *are* OB, 16 Bits Pixels *are* OW
453 // -value forced while Reading process-
456 // --> the following lines *looked* very clever,
457 // --> but they don't work on big endian processors.
458 // --> since I've no access for the moment to a big endian proc :-(
459 // --> I comment them out, to see the result on the dash board
462 // --> Revert to initial code : TestWriteSimple hangs on Darwin :-(
463 if (GetGroup() == 0x7fe0 && GetVR() == "OW")
465 uint16_t *binArea16 = (uint16_t*)binArea8;
466 binary_write (*fp, binArea16, lgr );
470 // For any other VR, DataEntry is re-written as-is
471 binary_write (*fp, binArea8, lgr );
475 // --> remove the following line, an uncomment the previous ones,
476 // --> if it doesn't work better
478 /*binary_write ( *fp, binArea8, lgr ); // Elem value*/
481 binary_write ( *fp, binArea8, lgr ); // Elem value
482 #endif //GDCM_WORDS_BIGENDIAN
486 // nothing was loaded, but we need to skip space on disc
488 // --> WARNING : nothing is written;
489 // --> the initial data (on the the source image) is lost
490 // --> user is *not* informed !
492 fp->seekp(lgr, std::ios::cur);
496 //-----------------------------------------------------------------------------
498 void DataEntry::NewBinArea(void)
501 if( GetLength() > 0 )
502 BinArea = new uint8_t[GetLength()];
506 void DataEntry::DeleteBinArea(void)
508 if (BinArea && SelfArea)
515 //-----------------------------------------------------------------------------
518 //-----------------------------------------------------------------------------
521 * \brief Prints a DataEntry (Dicom entry)
522 * @param os ostream we want to print in
523 * @param indent Indentation string to be prepended during printing
525 void DataEntry::Print(std::ostream &os, std::string const & )
530 uint16_t g = GetGroup();
531 if (g == 0xfffe) // delimiters have NO value
533 return; // just to avoid identing all the remaining code
536 std::ostringstream s;
542 const VRKey &vr = GetVR();
544 if( vr == "US" || vr == "SS" )
545 s << " [" << GetString() << "]";
546 else if( vr == "UL" || vr == "SL" )
547 s << " [" << GetString() << "]";
548 else if ( vr == "FL" )
549 s << " [" << GetString() << "]";
550 else if ( vr == "FD" )
551 s << " [" << GetString() << "]";
554 if(Global::GetVR()->IsVROfStringRepresentable(vr))
556 std::string cleanString = Util::CreateCleanString(v); // replace non printable characters by '.'
557 if ( cleanString.length() <= GetMaxSizePrintEntry()
561 s << " [" << cleanString << "]";
565 s << " [gdcm::too long for print (" << cleanString.length() << ") ]";
570 if ( Util::IsCleanArea( GetBinArea(),GetLength() ) )
572 std::string cleanString =
573 Util::CreateCleanString( BinArea,GetLength() );
574 s << " [" << cleanString << "]";
578 s << " [" << GDCM_BINLOADED << ";"
579 << "length = " << GetLength() << "]";
587 s << " [" << GDCM_NOTLOADED << "]";
588 else if( IsUnfound() )
589 s << " [" << GDCM_UNFOUND << "]";
590 else if( IsUnread() )
591 s << " [" << GDCM_UNREAD << "]";
592 else if ( GetLength() == 0 )
597 s << " (" << GDCM_PIXELDATA << ")";
599 // Display the UID value (instead of displaying only the rough code)
600 // First 'clean' trailing character (space or zero)
603 const uint16_t &gr = GetGroup();
604 const uint16_t &elt = GetElement();
605 TS *ts = Global::GetTS();
609 // Any more to be displayed ?
610 if ( elt == 0x0010 || elt == 0x0002 )
612 if ( v.length() != 0 ) // for brain damaged headers
614 if ( ! isdigit((unsigned char)v[v.length()-1]) )
616 v.erase(v.length()-1, 1);
619 s << " ==>\t[" << ts->GetValue(v) << "]";
622 else if (gr == 0x0008)
624 if ( elt == 0x0016 || elt == 0x1150 )
626 if ( v.length() != 0 ) // for brain damaged headers
628 if ( ! isdigit((unsigned char)v[v.length()-1]) )
630 v.erase(v.length()-1, 1);
633 s << " ==>\t[" << ts->GetValue(v) << "]";
636 else if (gr == 0x0004)
638 if ( elt == 0x1510 || elt == 0x1512 )
640 if ( v.length() != 0 ) // for brain damaged headers
642 if ( ! isdigit((unsigned char)v[v.length()-1]) )
644 v.erase(v.length()-1, 1);
647 s << " ==>\t[" << ts->GetValue(v) << "]";
655 //-----------------------------------------------------------------------------
656 } // end namespace gdcm