LTP GCOV extension - code coverage report
Current view: directory - frmts/epsilon - epsilondataset.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 419
Code covered: 77.1 % Executed lines: 323

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

Generated by: LTP GCOV extension version 1.5