LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffoddbitsband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 371 402 92.3 %
Date: 2024-11-21 22:18:42 Functions: 6 6 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 "cpl_float.h"  // CPLFloatToHalf()
      17             : #include "gtiffdataset.h"
      18             : #include "tiffio.h"
      19             : 
      20             : /************************************************************************/
      21             : /*                           GTiffOddBitsBand()                         */
      22             : /************************************************************************/
      23             : 
      24         775 : GTiffOddBitsBand::GTiffOddBitsBand(GTiffDataset *m_poGDSIn, int nBandIn)
      25         775 :     : GTiffRasterBand(m_poGDSIn, nBandIn)
      26             : 
      27             : {
      28         775 :     eDataType = GDT_Unknown;
      29         775 :     if ((m_poGDS->m_nBitsPerSample == 16 || m_poGDS->m_nBitsPerSample == 24) &&
      30          58 :         m_poGDS->m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
      31          26 :         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         749 :     else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
      35           2 :               m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
      36         749 :              m_poGDS->m_nBitsPerSample < 8)
      37         510 :         eDataType = GDT_Byte;
      38         239 :     else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
      39           2 :               m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
      40         239 :              m_poGDS->m_nBitsPerSample > 8 && m_poGDS->m_nBitsPerSample < 16)
      41         169 :         eDataType = GDT_UInt16;
      42          70 :     else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
      43           2 :               m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
      44          70 :              m_poGDS->m_nBitsPerSample > 16 && m_poGDS->m_nBitsPerSample < 32)
      45          69 :         eDataType = GDT_UInt32;
      46         775 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                            IWriteBlock()                             */
      50             : /************************************************************************/
      51             : 
      52        7308 : CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
      53             :                                      void *pImage)
      54             : 
      55             : {
      56        7308 :     m_poGDS->Crystalize();
      57             : 
      58        7308 :     if (m_poGDS->m_bWriteError)
      59             :     {
      60             :         // Report as an error if a previously loaded block couldn't be written
      61             :         // correctly.
      62           0 :         return CE_Failure;
      63             :     }
      64             : 
      65        7308 :     if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample != 16)
      66             :     {
      67           0 :         ReportError(
      68             :             CE_Failure, CPLE_NotSupported,
      69             :             "Writing float data with nBitsPerSample = %d is unsupported",
      70           0 :             m_poGDS->m_nBitsPerSample);
      71           0 :         return CE_Failure;
      72             :     }
      73             : 
      74             :     /* -------------------------------------------------------------------- */
      75             :     /*      Load the block buffer.                                          */
      76             :     /* -------------------------------------------------------------------- */
      77        7308 :     const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
      78             : 
      79             :     // Only read content from disk in the CONTIG case.
      80             :     {
      81        7308 :         const CPLErr eErr = m_poGDS->LoadBlockBuf(
      82       14525 :             nBlockId, m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
      83        7217 :                           m_poGDS->nBands > 1);
      84        7308 :         if (eErr != CE_None)
      85           0 :             return eErr;
      86             :     }
      87             : 
      88        7308 :     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        7308 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
      95        7217 :         m_poGDS->nBands == 1)
      96             :     {
      97             :         // TODO(schwehr): Create a CplNumBits8Aligned.
      98             :         // Bits per line rounds up to next byte boundary.
      99        7197 :         GInt64 nBitsPerLine =
     100        7197 :             static_cast<GInt64>(nBlockXSize) * m_poGDS->m_nBitsPerSample;
     101        7197 :         if ((nBitsPerLine & 7) != 0)
     102          62 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     103             : 
     104        7197 :         GPtrDiff_t iPixel = 0;
     105             : 
     106             :         // Small optimization in 1 bit case.
     107        7197 :         if (m_poGDS->m_nBitsPerSample == 1)
     108             :         {
     109      244568 :             for (int iY = 0; iY < nBlockYSize; ++iY, iPixel += nBlockXSize)
     110             :             {
     111      237515 :                 GInt64 iBitOffset = iY * nBitsPerLine;
     112             : 
     113      237515 :                 const GByte *pabySrc =
     114      237515 :                     static_cast<const GByte *>(pImage) + iPixel;
     115      237515 :                 auto iByteOffset = iBitOffset / 8;
     116      237515 :                 int iX = 0;  // Used after for.
     117     6735920 :                 for (; iX + 7 < nBlockXSize; iX += 8, iByteOffset++)
     118             :                 {
     119     6498410 :                     int nRes = (!(!pabySrc[iX + 0])) << 7;
     120     6498410 :                     nRes |= (!(!pabySrc[iX + 1])) << 6;
     121     6498410 :                     nRes |= (!(!pabySrc[iX + 2])) << 5;
     122     6498410 :                     nRes |= (!(!pabySrc[iX + 3])) << 4;
     123     6498410 :                     nRes |= (!(!pabySrc[iX + 4])) << 3;
     124     6498410 :                     nRes |= (!(!pabySrc[iX + 5])) << 2;
     125     6498410 :                     nRes |= (!(!pabySrc[iX + 6])) << 1;
     126     6498410 :                     nRes |= (!(!pabySrc[iX + 7])) << 0;
     127     6498410 :                     m_poGDS->m_pabyBlockBuf[iByteOffset] =
     128             :                         static_cast<GByte>(nRes);
     129             :                 }
     130      237515 :                 iBitOffset = iByteOffset * 8;
     131      237515 :                 if (iX < nBlockXSize)
     132             :                 {
     133        2088 :                     int nRes = 0;
     134        9219 :                     for (; iX < nBlockXSize; ++iX)
     135             :                     {
     136        7131 :                         if (pabySrc[iX])
     137        2452 :                             nRes |= (0x80 >> (iBitOffset & 7));
     138        7131 :                         ++iBitOffset;
     139             :                     }
     140        2088 :                     m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     141             :                         static_cast<GByte>(nRes);
     142             :                 }
     143             :             }
     144             : 
     145        7053 :             m_poGDS->m_bLoadedBlockDirty = true;
     146             : 
     147        7053 :             return CE_None;
     148             :         }
     149             : 
     150         144 :         if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample == 16)
     151             :         {
     152      240495 :             for (; iPixel < static_cast<GPtrDiff_t>(nBlockYSize) * nBlockXSize;
     153             :                  iPixel++)
     154             :             {
     155      240432 :                 GUInt32 nInWord = static_cast<GUInt32 *>(pImage)[iPixel];
     156      240432 :                 bool bClipWarn = m_poGDS->m_bClipWarn;
     157      240432 :                 GUInt16 nHalf = CPLFloatToHalf(nInWord, bClipWarn);
     158      240432 :                 m_poGDS->m_bClipWarn = bClipWarn;
     159      240432 :                 reinterpret_cast<GUInt16 *>(m_poGDS->m_pabyBlockBuf)[iPixel] =
     160             :                     nHalf;
     161             :             }
     162             : 
     163          63 :             m_poGDS->m_bLoadedBlockDirty = true;
     164             : 
     165          63 :             return CE_None;
     166             :         }
     167             : 
     168             :         // Initialize to zero as we set the buffer with binary or operations.
     169          81 :         if (m_poGDS->m_nBitsPerSample != 24)
     170          76 :             memset(m_poGDS->m_pabyBlockBuf, 0,
     171          76 :                    static_cast<size_t>((nBitsPerLine / 8) * nBlockYSize));
     172             : 
     173        3005 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     174             :         {
     175        2924 :             GInt64 iBitOffset = iY * nBitsPerLine;
     176             : 
     177        2924 :             if (m_poGDS->m_nBitsPerSample == 12)
     178             :             {
     179       37814 :                 for (int iX = 0; iX < nBlockXSize; ++iX)
     180             :                 {
     181       37280 :                     GUInt32 nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
     182       37280 :                     if (nInWord > nMaxVal)
     183             :                     {
     184           0 :                         nInWord = nMaxVal;
     185           0 :                         if (!m_poGDS->m_bClipWarn)
     186             :                         {
     187           0 :                             m_poGDS->m_bClipWarn = true;
     188           0 :                             ReportError(
     189             :                                 CE_Warning, CPLE_AppDefined,
     190             :                                 "One or more pixels clipped to fit %d bit "
     191             :                                 "domain.",
     192           0 :                                 m_poGDS->m_nBitsPerSample);
     193             :                         }
     194             :                     }
     195             : 
     196       37280 :                     if ((iBitOffset % 8) == 0)
     197             :                     {
     198       18640 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     199       18640 :                             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       18640 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     203       18640 :                             static_cast<GByte>((nInWord & 0xf) << 4);
     204             :                     }
     205             :                     else
     206             :                     {
     207             :                         // Must or to preserve the 4 upper bits written
     208             :                         // for the previous word.
     209       18640 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     210       18640 :                             static_cast<GByte>(nInWord >> 8);
     211       18640 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     212             :                             static_cast<GByte>(nInWord & 0xff);
     213             :                     }
     214             : 
     215       37280 :                     iBitOffset += m_poGDS->m_nBitsPerSample;
     216             :                 }
     217         534 :                 continue;
     218             :             }
     219             : 
     220      368160 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     221             :             {
     222      365770 :                 GUInt32 nInWord = 0;
     223      365770 :                 if (eDataType == GDT_Byte)
     224             :                 {
     225      361568 :                     nInWord = static_cast<GByte *>(pImage)[iPixel++];
     226             :                 }
     227        4202 :                 else if (eDataType == GDT_UInt16)
     228             :                 {
     229        1401 :                     nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
     230             :                 }
     231        2801 :                 else if (eDataType == GDT_UInt32)
     232             :                 {
     233        2801 :                     nInWord = static_cast<GUInt32 *>(pImage)[iPixel++];
     234             :                 }
     235             :                 else
     236             :                 {
     237           0 :                     CPLAssert(false);
     238             :                 }
     239             : 
     240      365770 :                 if (nInWord > nMaxVal)
     241             :                 {
     242         400 :                     nInWord = nMaxVal;
     243         400 :                     if (!m_poGDS->m_bClipWarn)
     244             :                     {
     245           1 :                         m_poGDS->m_bClipWarn = true;
     246           1 :                         ReportError(
     247             :                             CE_Warning, CPLE_AppDefined,
     248             :                             "One or more pixels clipped to fit %d bit domain.",
     249           1 :                             m_poGDS->m_nBitsPerSample);
     250             :                     }
     251             :                 }
     252             : 
     253      365770 :                 if (m_poGDS->m_nBitsPerSample == 24)
     254             :                 {
     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        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
     268        1400 :                         static_cast<GByte>(nInWord >> 16);
     269        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     270        1400 :                         static_cast<GByte>(nInWord >> 8);
     271        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
     272             :                         static_cast<GByte>(nInWord);
     273             : #endif
     274        1400 :                     iBitOffset += 24;
     275             :                 }
     276             :                 else
     277             :                 {
     278     2930970 :                     for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
     279             :                     {
     280     2566600 :                         if (nInWord &
     281     2566600 :                             (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
     282      256612 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     283      256612 :                                 (0x80 >> (iBitOffset & 7));
     284     2566600 :                         ++iBitOffset;
     285             :                     }
     286             :                 }
     287             :             }
     288             :         }
     289             : 
     290          81 :         m_poGDS->m_bLoadedBlockDirty = true;
     291             : 
     292          81 :         return CE_None;
     293             :     }
     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         442 :     for (int iBand = 0; iBand < m_poGDS->nBands; ++iBand)
     305             :     {
     306         331 :         const GByte *pabyThisImage = nullptr;
     307         331 :         GDALRasterBlock *poBlock = nullptr;
     308             : 
     309         331 :         if (iBand + 1 == nBand)
     310             :         {
     311         111 :             pabyThisImage = static_cast<GByte *>(pImage);
     312             :         }
     313             :         else
     314             :         {
     315         220 :             poBlock = cpl::down_cast<GTiffOddBitsBand *>(
     316         220 :                           m_poGDS->GetRasterBand(iBand + 1))
     317         220 :                           ->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
     318             : 
     319         220 :             if (poBlock == nullptr)
     320          11 :                 continue;
     321             : 
     322         209 :             if (!poBlock->GetDirty())
     323             :             {
     324           3 :                 poBlock->DropLock();
     325           3 :                 continue;
     326             :             }
     327             : 
     328         206 :             pabyThisImage = static_cast<GByte *>(poBlock->GetDataRef());
     329             :         }
     330             : 
     331         317 :         const int iPixelBitSkip = m_poGDS->m_nBitsPerSample * m_poGDS->nBands;
     332         317 :         const int iBandBitOffset = iBand * m_poGDS->m_nBitsPerSample;
     333             : 
     334             :         // Bits per line rounds up to next byte boundary.
     335         317 :         GInt64 nBitsPerLine = static_cast<GInt64>(nBlockXSize) * iPixelBitSkip;
     336         317 :         if ((nBitsPerLine & 7) != 0)
     337          16 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     338             : 
     339         317 :         GPtrDiff_t iPixel = 0;
     340             : 
     341         317 :         if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample == 16)
     342             :         {
     343           0 :             for (; iPixel < static_cast<GPtrDiff_t>(nBlockYSize) * nBlockXSize;
     344             :                  iPixel++)
     345             :             {
     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             :                 reinterpret_cast<GUInt16 *>(
     352           0 :                     m_poGDS->m_pabyBlockBuf)[iPixel * m_poGDS->nBands + iBand] =
     353             :                     nHalf;
     354             :             }
     355             : 
     356           0 :             if (poBlock != nullptr)
     357             :             {
     358           0 :                 poBlock->MarkClean();
     359           0 :                 poBlock->DropLock();
     360             :             }
     361           0 :             continue;
     362             :         }
     363             : 
     364        5547 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     365             :         {
     366        5230 :             GInt64 iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     367             : 
     368        5230 :             if (m_poGDS->m_nBitsPerSample == 12)
     369             :             {
     370       29704 :                 for (int iX = 0; iX < nBlockXSize; ++iX)
     371             :                 {
     372             :                     GUInt32 nInWord = reinterpret_cast<const GUInt16 *>(
     373       29048 :                         pabyThisImage)[iPixel++];
     374       29048 :                     if (nInWord > nMaxVal)
     375             :                     {
     376           0 :                         nInWord = nMaxVal;
     377           0 :                         if (!m_poGDS->m_bClipWarn)
     378             :                         {
     379           0 :                             m_poGDS->m_bClipWarn = true;
     380           0 :                             ReportError(
     381             :                                 CE_Warning, CPLE_AppDefined,
     382             :                                 "One or more pixels clipped to fit %d bit "
     383             :                                 "domain.",
     384           0 :                                 m_poGDS->m_nBitsPerSample);
     385             :                         }
     386             :                     }
     387             : 
     388       29048 :                     if ((iBitOffset % 8) == 0)
     389             :                     {
     390       14624 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     391       14624 :                             static_cast<GByte>(nInWord >> 4);
     392       14624 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     393             :                             static_cast<GByte>(
     394       14624 :                                 ((nInWord & 0xf) << 4) |
     395       14624 :                                 (m_poGDS
     396       14624 :                                      ->m_pabyBlockBuf[(iBitOffset >> 3) + 1] &
     397             :                                  0xf));
     398             :                     }
     399             :                     else
     400             :                     {
     401       14424 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     402             :                             static_cast<GByte>(
     403       14424 :                                 (m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &
     404       14424 :                                  0xf0) |
     405       14424 :                                 (nInWord >> 8));
     406       14424 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     407             :                             static_cast<GByte>(nInWord & 0xff);
     408             :                     }
     409             : 
     410       29048 :                     iBitOffset += iPixelBitSkip;
     411             :                 }
     412         656 :                 continue;
     413             :             }
     414             : 
     415      382340 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     416             :             {
     417      377766 :                 GUInt32 nInWord = 0;
     418      377766 :                 if (eDataType == GDT_Byte)
     419             :                 {
     420      179166 :                     nInWord =
     421      179166 :                         static_cast<const GByte *>(pabyThisImage)[iPixel++];
     422             :                 }
     423      198600 :                 else if (eDataType == GDT_UInt16)
     424             :                 {
     425      195800 :                     nInWord = reinterpret_cast<const GUInt16 *>(
     426      195800 :                         pabyThisImage)[iPixel++];
     427             :                 }
     428        2800 :                 else if (eDataType == GDT_UInt32)
     429             :                 {
     430        2800 :                     nInWord = reinterpret_cast<const GUInt32 *>(
     431        2800 :                         pabyThisImage)[iPixel++];
     432             :                 }
     433             :                 else
     434             :                 {
     435           0 :                     CPLAssert(false);
     436             :                 }
     437             : 
     438      377766 :                 if (nInWord > nMaxVal)
     439             :                 {
     440         344 :                     nInWord = nMaxVal;
     441         344 :                     if (!m_poGDS->m_bClipWarn)
     442             :                     {
     443           2 :                         m_poGDS->m_bClipWarn = true;
     444           2 :                         ReportError(
     445             :                             CE_Warning, CPLE_AppDefined,
     446             :                             "One or more pixels clipped to fit %d bit domain.",
     447           2 :                             m_poGDS->m_nBitsPerSample);
     448             :                     }
     449             :                 }
     450             : 
     451      377766 :                 if (m_poGDS->m_nBitsPerSample == 24)
     452             :                 {
     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        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
     466        1400 :                         static_cast<GByte>(nInWord >> 16);
     467        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     468        1400 :                         static_cast<GByte>(nInWord >> 8);
     469        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
     470             :                         static_cast<GByte>(nInWord);
     471             : #endif
     472        1400 :                     iBitOffset += 24;
     473             :                 }
     474             :                 else
     475             :                 {
     476     4581720 :                     for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
     477             :                     {
     478             :                         // TODO(schwehr): Revisit this block.
     479     4205360 :                         if (nInWord &
     480     4205360 :                             (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
     481             :                         {
     482      699473 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     483      699473 :                                 (0x80 >> (iBitOffset & 7));
     484             :                         }
     485             :                         else
     486             :                         {
     487             :                             // We must explicitly unset the bit as we
     488             :                             // may update an existing block.
     489     3505880 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &=
     490     3505880 :                                 ~(0x80 >> (iBitOffset & 7));
     491             :                         }
     492             : 
     493     4205360 :                         ++iBitOffset;
     494             :                     }
     495             :                 }
     496             : 
     497      377766 :                 iBitOffset =
     498      377766 :                     iBitOffset + iPixelBitSkip - m_poGDS->m_nBitsPerSample;
     499             :             }
     500             :         }
     501             : 
     502         317 :         if (poBlock != nullptr)
     503             :         {
     504         206 :             poBlock->MarkClean();
     505         206 :             poBlock->DropLock();
     506             :         }
     507             :     }
     508             : 
     509         111 :     m_poGDS->m_bLoadedBlockDirty = true;
     510             : 
     511         111 :     return CE_None;
     512             : }
     513             : 
     514             : /************************************************************************/
     515             : /*                             IReadBlock()                             */
     516             : /************************************************************************/
     517             : 
     518        6594 : static void ExpandPacked8ToByte1(const GByte *const CPL_RESTRICT pabySrc,
     519             :                                  GByte *const CPL_RESTRICT pabyDest,
     520             :                                  GPtrDiff_t nBytes)
     521             : {
     522      141502 :     for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
     523             :     {
     524      134908 :         const GByte byVal = pabySrc[i];
     525      134908 :         pabyDest[j + 0] = (byVal >> 7) & 0x1;
     526      134908 :         pabyDest[j + 1] = (byVal >> 6) & 0x1;
     527      134908 :         pabyDest[j + 2] = (byVal >> 5) & 0x1;
     528      134908 :         pabyDest[j + 3] = (byVal >> 4) & 0x1;
     529      134908 :         pabyDest[j + 4] = (byVal >> 3) & 0x1;
     530      134908 :         pabyDest[j + 5] = (byVal >> 2) & 0x1;
     531      134908 :         pabyDest[j + 6] = (byVal >> 1) & 0x1;
     532      134908 :         pabyDest[j + 7] = (byVal >> 0) & 0x1;
     533             :     }
     534        6594 : }
     535             : 
     536             : #if defined(__GNUC__) || defined(_MSC_VER)
     537             : // Signedness of char implementation dependent, so be explicit.
     538             : // Assumes 2-complement integer types and sign extension of right shifting
     539             : // GCC guarantees such:
     540             : // https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
     541     6168190 : static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
     542             : {
     543     6168190 :     return static_cast<GByte>(static_cast<signed char>(byVal << (7 - nBit)) >>
     544     6168190 :                               7);
     545             : }
     546             : #else
     547             : // Portable way
     548             : static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
     549             : {
     550             :     return (byVal & (1 << nBit)) ? 255 : 0;
     551             : }
     552             : #endif
     553             : 
     554       30234 : static void ExpandPacked8ToByte255(const GByte *const CPL_RESTRICT pabySrc,
     555             :                                    GByte *const CPL_RESTRICT pabyDest,
     556             :                                    GPtrDiff_t nBytes)
     557             : {
     558      801258 :     for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
     559             :     {
     560      771024 :         const GByte byVal = pabySrc[i];
     561      771024 :         pabyDest[j + 0] = ExtractBitAndConvertTo255(byVal, 7);
     562      771024 :         pabyDest[j + 1] = ExtractBitAndConvertTo255(byVal, 6);
     563      771024 :         pabyDest[j + 2] = ExtractBitAndConvertTo255(byVal, 5);
     564      771024 :         pabyDest[j + 3] = ExtractBitAndConvertTo255(byVal, 4);
     565      771024 :         pabyDest[j + 4] = ExtractBitAndConvertTo255(byVal, 3);
     566      771024 :         pabyDest[j + 5] = ExtractBitAndConvertTo255(byVal, 2);
     567      771024 :         pabyDest[j + 6] = ExtractBitAndConvertTo255(byVal, 1);
     568      771024 :         pabyDest[j + 7] = ExtractBitAndConvertTo255(byVal, 0);
     569             :     }
     570       30234 : }
     571             : 
     572        5561 : CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
     573             :                                     void *pImage)
     574             : 
     575             : {
     576        5561 :     m_poGDS->Crystalize();
     577             : 
     578        5561 :     const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
     579             : 
     580             :     /* -------------------------------------------------------------------- */
     581             :     /*      Handle the case of a strip in a writable file that doesn't      */
     582             :     /*      exist yet, but that we want to read.  Just set to zeros and     */
     583             :     /*      return.                                                         */
     584             :     /* -------------------------------------------------------------------- */
     585        5561 :     if (nBlockId != m_poGDS->m_nLoadedBlock)
     586             :     {
     587        5514 :         bool bErrOccurred = false;
     588        5514 :         if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, nullptr,
     589             :                                        &bErrOccurred))
     590             :         {
     591        4674 :             NullBlock(pImage);
     592        4674 :             if (bErrOccurred)
     593        4674 :                 return CE_Failure;
     594        4674 :             return CE_None;
     595             :         }
     596             :     }
     597             : 
     598             :     /* -------------------------------------------------------------------- */
     599             :     /*      Load the block buffer.                                          */
     600             :     /* -------------------------------------------------------------------- */
     601             :     {
     602         887 :         const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId);
     603         887 :         if (eErr != CE_None)
     604           0 :             return eErr;
     605             :     }
     606             : 
     607         887 :     if (m_poGDS->m_nBitsPerSample == 1 &&
     608         429 :         (m_poGDS->nBands == 1 ||
     609          28 :          m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
     610             :     {
     611             :         /* --------------------------------------------------------------------
     612             :          */
     613             :         /*      Translate 1bit data to eight bit. */
     614             :         /* --------------------------------------------------------------------
     615             :          */
     616         405 :         GPtrDiff_t iDstOffset = 0;
     617         405 :         const GByte *const CPL_RESTRICT m_pabyBlockBuf =
     618         405 :             m_poGDS->m_pabyBlockBuf;
     619         405 :         GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);
     620             : 
     621       37233 :         for (int iLine = 0; iLine < nBlockYSize; ++iLine)
     622             :         {
     623       36828 :             GPtrDiff_t iSrcOffsetByte =
     624       36828 :                 static_cast<GPtrDiff_t>((nBlockXSize + 7) >> 3) * iLine;
     625             : 
     626       36828 :             if (!m_poGDS->m_bPromoteTo8Bits)
     627             :             {
     628        6594 :                 ExpandPacked8ToByte1(m_pabyBlockBuf + iSrcOffsetByte,
     629        6594 :                                      pabyDest + iDstOffset, nBlockXSize / 8);
     630             :             }
     631             :             else
     632             :             {
     633       30234 :                 ExpandPacked8ToByte255(m_pabyBlockBuf + iSrcOffsetByte,
     634       30234 :                                        pabyDest + iDstOffset, nBlockXSize / 8);
     635             :             }
     636       36828 :             GPtrDiff_t iSrcOffsetBit = (iSrcOffsetByte + nBlockXSize / 8) * 8;
     637       36828 :             iDstOffset += nBlockXSize & ~0x7;
     638       36828 :             const GByte bSetVal = m_poGDS->m_bPromoteTo8Bits ? 255 : 1;
     639       49349 :             for (int iPixel = nBlockXSize & ~0x7; iPixel < nBlockXSize;
     640             :                  ++iPixel, ++iSrcOffsetBit)
     641             :             {
     642       12521 :                 if (m_pabyBlockBuf[iSrcOffsetBit >> 3] &
     643       12521 :                     (0x80 >> (iSrcOffsetBit & 0x7)))
     644        3995 :                     static_cast<GByte *>(pImage)[iDstOffset++] = bSetVal;
     645             :                 else
     646        8526 :                     static_cast<GByte *>(pImage)[iDstOffset++] = 0;
     647             :             }
     648         405 :         }
     649             :     }
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      Handle the case of 16- and 24-bit floating point data as per    */
     652             :     /*      TIFF Technical Note 3.                                          */
     653             :     /* -------------------------------------------------------------------- */
     654         482 :     else if (eDataType == GDT_Float32)
     655             :     {
     656          46 :         const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
     657          46 :         const GByte *pabyImage =
     658          40 :             m_poGDS->m_pabyBlockBuf +
     659          46 :             ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     660             :                  ? 0
     661           6 :                  : (nBand - 1) * nWordBytes);
     662          46 :         const int iSkipBytes =
     663          46 :             (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     664          46 :                 ? nWordBytes
     665           6 :                 : m_poGDS->nBands * nWordBytes;
     666             : 
     667          46 :         const auto nBlockPixels =
     668          46 :             static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
     669          46 :         if (m_poGDS->m_nBitsPerSample == 16)
     670             :         {
     671      161277 :             for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
     672             :             {
     673      322464 :                 static_cast<GUInt32 *>(pImage)[i] = CPLHalfToFloat(
     674      161232 :                     *reinterpret_cast<const GUInt16 *>(pabyImage));
     675      161232 :                 pabyImage += iSkipBytes;
     676             :             }
     677             :         }
     678           1 :         else if (m_poGDS->m_nBitsPerSample == 24)
     679             :         {
     680         401 :             for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
     681             :             {
     682             : #ifdef CPL_MSB
     683             :                 static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
     684             :                     (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
     685             :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     686             :                     static_cast<GUInt32>(*(pabyImage + 2)));
     687             : #else
     688         800 :                 static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
     689         400 :                     (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
     690         400 :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     691         400 :                     static_cast<GUInt32>(*pabyImage));
     692             : #endif
     693         400 :                 pabyImage += iSkipBytes;
     694             :             }
     695             :         }
     696             :     }
     697             : 
     698             :     /* -------------------------------------------------------------------- */
     699             :     /*      Special case for moving 12bit data somewhat more efficiently.   */
     700             :     /* -------------------------------------------------------------------- */
     701         436 :     else if (m_poGDS->m_nBitsPerSample == 12)
     702             :     {
     703          38 :         int iPixelBitSkip = 0;
     704          38 :         int iBandBitOffset = 0;
     705             : 
     706          38 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     707             :         {
     708          29 :             iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
     709          29 :             iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
     710             :         }
     711             :         else
     712             :         {
     713           9 :             iPixelBitSkip = m_poGDS->m_nBitsPerSample;
     714             :         }
     715             : 
     716             :         // Bits per line rounds up to next byte boundary.
     717          38 :         GPtrDiff_t nBitsPerLine =
     718          38 :             static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
     719          38 :         if ((nBitsPerLine & 7) != 0)
     720           0 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     721             : 
     722          38 :         int iPixel = 0;
     723        1184 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     724             :         {
     725        1146 :             GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     726             : 
     727       72994 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     728             :             {
     729       71848 :                 const auto iByte = iBitOffset >> 3;
     730             : 
     731       71848 :                 if ((iBitOffset & 0x7) == 0)
     732             :                 {
     733             :                     // Starting on byte boundary.
     734             : 
     735       36792 :                     static_cast<GUInt16 *>(pImage)[iPixel++] =
     736       36792 :                         (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
     737       36792 :                         (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
     738             :                 }
     739             :                 else
     740             :                 {
     741             :                     // Starting off byte boundary.
     742             : 
     743       35056 :                     static_cast<GUInt16 *>(pImage)[iPixel++] =
     744       35056 :                         ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
     745       35056 :                         (m_poGDS->m_pabyBlockBuf[iByte + 1]);
     746             :                 }
     747       71848 :                 iBitOffset += iPixelBitSkip;
     748             :             }
     749             :         }
     750             :     }
     751             : 
     752             :     /* -------------------------------------------------------------------- */
     753             :     /*      Special case for 24bit data which is pre-byteswapped since      */
     754             :     /*      the size falls on a byte boundary ... ugh (#2361).              */
     755             :     /* -------------------------------------------------------------------- */
     756         398 :     else if (m_poGDS->m_nBitsPerSample == 24)
     757             :     {
     758          11 :         int iPixelByteSkip = 0;
     759          11 :         int iBandByteOffset = 0;
     760             : 
     761          11 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     762             :         {
     763           8 :             iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
     764           8 :             iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
     765             :         }
     766             :         else
     767             :         {
     768           3 :             iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
     769             :         }
     770             : 
     771          11 :         const GPtrDiff_t nBytesPerLine =
     772          11 :             static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
     773             : 
     774          11 :         GPtrDiff_t iPixel = 0;
     775         191 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     776             :         {
     777         180 :             GByte *pabyImage =
     778         180 :                 m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
     779             : 
     780        3380 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     781             :             {
     782             : #ifdef CPL_MSB
     783             :                 static_cast<GUInt32 *>(pImage)[iPixel++] =
     784             :                     (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
     785             :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     786             :                     static_cast<GUInt32>(*(pabyImage + 0));
     787             : #else
     788        3200 :                 static_cast<GUInt32 *>(pImage)[iPixel++] =
     789        3200 :                     (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
     790        3200 :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     791        3200 :                     static_cast<GUInt32>(*(pabyImage + 2));
     792             : #endif
     793        3200 :                 pabyImage += iPixelByteSkip;
     794             :             }
     795             :         }
     796             :     }
     797             : 
     798             :     /* -------------------------------------------------------------------- */
     799             :     /*      Handle 1-32 bit integer data.                                   */
     800             :     /* -------------------------------------------------------------------- */
     801             :     else
     802             :     {
     803         387 :         unsigned iPixelBitSkip = 0;
     804         387 :         unsigned iBandBitOffset = 0;
     805             : 
     806         387 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     807             :         {
     808         381 :             iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
     809         381 :             iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
     810             :         }
     811             :         else
     812             :         {
     813           6 :             iPixelBitSkip = m_poGDS->m_nBitsPerSample;
     814             :         }
     815             : 
     816             :         // Bits per line rounds up to next byte boundary.
     817         387 :         GUIntBig nBitsPerLine =
     818         387 :             static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
     819         387 :         if ((nBitsPerLine & 7) != 0)
     820          52 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     821             : 
     822         387 :         const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
     823         387 :         const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
     824         387 :         GPtrDiff_t iPixel = 0;
     825             : 
     826         387 :         if (nBitsPerSample == 1 && eDataType == GDT_Byte)
     827             :         {
     828        1851 :             for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
     829             :             {
     830        1827 :                 GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     831             : 
     832      171892 :                 for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
     833             :                      ++iX)
     834             :                 {
     835      170065 :                     if (m_pabyBlockBuf[iBitOffset >> 3] &
     836      170065 :                         (0x80 >> (iBitOffset & 7)))
     837      102120 :                         static_cast<GByte *>(pImage)[iPixel] = 1;
     838             :                     else
     839       67945 :                         static_cast<GByte *>(pImage)[iPixel] = 0;
     840      170065 :                     iBitOffset += iPixelBitSkip;
     841      170065 :                     iPixel++;
     842             :                 }
     843          24 :             }
     844             :         }
     845             :         else
     846             :         {
     847        7424 :             for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
     848             :             {
     849        7061 :                 GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     850             : 
     851      498524 :                 for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
     852             :                      ++iX)
     853             :                 {
     854      491463 :                     unsigned nOutWord = 0;
     855             : 
     856     5520840 :                     for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
     857             :                     {
     858     5029380 :                         if (m_pabyBlockBuf[iBitOffset >> 3] &
     859     5029380 :                             (0x80 >> (iBitOffset & 7)))
     860      918393 :                             nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
     861     5029380 :                         ++iBitOffset;
     862             :                     }
     863             : 
     864      491463 :                     iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
     865             : 
     866      491463 :                     if (eDataType == GDT_Byte)
     867             :                     {
     868      291061 :                         static_cast<GByte *>(pImage)[iPixel++] =
     869             :                             static_cast<GByte>(nOutWord);
     870             :                     }
     871      200402 :                     else if (eDataType == GDT_UInt16)
     872             :                     {
     873      197601 :                         static_cast<GUInt16 *>(pImage)[iPixel++] =
     874             :                             static_cast<GUInt16>(nOutWord);
     875             :                     }
     876        2801 :                     else if (eDataType == GDT_UInt32)
     877             :                     {
     878        2801 :                         static_cast<GUInt32 *>(pImage)[iPixel++] = nOutWord;
     879             :                     }
     880             :                     else
     881             :                     {
     882           0 :                         CPLAssert(false);
     883             :                     }
     884             :                 }
     885             :             }
     886             :         }
     887             :     }
     888             : 
     889         887 :     CacheMaskForBlock(nBlockXOff, nBlockYOff);
     890             : 
     891         887 :     return CE_None;
     892             : }

Generated by: LCOV version 1.14