Coverage Report

Created: 2024-09-08 06:18

/src/librawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
    RawSpeed - RAW file decoder.
3
4
    Copyright (C) 2009-2014 Klaus Post
5
    Copyright (C) 2017-2018 Roman Lebeedv
6
7
    This library is free software; you can redistribute it and/or
8
    modify it under the terms of the GNU Lesser General Public
9
    License as published by the Free Software Foundation; either
10
    version 2 of the License, or (at your option) any later version.
11
12
    This library is distributed in the hope that it will be useful,
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
    Lesser General Public License for more details.
16
17
    You should have received a copy of the GNU Lesser General Public
18
    License along with this library; if not, write to the Free Software
19
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
#include "rawspeedconfig.h"
23
#include "decompressors/AbstractDngDecompressor.h"
24
#include "adt/Array1DRef.h"
25
#include "adt/Casts.h"
26
#include "adt/Invariant.h"
27
#include "adt/Point.h"
28
#include "bitstreams/BitStreams.h"
29
#include "common/Common.h"
30
#include "common/RawImage.h"
31
#include "decoders/RawDecoderException.h"
32
#include "decompressors/LJpegDecoder.h"
33
#include "decompressors/UncompressedDecompressor.h"
34
#include "decompressors/VC5Decompressor.h"
35
#include "io/ByteStream.h"
36
#include "io/Endianness.h"
37
#include "io/IOException.h"
38
#include <cstdint>
39
#include <limits>
40
#include <string>
41
#include <vector>
42
43
#ifdef HAVE_ZLIB
44
#include "decompressors/DeflateDecompressor.h"
45
#include <memory>
46
#endif
47
48
#ifdef HAVE_JPEG
49
#include "decompressors/JpegDecompressor.h"
50
#endif
51
52
namespace rawspeed {
53
54
91.1k
template <> void AbstractDngDecompressor::decompressThread<1>() const noexcept {
55
91.1k
#ifdef HAVE_OPENMP
56
91.1k
#pragma omp for schedule(static)
57
91.1k
#endif
58
91.1k
  for (const auto& e :
59
91.1k
       Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) {
60
91.1k
    try {
61
91.1k
      iPoint2D tileSize(e.width, e.height);
62
91.1k
      iPoint2D pos(e.offX, e.offY);
63
64
91.1k
      bool big_endian = e.bs.getByteOrder() == Endianness::big;
65
66
      // DNG spec says that if not 8/16/32 bit/sample, always use big endian.
67
      // It's not very obvious, but that does not appear to apply to FP.
68
91.1k
      switch (mBps) {
69
91.1k
      case 8:
70
91.1k
      case 16:
71
91.1k
      case 32:
72
91.1k
        break;
73
91.1k
      default:
74
91.1k
        if (mRaw->getDataType() == RawImageType::UINT16)
75
91.1k
          big_endian = true;
76
91.1k
        break;
77
91.1k
      }
78
79
91.1k
      const uint32_t inputPixelBits = mRaw->getCpp() * mBps;
80
81
91.1k
      if (e.dsc.tileW > std::numeric_limits<int>::max() / inputPixelBits)
82
91.1k
        ThrowIOE("Integer overflow when calculating input pitch");
83
84
91.1k
      const int inputPitchBits = inputPixelBits * e.dsc.tileW;
85
91.1k
      invariant(inputPitchBits > 0);
86
87
91.1k
      if (inputPitchBits % 8 != 0) {
88
91.1k
        ThrowRDE("Bad combination of cpp (%u), bps (%u) and width (%u), the "
89
91.1k
                 "pitch is %u bits, which is not a multiple of 8 (1 byte)",
90
91.1k
                 mRaw->getCpp(), mBps, e.width, inputPitchBits);
91
91.1k
      }
92
93
91.1k
      const int inputPitch = inputPitchBits / 8;
94
91.1k
      if (inputPitch == 0)
95
91.1k
        ThrowRDE("Data input pitch is too short. Can not decode!");
96
97
91.1k
      UncompressedDecompressor decompressor(
98
91.1k
          e.bs, mRaw, iRectangle2D(pos, tileSize), inputPitch, mBps,
99
91.1k
          big_endian ? BitOrder::MSB : BitOrder::LSB);
100
91.1k
      decompressor.readUncompressedRaw();
101
91.1k
    } catch (const RawDecoderException& err) {
102
91.1k
      mRaw->setError(err.what());
103
91.1k
    } catch (const IOException& err) {
104
91.1k
      mRaw->setError(err.what());
105
91.1k
    } catch (...) {
106
      // We should not get any other exception type here.
107
91.1k
      __builtin_unreachable();
108
91.1k
    }
109
91.1k
  }
110
91.1k
}
111
112
30.9k
template <> void AbstractDngDecompressor::decompressThread<7>() const noexcept {
113
30.9k
#ifdef HAVE_OPENMP
114
30.9k
#pragma omp for schedule(static)
115
30.9k
#endif
116
30.9k
  for (const auto& e :
117
30.9k
       Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) {
118
30.9k
    try {
119
30.9k
      LJpegDecoder d(e.bs, mRaw);
120
30.9k
      d.decode(e.offX, e.offY, e.width, e.height,
121
30.9k
               iPoint2D(e.dsc.tileW, e.dsc.tileH), mFixLjpeg);
122
30.9k
    } catch (const RawDecoderException& err) {
123
30.9k
      mRaw->setError(err.what());
124
30.9k
    } catch (const IOException& err) {
125
30.9k
      mRaw->setError(err.what());
126
30.9k
    } catch (...) {
127
      // We should not get any other exception type here.
128
30.9k
      __builtin_unreachable();
129
30.9k
    }
130
30.9k
  }
131
30.9k
}
132
133
#ifdef HAVE_ZLIB
134
template <> void AbstractDngDecompressor::decompressThread<8>() const noexcept {
135
  // NOLINTNEXTLINE(modernize-avoid-c-arrays)
136
  std::unique_ptr<unsigned char[]> uBuffer;
137
138
#ifdef HAVE_OPENMP
139
#pragma omp for schedule(static)
140
#endif
141
  for (const auto& e :
142
       Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) {
143
    try {
144
      DeflateDecompressor z(e.bs.peekBuffer(e.bs.getRemainSize()), mRaw,
145
                            mPredictor, mBps);
146
      z.decode(&uBuffer, iPoint2D(mRaw->getCpp() * e.dsc.tileW, e.dsc.tileH),
147
               iPoint2D(mRaw->getCpp() * e.width, e.height),
148
               iPoint2D(mRaw->getCpp() * e.offX, e.offY));
149
    } catch (const RawDecoderException& err) {
150
      mRaw->setError(err.what());
151
    } catch (const IOException& err) {
152
      mRaw->setError(err.what());
153
    } catch (...) {
154
      // We should not get any other exception type here.
155
      __builtin_unreachable();
156
    }
157
  }
158
}
159
#endif
160
161
31.5k
template <> void AbstractDngDecompressor::decompressThread<9>() const noexcept {
162
31.5k
#ifdef HAVE_OPENMP
163
31.5k
#pragma omp for schedule(static)
164
31.5k
#endif
165
31.5k
  for (const auto& e :
166
31.5k
       Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) {
167
31.5k
    try {
168
31.5k
      VC5Decompressor d(e.bs, mRaw);
169
31.5k
      d.decode(e.offX, e.offY, e.width, e.height);
170
31.5k
    } catch (const RawDecoderException& err) {
171
31.5k
      mRaw->setError(err.what());
172
31.5k
    } catch (const IOException& err) {
173
31.5k
      mRaw->setError(err.what());
174
31.5k
    } catch (...) {
175
      // We should not get any other exception type here.
176
31.5k
      __builtin_unreachable();
177
31.5k
    }
178
31.5k
  }
179
31.5k
}
180
181
#ifdef HAVE_JPEG
182
template <>
183
void AbstractDngDecompressor::decompressThread<0x884c>() const noexcept {
184
#ifdef HAVE_OPENMP
185
#pragma omp for schedule(static)
186
#endif
187
  for (const auto& e :
188
       Array1DRef(slices.data(), implicit_cast<int>(slices.size()))) {
189
    try {
190
      JpegDecompressor j(e.bs.peekBuffer(e.bs.getRemainSize()), mRaw);
191
      j.decode(e.offX, e.offY);
192
    } catch (const RawDecoderException& err) {
193
      mRaw->setError(err.what());
194
    } catch (const IOException& err) {
195
      mRaw->setError(err.what());
196
    } catch (...) {
197
      // We should not get any other exception type here.
198
      __builtin_unreachable();
199
    }
200
  }
201
}
202
#endif
203
204
39.8k
void AbstractDngDecompressor::decompressThread() const noexcept {
205
39.8k
  invariant(mRaw->dim.x > 0);
206
39.9k
  invariant(mRaw->dim.y > 0);
207
39.0k
  invariant(mRaw->getCpp() > 0 && mRaw->getCpp() <= 4);
208
37.6k
  invariant(mBps > 0 && mBps <= 32);
209
210
37.7k
  if (compression == 1) {
211
    /* Uncompressed */
212
14.1k
    decompressThread<1>();
213
23.5k
  } else if (compression == 7) {
214
    /* Lossless JPEG */
215
10.9k
    decompressThread<7>();
216
12.6k
  } else if (compression == 8) {
217
    /* Deflate compression */
218
#ifdef HAVE_ZLIB
219
    decompressThread<8>();
220
#else
221
0
#pragma message                                                                \
222
0
    "ZLIB is not present! Deflate compression will not be supported!"
223
0
    mRaw->setError("deflate support is disabled.");
224
0
#endif
225
12.6k
  } else if (compression == 9) {
226
    /* GOPRO VC-5 */
227
12.6k
    decompressThread<9>();
228
12.6k
  } else if (compression == 0x884c) {
229
    /* Lossy DNG */
230
#ifdef HAVE_JPEG
231
    decompressThread<0x884c>();
232
#else
233
0
#pragma message "JPEG is not present! Lossy JPEG DNG will not be supported!"
234
0
    mRaw->setError("jpeg support is disabled.");
235
0
#endif
236
0
  } else
237
16
    mRaw->setError("AbstractDngDecompressor: Unknown compression");
238
37.7k
}
239
240
11.7k
void AbstractDngDecompressor::decompress() const {
241
11.7k
#ifdef HAVE_OPENMP
242
11.7k
#pragma omp parallel default(none) num_threads(                                \
243
11.7k
        rawspeed_get_number_of_processor_cores()) if (slices.size() > 1)
244
11.7k
#endif
245
40.0k
  decompressThread();
246
247
11.7k
  std::string firstErr;
248
11.7k
  if (mRaw->isTooManyErrors(1, &firstErr)) {
249
2.87k
    ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
250
2.87k
             firstErr.c_str());
251
2.87k
  }
252
11.7k
}
253
254
} // namespace rawspeed