LCOV - code coverage report
Current view: directory - frmts/epsilon - epsilondataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 423 328 77.5 %
Date: 2012-12-26 Functions: 19 13 68.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: epsilondataset.cpp 22363 2011-05-12 18:26:19Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL Epsilon driver
       5                 :  * Purpose:  Implement GDAL Epsilon support using Epsilon library
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  **********************************************************************
       9                 :  * Copyright (c) 2009, Even Rouault, <even dot rouault at mines dash paris dot org>
      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 "epsilon.h"
      31                 : #include "gdal_pam.h"
      32                 : 
      33                 : CPL_CVSID("$Id: epsilondataset.cpp 22363 2011-05-12 18:26:19Z rouault $");
      34                 : 
      35                 : #define RASTERLITE_WAVELET_HEADER "StartWaveletsImage$$"
      36                 : #define RASTERLITE_WAVELET_FOOTER "$$EndWaveletsImage"
      37                 : 
      38                 : #define BLOCK_DATA_MAX_SIZE MAX(EPS_MAX_GRAYSCALE_BUF, EPS_MAX_TRUECOLOR_BUF)
      39                 : 
      40                 : class EpsilonRasterBand;
      41                 : 
      42                 : typedef struct
      43                 : {
      44                 :     int x;
      45                 :     int y;
      46                 :     int w;
      47                 :     int h;
      48                 :     vsi_l_offset offset;
      49                 : } BlockDesc;
      50                 : 
      51                 : #ifdef I_WANT_COMPATIBILITY_WITH_EPSILON_0_8_1
      52                 : #define GET_FIELD(hdr, field) \
      53                 :     (hdr.block_type == EPS_GRAYSCALE_BLOCK) ? hdr.gs.field : hdr.tc.field
      54                 : #else
      55                 : #define GET_FIELD(hdr, field) \
      56                 :     (hdr.block_type == EPS_GRAYSCALE_BLOCK) ? hdr.hdr_data.gs.field : hdr.hdr_data.tc.field
      57                 : #endif
      58                 : 
      59                 : /************************************************************************/
      60                 : /* ==================================================================== */
      61                 : /*                              EpsilonDataset                          */
      62                 : /* ==================================================================== */
      63                 : /************************************************************************/
      64                 : 
      65                 : class EpsilonDataset : public GDALPamDataset
      66                 : {
      67                 :     friend class EpsilonRasterBand;
      68                 : 
      69                 :     VSILFILE*    fp;
      70                 :     vsi_l_offset nFileOff;
      71                 :     
      72                 :     GByte*   pabyFileBuf;
      73                 :     int      nFileBufMaxSize;
      74                 :     int      nFileBufCurSize;
      75                 :     int      nFileBufOffset;
      76                 :     int      bEOF;
      77                 :     int      bError;
      78                 :     
      79                 :     GByte*   pabyBlockData;
      80                 :     int      nBlockDataSize;
      81                 :     vsi_l_offset nStartBlockFileOff;
      82                 :     
      83                 :     int      bRegularTiling;
      84                 :     
      85                 :     int        nBlocks;
      86                 :     BlockDesc* pasBlocks;
      87                 :     
      88                 :     int      nBufferedBlock;
      89                 :     GByte*   pabyRGBData;
      90                 :     
      91                 :     void     Seek(vsi_l_offset nPos);
      92                 :     int      GetNextByte();
      93                 :     int      GetNextBlockData();
      94                 :     int      ScanBlocks(int *pnBands);
      95                 : 
      96                 :   public:
      97                 :                  EpsilonDataset();
      98                 :     virtual     ~EpsilonDataset();
      99                 :     
     100                 :     static GDALDataset *Open( GDALOpenInfo * );
     101                 :     static int          Identify( GDALOpenInfo * );
     102                 : };
     103                 : 
     104                 : /************************************************************************/
     105                 : /* ==================================================================== */
     106                 : /*                            EpsilonRasterBand                         */
     107                 : /* ==================================================================== */
     108                 : /************************************************************************/
     109                 : 
     110                 : class EpsilonRasterBand : public GDALPamRasterBand
     111              20 : {
     112                 :   public:
     113                 :                             EpsilonRasterBand(EpsilonDataset* poDS, int nBand);
     114                 :                  
     115                 :     virtual CPLErr          IReadBlock( int, int, void * );
     116                 :     virtual GDALColorInterp GetColorInterpretation();
     117                 : };
     118                 : 
     119                 : /************************************************************************/
     120                 : /*                         EpsilonDataset()                             */
     121                 : /************************************************************************/
     122                 : 
     123              10 : EpsilonDataset::EpsilonDataset()
     124                 : {
     125              10 :     fp = NULL;
     126              10 :     nFileOff = 0;
     127                 :     
     128              10 :     pabyFileBuf = NULL;
     129              10 :     nFileBufMaxSize = 0;
     130              10 :     nFileBufCurSize = 0;
     131              10 :     nFileBufOffset = 0;
     132              10 :     bEOF = FALSE;
     133              10 :     bError = FALSE;
     134                 :     
     135              10 :     pabyBlockData = NULL;
     136              10 :     nBlockDataSize = 0;
     137              10 :     nStartBlockFileOff = 0;
     138                 :     
     139              10 :     bRegularTiling = FALSE;
     140                 :     
     141              10 :     nBlocks = 0;
     142              10 :     pasBlocks = NULL;
     143                 :     
     144              10 :     nBufferedBlock = -1;
     145              10 :     pabyRGBData = NULL;
     146              10 : }
     147                 : 
     148                 : /************************************************************************/
     149                 : /*                         ~EpsilonDataset()                            */
     150                 : /************************************************************************/
     151                 : 
     152              10 : EpsilonDataset::~EpsilonDataset()
     153                 : {
     154              10 :     if (fp)
     155              10 :         VSIFCloseL(fp);
     156              10 :     VSIFree(pabyFileBuf);
     157              10 :     VSIFree(pasBlocks);
     158              10 :     CPLFree(pabyRGBData);
     159              10 : }
     160                 : 
     161                 : /************************************************************************/
     162                 : /*                       EpsilonRasterBand()                            */
     163                 : /************************************************************************/
     164                 : 
     165              20 : EpsilonRasterBand::EpsilonRasterBand(EpsilonDataset* poDS, int nBand)
     166                 : {
     167              20 :     this->poDS = poDS;
     168              20 :     this->nBand = nBand;
     169              20 :     this->eDataType = GDT_Byte;
     170              20 :     this->nBlockXSize = poDS->pasBlocks[0].w;
     171              20 :     this->nBlockYSize = poDS->pasBlocks[0].h;
     172              20 : }
     173                 : 
     174                 : /************************************************************************/
     175                 : /*                   GetColorInterpretation()                           */
     176                 : /************************************************************************/
     177                 : 
     178               0 : GDALColorInterp EpsilonRasterBand::GetColorInterpretation()
     179                 : {
     180               0 :     EpsilonDataset* poGDS = (EpsilonDataset*) poDS;
     181               0 :     if (poGDS->nBands == 1)
     182                 :     {
     183               0 :         return GCI_GrayIndex;
     184                 :     }
     185                 :     else
     186                 :     {
     187               0 :         if (nBand == 1)
     188               0 :             return GCI_RedBand;
     189               0 :         else if (nBand == 2)
     190               0 :             return GCI_GreenBand;
     191                 :         else
     192               0 :             return GCI_BlueBand;
     193                 :     }
     194                 : }
     195                 : 
     196                 : /************************************************************************/
     197                 : /*                           IReadBlock()                               */
     198                 : /************************************************************************/
     199                 : 
     200               4 : CPLErr EpsilonRasterBand::IReadBlock( int nBlockXOff,
     201                 :                                       int nBlockYOff, void * pImage)
     202                 : {
     203               4 :     EpsilonDataset* poGDS = (EpsilonDataset*) poDS;
     204                 :     
     205                 :     //CPLDebug("EPSILON", "IReadBlock(nBand=%d,nBlockXOff=%d,nBlockYOff=%d)",
     206                 :     //         nBand, nBlockXOff, nBlockYOff);
     207                 : 
     208               4 :     int nBlocksPerRow = (poGDS->nRasterXSize + nBlockXSize - 1) / nBlockXSize;
     209               4 :     int nBlock = nBlockXOff + nBlockYOff * nBlocksPerRow;
     210                 :     
     211               4 :     BlockDesc* psDesc = &poGDS->pasBlocks[nBlock];
     212                 : #ifdef DEBUG
     213               4 :     int nBlocksPerColumn = (poGDS->nRasterYSize + nBlockYSize - 1) / nBlockYSize;
     214               4 :     CPLAssert(psDesc->x == nBlockXOff * nBlockXSize);
     215               4 :     CPLAssert(psDesc->y == nBlockYOff * nBlockYSize);
     216                 :     CPLAssert(psDesc->w == (nBlockXOff < nBlocksPerRow - 1) ?
     217               4 :                                 nBlockXSize : poGDS->nRasterXSize - psDesc->x);
     218                 :     CPLAssert(psDesc->h == (nBlockYOff < nBlocksPerColumn - 1) ?
     219               4 :                                 nBlockYSize : poGDS->nRasterYSize - psDesc->y);
     220                 : #endif
     221                 : 
     222               4 :     poGDS->Seek(psDesc->offset);
     223                 :         
     224               4 :     if (!poGDS->GetNextBlockData())
     225                 :     {
     226               0 :         memset(pImage, 0, nBlockXSize * nBlockYSize);
     227               0 :         return CE_Failure;
     228                 :     }
     229                 :     
     230                 :     eps_block_header hdr;
     231               4 :     if (eps_read_block_header (poGDS->pabyBlockData,
     232                 :                                poGDS->nBlockDataSize, &hdr) != EPS_OK)
     233                 :     {
     234               0 :         CPLError(CE_Warning, CPLE_AppDefined, "cannot read block header");
     235               0 :         memset(pImage, 0, nBlockXSize * nBlockYSize);
     236               0 :         return CE_Failure;
     237                 :     }
     238                 : 
     239               4 :     if (hdr.chk_flag == EPS_BAD_CRC ||
     240                 :         hdr.crc_flag == EPS_BAD_CRC)
     241                 :     {
     242               0 :         CPLError(CE_Warning, CPLE_AppDefined, "bad CRC");
     243               0 :         memset(pImage, 0, nBlockXSize * nBlockYSize);
     244               0 :         return CE_Failure;
     245                 :     }
     246                 :     
     247               4 :     int w = GET_FIELD(hdr, w);
     248               4 :     int h = GET_FIELD(hdr, h);
     249                 :     int i;
     250                 : 
     251               4 :     if (poGDS->nBands == 1)
     252                 :     {
     253                 :         unsigned char ** pTempData =
     254               2 :             (unsigned char **) CPLMalloc(h * sizeof(unsigned char*));        
     255              42 :         for(i=0;i<h;i++)
     256              40 :             pTempData[i] = ((GByte*)pImage) + i * nBlockXSize;
     257                 : 
     258               2 :         if (w != nBlockXSize || h != nBlockYSize)
     259               0 :             memset(pImage, 0, nBlockXSize * nBlockYSize);
     260                 : 
     261               2 :         if (eps_decode_grayscale_block (pTempData,
     262                 :                                         poGDS->pabyBlockData, &hdr) != EPS_OK)
     263                 :         {
     264               0 :             CPLFree(pTempData);
     265               0 :             memset(pImage, 0, nBlockXSize * nBlockYSize);
     266               0 :             return CE_Failure;
     267                 :         }
     268               2 :         CPLFree(pTempData);
     269                 :     }
     270                 :     else
     271                 :     {
     272               2 :         if (poGDS->pabyRGBData == NULL)
     273                 :         {
     274                 :             poGDS->pabyRGBData =
     275               2 :                             (GByte*) VSIMalloc3(nBlockXSize, nBlockYSize, 3);
     276               2 :             if (poGDS->pabyRGBData == NULL)
     277                 :             {
     278               0 :                 memset(pImage, 0, nBlockXSize * nBlockYSize);
     279               0 :                 return CE_Failure;
     280                 :             }
     281                 :         }
     282                 :             
     283               2 :         if (poGDS->nBufferedBlock == nBlock)
     284                 :         {
     285                 :             memcpy(pImage,
     286                 :                    poGDS->pabyRGBData + (nBand - 1) * nBlockXSize * nBlockYSize,
     287               0 :                    nBlockXSize * nBlockYSize);
     288               0 :             return CE_None;
     289                 :         }
     290                 :     
     291                 :         unsigned char ** pTempData[3];
     292                 :         int iBand;
     293               8 :         for(iBand=0;iBand<3;iBand++)
     294                 :         {
     295               6 :             pTempData[iBand] =
     296               6 :                 (unsigned char **) CPLMalloc(h * sizeof(unsigned char*));
     297             306 :             for(i=0;i<h;i++)
     298             300 :                 pTempData[iBand][i] = poGDS->pabyRGBData +
     299             300 :                     iBand * nBlockXSize * nBlockYSize + i * nBlockXSize;
     300                 :         }
     301                 :     
     302               2 :         if (w != nBlockXSize || h != nBlockYSize)
     303               0 :             memset(poGDS->pabyRGBData, 0, 3 * nBlockXSize * nBlockYSize);
     304                 :             
     305               2 :         if (eps_decode_truecolor_block (pTempData[0], pTempData[1], pTempData[2],
     306                 :                                         poGDS->pabyBlockData, &hdr) != EPS_OK)
     307                 :         {
     308               0 :             for(iBand=0;iBand<poGDS->nBands;iBand++)
     309               0 :                 CPLFree(pTempData[iBand]);
     310               0 :             memset(pImage, 0, nBlockXSize * nBlockYSize);
     311               0 :             return CE_Failure;
     312                 :         }
     313                 :         
     314               8 :         for(iBand=0;iBand<poGDS->nBands;iBand++)
     315               6 :             CPLFree(pTempData[iBand]);
     316                 :             
     317               2 :         poGDS->nBufferedBlock = nBlock;
     318                 :         memcpy(pImage,
     319                 :                poGDS->pabyRGBData + (nBand - 1) * nBlockXSize * nBlockYSize,
     320               2 :                nBlockXSize * nBlockYSize);
     321                 :                    
     322               2 :         if (nBand == 1)
     323                 :         {
     324                 :             int iOtherBand;
     325               6 :             for(iOtherBand=2;iOtherBand<=poGDS->nBands;iOtherBand++)
     326                 :             {
     327                 :                 GDALRasterBlock *poBlock;
     328                 : 
     329                 :                 poBlock = poGDS->GetRasterBand(iOtherBand)->
     330               4 :                     GetLockedBlockRef(nBlockXOff,nBlockYOff, TRUE);
     331               4 :                 if (poBlock == NULL)
     332               0 :                     break;
     333                 :                     
     334               4 :                 GByte* pabySrcBlock = (GByte *) poBlock->GetDataRef();
     335               4 :                 if( pabySrcBlock == NULL )
     336                 :                 {
     337               0 :                     poBlock->DropLock();
     338               0 :                     break;
     339                 :                 }
     340                 : 
     341                 :                 memcpy(pabySrcBlock,
     342                 :                        poGDS->pabyRGBData + (iOtherBand - 1) * nBlockXSize * nBlockYSize,
     343               4 :                        nBlockXSize * nBlockYSize);
     344                 : 
     345               4 :                 poBlock->DropLock();
     346                 :             }
     347                 :         }
     348                 :     }
     349                 :     
     350               4 :     return CE_None;
     351                 : }
     352                 : 
     353                 : /************************************************************************/
     354                 : /*                              Seek()                                  */
     355                 : /************************************************************************/
     356                 : 
     357              34 : void EpsilonDataset::Seek(vsi_l_offset nPos)
     358                 : {
     359              34 :     bEOF = FALSE;
     360              34 :     VSIFSeekL(fp, nPos, SEEK_SET);
     361              34 :     nFileBufOffset = 0;
     362              34 :     nFileBufCurSize = 0;
     363              34 :     nFileOff = nPos;
     364              34 : }
     365                 : 
     366                 : /************************************************************************/
     367                 : /*                          GetNextByte()                               */
     368                 : /************************************************************************/
     369                 : 
     370                 : #define BUFFER_CHUNK    16384
     371                 : 
     372            4333 : int EpsilonDataset::GetNextByte()
     373                 : {
     374            4333 :     if (nFileBufOffset < nFileBufCurSize)
     375                 :     {
     376            4299 :         nFileOff ++;
     377            4299 :         return pabyFileBuf[nFileBufOffset ++];
     378                 :     }
     379                 :         
     380              34 :     if (bError || bEOF)
     381               0 :         return -1;
     382                 : 
     383              34 :     if (nFileBufCurSize + BUFFER_CHUNK > nFileBufMaxSize)
     384                 :     {
     385                 :         GByte* pabyFileBufNew =
     386              10 :             (GByte*)VSIRealloc(pabyFileBuf, nFileBufCurSize + BUFFER_CHUNK);
     387              10 :         if (pabyFileBufNew == NULL)
     388                 :         {
     389               0 :             bError = TRUE;
     390               0 :             return -1;
     391                 :         }
     392              10 :         pabyFileBuf = pabyFileBufNew;
     393              10 :         nFileBufMaxSize = nFileBufCurSize + BUFFER_CHUNK;
     394                 :     }
     395                 :     int nBytesRead =
     396              34 :         (int)VSIFReadL(pabyFileBuf + nFileBufCurSize, 1, BUFFER_CHUNK, fp);
     397              34 :     nFileBufCurSize += nBytesRead;
     398              34 :     if (nBytesRead < BUFFER_CHUNK)
     399              34 :         bEOF = TRUE;
     400              34 :     if (nBytesRead == 0)
     401               0 :         return -1;
     402                 :     
     403              34 :     nFileOff ++;
     404              34 :     return pabyFileBuf[nFileBufOffset ++];
     405                 : }
     406                 : 
     407                 : /************************************************************************/
     408                 : /*                     GetNextBlockData()                               */
     409                 : /************************************************************************/
     410                 : 
     411                 : #define MAX_SIZE_BEFORE_BLOCK_MARKER        100
     412                 : 
     413              34 : int EpsilonDataset::GetNextBlockData()
     414                 : {
     415              34 :     int nStartBlockBufOffset = 0;
     416              34 :     pabyBlockData = NULL;
     417              34 :     nBlockDataSize = 0;
     418                 :     
     419              88 :     while (nFileBufOffset < MAX_SIZE_BEFORE_BLOCK_MARKER)
     420                 :     {
     421              54 :         int chNextByte = GetNextByte();
     422              54 :         if (chNextByte < 0)
     423               0 :             return FALSE;
     424                 :         
     425              54 :         if (chNextByte != EPS_MARKER)
     426                 :         {
     427              34 :             nStartBlockFileOff = nFileOff - 1;
     428              34 :             nStartBlockBufOffset = nFileBufOffset - 1;
     429              34 :             nBlockDataSize = 1;
     430              34 :             break;
     431                 :         }
     432                 :     }
     433              34 :     if (nFileBufOffset == MAX_SIZE_BEFORE_BLOCK_MARKER)
     434               0 :         return FALSE;
     435                 :         
     436            4313 :     while (nFileBufOffset < BLOCK_DATA_MAX_SIZE)
     437                 :     {
     438            4279 :         int chNextByte = GetNextByte();
     439            4279 :         if (chNextByte < 0)
     440               0 :             break;
     441                 : 
     442            4279 :         if (chNextByte == EPS_MARKER)
     443                 :         {
     444              34 :             pabyBlockData = pabyFileBuf + nStartBlockBufOffset;
     445              34 :             return TRUE;
     446                 :         }
     447                 :             
     448            4245 :         nBlockDataSize ++;
     449                 :     }
     450                 :     
     451               0 :     pabyBlockData = pabyFileBuf + nStartBlockBufOffset;
     452               0 :     return TRUE;
     453                 : }
     454                 : 
     455                 : /************************************************************************/
     456                 : /*                           ScanBlocks()                               */
     457                 : /************************************************************************/
     458                 : 
     459              10 : int EpsilonDataset::ScanBlocks(int* pnBands)
     460                 : {
     461              10 :     int bRet = FALSE;
     462                 : 
     463              10 :     int nExpectedX = 0;
     464              10 :     int nExpectedY = 0;
     465                 : 
     466              10 :     int nTileW = -1;
     467              10 :     int nTileH = -1;
     468                 :     
     469              10 :     *pnBands = 0;
     470                 : 
     471              10 :     bRegularTiling = TRUE;
     472                 :     
     473                 :     eps_block_header hdr;
     474              20 :     while(TRUE)
     475                 :     {
     476              30 :         Seek(nStartBlockFileOff + nBlockDataSize);
     477                 :         
     478              30 :         if (!GetNextBlockData())
     479                 :         {
     480               0 :             break;
     481                 :         }
     482                 :         
     483                 :         /* Ignore rasterlite wavelet header */
     484              30 :         int nRasterliteWaveletHeaderLen = strlen(RASTERLITE_WAVELET_HEADER);
     485              30 :         if (nBlockDataSize >= nRasterliteWaveletHeaderLen &&
     486                 :             memcmp(pabyBlockData, RASTERLITE_WAVELET_HEADER,
     487                 :                    nRasterliteWaveletHeaderLen) == 0)
     488                 :         {
     489              10 :             continue;
     490                 :         }
     491                 :         
     492                 :         /* Stop at rasterlite wavelet footer */
     493              20 :         int nRasterlineWaveletFooterLen = strlen(RASTERLITE_WAVELET_FOOTER);
     494              20 :         if (nBlockDataSize >= nRasterlineWaveletFooterLen &&
     495                 :             memcmp(pabyBlockData, RASTERLITE_WAVELET_FOOTER,
     496                 :                    nRasterlineWaveletFooterLen) == 0)
     497                 :         {
     498              10 :             break;
     499                 :         }
     500                 :         
     501              10 :         if (eps_read_block_header (pabyBlockData,
     502                 :                                    nBlockDataSize, &hdr) != EPS_OK)
     503                 :         {
     504               0 :             CPLError(CE_Warning, CPLE_AppDefined, "cannot read block header");
     505               0 :             continue;
     506                 :         }
     507                 : 
     508              10 :         if (hdr.chk_flag == EPS_BAD_CRC ||
     509                 :             hdr.crc_flag == EPS_BAD_CRC)
     510                 :         {
     511               0 :             CPLError(CE_Warning, CPLE_AppDefined, "bad CRC");
     512               0 :             continue;
     513                 :         }
     514                 :         
     515              10 :         int W = GET_FIELD(hdr, W);
     516              10 :         int H = GET_FIELD(hdr, H);
     517              10 :         int x = GET_FIELD(hdr, x);
     518              10 :         int y = GET_FIELD(hdr, y);
     519              10 :         int w = GET_FIELD(hdr, w);
     520              10 :         int h = GET_FIELD(hdr, h);
     521                 : 
     522                 :         //CPLDebug("EPSILON", "W=%d,H=%d,x=%d,y=%d,w=%d,h=%d,offset=" CPL_FRMT_GUIB,
     523                 :         //                    W, H, x, y, w, h, nStartBlockFileOff);
     524                 :         
     525              10 :         int nNewBands = (hdr.block_type == EPS_GRAYSCALE_BLOCK) ? 1 : 3;
     526              10 :         if (nRasterXSize == 0)
     527                 :         {
     528              10 :             if (W <= 0 || H <= 0)
     529                 :             {
     530               0 :                 break;
     531                 :             }
     532                 :             
     533              10 :             bRet = TRUE;
     534              10 :             nRasterXSize = W;
     535              10 :             nRasterYSize = H;
     536              10 :             *pnBands = nNewBands;
     537                 :         }
     538                 :         
     539              10 :         if (nRasterXSize != W || nRasterYSize != H || *pnBands != nNewBands ||
     540                 :             x < 0 || y < 0 || x + w > W || y + h > H)
     541                 :         {
     542               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Bad block characteristics");
     543               0 :             bRet = FALSE;
     544               0 :             break;
     545                 :         }
     546                 :         
     547              10 :         nBlocks++;
     548              10 :         pasBlocks = (BlockDesc*)VSIRealloc(pasBlocks, sizeof(BlockDesc) * nBlocks);
     549              10 :         pasBlocks[nBlocks-1].x = x;
     550              10 :         pasBlocks[nBlocks-1].y = y;
     551              10 :         pasBlocks[nBlocks-1].w = w;
     552              10 :         pasBlocks[nBlocks-1].h = h;
     553              10 :         pasBlocks[nBlocks-1].offset = nStartBlockFileOff;
     554                 :         
     555              10 :         if (bRegularTiling)
     556                 :         {
     557              10 :             if (nTileW < 0)
     558                 :             {
     559              10 :                 nTileW = w;
     560              10 :                 nTileH = h;
     561                 :             }
     562                 :             
     563              10 :             if (w > nTileW || h > nTileH)
     564               0 :                 bRegularTiling = FALSE;
     565                 :             
     566              10 :             if (x != nExpectedX)
     567               0 :                 bRegularTiling = FALSE;
     568                 : 
     569              10 :             if (y != nExpectedY || nTileH != h)
     570                 :             {
     571               0 :                 if (y + h != H)
     572               0 :                     bRegularTiling = FALSE;
     573                 :             }
     574                 :             
     575              10 :             if (nTileW != w)
     576                 :             {
     577               0 :                 if (x + w != W)
     578               0 :                     bRegularTiling = FALSE;
     579                 :                 else
     580                 :                 {
     581               0 :                     nExpectedX = 0;
     582               0 :                     nExpectedY += nTileW;
     583                 :                 }
     584                 :             }
     585                 :             else
     586              10 :                 nExpectedX += nTileW;
     587                 :             
     588                 :             //if (!bRegularTiling)
     589                 :             //    CPLDebug("EPSILON", "not regular tiling!");
     590                 :         }
     591                 :     } 
     592                 : 
     593              10 :     return bRet;
     594                 : }
     595                 : 
     596                 : /************************************************************************/
     597                 : /*                             Identify()                               */
     598                 : /************************************************************************/
     599                 : 
     600           11746 : int EpsilonDataset::Identify(GDALOpenInfo* poOpenInfo)
     601                 : {
     602           11746 :     int nRasterliteWaveletHeaderLen = strlen(RASTERLITE_WAVELET_HEADER);
     603           11746 :     if (poOpenInfo->nHeaderBytes > nRasterliteWaveletHeaderLen + 1 &&
     604                 :           EQUALN((const char*)poOpenInfo->pabyHeader,
     605                 :                  RASTERLITE_WAVELET_HEADER, nRasterliteWaveletHeaderLen))
     606                 :     {
     607              10 :         return TRUE;
     608                 :     }
     609                 :     
     610           11736 :     if (poOpenInfo->nHeaderBytes > EPS_MIN_GRAYSCALE_BUF &&
     611                 :         (EQUALN((const char*)poOpenInfo->pabyHeader, "type=gs", 7) ||
     612                 :          EQUALN((const char*)poOpenInfo->pabyHeader, "type=tc", 7)))
     613                 :     {
     614               0 :         return TRUE;
     615                 :     }
     616                 :     
     617           11736 :     return FALSE;
     618                 : }
     619                 : 
     620                 : /************************************************************************/
     621                 : /*                                Open()                                */
     622                 : /************************************************************************/
     623                 : 
     624            1656 : GDALDataset* EpsilonDataset::Open(GDALOpenInfo* poOpenInfo)
     625                 : {
     626            1656 :     if (!Identify(poOpenInfo))
     627            1646 :         return NULL;
     628                 : 
     629              10 :     if( poOpenInfo->eAccess == GA_Update )
     630                 :     {
     631                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     632                 :                   "The EPSILON driver does not support update access to existing"
     633               0 :                   " files.\n" );
     634               0 :         return NULL;
     635                 :     }
     636                 : 
     637              10 :     VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
     638              10 :     if (fp == NULL)
     639               0 :         return NULL;
     640                 :     
     641              10 :     EpsilonDataset* poDS = new EpsilonDataset();
     642              10 :     poDS->fp = fp;
     643                 :     
     644              10 :     poDS->nRasterXSize = 0;
     645              10 :     poDS->nRasterYSize = 0;
     646                 :     
     647              10 :     int nBandsToAdd = 0;
     648              10 :     if (!poDS->ScanBlocks(&nBandsToAdd))
     649                 :     {
     650               0 :         delete poDS;
     651               0 :         return NULL;
     652                 :     }
     653                 :     
     654              10 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     655                 :         !GDALCheckBandCount(nBandsToAdd, FALSE))
     656                 :     {
     657               0 :         delete poDS;
     658               0 :         return NULL;
     659                 :     }
     660              10 :     if (!poDS->bRegularTiling)
     661                 :     {
     662                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     663                 :                   "The EPSILON driver does not support reading "
     664               0 :                   "not regularly blocked files.\n" );
     665               0 :         delete poDS;
     666               0 :         return NULL;
     667                 :     }
     668                 :     
     669                 :     int i;
     670              60 :     for(i=1;i<=nBandsToAdd;i++)
     671              20 :         poDS->SetBand(i, new EpsilonRasterBand(poDS, i));
     672                 :         
     673              10 :     if (nBandsToAdd > 1)
     674               5 :         poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
     675                 :     
     676              10 :     return poDS;
     677                 : }
     678                 : 
     679                 : 
     680                 : /************************************************************************/
     681                 : /*                  EpsilonDatasetCreateCopy ()                         */
     682                 : /************************************************************************/
     683                 : 
     684                 : GDALDataset *
     685              20 : EpsilonDatasetCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     686                 :                        int bStrict, char ** papszOptions, 
     687                 :                        GDALProgressFunc pfnProgress, void * pProgressData )
     688                 : {
     689              20 :     int nBands = poSrcDS->GetRasterCount();
     690              36 :     if ((nBands != 1 && nBands != 3) ||
     691              16 :         (nBands > 0 && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL))
     692                 :     {
     693                 :         CPLError(CE_Failure, CPLE_NotSupported,
     694                 :                  "The EPSILON driver only supports 1 band (grayscale) "
     695               4 :                  "or 3 band (RGB) data");
     696               4 :         return NULL;
     697                 :     }
     698                 :     
     699                 : /* -------------------------------------------------------------------- */
     700                 : /*      Fetch and check creation options                                */
     701                 : /* -------------------------------------------------------------------- */
     702                 : 
     703                 :     int nBlockXSize =
     704              16 :         atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "256"));
     705                 :     int nBlockYSize =
     706              16 :         atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "256"));
     707              16 :     if ((nBlockXSize != 32 && nBlockXSize != 64 && nBlockXSize != 128 &&
     708                 :          nBlockXSize != 256 && nBlockXSize != 512 && nBlockXSize != 1024) ||
     709                 :         (nBlockYSize != 32 && nBlockYSize != 64 && nBlockYSize != 128 &&
     710                 :          nBlockYSize != 256 && nBlockYSize != 512 && nBlockYSize != 1024))
     711                 :     {
     712                 :         CPLError(CE_Failure, CPLE_NotSupported,
     713               0 :                 "Block size must be a power of 2 between 32 et 1024");
     714               0 :         return NULL;
     715                 :     }         
     716                 :     
     717                 :     const char* pszFilter =
     718              16 :         CSLFetchNameValueDef(papszOptions, "FILTER", "daub97lift");
     719              16 :     char** papszFBID = eps_get_fb_info(EPS_FB_ID);
     720              16 :     char** papszFBIDIter = papszFBID;
     721              16 :     int bFound = FALSE;
     722              16 :     int nIndexFB = 0;
     723             464 :     while(papszFBIDIter && *papszFBIDIter && !bFound)
     724                 :     {
     725             432 :         if (strcmp(*papszFBIDIter, pszFilter) == 0)
     726              16 :             bFound = TRUE;
     727                 :         else
     728             416 :             nIndexFB ++;
     729             432 :         papszFBIDIter ++;
     730                 :     }
     731              16 :     eps_free_fb_info(papszFBID);
     732              16 :     if (!bFound)
     733                 :     {
     734                 :         CPLError(CE_Failure, CPLE_NotSupported, "FILTER='%s' not supported",
     735               0 :                  pszFilter);
     736               0 :         return NULL;
     737                 :     }
     738                 :     
     739              16 :     int eMode = EPS_MODE_OTLPF;
     740              16 :     const char* pszMode = CSLFetchNameValueDef(papszOptions, "MODE", "OTLPF");
     741              16 :     if (EQUAL(pszMode, "NORMAL"))
     742               0 :         eMode = EPS_MODE_NORMAL;
     743              16 :     else if (EQUAL(pszMode, "OTLPF"))
     744              16 :         eMode = EPS_MODE_OTLPF;
     745                 :     else
     746                 :     {
     747                 :         CPLError(CE_Failure, CPLE_NotSupported, "MODE='%s' not supported",
     748               0 :                  pszMode);
     749               0 :         return NULL;
     750                 :     }
     751                 :     
     752              16 :     char** papszFBType = eps_get_fb_info(EPS_FB_TYPE);
     753              16 :     int bIsBiOrthogonal = EQUAL(papszFBType[nIndexFB], "biorthogonal");
     754              16 :     eps_free_fb_info(papszFBType);
     755                 :     
     756              16 :     if (eMode == EPS_MODE_OTLPF && !bIsBiOrthogonal)
     757                 :     {
     758                 :         CPLError(CE_Failure, CPLE_NotSupported,
     759                 :                  "MODE=OTLPF can only be used with biorthogonal filters. "
     760               0 :                  "Use MODE=NORMAL instead");
     761               0 :         return NULL;
     762                 :     }    
     763                 :     
     764                 :     int bRasterliteOutput =
     765                 :         CSLTestBoolean(CSLFetchNameValueDef(papszOptions,
     766              16 :                                             "RASTERLITE_OUTPUT", "NO"));
     767                 :              
     768              16 :     int nYRatio = EPS_Y_RT;
     769              16 :     int nCbRatio = EPS_Cb_RT;
     770              16 :     int nCrRatio = EPS_Cr_RT;
     771                 :     
     772                 :     int eResample;
     773              16 :     if (CSLTestBoolean(CSLFetchNameValueDef(papszOptions,
     774                 :                                             "RGB_RESAMPLE", "YES")))
     775              16 :         eResample = EPS_RESAMPLE_420;
     776                 :     else
     777               0 :         eResample = EPS_RESAMPLE_444;
     778                 :     
     779              16 :     const char* pszTarget = CSLFetchNameValueDef(papszOptions, "TARGET", "96");
     780              16 :     double dfReductionFactor = 1 - atof(pszTarget) / 100;
     781              16 :     if (dfReductionFactor > 1)
     782               0 :         dfReductionFactor = 1;
     783              16 :     else if (dfReductionFactor < 0)
     784               0 :         dfReductionFactor = 0;
     785                 :     
     786                 : /* -------------------------------------------------------------------- */
     787                 : /*      Open file                                                       */
     788                 : /* -------------------------------------------------------------------- */
     789                 : 
     790              16 :     VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
     791              16 :     if (fp == NULL)
     792               2 :         return NULL;
     793                 : 
     794                 : /* -------------------------------------------------------------------- */
     795                 : /*      Compute number of blocks, block size, etc...                    */
     796                 : /* -------------------------------------------------------------------- */
     797                 : 
     798              14 :     int nXSize = poSrcDS->GetRasterXSize();
     799              14 :     int nYSize = poSrcDS->GetRasterYSize();
     800              14 :     if (eMode == EPS_MODE_OTLPF)
     801                 :     {
     802              14 :         nBlockXSize ++;
     803              14 :         nBlockYSize ++;
     804                 :     }
     805              14 :     int nXBlocks = (nXSize + nBlockXSize - 1) / nBlockXSize;
     806              14 :     int nYBlocks = (nYSize + nBlockYSize - 1) / nBlockYSize;
     807              14 :     int nBlocks = nXBlocks * nYBlocks;
     808              14 :     int nUncompressedFileSize = nXSize * nYSize * nBands;
     809              14 :     int nUncompressedBlockSize = nUncompressedFileSize / nBlocks;
     810              14 :     int nTargetBlockSize = (int) (dfReductionFactor * nUncompressedBlockSize);
     811              14 :     if (nBands == 1)
     812              12 :         nTargetBlockSize = MAX (nTargetBlockSize, EPS_MIN_GRAYSCALE_BUF + 1);
     813                 :     else
     814               2 :         nTargetBlockSize = MAX (nTargetBlockSize, EPS_MIN_TRUECOLOR_BUF + 1);
     815                 : 
     816                 : /* -------------------------------------------------------------------- */
     817                 : /*      Allocate work buffers                                           */
     818                 : /* -------------------------------------------------------------------- */
     819                 : 
     820              14 :     GByte* pabyBuffer = (GByte*)VSIMalloc3(nBlockXSize, nBlockYSize, nBands);
     821              14 :     if (pabyBuffer == NULL)
     822                 :     {
     823               0 :         VSIFCloseL(fp);
     824               0 :         return NULL;
     825                 :     }
     826                 :     
     827              14 :     GByte* pabyOutBuf = (GByte*)VSIMalloc(nTargetBlockSize);
     828              14 :     if (pabyOutBuf == NULL)
     829                 :     {
     830               0 :         VSIFree(pabyBuffer);
     831               0 :         VSIFCloseL(fp);
     832               0 :         return NULL;
     833                 :     }
     834                 :     
     835                 :     GByte** apapbyRawBuffer[3];
     836                 :     int i, j;
     837              32 :     for(i=0;i<nBands;i++)
     838                 :     {
     839              18 :         apapbyRawBuffer[i] = (GByte**) VSIMalloc(sizeof(GByte*) * nBlockYSize);
     840            4644 :         for(j=0;j<nBlockYSize;j++)
     841                 :         {
     842            4626 :             apapbyRawBuffer[i][j] =
     843            4626 :                             pabyBuffer + (i * nBlockXSize + j) * nBlockYSize;
     844                 :         }
     845                 :     }
     846                 :     
     847              14 :     if (bRasterliteOutput)
     848                 :     {
     849               2 :         const char* pszHeader = RASTERLITE_WAVELET_HEADER;
     850               2 :         VSIFWriteL(pszHeader, 1, strlen(pszHeader) + 1, fp);
     851                 :     }
     852                 : 
     853                 : /* -------------------------------------------------------------------- */
     854                 : /*      Iterate over blocks                                             */
     855                 : /* -------------------------------------------------------------------- */
     856                 : 
     857                 :     int nBlockXOff, nBlockYOff;
     858              14 :     CPLErr eErr = CE_None;
     859              28 :     for(nBlockYOff = 0;
     860                 :         eErr == CE_None && nBlockYOff < nYBlocks; nBlockYOff ++)
     861                 :     {
     862              28 :         for(nBlockXOff = 0;
     863                 :             eErr == CE_None && nBlockXOff < nXBlocks; nBlockXOff ++)
     864                 :         {
     865              14 :             int bMustMemset = FALSE;
     866              14 :             int nReqXSize = nBlockXSize, nReqYSize = nBlockYSize;
     867              14 :             if ((nBlockXOff+1) * nBlockXSize > nXSize)
     868                 :             {
     869              14 :                 bMustMemset = TRUE;
     870              14 :                 nReqXSize = nXSize - nBlockXOff * nBlockXSize;
     871                 :             }
     872              14 :             if ((nBlockYOff+1) * nBlockYSize > nYSize)
     873                 :             {
     874              14 :                 bMustMemset = TRUE;
     875              14 :                 nReqYSize = nYSize - nBlockYOff * nBlockYSize;
     876                 :             }
     877              14 :             if (bMustMemset)
     878              14 :                 memset(pabyBuffer, 0, nBands * nBlockXSize * nBlockYSize);
     879                 :             
     880                 :             eErr = poSrcDS->RasterIO(GF_Read,
     881                 :                               nBlockXOff * nBlockXSize,
     882                 :                               nBlockYOff * nBlockYSize,
     883                 :                               nReqXSize, nReqYSize,
     884                 :                               pabyBuffer,
     885                 :                               nReqXSize, nReqYSize,
     886                 :                               GDT_Byte, nBands, NULL,
     887                 :                               1,
     888                 :                               nBlockXSize,
     889              14 :                               nBlockXSize * nBlockYSize);
     890                 :             
     891              14 :             int nOutBufSize = nTargetBlockSize;
     892              26 :             if (eErr == CE_None && nBands == 1)
     893                 :             {
     894              12 :                 if (EPS_OK != eps_encode_grayscale_block(apapbyRawBuffer[0],
     895                 :                                            nXSize, nYSize,
     896                 :                                            nReqXSize, nReqYSize,
     897                 :                                            nBlockXOff * nBlockXSize,
     898                 :                                            nBlockYOff * nBlockYSize,
     899                 :                                            pabyOutBuf, &nOutBufSize,
     900                 :                                            (char*) pszFilter, eMode))
     901                 :                 {
     902                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     903                 :                              "Error occured when encoding block (%d, %d)",
     904               0 :                              nBlockXOff, nBlockYOff);
     905               0 :                     eErr = CE_Failure;
     906                 :                 }
     907                 :             }
     908               2 :             else if (eErr == CE_None)
     909                 :             {
     910               2 :                 if (EPS_OK != eps_encode_truecolor_block(
     911                 :                                            apapbyRawBuffer[0],
     912                 :                                            apapbyRawBuffer[1],
     913                 :                                            apapbyRawBuffer[2],
     914                 :                                            nXSize, nYSize,
     915                 :                                            nReqXSize, nReqYSize,
     916                 :                                            nBlockXOff * nBlockXSize,
     917                 :                                            nBlockYOff * nBlockYSize,
     918                 :                                            eResample,
     919                 :                                            pabyOutBuf, &nOutBufSize,
     920                 :                                            nYRatio, nCbRatio, nCrRatio,
     921                 :                                            (char*) pszFilter, eMode))
     922                 :                 {
     923                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     924                 :                              "Error occured when encoding block (%d, %d)",
     925               0 :                              nBlockXOff, nBlockYOff);
     926               0 :                     eErr = CE_Failure;
     927                 :                 }
     928                 :             }
     929                 :             
     930              14 :             if (eErr == CE_None)
     931                 :             {
     932              14 :                 if ((int)VSIFWriteL(pabyOutBuf, 1, nOutBufSize, fp) !=
     933                 :                                                                 nOutBufSize)
     934               0 :                     eErr = CE_Failure;
     935                 : 
     936              14 :                 char chEPSMarker = EPS_MARKER;
     937              14 :                 VSIFWriteL(&chEPSMarker, 1, 1, fp);
     938                 :                 
     939              14 :                 if (pfnProgress && !pfnProgress(
     940                 :                       1.0 * (nBlockYOff * nXBlocks + nBlockXOff + 1) / nBlocks,
     941                 :                       NULL, pProgressData))
     942                 :                 {
     943               0 :                     eErr = CE_Failure;
     944                 :                 }
     945                 :             }
     946                 :         }
     947                 :     }
     948                 :     
     949              14 :     if (bRasterliteOutput)
     950                 :     {
     951               2 :         const char* pszFooter = RASTERLITE_WAVELET_FOOTER;
     952               2 :         VSIFWriteL(pszFooter, 1, strlen(pszFooter) + 1, fp);
     953                 :     }
     954                 : 
     955                 : /* -------------------------------------------------------------------- */
     956                 : /*      Cleanup work buffers                                            */
     957                 : /* -------------------------------------------------------------------- */
     958                 :     
     959              32 :     for(i=0;i<nBands;i++)
     960                 :     {
     961              18 :         VSIFree(apapbyRawBuffer[i]);
     962                 :     }
     963                 :     
     964              14 :     VSIFree(pabyOutBuf);
     965              14 :     VSIFree(pabyBuffer);
     966                 :         
     967              14 :     VSIFCloseL(fp);
     968                 :     
     969              14 :     if (eErr != CE_None)
     970               0 :         return NULL;
     971                 : 
     972                 : /* -------------------------------------------------------------------- */
     973                 : /*      Reopen the dataset, unless asked for not (Rasterlite optim)     */
     974                 : /* -------------------------------------------------------------------- */
     975              14 :     return (GDALDataset*) GDALOpen(pszFilename, GA_ReadOnly);
     976                 : }
     977                 : 
     978                 : /************************************************************************/
     979                 : /*                     GDALRegister_EPSILON()                           */
     980                 : /************************************************************************/
     981                 : 
     982             582 : void GDALRegister_EPSILON()
     983                 : 
     984                 : {
     985                 :     GDALDriver  *poDriver;
     986                 :     
     987             582 :     if (! GDAL_CHECK_VERSION("EPSILON driver"))
     988               0 :         return;
     989                 : 
     990             582 :     if( GDALGetDriverByName( "EPSILON" ) == NULL )
     991                 :     {
     992             561 :         poDriver = new GDALDriver();
     993                 :         
     994             561 :         poDriver->SetDescription( "EPSILON" );
     995                 :         
     996                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
     997             561 :                                    "Epsilon wavelets" );
     998                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
     999             561 :                                    "frmt_epsilon.html" );
    1000                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
    1001             561 :                                    "Byte" );
    1002                 : 
    1003             561 :         CPLString osMethods;
    1004            1122 :         char** papszFBID = eps_get_fb_info(EPS_FB_ID);
    1005             561 :         char** papszFBIDIter = papszFBID;
    1006           19074 :         while(papszFBIDIter && *papszFBIDIter)
    1007                 :         {
    1008           17952 :             osMethods += "       <Value>";
    1009           17952 :             osMethods += *papszFBIDIter;
    1010           17952 :             osMethods += "</Value>\n";
    1011           17952 :             papszFBIDIter ++;
    1012                 :         }
    1013             561 :         eps_free_fb_info(papszFBID);
    1014                 :         
    1015             561 :         CPLString osOptionList;
    1016                 :         osOptionList.Printf(
    1017                 : "<CreationOptionList>"
    1018                 : "   <Option name='TARGET' type='int' description='target size reduction as a percentage of the original (0-100)' default='75'/>"
    1019                 : "   <Option name='FILTER' type='string-select' description='Filter ID' default='daub97lift'>"
    1020                 : "%s"
    1021                 : "   </Option>"
    1022                 : "   <Option name='BLOCKXSIZE' type='int' description='Tile Width. Between 32 and 1024' default='256'/>"
    1023                 : "   <Option name='BLOCKYSIZE' type='int' description='Tile Height. Between 32 and 1024' default='256'/>"
    1024                 : "   <Option name='MODE' type='string-select' default='OTLPF'>"
    1025                 : "       <Value>NORMAL</Value>"
    1026                 : "       <Value>OTLPF</Value>"
    1027                 : "   </Option>"
    1028                 : "   <Option name='RGB_RESAMPLE' type='boolean' description='if RGB must be resampled to 4:2:0' default='YES'/>"
    1029                 : "   <Option name='RASTERLITE_OUTPUT' type='boolean' description='if Rasterlite header and footers must be inserted' default='FALSE'/>"
    1030             561 : "</CreationOptionList>", osMethods.c_str()  );
    1031                 : 
    1032                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    1033             561 :                                    osOptionList.c_str() );
    1034                 :                             
    1035             561 :         poDriver->pfnOpen = EpsilonDataset::Open;
    1036             561 :         poDriver->pfnIdentify = EpsilonDataset::Identify;
    1037             561 :         poDriver->pfnCreateCopy = EpsilonDatasetCreateCopy;
    1038                 :         
    1039             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1040                 : 
    1041             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1042                 :     }
    1043                 : }

Generated by: LCOV version 1.7