Coverage Report

Created: 2025-08-11 09:23

/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
57.9M
    : GTiffRasterBand(m_poGDSIn, nBandIn)
26
27
57.9M
{
28
57.9M
    eDataType = GDT_Unknown;
29
57.9M
    if (m_poGDS->m_nBitsPerSample == 24 &&
30
57.9M
        m_poGDS->m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
31
74.4k
        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
57.8M
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
35
57.8M
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
36
57.8M
             m_poGDS->m_nBitsPerSample < 8)
37
52.5M
        eDataType = GDT_Byte;
38
5.29M
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
39
5.29M
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
40
5.29M
             m_poGDS->m_nBitsPerSample > 8 && m_poGDS->m_nBitsPerSample < 16)
41
1.40M
        eDataType = GDT_UInt16;
42
3.88M
    else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
43
3.88M
              m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
44
3.88M
             m_poGDS->m_nBitsPerSample > 16 && m_poGDS->m_nBitsPerSample < 32)
45
683k
        eDataType = GDT_UInt32;
46
57.9M
}
47
48
/************************************************************************/
49
/*                            IWriteBlock()                             */
50
/************************************************************************/
51
52
CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
53
                                     void *pImage)
54
55
13.5k
{
56
13.5k
    m_poGDS->Crystalize();
57
58
13.5k
    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
13.5k
    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
13.5k
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
78
79
    // Only read content from disk in the CONTIG case.
80
13.5k
    {
81
13.5k
        const CPLErr eErr = m_poGDS->LoadBlockBuf(
82
13.5k
            nBlockId, m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
83
13.5k
                          m_poGDS->nBands > 1);
84
13.5k
        if (eErr != CE_None)
85
0
            return eErr;
86
13.5k
    }
87
88
13.5k
    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
13.5k
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
95
13.5k
        m_poGDS->nBands == 1)
96
1.85k
    {
97
        // TODO(schwehr): Create a CplNumBits8Aligned.
98
        // Bits per line rounds up to next byte boundary.
99
1.85k
        GInt64 nBitsPerLine =
100
1.85k
            static_cast<GInt64>(nBlockXSize) * m_poGDS->m_nBitsPerSample;
101
1.85k
        if ((nBitsPerLine & 7) != 0)
102
1.64k
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
103
104
1.85k
        GPtrDiff_t iPixel = 0;
105
106
        // Small optimization in 1 bit case.
107
1.85k
        if (m_poGDS->m_nBitsPerSample == 1)
108
1.47k
        {
109
122k
            for (int iY = 0; iY < nBlockYSize; ++iY, iPixel += nBlockXSize)
110
121k
            {
111
121k
                GInt64 iBitOffset = iY * nBitsPerLine;
112
113
121k
                const GByte *pabySrc =
114
121k
                    static_cast<const GByte *>(pImage) + iPixel;
115
121k
                auto iByteOffset = iBitOffset / 8;
116
121k
                int iX = 0;  // Used after for.
117
1.65M
                for (; iX + 7 < nBlockXSize; iX += 8, iByteOffset++)
118
1.53M
                {
119
1.53M
                    int nRes = (!(!pabySrc[iX + 0])) << 7;
120
1.53M
                    nRes |= (!(!pabySrc[iX + 1])) << 6;
121
1.53M
                    nRes |= (!(!pabySrc[iX + 2])) << 5;
122
1.53M
                    nRes |= (!(!pabySrc[iX + 3])) << 4;
123
1.53M
                    nRes |= (!(!pabySrc[iX + 4])) << 3;
124
1.53M
                    nRes |= (!(!pabySrc[iX + 5])) << 2;
125
1.53M
                    nRes |= (!(!pabySrc[iX + 6])) << 1;
126
1.53M
                    nRes |= (!(!pabySrc[iX + 7])) << 0;
127
1.53M
                    m_poGDS->m_pabyBlockBuf[iByteOffset] =
128
1.53M
                        static_cast<GByte>(nRes);
129
1.53M
                }
130
121k
                iBitOffset = iByteOffset * 8;
131
121k
                if (iX < nBlockXSize)
132
67.6k
                {
133
67.6k
                    int nRes = 0;
134
334k
                    for (; iX < nBlockXSize; ++iX)
135
267k
                    {
136
267k
                        if (pabySrc[iX])
137
98.2k
                            nRes |= (0x80 >> (iBitOffset & 7));
138
267k
                        ++iBitOffset;
139
267k
                    }
140
67.6k
                    m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
141
67.6k
                        static_cast<GByte>(nRes);
142
67.6k
                }
143
121k
            }
144
145
1.47k
            m_poGDS->m_bLoadedBlockDirty = true;
146
147
1.47k
            return CE_None;
148
1.47k
        }
149
150
378
        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
378
        if (m_poGDS->m_nBitsPerSample != 24)
170
350
            memset(m_poGDS->m_pabyBlockBuf, 0,
171
350
                   static_cast<size_t>((nBitsPerLine / 8) * nBlockYSize));
172
173
663k
        for (int iY = 0; iY < nBlockYSize; ++iY)
174
662k
        {
175
662k
            GInt64 iBitOffset = iY * nBitsPerLine;
176
177
662k
            if (m_poGDS->m_nBitsPerSample == 12)
178
11.1k
            {
179
25.5k
                for (int iX = 0; iX < nBlockXSize; ++iX)
180
14.4k
                {
181
14.4k
                    GUInt32 nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
182
14.4k
                    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
14.4k
                    if ((iBitOffset % 8) == 0)
197
12.6k
                    {
198
12.6k
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
199
12.6k
                            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
12.6k
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
203
12.6k
                            static_cast<GByte>((nInWord & 0xf) << 4);
204
12.6k
                    }
205
1.73k
                    else
206
1.73k
                    {
207
                        // Must or to preserve the 4 upper bits written
208
                        // for the previous word.
209
1.73k
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
210
1.73k
                            static_cast<GByte>(nInWord >> 8);
211
1.73k
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
212
1.73k
                            static_cast<GByte>(nInWord & 0xff);
213
1.73k
                    }
214
215
14.4k
                    iBitOffset += m_poGDS->m_nBitsPerSample;
216
14.4k
                }
217
11.1k
                continue;
218
11.1k
            }
219
220
5.62M
            for (int iX = 0; iX < nBlockXSize; ++iX)
221
4.97M
            {
222
4.97M
                GUInt32 nInWord = 0;
223
4.97M
                if (eDataType == GDT_Byte)
224
4.92M
                {
225
4.92M
                    nInWord = static_cast<GByte *>(pImage)[iPixel++];
226
4.92M
                }
227
47.0k
                else if (eDataType == GDT_UInt16)
228
760
                {
229
760
                    nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
230
760
                }
231
46.2k
                else if (eDataType == GDT_UInt32)
232
46.2k
                {
233
46.2k
                    nInWord = static_cast<GUInt32 *>(pImage)[iPixel++];
234
46.2k
                }
235
0
                else
236
0
                {
237
0
                    CPLAssert(false);
238
0
                }
239
240
4.97M
                if (nInWord > nMaxVal)
241
14
                {
242
14
                    nInWord = nMaxVal;
243
14
                    if (!m_poGDS->m_bClipWarn)
244
1
                    {
245
1
                        m_poGDS->m_bClipWarn = true;
246
1
                        ReportError(
247
1
                            CE_Warning, CPLE_AppDefined,
248
1
                            "One or more pixels clipped to fit %d bit domain.",
249
1
                            m_poGDS->m_nBitsPerSample);
250
1
                    }
251
14
                }
252
253
4.97M
                if (m_poGDS->m_nBitsPerSample == 24)
254
45.4k
                {
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
45.4k
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
268
45.4k
                        static_cast<GByte>(nInWord >> 16);
269
45.4k
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
270
45.4k
                        static_cast<GByte>(nInWord >> 8);
271
45.4k
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
272
45.4k
                        static_cast<GByte>(nInWord);
273
45.4k
#endif
274
45.4k
                    iBitOffset += 24;
275
45.4k
                }
276
4.92M
                else
277
4.92M
                {
278
19.4M
                    for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
279
14.5M
                    {
280
14.5M
                        if (nInWord &
281
14.5M
                            (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
282
5.39M
                            m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
283
5.39M
                                (0x80 >> (iBitOffset & 7));
284
14.5M
                        ++iBitOffset;
285
14.5M
                    }
286
4.92M
                }
287
4.97M
            }
288
651k
        }
289
290
378
        m_poGDS->m_bLoadedBlockDirty = true;
291
292
378
        return CE_None;
293
378
    }
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
58.8k
    for (int iBand = 0; iBand < m_poGDS->nBands; ++iBand)
305
47.1k
    {
306
47.1k
        const GByte *pabyThisImage = nullptr;
307
47.1k
        GDALRasterBlock *poBlock = nullptr;
308
309
47.1k
        if (iBand + 1 == nBand)
310
11.6k
        {
311
11.6k
            pabyThisImage = static_cast<GByte *>(pImage);
312
11.6k
        }
313
35.5k
        else
314
35.5k
        {
315
35.5k
            poBlock = cpl::down_cast<GTiffOddBitsBand *>(
316
35.5k
                          m_poGDS->GetRasterBand(iBand + 1))
317
35.5k
                          ->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
318
319
35.5k
            if (poBlock == nullptr)
320
0
                continue;
321
322
35.5k
            if (!poBlock->GetDirty())
323
0
            {
324
0
                poBlock->DropLock();
325
0
                continue;
326
0
            }
327
328
35.5k
            pabyThisImage = static_cast<GByte *>(poBlock->GetDataRef());
329
35.5k
        }
330
331
47.1k
        const int iPixelBitSkip = m_poGDS->m_nBitsPerSample * m_poGDS->nBands;
332
47.1k
        const int iBandBitOffset = iBand * m_poGDS->m_nBitsPerSample;
333
334
        // Bits per line rounds up to next byte boundary.
335
47.1k
        GInt64 nBitsPerLine = static_cast<GInt64>(nBlockXSize) * iPixelBitSkip;
336
47.1k
        if ((nBitsPerLine & 7) != 0)
337
46.5k
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
338
339
47.1k
        GPtrDiff_t iPixel = 0;
340
341
47.1k
        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
141k
        for (int iY = 0; iY < nBlockYSize; ++iY)
365
94.4k
        {
366
94.4k
            GInt64 iBitOffset = iBandBitOffset + iY * nBitsPerLine;
367
368
94.4k
            if (m_poGDS->m_nBitsPerSample == 12)
369
798
            {
370
6.75k
                for (int iX = 0; iX < nBlockXSize; ++iX)
371
5.95k
                {
372
5.95k
                    GUInt32 nInWord = reinterpret_cast<const GUInt16 *>(
373
5.95k
                        pabyThisImage)[iPixel++];
374
5.95k
                    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
5.95k
                    if ((iBitOffset % 8) == 0)
389
3.11k
                    {
390
3.11k
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
391
3.11k
                            static_cast<GByte>(nInWord >> 4);
392
3.11k
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
393
3.11k
                            static_cast<GByte>(
394
3.11k
                                ((nInWord & 0xf) << 4) |
395
3.11k
                                (m_poGDS
396
3.11k
                                     ->m_pabyBlockBuf[(iBitOffset >> 3) + 1] &
397
3.11k
                                 0xf));
398
3.11k
                    }
399
2.84k
                    else
400
2.84k
                    {
401
2.84k
                        m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
402
2.84k
                            static_cast<GByte>(
403
2.84k
                                (m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &
404
2.84k
                                 0xf0) |
405
2.84k
                                (nInWord >> 8));
406
2.84k
                        m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
407
2.84k
                            static_cast<GByte>(nInWord & 0xff);
408
2.84k
                    }
409
410
5.95k
                    iBitOffset += iPixelBitSkip;
411
5.95k
                }
412
798
                continue;
413
798
            }
414
415
84.8M
            for (int iX = 0; iX < nBlockXSize; ++iX)
416
84.7M
            {
417
84.7M
                GUInt32 nInWord = 0;
418
84.7M
                if (eDataType == GDT_Byte)
419
84.6M
                {
420
84.6M
                    nInWord =
421
84.6M
                        static_cast<const GByte *>(pabyThisImage)[iPixel++];
422
84.6M
                }
423
155k
                else if (eDataType == GDT_UInt16)
424
35.9k
                {
425
35.9k
                    nInWord = reinterpret_cast<const GUInt16 *>(
426
35.9k
                        pabyThisImage)[iPixel++];
427
35.9k
                }
428
119k
                else if (eDataType == GDT_UInt32)
429
119k
                {
430
119k
                    nInWord = reinterpret_cast<const GUInt32 *>(
431
119k
                        pabyThisImage)[iPixel++];
432
119k
                }
433
0
                else
434
0
                {
435
0
                    CPLAssert(false);
436
0
                }
437
438
84.7M
                if (nInWord > nMaxVal)
439
5.26M
                {
440
5.26M
                    nInWord = nMaxVal;
441
5.26M
                    if (!m_poGDS->m_bClipWarn)
442
29
                    {
443
29
                        m_poGDS->m_bClipWarn = true;
444
29
                        ReportError(
445
29
                            CE_Warning, CPLE_AppDefined,
446
29
                            "One or more pixels clipped to fit %d bit domain.",
447
29
                            m_poGDS->m_nBitsPerSample);
448
29
                    }
449
5.26M
                }
450
451
84.7M
                if (m_poGDS->m_nBitsPerSample == 24)
452
40.3k
                {
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
40.3k
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
466
40.3k
                        static_cast<GByte>(nInWord >> 16);
467
40.3k
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
468
40.3k
                        static_cast<GByte>(nInWord >> 8);
469
40.3k
                    m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
470
40.3k
                        static_cast<GByte>(nInWord);
471
40.3k
#endif
472
40.3k
                    iBitOffset += 24;
473
40.3k
                }
474
84.7M
                else
475
84.7M
                {
476
501M
                    for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
477
416M
                    {
478
                        // TODO(schwehr): Revisit this block.
479
416M
                        if (nInWord &
480
416M
                            (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
481
28.2M
                        {
482
28.2M
                            m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
483
28.2M
                                (0x80 >> (iBitOffset & 7));
484
28.2M
                        }
485
388M
                        else
486
388M
                        {
487
                            // We must explicitly unset the bit as we
488
                            // may update an existing block.
489
388M
                            m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &=
490
388M
                                ~(0x80 >> (iBitOffset & 7));
491
388M
                        }
492
493
416M
                        ++iBitOffset;
494
416M
                    }
495
84.7M
                }
496
497
84.7M
                iBitOffset =
498
84.7M
                    iBitOffset + iPixelBitSkip - m_poGDS->m_nBitsPerSample;
499
84.7M
            }
500
93.6k
        }
501
502
47.1k
        if (poBlock != nullptr)
503
35.5k
        {
504
35.5k
            poBlock->MarkClean();
505
35.5k
            poBlock->DropLock();
506
35.5k
        }
507
47.1k
    }
508
509
11.6k
    m_poGDS->m_bLoadedBlockDirty = true;
510
511
11.6k
    return CE_None;
512
13.5k
}
513
514
/************************************************************************/
515
/*                             IReadBlock()                             */
516
/************************************************************************/
517
518
CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
519
                                    void *pImage)
520
521
1.55M
{
522
1.55M
    m_poGDS->Crystalize();
523
524
1.55M
    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
1.55M
    if (nBlockId != m_poGDS->m_nLoadedBlock)
532
1.54M
    {
533
1.54M
        bool bErrOccurred = false;
534
1.54M
        if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, nullptr,
535
1.54M
                                       &bErrOccurred))
536
375k
        {
537
375k
            NullBlock(pImage);
538
375k
            if (bErrOccurred)
539
7.76k
                return CE_Failure;
540
367k
            return CE_None;
541
375k
        }
542
1.54M
    }
543
544
    /* -------------------------------------------------------------------- */
545
    /*      Load the block buffer.                                          */
546
    /* -------------------------------------------------------------------- */
547
1.17M
    {
548
1.17M
        const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId);
549
1.17M
        if (eErr != CE_None)
550
48.6k
            return eErr;
551
1.17M
    }
552
553
1.12M
    if (m_poGDS->m_nBitsPerSample == 1 &&
554
1.12M
        (m_poGDS->nBands == 1 ||
555
926k
         m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
556
822k
    {
557
        // Translate 1bit data to eight bit.
558
822k
        const GByte *CPL_RESTRICT pabySrc = m_poGDS->m_pabyBlockBuf;
559
822k
        GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);
560
561
2.37G
        for (int iLine = 0; iLine < nBlockYSize; ++iLine)
562
2.37G
        {
563
2.37G
            if (m_poGDS->m_bPromoteTo8Bits)
564
37.9k
            {
565
37.9k
                GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
566
37.9k
                                                   nBlockXSize);
567
37.9k
            }
568
2.37G
            else
569
2.37G
            {
570
2.37G
                GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
571
2.37G
                                                 nBlockXSize);
572
2.37G
            }
573
2.37G
            pabySrc += (nBlockXSize + 7) / 8;
574
2.37G
            pabyDest += nBlockXSize;
575
2.37G
        }
576
822k
    }
577
    /* -------------------------------------------------------------------- */
578
    /*      Handle the case of 16- and 24-bit floating point data as per    */
579
    /*      TIFF Technical Note 3.                                          */
580
    /* -------------------------------------------------------------------- */
581
304k
    else if (eDataType == GDT_Float32)
582
59.2k
    {
583
59.2k
        const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
584
59.2k
        const GByte *pabyImage =
585
59.2k
            m_poGDS->m_pabyBlockBuf +
586
59.2k
            ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
587
59.2k
                 ? 0
588
59.2k
                 : (nBand - 1) * nWordBytes);
589
59.2k
        const int iSkipBytes =
590
59.2k
            (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
591
59.2k
                ? nWordBytes
592
59.2k
                : m_poGDS->nBands * nWordBytes;
593
594
59.2k
        const auto nBlockPixels =
595
59.2k
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
596
59.2k
        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
59.2k
        else if (m_poGDS->m_nBitsPerSample == 24)
606
59.2k
        {
607
1.24M
            for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
608
1.18M
            {
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
1.18M
                static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
616
1.18M
                    (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
617
1.18M
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
618
1.18M
                    static_cast<GUInt32>(*pabyImage));
619
1.18M
#endif
620
1.18M
                pabyImage += iSkipBytes;
621
1.18M
            }
622
59.2k
        }
623
59.2k
    }
624
625
    /* -------------------------------------------------------------------- */
626
    /*      Special case for moving 12bit data somewhat more efficiently.   */
627
    /* -------------------------------------------------------------------- */
628
244k
    else if (m_poGDS->m_nBitsPerSample == 12)
629
24.7k
    {
630
24.7k
        int iPixelBitSkip = 0;
631
24.7k
        int iBandBitOffset = 0;
632
633
24.7k
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
634
16.4k
        {
635
16.4k
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
636
16.4k
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
637
16.4k
        }
638
8.24k
        else
639
8.24k
        {
640
8.24k
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
641
8.24k
        }
642
643
        // Bits per line rounds up to next byte boundary.
644
24.7k
        GPtrDiff_t nBitsPerLine =
645
24.7k
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
646
24.7k
        if ((nBitsPerLine & 7) != 0)
647
12.8k
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
648
649
24.7k
        int iPixel = 0;
650
15.2M
        for (int iY = 0; iY < nBlockYSize; ++iY)
651
15.2M
        {
652
15.2M
            GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
653
654
1.08G
            for (int iX = 0; iX < nBlockXSize; ++iX)
655
1.07G
            {
656
1.07G
                const auto iByte = iBitOffset >> 3;
657
658
1.07G
                if ((iBitOffset & 0x7) == 0)
659
537M
                {
660
                    // Starting on byte boundary.
661
662
537M
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
663
537M
                        (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
664
537M
                        (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
665
537M
                }
666
536M
                else
667
536M
                {
668
                    // Starting off byte boundary.
669
670
536M
                    static_cast<GUInt16 *>(pImage)[iPixel++] =
671
536M
                        ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
672
536M
                        (m_poGDS->m_pabyBlockBuf[iByte + 1]);
673
536M
                }
674
1.07G
                iBitOffset += iPixelBitSkip;
675
1.07G
            }
676
15.2M
        }
677
24.7k
    }
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
220k
    else if (m_poGDS->m_nBitsPerSample == 24)
684
23.7k
    {
685
23.7k
        int iPixelByteSkip = 0;
686
23.7k
        int iBandByteOffset = 0;
687
688
23.7k
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
689
14.0k
        {
690
14.0k
            iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
691
14.0k
            iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
692
14.0k
        }
693
9.67k
        else
694
9.67k
        {
695
9.67k
            iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
696
9.67k
        }
697
698
23.7k
        const GPtrDiff_t nBytesPerLine =
699
23.7k
            static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
700
701
23.7k
        GPtrDiff_t iPixel = 0;
702
197k
        for (int iY = 0; iY < nBlockYSize; ++iY)
703
173k
        {
704
173k
            GByte *pabyImage =
705
173k
                m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
706
707
1.17M
            for (int iX = 0; iX < nBlockXSize; ++iX)
708
999k
            {
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
999k
                static_cast<GUInt32 *>(pImage)[iPixel++] =
716
999k
                    (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
717
999k
                    (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
718
999k
                    static_cast<GUInt32>(*(pabyImage + 2));
719
999k
#endif
720
999k
                pabyImage += iPixelByteSkip;
721
999k
            }
722
173k
        }
723
23.7k
    }
724
725
    /* -------------------------------------------------------------------- */
726
    /*      Handle 1-32 bit integer data.                                   */
727
    /* -------------------------------------------------------------------- */
728
196k
    else
729
196k
    {
730
196k
        unsigned iPixelBitSkip = 0;
731
196k
        unsigned iBandBitOffset = 0;
732
733
196k
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
734
125k
        {
735
125k
            iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
736
125k
            iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
737
125k
        }
738
70.8k
        else
739
70.8k
        {
740
70.8k
            iPixelBitSkip = m_poGDS->m_nBitsPerSample;
741
70.8k
        }
742
743
        // Bits per line rounds up to next byte boundary.
744
196k
        GUIntBig nBitsPerLine =
745
196k
            static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
746
196k
        if ((nBitsPerLine & 7) != 0)
747
133k
            nBitsPerLine = (nBitsPerLine + 7) & (~7);
748
749
196k
        const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
750
196k
        const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
751
196k
        GPtrDiff_t iPixel = 0;
752
753
196k
        if (nBitsPerSample == 1 && eDataType == GDT_Byte)
754
103k
        {
755
1.19M
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
756
1.09M
            {
757
1.09M
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
758
759
14.9M
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
760
13.8M
                     ++iX)
761
13.8M
                {
762
13.8M
                    if (m_pabyBlockBuf[iBitOffset >> 3] &
763
13.8M
                        (0x80 >> (iBitOffset & 7)))
764
4.56M
                        static_cast<GByte *>(pImage)[iPixel] = 1;
765
9.27M
                    else
766
9.27M
                        static_cast<GByte *>(pImage)[iPixel] = 0;
767
13.8M
                    iBitOffset += iPixelBitSkip;
768
13.8M
                    iPixel++;
769
13.8M
                }
770
1.09M
            }
771
103k
        }
772
92.6k
        else
773
92.6k
        {
774
39.8M
            for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
775
39.7M
            {
776
39.7M
                GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
777
778
195M
                for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
779
156M
                     ++iX)
780
156M
                {
781
156M
                    unsigned nOutWord = 0;
782
783
587M
                    for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
784
431M
                    {
785
431M
                        if (m_pabyBlockBuf[iBitOffset >> 3] &
786
431M
                            (0x80 >> (iBitOffset & 7)))
787
318M
                            nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
788
431M
                        ++iBitOffset;
789
431M
                    }
790
791
156M
                    iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
792
793
156M
                    if (eDataType == GDT_Byte)
794
142M
                    {
795
142M
                        static_cast<GByte *>(pImage)[iPixel++] =
796
142M
                            static_cast<GByte>(nOutWord);
797
142M
                    }
798
13.2M
                    else if (eDataType == GDT_UInt16)
799
11.9M
                    {
800
11.9M
                        static_cast<GUInt16 *>(pImage)[iPixel++] =
801
11.9M
                            static_cast<GUInt16>(nOutWord);
802
11.9M
                    }
803
1.25M
                    else if (eDataType == GDT_UInt32)
804
1.25M
                    {
805
1.25M
                        static_cast<GUInt32 *>(pImage)[iPixel++] = nOutWord;
806
1.25M
                    }
807
0
                    else
808
0
                    {
809
0
                        CPLAssert(false);
810
0
                    }
811
156M
                }
812
39.7M
            }
813
92.6k
        }
814
196k
    }
815
816
1.12M
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
817
818
1.12M
    return CE_None;
819
1.17M
}