]> Creatis software - gdcm.git/blob - src/gdcmDocEntrySet.cxx
re indent
[gdcm.git] / src / gdcmDocEntrySet.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocEntrySet.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/09/17 12:16:02 $
7   Version:   $Revision: 1.76 $
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_NAME_SPACE 
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 DocEntrySet::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 DocEntrySet::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 its (group, element) and modifies its 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 its (group, element) and modifies its 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 its 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 its 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. Creates 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    VRKey localVR = vr;
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    else // the 'currentEntry' was not found
244    {
245       if ( vr == GDCM_VRUNKNOWN ) // user didn't specify a VR.
246                                   //  Probabely he trusts the Dicom Dict !
247       {
248           DictEntry *e = 
249             Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, elem);
250           if ( e )
251           {
252              localVR = e->GetVR();  
253              e->Register(); // ?? JPRx
254          }
255       }
256    }
257
258    // Create a new dataEntry if necessary
259    if ( !dataEntry )
260    {
261       dataEntry = NewDataEntry( group, elem, localVR );
262
263       if ( !AddEntry(dataEntry) )
264       {
265          gdcmWarningMacro("AddEntry " << dataEntry->GetKey() 
266                  << " failed although this is a creation.");
267          dataEntry->Delete();
268          return NULL;
269       }
270       dataEntry->Delete(); // ?!? JPRx
271    }
272
273    // Set the dataEntry value
274    SetEntryString(value, dataEntry); // The std::string value
275    return dataEntry;
276 }
277
278 /**
279  * \brief   Modifies the value of a given Header Entry (Dicom Element)
280  *          when it exists. Create it with the given value when unexistant.
281  *          A copy of the binArea is made to be kept in the Document.
282  * @param   binArea (binary) value to be set
283  * @param   lgth length of the Bin Area we want to set
284  * @param   group   Group number of the Entry 
285  * @param   elem  Element number of the Entry
286  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
287  * \return  pointer to the modified/created Header Entry (NULL when creation
288  *          failed).
289  */
290 DataEntry *DocEntrySet::InsertEntryBinArea(uint8_t *binArea, int lgth, 
291                                            uint16_t group, uint16_t elem,
292                                            VRKey const &vr )
293 {
294    DataEntry *dataEntry = 0;
295    DocEntry *currentEntry = GetDocEntry( group, elem );
296
297    // Verify the currentEntry
298    if (currentEntry)
299    {
300       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
301
302       // Verify the VR
303       if ( dataEntry )
304          if ( dataEntry->GetVR()!=vr )
305             dataEntry = NULL;
306
307       // if currentEntry doesn't correspond to the requested dataEntry
308       if ( !dataEntry)
309       {
310          if ( !RemoveEntry(currentEntry) )
311          {
312             gdcmWarningMacro( "Removal of previous DocEntry failed.");
313             return NULL;
314          }
315       }
316    }
317
318    // Create a new dataEntry if necessary
319    if ( !dataEntry)
320    {
321       dataEntry = NewDataEntry(group, elem, vr);
322
323       if ( !AddEntry(dataEntry) )
324       {
325          gdcmWarningMacro( "AddEntry failed although this is a creation.");
326          dataEntry->Delete();
327          return NULL;
328       }
329       dataEntry->Delete();
330    }
331
332    // Set the dataEntry value
333    uint8_t *tmpArea;
334    if ( lgth>0 && binArea )
335    {
336       tmpArea = new uint8_t[lgth];
337       memcpy(tmpArea,binArea,lgth);
338    }
339    else
340    {
341       tmpArea = 0;
342    }
343    if ( !SetEntryBinArea(tmpArea,lgth,dataEntry) )
344    {
345       if ( tmpArea )
346       {
347          delete[] tmpArea;
348       }
349    }
350    return dataEntry;
351 }  
352
353 /**
354  * \brief   Creates a new gdcm::SeqEntry and adds it to the current DocEntrySet.
355  *          (remove any existing entry with same group,elem)
356  * @param   group   Group number of the Entry 
357  * @param   elem  Element number of the Entry
358  * \return  pointer to the created SeqEntry (NULL when creation
359  *          failed).
360  */
361 SeqEntry *DocEntrySet::InsertSeqEntry(uint16_t group, uint16_t elem)
362 {
363    SeqEntry *seqEntry = 0;
364    DocEntry *currentEntry = GetDocEntry( group, elem );
365
366    // Verify the currentEntry
367    if ( currentEntry )
368    {
369       seqEntry = dynamic_cast<SeqEntry *>(currentEntry);
370
371       // Verify the VR
372       if ( seqEntry )
373          seqEntry = NULL;
374
375       // if currentEntry doesn't correspond to the requested seqEntry
376       if ( !seqEntry )
377       {
378          if (!RemoveEntry(currentEntry))
379          {
380             gdcmWarningMacro( "Removal of previous DocEntry failed for ("
381                <<std::hex << group << "|" << elem <<")" );
382             return NULL;
383          }
384       }
385    }
386    // Create a new seqEntry if necessary
387    if ( !seqEntry )
388    {
389       seqEntry = NewSeqEntry(group, elem);
390
391       if ( !AddEntry(seqEntry) )
392       {
393          gdcmWarningMacro( "AddEntry failed although this is a creation for ("
394             <<std::hex << group << "|" << elem <<")" );
395          seqEntry->Delete();
396          return NULL;
397       }
398       seqEntry->Delete();
399    }
400    // Remark :
401    // SequenceDelimitationItem will be added at the end of the SeqEntry,
402    // at write time
403    return seqEntry;
404
405  
406 /**
407  * \brief   Checks if a given Dicom Element exists within the DocEntrySet
408  * @param   group   Group number of the searched Dicom Element 
409  * @param   elem  Element number of the searched Dicom Element 
410  * @return true is found
411  */
412 bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem )
413 {
414    return GetDocEntry(group,elem)!=NULL;
415 }
416
417
418 /**
419  * \brief   Build a new DataEntry from all the low level arguments. 
420  * @param   group Group number   of the new Entry
421  * @param   elem  Element number of the new Entry
422  * @param   vr    V(alue) R(epresentation) of the new Entry 
423  * \remarks The user of this method must destroy the DataEntry when unused
424  */
425 DataEntry *DocEntrySet::NewDataEntry(uint16_t group, uint16_t elem,
426                                      VRKey const &vr) 
427 {
428
429    DataEntry *newEntry = DataEntry::New(group, elem, vr);
430    if (!newEntry) 
431    {
432       gdcmWarningMacro( "Failed to allocate DataEntry for ("
433           <<std::hex << group << "|" << elem <<")" );
434       return 0;
435    }
436    return newEntry;
437 }
438
439 /**
440  * \brief   Build a new SeqEntry from all the low level arguments. 
441  * @param   group Group   number of the new Entry
442  * @param   elem  Element number of the new Entry
443  * \remarks The user of this method must destroy the SeqEntry when unused
444  */
445 SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) 
446 {
447    //DictEntry *dictEntry = GetDictEntry(group, elem, "SQ");
448
449    //SeqEntry *newEntry = SeqEntry::New( dictEntry );
450    SeqEntry *newEntry = SeqEntry::New( group, elem );
451    //dictEntry->Unregister(); // GetDictEntry register it
452    if (!newEntry)
453    {
454       gdcmWarningMacro( "Failed to allocate SeqEntry for ("
455          <<std::hex << group << "|" << elem <<")" );
456       return 0;
457    }     
458    return newEntry;
459 }
460
461 //-----------------------------------------------------------------------------
462 // Protected
463 /**
464  * \brief   Searches [both] the public [and the shadow dictionary (when they
465  *          exist)] for the presence of the DictEntry with given
466  *          group and element. The public dictionary has precedence on the
467  *          shadow one(s), if any.
468  * @param   group  Group number of the searched DictEntry
469  * @param   elem Element number of the searched DictEntry
470  * @return  Corresponding DictEntry when it exists, NULL otherwise.
471  * \remarks The returned DictEntry is registered when existing
472  */
473 DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) 
474 {
475    DictEntry *found = 0;
476    /// \todo store the DefaultPubDict somwhere, in order not to access the HTable
477    ///       every time ! --> Done!
478    Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
479    if (!pubDict) 
480    {
481       gdcmWarningMacro( "We SHOULD have a default dictionary");
482    }
483    else
484    {
485       found = pubDict->GetEntry(group, elem);
486       if( found )
487          found->Register();
488    }
489    return found;
490 }
491
492 //-----------------------------------------------------------------------------
493 // Private
494
495 //-----------------------------------------------------------------------------
496 // Print
497
498 //-----------------------------------------------------------------------------
499 } // end namespace gdcm