]> Creatis software - gdcm.git/blob - src/gdcmDocEntrySet.cxx
* Minor coding-style clean up
[gdcm.git] / src / gdcmDocEntrySet.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocEntrySet.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/10/18 08:35:49 $
7   Version:   $Revision: 1.60 $
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 #include "gdcmDocEntrySet.h"
19
20 #include "gdcmDebug.h"
21 #include "gdcmCommon.h"
22 #include "gdcmDictSet.h"
23 #include "gdcmGlobal.h"
24 #include "gdcmDocEntry.h"
25 #include "gdcmSeqEntry.h"
26 #include "gdcmUtil.h"
27 #include "gdcmDataEntry.h"
28 #include "gdcmVR.h"
29
30 namespace gdcm 
31 {
32 //-----------------------------------------------------------------------------
33 // Constructor / Destructor
34 DocEntrySet::DocEntrySet() 
35
36    PreviousDocEntry = 0;
37 }
38 //-----------------------------------------------------------------------------
39 // Public
40 /**
41  * \brief   Get the "std::string representable" value of the Dicom entry
42  * @param   group  Group number of the searched tag.
43  * @param   elem Element number of the searched tag.
44  * @return  Corresponding element value when it exists,
45  *          and the string GDCM_UNFOUND otherwise.
46  */
47 std::string DocEntrySet::GetEntryString(uint16_t group, uint16_t elem)
48 {
49    DataEntry *entry = dynamic_cast<DataEntry *>(GetDocEntry(group,elem));
50    if ( entry )
51    {
52       if( entry->IsNotLoaded() )
53          return GDCM_NOTLOADED;
54       if( entry->IsUnfound() )
55          return GDCM_UNFOUND;
56       if( entry->IsUnread() )
57          return GDCM_UNREAD;
58       return entry->GetString();
59    }
60    return GDCM_UNFOUND;
61 }
62
63 /**
64  * \brief   Gets (from Header) a 'non string' element value 
65  * @param group   group number of the Entry 
66  * @param elem  element number of the Entry
67  * @return Pointer to the 'non string' area
68  */
69 void *DocEntrySet::GetEntryBinArea(uint16_t group, uint16_t elem) 
70 {
71    DataEntry *entry = GetDataEntry(group, elem);
72    if ( entry )
73       return entry->GetBinArea();
74    return 0;
75 }
76
77 /**
78  * \brief   Return the value of the DataEntry if it's "std::string representable"
79  * @param   group  Group number of the searched tag.
80  * @param   elem Element number of the searched tag.
81  * @return  Corresponding element value when it's "std::string representable"
82  *          and the string GDCM_NOTASCII otherwise.
83  */
84 std::string DocEntrySet::GetEntryForcedAsciiValue(uint16_t group, uint16_t elem)
85 {
86    DocEntry *d = GetDocEntry(group,elem);
87    if ( !d )
88       return GDCM_UNFOUND;
89
90    DataEntry *de = dynamic_cast<DataEntry *>(d);
91    if ( de )
92    {
93       if( de->IsNotLoaded() )
94          return GDCM_NOTLOADED;
95       if( de->IsUnfound() )
96          return GDCM_UNFOUND;
97       if( de->IsUnread() )
98          return GDCM_UNREAD;
99    }
100
101    if( Global::GetVR()->IsVROfStringRepresentable( de->GetVR() ) )
102       return de->GetString();
103    else
104    {
105       uint8_t *a = de->GetBinArea();
106       if( Util::IsCleanArea(a, de->GetLength()) )
107          return  Util::CreateCleanString(a, de->GetLength());
108    }
109    return GDCM_NOTASCII;
110 }
111
112 /**
113  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
114  *          the public and private dictionaries 
115  *          for the value length of a given tag..
116  * @param   group  Group number of the searched tag.
117  * @param   elem Element number of the searched tag.
118  * @return  Corresponding element length; -2 if not found
119  */
120 int DocEntrySet::GetEntryLength(uint16_t group, uint16_t elem)
121 {
122    DocEntry *entry = GetDocEntry(group, elem);
123    if ( entry )
124       return entry->GetLength();
125    return -1;
126 }
127
128 /**
129  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
130  *          the public [and private dictionaries] 
131  *          for the element value representation of a given tag..
132  *          Obtaining the VR (Value Representation) might be needed by caller
133  *          to convert the string typed content to caller's native type 
134  *          (think of C++ vs Python). The VR is actually of a higher level
135  *          of semantics than just the native C++ type.
136  * @param   group  Group number of the searched tag.
137  * @param   elem Element number of the searched tag.
138  * @return  Corresponding element value representation when it exists,
139  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
140  */
141 std::string DocEntrySet::GetEntryVR(uint16_t group, uint16_t elem)
142 {
143    DocEntry *entry = GetDocEntry(group, elem);
144    if ( entry )
145       return entry->GetVR();
146    return GDCM_UNFOUND;
147 }
148
149 /**
150  * \brief  Same as \ref Document::GetDocEntry except it only
151  *         returns a result when the corresponding entry is of type
152  *         DataEntry.
153  * @param   group  Group number of the searched Dicom Element 
154  * @param   elem Element number of the searched Dicom Element  
155  * @return When present, the corresponding DataEntry. 
156  */
157 DataEntry *DocEntrySet::GetDataEntry(uint16_t group, uint16_t elem)
158 {
159    DocEntry *currentEntry = GetDocEntry(group, elem);
160    if ( !currentEntry )
161       return NULL;
162
163    return dynamic_cast<DataEntry*>(currentEntry);
164 }
165
166 /**
167  * \brief  Same as \ref Document::GetDocEntry except it only
168  *         returns a result when the corresponding entry is of type
169  *         SeqEntry.
170  * @param   group  Group number of the searched Dicom Element 
171  * @param   elem Element number of the searched Dicom Element  
172  * @return When present, the corresponding SeqEntry. 
173  */
174 SeqEntry *DocEntrySet::GetSeqEntry(uint16_t group, uint16_t elem)
175 {
176    DocEntry *currentEntry = GetDocEntry(group, elem);
177    if ( !currentEntry )
178    {
179       gdcmWarningMacro( "No corresponding SeqEntry " << std::hex << group <<
180                         "," << elem);
181       return NULL;
182    }
183
184    return dynamic_cast<SeqEntry*>(currentEntry);
185 }
186
187 /**
188  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
189  *          through it's (group, element) and modifies it's content with
190  *          the given value.
191  * @param   content new value (string) to substitute with
192  * @param   group  group number of the Dicom Element to modify
193  * @param   elem element number of the Dicom Element to modify
194  */
195 bool DocEntrySet::SetEntryString(std::string const &content, 
196                                  uint16_t group, uint16_t elem) 
197 {
198    DataEntry *entry = GetDataEntry(group, elem);
199    if (!entry )
200    {
201       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
202                          "," << elem << " element (try promotion first).");
203       return false;
204    }
205    return SetEntryString(content,entry);
206 }
207
208 /**
209  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
210  *          through it's (group, element) and modifies it's content with
211  *          the given value.
212  * @param   content new value (void*  -> uint8_t*) to substitute with
213  * @param   lgth new value length
214  * @param   group  group number of the Dicom Element to modify
215  * @param   elem element number of the Dicom Element to modify
216  */
217 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, 
218                                   uint16_t group, uint16_t elem) 
219 {
220    DataEntry *entry = GetDataEntry(group, elem);
221    if (!entry )
222    {
223       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
224                         "," << elem << " element (try promotion first).");
225       return false;
226    }
227
228    return SetEntryBinArea(content,lgth,entry);
229
230
231 /**
232  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
233  *          and modifies it's content with the given value.
234  * @param  content new value (string) to substitute with
235  * @param  entry Entry to be modified
236  */
237 bool DocEntrySet::SetEntryString(std::string const &content, DataEntry *entry)
238 {
239    if (entry)
240    {
241       entry->SetString(content);
242       return true;
243    }
244    return false;
245 }
246
247 /**
248  * \brief   Accesses an existing DataEntry (i.e. a Dicom Element)
249  *          and modifies it's content with the given value.
250  * @param   content new value (void*  -> uint8_t*) to substitute with
251  * @param  entry Entry to be modified 
252  * @param  lgth new value length
253  */
254 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, DataEntry *entry)
255 {
256    if (entry)
257    {
258       entry->SetLength(lgth);
259       entry->SetBinArea(content);  
260       return true;
261    }
262    return false;
263 }
264
265 /**
266  * \brief   Modifies the value of a given Doc Entry (Dicom Element)
267  *          when it exists. Create it with the given value when unexistant.
268  * @param   value (string) Value to be set
269  * @param   group   Group number of the Entry 
270  * @param   elem  Element number of the Entry
271  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
272  * \return  pointer to the modified/created Header Entry (NULL when creation
273  *          failed).
274  */ 
275 DataEntry *DocEntrySet::InsertEntryString(std::string const &value, 
276                                              uint16_t group, uint16_t elem,
277                                              TagName const &vr )
278 {
279    DataEntry *dataEntry = 0;
280    DocEntry *currentEntry = GetDocEntry( group, elem );
281    
282    if (currentEntry)
283    {
284       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
285
286       // Verify the VR
287       if ( dataEntry )
288          if ( dataEntry->GetVR()!=vr )
289             dataEntry = NULL;
290
291       // if currentEntry doesn't correspond to the requested dataEntry
292       if ( !dataEntry)
293       {
294          if ( !RemoveEntry(currentEntry) )
295          {
296             gdcmWarningMacro( "Removal of previous DocEntry failed.");
297             return NULL;
298          }
299       }
300    }
301
302    // Create a new dataEntry if necessary
303    if ( !dataEntry )
304    {
305       dataEntry = NewDataEntry( group, elem, vr );
306
307       if ( !AddEntry(dataEntry) )
308       {
309          gdcmWarningMacro("AddEntry failed although this is a creation.");
310
311          delete dataEntry;
312          return NULL;
313       }
314    }
315
316    // Set the dataEntry value
317    SetEntryString(value, dataEntry); // The std::string value
318    return dataEntry;
319 }
320
321 /**
322  * \brief   Modifies the value of a given Header Entry (Dicom Element)
323  *          when it exists. Create it with the given value when unexistant.
324  *          A copy of the binArea is made to be kept in the Document.
325  * @param   binArea (binary) value to be set
326  * @param   lgth length of the Bin Area we want to set
327  * @param   group   Group number of the Entry 
328  * @param   elem  Element number of the Entry
329  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
330  * \return  pointer to the modified/created Header Entry (NULL when creation
331  *          failed).
332  */
333 DataEntry *DocEntrySet::InsertEntryBinArea(uint8_t *binArea, int lgth, 
334                                               uint16_t group, uint16_t elem,
335                                               TagName const &vr )
336 {
337    DataEntry *dataEntry = 0;
338    DocEntry *currentEntry = GetDocEntry( group, elem );
339
340    // Verify the currentEntry
341    if (currentEntry)
342    {
343       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
344
345       // Verify the VR
346       if ( dataEntry )
347          if ( dataEntry->GetVR()!=vr )
348             dataEntry = NULL;
349
350       // if currentEntry doesn't correspond to the requested dataEntry
351       if ( !dataEntry)
352       {
353          if ( !RemoveEntry(currentEntry) )
354          {
355             gdcmWarningMacro( "Removal of previous DocEntry failed.");
356             return NULL;
357          }
358       }
359    }
360
361    // Create a new dataEntry if necessary
362    if ( !dataEntry)
363    {
364       dataEntry = NewDataEntry(group, elem, vr);
365
366       if ( !AddEntry(dataEntry) )
367       {
368          gdcmWarningMacro( "AddEntry failed although this is a creation.");
369
370          delete dataEntry;
371          return NULL;
372       }
373    }
374
375    // Set the dataEntry value
376    uint8_t *tmpArea;
377    if ( lgth>0 && binArea )
378    {
379       tmpArea = new uint8_t[lgth];
380       memcpy(tmpArea,binArea,lgth);
381    }
382    else
383    {
384       tmpArea = 0;
385    }
386    if ( !SetEntryBinArea(tmpArea,lgth,dataEntry) )
387    {
388       if ( tmpArea )
389       {
390          delete[] tmpArea;
391       }
392    }
393
394    return dataEntry;
395 }  
396
397 /**
398  * \brief   Modifies the value of a given Doc Entry (Dicom Element)
399  *          when it exists. Creates it when unexistant.
400  * @param   group   Group number of the Entry 
401  * @param   elem  Element number of the Entry
402  * \return  pointer to the modified/created SeqEntry (NULL when creation
403  *          failed).
404  */
405 SeqEntry *DocEntrySet::InsertSeqEntry(uint16_t group, uint16_t elem)
406 {
407    SeqEntry *seqEntry = 0;
408    DocEntry *currentEntry = GetDocEntry( group, elem );
409
410    // Verify the currentEntry
411    if ( currentEntry )
412    {
413       seqEntry = dynamic_cast<SeqEntry *>(currentEntry);
414
415       // Verify the VR
416       if ( seqEntry )
417          seqEntry = NULL;
418
419       // if currentEntry doesn't correspond to the requested seqEntry
420       if ( !seqEntry )
421       {
422          if (!RemoveEntry(currentEntry))
423          {
424             gdcmWarningMacro( "Removal of previous DocEntry failed.");
425
426             return NULL;
427          }
428       }
429    }
430    // Create a new seqEntry if necessary
431    if ( !seqEntry )
432    {
433       seqEntry = NewSeqEntry(group, elem);
434
435       if ( !AddEntry(seqEntry) )
436       {
437          gdcmWarningMacro( "AddEntry failed although this is a creation.");
438
439          delete seqEntry;
440          return NULL;
441       }
442    }
443
444    // TODO : Find a trick to insert a SequenceDelimitationItem 
445    //       in the SeqEntry, at the end.
446    return seqEntry;
447
448  
449 /**
450  * \brief   Checks if a given Dicom Element exists within the H table
451  * @param   group   Group number of the searched Dicom Element 
452  * @param   elem  Element number of the searched Dicom Element 
453  * @return true is found
454  */
455 bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem )
456 {
457    return GetDocEntry(group,elem)!=NULL;
458 }
459
460 /**
461  * \brief   Build a new Val Entry from all the low level arguments. 
462  *          Check for existence of dictionary entry, and build
463  *          a default one when absent.
464  * @param   group Group number   of the new Entry
465  * @param   elem  Element number of the new Entry
466  * @param   vr    V(alue) R(epresentation) of the new Entry 
467  */
468 DataEntry *DocEntrySet::NewDataEntry(uint16_t group,uint16_t elem,
469                                    TagName const &vr) 
470 {
471    DictEntry *dictEntry = GetDictEntry(group, elem, vr);
472    gdcmAssertMacro(dictEntry);
473
474    DataEntry *newEntry = new DataEntry(dictEntry);
475    if (!newEntry) 
476    {
477       gdcmWarningMacro( "Failed to allocate DataEntry");
478       return 0;
479    }
480    return newEntry;
481 }
482
483 /**
484  * \brief   Build a new Seq Entry from all the low level arguments. 
485  *          Check for existence of dictionary entry, and build
486  *          a default one when absent.
487  * @param   group Group   number of the new Entry
488  * @param   elem  Element number of the new Entry
489  */
490 SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) 
491 {
492    DictEntry *dictEntry = GetDictEntry(group, elem, "SQ");
493    gdcmAssertMacro(dictEntry);
494
495    SeqEntry *newEntry = new SeqEntry( dictEntry );
496    if (!newEntry)
497    {
498       gdcmWarningMacro( "Failed to allocate SeqEntry");
499       return 0;
500    }
501    return newEntry;
502 }
503
504 /**
505  * \brief   Request a new virtual dict entry to the dict set
506  * @param   group Group   number of the underlying DictEntry
507  * @param   elem  Element number of the underlying DictEntry
508  * @param   vr    V(alue) R(epresentation) of the underlying DictEntry
509  * @param   vm    V(alue) M(ultiplicity)   of the underlying DictEntry
510  * @param   name   english name
511  */
512 DictEntry* DocEntrySet::NewVirtualDictEntry( uint16_t group, uint16_t elem,
513                                              TagName const &vr,
514                                              TagName const &vm,
515                                              TagName const &name )
516 {
517    return Global::GetDicts()->NewVirtualDictEntry(group,elem,vr,vm,name);
518 }
519
520 //-----------------------------------------------------------------------------
521 // Protected
522 /**
523  * \brief   Searches [both] the public [and the shadow dictionary (when they
524  *          exist)] for the presence of the DictEntry with given
525  *          group and element. The public dictionary has precedence on the
526  *          shadow one(s), if any.
527  * @param   group  Group number of the searched DictEntry
528  * @param   elem Element number of the searched DictEntry
529  * @return  Corresponding DictEntry when it exists, NULL otherwise.
530  */
531 DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) 
532 {
533    DictEntry *found = 0;
534    Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
535    if (!pubDict) 
536    {
537       gdcmWarningMacro( "We SHOULD have a default dictionary");
538    }
539    else
540    {
541       found = pubDict->GetEntry(group, elem);  
542    }
543    return found;
544 }
545
546 /**
547  * \brief   Searches [both] the public [and the shadow dictionary (when they
548  *          exist)] for the presence of the DictEntry with given
549  *          group and element, and create a new virtual DictEntry if necessary
550  * @param   group  group number of the searched DictEntry
551  * @param   elem element number of the searched DictEntry
552  * @param   vr V(alue) R(epresentation) to use, if necessary 
553  * @return  Corresponding DictEntry when it exists, NULL otherwise.
554  */
555 DictEntry *DocEntrySet::GetDictEntry(uint16_t group, uint16_t elem,
556                                      TagName const &vr)
557 {
558    DictEntry *dictEntry = GetDictEntry(group,elem);
559    DictEntry *goodEntry = dictEntry;
560    std::string goodVR = vr;
561
562    if (elem == 0x0000) goodVR="UL";
563
564    if ( goodEntry )
565    {
566       if ( goodVR != goodEntry->GetVR()
567         && goodVR != GDCM_UNKNOWN )
568       {
569          goodEntry = NULL;
570       }
571    }
572
573    // Create a new virtual DictEntry if necessary
574    if (!goodEntry)
575    {
576       if (dictEntry)
577       {
578          goodEntry = NewVirtualDictEntry(group, elem, goodVR, "FIXME", 
579                                          dictEntry->GetName() );
580       }
581       else
582       {
583          goodEntry = NewVirtualDictEntry(group, elem, goodVR);
584       }
585    }
586    return goodEntry;
587 }
588
589 //-----------------------------------------------------------------------------
590 // Private
591
592 //-----------------------------------------------------------------------------
593 // Print
594
595 //-----------------------------------------------------------------------------
596 } // end namespace gdcm