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

Generated by: LCOV version 1.14