Coverage Report

Created: 2026-11-12 07:19

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