1 /*
2  *
3  *  Copyright (C) 1997-2020, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module:  dcmdata
15  *
16  *  Author:  Andreas Barth
17  *
18  *  Purpose: abstract class DcmCodec and the class DcmCodecStruct
19  *
20  */
21 
22 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
23 #include "dcmtk/dcmdata/dccodec.h"
24 #include "dcmtk/ofstd/oflist.h"
25 #include "dcmtk/ofstd/ofthread.h"
26 #include "dcmtk/dcmdata/dcdeftag.h"  /* for tag constants */
27 #include "dcmtk/dcmdata/dcuid.h"     /* for dcmGenerateUniqueIdentifer()*/
28 #include "dcmtk/dcmdata/dcitem.h"    /* for class DcmItem */
29 #include "dcmtk/dcmdata/dcsequen.h"  /* for DcmSequenceOfItems */
30 #include "dcmtk/dcmdata/dcpixseq.h"  /* for DcmPixelSequence */
31 #include "dcmtk/dcmdata/dcpxitem.h"  /* for DcmPixelItem */
32 #include "dcmtk/dcmdata/dcswap.h"    /* for swapIfNecessary */
33 #include "dcmtk/dcmdata/dcvrui.h"    /* for DcmUniqueIdentifier */
34 
35 // static member variables
36 OFList<DcmCodecList *> DcmCodecList::registeredCodecs;
37 
38 #ifdef WITH_THREADS
39 OFReadWriteLock DcmCodecList::codecLock;
40 #endif
41 
42 /* --------------------------------------------------------------- */
43 
44 // DcmCodec static helper methods
45 
insertStringIfMissing(DcmItem * dataset,const DcmTagKey & tag,const char * val)46 OFCondition DcmCodec::insertStringIfMissing(DcmItem *dataset, const DcmTagKey& tag, const char *val)
47 {
48   DcmStack stack;
49   if ((dataset->search(tag, stack, ESM_fromHere, OFFalse)).bad())
50   {
51     return dataset->putAndInsertString(tag, val, OFTrue);
52   }
53   return EC_Normal;
54 }
55 
56 
convertToSecondaryCapture(DcmItem * dataset)57 OFCondition DcmCodec::convertToSecondaryCapture(DcmItem *dataset)
58 {
59   if (dataset == NULL) return EC_IllegalCall;
60 
61   OFCondition result = EC_Normal;
62   char buf[70];
63 
64   // SOP Class UID - always replace
65   if (result.good()) result = dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
66 
67   // SOP Instance UID - only insert if missing.
68   dcmGenerateUniqueIdentifier(buf);
69   if (result.good()) result = insertStringIfMissing(dataset, DCM_SOPInstanceUID, buf);
70 
71   // Type 1 attributes - insert with value if missing
72   dcmGenerateUniqueIdentifier(buf, SITE_STUDY_UID_ROOT);
73   if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyInstanceUID, buf);
74   dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
75   if (result.good()) result = insertStringIfMissing(dataset, DCM_SeriesInstanceUID, buf);
76   if (result.good()) result = insertStringIfMissing(dataset, DCM_ConversionType, "WSD");
77   if (result.good()) result = insertStringIfMissing(dataset, DCM_Modality, "OT");
78 
79   // Type 2 attributes - insert without value if missing
80   if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientName, NULL);
81   if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientID, NULL);
82   if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientBirthDate, NULL);
83   if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientSex, NULL);
84   if (result.good()) result = insertStringIfMissing(dataset, DCM_PatientOrientation, NULL);
85   if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyDate, NULL);
86   if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyTime, NULL);
87   if (result.good()) result = insertStringIfMissing(dataset, DCM_ReferringPhysicianName, NULL);
88   if (result.good()) result = insertStringIfMissing(dataset, DCM_StudyID, NULL);
89   if (result.good()) result = insertStringIfMissing(dataset, DCM_AccessionNumber, NULL);
90   if (result.good()) result = insertStringIfMissing(dataset, DCM_SeriesNumber, NULL);
91   if (result.good()) result = insertStringIfMissing(dataset, DCM_InstanceNumber, NULL);
92 
93   return result;
94 }
95 
96 
insertCodeSequence(DcmItem * dataset,const DcmTagKey & tagKey,const char * codingSchemeDesignator,const char * codeValue,const char * codeMeaning)97 OFCondition DcmCodec::insertCodeSequence(
98   DcmItem *dataset,
99   const DcmTagKey &tagKey,
100   const char *codingSchemeDesignator,
101   const char *codeValue,
102   const char *codeMeaning)
103 {
104   if (dataset == NULL || codingSchemeDesignator == NULL ||
105      codeValue == NULL || codeMeaning == NULL) return EC_IllegalCall;
106 
107   OFCondition result = EC_Normal;
108   DcmSequenceOfItems *dseq = new DcmSequenceOfItems(tagKey);
109   if (dseq)
110   {
111     DcmItem *ditem = new DcmItem();
112     if (ditem)
113     {
114       dseq->insert(ditem);
115       result = ditem->putAndInsertString(DCM_CodingSchemeDesignator, codingSchemeDesignator);
116       if (result.good()) result = ditem->putAndInsertString(DCM_CodeValue, codeValue);
117       if (result.good()) result = ditem->putAndInsertString(DCM_CodeMeaning, codeMeaning);
118     } else result = EC_MemoryExhausted;
119 
120     // insert sequence into dataset if everything went well
121     if (result.good()) dataset->insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
122   } else result = EC_MemoryExhausted;
123 
124   return result;
125 }
126 
127 
newInstance(DcmItem * dataset,const char * purposeOfReferenceCodingScheme,const char * purposeOfReferenceCodeValue,const char * purposeOfReferenceCodeMeaning)128 OFCondition DcmCodec::newInstance(
129   DcmItem *dataset,
130   const char *purposeOfReferenceCodingScheme,
131   const char *purposeOfReferenceCodeValue,
132   const char *purposeOfReferenceCodeMeaning)
133 {
134   if (dataset == NULL) return EC_IllegalCall;
135   OFCondition result = EC_Normal;
136 
137   // look up current SOP Class UID and SOP Instance UID
138   const char *classUID = NULL;
139   const char *instanceUID = NULL;
140 
141   // search for existing SOP Class UID / SOP Instance UID
142   OFCondition tempResult = dataset->findAndGetString(DCM_SOPClassUID, classUID);
143   if (tempResult.good()) tempResult = dataset->findAndGetString(DCM_SOPInstanceUID, instanceUID);
144   if (tempResult.good() && classUID && instanceUID)
145   {
146     // create source image sequence
147     DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_SourceImageSequence);
148     if (dseq)
149     {
150       DcmItem *ditem = new DcmItem();
151       if (ditem)
152       {
153         dseq->insert(ditem);
154         DcmElement *elem1 = new DcmUniqueIdentifier(DCM_ReferencedSOPClassUID);
155         if (elem1)
156         {
157           result = elem1->putString(classUID);
158           ditem->insert(elem1, OFTrue /*replaceOld*/);
159           if (result.good())
160           {
161             DcmElement *elem2 = new DcmUniqueIdentifier(DCM_ReferencedSOPInstanceUID);
162             if (elem2)
163             {
164               result = elem2->putString(instanceUID);
165               ditem->insert(elem2, OFTrue /*replaceOld*/);
166             } else result = EC_MemoryExhausted;
167           }
168         } else result = EC_MemoryExhausted;
169 
170         if (result.good() && purposeOfReferenceCodingScheme &&
171            purposeOfReferenceCodeValue && purposeOfReferenceCodeMeaning)
172         {
173           // add purpose of reference code sequence
174           result = DcmCodec::insertCodeSequence(ditem, DCM_PurposeOfReferenceCodeSequence,
175             purposeOfReferenceCodingScheme, purposeOfReferenceCodeValue, purposeOfReferenceCodeMeaning);
176         }
177       } else result = EC_MemoryExhausted;
178       if (result.good()) dataset->insert(dseq, OFTrue); else delete dseq;
179     } else result = EC_MemoryExhausted;
180   }
181 
182   // create new SOP instance UID
183   if (result.good())
184   {
185     char new_uid[100];
186     DcmElement *elem = new DcmUniqueIdentifier(DCM_SOPInstanceUID);
187     if (elem)
188     {
189       if (EC_Normal == (result = elem->putString(dcmGenerateUniqueIdentifier(new_uid))))
190         dataset->insert(elem, OFTrue); // replace SOP Instance UID
191         else delete elem;
192     } else result = EC_MemoryExhausted;
193   }
194 
195   return result;
196 }
197 
198 
updateImageType(DcmItem * dataset)199 OFCondition DcmCodec::updateImageType(DcmItem *dataset)
200 {
201   if (dataset == NULL) return EC_IllegalCall;
202 
203   DcmStack stack;
204   OFString imageType("DERIVED");
205   OFString a;
206 
207   /* find existing Image Type element */
208   OFCondition status = dataset->search(DCM_ImageType, stack, ESM_fromHere, OFFalse);
209   if (status.good())
210   {
211     DcmElement *elem = OFstatic_cast(DcmElement *, stack.top());
212     unsigned long pos = 1;
213 
214     // append old image type information beginning with second entry
215     while ((elem->getOFString(a, pos++)).good())
216     {
217       imageType += "\\";
218       imageType += a;
219     }
220   }
221 
222   // insert new Image Type, replace old value
223   return dataset->putAndInsertString(DCM_ImageType, imageType.c_str(), OFTrue);
224 }
225 
226 
determineStartFragment(Uint32 frameNo,Sint32 numberOfFrames,DcmPixelSequence * fromPixSeq,Uint32 & currentItem)227 OFCondition DcmCodec::determineStartFragment(
228   Uint32 frameNo,
229   Sint32 numberOfFrames,
230   DcmPixelSequence * fromPixSeq,
231   Uint32& currentItem)
232 {
233   Uint32 numberOfFragments = OFstatic_cast(Uint32, fromPixSeq->card());
234   if (numberOfFrames < 1 || numberOfFragments <= OFstatic_cast(Uint32, numberOfFrames) || frameNo >= OFstatic_cast(Uint32, numberOfFrames))
235     return EC_IllegalCall;
236 
237   if (frameNo == 0)
238   {
239     // simple case: first frame is always at second fragment
240     currentItem = 1;
241     return EC_Normal;
242   }
243 
244   if (numberOfFragments == OFstatic_cast(Uint32, numberOfFrames) + 1)
245   {
246     // standard case: there is one fragment per frame.
247     currentItem = frameNo + 1;
248     return EC_Normal;
249   }
250 
251   // non-standard case: multiple fragments per frame.
252   // We now try to consult the offset table.
253   DcmPixelItem *pixItem = NULL;
254   Uint8 *rawOffsetTable = NULL;
255 
256   // get first pixel item, i.e. the fragment containing the offset table
257   OFCondition result = fromPixSeq->getItem(pixItem, 0);
258   if (result.good())
259   {
260     Uint32 tableLength = pixItem->getLength();
261     result = pixItem->getUint8Array(rawOffsetTable);
262     if (result.good())
263     {
264       // check if the offset table is empty
265       if (tableLength == 0)
266         result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: basic offset table is empty");
267       // check if the offset table has the right size: 4 bytes for each frame (not fragment!)
268       else if (tableLength != 4 * OFstatic_cast(Uint32, numberOfFrames))
269         result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: basic offset table has wrong size");
270       else {
271 
272         // byte swap offset table into local byte order. In file, the offset table is always in little endian
273         swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, rawOffsetTable, tableLength, sizeof(Uint32));
274 
275         // cast offset table to Uint32.
276         Uint32 *offsetTable = OFreinterpret_cast(Uint32 *, rawOffsetTable);
277 
278         // now access offset of the frame we're looking for
279         Uint32 offset = offsetTable[frameNo];
280 
281         // OK, now let's look if we can find a fragment that actually corresponds to that offset.
282         // In counter we compute the offset for each frame by adding all fragment lengths
283         Uint32 counter = 0;
284         // now iterate over all fragments except the index table. The start of the first fragment
285         // is defined as zero.
286         for (Uint32 idx = 1; idx < numberOfFragments; ++idx)
287         {
288           if (counter == offset)
289           {
290             // hooray, we are lucky. We have found the fragment we're looking for
291             currentItem = idx;
292             return EC_Normal;
293           }
294 
295           // access pixel item in order to determine its length
296           result = fromPixSeq->getItem(pixItem, idx);
297           if (result.bad())
298             return makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: cannot access referenced pixel item");
299 
300           // add pixel item length plus 8 bytes overhead for the item tag and length field
301           counter += pixItem->getLength() + 8;
302         }
303 
304         // bad luck. We have not found a fragment corresponding to the offset in the offset table.
305         // Either we cannot correctly add numbers, or they cannot :-)
306         result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: possibly wrong value in basic offset table");
307       }
308     } else
309       result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: cannot access content of basic offset table");
310   } else
311     result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotDetermineStartFragment, OF_error, "Cannot determine start fragment: cannot access basic offset table (first item)");
312   return result;
313 }
314 
315 
316 /* --------------------------------------------------------------- */
317 
DcmCodecList(const DcmCodec * aCodec,const DcmRepresentationParameter * aDefaultRepParam,const DcmCodecParameter * aCodecParameter)318 DcmCodecList::DcmCodecList(
319   const DcmCodec *aCodec,
320   const DcmRepresentationParameter *aDefaultRepParam,
321   const DcmCodecParameter *aCodecParameter)
322 : codec(aCodec)
323 , defaultRepParam(aDefaultRepParam)
324 , codecParameter(aCodecParameter)
325 {
326 }
327 
~DcmCodecList()328 DcmCodecList::~DcmCodecList()
329 {
330 }
331 
registerCodec(const DcmCodec * aCodec,const DcmRepresentationParameter * aDefaultRepParam,const DcmCodecParameter * aCodecParameter)332 OFCondition DcmCodecList::registerCodec(
333   const DcmCodec *aCodec,
334   const DcmRepresentationParameter *aDefaultRepParam,
335   const DcmCodecParameter *aCodecParameter)
336 {
337   if ((aCodec == NULL)||(aCodecParameter == NULL)) return EC_IllegalParameter;
338 #ifdef WITH_THREADS
339   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
340 #endif
341 
342   // acquire write lock on codec list.  Will block if some codec is currently active.
343   OFCondition result = EC_Normal;
344 #ifdef WITH_THREADS
345   OFReadWriteLocker locker(codecLock);
346   if (0 == locker.wrlock())
347   {
348 #endif
349     DcmCodecList *listEntry = new DcmCodecList(aCodec, aDefaultRepParam, aCodecParameter);
350     if (listEntry)
351     {
352       // prevent codec from being registered twice
353       OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
354       OFListIterator(DcmCodecList *) last = registeredCodecs.end();
355       while (first != last)
356       {
357         if ((*first)->codec == aCodec)
358         {
359           // this codec is already registered.
360           first = last;
361           result = EC_IllegalCall;
362         } else ++first;
363       }
364       if (result.good()) registeredCodecs.push_back(listEntry); else delete listEntry;
365     } else result = EC_MemoryExhausted;
366 #ifdef WITH_THREADS
367   } else result = EC_IllegalCall;
368 #endif
369   return result;
370 }
371 
deregisterCodec(const DcmCodec * aCodec)372 OFCondition DcmCodecList::deregisterCodec(const DcmCodec *aCodec)
373 {
374   if (aCodec == NULL) return EC_IllegalParameter;
375 #ifdef WITH_THREADS
376   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
377 #endif
378   // acquire write lock on codec list.  Will block if some codec is currently active.
379   OFCondition result = EC_Normal;
380 
381 #ifdef WITH_THREADS
382   OFReadWriteLocker locker(codecLock);
383   if (0 == locker.wrlock())
384   {
385 #endif
386     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
387     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
388     while (first != last)
389     {
390       if ((*first)->codec == aCodec)
391       {
392         delete *first;
393         first = registeredCodecs.erase(first);
394       } else ++first;
395     }
396 #ifdef WITH_THREADS
397   } else result = EC_IllegalCall;
398 #endif
399   return result;
400 }
401 
updateCodecParameter(const DcmCodec * aCodec,const DcmCodecParameter * aCodecParameter)402 OFCondition DcmCodecList::updateCodecParameter(
403   const DcmCodec *aCodec,
404   const DcmCodecParameter *aCodecParameter)
405 {
406   if ((aCodec == NULL)||(aCodecParameter == NULL)) return EC_IllegalParameter;
407 #ifdef WITH_THREADS
408   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
409 #endif
410   // acquire write lock on codec list.  Will block if some codec is currently active.
411   OFCondition result = EC_Normal;
412 
413 #ifdef WITH_THREADS
414   OFReadWriteLocker locker(codecLock);
415   if (0 == locker.wrlock())
416   {
417 #endif
418     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
419     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
420     while (first != last)
421     {
422       if ((*first)->codec == aCodec) (*first)->codecParameter = aCodecParameter;
423       ++first;
424     }
425 #ifdef WITH_THREADS
426   } else result = EC_IllegalCall;
427 #endif
428   return result;
429 }
430 
431 
decode(const DcmXfer & fromType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,DcmPolymorphOBOW & uncompressedPixelData,DcmStack & pixelStack,OFBool & removeOldRep)432 OFCondition DcmCodecList::decode(
433   const DcmXfer & fromType,
434   const DcmRepresentationParameter * fromParam,
435   DcmPixelSequence * fromPixSeq,
436   DcmPolymorphOBOW& uncompressedPixelData,
437   DcmStack & pixelStack,
438   OFBool& removeOldRep)
439 {
440 #ifdef WITH_THREADS
441   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
442 #endif
443   OFCondition result = EC_CannotChangeRepresentation;
444 
445   // acquire write lock on codec list.  Will block if some write lock is currently active.
446 #ifdef WITH_THREADS
447   OFReadWriteLocker locker(codecLock);
448   if (0 == locker.rdlock())
449   {
450 #endif
451     E_TransferSyntax fromXfer = fromType.getXfer();
452     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
453     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
454     while (first != last)
455     {
456       if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
457       {
458         result = (*first)->codec->decode(fromParam, fromPixSeq, uncompressedPixelData, (*first)->codecParameter, pixelStack, removeOldRep);
459         first = last;
460       } else ++first;
461     }
462 #ifdef WITH_THREADS
463   } else result = EC_IllegalCall;
464 #endif
465   return result;
466 }
467 
468 
decodeFrame(const DcmXfer & fromType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,DcmItem * dataset,Uint32 frameNo,Uint32 & startFragment,void * buffer,Uint32 bufSize,OFString & decompressedColorModel)469 OFCondition DcmCodecList::decodeFrame(
470   const DcmXfer & fromType,
471   const DcmRepresentationParameter * fromParam,
472   DcmPixelSequence * fromPixSeq,
473   DcmItem *dataset,
474   Uint32 frameNo,
475   Uint32& startFragment,
476   void *buffer,
477   Uint32 bufSize,
478   OFString& decompressedColorModel)
479 {
480 #ifdef WITH_THREADS
481   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
482 #endif
483   OFCondition result = EC_CannotChangeRepresentation;
484 
485   // acquire write lock on codec list.  Will block if some write lock is currently active.
486 #ifdef WITH_THREADS
487   OFReadWriteLocker locker(codecLock);
488   if (0 == locker.rdlock())
489   {
490 #endif
491     E_TransferSyntax fromXfer = fromType.getXfer();
492     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
493     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
494     while (first != last)
495     {
496       if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
497       {
498         result = (*first)->codec->decodeFrame(fromParam, fromPixSeq, (*first)->codecParameter,
499                  dataset, frameNo, startFragment, buffer, bufSize, decompressedColorModel);
500         first = last;
501       } else ++first;
502     }
503 #ifdef WITH_THREADS
504   } else result = EC_IllegalCall;
505 #endif
506   return result;
507 }
508 
509 
encode(const E_TransferSyntax fromRepType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,const E_TransferSyntax toRepType,const DcmRepresentationParameter * toRepParam,DcmPixelSequence * & toPixSeq,DcmStack & pixelStack,OFBool & removeOldRep)510 OFCondition DcmCodecList::encode(
511   const E_TransferSyntax fromRepType,
512   const DcmRepresentationParameter * fromParam,
513   DcmPixelSequence * fromPixSeq,
514   const E_TransferSyntax toRepType,
515   const DcmRepresentationParameter * toRepParam,
516   DcmPixelSequence * & toPixSeq,
517   DcmStack & pixelStack,
518   OFBool& removeOldRep)
519 {
520   toPixSeq = NULL;
521 #ifdef WITH_THREADS
522   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
523 #endif
524   OFCondition result = EC_CannotChangeRepresentation;
525 
526   // acquire write lock on codec list.  Will block if some write lock is currently active.
527 #ifdef WITH_THREADS
528   OFReadWriteLocker locker(codecLock);
529   if (0 == locker.rdlock())
530   {
531 #endif
532     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
533     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
534     while (first != last)
535     {
536       if ((*first)->codec->canChangeCoding(fromRepType, toRepType))
537       {
538         if (!toRepParam) toRepParam = (*first)->defaultRepParam;
539         result = (*first)->codec->encode(fromRepType, fromParam, fromPixSeq,
540                  toRepParam, toPixSeq, (*first)->codecParameter, pixelStack, removeOldRep);
541         first = last;
542       } else ++first;
543     }
544 #ifdef WITH_THREADS
545   } else result = EC_IllegalCall;
546 #endif
547 
548   return result;
549 }
550 
encode(const E_TransferSyntax fromRepType,const Uint16 * pixelData,const Uint32 length,const E_TransferSyntax toRepType,const DcmRepresentationParameter * toRepParam,DcmPixelSequence * & toPixSeq,DcmStack & pixelStack,OFBool & removeOldRep)551 OFCondition DcmCodecList::encode(
552   const E_TransferSyntax fromRepType,
553   const Uint16 * pixelData,
554   const Uint32 length,
555   const E_TransferSyntax toRepType,
556   const DcmRepresentationParameter * toRepParam,
557   DcmPixelSequence * & toPixSeq,
558   DcmStack & pixelStack,
559   OFBool& removeOldRep)
560 {
561   toPixSeq = NULL;
562 #ifdef WITH_THREADS
563   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
564 #endif
565   OFCondition result = EC_CannotChangeRepresentation;
566 
567   // acquire write lock on codec list.  Will block if some write lock is currently active.
568 #ifdef WITH_THREADS
569   OFReadWriteLocker locker(codecLock);
570   if (0 == locker.rdlock())
571   {
572 #endif
573     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
574     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
575     while (first != last)
576     {
577       if ((*first)->codec->canChangeCoding(fromRepType, toRepType))
578       {
579         if (!toRepParam) toRepParam = (*first)->defaultRepParam;
580         result = (*first)->codec->encode(pixelData, length, toRepParam, toPixSeq,
581                  (*first)->codecParameter, pixelStack, removeOldRep);
582         first = last;
583       } else ++first;
584     }
585 #ifdef WITH_THREADS
586   } else result = EC_IllegalCall;
587 #endif
588 
589   return result;
590 }
591 
canChangeCoding(const E_TransferSyntax fromRepType,const E_TransferSyntax toRepType)592 OFBool DcmCodecList::canChangeCoding(
593   const E_TransferSyntax fromRepType,
594   const E_TransferSyntax toRepType)
595 {
596 #ifdef WITH_THREADS
597   if (! codecLock.initialized()) return OFFalse; // should never happen
598 #endif
599   OFBool result = OFFalse;
600 
601   // acquire write lock on codec list.  Will block if some write lock is currently active.
602 #ifdef WITH_THREADS
603   OFReadWriteLocker locker(codecLock);
604   if (0 == locker.rdlock())
605   {
606 #endif
607     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
608     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
609     while (first != last)
610     {
611       if ((*first)->codec->canChangeCoding(fromRepType, toRepType))
612       {
613         result = OFTrue;
614         first = last;
615       } else ++first;
616     }
617 #ifdef WITH_THREADS
618   }
619 #endif
620 
621   return result;
622 }
623 
determineDecompressedColorModel(const DcmXfer & fromType,const DcmRepresentationParameter * fromParam,DcmPixelSequence * fromPixSeq,DcmItem * dataset,OFString & decompressedColorModel)624 OFCondition DcmCodecList::determineDecompressedColorModel(
625   const DcmXfer &fromType,
626   const DcmRepresentationParameter *fromParam,
627   DcmPixelSequence *fromPixSeq,
628   DcmItem *dataset,
629   OFString &decompressedColorModel)
630 {
631 #ifdef WITH_THREADS
632   if (! codecLock.initialized()) return EC_IllegalCall; // should never happen
633 #endif
634   OFCondition result = EC_CannotChangeRepresentation;
635 
636   // acquire write lock on codec list.  Will block if some write lock is currently active.
637 #ifdef WITH_THREADS
638   OFReadWriteLocker locker(codecLock);
639   if (0 == locker.rdlock())
640   {
641 #endif
642     E_TransferSyntax fromXfer = fromType.getXfer();
643     OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
644     OFListIterator(DcmCodecList *) last = registeredCodecs.end();
645     while (first != last)
646     {
647       if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
648       {
649         result = (*first)->codec->determineDecompressedColorModel(fromParam, fromPixSeq, (*first)->codecParameter,
650                  dataset, decompressedColorModel);
651         first = last;
652       } else ++first;
653     }
654 #ifdef WITH_THREADS
655   } else result = EC_IllegalCall;
656 #endif
657   return result;
658 }
659