LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/channel - ctiledchannel.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 221 292 75.7 %
Date: 2026-08-22 15:37:05 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Implementation of the CTiledChannel class.
       4             :  *
       5             :  * This class is used to implement band interleaved channels within a
       6             :  * PCIDSK file (which are always packed, and FILE interleaved data from
       7             :  * external raw files which may not be packed.
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2009
      11             :  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "pcidsk_config.h"
      17             : #include "pcidsk_types.h"
      18             : #include "pcidsk_exception.h"
      19             : #include "channel/ctiledchannel.h"
      20             : #include "segment/systiledir.h"
      21             : #include "blockdir/blocktilelayer.h"
      22             : #include "core/cpcidskfile.h"
      23             : #include "core/cpcidskblockfile.h"
      24             : #include "core/pcidsk_raster.h"
      25             : #include "core/pcidsk_utils.h"
      26             : #include <cassert>
      27             : #include <cstdlib>
      28             : #include <cstring>
      29             : 
      30             : namespace PCIDSK
      31             : {
      32             : 
      33             : /************************************************************************/
      34             : /*                           CTiledChannel()                            */
      35             : /************************************************************************/
      36             : 
      37          38 : CTiledChannel::CTiledChannel( PCIDSKBuffer &image_headerIn,
      38             :                               uint64 ih_offsetIn,
      39             :                               CPL_UNUSED PCIDSKBuffer &file_headerIn,
      40             :                               int channelnumIn,
      41             :                               CPCIDSKFile *fileIn,
      42          38 :                               eChanType pixel_typeIn )
      43          38 :         : CPCIDSKChannel( image_headerIn, ih_offsetIn, fileIn, pixel_typeIn, channelnumIn)
      44             : 
      45             : {
      46          38 :     std::string filename;
      47             : 
      48          38 :     image_headerIn.Get(64,64,filename);
      49             : 
      50          38 :     assert( strstr(filename.c_str(),"SIS=") != nullptr );
      51             : 
      52          38 :     image = atoi(strstr(filename.c_str(),"SIS=") + 4);
      53             : 
      54          38 :     mpoTileLayer = nullptr;
      55          38 : }
      56             : 
      57             : /************************************************************************/
      58             : /*                           ~CTiledChannel()                           */
      59             : /************************************************************************/
      60          76 : CTiledChannel::~CTiledChannel()
      61             : {
      62             :     try
      63             :     {
      64          38 :         Synchronize();
      65             :     }
      66           0 :     catch( const PCIDSKException& e )
      67             :     {
      68           0 :         fprintf(stderr, "Exception in ~CTiledChannel(): %s", e.what()); // ok
      69             :     }
      70          76 : }
      71             : 
      72             : /************************************************************************/
      73             : /*                          EstablishAccess()                           */
      74             : /************************************************************************/
      75         249 : void CTiledChannel::EstablishAccess() const
      76             : {
      77         249 :     if (mpoTileLayer)
      78         211 :         return;
      79             : 
      80          39 :     CPCIDSKBlockFile oBlockFile(file);
      81             : 
      82          38 :     SysTileDir * poTileDir = oBlockFile.GetTileDir();
      83             : 
      84          38 :     if (!poTileDir)
      85           0 :         return ThrowPCIDSKException("Unable to find the tile directory segment.");
      86             : 
      87          38 :     mpoTileLayer = poTileDir->GetTileLayer((uint32) image);
      88             : 
      89          38 :     if (!mpoTileLayer)
      90           0 :         return ThrowPCIDSKException("Unable to find the tiled channel: %d", image);
      91             : 
      92          38 :     const char * pszDataType = mpoTileLayer->GetDataType();
      93             : 
      94          38 :     eChanType nLayerType = GetDataTypeFromName(pszDataType);
      95             : 
      96          38 :     if (nLayerType == CHN_UNKNOWN)
      97           0 :         return ThrowPCIDSKException("Unknown channel type: %s", pszDataType);
      98             : 
      99             :     // The read buffer is sized by the caller from the image band header pixel
     100             :     // type, while the amount copied per tile comes from the tile layer data
     101             :     // type. If they disagree a wider tile can be written into a buffer sized
     102             :     // for a narrower type, so reject the mismatch here.
     103          38 :     if (pixel_type != CHN_UNKNOWN && pixel_type != nLayerType)
     104           1 :         return ThrowPCIDSKException(
     105             :             "Tiled channel %d data type (%s) does not match image header "
     106             :             "pixel type (%s).",
     107           1 :             image, pszDataType, DataTypeName(pixel_type));
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                            Synchronize()                             */
     112             : /*                                                                      */
     113             : /*      Flush updated blockmap to disk if it is dirty.                  */
     114             : /************************************************************************/
     115          55 : void CTiledChannel::Synchronize()
     116             : {
     117          55 :     if (mpoTileLayer)
     118          55 :         mpoTileLayer->Sync();
     119          55 : }
     120             : 
     121             : /************************************************************************/
     122             : /*                              ReadTile()                              */
     123             : /************************************************************************/
     124          29 : void CTiledChannel::ReadTile(void * buffer, uint32 nCol, uint32 nRow)
     125             : {
     126          29 :     int nTileXSize = (int) mpoTileLayer->GetTileXSize();
     127          29 :     int nTileYSize = (int) mpoTileLayer->GetTileYSize();
     128             : 
     129          29 :     eChanType nDataType = GetType();
     130             : 
     131             :     // Check if we can read an sparse tile.
     132          29 :     if (mpoTileLayer->ReadSparseTile(buffer, nCol, nRow))
     133             :     {
     134             :         // Do byte swapping if needed.
     135           0 :         if( needs_swap )
     136             :         {
     137           0 :             SwapPixels( buffer, nDataType, static_cast<size_t>(nTileXSize) * nTileYSize );
     138             :         }
     139             : 
     140          25 :         return;
     141             :     }
     142             : 
     143          29 :     const char * compression = mpoTileLayer->GetCompressType();
     144             : 
     145          29 :     if (strcmp(compression, "NONE") == 0)
     146             :     {
     147          25 :         mpoTileLayer->ReadTile(buffer, nCol, nRow, mpoTileLayer->GetTileSize());
     148             : 
     149             :         // Do byte swapping if needed.
     150          25 :         if( needs_swap )
     151             :         {
     152           7 :             SwapPixels( buffer, nDataType, static_cast<size_t>(nTileXSize) * nTileYSize );
     153             :         }
     154             : 
     155          25 :         return;
     156             :     }
     157             : 
     158           4 :     uint32 nTileDataSize = mpoTileLayer->GetTileDataSize(nCol, nRow);
     159             : 
     160           4 :     PCIDSKBuffer oCompressedData(nTileDataSize);
     161           4 :     PCIDSKBuffer oUncompressedData(mpoTileLayer->GetTileSize());
     162             : 
     163           4 :     mpoTileLayer->ReadTile(oCompressedData.buffer, nCol, nRow, nTileDataSize);
     164             : 
     165           4 :     if (strcmp(compression, "RLE") == 0)
     166             :     {
     167           3 :         RLEDecompressBlock( oCompressedData, oUncompressedData );
     168             :     }
     169           1 :     else if (STARTS_WITH(compression, "JPEG"))
     170             :     {
     171           1 :         JPEGDecompressBlock( oCompressedData, oUncompressedData );
     172             :     }
     173             :     else
     174             :     {
     175           0 :         return ThrowPCIDSKException(
     176             :             "Unable to read tile of unsupported compression type: %s",
     177           0 :             compression);
     178             :     }
     179             : 
     180             : /* -------------------------------------------------------------------- */
     181             : /*      Swap if necessary.  TODO: there is some reason to doubt that    */
     182             : /*      the old implementation properly byte swapped compressed         */
     183             : /*      data.  Perhaps this should be conditional?                      */
     184             : /* -------------------------------------------------------------------- */
     185           4 :     if( needs_swap )
     186           3 :         SwapPixels( oUncompressedData.buffer, nDataType,
     187           3 :                     static_cast<size_t>(nTileXSize) * nTileYSize );
     188             : 
     189           4 :     memcpy(buffer, oUncompressedData.buffer, oUncompressedData.buffer_size);
     190             : }
     191             : 
     192             : /************************************************************************/
     193             : /*                             ReadBlock()                              */
     194             : /************************************************************************/
     195          29 : int CTiledChannel::ReadBlock( int iBlock, void *buffer,
     196             :                               int xoff, int yoff,
     197             :                               int xsize, int ysize )
     198             : {
     199          29 :     EstablishAccess();
     200             : 
     201             :     // Validate the block index.
     202          29 :     int nTileCount = (int) mpoTileLayer->GetTileCount();
     203             : 
     204          29 :     if( iBlock < 0 || iBlock >= nTileCount )
     205             :     {
     206           0 :         return ThrowPCIDSKException(0, "Requested non-existent block (%d)",
     207           0 :                               iBlock );
     208             :     }
     209             : 
     210          29 :     int nTileXSize = (int) mpoTileLayer->GetTileXSize();
     211          29 :     int nTileYSize = (int) mpoTileLayer->GetTileYSize();
     212             : 
     213             :     // Default window.
     214          29 :     if (xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1)
     215             :     {
     216          29 :         xoff = 0;
     217          29 :         yoff = 0;
     218          29 :         xsize = nTileXSize;
     219          29 :         ysize = nTileYSize;
     220             :     }
     221             : 
     222             :     // Validate the requested window.
     223          29 :     if (xoff < 0 || xoff + xsize > nTileXSize ||
     224          29 :         yoff < 0 || yoff + ysize > nTileYSize)
     225             :     {
     226           0 :         return ThrowPCIDSKException(0,
     227             :             "Invalid window in ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
     228           0 :             xoff, yoff, xsize, ysize );
     229             :     }
     230             : 
     231          29 :     uint32 nTilePerRow = mpoTileLayer->GetTilePerRow();
     232             : 
     233          29 :     if (nTilePerRow == 0)
     234           0 :         return ThrowPCIDSKException(0, "Invalid number of tiles per row.");
     235             : 
     236          29 :     uint32 nCol = iBlock % nTilePerRow;
     237          29 :     uint32 nRow = iBlock / nTilePerRow;
     238             : 
     239             :     // Check if the entire tile was requested.
     240          29 :     if (xoff == 0 && xsize == nTileXSize &&
     241          29 :         yoff == 0 && ysize == nTileYSize)
     242             :     {
     243          29 :         ReadTile(buffer, nCol, nRow);
     244             : 
     245          29 :         return 1;
     246             :     }
     247             : 
     248           0 :     eChanType nDataType = GetType();
     249           0 :     int nPixelSize = DataTypeSize(nDataType);
     250           0 :     int nPixelCount = xsize * ysize;
     251             : 
     252             :     // Check if we can read an sparse tile.
     253           0 :     if (!mpoTileLayer->IsTileValid(nCol, nRow))
     254             :     {
     255           0 :         if (xoff == 0 && xsize == nTileXSize)
     256             :         {
     257           0 :             mpoTileLayer->ReadPartialSparseTile
     258           0 :                 (buffer, nCol, nRow,
     259           0 :                  yoff * nTileXSize * nPixelSize,
     260           0 :                  nPixelCount * nPixelSize);
     261             :         }
     262             :         else
     263             :         {
     264           0 :             for (int iy = 0; iy < ysize; iy++)
     265             :             {
     266           0 :                 mpoTileLayer->ReadPartialSparseTile
     267           0 :                     ((char*) buffer + iy * xsize * nPixelSize, nCol, nRow,
     268           0 :                      ((iy + yoff) * nTileXSize + xoff) * nPixelSize,
     269           0 :                      xsize * nPixelSize);
     270             :             }
     271             :         }
     272             : 
     273             :         // Do byte swapping if needed.
     274           0 :         if( needs_swap )
     275           0 :             SwapPixels( buffer, nDataType, nPixelCount );
     276             : 
     277           0 :         return 1;
     278             :     }
     279             : 
     280           0 :     const char * compression = mpoTileLayer->GetCompressType();
     281             : 
     282             :     // Read the requested window.
     283           0 :     if (strcmp(compression, "NONE") == 0 && xoff == 0 && xsize == nTileXSize)
     284             :     {
     285           0 :         mpoTileLayer->ReadPartialTile(buffer, nCol, nRow,
     286           0 :                                       yoff * nTileXSize * nPixelSize,
     287           0 :                                       nPixelCount * nPixelSize);
     288             : 
     289             :         // Do byte swapping if needed.
     290           0 :         if( needs_swap )
     291           0 :             SwapPixels( buffer, nDataType, nPixelCount );
     292             :     }
     293             :     // Read the requested window line by line.
     294           0 :     else if (strcmp(compression, "NONE") == 0)
     295             :     {
     296           0 :         for (int iy = 0; iy < ysize; iy++)
     297             :         {
     298           0 :             mpoTileLayer->ReadPartialTile
     299           0 :                 ((char*) buffer + iy * xsize * nPixelSize, nCol, nRow,
     300           0 :                  ((iy + yoff) * nTileXSize + xoff) * nPixelSize,
     301           0 :                  xsize * nPixelSize);
     302             :         }
     303             : 
     304             :         // Do byte swapping if needed.
     305           0 :         if( needs_swap )
     306           0 :             SwapPixels( buffer, nDataType, nPixelCount );
     307             :     }
     308             :     // Read the entire tile and copy the requested window.
     309             :     else
     310             :     {
     311           0 :         PCIDSKBuffer oTileData(mpoTileLayer->GetTileSize());
     312             : 
     313           0 :         ReadTile(oTileData.buffer, nCol, nRow);
     314             : 
     315           0 :         for (int iy = 0; iy < ysize; iy++)
     316             :         {
     317           0 :             memcpy((char*) buffer + iy * xsize * nPixelSize,
     318           0 :                    oTileData.buffer + ((iy + yoff) * nTileXSize + xoff) * nPixelSize,
     319           0 :                    static_cast<size_t>(xsize) * nPixelSize);
     320             :         }
     321             :     }
     322             : 
     323           0 :     return 1;
     324             : }
     325             : 
     326             : /************************************************************************/
     327             : /*                             WriteBlock()                             */
     328             : /************************************************************************/
     329          12 : int CTiledChannel::WriteBlock( int iBlock, void *buffer )
     330             : {
     331          12 :     if( !file->GetUpdatable() )
     332           0 :         return ThrowPCIDSKException(0, "File not open for update in WriteBlock()" );
     333             : 
     334          12 :     InvalidateOverviews();
     335             : 
     336          12 :     EstablishAccess();
     337             : 
     338             :     // Validate the block index.
     339          12 :     int nTileCount = (int) mpoTileLayer->GetTileCount();
     340             : 
     341          12 :     if( iBlock < 0 || iBlock >= nTileCount )
     342             :     {
     343           0 :         return ThrowPCIDSKException(0, "Requested non-existent block (%d)",
     344           0 :                               iBlock );
     345             :     }
     346             : 
     347          12 :     int nTileXSize = GetBlockWidth();
     348          12 :     int nTileYSize = GetBlockHeight();
     349             : 
     350          12 :     eChanType nDataType = GetType();
     351          12 :     int nPixelCount = nTileXSize * nTileYSize;
     352             : 
     353          12 :     uint32 nTilePerRow = mpoTileLayer->GetTilePerRow();
     354             : 
     355          12 :     if (nTilePerRow == 0)
     356           0 :         return ThrowPCIDSKException(0, "Invalid number of tiles per row.");
     357             : 
     358          12 :     uint32 nCol = iBlock % nTilePerRow;
     359          12 :     uint32 nRow = iBlock / nTilePerRow;
     360             : 
     361             :     // Do byte swapping if needed.
     362          12 :     if( needs_swap )
     363          11 :         SwapPixels( buffer, nDataType, nPixelCount );
     364             : 
     365             :     // Check if we can write an sparse tile.
     366          12 :     if (mpoTileLayer->WriteSparseTile(buffer, nCol, nRow))
     367             :     {
     368           0 :         if( needs_swap )
     369           0 :             SwapPixels( buffer, nDataType, nPixelCount );
     370             : 
     371           0 :         return 1;
     372             :     }
     373             : 
     374          12 :     const char * compression = mpoTileLayer->GetCompressType();
     375             : 
     376             : /* -------------------------------------------------------------------- */
     377             : /*      The simplest case it an uncompressed direct and complete       */
     378             : /*      tile read into the destination buffer.                          */
     379             : /* -------------------------------------------------------------------- */
     380          12 :     if (strcmp(compression, "NONE") == 0)
     381             :     {
     382           8 :         mpoTileLayer->WriteTile(buffer, nCol, nRow);
     383             : 
     384           8 :         if( needs_swap )
     385           8 :             SwapPixels( buffer, nDataType, nPixelCount );
     386             : 
     387           8 :         return 1;
     388             :     }
     389             : 
     390             : /* -------------------------------------------------------------------- */
     391             : /*      Copy the uncompressed data into a PCIDSKBuffer, and byte        */
     392             : /*      swap if needed.                                                 */
     393             : /* -------------------------------------------------------------------- */
     394           8 :     PCIDSKBuffer oUncompressedData(mpoTileLayer->GetTileSize());
     395             : 
     396           4 :     memcpy(oUncompressedData.buffer, buffer,
     397           4 :            oUncompressedData.buffer_size);
     398             : 
     399           4 :     if( needs_swap )
     400           3 :         SwapPixels( buffer, nDataType, nPixelCount );
     401             : 
     402             : /* -------------------------------------------------------------------- */
     403             : /*      Compress the imagery.                                           */
     404             : /* -------------------------------------------------------------------- */
     405           8 :     PCIDSKBuffer oCompressedData;
     406             : 
     407           4 :     if (strcmp(compression, "NONE") == 0)
     408             :     {
     409           0 :         oCompressedData = oUncompressedData;
     410             :     }
     411           4 :     else if (strcmp(compression, "RLE") == 0)
     412             :     {
     413           3 :         RLECompressBlock( oUncompressedData, oCompressedData );
     414             :     }
     415           1 :     else if (STARTS_WITH(compression, "JPEG"))
     416             :     {
     417           1 :         JPEGCompressBlock( oUncompressedData, oCompressedData );
     418             :     }
     419             :     else
     420             :     {
     421           0 :         return ThrowPCIDSKException(0,
     422             :             "Unable to write tile of unsupported compression type: %s",
     423           0 :             compression);
     424             :     }
     425             : 
     426           4 :     mpoTileLayer->WriteTile(oCompressedData.buffer, nCol, nRow,
     427           4 :                             oCompressedData.buffer_size);
     428             : 
     429           4 :     return 1;
     430             : }
     431             : 
     432             : /************************************************************************/
     433             : /*                           GetBlockWidth()                            */
     434             : /************************************************************************/
     435          78 : int CTiledChannel::GetBlockWidth(void) const
     436             : {
     437          78 :     EstablishAccess();
     438             : 
     439          77 :     return (int) mpoTileLayer->GetTileXSize();
     440             : }
     441             : 
     442             : /************************************************************************/
     443             : /*                           GetBlockHeight()                           */
     444             : /************************************************************************/
     445          77 : int CTiledChannel::GetBlockHeight(void) const
     446             : {
     447          77 :     EstablishAccess();
     448             : 
     449          77 :     return (int) mpoTileLayer->GetTileYSize();
     450             : }
     451             : 
     452             : /************************************************************************/
     453             : /*                              GetWidth()                              */
     454             : /************************************************************************/
     455          11 : int CTiledChannel::GetWidth(void) const
     456             : {
     457          11 :     EstablishAccess();
     458             : 
     459          11 :     return (int) mpoTileLayer->GetXSize();
     460             : }
     461             : 
     462             : /************************************************************************/
     463             : /*                             GetHeight()                              */
     464             : /************************************************************************/
     465          11 : int CTiledChannel::GetHeight(void) const
     466             : {
     467          11 :     EstablishAccess();
     468             : 
     469          11 :     return (int) mpoTileLayer->GetYSize();
     470             : }
     471             : 
     472             : /************************************************************************/
     473             : /*                              GetType()                               */
     474             : /************************************************************************/
     475         172 : eChanType CTiledChannel::GetType(void) const
     476             : {
     477         172 :     eChanType nDataType = CPCIDSKChannel::GetType();
     478             : 
     479         172 :     if (nDataType != CHN_UNKNOWN)
     480         141 :         return nDataType;
     481             : 
     482          31 :     EstablishAccess();
     483             : 
     484          31 :     return GetDataTypeFromName(mpoTileLayer->GetDataType());
     485             : }
     486             : 
     487             : /************************************************************************/
     488             : /*                         RLEDecompressBlock()                         */
     489             : /************************************************************************/
     490             : 
     491           3 : void CTiledChannel::RLEDecompressBlock( PCIDSKBuffer &oCompressedData,
     492             :                                         PCIDSKBuffer &oDecompressedData )
     493             : 
     494             : 
     495             : {
     496           3 :     int    src_offset=0, dst_offset=0;
     497           3 :     uint8  *src = (uint8 *) oCompressedData.buffer;
     498           3 :     uint8  *dst = (uint8 *) oDecompressedData.buffer;
     499           3 :     int    nPixelSize = DataTypeSize(GetType());
     500             : 
     501             : /* -------------------------------------------------------------------- */
     502             : /*      Process till we are out of source data, or our destination      */
     503             : /*      buffer is full.  These conditions should be satisfied at       */
     504             : /*      the same time!                                                  */
     505             : /* -------------------------------------------------------------------- */
     506          27 :     while( src_offset + 1 + nPixelSize <= oCompressedData.buffer_size
     507          30 :            && dst_offset < oDecompressedData.buffer_size )
     508             :     {
     509             : /* -------------------------------------------------------------------- */
     510             : /*      Extract a repeat run                                            */
     511             : /* -------------------------------------------------------------------- */
     512          27 :         if( src[src_offset] > 127 )
     513             :         {
     514          15 :             int count = src[src_offset++] - 128;
     515             :             int i;
     516             : 
     517          15 :             if( dst_offset + count * nPixelSize > oDecompressedData.buffer_size)
     518             :             {
     519           0 :                 return ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." );
     520             :             }
     521             : 
     522        1563 :             while( count-- > 0 )
     523             :             {
     524        4644 :                 for( i = 0; i < nPixelSize; i++ )
     525        3096 :                     dst[dst_offset++] = src[src_offset+i];
     526             :             }
     527          15 :             src_offset += nPixelSize;
     528             :         }
     529             : 
     530             : /* -------------------------------------------------------------------- */
     531             : /*      Extract a literal run.                                          */
     532             : /* -------------------------------------------------------------------- */
     533             :         else
     534             :         {
     535          12 :             int count = src[src_offset++];
     536             : 
     537          12 :             if( dst_offset + count*nPixelSize > oDecompressedData.buffer_size
     538          12 :                 || src_offset + count*nPixelSize > oCompressedData.buffer_size)
     539             :             {
     540           0 :                 return ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." );
     541             :             }
     542             : 
     543          12 :             memcpy( dst + dst_offset, src + src_offset,
     544          12 :                     nPixelSize * count );
     545          12 :             src_offset += nPixelSize * count;
     546          12 :             dst_offset += nPixelSize * count;
     547             :         }
     548             : 
     549             :     }
     550             : 
     551             : /* -------------------------------------------------------------------- */
     552             : /*      Final validation.                                               */
     553             : /* -------------------------------------------------------------------- */
     554           3 :     if( src_offset != oCompressedData.buffer_size
     555           3 :         || dst_offset != oDecompressedData.buffer_size )
     556             :     {
     557           0 :         return ThrowPCIDSKException( "RLE compressed tile corrupt, result incomplete." );
     558             :     }
     559             : }
     560             : 
     561             : /************************************************************************/
     562             : /*                         RLECompressBlock()                           */
     563             : /*                                                                      */
     564             : /*      TODO: There does not seem to be any byte order logic in here!   */
     565             : /************************************************************************/
     566             : 
     567           3 : void CTiledChannel::RLECompressBlock( PCIDSKBuffer &oUncompressedData,
     568             :                                       PCIDSKBuffer &oCompressedData )
     569             : 
     570             : 
     571             : {
     572           3 :     int    src_bytes = oUncompressedData.buffer_size;
     573           3 :     int    nPixelSize = DataTypeSize(GetType());
     574           3 :     int    src_offset = 0, dst_offset = 0;
     575             :     int    i;
     576           3 :     uint8  *src = (uint8 *) oUncompressedData.buffer;
     577             : 
     578             : /* -------------------------------------------------------------------- */
     579             : /*      Loop till input exhausted.                                       */
     580             : /* -------------------------------------------------------------------- */
     581          30 :     while( src_offset < src_bytes )
     582             :     {
     583          27 :         bool    bGotARun = false;
     584             : 
     585             : /* -------------------------------------------------------------------- */
     586             : /*      Establish the run length, and emit if greater than 3.           */
     587             : /* -------------------------------------------------------------------- */
     588          27 :         if( src_offset + 3*nPixelSize < src_bytes )
     589             :         {
     590          27 :             int         count = 1;
     591             : 
     592        1533 :             while( count < 127
     593        1560 :                    && src_offset + count*nPixelSize < src_bytes )
     594             :             {
     595        1548 :                 bool    bWordMatch = true;
     596             : 
     597        4644 :                 for( i = 0; i < nPixelSize; i++ )
     598             :                 {
     599        3096 :                     if( src[src_offset+i]
     600        3096 :                         != src[src_offset+i+count*nPixelSize] )
     601          24 :                         bWordMatch = false;
     602             :                 }
     603             : 
     604        1548 :                 if( !bWordMatch )
     605          15 :                     break;
     606             : 
     607        1533 :                 count++;
     608             :             }
     609             : 
     610          27 :             if( count >= 3 )
     611             :             {
     612          15 :                 if( oCompressedData.buffer_size < dst_offset + nPixelSize+1 )
     613           3 :                     oCompressedData.SetSize( oCompressedData.buffer_size*2+100);
     614             : 
     615          15 :                 oCompressedData.buffer[dst_offset++] = (char) (count+128);
     616             : 
     617          45 :                 for( i = 0; i < nPixelSize; i++ )
     618          30 :                     oCompressedData.buffer[dst_offset++] = src[src_offset+i];
     619             : 
     620          15 :                 src_offset += count * nPixelSize;
     621             : 
     622          15 :                 bGotARun = true;
     623             :             }
     624             :             else
     625          12 :                 bGotARun = false;
     626             :         }
     627             : 
     628             : /* -------------------------------------------------------------------- */
     629             : /*      Otherwise emit a literal till we encounter at least a three     */
     630             : /*      word series.                                                    */
     631             : /* -------------------------------------------------------------------- */
     632          27 :         if( !bGotARun )
     633             :         {
     634          12 :             int         count = 1;
     635          12 :             int         match_count = 0;
     636             : 
     637        1512 :             while( count < 127
     638        1524 :                    && src_offset + count*nPixelSize < src_bytes )
     639             :             {
     640        1512 :                 bool    bWordMatch = true;
     641             : 
     642        4536 :                 for( i = 0; i < nPixelSize; i++ )
     643             :                 {
     644        3024 :                     if( src[src_offset+i]
     645        3024 :                         != src[src_offset+i+count*nPixelSize] )
     646        2172 :                         bWordMatch = false;
     647             :                 }
     648             : 
     649        1512 :                 if( bWordMatch )
     650           0 :                     match_count++;
     651             :                 else
     652        1512 :                     match_count = 0;
     653             : 
     654        1512 :                 if( match_count > 2 )
     655           0 :                     break;
     656             : 
     657        1512 :                 count++;
     658             :             }
     659             : 
     660          12 :             assert( src_offset + count*nPixelSize <= src_bytes );
     661             : 
     662           9 :             while( oCompressedData.buffer_size
     663          21 :                    < dst_offset + count*nPixelSize+1 )
     664           9 :                 oCompressedData.SetSize( oCompressedData.buffer_size*2+100 );
     665             : 
     666          12 :             oCompressedData.buffer[dst_offset++] = (char) count;
     667          12 :             memcpy( oCompressedData.buffer + dst_offset,
     668          12 :                     src + src_offset,
     669          12 :                     cpl::fits_on<int>(count * nPixelSize) );
     670          12 :             src_offset += count * nPixelSize;
     671          12 :             dst_offset += count * nPixelSize;
     672             :         }
     673             :     }
     674             : 
     675           3 :     oCompressedData.buffer_size = dst_offset;
     676           3 : }
     677             : 
     678             : /************************************************************************/
     679             : /*                        JPEGDecompressBlock()                         */
     680             : /************************************************************************/
     681             : 
     682           1 : void CTiledChannel::JPEGDecompressBlock( PCIDSKBuffer &oCompressedData,
     683             :                                          PCIDSKBuffer &oDecompressedData )
     684             : 
     685             : 
     686             : {
     687           1 :     if( file->GetInterfaces()->JPEGDecompressBlock == nullptr )
     688           0 :         return ThrowPCIDSKException( "JPEG decompression not enabled in the PCIDSKInterfaces of this build." );
     689             : 
     690           1 :     file->GetInterfaces()->JPEGDecompressBlock(
     691           1 :         (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size,
     692           1 :         (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size,
     693             :         GetBlockWidth(), GetBlockHeight(), GetType() );
     694             : }
     695             : 
     696             : /************************************************************************/
     697             : /*                         JPEGCompressBlock()                          */
     698             : /************************************************************************/
     699             : 
     700           1 : void CTiledChannel::JPEGCompressBlock( PCIDSKBuffer &oDecompressedData,
     701             :                                        PCIDSKBuffer &oCompressedData )
     702             : 
     703             : 
     704             : 
     705             : {
     706           1 :     if( file->GetInterfaces()->JPEGCompressBlock == nullptr )
     707           0 :         return ThrowPCIDSKException( "JPEG compression not enabled in the PCIDSKInterfaces of this build." );
     708             : 
     709             : /* -------------------------------------------------------------------- */
     710             : /*      What quality should we be using?                                */
     711             : /* -------------------------------------------------------------------- */
     712           1 :     int quality = 75;
     713             : 
     714           1 :     const char * compression = mpoTileLayer->GetCompressType();
     715             : 
     716           1 :     if (strlen(compression) > 4 && isdigit(static_cast<unsigned char>(compression[4])))
     717           0 :         quality = atoi(compression + 4);
     718             : 
     719             : /* -------------------------------------------------------------------- */
     720             : /*      Make the output buffer plenty big to hold any conceivable        */
     721             : /*      result.                                                         */
     722             : /* -------------------------------------------------------------------- */
     723           1 :     oCompressedData.SetSize( oDecompressedData.buffer_size * 2 + 1000 );
     724             : 
     725             : /* -------------------------------------------------------------------- */
     726             : /*      invoke.                                                         */
     727             : /* -------------------------------------------------------------------- */
     728           1 :     file->GetInterfaces()->JPEGCompressBlock(
     729           1 :         (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size,
     730           1 :         (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size,
     731             :         GetBlockWidth(), GetBlockHeight(), GetType(), quality );
     732             : }
     733             : 
     734             : } // namespace PCIDSK;

Generated by: LCOV version 1.14