1 /*
2  *
3  *  Copyright (C) 2015-2019, Open Connections GmbH
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation are maintained by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module:  dcmfg
15  *
16  *  Author:  Michael Onken
17  *
18  *  Purpose: Base class(es) for functional groups
19  *
20  */
21 
22 #include "dcmtk/config/osconfig.h"
23 
24 #include "dcmtk/dcmdata/dcdeftag.h"
25 #include "dcmtk/dcmfg/fgbase.h"
26 #include "dcmtk/dcmiod/iodcommn.h" // for static element helpers
27 
FGBase(const DcmFGTypes::E_FGType fgType)28 FGBase::FGBase(const DcmFGTypes::E_FGType fgType)
29     : m_fgType(fgType)
30 {
31 }
32 
~FGBase()33 FGBase::~FGBase()
34 {
35 }
36 
clearData()37 void FGBase::clearData()
38 {
39 }
40 
getType() const41 DcmFGTypes::E_FGType FGBase::getType() const
42 {
43     return m_fgType;
44 }
45 
getSharedType() const46 DcmFGTypes::E_FGSharedType FGBase::getSharedType() const
47 {
48     return DcmFGTypes::EFGS_UNKNOWN;
49 }
50 
compare(const FGBase & rhs) const51 int FGBase::compare(const FGBase& rhs) const
52 {
53     // Check for equality from FGBase' point of view
54 
55     // Same objects?
56     if (this == &rhs)
57         return 0;
58 
59     // Type identical?
60     if (this->getType() != rhs.getType())
61         return -1;
62 
63     // This is all we can do
64     return 0;
65 }
66 
getItemFromFGSequence(DcmItem & source,const DcmTagKey & seqKey,const long unsigned int itemNum,DcmItem * & result)67 OFCondition FGBase::getItemFromFGSequence(DcmItem& source,
68                                           const DcmTagKey& seqKey,
69                                           const long unsigned int itemNum,
70                                           DcmItem*& result)
71 {
72     result                  = NULL;
73     DcmSequenceOfItems* seq = NULL;
74     if (source.findAndGetSequence(seqKey, seq).bad())
75     {
76         DCMFG_ERROR("Functional Group Sequence does not exist: " << seqKey << " (" << DcmFGTypes::tagKey2FGType(seqKey)
77                                                                  << ")");
78         return EC_TagNotFound;
79     }
80     result = seq->getItem(itemNum);
81     if (result == NULL)
82     {
83         DCMFG_DEBUG("Functional Group Sequence " << seqKey << " (" << DcmFGTypes::tagKey2FGType(seqKey)
84                                                  << ") does not have " << itemNum - 1 << " items");
85         return FG_EC_NotEnoughItems;
86     }
87     return EC_Normal;
88 }
89 
getNumItemsFromFGSequence(DcmItem & source,const DcmTagKey & seqKey,unsigned long & result)90 OFCondition FGBase::getNumItemsFromFGSequence(DcmItem& source, const DcmTagKey& seqKey, unsigned long& result)
91 {
92     result                  = 0;
93     DcmSequenceOfItems* seq = NULL;
94     if (source.findAndGetSequence(seqKey, seq).bad())
95     {
96         DCMFG_ERROR("Functional Group Sequence does not exist: " << seqKey << " (" << DcmFGTypes::tagKey2FGType(seqKey)
97                                                                  << ")");
98         return EC_TagNotFound;
99     }
100     result = seq->card();
101     return EC_Normal;
102 }
103 
createNewFGSequence(DcmItem & destination,const DcmTagKey & seqKey,const unsigned long numItems,DcmItem * & firstItem)104 OFCondition FGBase::createNewFGSequence(DcmItem& destination,
105                                         const DcmTagKey& seqKey,
106                                         const unsigned long numItems,
107                                         DcmItem*& firstItem)
108 {
109     if (numItems > OFstatic_cast(unsigned long, OFnumeric_limits<signed long>::max()))
110         return EC_IllegalParameter;
111 
112     firstItem          = NULL;
113     OFCondition result = destination.insertEmptyElement(seqKey, OFTrue /* replace old */);
114     if (result.bad())
115     {
116         DCMFG_ERROR("Could not create Functional Group with sequence " << seqKey << " ("
117                                                                        << DcmFGTypes::tagKey2FGType(seqKey) << ")");
118         return FG_EC_CouldNotInsertFG;
119     }
120     DcmItem* dummy = NULL;
121     result         = destination.findOrCreateSequenceItem(seqKey, dummy, OFstatic_cast(signed long, numItems));
122     if (result.bad())
123     {
124         // clean up
125         destination.findAndDeleteElement(seqKey);
126         DCMFG_ERROR("Could not create " << numItems << " items in Functional Group with sequence " << seqKey << " ("
127                                         << DcmFGTypes::tagKey2FGType(seqKey) << ")");
128         return FG_EC_CouldNotInsertFG;
129     }
130     destination.findOrCreateSequenceItem(seqKey, firstItem, 0);
131     return EC_Normal;
132 }
133 
134 // ------------------ class FGUnknown ------------------------------------
135 
FGUnknown(const DcmTagKey & seqStartTag,const DcmFGTypes::E_FGSharedType sharedType)136 FGUnknown::FGUnknown(const DcmTagKey& seqStartTag, const DcmFGTypes::E_FGSharedType sharedType)
137     : FGBase(DcmFGTypes::EFG_UNKNOWN)
138     , m_seqStartTag(seqStartTag)
139     , m_fgSequence(NULL)
140     , m_sharedType(sharedType)
141 {
142 }
143 
FGUnknown(const FGUnknown & rhs)144 FGUnknown::FGUnknown(const FGUnknown& rhs)
145     : FGBase(DcmFGTypes::EFG_UNKNOWN)
146     , m_seqStartTag(rhs.m_seqStartTag)
147     , m_fgSequence(OFstatic_cast(DcmSequenceOfItems*, rhs.m_fgSequence->clone()))
148     , m_sharedType(rhs.m_sharedType)
149 {
150 }
151 
operator =(const FGUnknown & rhs)152 FGUnknown& FGUnknown::operator=(const FGUnknown& rhs)
153 {
154     m_seqStartTag = rhs.m_seqStartTag;
155     m_fgSequence  = OFstatic_cast(DcmSequenceOfItems*, rhs.m_fgSequence->clone());
156     m_sharedType  = rhs.m_sharedType;
157     return *this;
158 }
159 
clearData()160 void FGUnknown::clearData()
161 {
162     if (m_fgSequence != NULL)
163     {
164         delete m_fgSequence;
165         m_fgSequence = NULL;
166     }
167 }
168 
read(DcmItem & item)169 OFCondition FGUnknown::read(DcmItem& item)
170 {
171     // clear old data
172     clearData();
173     OFCondition result = item.findAndGetSequence(
174         m_seqStartTag, m_fgSequence, OFFalse /* no depth search */, OFTrue /* create copy! */);
175     if (result.bad())
176     {
177         if (m_fgSequence != NULL)
178             delete m_fgSequence;
179         m_fgSequence = NULL;
180     }
181     return result;
182 }
183 
write(DcmItem & item)184 OFCondition FGUnknown::write(DcmItem& item)
185 {
186     return item.insert(new DcmSequenceOfItems(*m_fgSequence), OFTrue /* replace old! */);
187 }
188 
check() const189 OFCondition FGUnknown::check() const
190 {
191     return EC_Normal;
192 }
193 
compare(const FGBase & rhs) const194 int FGUnknown::compare(const FGBase& rhs) const
195 {
196     int result = FGBase::compare(rhs);
197     if (result == 0)
198     {
199         const FGUnknown* myRhs = OFstatic_cast(const FGUnknown*, &rhs);
200 
201         // Compare all elements
202         if (m_seqStartTag == myRhs->m_seqStartTag)
203         {
204             if (m_fgSequence && myRhs->m_fgSequence)
205             {
206                 result = m_fgSequence->compare(*(myRhs->m_fgSequence));
207             }
208             else if (!m_fgSequence && !myRhs->m_fgSequence) // if both are not set, objects are still equal
209             {
210                 result = 0;
211             }
212             else if (m_fgSequence)
213             {
214                 result = 1; // this object is bigger (more information)
215             }
216             else if (myRhs->m_fgSequence)
217             {
218                 result = -1; // rhs object is bigger (more information)
219             }
220         }
221         else
222         {
223             result = (m_seqStartTag < myRhs->m_seqStartTag) ? -1 : 1;
224         }
225     }
226 
227     return result;
228 }
229 
~FGUnknown()230 FGUnknown::~FGUnknown()
231 {
232     clearData();
233 }
234 
clone() const235 FGBase* FGUnknown::clone() const
236 {
237     FGUnknown* copy = new FGUnknown(this->m_seqStartTag);
238     if (copy)
239     {
240         *(copy->m_fgSequence) = *(this->m_fgSequence);
241     }
242     return copy;
243 }
244