Coverage Report

Created: 2025-11-16 06:25

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_Byte;
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 + 7 < nBlockXSize; 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_Byte)
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_Byte)
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
562
0
        for (int iLine = 0; iLine < nBlockYSize; ++iLine)
563
0
        {
564
0
            if (m_poGDS->m_bPromoteTo8Bits)
565
0
            {
566
0
                GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
567
0
                                                   nBlockXSize);
568
0
            }
569
0
            else
570
0
            {
571
0
                GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
572
0
                                                 nBlockXSize);
573
0
            }
574
0
            pabySrc += (nBlockXSize + 7) / 8;
575
0
            pabyDest += nBlockXSize;
576
0
        }
577
0
    }
578
    /* -------------------------------------------------------------------- */
579
    /*      Handle the case of 16- and 24-bit floating point data as per    */
580
    /*      TIFF Technical Note 3.                                          */
581
    /* -------------------------------------------------------------------- */
582
0
    else if (eDataType == GDT_Float32)
583
0
    {
584
0
        const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
585
0
        const GByte *pabyImage =
586
0
            m_poGDS->m_pabyBlockBuf +
587
0
            ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
588
0
                 ? 0
589
0
                 : (nBand - 1) * nWordBytes);
590
0
        const int iSkipBytes =
591
0
            (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
592
0
                ? nWordBytes
593
0
                : m_poGDS->nBands * nWordBytes;
594
595
0
        const auto nBlockPixels =
596
0
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
597
0
        if (m_poGDS->m_nBitsPerSample == 16)
598
0
        {
599
0
            for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
600
0
            {
601
0
                static_cast<GUInt32 *>(pImage)[i] = CPLHalfToFloat(
602
0
                    *reinterpret_cast<const GUInt16 *>(pabyImage));
603
0
                pabyImage += iSkipBytes;
604
0
            }
605
0
        }
606
0
        else if (m_poGDS->m_nBitsPerSample == 24)
607
0
        {
608
0
            for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
609
0
            {
610
#ifdef CPL_MSB
611
                static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
612
                    (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
613
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
614
                    static_cast<GUInt32>(*(pabyImage + 2)));
615
#else
616
0
                static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
617
0
                    (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
618
0
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
619
0
                    static_cast<GUInt32>(*pabyImage));
620
0
#endif
621
0
                pabyImage += iSkipBytes;
622
0
            }
623
0
        }
624
0
    }
625
626
    /* -------------------------------------------------------------------- */
627
    /*      Special case for moving 12bit data somewhat more efficiently.   */
628
    /* -------------------------------------------------------------------- */
629
0
    else if (m_poGDS->m_nBitsPerSample == 12)
630
0
    {
631
0
        int iPixelBitSkip = 0;
632
0
        int iBandBitOffset = 0;
633
634
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
635
0
        {
636
0
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
637
0
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
638
0
        }
639
0
        else
640
0
        {
641
0
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
642
0
        }
643
644
        // Bits per line rounds up to next byte boundary.
645
0
        GPtrDiff_t nBitsPerLine =
646
0
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
647
0
        if ((nBitsPerLine & 7) != 0)
648
0
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
649
650
0
        int iPixel = 0;
651
0
        for (int iY = 0; iY < nBlockYSize; ++iY)
652
0
        {
653
0
            GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
654
655
0
            for (int iX = 0; iX < nBlockXSize; ++iX)
656
0
            {
657
0
                const auto iByte = iBitOffset >> 3;
658
659
0
                if ((iBitOffset & 0x7) == 0)
660
0
                {
661
                    // Starting on byte boundary.
662
663
0
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
664
0
                        (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
665
0
                        (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
666
0
                }
667
0
                else
668
0
                {
669
                    // Starting off byte boundary.
670
671
0
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
672
0
                        ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
673
0
                        (m_poGDS->m_pabyBlockBuf[iByte + 1]);
674
0
                }
675
0
                iBitOffset += iPixelBitSkip;
676
0
            }
677
0
        }
678
0
    }
679
680
    /* -------------------------------------------------------------------- */
681
    /*      Special case for 24bit data which is pre-byteswapped since      */
682
    /*      the size falls on a byte boundary ... ugh (#2361).              */
683
    /* -------------------------------------------------------------------- */
684
0
    else if (m_poGDS->m_nBitsPerSample == 24)
685
0
    {
686
0
        int iPixelByteSkip = 0;
687
0
        int iBandByteOffset = 0;
688
689
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
690
0
        {
691
0
            iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
692
0
            iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
693
0
        }
694
0
        else
695
0
        {
696
0
            iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
697
0
        }
698
699
0
        const GPtrDiff_t nBytesPerLine =
700
0
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
701
702
0
        GPtrDiff_t iPixel = 0;
703
0
        for (int iY = 0; iY < nBlockYSize; ++iY)
704
0
        {
705
0
            GByte *pabyImage =
706
0
                m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
707
708
0
            for (int iX = 0; iX < nBlockXSize; ++iX)
709
0
            {
710
#ifdef CPL_MSB
711
                static_cast<GUInt32 *>(pImage)[iPixel++] =
712
                    (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
713
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
714
                    static_cast<GUInt32>(*(pabyImage + 0));
715
#else
716
0
                static_cast<GUInt32 *>(pImage)[iPixel++] =
717
0
                    (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
718
0
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
719
0
                    static_cast<GUInt32>(*(pabyImage + 2));
720
0
#endif
721
0
                pabyImage += iPixelByteSkip;
722
0
            }
723
0
        }
724
0
    }
725
726
    /* -------------------------------------------------------------------- */
727
    /*      Handle 1-32 bit integer data.                                   */
728
    /* -------------------------------------------------------------------- */
729
0
    else
730
0
    {
731
0
        unsigned iPixelBitSkip = 0;
732
0
        unsigned iBandBitOffset = 0;
733
734
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
735
0
        {
736
0
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
737
0
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
738
0
        }
739
0
        else
740
0
        {
741
0
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
742
0
        }
743
744
        // Bits per line rounds up to next byte boundary.
745
0
        GUIntBig nBitsPerLine =
746
0
            static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
747
0
        if ((nBitsPerLine & 7) != 0)
748
0
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
749
750
0
        const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
751
0
        const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
752
0
        GPtrDiff_t iPixel = 0;
753
754
0
        if (nBitsPerSample == 1 && eDataType == GDT_Byte)
755
0
        {
756
0
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
757
0
            {
758
0
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
759
760
0
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
761
0
                     ++iX)
762
0
                {
763
0
                    if (m_pabyBlockBuf[iBitOffset >> 3] &
764
0
                        (0x80 >> (iBitOffset & 7)))
765
0
                        static_cast<GByte *>(pImage)[iPixel] = 1;
766
0
                    else
767
0
                        static_cast<GByte *>(pImage)[iPixel] = 0;
768
0
                    iBitOffset += iPixelBitSkip;
769
0
                    iPixel++;
770
0
                }
771
0
            }
772
0
        }
773
0
        else
774
0
        {
775
0
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
776
0
            {
777
0
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
778
779
0
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
780
0
                     ++iX)
781
0
                {
782
0
                    unsigned nOutWord = 0;
783
784
0
                    for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
785
0
                    {
786
0
                        if (m_pabyBlockBuf[iBitOffset >> 3] &
787
0
                            (0x80 >> (iBitOffset & 7)))
788
0
                            nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
789
0
                        ++iBitOffset;
790
0
                    }
791
792
0
                    iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
793
794
0
                    if (eDataType == GDT_Byte)
795
0
                    {
796
0
                        static_cast<GByte *>(pImage)[iPixel++] =
797
0
                            static_cast<GByte>(nOutWord);
798
0
                    }
799
0
                    else if (eDataType == GDT_UInt16)
800
0
                    {
801
0
                        static_cast<GUInt16 *>(pImage)[iPixel++] =
802
0
                            static_cast<GUInt16>(nOutWord);
803
0
                    }
804
0
                    else if (eDataType == GDT_UInt32)
805
0
                    {
806
0
                        static_cast<GUInt32 *>(pImage)[iPixel++] = nOutWord;
807
0
                    }
808
0
                    else
809
0
                    {
810
0
                        CPLAssert(false);
811
0
                    }
812
0
                }
813
0
            }
814
0
        }
815
0
    }
816
817
0
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
818
819
0
    return CE_None;
820
0
}