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

Generated by: LCOV version 1.14