]> Creatis software - gdcm.git/blob - src/gdcmDocEntrySet.cxx
ENH: Try to sync gdcm CVS and gdcm 1.2. ~2000 lines of changes, please be gentle...
[gdcm.git] / src / gdcmDocEntrySet.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocEntrySet.cxx,v $
5   Language:  C++
6   Date:      $Date: 2006/02/16 20:06:14 $
7   Version:   $Revision: 1.70 $
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 #if defined(__BORLANDC__)
31    #include <mem.h> // for memset
32 #endif 
33
34 namespace gdcm 
35 {
36 //-----------------------------------------------------------------------------
37 // Constructor / Destructor
38 DocEntrySet::DocEntrySet() 
39
40    PreviousDocEntry = 0;
41 }
42 //-----------------------------------------------------------------------------
43 // Public
44 /**
45  * \brief   Get the "std::string representable" value of the Dicom entry
46  * @param   group  Group number of the searched tag.
47  * @param   elem Element number of the searched tag.
48  * @return  Corresponding element value when it exists,
49  *          and the string GDCM_UNFOUND otherwise.
50  */
51 std::string DocEntrySet::GetEntryString(uint16_t group, uint16_t elem)
52 {
53    DataEntry *entry = dynamic_cast<DataEntry *>(GetDocEntry(group,elem));
54    if ( entry )
55    {
56       if( entry->IsNotLoaded() )
57          return GDCM_NOTLOADED;
58       if( entry->IsUnfound() )
59          return GDCM_UNFOUND;
60       if( entry->IsUnread() )
61          return GDCM_UNREAD;
62       return entry->GetString();
63    }
64    return GDCM_UNFOUND;
65 }
66
67 /**
68  * \brief   Gets (from Header) a 'non string' element value 
69  * @param group   group number of the Entry 
70  * @param elem  element number of the Entry
71  * @return Pointer to the 'non string' area
72  */
73 void *DocEntrySet::GetEntryBinArea(uint16_t group, uint16_t elem) 
74 {
75    DataEntry *entry = GetDataEntry(group, elem);
76    if ( entry )
77       return entry->GetBinArea();
78    return 0;
79 }
80
81 /**
82  * \brief   Searches within the DocEntrySet
83  *          for the value length of a given tag..
84  * @param   group  Group number of the searched tag.
85  * @param   elem Element number of the searched tag.
86  * @return  Corresponding element length; -1 if not found
87  */
88 int DocEntrySet::GetEntryLength(uint16_t group, uint16_t elem)
89 {
90    DocEntry *entry = GetDocEntry(group, elem);
91    if ( entry )
92       return entry->GetLength();
93    return -1;
94 }
95
96 /**
97  * \brief  Same as \ref Document::GetDocEntry except it returns a result 
98  *         only when the corresponding entry is of type DataEntry.
99  * @param   group  Group number of the searched Dicom Element 
100  * @param   elem Element number of the searched Dicom Element  
101  * @return When present, the corresponding DataEntry. 
102  */
103 DataEntry *DocEntrySet::GetDataEntry(uint16_t group, uint16_t elem)
104 {
105    DocEntry *currentEntry = GetDocEntry(group, elem);
106    if ( !currentEntry )
107       return NULL;
108
109    return dynamic_cast<DataEntry*>(currentEntry);
110 }
111
112 /**
113  * \brief  Same as \ref Document::GetDocEntry except it returns a result
114  *          only when the corresponding entry is of type SeqEntry.
115  * @param   group  Group number of the searched Dicom Element 
116  * @param   elem Element number of the searched Dicom Element  
117  * @return When present, the corresponding SeqEntry. 
118  */
119 SeqEntry *DocEntrySet::GetSeqEntry(uint16_t group, uint16_t elem)
120 {
121    DocEntry *currentEntry = GetDocEntry(group, elem);
122    if ( !currentEntry )
123       return NULL;
124
125    return dynamic_cast<SeqEntry*>(currentEntry);
126 }
127
128 /**
129  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
130  *          through it's (group, element) and modifies it's content with
131  *          the given value.
132  * @param   content new value (string) to substitute with
133  * @param   group  group number of the Dicom Element to modify
134  * @param   elem element number of the Dicom Element to modify
135  */
136 bool DocEntrySet::SetEntryString(std::string const &content, 
137                                  uint16_t group, uint16_t elem) 
138 {
139    DataEntry *entry = GetDataEntry(group, elem);
140    if (!entry )
141    {
142       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
143                          "," << elem << " element (try promotion first).");
144       return false;
145    }
146    return SetEntryString(content,entry);
147 }
148
149 /**
150  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
151  *          through it's (group, element) and modifies it's content with
152  *          the given value.
153  * @param   content new value (void*  -> uint8_t*) to substitute with
154  * @param   lgth new value length
155  * @param   group  group number of the Dicom Element to modify
156  * @param   elem element number of the Dicom Element to modify
157  */
158 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, 
159                                   uint16_t group, uint16_t elem) 
160 {
161    DataEntry *entry = GetDataEntry(group, elem);
162    if (!entry )
163    {
164       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
165                         "," << elem << " element (try promotion first).");
166       return false;
167    }
168
169    return SetEntryBinArea(content,lgth,entry);
170
171
172 /**
173  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
174  *          and modifies it's content with the given value.
175  * @param  content new value (string) to substitute with
176  * @param  entry Entry to be modified
177  */
178 bool DocEntrySet::SetEntryString(std::string const &content, DataEntry *entry)
179 {
180    if (entry)
181    {
182       entry->SetString(content);
183       return true;
184    }
185    return false;
186 }
187
188 /**
189  * \brief   Accesses an existing DataEntry (i.e. a Dicom Element)
190  *          and modifies it's content with the given value.
191  * @param   content new value (void*  -> uint8_t*) to substitute with
192  * @param  entry Entry to be modified 
193  * @param  lgth new value length
194  */
195 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, DataEntry *entry)
196 {
197    if (entry)
198    {
199       entry->SetLength(lgth);
200       entry->SetBinArea(content);  
201       return true;
202    }
203    return false;
204 }
205
206 /**
207  * \brief   Modifies the value of a given Doc Entry (Dicom Element)
208  *          when it exists. Create it with the given value when unexistant.
209  * @param   value (string) Value to be set
210  * @param   group   Group number of the Entry 
211  * @param   elem  Element number of the Entry
212  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
213  * \return  pointer to the modified/created Header Entry (NULL when creation
214  *          failed).
215  */ 
216 DataEntry *DocEntrySet::InsertEntryString(std::string const &value, 
217                                           uint16_t group, uint16_t elem,
218                                           VRKey const &vr )
219 {
220    DataEntry *dataEntry = 0;
221    DocEntry *currentEntry = GetDocEntry( group, elem );
222    
223    if (currentEntry)
224    {
225       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
226
227       // Verify the VR
228       if ( dataEntry )
229          if ( dataEntry->GetVR()!=vr )
230             dataEntry = NULL;
231
232       // if currentEntry doesn't correspond to the requested dataEntry
233       if ( !dataEntry)
234       {
235          if ( !RemoveEntry(currentEntry) )
236          {
237             gdcmWarningMacro( "Removal of previous DocEntry failed.");
238             return NULL;
239          }
240       }
241    }
242
243    // Create a new dataEntry if necessary
244    if ( !dataEntry )
245    {
246       dataEntry = NewDataEntry( group, elem, vr );
247
248       if ( !AddEntry(dataEntry) )
249       {
250          gdcmWarningMacro("AddEntry failed although this is a creation.");
251          dataEntry->Delete();
252          return NULL;
253       }
254       dataEntry->Delete();
255    }
256
257    // Set the dataEntry value
258    SetEntryString(value, dataEntry); // The std::string value
259    return dataEntry;
260 }
261
262 /**
263  * \brief   Modifies the value of a given Header Entry (Dicom Element)
264  *          when it exists. Create it with the given value when unexistant.
265  *          A copy of the binArea is made to be kept in the Document.
266  * @param   binArea (binary) value to be set
267  * @param   lgth length of the Bin Area we want to set
268  * @param   group   Group number of the Entry 
269  * @param   elem  Element number of the Entry
270  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
271  * \return  pointer to the modified/created Header Entry (NULL when creation
272  *          failed).
273  */
274 DataEntry *DocEntrySet::InsertEntryBinArea(uint8_t *binArea, int lgth, 
275                                            uint16_t group, uint16_t elem,
276                                            VRKey const &vr )
277 {
278    DataEntry *dataEntry = 0;
279    DocEntry *currentEntry = GetDocEntry( group, elem );
280
281    // Verify the currentEntry
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          dataEntry->Delete();
311          return NULL;
312       }
313       dataEntry->Delete();
314    }
315
316    // Set the dataEntry value
317    uint8_t *tmpArea;
318    if ( lgth>0 && binArea )
319    {
320       tmpArea = new uint8_t[lgth];
321       memcpy(tmpArea,binArea,lgth);
322    }
323    else
324    {
325       tmpArea = 0;
326    }
327    if ( !SetEntryBinArea(tmpArea,lgth,dataEntry) )
328    {
329       if ( tmpArea )
330       {
331          delete[] tmpArea;
332       }
333    }
334    return dataEntry;
335 }  
336
337 /**
338  * \brief   Creates a new gdcm::SeqEntry and adds it to the current DocEntrySet.
339  *          (remove any existing entry with same group,elem)
340  * @param   group   Group number of the Entry 
341  * @param   elem  Element number of the Entry
342  * \return  pointer to the created SeqEntry (NULL when creation
343  *          failed).
344  */
345 SeqEntry *DocEntrySet::InsertSeqEntry(uint16_t group, uint16_t elem)
346 {
347    SeqEntry *seqEntry = 0;
348    DocEntry *currentEntry = GetDocEntry( group, elem );
349
350    // Verify the currentEntry
351    if ( currentEntry )
352    {
353       seqEntry = dynamic_cast<SeqEntry *>(currentEntry);
354
355       // Verify the VR
356       if ( seqEntry )
357          seqEntry = NULL;
358
359       // if currentEntry doesn't correspond to the requested seqEntry
360       if ( !seqEntry )
361       {
362          if (!RemoveEntry(currentEntry))
363          {
364             gdcmWarningMacro( "Removal of previous DocEntry failed for ("
365                <<std::hex << group << "|" << elem <<")" );
366             return NULL;
367          }
368       }
369    }
370    // Create a new seqEntry if necessary
371    if ( !seqEntry )
372    {
373       seqEntry = NewSeqEntry(group, elem);
374
375       if ( !AddEntry(seqEntry) )
376       {
377          gdcmWarningMacro( "AddEntry failed although this is a creation for ("
378             <<std::hex << group << "|" << elem <<")" );
379          seqEntry->Delete();
380          return NULL;
381       }
382       seqEntry->Delete();
383    }
384    // Remark :
385    // SequenceDelimitationItem will be added at the end of the SeqEntry,
386    // at write time
387    return seqEntry;
388
389  
390 /**
391  * \brief   Checks if a given Dicom Element exists within the DocEntrySet
392  * @param   group   Group number of the searched Dicom Element 
393  * @param   elem  Element number of the searched Dicom Element 
394  * @return true is found
395  */
396 bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem )
397 {
398    return GetDocEntry(group,elem)!=NULL;
399 }
400
401 /**
402  * \brief   Build a new DataEntry from all the low level arguments. 
403  *          Check for existence of dictionary entry, and build
404  *          a default one when absent.
405  * @param   group Group number   of the new Entry
406  * @param   elem  Element number of the new Entry
407  * @param   vr    V(alue) R(epresentation) of the new Entry 
408  * \remarks The user of this method must destroy the DataEntry when unused
409  */
410 DataEntry *DocEntrySet::NewDataEntry(uint16_t group,uint16_t elem,
411                                      VRKey const &vr) 
412 {
413    DictEntry *dictEntry = GetDictEntry(group, elem, vr);
414
415    DataEntry *newEntry = DataEntry::New(dictEntry);
416    dictEntry->Unregister(); // GetDictEntry register it
417    if (!newEntry) 
418    {
419       gdcmWarningMacro( "Failed to allocate DataEntry for ("
420           <<std::hex << group << "|" << elem <<")" );
421       return 0;
422    }
423    return newEntry;
424 }
425
426 /**
427  * \brief   Build a new SeqEntry from all the low level arguments. 
428  *          Check for existence of dictionary entry, and build
429  *          a default one when absent.
430  * @param   group Group   number of the new Entry
431  * @param   elem  Element number of the new Entry
432  * \remarks The user of this method must destroy the SeqEntry when unused
433  */
434 SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) 
435 {
436    DictEntry *dictEntry = GetDictEntry(group, elem, "SQ");
437
438    SeqEntry *newEntry = SeqEntry::New( dictEntry );
439    dictEntry->Unregister(); // GetDictEntry register it
440    if (!newEntry)
441    {
442       gdcmWarningMacro( "Failed to allocate SeqEntry for ("
443          <<std::hex << group << "|" << elem <<")" );
444       return 0;
445    }
446    return newEntry;
447 }
448
449 //-----------------------------------------------------------------------------
450 // Protected
451 /**
452  * \brief   Searches [both] the public [and the shadow dictionary (when they
453  *          exist)] for the presence of the DictEntry with given
454  *          group and element. The public dictionary has precedence on the
455  *          shadow one(s), if any.
456  * @param   group  Group number of the searched DictEntry
457  * @param   elem Element number of the searched DictEntry
458  * @return  Corresponding DictEntry when it exists, NULL otherwise.
459  * \remarks The returned DictEntry is registered when existing
460  */
461 DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) 
462 {
463    DictEntry *found = 0;
464    Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
465    if (!pubDict) 
466    {
467       gdcmWarningMacro( "We SHOULD have a default dictionary");
468    }
469    else
470    {
471       found = pubDict->GetEntry(group, elem);
472       if( found )
473          found->Register();
474    }
475    return found;
476 }
477
478 /**
479  * \brief   Searches [both] the public [and the shadow dictionary (when they
480  *          exist)] for the presence of the DictEntry with given
481  *          group and element, and create a new virtual DictEntry if necessary
482  * @param   group  group number of the searched DictEntry
483  * @param   elem element number of the searched DictEntry
484  * @param   vr V(alue) R(epresentation) to use, if necessary 
485  * @return  Corresponding DictEntry when it exists, NULL otherwise.
486  * \remarks The returned DictEntry is registered
487  */
488 DictEntry *DocEntrySet::GetDictEntry(uint16_t group, uint16_t elem,
489                                      VRKey const &vr)
490 {
491    DictEntry *dictEntry = GetDictEntry(group,elem);
492    DictEntry *goodEntry = dictEntry;
493    VRKey goodVR = vr;
494    TagName vm;
495    if (elem == 0x0000)
496       goodVR="UL";
497
498    if ( goodEntry )
499    {
500       if ( goodVR != goodEntry->GetVR()
501         && goodVR != GDCM_VRUNKNOWN )
502       {
503          gdcmWarningMacro("For (" << std::hex << group << "|"
504             << elem << "), found VR : [" << vr << "]"
505             << " expected: [" << goodEntry->GetVR() << "]" ) ;
506         // avoid confusing further validator with "FIXME" VM
507         // when possible      
508          vm = dictEntry->GetVM();
509          goodEntry = NULL;
510       }
511       dictEntry->Unregister();
512    }
513    else
514    {
515       vm = "FIXME";
516    }
517    // Create a new virtual DictEntry if necessary
518    if (!goodEntry)
519    {
520       if (dictEntry)
521       {
522
523          goodEntry = DictEntry::New(group, elem, goodVR, vm,
524                                     dictEntry->GetName() );
525       }
526       else
527       {
528          goodEntry = DictEntry::New(group, elem, goodVR);
529       }
530    }
531    else
532    {
533       goodEntry->Register();
534    }
535    return goodEntry;
536 }
537
538 //-----------------------------------------------------------------------------
539 // Private
540
541 //-----------------------------------------------------------------------------
542 // Print
543
544 //-----------------------------------------------------------------------------
545 } // end namespace gdcm