Coverage Report

Created: 2026-07-25 06:50

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