Coverage Report

Created: 2025-06-13 06:18

/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
0
    : GTiffRasterBand(m_poGDSIn, nBandIn)
26
27
0
{
28
0
    eDataType = GDT_Unknown;
29
0
    if (m_poGDS->m_nBitsPerSample == 24 &&
30
0
        m_poGDS->m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
31
0
        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
0
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
35
0
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
36
0
             m_poGDS->m_nBitsPerSample < 8)
37
0
        eDataType = GDT_Byte;
38
0
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
39
0
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
40
0
             m_poGDS->m_nBitsPerSample > 8 && m_poGDS->m_nBitsPerSample < 16)
41
0
        eDataType = GDT_UInt16;
42
0
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
43
0
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
44
0
             m_poGDS->m_nBitsPerSample > 16 && m_poGDS->m_nBitsPerSample < 32)
45
0
        eDataType = GDT_UInt32;
46
0
}
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
0
{
522
0
    m_poGDS->Crystalize();
523
524
0
    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
0
    if (nBlockId != m_poGDS->m_nLoadedBlock)
532
0
    {
533
0
        bool bErrOccurred = false;
534
0
        if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, nullptr,
535
0
                                       &bErrOccurred))
536
0
        {
537
0
            NullBlock(pImage);
538
0
            if (bErrOccurred)
539
0
                return CE_Failure;
540
0
            return CE_None;
541
0
        }
542
0
    }
543
544
    /* -------------------------------------------------------------------- */
545
    /*      Load the block buffer.                                          */
546
    /* -------------------------------------------------------------------- */
547
0
    {
548
0
        const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId);
549
0
        if (eErr != CE_None)
550
0
            return eErr;
551
0
    }
552
553
0
    if (m_poGDS->m_nBitsPerSample == 1 &&
554
0
        (m_poGDS->nBands == 1 ||
555
0
         m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
556
0
    {
557
        // Translate 1bit data to eight bit.
558
0
        const GByte *CPL_RESTRICT pabySrc = m_poGDS->m_pabyBlockBuf;
559
0
        GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);
560
561
0
        for (int iLine = 0; iLine < nBlockYSize; ++iLine)
562
0
        {
563
0
            if (m_poGDS->m_bPromoteTo8Bits)
564
0
            {
565
0
                GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
566
0
                                                   nBlockXSize);
567
0
            }
568
0
            else
569
0
            {
570
0
                GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
571
0
                                                 nBlockXSize);
572
0
            }
573
0
            pabySrc += (nBlockXSize + 7) / 8;
574
0
            pabyDest += nBlockXSize;
575
0
        }
576
0
    }
577
    /* -------------------------------------------------------------------- */
578
    /*      Handle the case of 16- and 24-bit floating point data as per    */
579
    /*      TIFF Technical Note 3.                                          */
580
    /* -------------------------------------------------------------------- */
581
0
    else if (eDataType == GDT_Float32)
582
0
    {
583
0
        const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
584
0
        const GByte *pabyImage =
585
0
            m_poGDS->m_pabyBlockBuf +
586
0
            ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
587
0
                 ? 0
588
0
                 : (nBand - 1) * nWordBytes);
589
0
        const int iSkipBytes =
590
0
            (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
591
0
                ? nWordBytes
592
0
                : m_poGDS->nBands * nWordBytes;
593
594
0
        const auto nBlockPixels =
595
0
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
596
0
        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
0
        else if (m_poGDS->m_nBitsPerSample == 24)
606
0
        {
607
0
            for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
608
0
            {
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
0
                static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
616
0
                    (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
617
0
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
618
0
                    static_cast<GUInt32>(*pabyImage));
619
0
#endif
620
0
                pabyImage += iSkipBytes;
621
0
            }
622
0
        }
623
0
    }
624
625
    /* -------------------------------------------------------------------- */
626
    /*      Special case for moving 12bit data somewhat more efficiently.   */
627
    /* -------------------------------------------------------------------- */
628
0
    else if (m_poGDS->m_nBitsPerSample == 12)
629
0
    {
630
0
        int iPixelBitSkip = 0;
631
0
        int iBandBitOffset = 0;
632
633
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
634
0
        {
635
0
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
636
0
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
637
0
        }
638
0
        else
639
0
        {
640
0
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
641
0
        }
642
643
        // Bits per line rounds up to next byte boundary.
644
0
        GPtrDiff_t nBitsPerLine =
645
0
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
646
0
        if ((nBitsPerLine & 7) != 0)
647
0
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
648
649
0
        int iPixel = 0;
650
0
        for (int iY = 0; iY < nBlockYSize; ++iY)
651
0
        {
652
0
            GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
653
654
0
            for (int iX = 0; iX < nBlockXSize; ++iX)
655
0
            {
656
0
                const auto iByte = iBitOffset >> 3;
657
658
0
                if ((iBitOffset & 0x7) == 0)
659
0
                {
660
                    // Starting on byte boundary.
661
662
0
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
663
0
                        (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
664
0
                        (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
665
0
                }
666
0
                else
667
0
                {
668
                    // Starting off byte boundary.
669
670
0
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
671
0
                        ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
672
0
                        (m_poGDS->m_pabyBlockBuf[iByte + 1]);
673
0
                }
674
0
                iBitOffset += iPixelBitSkip;
675
0
            }
676
0
        }
677
0
    }
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
0
    else if (m_poGDS->m_nBitsPerSample == 24)
684
0
    {
685
0
        int iPixelByteSkip = 0;
686
0
        int iBandByteOffset = 0;
687
688
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
689
0
        {
690
0
            iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
691
0
            iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
692
0
        }
693
0
        else
694
0
        {
695
0
            iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
696
0
        }
697
698
0
        const GPtrDiff_t nBytesPerLine =
699
0
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
700
701
0
        GPtrDiff_t iPixel = 0;
702
0
        for (int iY = 0; iY < nBlockYSize; ++iY)
703
0
        {
704
0
            GByte *pabyImage =
705
0
                m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
706
707
0
            for (int iX = 0; iX < nBlockXSize; ++iX)
708
0
            {
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
0
                static_cast<GUInt32 *>(pImage)[iPixel++] =
716
0
                    (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
717
0
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
718
0
                    static_cast<GUInt32>(*(pabyImage + 2));
719
0
#endif
720
0
                pabyImage += iPixelByteSkip;
721
0
            }
722
0
        }
723
0
    }
724
725
    /* -------------------------------------------------------------------- */
726
    /*      Handle 1-32 bit integer data.                                   */
727
    /* -------------------------------------------------------------------- */
728
0
    else
729
0
    {
730
0
        unsigned iPixelBitSkip = 0;
731
0
        unsigned iBandBitOffset = 0;
732
733
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
734
0
        {
735
0
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
736
0
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
737
0
        }
738
0
        else
739
0
        {
740
0
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
741
0
        }
742
743
        // Bits per line rounds up to next byte boundary.
744
0
        GUIntBig nBitsPerLine =
745
0
            static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
746
0
        if ((nBitsPerLine & 7) != 0)
747
0
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
748
749
0
        const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
750
0
        const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
751
0
        GPtrDiff_t iPixel = 0;
752
753
0
        if (nBitsPerSample == 1 && eDataType == GDT_Byte)
754
0
        {
755
0
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
756
0
            {
757
0
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
758
759
0
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
760
0
                     ++iX)
761
0
                {
762
0
                    if (m_pabyBlockBuf[iBitOffset >> 3] &
763
0
                        (0x80 >> (iBitOffset & 7)))
764
0
                        static_cast<GByte *>(pImage)[iPixel] = 1;
765
0
                    else
766
0
                        static_cast<GByte *>(pImage)[iPixel] = 0;
767
0
                    iBitOffset += iPixelBitSkip;
768
0
                    iPixel++;
769
0
                }
770
0
            }
771
0
        }
772
0
        else
773
0
        {
774
0
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
775
0
            {
776
0
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
777
778
0
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
779
0
                     ++iX)
780
0
                {
781
0
                    unsigned nOutWord = 0;
782
783
0
                    for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
784
0
                    {
785
0
                        if (m_pabyBlockBuf[iBitOffset >> 3] &
786
0
                            (0x80 >> (iBitOffset & 7)))
787
0
                            nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
788
0
                        ++iBitOffset;
789
0
                    }
790
791
0
                    iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
792
793
0
                    if (eDataType == GDT_Byte)
794
0
                    {
795
0
                        static_cast<GByte *>(pImage)[iPixel++] =
796
0
                            static_cast<GByte>(nOutWord);
797
0
                    }
798
0
                    else if (eDataType == GDT_UInt16)
799
0
                    {
800
0
                        static_cast<GUInt16 *>(pImage)[iPixel++] =
801
0
                            static_cast<GUInt16>(nOutWord);
802
0
                    }
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
0
                }
812
0
            }
813
0
        }
814
0
    }
815
816
0
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
817
818
0
    return CE_None;
819
0
}