Coverage Report

Created: 2026-02-14 06:52

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