LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffoddbitsband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 321 365 87.9 %
Date: 2025-10-21 22:35:35 Functions: 3 3 100.0 %

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

Generated by: LCOV version 1.14