1 /*=========================================================================
4 Module: $RCSfile: gdcmDataEntry.cxx,v $
6 Date: $Date: 2005/10/21 14:15:41 $
7 Version: $Revision: 1.6 $
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
225 std::istringstream os;
228 return vm == GetValueCount();
231 uint32_t DataEntry::GetValueCount(void) const
233 const VRKey &vr = GetVR();
234 if( vr == "US" || vr == "SS" )
235 return GetLength()/sizeof(uint16_t);
236 else if( vr == "UL" || vr == "SL" )
237 return GetLength()/sizeof(uint32_t);
238 else if( vr == "FL" )
239 return GetLength()/sizeof(float);
240 else if( vr == "FD" )
241 return GetLength()/sizeof(double);
242 else if( Global::GetVR()->IsVROfStringRepresentable(vr) )
244 // Don't use std::string to accelerate processing
246 for(uint32_t i=0;i<GetLength();i++)
248 if( BinArea[i] == '\\')
257 void DataEntry::SetString(std::string const &value)
261 const VRKey &vr = GetVR();
262 if ( vr == "US" || vr == "SS" )
264 std::vector<std::string> tokens;
265 Util::Tokenize (value, tokens, "\\");
266 SetLength(tokens.size()*sizeof(uint16_t));
269 uint16_t *data = (uint16_t *)BinArea;
270 for (unsigned int i=0; i<tokens.size();i++)
271 data[i] = atoi(tokens[i].c_str());
274 else if ( vr == "UL" || vr == "SL" )
276 std::vector<std::string> tokens;
277 Util::Tokenize (value, tokens, "\\");
278 SetLength(tokens.size()*sizeof(uint32_t));
281 uint32_t *data = (uint32_t *)BinArea;
282 for (unsigned int i=0; i<tokens.size();i++)
283 data[i] = atoi(tokens[i].c_str());
286 else if ( vr == "FL" )
288 std::vector<std::string> tokens;
289 Util::Tokenize (value, tokens, "\\");
290 SetLength(tokens.size()*sizeof(float));
293 float *data = (float *)BinArea;
294 for (unsigned int i=0; i<tokens.size();i++)
295 data[i] = (float)atof(tokens[i].c_str());
298 else if ( vr == "FD" )
300 std::vector<std::string> tokens;
301 Util::Tokenize (value, tokens, "\\");
302 SetLength(tokens.size()*sizeof(double));
305 double *data = (double *)BinArea;
306 for (unsigned int i=0; i<tokens.size();i++)
307 data[i] = atof(tokens[i].c_str());
312 if( value.size() > 0 )
314 std::string finalVal = Util::DicomString( value.c_str() );
315 SetLength(finalVal.size());
318 memcpy(BinArea, &(finalVal[0]), finalVal.size());
321 State = STATE_LOADED;
324 std::string const &DataEntry::GetString() const
326 static std::ostringstream s;
327 const VRKey &vr = GetVR();
335 if( vr == "US" || vr == "SS" )
337 uint16_t *data=(uint16_t *)BinArea;
339 for (unsigned int i=0; i < GetValueCount(); i++)
347 // See above comment on multiple integers (mutatis mutandis).
348 else if( vr == "UL" || vr == "SL" )
350 uint32_t *data=(uint32_t *)BinArea;
352 for (unsigned int i=0; i < GetValueCount(); i++)
360 else if( vr == "FL" )
362 float *data=(float *)BinArea;
364 for (unsigned int i=0; i < GetValueCount(); i++)
372 else if( vr == "FD" )
374 double *data=(double *)BinArea;
376 for (unsigned int i=0; i < GetValueCount(); i++)
385 StrArea.append((const char *)BinArea,GetLength());
390 void DataEntry::Copy(DocEntry *doc)
394 DataEntry *entry = dynamic_cast<DataEntry *>(doc);
397 State = entry->State;
399 CopyBinArea(entry->BinArea,entry->GetLength());
403 void DataEntry::WriteContent(std::ofstream *fp, FileType filetype)
405 DocEntry::WriteContent(fp, filetype);
407 if ( GetGroup() == 0xfffe )
409 return; //delimitors have NO value
412 uint8_t *binArea8 = BinArea; //safe notation
413 size_t lgr = GetLength();
414 if (BinArea) // the binArea was *actually* loaded
417 // The same operation should be done if we wanted
418 // to write image with Big Endian Transfer Syntax,
419 // while working on Little Endian Processor
420 // --> forget Big Endian Transfer Syntax writting!
421 // Next DICOM version will give it up ...
424 // The stuff looks nice, but it's probably bugged,
425 // since troubles occur on big endian processors (SunSparc, Motorola)
426 // while reading the pixels of a
427 // gdcm-written Little-Endian 16 bits per pixel image
429 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
431 /// \todo FIXME : Right now, we only care of Pixels element
432 /// we should deal with *all* the BinEntries
433 /// Well, not really since we are not interpreting values read...
435 // 8 Bits Pixels *are* OB, 16 Bits Pixels *are* OW
436 // -value forced while Reading process-
439 // --> the following lines *looked* very clever,
440 // --> but they don't work on big endian processors.
441 // --> since I've no access for the moment to a big endian proc :-(
442 // --> I comment them out, to see the result on the dash board
445 // --> Revert to initial code : TestWriteSimple hangs on Darwin :-(
446 if (GetGroup() == 0x7fe0 && GetVR() == "OW")
448 uint16_t *binArea16 = (uint16_t*)binArea8;
449 binary_write (*fp, binArea16, lgr );
453 // For any other VR, DataEntry is re-written as-is
454 binary_write (*fp, binArea8, lgr );
458 // --> remove the following line, an uncomment the previous ones,
459 // --> if it doesn't work better
461 /*binary_write ( *fp, binArea8, lgr ); // Elem value*/
464 binary_write ( *fp, binArea8, lgr ); // Elem value
465 #endif //GDCM_WORDS_BIGENDIAN
469 // nothing was loaded, but we need to skip space on disc
471 // --> WARNING : nothing is written;
472 // --> the initial data (on the the source image) is lost
473 // --> user is *not* informed !
475 fp->seekp(lgr, std::ios::cur);
479 //-----------------------------------------------------------------------------
481 void DataEntry::NewBinArea(void)
484 if( GetLength() > 0 )
485 BinArea = new uint8_t[GetLength()];
489 void DataEntry::DeleteBinArea(void)
491 if (BinArea && SelfArea)
498 //-----------------------------------------------------------------------------
501 //-----------------------------------------------------------------------------
504 * \brief Prints a DataEntry (Dicom entry)
505 * @param os ostream we want to print in
506 * @param indent Indentation string to be prepended during printing
508 void DataEntry::Print(std::ostream &os, std::string const & )
513 uint16_t g = GetGroup();
514 if (g == 0xfffe) // delimiters have NO value
516 return; // just to avoid identing all the remaining code
519 std::ostringstream s;
525 const VRKey &vr = GetVR();
527 if( vr == "US" || vr == "SS" )
528 s << " [" << GetString() << "]";
529 else if( vr == "UL" || vr == "SL" )
530 s << " [" << GetString() << "]";
531 else if ( vr == "FL" )
532 s << " [" << GetString() << "]";
533 else if ( vr == "FD" )
534 s << " [" << GetString() << "]";
537 if(Global::GetVR()->IsVROfStringRepresentable(vr))
539 std::string cleanString = Util::CreateCleanString(v); // replace non printable characters by '.'
540 if ( cleanString.length() <= GetMaxSizePrintEntry()
544 s << " [" << cleanString << "]";
548 s << " [gdcm::too long for print (" << cleanString.length() << ") ]";
553 if ( Util::IsCleanArea( GetBinArea(),GetLength() ) )
555 std::string cleanString =
556 Util::CreateCleanString( BinArea,GetLength() );
557 s << " [" << cleanString << "]";
561 s << " [" << GDCM_BINLOADED << ";"
562 << "length = " << GetLength() << "]";
570 s << " [" << GDCM_NOTLOADED << "]";
571 else if( IsUnfound() )
572 s << " [" << GDCM_UNFOUND << "]";
573 else if( IsUnread() )
574 s << " [" << GDCM_UNREAD << "]";
575 else if ( GetLength() == 0 )
580 s << " (" << GDCM_PIXELDATA << ")";
582 // Display the UID value (instead of displaying only the rough code)
583 // First 'clean' trailing character (space or zero)
586 const uint16_t &gr = GetGroup();
587 const uint16_t &elt = GetElement();
588 TS *ts = Global::GetTS();
592 // Any more to be displayed ?
593 if ( elt == 0x0010 || elt == 0x0002 )
595 if ( v.length() != 0 ) // for brain damaged headers
597 if ( ! isdigit((unsigned char)v[v.length()-1]) )
599 v.erase(v.length()-1, 1);
602 s << " ==>\t[" << ts->GetValue(v) << "]";
605 else if (gr == 0x0008)
607 if ( elt == 0x0016 || elt == 0x1150 )
609 if ( v.length() != 0 ) // for brain damaged headers
611 if ( ! isdigit((unsigned char)v[v.length()-1]) )
613 v.erase(v.length()-1, 1);
616 s << " ==>\t[" << ts->GetValue(v) << "]";
619 else if (gr == 0x0004)
621 if ( elt == 0x1510 || elt == 0x1512 )
623 if ( v.length() != 0 ) // for brain damaged headers
625 if ( ! isdigit((unsigned char)v[v.length()-1]) )
627 v.erase(v.length()-1, 1);
630 s << " ==>\t[" << ts->GetValue(v) << "]";
638 //-----------------------------------------------------------------------------
639 } // end namespace gdcm