Coverage Report

Created: 2025-06-09 07:43

/src/gdal/frmts/gtiff/gtiffoddbitsband.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GeoTIFF Driver
4
 * Purpose:  GDAL GeoTIFF support.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "gtiffoddbitsband.h"
15
16
#include "cpl_float.h"  // CPLFloatToHalf()
17
#include "gtiffdataset.h"
18
#include "tiffio.h"
19
20
/************************************************************************/
21
/*                           GTiffOddBitsBand()                         */
22
/************************************************************************/
23
24
GTiffOddBitsBand::GTiffOddBitsBand(GTiffDataset *m_poGDSIn, int nBandIn)
25
571k
    : GTiffRasterBand(m_poGDSIn, nBandIn)
26
27
571k
{
28
571k
    eDataType = GDT_Unknown;
29
571k
    if (m_poGDS->m_nBitsPerSample == 24 &&
30
571k
        m_poGDS->m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
31
119
        eDataType = GDT_Float32;
32
    // FIXME ? in autotest we currently open gcore/data/int24.tif
33
    // which is declared as signed, but we consider it as unsigned
34
571k
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
35
571k
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
36
571k
             m_poGDS->m_nBitsPerSample < 8)
37
557k
        eDataType = GDT_Byte;
38
13.5k
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
39
13.5k
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
40
13.5k
             m_poGDS->m_nBitsPerSample > 8 && m_poGDS->m_nBitsPerSample < 16)
41
12.6k
        eDataType = GDT_UInt16;
42
924
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
43
924
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
44
924
             m_poGDS->m_nBitsPerSample > 16 && m_poGDS->m_nBitsPerSample < 32)
45
412
        eDataType = GDT_UInt32;
46
571k
}
47
48
/************************************************************************/
49
/*                            IWriteBlock()                             */
50
/************************************************************************/
51
52
CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
53
                                     void *pImage)
54
55
0
{
56
0
    m_poGDS->Crystalize();
57
58
0
    if (m_poGDS->m_bWriteError)
59
0
    {
60
        // Report as an error if a previously loaded block couldn't be written
61
        // correctly.
62
0
        return CE_Failure;
63
0
    }
64
65
0
    if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample != 16)
66
0
    {
67
0
        ReportError(
68
0
            CE_Failure, CPLE_NotSupported,
69
0
            "Writing float data with nBitsPerSample = %d is unsupported",
70
0
            m_poGDS->m_nBitsPerSample);
71
0
        return CE_Failure;
72
0
    }
73
74
    /* -------------------------------------------------------------------- */
75
    /*      Load the block buffer.                                          */
76
    /* -------------------------------------------------------------------- */
77
0
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
78
79
    // Only read content from disk in the CONTIG case.
80
0
    {
81
0
        const CPLErr eErr = m_poGDS->LoadBlockBuf(
82
0
            nBlockId, m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
83
0
                          m_poGDS->nBands > 1);
84
0
        if (eErr != CE_None)
85
0
            return eErr;
86
0
    }
87
88
0
    const GUInt32 nMaxVal = (1U << m_poGDS->m_nBitsPerSample) - 1;
89
90
    /* -------------------------------------------------------------------- */
91
    /*      Handle case of "separate" images or single band images where    */
92
    /*      no interleaving with other data is required.                    */
93
    /* -------------------------------------------------------------------- */
94
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
95
0
        m_poGDS->nBands == 1)
96
0
    {
97
        // TODO(schwehr): Create a CplNumBits8Aligned.
98
        // Bits per line rounds up to next byte boundary.
99
0
        GInt64 nBitsPerLine =
100
0
            static_cast<GInt64>(nBlockXSize) * m_poGDS->m_nBitsPerSample;
101
0
        if ((nBitsPerLine & 7) != 0)
102
0
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
103
104
0
        GPtrDiff_t iPixel = 0;
105
106
        // Small optimization in 1 bit case.
107
0
        if (m_poGDS->m_nBitsPerSample == 1)
108
0
        {
109
0
            for (int iY = 0; iY < nBlockYSize; ++iY, iPixel += nBlockXSize)
110
0
            {
111
0
                GInt64 iBitOffset = iY * nBitsPerLine;
112
113
0
                const GByte *pabySrc =
114
0
                    static_cast<const GByte *>(pImage) + iPixel;
115
0
                auto iByteOffset = iBitOffset / 8;
116
0
                int iX = 0;  // Used after for.
117
0
                for (; iX + 7 < nBlockXSize; iX += 8, iByteOffset++)
118
0
                {
119
0
                    int nRes = (!(!pabySrc[iX + 0])) << 7;
120
0
                    nRes |= (!(!pabySrc[iX + 1])) << 6;
121
0
                    nRes |= (!(!pabySrc[iX + 2])) << 5;
122
0
                    nRes |= (!(!pabySrc[iX + 3])) << 4;
123
0
                    nRes |= (!(!pabySrc[iX + 4])) << 3;
124
0
                    nRes |= (!(!pabySrc[iX + 5])) << 2;
125
0
                    nRes |= (!(!pabySrc[iX + 6])) << 1;
126
0
                    nRes |= (!(!pabySrc[iX + 7])) << 0;
127
0
                    m_poGDS->m_pabyBlockBuf[iByteOffset] =
128
0
                        static_cast<GByte>(nRes);
129
0
                }
130
0
                iBitOffset = iByteOffset * 8;
131
0
                if (iX < nBlockXSize)
132
0
                {
133
0
                    int nRes = 0;
134
0
                    for (; iX < nBlockXSize; ++iX)
135
0
                    {
136
0
                        if (pabySrc[iX])
137
0
                            nRes |= (0x80 >> (iBitOffset & 7));
138
0
                        ++iBitOffset;
139
0
                    }
140
0
                    m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
141
0
                        static_cast<GByte>(nRes);
142
0
                }
143
0
            }
144
145
0
            m_poGDS->m_bLoadedBlockDirty = true;
146
147
0
            return CE_None;
148
0
        }
149
150
0
        if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample == 16)
151
0
        {
152
0
            for (; iPixel < static_cast<GPtrDiff_t>(nBlockYSize) * nBlockXSize;
153
0
                 iPixel++)
154
0
            {
155
0
                GUInt32 nInWord = static_cast<GUInt32 *>(pImage)[iPixel];
156
0
                bool bClipWarn = m_poGDS->m_bClipWarn;
157
0
                GUInt16 nHalf = CPLFloatToHalf(nInWord, bClipWarn);
158
0
                m_poGDS->m_bClipWarn = bClipWarn;
159
0
                reinterpret_cast<GUInt16 *>(m_poGDS->m_pabyBlockBuf)[iPixel] =
160
0
                    nHalf;
161
0
            }
162
163
0
            m_poGDS->m_bLoadedBlockDirty = true;
164
165
0
            return CE_None;
166
0
        }
167
168
        // Initialize to zero as we set the buffer with binary or operations.
169
0
        if (m_poGDS->m_nBitsPerSample != 24)
170
0
            memset(m_poGDS->m_pabyBlockBuf, 0,
171
0
                   static_cast<size_t>((nBitsPerLine / 8) * nBlockYSize));
172
173
0
        for (int iY = 0; iY < nBlockYSize; ++iY)
174
0
        {
175
0
            GInt64 iBitOffset = iY * nBitsPerLine;
176
177
0
            if (m_poGDS->m_nBitsPerSample == 12)
178
0
            {
179
0
                for (int iX = 0; iX < nBlockXSize; ++iX)
180
0
                {
181
0
                    GUInt32 nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
182
0
                    if (nInWord > nMaxVal)
183
0
                    {
184
0
                        nInWord = nMaxVal;
185
0
                        if (!m_poGDS->m_bClipWarn)
186
0
                        {
187
0
                            m_poGDS->m_bClipWarn = true;
188
0
                            ReportError(
189
0
                                CE_Warning, CPLE_AppDefined,
190
0
                                "One or more pixels clipped to fit %d bit "
191
0
                                "domain.",
192
0
                                m_poGDS->m_nBitsPerSample);
193
0
                        }
194
0
                    }
195
196
0
                    if ((iBitOffset % 8) == 0)
197
0
                    {
198
0
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
199
0
                            static_cast<GByte>(nInWord >> 4);
200
                        // Let 4 lower bits to zero as they're going to be
201
                        // overridden by the next word.
202
0
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
203
0
                            static_cast<GByte>((nInWord & 0xf) << 4);
204
0
                    }
205
0
                    else
206
0
                    {
207
                        // Must or to preserve the 4 upper bits written
208
                        // for the previous word.
209
0
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
210
0
                            static_cast<GByte>(nInWord >> 8);
211
0
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
212
0
                            static_cast<GByte>(nInWord & 0xff);
213
0
                    }
214
215
0
                    iBitOffset += m_poGDS->m_nBitsPerSample;
216
0
                }
217
0
                continue;
218
0
            }
219
220
0
            for (int iX = 0; iX < nBlockXSize; ++iX)
221
0
            {
222
0
                GUInt32 nInWord = 0;
223
0
                if (eDataType == GDT_Byte)
224
0
                {
225
0
                    nInWord = static_cast<GByte *>(pImage)[iPixel++];
226
0
                }
227
0
                else if (eDataType == GDT_UInt16)
228
0
                {
229
0
                    nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
230
0
                }
231
0
                else if (eDataType == GDT_UInt32)
232
0
                {
233
0
                    nInWord = static_cast<GUInt32 *>(pImage)[iPixel++];
234
0
                }
235
0
                else
236
0
                {
237
0
                    CPLAssert(false);
238
0
                }
239
240
0
                if (nInWord > nMaxVal)
241
0
                {
242
0
                    nInWord = nMaxVal;
243
0
                    if (!m_poGDS->m_bClipWarn)
244
0
                    {
245
0
                        m_poGDS->m_bClipWarn = true;
246
0
                        ReportError(
247
0
                            CE_Warning, CPLE_AppDefined,
248
0
                            "One or more pixels clipped to fit %d bit domain.",
249
0
                            m_poGDS->m_nBitsPerSample);
250
0
                    }
251
0
                }
252
253
0
                if (m_poGDS->m_nBitsPerSample == 24)
254
0
                {
255
/* -------------------------------------------------------------------- */
256
/*      Special case for 24bit data which is pre-byteswapped since      */
257
/*      the size falls on a byte boundary ... ugh (#2361).              */
258
/* -------------------------------------------------------------------- */
259
#ifdef CPL_MSB
260
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
261
                        static_cast<GByte>(nInWord);
262
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
263
                        static_cast<GByte>(nInWord >> 8);
264
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
265
                        static_cast<GByte>(nInWord >> 16);
266
#else
267
0
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
268
0
                        static_cast<GByte>(nInWord >> 16);
269
0
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
270
0
                        static_cast<GByte>(nInWord >> 8);
271
0
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
272
0
                        static_cast<GByte>(nInWord);
273
0
#endif
274
0
                    iBitOffset += 24;
275
0
                }
276
0
                else
277
0
                {
278
0
                    for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
279
0
                    {
280
0
                        if (nInWord &
281
0
                            (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
282
0
                            m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
283
0
                                (0x80 >> (iBitOffset & 7));
284
0
                        ++iBitOffset;
285
0
                    }
286
0
                }
287
0
            }
288
0
        }
289
290
0
        m_poGDS->m_bLoadedBlockDirty = true;
291
292
0
        return CE_None;
293
0
    }
294
295
    /* -------------------------------------------------------------------- */
296
    /*      Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images.  */
297
    /* -------------------------------------------------------------------- */
298
299
    /* -------------------------------------------------------------------- */
300
    /*      On write of pixel interleaved data, we might as well flush      */
301
    /*      out any other bands that are dirty in our cache.  This is       */
302
    /*      especially helpful when writing compressed blocks.              */
303
    /* -------------------------------------------------------------------- */
304
0
    for (int iBand = 0; iBand < m_poGDS->nBands; ++iBand)
305
0
    {
306
0
        const GByte *pabyThisImage = nullptr;
307
0
        GDALRasterBlock *poBlock = nullptr;
308
309
0
        if (iBand + 1 == nBand)
310
0
        {
311
0
            pabyThisImage = static_cast<GByte *>(pImage);
312
0
        }
313
0
        else
314
0
        {
315
0
            poBlock = cpl::down_cast<GTiffOddBitsBand *>(
316
0
                          m_poGDS->GetRasterBand(iBand + 1))
317
0
                          ->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
318
319
0
            if (poBlock == nullptr)
320
0
                continue;
321
322
0
            if (!poBlock->GetDirty())
323
0
            {
324
0
                poBlock->DropLock();
325
0
                continue;
326
0
            }
327
328
0
            pabyThisImage = static_cast<GByte *>(poBlock->GetDataRef());
329
0
        }
330
331
0
        const int iPixelBitSkip = m_poGDS->m_nBitsPerSample * m_poGDS->nBands;
332
0
        const int iBandBitOffset = iBand * m_poGDS->m_nBitsPerSample;
333
334
        // Bits per line rounds up to next byte boundary.
335
0
        GInt64 nBitsPerLine = static_cast<GInt64>(nBlockXSize) * iPixelBitSkip;
336
0
        if ((nBitsPerLine & 7) != 0)
337
0
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
338
339
0
        GPtrDiff_t iPixel = 0;
340
341
0
        if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample == 16)
342
0
        {
343
0
            for (; iPixel < static_cast<GPtrDiff_t>(nBlockYSize) * nBlockXSize;
344
0
                 iPixel++)
345
0
            {
346
0
                GUInt32 nInWord =
347
0
                    reinterpret_cast<const GUInt32 *>(pabyThisImage)[iPixel];
348
0
                bool bClipWarn = m_poGDS->m_bClipWarn;
349
0
                GUInt16 nHalf = CPLFloatToHalf(nInWord, bClipWarn);
350
0
                m_poGDS->m_bClipWarn = bClipWarn;
351
0
                reinterpret_cast<GUInt16 *>(
352
0
                    m_poGDS->m_pabyBlockBuf)[iPixel * m_poGDS->nBands + iBand] =
353
0
                    nHalf;
354
0
            }
355
356
0
            if (poBlock != nullptr)
357
0
            {
358
0
                poBlock->MarkClean();
359
0
                poBlock->DropLock();
360
0
            }
361
0
            continue;
362
0
        }
363
364
0
        for (int iY = 0; iY < nBlockYSize; ++iY)
365
0
        {
366
0
            GInt64 iBitOffset = iBandBitOffset + iY * nBitsPerLine;
367
368
0
            if (m_poGDS->m_nBitsPerSample == 12)
369
0
            {
370
0
                for (int iX = 0; iX < nBlockXSize; ++iX)
371
0
                {
372
0
                    GUInt32 nInWord = reinterpret_cast<const GUInt16 *>(
373
0
                        pabyThisImage)[iPixel++];
374
0
                    if (nInWord > nMaxVal)
375
0
                    {
376
0
                        nInWord = nMaxVal;
377
0
                        if (!m_poGDS->m_bClipWarn)
378
0
                        {
379
0
                            m_poGDS->m_bClipWarn = true;
380
0
                            ReportError(
381
0
                                CE_Warning, CPLE_AppDefined,
382
0
                                "One or more pixels clipped to fit %d bit "
383
0
                                "domain.",
384
0
                                m_poGDS->m_nBitsPerSample);
385
0
                        }
386
0
                    }
387
388
0
                    if ((iBitOffset % 8) == 0)
389
0
                    {
390
0
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
391
0
                            static_cast<GByte>(nInWord >> 4);
392
0
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
393
0
                            static_cast<GByte>(
394
0
                                ((nInWord & 0xf) << 4) |
395
0
                                (m_poGDS
396
0
                                     ->m_pabyBlockBuf[(iBitOffset >> 3) + 1] &
397
0
                                 0xf));
398
0
                    }
399
0
                    else
400
0
                    {
401
0
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
402
0
                            static_cast<GByte>(
403
0
                                (m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &
404
0
                                 0xf0) |
405
0
                                (nInWord >> 8));
406
0
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
407
0
                            static_cast<GByte>(nInWord & 0xff);
408
0
                    }
409
410
0
                    iBitOffset += iPixelBitSkip;
411
0
                }
412
0
                continue;
413
0
            }
414
415
0
            for (int iX = 0; iX < nBlockXSize; ++iX)
416
0
            {
417
0
                GUInt32 nInWord = 0;
418
0
                if (eDataType == GDT_Byte)
419
0
                {
420
0
                    nInWord =
421
0
                        static_cast<const GByte *>(pabyThisImage)[iPixel++];
422
0
                }
423
0
                else if (eDataType == GDT_UInt16)
424
0
                {
425
0
                    nInWord = reinterpret_cast<const GUInt16 *>(
426
0
                        pabyThisImage)[iPixel++];
427
0
                }
428
0
                else if (eDataType == GDT_UInt32)
429
0
                {
430
0
                    nInWord = reinterpret_cast<const GUInt32 *>(
431
0
                        pabyThisImage)[iPixel++];
432
0
                }
433
0
                else
434
0
                {
435
0
                    CPLAssert(false);
436
0
                }
437
438
0
                if (nInWord > nMaxVal)
439
0
                {
440
0
                    nInWord = nMaxVal;
441
0
                    if (!m_poGDS->m_bClipWarn)
442
0
                    {
443
0
                        m_poGDS->m_bClipWarn = true;
444
0
                        ReportError(
445
0
                            CE_Warning, CPLE_AppDefined,
446
0
                            "One or more pixels clipped to fit %d bit domain.",
447
0
                            m_poGDS->m_nBitsPerSample);
448
0
                    }
449
0
                }
450
451
0
                if (m_poGDS->m_nBitsPerSample == 24)
452
0
                {
453
/* -------------------------------------------------------------------- */
454
/*      Special case for 24bit data which is pre-byteswapped since      */
455
/*      the size falls on a byte boundary ... ugh (#2361).              */
456
/* -------------------------------------------------------------------- */
457
#ifdef CPL_MSB
458
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
459
                        static_cast<GByte>(nInWord);
460
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
461
                        static_cast<GByte>(nInWord >> 8);
462
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
463
                        static_cast<GByte>(nInWord >> 16);
464
#else
465
0
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
466
0
                        static_cast<GByte>(nInWord >> 16);
467
0
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
468
0
                        static_cast<GByte>(nInWord >> 8);
469
0
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
470
0
                        static_cast<GByte>(nInWord);
471
0
#endif
472
0
                    iBitOffset += 24;
473
0
                }
474
0
                else
475
0
                {
476
0
                    for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
477
0
                    {
478
                        // TODO(schwehr): Revisit this block.
479
0
                        if (nInWord &
480
0
                            (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
481
0
                        {
482
0
                            m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
483
0
                                (0x80 >> (iBitOffset & 7));
484
0
                        }
485
0
                        else
486
0
                        {
487
                            // We must explicitly unset the bit as we
488
                            // may update an existing block.
489
0
                            m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &=
490
0
                                ~(0x80 >> (iBitOffset & 7));
491
0
                        }
492
493
0
                        ++iBitOffset;
494
0
                    }
495
0
                }
496
497
0
                iBitOffset =
498
0
                    iBitOffset + iPixelBitSkip - m_poGDS->m_nBitsPerSample;
499
0
            }
500
0
        }
501
502
0
        if (poBlock != nullptr)
503
0
        {
504
0
            poBlock->MarkClean();
505
0
            poBlock->DropLock();
506
0
        }
507
0
    }
508
509
0
    m_poGDS->m_bLoadedBlockDirty = true;
510
511
0
    return CE_None;
512
0
}
513
514
/************************************************************************/
515
/*                             IReadBlock()                             */
516
/************************************************************************/
517
518
CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
519
                                    void *pImage)
520
521
172k
{
522
172k
    m_poGDS->Crystalize();
523
524
172k
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
525
526
    /* -------------------------------------------------------------------- */
527
    /*      Handle the case of a strip in a writable file that doesn't      */
528
    /*      exist yet, but that we want to read.  Just set to zeros and     */
529
    /*      return.                                                         */
530
    /* -------------------------------------------------------------------- */
531
172k
    if (nBlockId != m_poGDS->m_nLoadedBlock)
532
172k
    {
533
172k
        bool bErrOccurred = false;
534
172k
        if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, nullptr,
535
172k
                                       &bErrOccurred))
536
22.4k
        {
537
22.4k
            NullBlock(pImage);
538
22.4k
            if (bErrOccurred)
539
385
                return CE_Failure;
540
22.1k
            return CE_None;
541
22.4k
        }
542
172k
    }
543
544
    /* -------------------------------------------------------------------- */
545
    /*      Load the block buffer.                                          */
546
    /* -------------------------------------------------------------------- */
547
149k
    {
548
149k
        const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId);
549
149k
        if (eErr != CE_None)
550
1.99k
            return eErr;
551
149k
    }
552
553
147k
    if (m_poGDS->m_nBitsPerSample == 1 &&
554
147k
        (m_poGDS->nBands == 1 ||
555
129k
         m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
556
119k
    {
557
        // Translate 1bit data to eight bit.
558
119k
        const GByte *CPL_RESTRICT pabySrc = m_poGDS->m_pabyBlockBuf;
559
119k
        GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);
560
561
416M
        for (int iLine = 0; iLine < nBlockYSize; ++iLine)
562
416M
        {
563
416M
            if (m_poGDS->m_bPromoteTo8Bits)
564
1.95k
            {
565
1.95k
                GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
566
1.95k
                                                   nBlockXSize);
567
1.95k
            }
568
416M
            else
569
416M
            {
570
416M
                GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
571
416M
                                                 nBlockXSize);
572
416M
            }
573
416M
            pabySrc += (nBlockXSize + 7) / 8;
574
416M
            pabyDest += nBlockXSize;
575
416M
        }
576
119k
    }
577
    /* -------------------------------------------------------------------- */
578
    /*      Handle the case of 16- and 24-bit floating point data as per    */
579
    /*      TIFF Technical Note 3.                                          */
580
    /* -------------------------------------------------------------------- */
581
28.1k
    else if (eDataType == GDT_Float32)
582
7.78k
    {
583
7.78k
        const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
584
7.78k
        const GByte *pabyImage =
585
7.78k
            m_poGDS->m_pabyBlockBuf +
586
7.78k
            ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
587
7.78k
                 ? 0
588
7.78k
                 : (nBand - 1) * nWordBytes);
589
7.78k
        const int iSkipBytes =
590
7.78k
            (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
591
7.78k
                ? nWordBytes
592
7.78k
                : m_poGDS->nBands * nWordBytes;
593
594
7.78k
        const auto nBlockPixels =
595
7.78k
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
596
7.78k
        if (m_poGDS->m_nBitsPerSample == 16)
597
0
        {
598
0
            for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
599
0
            {
600
0
                static_cast<GUInt32 *>(pImage)[i] = CPLHalfToFloat(
601
0
                    *reinterpret_cast<const GUInt16 *>(pabyImage));
602
0
                pabyImage += iSkipBytes;
603
0
            }
604
0
        }
605
7.78k
        else if (m_poGDS->m_nBitsPerSample == 24)
606
7.78k
        {
607
158k
            for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
608
150k
            {
609
#ifdef CPL_MSB
610
                static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
611
                    (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
612
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
613
                    static_cast<GUInt32>(*(pabyImage + 2)));
614
#else
615
150k
                static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
616
150k
                    (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
617
150k
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
618
150k
                    static_cast<GUInt32>(*pabyImage));
619
150k
#endif
620
150k
                pabyImage += iSkipBytes;
621
150k
            }
622
7.78k
        }
623
7.78k
    }
624
625
    /* -------------------------------------------------------------------- */
626
    /*      Special case for moving 12bit data somewhat more efficiently.   */
627
    /* -------------------------------------------------------------------- */
628
20.3k
    else if (m_poGDS->m_nBitsPerSample == 12)
629
27
    {
630
27
        int iPixelBitSkip = 0;
631
27
        int iBandBitOffset = 0;
632
633
27
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
634
24
        {
635
24
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
636
24
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
637
24
        }
638
3
        else
639
3
        {
640
3
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
641
3
        }
642
643
        // Bits per line rounds up to next byte boundary.
644
27
        GPtrDiff_t nBitsPerLine =
645
27
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
646
27
        if ((nBitsPerLine & 7) != 0)
647
10
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
648
649
27
        int iPixel = 0;
650
24.4k
        for (int iY = 0; iY < nBlockYSize; ++iY)
651
24.4k
        {
652
24.4k
            GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
653
654
21.7M
            for (int iX = 0; iX < nBlockXSize; ++iX)
655
21.6M
            {
656
21.6M
                const auto iByte = iBitOffset >> 3;
657
658
21.6M
                if ((iBitOffset & 0x7) == 0)
659
10.8M
                {
660
                    // Starting on byte boundary.
661
662
10.8M
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
663
10.8M
                        (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
664
10.8M
                        (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
665
10.8M
                }
666
10.8M
                else
667
10.8M
                {
668
                    // Starting off byte boundary.
669
670
10.8M
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
671
10.8M
                        ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
672
10.8M
                        (m_poGDS->m_pabyBlockBuf[iByte + 1]);
673
10.8M
                }
674
21.6M
                iBitOffset += iPixelBitSkip;
675
21.6M
            }
676
24.4k
        }
677
27
    }
678
679
    /* -------------------------------------------------------------------- */
680
    /*      Special case for 24bit data which is pre-byteswapped since      */
681
    /*      the size falls on a byte boundary ... ugh (#2361).              */
682
    /* -------------------------------------------------------------------- */
683
20.2k
    else if (m_poGDS->m_nBitsPerSample == 24)
684
478
    {
685
478
        int iPixelByteSkip = 0;
686
478
        int iBandByteOffset = 0;
687
688
478
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
689
4
        {
690
4
            iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
691
4
            iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
692
4
        }
693
474
        else
694
474
        {
695
474
            iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
696
474
        }
697
698
478
        const GPtrDiff_t nBytesPerLine =
699
478
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
700
701
478
        GPtrDiff_t iPixel = 0;
702
1.10k
        for (int iY = 0; iY < nBlockYSize; ++iY)
703
624
        {
704
624
            GByte *pabyImage =
705
624
                m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
706
707
36.7k
            for (int iX = 0; iX < nBlockXSize; ++iX)
708
36.1k
            {
709
#ifdef CPL_MSB
710
                static_cast<GUInt32 *>(pImage)[iPixel++] =
711
                    (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
712
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
713
                    static_cast<GUInt32>(*(pabyImage + 0));
714
#else
715
36.1k
                static_cast<GUInt32 *>(pImage)[iPixel++] =
716
36.1k
                    (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
717
36.1k
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
718
36.1k
                    static_cast<GUInt32>(*(pabyImage + 2));
719
36.1k
#endif
720
36.1k
                pabyImage += iPixelByteSkip;
721
36.1k
            }
722
624
        }
723
478
    }
724
725
    /* -------------------------------------------------------------------- */
726
    /*      Handle 1-32 bit integer data.                                   */
727
    /* -------------------------------------------------------------------- */
728
19.8k
    else
729
19.8k
    {
730
19.8k
        unsigned iPixelBitSkip = 0;
731
19.8k
        unsigned iBandBitOffset = 0;
732
733
19.8k
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
734
10.4k
        {
735
10.4k
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
736
10.4k
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
737
10.4k
        }
738
9.34k
        else
739
9.34k
        {
740
9.34k
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
741
9.34k
        }
742
743
        // Bits per line rounds up to next byte boundary.
744
19.8k
        GUIntBig nBitsPerLine =
745
19.8k
            static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
746
19.8k
        if ((nBitsPerLine & 7) != 0)
747
11.1k
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
748
749
19.8k
        const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
750
19.8k
        const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
751
19.8k
        GPtrDiff_t iPixel = 0;
752
753
19.8k
        if (nBitsPerSample == 1 && eDataType == GDT_Byte)
754
10.3k
        {
755
470k
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
756
460k
            {
757
460k
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
758
759
2.39M
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
760
1.92M
                     ++iX)
761
1.92M
                {
762
1.92M
                    if (m_pabyBlockBuf[iBitOffset >> 3] &
763
1.92M
                        (0x80 >> (iBitOffset & 7)))
764
516k
                        static_cast<GByte *>(pImage)[iPixel] = 1;
765
1.41M
                    else
766
1.41M
                        static_cast<GByte *>(pImage)[iPixel] = 0;
767
1.92M
                    iBitOffset += iPixelBitSkip;
768
1.92M
                    iPixel++;
769
1.92M
                }
770
460k
            }
771
10.3k
        }
772
9.44k
        else
773
9.44k
        {
774
21.3k
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
775
11.9k
            {
776
11.9k
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
777
778
13.3M
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
779
13.3M
                     ++iX)
780
13.3M
                {
781
13.3M
                    unsigned nOutWord = 0;
782
783
146M
                    for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
784
132M
                    {
785
132M
                        if (m_pabyBlockBuf[iBitOffset >> 3] &
786
132M
                            (0x80 >> (iBitOffset & 7)))
787
35.4M
                            nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
788
132M
                        ++iBitOffset;
789
132M
                    }
790
791
13.3M
                    iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
792
793
13.3M
                    if (eDataType == GDT_Byte)
794
68.9k
                    {
795
68.9k
                        static_cast<GByte *>(pImage)[iPixel++] =
796
68.9k
                            static_cast<GByte>(nOutWord);
797
68.9k
                    }
798
13.2M
                    else if (eDataType == GDT_UInt16)
799
13.2M
                    {
800
13.2M
                        static_cast<GUInt16 *>(pImage)[iPixel++] =
801
13.2M
                            static_cast<GUInt16>(nOutWord);
802
13.2M
                    }
803
0
                    else if (eDataType == GDT_UInt32)
804
0
                    {
805
0
                        static_cast<GUInt32 *>(pImage)[iPixel++] = nOutWord;
806
0
                    }
807
0
                    else
808
0
                    {
809
0
                        CPLAssert(false);
810
0
                    }
811
13.3M
                }
812
11.9k
            }
813
9.44k
        }
814
19.8k
    }
815
816
147k
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
817
818
147k
    return CE_None;
819
149k
}