LCOV - code coverage report
Current view: directory - frmts/mbtiles - mbtilesdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 797 568 71.3 %
Date: 2012-04-28 Functions: 31 25 80.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: mbtilesdataset.cpp 23737 2012-01-09 19:26:10Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL MBTiles driver
       5                 :  * Purpose:  Implement GDAL MBTiles support using OGR SQLite driver
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  **********************************************************************
       9                 :  * Copyright (c) 2012, 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 "gdal_frmts.h"
      31                 : #include "gdal_pam.h"
      32                 : #include "ogr_api.h"
      33                 : #include "cpl_vsil_curl_priv.h"
      34                 : 
      35                 : #include "zlib.h"
      36                 : #include "jsonc/json.h"
      37                 : 
      38                 : #include <math.h>
      39                 : 
      40                 : extern "C" void GDALRegister_MBTiles();
      41                 : 
      42                 : CPL_CVSID("$Id: mbtilesdataset.cpp 23737 2012-01-09 19:26:10Z rouault $");
      43                 : 
      44                 : static const char * const apszAllowedDrivers[] = {"JPEG", "PNG", NULL};
      45                 : 
      46                 : class MBTilesBand;
      47                 : 
      48                 : /************************************************************************/
      49                 : /* ==================================================================== */
      50                 : /*                              MBTilesDataset                          */
      51                 : /* ==================================================================== */
      52                 : /************************************************************************/
      53                 : 
      54                 : class MBTilesDataset : public GDALPamDataset
      55                 : {
      56                 :     friend class MBTilesBand;
      57                 : 
      58                 :   public:
      59                 :                  MBTilesDataset();
      60                 :                  MBTilesDataset(MBTilesDataset* poMainDS, int nLevel);
      61                 : 
      62                 :     virtual     ~MBTilesDataset();
      63                 : 
      64                 :     virtual CPLErr GetGeoTransform(double* padfGeoTransform);
      65                 :     virtual const char* GetProjectionRef();
      66                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
      67                 : 
      68                 :     static GDALDataset *Open( GDALOpenInfo * );
      69                 :     static int          Identify( GDALOpenInfo * );
      70                 : 
      71                 :     char*               FindKey(int iPixel, int iLine,
      72                 :                                 int& nTileColumn, int& nTileRow, int& nZoomLevel);
      73                 :     void                ComputeTileColTileRowZoomLevel( int nBlockXOff,
      74                 :                                                         int nBlockYOff,
      75                 :                                                         int &nTileColumn,
      76                 :                                                         int &nTileRow,
      77                 :                                                         int &nZoomLevel );
      78                 :     int                 HasNonEmptyGrids();
      79                 : 
      80                 :   protected:
      81                 :     virtual int         CloseDependentDatasets();
      82                 : 
      83                 :   private:
      84                 : 
      85                 :     int bMustFree;
      86                 :     MBTilesDataset* poMainDS;
      87                 :     int nLevel;
      88                 :     int nMinTileCol, nMinTileRow;
      89                 :     int nMinLevel;
      90                 : 
      91                 :     char** papszMetadata;
      92                 :     char** papszImageStructure;
      93                 : 
      94                 :     int nResolutions;
      95                 :     MBTilesDataset** papoOverviews;
      96                 : 
      97                 :     OGRDataSourceH hDS;
      98                 : 
      99                 :     int bFetchedMetadata;
     100                 :     CPLStringList aosList;
     101                 : 
     102                 :     int bHasNonEmptyGrids;
     103                 : };
     104                 : 
     105                 : /************************************************************************/
     106                 : /* ==================================================================== */
     107                 : /*                              MBTilesBand                             */
     108                 : /* ==================================================================== */
     109                 : /************************************************************************/
     110                 : 
     111                 : class MBTilesBand: public GDALPamRasterBand
     112              66 : {
     113                 :     friend class MBTilesDataset;
     114                 : 
     115                 :     CPLString               osLocationInfo;
     116                 : 
     117                 :   public:
     118                 :                             MBTilesBand( MBTilesDataset* poDS, int nBand,
     119                 :                                             GDALDataType eDataType,
     120                 :                                             int nBlockXSize, int nBlockYSize);
     121                 : 
     122                 :     virtual GDALColorInterp GetColorInterpretation();
     123                 : 
     124                 :     virtual int             GetOverviewCount();
     125                 :     virtual GDALRasterBand* GetOverview(int nLevel);
     126                 : 
     127                 :     virtual CPLErr          IReadBlock( int, int, void * );
     128                 : 
     129                 :     virtual const char *GetMetadataItem( const char * pszName,
     130                 :                                          const char * pszDomain = "" );
     131                 : };
     132                 : 
     133                 : /************************************************************************/
     134                 : /*                            MBTilesBand()                          */
     135                 : /************************************************************************/
     136                 : 
     137              66 : MBTilesBand::MBTilesBand(MBTilesDataset* poDS, int nBand,
     138                 :                                 GDALDataType eDataType,
     139              66 :                                 int nBlockXSize, int nBlockYSize)
     140                 : {
     141              66 :     this->poDS = poDS;
     142              66 :     this->nBand = nBand;
     143              66 :     this->eDataType = eDataType;
     144              66 :     this->nBlockXSize = nBlockXSize;
     145              66 :     this->nBlockYSize = nBlockYSize;
     146              66 : }
     147                 : 
     148                 : /************************************************************************/
     149                 : /*                            IReadBlock()                              */
     150                 : /************************************************************************/
     151                 : 
     152              10 : CPLErr MBTilesBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage)
     153                 : {
     154              10 :     MBTilesDataset* poGDS = (MBTilesDataset*) poDS;
     155                 : 
     156              10 :     int bGotTile = FALSE;
     157              10 :     CPLAssert(eDataType == GDT_Byte);
     158                 : 
     159                 :     int nTileColumn, nTileRow, nZoomLevel;
     160                 :     poGDS->ComputeTileColTileRowZoomLevel(nBlockXOff, nBlockYOff,
     161              10 :                                           nTileColumn, nTileRow, nZoomLevel);
     162                 : 
     163                 :     const char* pszSQL = CPLSPrintf("SELECT tile_data FROM tiles WHERE "
     164                 :                                     "tile_column = %d AND tile_row = %d AND zoom_level=%d",
     165              10 :                                     nTileColumn, nTileRow, nZoomLevel);
     166                 :     CPLDebug("MBTILES", "nBand=%d, nBlockXOff=%d, nBlockYOff=%d, %s",
     167              10 :              nBand, nBlockXOff, nBlockYOff, pszSQL);
     168              10 :     OGRLayerH hSQLLyr = OGR_DS_ExecuteSQL(poGDS->hDS, pszSQL, NULL, NULL);
     169                 : 
     170              10 :     OGRFeatureH hFeat = hSQLLyr ? OGR_L_GetNextFeature(hSQLLyr) : NULL;
     171              10 :     if (hFeat != NULL)
     172                 :     {
     173              10 :         CPLString osMemFileName;
     174              10 :         osMemFileName.Printf("/vsimem/%p", this);
     175                 : 
     176              10 :         int nDataSize = 0;
     177              10 :         GByte* pabyData = OGR_F_GetFieldAsBinary(hFeat, 0, &nDataSize);
     178                 : 
     179                 :         VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyData,
     180              10 :                                             nDataSize, FALSE);
     181              10 :         VSIFCloseL(fp);
     182                 : 
     183              10 :         GDALDatasetH hDSTile = GDALOpenInternal(osMemFileName.c_str(), GA_ReadOnly, apszAllowedDrivers);
     184              10 :         if (hDSTile != NULL)
     185                 :         {
     186              10 :             int nTileBands = GDALGetRasterCount(hDSTile);
     187              10 :             if (nTileBands == 4 && poGDS->nBands == 3)
     188               0 :                 nTileBands = 3;
     189                 : 
     190              10 :             if (GDALGetRasterXSize(hDSTile) == nBlockXSize &&
     191                 :                 GDALGetRasterYSize(hDSTile) == nBlockYSize &&
     192                 :                 (nTileBands == poGDS->nBands ||
     193                 :                  (nTileBands == 1 && (poGDS->nBands == 3 || poGDS->nBands == 4)) ||
     194                 :                  (nTileBands == 3 && poGDS->nBands == 4)))
     195                 :             {
     196                 :                 int iBand;
     197              10 :                 void* pSrcImage = NULL;
     198                 :                 GByte abyTranslation[256][3];
     199                 : 
     200              10 :                 bGotTile = TRUE;
     201                 : 
     202              10 :                 GDALColorTableH hCT = GDALGetRasterColorTable(GDALGetRasterBand(hDSTile, 1));
     203              10 :                 if (nTileBands == 1 && (poGDS->nBands == 3 || poGDS->nBands == 4))
     204                 :                 {
     205               0 :                     if (hCT != NULL)
     206               0 :                         pSrcImage = CPLMalloc(nBlockXSize * nBlockYSize);
     207               0 :                     iBand = 1;
     208                 :                 }
     209                 :                 else
     210              10 :                     iBand = nBand;
     211                 : 
     212              10 :                 if (nTileBands == 3 && poGDS->nBands == 4 && iBand == 4)
     213               0 :                     memset(pImage, 255, nBlockXSize * nBlockYSize);
     214                 :                 else
     215                 :                 {
     216                 :                     GDALRasterIO(GDALGetRasterBand(hDSTile, iBand), GF_Read,
     217                 :                                 0, 0, nBlockXSize, nBlockYSize,
     218              10 :                                 pImage, nBlockXSize, nBlockYSize, eDataType, 0, 0);
     219                 :                 }
     220                 : 
     221              10 :                 if (pSrcImage != NULL && hCT != NULL)
     222                 :                 {
     223                 :                     int i;
     224               0 :                     memcpy(pSrcImage, pImage, nBlockXSize * nBlockYSize);
     225                 : 
     226               0 :                     int nEntryCount = GDALGetColorEntryCount( hCT );
     227               0 :                     if (nEntryCount > 256)
     228               0 :                         nEntryCount = 256;
     229               0 :                     for(i = 0; i < nEntryCount; i++)
     230                 :                     {
     231               0 :                         const GDALColorEntry* psEntry = GDALGetColorEntry( hCT, i );
     232               0 :                         abyTranslation[i][0] = (GByte) psEntry->c1;
     233               0 :                         abyTranslation[i][1] = (GByte) psEntry->c2;
     234               0 :                         abyTranslation[i][2] = (GByte) psEntry->c3;
     235                 :                     }
     236               0 :                     for(; i < 256; i++)
     237                 :                     {
     238               0 :                         abyTranslation[i][0] = 0;
     239               0 :                         abyTranslation[i][1] = 0;
     240               0 :                         abyTranslation[i][2] = 0;
     241                 :                     }
     242                 : 
     243               0 :                     for(i = 0; i < nBlockXSize * nBlockYSize; i++)
     244                 :                     {
     245               0 :                         ((GByte*)pImage)[i] = abyTranslation[((GByte*)pSrcImage)[i]][nBand-1];
     246                 :                     }
     247                 :                 }
     248                 : 
     249              40 :                 for(int iOtherBand=1;iOtherBand<=poGDS->nBands;iOtherBand++)
     250                 :                 {
     251                 :                     GDALRasterBlock *poBlock;
     252                 : 
     253              30 :                     if (iOtherBand == nBand)
     254              10 :                         continue;
     255                 : 
     256                 :                     poBlock = ((MBTilesBand*)poGDS->GetRasterBand(iOtherBand))->
     257              20 :                         TryGetLockedBlockRef(nBlockXOff,nBlockYOff);
     258                 : 
     259              20 :                     if (poBlock != NULL)
     260                 :                     {
     261               0 :                         poBlock->DropLock();
     262               0 :                         continue;
     263                 :                     }
     264                 : 
     265                 :                     poBlock = poGDS->GetRasterBand(iOtherBand)->
     266              20 :                         GetLockedBlockRef(nBlockXOff,nBlockYOff, TRUE);
     267              20 :                     if (poBlock == NULL)
     268               0 :                         break;
     269                 : 
     270              20 :                     GByte* pabySrcBlock = (GByte *) poBlock->GetDataRef();
     271              20 :                     if( pabySrcBlock == NULL )
     272                 :                     {
     273               0 :                         poBlock->DropLock();
     274               0 :                         break;
     275                 :                     }
     276                 : 
     277              20 :                     if (nTileBands == 3 && poGDS->nBands == 4 && iOtherBand == 4)
     278               0 :                         memset(pabySrcBlock, 255, nBlockXSize * nBlockYSize);
     279              20 :                     else if (nTileBands == 1 && (poGDS->nBands == 3 || poGDS->nBands == 4))
     280                 :                     {
     281                 :                         int i;
     282               0 :                         if (iOtherBand == 4)
     283                 :                         {
     284               0 :                             memset(pabySrcBlock, 255, nBlockXSize * nBlockYSize);
     285                 :                         }
     286               0 :                         else if (pSrcImage)
     287                 :                         {
     288               0 :                             for(i = 0; i < nBlockXSize * nBlockYSize; i++)
     289                 :                             {
     290               0 :                                 ((GByte*)pabySrcBlock)[i] =
     291               0 :                                     abyTranslation[((GByte*)pSrcImage)[i]][iOtherBand-1];
     292                 :                             }
     293                 :                         }
     294                 :                         else
     295               0 :                             memcpy(pabySrcBlock, pImage, nBlockXSize * nBlockYSize);
     296                 :                     }
     297                 :                     else
     298                 :                     {
     299                 :                         GDALRasterIO(GDALGetRasterBand(hDSTile, iOtherBand), GF_Read,
     300                 :                             0, 0, nBlockXSize, nBlockYSize,
     301              20 :                             pabySrcBlock, nBlockXSize, nBlockYSize, eDataType, 0, 0);
     302                 :                     }
     303                 : 
     304              20 :                     poBlock->DropLock();
     305                 :                 }
     306                 : 
     307              10 :                 CPLFree(pSrcImage);
     308                 :             }
     309               0 :             else if (GDALGetRasterXSize(hDSTile) == nBlockXSize &&
     310                 :                      GDALGetRasterYSize(hDSTile) == nBlockYSize &&
     311                 :                      (nTileBands == 3 && poGDS->nBands == 1))
     312                 :             {
     313               0 :                 bGotTile = TRUE;
     314                 : 
     315               0 :                 GByte* pabyRGBImage = (GByte*)CPLMalloc(3 * nBlockXSize * nBlockYSize);
     316                 :                 GDALDatasetRasterIO(hDSTile, GF_Read,
     317                 :                                     0, 0, nBlockXSize, nBlockYSize,
     318                 :                                     pabyRGBImage, nBlockXSize, nBlockYSize, eDataType,
     319               0 :                                     3, NULL, 3, 3 * nBlockXSize, 1);
     320               0 :                 for(int i=0;i<nBlockXSize*nBlockYSize;i++)
     321                 :                 {
     322               0 :                     int R = pabyRGBImage[3*i];
     323               0 :                     int G = pabyRGBImage[3*i+1];
     324               0 :                     int B = pabyRGBImage[3*i+2];
     325               0 :                     GByte Y = (GByte)((213 * R + 715 * G + 72 * B) / 1000);
     326               0 :                     ((GByte*)pImage)[i] = Y;
     327                 :                 }
     328               0 :                 CPLFree(pabyRGBImage);
     329                 :             }
     330                 :             else
     331                 :             {
     332                 :                 CPLDebug("MBTILES", "tile size = %d, tile height = %d, tile bands = %d",
     333                 :                          GDALGetRasterXSize(hDSTile), GDALGetRasterYSize(hDSTile),
     334               0 :                          GDALGetRasterCount(hDSTile));
     335                 :             }
     336              10 :             GDALClose(hDSTile);
     337                 :         }
     338                 : 
     339              10 :         VSIUnlink( osMemFileName.c_str() );
     340                 : 
     341              10 :         OGR_F_Destroy(hFeat);
     342                 :     }
     343                 : 
     344              10 :     OGR_DS_ReleaseResultSet(poGDS->hDS, hSQLLyr);
     345                 : 
     346              10 :     if (!bGotTile)
     347                 :     {
     348               0 :         memset(pImage, (nBand == 4) ? 0 : 255, nBlockXSize * nBlockYSize);
     349                 : 
     350               0 :         for(int iOtherBand=1;iOtherBand<=poGDS->nBands;iOtherBand++)
     351                 :         {
     352                 :             GDALRasterBlock *poBlock;
     353                 : 
     354               0 :             if (iOtherBand == nBand)
     355               0 :                 continue;
     356                 : 
     357                 :             poBlock = poGDS->GetRasterBand(iOtherBand)->
     358               0 :                 GetLockedBlockRef(nBlockXOff,nBlockYOff, TRUE);
     359               0 :             if (poBlock == NULL)
     360               0 :                 break;
     361                 : 
     362               0 :             GByte* pabySrcBlock = (GByte *) poBlock->GetDataRef();
     363               0 :             if( pabySrcBlock == NULL )
     364                 :             {
     365               0 :                 poBlock->DropLock();
     366               0 :                 break;
     367                 :             }
     368                 : 
     369                 :             memset(pabySrcBlock, (iOtherBand == 4) ? 0 : 255,
     370               0 :                    nBlockXSize * nBlockYSize);
     371                 : 
     372               0 :             poBlock->DropLock();
     373                 :         }
     374                 :     }
     375                 : 
     376              10 :     return CE_None;
     377                 : }
     378                 : 
     379                 : /************************************************************************/
     380                 : /*                           utf8decode()                               */
     381                 : /************************************************************************/
     382                 : 
     383              60 : static unsigned utf8decode(const char* p, const char* end, int* len)
     384                 : {
     385              60 :   unsigned char c = *(unsigned char*)p;
     386              60 :   if (c < 0x80) {
     387              60 :     *len = 1;
     388              60 :     return c;
     389               0 :   } else if (c < 0xc2) {
     390               0 :     goto FAIL;
     391                 :   }
     392               0 :   if (p+1 >= end || (p[1]&0xc0) != 0x80) goto FAIL;
     393               0 :   if (c < 0xe0) {
     394               0 :     *len = 2;
     395                 :     return
     396               0 :       ((p[0] & 0x1f) << 6) +
     397               0 :       ((p[1] & 0x3f));
     398               0 :   } else if (c == 0xe0) {
     399               0 :     if (((unsigned char*)p)[1] < 0xa0) goto FAIL;
     400               0 :     goto UTF8_3;
     401                 : #if STRICT_RFC3629
     402                 :   } else if (c == 0xed) {
     403                 :     // RFC 3629 says surrogate chars are illegal.
     404                 :     if (((unsigned char*)p)[1] >= 0xa0) goto FAIL;
     405                 :     goto UTF8_3;
     406                 :   } else if (c == 0xef) {
     407                 :     // 0xfffe and 0xffff are also illegal characters
     408                 :     if (((unsigned char*)p)[1]==0xbf &&
     409                 :     ((unsigned char*)p)[2]>=0xbe) goto FAIL;
     410                 :     goto UTF8_3;
     411                 : #endif
     412               0 :   } else if (c < 0xf0) {
     413                 :   UTF8_3:
     414               0 :     if (p+2 >= end || (p[2]&0xc0) != 0x80) goto FAIL;
     415               0 :     *len = 3;
     416                 :     return
     417               0 :       ((p[0] & 0x0f) << 12) +
     418               0 :       ((p[1] & 0x3f) << 6) +
     419               0 :       ((p[2] & 0x3f));
     420               0 :   } else if (c == 0xf0) {
     421               0 :     if (((unsigned char*)p)[1] < 0x90) goto FAIL;
     422               0 :     goto UTF8_4;
     423               0 :   } else if (c < 0xf4) {
     424                 :   UTF8_4:
     425               0 :     if (p+3 >= end || (p[2]&0xc0) != 0x80 || (p[3]&0xc0) != 0x80) goto FAIL;
     426               0 :     *len = 4;
     427                 : #if STRICT_RFC3629
     428                 :     // RFC 3629 says all codes ending in fffe or ffff are illegal:
     429                 :     if ((p[1]&0xf)==0xf &&
     430                 :     ((unsigned char*)p)[2] == 0xbf &&
     431                 :     ((unsigned char*)p)[3] >= 0xbe) goto FAIL;
     432                 : #endif
     433                 :     return
     434               0 :       ((p[0] & 0x07) << 18) +
     435               0 :       ((p[1] & 0x3f) << 12) +
     436               0 :       ((p[2] & 0x3f) << 6) +
     437               0 :       ((p[3] & 0x3f));
     438               0 :   } else if (c == 0xf4) {
     439               0 :     if (((unsigned char*)p)[1] > 0x8f) goto FAIL; // after 0x10ffff
     440               0 :     goto UTF8_4;
     441                 :   } else {
     442                 :   FAIL:
     443               0 :     *len = 1;
     444               0 :     return 0xfffd; // Unicode REPLACEMENT CHARACTER
     445                 :   }
     446                 : }
     447                 : 
     448                 : 
     449                 : /************************************************************************/
     450                 : /*                  ComputeTileColTileRowZoomLevel()                    */
     451                 : /************************************************************************/
     452                 : 
     453              14 : void MBTilesDataset::ComputeTileColTileRowZoomLevel(int nBlockXOff,
     454                 :                                                     int nBlockYOff,
     455                 :                                                     int &nTileColumn,
     456                 :                                                     int &nTileRow,
     457                 :                                                     int &nZoomLevel)
     458                 : {
     459              14 :     const int nBlockYSize = 256;
     460                 : 
     461              14 :     int _nMinLevel = (poMainDS) ? poMainDS->nMinLevel : nMinLevel;
     462              14 :     int _nMinTileCol = (poMainDS) ? poMainDS->nMinTileCol : nMinTileCol;
     463              14 :     int _nMinTileRow = (poMainDS) ? poMainDS->nMinTileRow : nMinTileRow;
     464              14 :     _nMinTileCol >>= nLevel;
     465                 : 
     466              14 :     nTileColumn = nBlockXOff + _nMinTileCol;
     467              14 :     nTileRow = (((nRasterYSize / nBlockYSize - 1 - nBlockYOff) << nLevel) + _nMinTileRow) >> nLevel;
     468              14 :     nZoomLevel = ((poMainDS) ? poMainDS->nResolutions : nResolutions) - nLevel + _nMinLevel;
     469              14 : }
     470                 : 
     471                 : /************************************************************************/
     472                 : /*                          HasNonEmptyGrids()                          */
     473                 : /************************************************************************/
     474                 : 
     475               6 : int MBTilesDataset::HasNonEmptyGrids()
     476                 : {
     477                 :     OGRLayerH hSQLLyr;
     478                 :     OGRFeatureH hFeat;
     479                 :     const char* pszSQL;
     480                 : 
     481               6 :     if (poMainDS)
     482               2 :         return poMainDS->HasNonEmptyGrids();
     483                 : 
     484               4 :     if (bHasNonEmptyGrids >= 0)
     485               2 :         return bHasNonEmptyGrids;
     486                 : 
     487               2 :     bHasNonEmptyGrids = FALSE;
     488                 : 
     489               2 :     if (OGR_DS_GetLayerByName(hDS, "grids") == NULL)
     490               0 :         return FALSE;
     491                 : 
     492               2 :     pszSQL = "SELECT type FROM sqlite_master WHERE name = 'grids'";
     493               2 :     CPLDebug("MBTILES", "%s", pszSQL);
     494               2 :     hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
     495               2 :     if (hSQLLyr == NULL)
     496               0 :         return FALSE;
     497                 : 
     498               2 :     hFeat = OGR_L_GetNextFeature(hSQLLyr);
     499               2 :     if (hFeat == NULL || !OGR_F_IsFieldSet(hFeat, 0))
     500                 :     {
     501               0 :         OGR_F_Destroy(hFeat);
     502               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
     503               0 :         return FALSE;
     504                 :     }
     505                 : 
     506               2 :     int bGridsIsView = strcmp(OGR_F_GetFieldAsString(hFeat, 0), "view") == 0;
     507                 : 
     508               2 :     OGR_F_Destroy(hFeat);
     509               2 :     OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
     510                 : 
     511               2 :     bHasNonEmptyGrids = TRUE;
     512                 : 
     513                 :     /* In the case 'grids' is a view (and a join between the 'map' and 'grid_utfgrid' layers */
     514                 :     /* the cost of evaluating a join is very long, even if grid_utfgrid is empty */
     515                 :     /* so check it is not empty */
     516               2 :     if (bGridsIsView)
     517                 :     {
     518                 :         OGRLayerH hGridUTFGridLyr;
     519               2 :         hGridUTFGridLyr = OGR_DS_GetLayerByName(hDS, "grid_utfgrid");
     520               2 :         if (hGridUTFGridLyr != NULL)
     521                 :         {
     522               2 :             OGR_L_ResetReading(hGridUTFGridLyr);
     523               2 :             hFeat = OGR_L_GetNextFeature(hGridUTFGridLyr);
     524               2 :             OGR_F_Destroy(hFeat);
     525                 : 
     526               2 :             bHasNonEmptyGrids = hFeat != NULL;
     527                 :         }
     528                 :     }
     529                 : 
     530               2 :     return bHasNonEmptyGrids;
     531                 : }
     532                 : 
     533                 : /************************************************************************/
     534                 : /*                             FindKey()                                */
     535                 : /************************************************************************/
     536                 : 
     537               4 : char* MBTilesDataset::FindKey(int iPixel, int iLine,
     538                 :                               int& nTileColumn, int& nTileRow, int& nZoomLevel)
     539                 : {
     540               4 :     const int nBlockXSize = 256, nBlockYSize = 256;
     541               4 :     int nBlockXOff = iPixel / nBlockXSize;
     542               4 :     int nBlockYOff = iLine / nBlockYSize;
     543                 : 
     544               4 :     int nColInBlock = iPixel % nBlockXSize;
     545               4 :     int nRowInBlock = iLine % nBlockXSize;
     546                 : 
     547                 :     ComputeTileColTileRowZoomLevel(nBlockXOff, nBlockYOff,
     548               4 :                                    nTileColumn, nTileRow, nZoomLevel);
     549                 : 
     550               4 :     char* pszKey = NULL;
     551                 : 
     552                 :     OGRLayerH hSQLLyr;
     553                 :     OGRFeatureH hFeat;
     554                 :     const char* pszSQL;
     555               4 :     json_object* poGrid = NULL;
     556                 :     int i;
     557                 : 
     558                 :     /* See https://github.com/mapbox/utfgrid-spec/blob/master/1.0/utfgrid.md */
     559                 :     /* for the explanation of the following processings */
     560                 : 
     561                 :     pszSQL = CPLSPrintf("SELECT grid FROM grids WHERE "
     562                 :                         "zoom_level = %d AND tile_column = %d AND tile_row = %d",
     563               4 :                         nZoomLevel, nTileColumn, nTileRow);
     564               4 :     CPLDebug("MBTILES", "%s", pszSQL);
     565               4 :     hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
     566               4 :     if (hSQLLyr == NULL)
     567               0 :         return NULL;
     568                 : 
     569               4 :     hFeat = OGR_L_GetNextFeature(hSQLLyr);
     570               4 :     if (hFeat == NULL || !OGR_F_IsFieldSet(hFeat, 0))
     571                 :     {
     572               0 :         OGR_F_Destroy(hFeat);
     573               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
     574               0 :         return NULL;
     575                 :     }
     576                 : 
     577               4 :     int nDataSize = 0;
     578               4 :     GByte* pabyData = OGR_F_GetFieldAsBinary(hFeat, 0, &nDataSize);
     579                 : 
     580               4 :     int nUncompressedSize = 256*256;
     581               4 :     GByte* pabyUncompressed = (GByte*)CPLMalloc(nUncompressedSize + 1);
     582                 : 
     583                 :     z_stream sStream;
     584               4 :     memset(&sStream, 0, sizeof(sStream));
     585               4 :     inflateInit(&sStream);
     586               4 :     sStream.next_in   = pabyData;
     587               4 :     sStream.avail_in  = nDataSize;
     588               4 :     sStream.next_out  = pabyUncompressed;
     589               4 :     sStream.avail_out = nUncompressedSize;
     590               4 :     int nStatus = inflate(&sStream, Z_FINISH);
     591               4 :     inflateEnd(&sStream);
     592               4 :     if (nStatus != Z_OK && nStatus != Z_STREAM_END)
     593                 :     {
     594               0 :         CPLDebug("MBTILES", "Error unzipping grid");
     595               0 :         nUncompressedSize = 0;
     596               0 :         pabyUncompressed[nUncompressedSize] = 0;
     597                 :     }
     598                 :     else
     599                 :     {
     600               4 :         nUncompressedSize -= sStream.avail_out;
     601               4 :         pabyUncompressed[nUncompressedSize] = 0;
     602                 :         //CPLDebug("MBTILES", "Grid size = %d", nUncompressedSize);
     603                 :         //CPLDebug("MBTILES", "Grid value = %s", (const char*)pabyUncompressed);
     604                 :     }
     605                 : 
     606               4 :     struct json_tokener *jstok = NULL;
     607               4 :     json_object* jsobj = NULL;
     608                 : 
     609               4 :     if (nUncompressedSize == 0)
     610                 :     {
     611               0 :         goto end;
     612                 :     }
     613                 : 
     614               4 :     jstok = json_tokener_new();
     615               4 :     jsobj = json_tokener_parse_ex(jstok, (const char*)pabyUncompressed, -1);
     616               4 :     if( jstok->err != json_tokener_success)
     617                 :     {
     618                 :         CPLError( CE_Failure, CPLE_AppDefined,
     619                 :                     "JSON parsing error: %s (at offset %d)",
     620                 :                     json_tokener_errors[jstok->err],
     621               0 :                     jstok->char_offset);
     622               0 :         json_tokener_free(jstok);
     623                 : 
     624               0 :         goto end;
     625                 :     }
     626                 : 
     627               4 :     json_tokener_free(jstok);
     628                 : 
     629               4 :     if (json_object_is_type(jsobj, json_type_object))
     630                 :     {
     631               4 :         poGrid = json_object_object_get(jsobj, "grid");
     632                 :     }
     633               4 :     if (poGrid != NULL && json_object_is_type(poGrid, json_type_array))
     634                 :     {
     635                 :         int nLines;
     636                 :         int nFactor;
     637                 :         json_object* poRow;
     638               4 :         char* pszRow = NULL;
     639                 : 
     640               4 :         nLines = json_object_array_length(poGrid);
     641               4 :         if (nLines == 0)
     642               0 :             goto end;
     643                 : 
     644               4 :         nFactor = 256 / nLines;
     645               4 :         nRowInBlock /= nFactor;
     646               4 :         nColInBlock /= nFactor;
     647                 : 
     648               4 :         poRow = json_object_array_get_idx(poGrid, nRowInBlock);
     649                 : 
     650                 :         /* Extract line of interest in grid */
     651               4 :         if (poRow != NULL && json_object_is_type(poRow, json_type_string))
     652                 :         {
     653               4 :             pszRow = CPLStrdup(json_object_get_string(poRow));
     654                 :         }
     655                 : 
     656               4 :         if (pszRow == NULL)
     657               0 :             goto end;
     658                 : 
     659                 :         /* Unapply JSON encoding */
     660             260 :         for (i = 0; pszRow[i] != '\0'; i++)
     661                 :         {
     662             256 :             unsigned char c = ((GByte*)pszRow)[i];
     663             256 :             if (c >= 93) c--;
     664             256 :             if (c >= 35) c--;
     665             256 :             if (c < 32)
     666                 :             {
     667               0 :                 CPLDebug("MBTILES", "Invalid character at byte %d", i);
     668               0 :                 break;
     669                 :             }
     670             256 :             c -= 32;
     671             256 :             ((GByte*)pszRow)[i] = c;
     672                 :         }
     673                 : 
     674               4 :         if (pszRow[i] == '\0')
     675                 :         {
     676               4 :             char* pszEnd = pszRow + i;
     677                 : 
     678               4 :             int iCol = 0;
     679               4 :             i = 0;
     680               4 :             int nKey = -1;
     681              64 :             while(pszRow + i < pszEnd)
     682                 :             {
     683              60 :                 int len = 0;
     684              60 :                 unsigned int res = utf8decode(pszRow + i, pszEnd, &len);
     685                 : 
     686                 :                 /* Invalid UTF8 ? */
     687              60 :                 if (res > 127 && len == 1)
     688               0 :                     break;
     689                 : 
     690              60 :                 if (iCol == nColInBlock)
     691                 :                 {
     692               4 :                     nKey = (int)res;
     693                 :                     //CPLDebug("MBTILES", "Key index = %d", nKey);
     694               4 :                     break;
     695                 :                 }
     696              56 :                 i += len;
     697              56 :                 iCol ++;
     698                 :             }
     699                 : 
     700                 :             /* Find key */
     701               4 :             json_object* poKeys = json_object_object_get(jsobj, "keys");
     702               4 :             if (nKey >= 0 && poKeys != NULL &&
     703                 :                 json_object_is_type(poKeys, json_type_array) &&
     704                 :                 nKey < json_object_array_length(poKeys))
     705                 :             {
     706               4 :                 json_object* poKey = json_object_array_get_idx(poKeys, nKey);
     707               4 :                 if (poKey != NULL && json_object_is_type(poKey, json_type_string))
     708                 :                 {
     709               4 :                     pszKey = CPLStrdup(json_object_get_string(poKey));
     710                 :                 }
     711                 :             }
     712                 :         }
     713                 : 
     714               4 :         CPLFree(pszRow);
     715                 :     }
     716                 : 
     717                 : end:
     718               4 :     if (jsobj)
     719               4 :         json_object_put(jsobj);
     720               4 :     if (pabyUncompressed)
     721               4 :         CPLFree(pabyUncompressed);
     722               4 :     if (hFeat)
     723               4 :         OGR_F_Destroy(hFeat);
     724               4 :     if (hSQLLyr)
     725               4 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
     726                 : 
     727               4 :     return pszKey;
     728                 : }
     729                 : 
     730                 : /************************************************************************/
     731                 : /*                         GetMetadataItem()                            */
     732                 : /************************************************************************/
     733                 : 
     734               4 : const char *MBTilesBand::GetMetadataItem( const char * pszName,
     735                 :                                           const char * pszDomain )
     736                 : {
     737               4 :     MBTilesDataset* poGDS = (MBTilesDataset*) poDS;
     738                 : 
     739                 : /* ==================================================================== */
     740                 : /*      LocationInfo handling.                                          */
     741                 : /* ==================================================================== */
     742               4 :     if( pszDomain != NULL
     743                 :         && EQUAL(pszDomain,"LocationInfo")
     744                 :         && (EQUALN(pszName,"Pixel_",6) || EQUALN(pszName,"GeoPixel_",9)) )
     745                 :     {
     746                 :         int iPixel, iLine;
     747                 : 
     748               4 :         if (!poGDS->HasNonEmptyGrids())
     749               0 :             return NULL;
     750                 : 
     751                 : /* -------------------------------------------------------------------- */
     752                 : /*      What pixel are we aiming at?                                    */
     753                 : /* -------------------------------------------------------------------- */
     754               4 :         if( EQUALN(pszName,"Pixel_",6) )
     755                 :         {
     756               0 :             if( sscanf( pszName+6, "%d_%d", &iPixel, &iLine ) != 2 )
     757               0 :                 return NULL;
     758                 :         }
     759               4 :         else if( EQUALN(pszName,"GeoPixel_",9) )
     760                 :         {
     761                 :             double adfGeoTransform[6];
     762                 :             double adfInvGeoTransform[6];
     763                 :             double dfGeoX, dfGeoY;
     764                 : 
     765               4 :             if( sscanf( pszName+9, "%lf_%lf", &dfGeoX, &dfGeoY ) != 2 )
     766               0 :                 return NULL;
     767                 : 
     768               4 :             if( GetDataset() == NULL )
     769               0 :                 return NULL;
     770                 : 
     771               4 :             if( GetDataset()->GetGeoTransform( adfGeoTransform ) != CE_None )
     772               0 :                 return NULL;
     773                 : 
     774               4 :             if( !GDALInvGeoTransform( adfGeoTransform, adfInvGeoTransform ) )
     775               0 :                 return NULL;
     776                 : 
     777                 :             iPixel = (int) floor(
     778               4 :                 adfInvGeoTransform[0]
     779               4 :                 + adfInvGeoTransform[1] * dfGeoX
     780               4 :                 + adfInvGeoTransform[2] * dfGeoY );
     781                 :             iLine = (int) floor(
     782               4 :                 adfInvGeoTransform[3]
     783               4 :                 + adfInvGeoTransform[4] * dfGeoX
     784               4 :                 + adfInvGeoTransform[5] * dfGeoY );
     785                 :         }
     786                 :         else
     787               0 :             return NULL;
     788                 : 
     789               4 :         if( iPixel < 0 || iLine < 0
     790                 :             || iPixel >= GetXSize()
     791                 :             || iLine >= GetYSize() )
     792               0 :             return NULL;
     793                 : 
     794               4 :         int nTileColumn = -1, nTileRow = -1, nZoomLevel = -1;
     795               4 :         char* pszKey = poGDS->FindKey(iPixel, iLine, nTileColumn, nTileRow, nZoomLevel);
     796                 : 
     797               4 :         if (pszKey != NULL)
     798                 :         {
     799                 :             //CPLDebug("MBTILES", "Key = %s", pszKey);
     800                 : 
     801               4 :             osLocationInfo = "<LocationInfo>";
     802               4 :             osLocationInfo += "<Key>";
     803               4 :             char* pszXMLEscaped = CPLEscapeString(pszKey, -1, CPLES_XML_BUT_QUOTES);
     804               4 :             osLocationInfo += pszXMLEscaped;
     805               4 :             CPLFree(pszXMLEscaped);
     806               4 :             osLocationInfo += "</Key>";
     807                 : 
     808               8 :             if (OGR_DS_GetLayerByName(poGDS->hDS, "grid_data") != NULL &&
     809                 :                 strchr(pszKey, '\'') == NULL)
     810                 :             {
     811                 :                 const char* pszSQL;
     812                 :                 OGRLayerH hSQLLyr;
     813                 :                 OGRFeatureH hFeat;
     814                 : 
     815                 :                 pszSQL = CPLSPrintf("SELECT key_json FROM keymap WHERE "
     816                 :                                     "key_name = '%s'",
     817               4 :                                     pszKey);
     818               4 :                 CPLDebug("MBTILES", "%s", pszSQL);
     819               4 :                 hSQLLyr = OGR_DS_ExecuteSQL(poGDS->hDS, pszSQL, NULL, NULL);
     820               4 :                 if (hSQLLyr)
     821                 :                 {
     822               4 :                     hFeat = OGR_L_GetNextFeature(hSQLLyr);
     823               4 :                     if (hFeat != NULL && OGR_F_IsFieldSet(hFeat, 0))
     824                 :                     {
     825               4 :                         const char* pszJSon = OGR_F_GetFieldAsString(hFeat, 0);
     826                 :                         //CPLDebug("MBTILES", "JSon = %s", pszJSon);
     827                 : 
     828               4 :                         osLocationInfo += "<JSon>";
     829                 : #ifdef CPLES_XML_BUT_QUOTES
     830               4 :                         pszXMLEscaped = CPLEscapeString(pszJSon, -1, CPLES_XML_BUT_QUOTES);
     831                 : #else
     832                 :                         pszXMLEscaped = CPLEscapeString(pszJSon, -1, CPLES_XML);
     833                 : #endif
     834               4 :                         osLocationInfo += pszXMLEscaped;
     835               4 :                         CPLFree(pszXMLEscaped);
     836               4 :                         osLocationInfo += "</JSon>";
     837                 :                     }
     838               4 :                     OGR_F_Destroy(hFeat);
     839                 :                 }
     840               4 :                 OGR_DS_ReleaseResultSet(poGDS->hDS, hSQLLyr);
     841                 :             }
     842                 : 
     843               4 :             osLocationInfo += "</LocationInfo>";
     844                 : 
     845               4 :             CPLFree(pszKey);
     846                 : 
     847               4 :             return osLocationInfo.c_str();
     848                 :         }
     849                 : 
     850               0 :         return NULL;
     851                 :     }
     852                 :     else
     853               0 :         return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     854                 : }
     855                 : 
     856                 : /************************************************************************/
     857                 : /*                         GetOverviewCount()                           */
     858                 : /************************************************************************/
     859                 : 
     860               2 : int MBTilesBand::GetOverviewCount()
     861                 : {
     862               2 :     MBTilesDataset* poGDS = (MBTilesDataset*) poDS;
     863                 : 
     864               2 :     if (poGDS->nResolutions >= 1)
     865               2 :         return poGDS->nResolutions;
     866                 :     else
     867               0 :         return GDALPamRasterBand::GetOverviewCount();
     868                 : }
     869                 : 
     870                 : /************************************************************************/
     871                 : /*                              GetOverview()                           */
     872                 : /************************************************************************/
     873                 : 
     874               8 : GDALRasterBand* MBTilesBand::GetOverview(int nLevel)
     875                 : {
     876               8 :     MBTilesDataset* poGDS = (MBTilesDataset*) poDS;
     877                 : 
     878               8 :     if (poGDS->nResolutions == 0)
     879               0 :         return GDALPamRasterBand::GetOverview(nLevel);
     880                 : 
     881               8 :     if (nLevel < 0 || nLevel >= poGDS->nResolutions)
     882               0 :         return NULL;
     883                 : 
     884               8 :     GDALDataset* poOvrDS = poGDS->papoOverviews[nLevel];
     885               8 :     if (poOvrDS)
     886               8 :         return poOvrDS->GetRasterBand(nBand);
     887                 :     else
     888               0 :         return NULL;
     889                 : }
     890                 : 
     891                 : /************************************************************************/
     892                 : /*                   GetColorInterpretation()                           */
     893                 : /************************************************************************/
     894                 : 
     895               6 : GDALColorInterp MBTilesBand::GetColorInterpretation()
     896                 : {
     897               6 :     MBTilesDataset* poGDS = (MBTilesDataset*) poDS;
     898               6 :     if (poGDS->nBands == 1)
     899                 :     {
     900               0 :         return GCI_GrayIndex;
     901                 :     }
     902               6 :     else if (poGDS->nBands == 3 || poGDS->nBands == 4)
     903                 :     {
     904               6 :         if (nBand == 1)
     905               2 :             return GCI_RedBand;
     906               4 :         else if (nBand == 2)
     907               2 :             return GCI_GreenBand;
     908               2 :         else if (nBand == 3)
     909               2 :             return GCI_BlueBand;
     910               0 :         else if (nBand == 4)
     911               0 :             return GCI_AlphaBand;
     912                 :     }
     913                 : 
     914               0 :     return GCI_Undefined;
     915                 : }
     916                 : 
     917                 : /************************************************************************/
     918                 : /*                         MBTilesDataset()                          */
     919                 : /************************************************************************/
     920                 : 
     921               4 : MBTilesDataset::MBTilesDataset()
     922                 : {
     923               4 :     bMustFree = FALSE;
     924               4 :     nLevel = 0;
     925               4 :     poMainDS = NULL;
     926               4 :     nResolutions = 0;
     927               4 :     hDS = NULL;
     928               4 :     papoOverviews = NULL;
     929               4 :     papszMetadata = NULL;
     930                 :     papszImageStructure =
     931               4 :         CSLAddString(NULL, "INTERLEAVE=PIXEL");
     932               4 :     nMinTileCol = nMinTileRow = 0;
     933               4 :     nMinLevel = 0;
     934               4 :     bFetchedMetadata = FALSE;
     935               4 :     bHasNonEmptyGrids = -1;
     936               4 : }
     937                 : 
     938                 : /************************************************************************/
     939                 : /*                          MBTilesDataset()                            */
     940                 : /************************************************************************/
     941                 : 
     942              18 : MBTilesDataset::MBTilesDataset(MBTilesDataset* poMainDS, int nLevel)
     943                 : {
     944              18 :     bMustFree = FALSE;
     945              18 :     this->nLevel = nLevel;
     946              18 :     this->poMainDS = poMainDS;
     947              18 :     nResolutions = poMainDS->nResolutions - nLevel;
     948              18 :     hDS = poMainDS->hDS;
     949              18 :     papoOverviews = poMainDS->papoOverviews + nLevel;
     950              18 :     papszMetadata = poMainDS->papszMetadata;
     951              18 :     papszImageStructure =  poMainDS->papszImageStructure;
     952                 : 
     953              18 :     nRasterXSize = poMainDS->nRasterXSize / (1 << nLevel);
     954              18 :     nRasterYSize = poMainDS->nRasterYSize / (1 << nLevel);
     955              18 :     nMinTileCol = nMinTileRow = 0;
     956              18 :     nMinLevel = 0;
     957              18 :     bFetchedMetadata = FALSE;
     958              18 :     bHasNonEmptyGrids = -1;
     959              18 : }
     960                 : 
     961                 : /************************************************************************/
     962                 : /*                        ~MBTilesDataset()                             */
     963                 : /************************************************************************/
     964                 : 
     965              22 : MBTilesDataset::~MBTilesDataset()
     966                 : {
     967              22 :     CloseDependentDatasets();
     968              22 : }
     969                 : 
     970                 : /************************************************************************/
     971                 : /*                      CloseDependentDatasets()                        */
     972                 : /************************************************************************/
     973                 : 
     974              22 : int MBTilesDataset::CloseDependentDatasets()
     975                 : {
     976              22 :     int bRet = GDALPamDataset::CloseDependentDatasets();
     977                 : 
     978              26 :     if (poMainDS == NULL && !bMustFree)
     979                 :     {
     980               4 :         CSLDestroy(papszMetadata);
     981               4 :         papszMetadata = NULL;
     982               4 :         CSLDestroy(papszImageStructure);
     983               4 :         papszImageStructure = NULL;
     984                 : 
     985                 :         int i;
     986                 : 
     987               4 :         if (papoOverviews)
     988                 :         {
     989              22 :             for(i=0;i<nResolutions;i++)
     990                 :             {
     991              36 :                 if (papoOverviews[i] != NULL &&
     992              18 :                     papoOverviews[i]->bMustFree)
     993                 :                 {
     994               0 :                     papoOverviews[i]->poMainDS = NULL;
     995                 :                 }
     996              18 :                 delete papoOverviews[i];
     997                 :             }
     998               4 :             CPLFree(papoOverviews);
     999               4 :             papoOverviews = NULL;
    1000               4 :             nResolutions = 0;
    1001               4 :             bRet = TRUE;
    1002                 :         }
    1003                 : 
    1004               4 :         if (hDS != NULL)
    1005               4 :             OGRReleaseDataSource(hDS);
    1006               4 :         hDS = NULL;
    1007                 :     }
    1008              18 :     else if (poMainDS != NULL && bMustFree)
    1009                 :     {
    1010               0 :         poMainDS->papoOverviews[nLevel-1] = NULL;
    1011               0 :         delete poMainDS;
    1012               0 :         poMainDS = NULL;
    1013               0 :         bRet = TRUE;
    1014                 :     }
    1015                 : 
    1016              22 :     return bRet;
    1017                 : }
    1018                 : 
    1019                 : /************************************************************************/
    1020                 : /*                          GetGeoTransform()                           */
    1021                 : /************************************************************************/
    1022                 : 
    1023                 : //#define MAX_GM 20037508.3427892
    1024                 : #define MAX_GM 20037500.
    1025                 : 
    1026               6 : CPLErr MBTilesDataset::GetGeoTransform(double* padfGeoTransform)
    1027                 : {
    1028               6 :     int nMaxLevel = nMinLevel + nResolutions;
    1029               6 :     if (nMaxLevel == 0)
    1030                 :     {
    1031               0 :         padfGeoTransform[0] = -MAX_GM;
    1032               0 :         padfGeoTransform[1] = 2 * MAX_GM / nRasterXSize;
    1033               0 :         padfGeoTransform[2] = 0;
    1034               0 :         padfGeoTransform[3] = MAX_GM;
    1035               0 :         padfGeoTransform[4] = 0;
    1036               0 :         padfGeoTransform[5] = -2 * MAX_GM / nRasterYSize;
    1037                 :     }
    1038                 :     else
    1039                 :     {
    1040               6 :         int nMaxTileCol = nMinTileCol + nRasterXSize / 256;
    1041               6 :         int nMaxTileRow = nMinTileRow + nRasterYSize / 256;
    1042               6 :         int nMiddleTile = (1 << nMaxLevel) / 2;
    1043               6 :         padfGeoTransform[0] = 2 * MAX_GM * (nMinTileCol - nMiddleTile) / (1 << nMaxLevel);
    1044               6 :         padfGeoTransform[1] = 2 * MAX_GM * (nMaxTileCol - nMinTileCol) / (1 << nMaxLevel) / nRasterXSize;
    1045               6 :         padfGeoTransform[2] = 0;
    1046               6 :         padfGeoTransform[3] = 2 * MAX_GM * (nMaxTileRow - nMiddleTile) / (1 << nMaxLevel);
    1047               6 :         padfGeoTransform[4] = 0;
    1048               6 :         padfGeoTransform[5] = -2 * MAX_GM * (nMaxTileRow - nMinTileRow) / (1 << nMaxLevel) / nRasterYSize;
    1049                 :     }
    1050               6 :     return CE_None;
    1051                 : }
    1052                 : 
    1053                 : /************************************************************************/
    1054                 : /*                         GetProjectionRef()                           */
    1055                 : /************************************************************************/
    1056                 : 
    1057               2 : const char* MBTilesDataset::GetProjectionRef()
    1058                 : {
    1059               2 :     return "PROJCS[\"WGS 84 / Pseudo-Mercator\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],PROJECTION[\"Mercator_1SP\"],PARAMETER[\"central_meridian\",0],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH],EXTENSION[\"PROJ4\",\"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs\"],AUTHORITY[\"EPSG\",\"3857\"]]";
    1060                 : }
    1061                 : 
    1062                 : /************************************************************************/
    1063                 : /*                            GetMetadata()                             */
    1064                 : /************************************************************************/
    1065                 : 
    1066               2 : char** MBTilesDataset::GetMetadata( const char * pszDomain )
    1067                 : {
    1068               2 :     if (pszDomain != NULL && !EQUAL(pszDomain, ""))
    1069               0 :         return GDALPamDataset::GetMetadata(pszDomain);
    1070                 : 
    1071               2 :     if (bFetchedMetadata)
    1072               0 :         return aosList.List();
    1073                 : 
    1074               2 :     bFetchedMetadata = TRUE;
    1075                 : 
    1076                 :     OGRLayerH hSQLLyr = OGR_DS_ExecuteSQL(hDS,
    1077               2 :             "SELECT name, value FROM metadata", NULL, NULL);
    1078               2 :     if (hSQLLyr == NULL)
    1079               0 :         return NULL;
    1080                 : 
    1081               2 :     if (OGR_FD_GetFieldCount(OGR_L_GetLayerDefn(hSQLLyr)) != 2)
    1082                 :     {
    1083               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1084               0 :         return NULL;
    1085                 :     }
    1086                 : 
    1087                 :     OGRFeatureH hFeat;
    1088               6 :     while( (hFeat = OGR_L_GetNextFeature(hSQLLyr)) != NULL )
    1089                 :     {
    1090               2 :         if (OGR_F_IsFieldSet(hFeat, 0) && OGR_F_IsFieldSet(hFeat, 1))
    1091                 :         {
    1092               2 :             const char* pszName = OGR_F_GetFieldAsString(hFeat, 0);
    1093               2 :             const char* pszValue = OGR_F_GetFieldAsString(hFeat, 1);
    1094               2 :             if (pszValue[0] != '\0' &&
    1095                 :                 strncmp(pszValue, "function(",9) != 0 &&
    1096                 :                 strstr(pszValue, "<img ") == NULL &&
    1097                 :                 strstr(pszValue, "<p>") == NULL &&
    1098                 :                 strstr(pszValue, "</p>") == NULL &&
    1099                 :                 strstr(pszValue, "<div") == NULL)
    1100                 :             {
    1101               2 :                 aosList.AddNameValue(pszName, pszValue);
    1102                 :             }
    1103                 :         }
    1104               2 :         OGR_F_Destroy(hFeat);
    1105                 :     }
    1106               2 :     OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1107                 : 
    1108               2 :     return aosList.List();
    1109                 : }
    1110                 : 
    1111                 : /************************************************************************/
    1112                 : /*                             Identify()                               */
    1113                 : /************************************************************************/
    1114                 : 
    1115           21452 : int MBTilesDataset::Identify(GDALOpenInfo* poOpenInfo)
    1116                 : {
    1117           21452 :     if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MBTILES") &&
    1118                 :         poOpenInfo->nHeaderBytes >= 1024 &&
    1119                 :         EQUALN((const char*)poOpenInfo->pabyHeader, "SQLite Format 3", 15))
    1120                 :     {
    1121               4 :         return TRUE;
    1122                 :     }
    1123                 : 
    1124           21448 :     return FALSE;
    1125                 : }
    1126                 : 
    1127                 : /************************************************************************/
    1128                 : /*                        MBTilesGetMinMaxZoomLevel()                   */
    1129                 : /************************************************************************/
    1130                 : 
    1131                 : static
    1132               4 : int MBTilesGetMinMaxZoomLevel(OGRDataSourceH hDS, int bHasMap,
    1133                 :                                 int &nMinLevel, int &nMaxLevel)
    1134                 : {
    1135                 :     const char* pszSQL;
    1136                 :     OGRLayerH hSQLLyr;
    1137                 :     OGRFeatureH hFeat;
    1138               4 :     int bHasMinMaxLevel = FALSE;
    1139                 : 
    1140                 :     pszSQL = "SELECT value FROM metadata WHERE name = 'minzoom' UNION ALL "
    1141               4 :              "SELECT value FROM metadata WHERE name = 'maxzoom'";
    1142               4 :     CPLDebug("MBTILES", "%s", pszSQL);
    1143               4 :     hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1144               4 :     if (hSQLLyr)
    1145                 :     {
    1146               2 :         hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1147               2 :         if (hFeat)
    1148                 :         {
    1149               2 :             int bHasMinLevel = FALSE;
    1150               2 :             if (OGR_F_IsFieldSet(hFeat, 0))
    1151                 :             {
    1152               2 :                 nMinLevel = OGR_F_GetFieldAsInteger(hFeat, 0);
    1153               2 :                 bHasMinLevel = TRUE;
    1154                 :             }
    1155               2 :             OGR_F_Destroy(hFeat);
    1156                 : 
    1157               2 :             if (bHasMinLevel)
    1158                 :             {
    1159               2 :                 hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1160               2 :                 if (hFeat)
    1161                 :                 {
    1162               2 :                     if (OGR_F_IsFieldSet(hFeat, 0))
    1163                 :                     {
    1164               2 :                         nMaxLevel = OGR_F_GetFieldAsInteger(hFeat, 0);
    1165               2 :                         bHasMinMaxLevel = TRUE;
    1166                 :                     }
    1167               2 :                     OGR_F_Destroy(hFeat);
    1168                 :                 }
    1169                 :             }
    1170                 :         }
    1171                 : 
    1172               2 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1173                 :     }
    1174                 : 
    1175               4 :     if( !bHasMinMaxLevel )
    1176                 :     {
    1177                 : #define OPTIMIZED_FOR_VSICURL
    1178                 : #ifdef  OPTIMIZED_FOR_VSICURL
    1179                 :         int iLevel;
    1180               4 :         for(iLevel = 0; nMinLevel < 0 && iLevel < 16; iLevel ++)
    1181                 :         {
    1182                 :             pszSQL = CPLSPrintf(
    1183                 :                 "SELECT zoom_level FROM %s WHERE zoom_level = %d LIMIT 1",
    1184               2 :                 (bHasMap) ? "map" : "tiles", iLevel);
    1185               2 :             CPLDebug("MBTILES", "%s", pszSQL);
    1186               2 :             hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1187               2 :             if (hSQLLyr)
    1188                 :             {
    1189               2 :                 hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1190               2 :                 if (hFeat)
    1191                 :                 {
    1192               2 :                     nMinLevel = iLevel;
    1193               2 :                     OGR_F_Destroy(hFeat);
    1194                 :                 }
    1195               2 :                 OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1196                 :             }
    1197                 :         }
    1198                 : 
    1199               2 :         if (nMinLevel < 0)
    1200               0 :             return FALSE;
    1201                 : 
    1202              66 :         for(iLevel = 32; nMaxLevel < 0 && iLevel >= nMinLevel; iLevel --)
    1203                 :         {
    1204                 :             pszSQL = CPLSPrintf(
    1205                 :                 "SELECT zoom_level FROM %s WHERE zoom_level = %d LIMIT 1",
    1206              64 :                 (bHasMap) ? "map" : "tiles", iLevel);
    1207              64 :             CPLDebug("MBTILES", "%s", pszSQL);
    1208              64 :             hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1209              64 :             if (hSQLLyr)
    1210                 :             {
    1211               2 :                 hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1212               2 :                 if (hFeat)
    1213                 :                 {
    1214               2 :                     nMaxLevel = iLevel;
    1215               2 :                     bHasMinMaxLevel = TRUE;
    1216               2 :                     OGR_F_Destroy(hFeat);
    1217                 :                 }
    1218               2 :                 OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1219                 :             }
    1220                 :         }
    1221                 : #else
    1222                 :         pszSQL = "SELECT min(zoom_level), max(zoom_level) FROM tiles";
    1223                 :         CPLDebug("MBTILES", "%s", pszSQL);
    1224                 :         hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1225                 :         if (hSQLLyr == NULL)
    1226                 :         {
    1227                 :             return FALSE;
    1228                 :         }
    1229                 : 
    1230                 :         hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1231                 :         if (hFeat == NULL)
    1232                 :         {
    1233                 :             OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1234                 :             return FALSE;
    1235                 :         }
    1236                 : 
    1237                 :         if (OGR_F_IsFieldSet(hFeat, 0) && OGR_F_IsFieldSet(hFeat, 1))
    1238                 :         {
    1239                 :             nMinLevel = OGR_F_GetFieldAsInteger(hFeat, 0);
    1240                 :             nMaxLevel = OGR_F_GetFieldAsInteger(hFeat, 1);
    1241                 :             bHasMinMaxLevel = TRUE;
    1242                 :         }
    1243                 : 
    1244                 :         OGR_F_Destroy(hFeat);
    1245                 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1246                 : #endif
    1247                 :     }
    1248                 : 
    1249               4 :     return bHasMinMaxLevel;
    1250                 : }
    1251                 : 
    1252                 : /************************************************************************/
    1253                 : /*                           MBTilesGetBounds()                         */
    1254                 : /************************************************************************/
    1255                 : 
    1256                 : static
    1257               4 : int MBTilesGetBounds(OGRDataSourceH hDS, int nMinLevel, int nMaxLevel,
    1258                 :                      int& nMinTileRow, int& nMaxTileRow,
    1259                 :                      int& nMinTileCol, int &nMaxTileCol)
    1260                 : {
    1261                 :     const char* pszSQL;
    1262               4 :     int bHasBounds = FALSE;
    1263                 :     OGRLayerH hSQLLyr;
    1264                 :     OGRFeatureH hFeat;
    1265                 : 
    1266               4 :     pszSQL = "SELECT value FROM metadata WHERE name = 'bounds'";
    1267               4 :     CPLDebug("MBTILES", "%s", pszSQL);
    1268               4 :     hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1269               4 :     if (hSQLLyr)
    1270                 :     {
    1271               4 :         hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1272               4 :         if (hFeat != NULL)
    1273                 :         {
    1274               4 :             const char* pszBounds = OGR_F_GetFieldAsString(hFeat, 0);
    1275               4 :             char** papszTokens = CSLTokenizeString2(pszBounds, ",", 0);
    1276              36 :             if (CSLCount(papszTokens) != 4 ||
    1277               4 :                 fabs(atof(papszTokens[0])) > 180 ||
    1278               4 :                 fabs(atof(papszTokens[1])) > 86 ||
    1279               4 :                 fabs(atof(papszTokens[2])) > 180 ||
    1280               4 :                 fabs(atof(papszTokens[3])) > 86 ||
    1281               8 :                 atof(papszTokens[0]) > atof(papszTokens[2]) ||
    1282               8 :                 atof(papszTokens[1]) > atof(papszTokens[3]))
    1283                 :             {
    1284               0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for 'bounds' metadata");
    1285               0 :                 CSLDestroy(papszTokens);
    1286               0 :                 OGR_F_Destroy(hFeat);
    1287               0 :                 OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1288               0 :                 return FALSE;
    1289                 :             }
    1290                 : 
    1291                 :             #define FORTPI      0.78539816339744833
    1292                 :             /* Latitude to Google-mercator northing */
    1293                 :             #define LAT_TO_NORTHING(lat) \
    1294                 :                 6378137 * log(tan(FORTPI + .5 * (lat) / 180 * (4 * FORTPI)))
    1295                 : 
    1296               4 :             nMinTileCol = (int)(((atof(papszTokens[0]) + 180) / 360) * (1 << nMaxLevel));
    1297               4 :             nMaxTileCol = (int)(((atof(papszTokens[2]) + 180) / 360) * (1 << nMaxLevel));
    1298               4 :             nMinTileRow = (int)(0.5 + ((LAT_TO_NORTHING(atof(papszTokens[1])) + MAX_GM) / (2* MAX_GM)) * (1 << nMaxLevel));
    1299               4 :             nMaxTileRow = (int)(0.5 + ((LAT_TO_NORTHING(atof(papszTokens[3])) + MAX_GM) / (2* MAX_GM)) * (1 << nMaxLevel));
    1300                 : 
    1301               4 :             bHasBounds = TRUE;
    1302                 : 
    1303               4 :             CSLDestroy(papszTokens);
    1304                 : 
    1305               4 :             OGR_F_Destroy(hFeat);
    1306                 :         }
    1307               4 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1308                 :     }
    1309                 : 
    1310               4 :     if (!bHasBounds)
    1311                 :     {
    1312                 :         pszSQL = CPLSPrintf("SELECT min(tile_column), max(tile_column), "
    1313                 :                             "min(tile_row), max(tile_row) FROM tiles "
    1314               0 :                             "WHERE zoom_level = %d", nMaxLevel);
    1315               0 :         CPLDebug("MBTILES", "%s", pszSQL);
    1316               0 :         hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1317               0 :         if (hSQLLyr == NULL)
    1318                 :         {
    1319               0 :             return FALSE;
    1320                 :         }
    1321                 : 
    1322               0 :         hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1323               0 :         if (hFeat == NULL)
    1324                 :         {
    1325               0 :             OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1326               0 :             return FALSE;
    1327                 :         }
    1328                 : 
    1329               0 :         if (OGR_F_IsFieldSet(hFeat, 0) &&
    1330                 :             OGR_F_IsFieldSet(hFeat, 1) &&
    1331                 :             OGR_F_IsFieldSet(hFeat, 2) &&
    1332                 :             OGR_F_IsFieldSet(hFeat, 3))
    1333                 :         {
    1334               0 :             nMinTileCol = OGR_F_GetFieldAsInteger(hFeat, 0);
    1335               0 :             nMaxTileCol = OGR_F_GetFieldAsInteger(hFeat, 1);
    1336               0 :             nMinTileRow = OGR_F_GetFieldAsInteger(hFeat, 2);
    1337               0 :             nMaxTileRow = OGR_F_GetFieldAsInteger(hFeat, 3);
    1338               0 :             bHasBounds = TRUE;
    1339                 :         }
    1340                 : 
    1341               0 :         OGR_F_Destroy(hFeat);
    1342               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1343                 :     }
    1344                 : 
    1345               4 :     return bHasBounds;
    1346                 : }
    1347                 : 
    1348                 : /************************************************************************/
    1349                 : /*                        MBTilesCurlReadCbk()                          */
    1350                 : /************************************************************************/
    1351                 : 
    1352                 : /* We spy the data received by CURL for the initial request where we try */
    1353                 : /* to get a first tile to see its characteristics. We just need the header */
    1354                 : /* to determine that, so let's make VSICurl stop reading after we have found it */
    1355                 : 
    1356              12 : static int MBTilesCurlReadCbk(VSILFILE* fp,
    1357                 :                               void *pabyBuffer, size_t nBufferSize,
    1358                 :                               void* pfnUserData)
    1359                 : {
    1360                 :     const GByte abyPNGSig[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, /* PNG signature */
    1361                 :                                 0x00, 0x00, 0x00, 0x0D, /* IHDR length */
    1362              12 :                                 0x49, 0x48, 0x44, 0x52  /* IHDR chunk */ };
    1363                 : 
    1364                 :     /* JPEG SOF0 (Start Of Frame 0) marker */
    1365                 :     const GByte abyJPEG1CompSig[] = { 0xFF, 0xC0, /* marker */
    1366                 :                                       0x00, 0x0B, /* data length = 8 + 1 * 3 */
    1367                 :                                       0x08,       /* depth : 8 bit */
    1368                 :                                       0x01, 0x00, /* width : 256 */
    1369                 :                                       0x01, 0x00, /* height : 256 */
    1370                 :                                       0x01        /* components : 1 */
    1371              12 :                                     };
    1372                 :     const GByte abyJPEG3CompSig[] = { 0xFF, 0xC0, /* marker */
    1373                 :                                       0x00, 0x11, /* data length = 8 + 3 * 3 */
    1374                 :                                       0x08,       /* depth : 8 bit */
    1375                 :                                       0x01, 0x00, /* width : 256 */
    1376                 :                                       0x01, 0x00, /* width : 256 */
    1377                 :                                       0x03        /* components : 3 */
    1378              12 :                                      };
    1379                 : 
    1380                 :     int i;
    1381           16328 :     for(i = 0; i < (int)nBufferSize - (int)sizeof(abyPNGSig); i++)
    1382                 :     {
    1383           16316 :         if (memcmp(((GByte*)pabyBuffer) + i, abyPNGSig, sizeof(abyPNGSig)) == 0 &&
    1384                 :             i + sizeof(abyPNGSig) + 4 + 4 + 1 + 1 < nBufferSize)
    1385                 :         {
    1386               0 :             GByte* ptr = ((GByte*)(pabyBuffer)) + i + (int)sizeof(abyPNGSig);
    1387                 : 
    1388                 :             int nWidth;
    1389               0 :             memcpy(&nWidth, ptr, 4);
    1390               0 :             CPL_MSBPTR32(&nWidth);
    1391               0 :             ptr += 4;
    1392                 : 
    1393                 :             int nHeight;
    1394               0 :             memcpy(&nHeight, ptr, 4);
    1395               0 :             CPL_MSBPTR32(&nHeight);
    1396               0 :             ptr += 4;
    1397                 : 
    1398               0 :             GByte nDepth = *ptr;
    1399               0 :             ptr += 1;
    1400                 : 
    1401               0 :             GByte nColorType = *ptr;
    1402                 :             CPLDebug("MBTILES", "PNG: nWidth=%d nHeight=%d depth=%d nColorType=%d",
    1403               0 :                         nWidth, nHeight, nDepth, nColorType);
    1404                 : 
    1405               0 :             int* pnBands = (int*) pfnUserData;
    1406               0 :             *pnBands = -2;
    1407               0 :             if (nWidth == 256 && nHeight == 256 && nDepth == 8)
    1408                 :             {
    1409               0 :                 if (nColorType == 0)
    1410               0 :                     *pnBands = 1; /* Gray */
    1411               0 :                 else if (nColorType == 2)
    1412               0 :                     *pnBands = 3; /* RGB */
    1413               0 :                 else if (nColorType == 3)
    1414               0 :                     *pnBands = 3; /* palette -> RGB */
    1415               0 :                 else if (nColorType == 4)
    1416               0 :                     *pnBands = 2; /* Gray + alpha */
    1417               0 :                 else if (nColorType == 6)
    1418               0 :                     *pnBands = 4; /* RGB + alpha */
    1419                 :             }
    1420                 : 
    1421               0 :             return FALSE;
    1422                 :         }
    1423                 :     }
    1424                 : 
    1425           15702 :     for(i = 0; i < (int)nBufferSize - (int)sizeof(abyJPEG1CompSig); i++)
    1426                 :     {
    1427           15692 :         if (memcmp(((GByte*)pabyBuffer) + i, abyJPEG1CompSig, sizeof(abyJPEG1CompSig)) == 0)
    1428                 :         {
    1429                 :             CPLDebug("MBTILES", "JPEG: nWidth=%d nHeight=%d depth=%d nBands=%d",
    1430               0 :                         256, 256, 8, 1);
    1431                 : 
    1432               0 :             int* pnBands = (int*) pfnUserData;
    1433               0 :             *pnBands = 1;
    1434                 : 
    1435               0 :             return FALSE;
    1436                 :         }
    1437           15692 :         else if (memcmp(((GByte*)pabyBuffer) + i, abyJPEG3CompSig, sizeof(abyJPEG3CompSig)) == 0)
    1438                 :         {
    1439                 :             CPLDebug("MBTILES", "JPEG: nWidth=%d nHeight=%d depth=%d nBands=%d",
    1440               2 :                         256, 256, 8, 3);
    1441                 : 
    1442               2 :             int* pnBands = (int*) pfnUserData;
    1443               2 :             *pnBands = 3;
    1444                 : 
    1445               2 :             return FALSE;
    1446                 :         }
    1447                 :     }
    1448                 : 
    1449              10 :     return TRUE;
    1450                 : }
    1451                 : 
    1452                 : /************************************************************************/
    1453                 : /*                        MBTilesGetBandCount()                         */
    1454                 : /************************************************************************/
    1455                 : 
    1456                 : static
    1457               4 : int MBTilesGetBandCount(OGRDataSourceH &hDS, int nMinLevel, int nMaxLevel,
    1458                 :                         int nMinTileRow, int nMaxTileRow,
    1459                 :                         int nMinTileCol, int nMaxTileCol)
    1460                 : {
    1461                 :     OGRLayerH hSQLLyr;
    1462                 :     OGRFeatureH hFeat;
    1463                 :     const char* pszSQL;
    1464               4 :     VSILFILE* fpCURLOGR = NULL;
    1465                 : 
    1466               4 :     int nBands = -1;
    1467                 : 
    1468                 :     /* Small trick to get the VSILFILE associated with the OGR SQLite */
    1469                 :     /* DB */
    1470               4 :     CPLString osDSName(OGR_DS_GetName(hDS));
    1471               4 :     if (strncmp(osDSName.c_str(), "/vsicurl/", 9) == 0)
    1472                 :     {
    1473               2 :         CPLErrorReset();
    1474               2 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1475               2 :         hSQLLyr = OGR_DS_ExecuteSQL(hDS, "GetVSILFILE()", NULL, NULL);
    1476               2 :         CPLPopErrorHandler();
    1477               2 :         CPLErrorReset();
    1478               2 :         if (hSQLLyr != NULL)
    1479                 :         {
    1480               2 :             hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1481               2 :             if (hFeat)
    1482                 :             {
    1483               2 :                 if (OGR_F_IsFieldSet(hFeat, 0))
    1484                 :                 {
    1485               2 :                     const char* pszPointer = OGR_F_GetFieldAsString(hFeat, 0);
    1486               2 :                     fpCURLOGR = (VSILFILE* )CPLScanPointer( pszPointer, strlen(pszPointer) );
    1487                 :                 }
    1488               2 :                 OGR_F_Destroy(hFeat);
    1489                 :             }
    1490               2 :             OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1491                 :         }
    1492                 :     }
    1493                 : 
    1494                 :     pszSQL = CPLSPrintf("SELECT tile_data FROM tiles WHERE "
    1495                 :                             "tile_column = %d AND tile_row = %d AND zoom_level = %d",
    1496                 :                             (nMinTileCol  + nMaxTileCol) / 2,
    1497                 :                             (nMinTileRow  + nMaxTileRow) / 2,
    1498               4 :                             nMaxLevel);
    1499               4 :     CPLDebug("MBTILES", "%s", pszSQL);
    1500                 : 
    1501               4 :     if (fpCURLOGR)
    1502                 :     {
    1503                 :         /* Install a spy on the file connexion that will intercept */
    1504                 :         /* PNG or JPEG headers, to interrupt their downloading */
    1505                 :         /* once the header is found. Speeds up dataset opening. */
    1506               2 :         VSICurlInstallReadCbk(fpCURLOGR, MBTilesCurlReadCbk, &nBands, TRUE);
    1507                 : 
    1508               2 :         CPLErrorReset();
    1509               2 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1510               2 :         hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1511               2 :         CPLPopErrorHandler();
    1512                 : 
    1513               2 :         VSICurlUninstallReadCbk(fpCURLOGR);
    1514                 : 
    1515                 :         /* Did the spy intercept something interesting ? */
    1516               2 :         if (nBands != -1)
    1517                 :         {
    1518               2 :             CPLErrorReset();
    1519                 : 
    1520               2 :             OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1521               2 :             hSQLLyr = NULL;
    1522                 : 
    1523                 :             /* Re-open OGR SQLite DB, because with our spy we have simulated an I/O error */
    1524                 :             /* that SQLite will have difficulies to recover within the existing connection */
    1525                 :             /* No worry ! This will be fast because the /vsicurl/ cache has cached the already */
    1526                 :             /* read blocks */
    1527               2 :             OGRReleaseDataSource(hDS);
    1528               2 :             hDS = OGROpen(osDSName.c_str(), FALSE, NULL);
    1529               2 :             if (hDS == NULL)
    1530               0 :                 return -1;
    1531                 : 
    1532                 :             /* Unrecognized form of PNG. Error out */
    1533               2 :             if (nBands <= 0)
    1534               0 :                 return -1;
    1535                 : 
    1536               2 :             return nBands;
    1537                 :         }
    1538               0 :         else if (CPLGetLastErrorType() == CE_Failure)
    1539                 :         {
    1540               0 :             CPLError(CE_Failure, CPLGetLastErrorNo(), "%s", CPLGetLastErrorMsg());
    1541                 :         }
    1542                 :     }
    1543                 :     else
    1544                 :     {
    1545               2 :         hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1546                 :     }
    1547                 : 
    1548               2 :     if (hSQLLyr == NULL)
    1549                 :     {
    1550                 :         pszSQL = CPLSPrintf("SELECT tile_data FROM tiles WHERE "
    1551               0 :                             "zoom_level = %d LIMIT 1", nMaxLevel);
    1552               0 :         CPLDebug("MBTILES", "%s", pszSQL);
    1553               0 :         hSQLLyr = OGR_DS_ExecuteSQL(hDS, pszSQL, NULL, NULL);
    1554               0 :         if (hSQLLyr == NULL)
    1555               0 :             return -1;
    1556                 :     }
    1557                 : 
    1558               2 :     hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1559               2 :     if (hFeat == NULL)
    1560                 :     {
    1561               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1562               0 :         return -1;
    1563                 :     }
    1564                 : 
    1565               2 :     CPLString osMemFileName;
    1566               2 :     osMemFileName.Printf("/vsimem/%p", hSQLLyr);
    1567                 : 
    1568               2 :     int nDataSize = 0;
    1569               2 :     GByte* pabyData = OGR_F_GetFieldAsBinary(hFeat, 0, &nDataSize);
    1570                 : 
    1571                 :     VSIFCloseL(VSIFileFromMemBuffer( osMemFileName.c_str(), pabyData,
    1572               2 :                                     nDataSize, FALSE));
    1573                 : 
    1574                 :     GDALDatasetH hDSTile =
    1575               2 :         GDALOpenInternal(osMemFileName.c_str(), GA_ReadOnly, apszAllowedDrivers);
    1576               2 :     if (hDSTile == NULL)
    1577                 :     {
    1578               0 :         VSIUnlink(osMemFileName.c_str());
    1579               0 :         OGR_F_Destroy(hFeat);
    1580               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1581               0 :         return -1;
    1582                 :     }
    1583                 : 
    1584               2 :     nBands = GDALGetRasterCount(hDSTile);
    1585                 : 
    1586               2 :     if ((nBands != 1 && nBands != 3 && nBands != 4) ||
    1587                 :         GDALGetRasterXSize(hDSTile) != 256 ||
    1588                 :         GDALGetRasterYSize(hDSTile) != 256 ||
    1589                 :         GDALGetRasterDataType(GDALGetRasterBand(hDSTile, 1)) != GDT_Byte)
    1590                 :     {
    1591               0 :         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported tile characteristics");
    1592               0 :         GDALClose(hDSTile);
    1593               0 :         VSIUnlink(osMemFileName.c_str());
    1594               0 :         OGR_F_Destroy(hFeat);
    1595               0 :         OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1596               0 :         return -1;
    1597                 :     }
    1598                 : 
    1599               2 :     if (nBands == 1 &&
    1600                 :         GDALGetRasterColorTable(GDALGetRasterBand(hDSTile, 1)) != NULL)
    1601                 :     {
    1602               0 :         nBands = 3;
    1603                 :     }
    1604                 : 
    1605               2 :     GDALClose(hDSTile);
    1606               2 :     VSIUnlink(osMemFileName.c_str());
    1607               2 :     OGR_F_Destroy(hFeat);
    1608               2 :     OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1609                 : 
    1610               2 :     return nBands;
    1611                 : }
    1612                 : 
    1613                 : /************************************************************************/
    1614                 : /*                                Open()                                */
    1615                 : /************************************************************************/
    1616                 : 
    1617            2558 : GDALDataset* MBTilesDataset::Open(GDALOpenInfo* poOpenInfo)
    1618                 : {
    1619            2558 :     CPLString osFileName;
    1620            2558 :     CPLString osTableName;
    1621                 : 
    1622            2558 :     if (!Identify(poOpenInfo))
    1623            2554 :         return NULL;
    1624                 : 
    1625               4 :     if (OGRGetDriverCount() == 0)
    1626               0 :         OGRRegisterAll();
    1627                 : 
    1628                 : /* -------------------------------------------------------------------- */
    1629                 : /*      Open underlying OGR DB                                          */
    1630                 : /* -------------------------------------------------------------------- */
    1631                 : 
    1632               4 :     OGRDataSourceH hDS = OGROpen(poOpenInfo->pszFilename, FALSE, NULL);
    1633                 : 
    1634               4 :     MBTilesDataset* poDS = NULL;
    1635                 : 
    1636               4 :     if (hDS == NULL)
    1637               0 :         goto end;
    1638                 : 
    1639                 : /* -------------------------------------------------------------------- */
    1640                 : /*      Build dataset                                                   */
    1641                 : /* -------------------------------------------------------------------- */
    1642                 :     {
    1643               4 :         CPLString osMetadataTableName, osRasterTableName;
    1644               4 :         CPLString osSQL;
    1645                 :         OGRLayerH hMetadataLyr, hRasterLyr;
    1646                 :         OGRFeatureH hFeat;
    1647                 :         int nResolutions;
    1648                 :         int iBand, nBands, nBlockXSize, nBlockYSize;
    1649                 :         GDALDataType eDataType;
    1650               4 :         OGRLayerH hSQLLyr = NULL;
    1651               4 :         int nMinLevel = -1, nMaxLevel = -1;
    1652               4 :         int nMinTileRow = 0, nMaxTileRow = 0, nMinTileCol = 0, nMaxTileCol = 0;
    1653               4 :         int bHasBounds = FALSE;
    1654               4 :         int bHasMinMaxLevel = FALSE;
    1655                 :         int bHasMap;
    1656                 :         const char* pszBandCount;
    1657                 : 
    1658               4 :         osMetadataTableName = "metadata";
    1659                 : 
    1660               4 :         hMetadataLyr = OGR_DS_GetLayerByName(hDS, osMetadataTableName.c_str());
    1661               4 :         if (hMetadataLyr == NULL)
    1662                 :             goto end;
    1663                 : 
    1664               4 :         osRasterTableName += "tiles";
    1665                 : 
    1666               4 :         hRasterLyr = OGR_DS_GetLayerByName(hDS, osRasterTableName.c_str());
    1667               4 :         if (hRasterLyr == NULL)
    1668                 :             goto end;
    1669                 : 
    1670               4 :         bHasMap = OGR_DS_GetLayerByName(hDS, "map") != NULL;
    1671               4 :         if (bHasMap)
    1672                 :         {
    1673               2 :             bHasMap = FALSE;
    1674                 : 
    1675               2 :             hSQLLyr = OGR_DS_ExecuteSQL(hDS, "SELECT type FROM sqlite_master WHERE name = 'tiles'", NULL, NULL);
    1676               2 :             if (hSQLLyr != NULL)
    1677                 :             {
    1678               2 :                 hFeat = OGR_L_GetNextFeature(hSQLLyr);
    1679               2 :                 if (hFeat)
    1680                 :                 {
    1681               2 :                     if (OGR_F_IsFieldSet(hFeat, 0))
    1682                 :                     {
    1683                 :                         bHasMap = strcmp(OGR_F_GetFieldAsString(hFeat, 0),
    1684               2 :                                          "view") == 0;
    1685               2 :                         if (!bHasMap)
    1686                 :                         {
    1687               0 :                             CPLDebug("MBTILES", "Weird! 'tiles' is not a view, but 'map' exists");
    1688                 :                         }
    1689                 :                     }
    1690               2 :                     OGR_F_Destroy(hFeat);
    1691                 :                 }
    1692               2 :                 OGR_DS_ReleaseResultSet(hDS, hSQLLyr);
    1693                 :             }
    1694                 :         }
    1695                 : 
    1696                 : /* -------------------------------------------------------------------- */
    1697                 : /*      Get minimum and maximum zoom levels                             */
    1698                 : /* -------------------------------------------------------------------- */
    1699                 : 
    1700                 :         bHasMinMaxLevel = MBTilesGetMinMaxZoomLevel(hDS, bHasMap,
    1701               4 :                                                     nMinLevel, nMaxLevel);
    1702                 : 
    1703               4 :         if (bHasMinMaxLevel && (nMinLevel < 0 || nMinLevel > nMaxLevel))
    1704                 :         {
    1705                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1706                 :                      "Inconsistant values : min(zoom_level) = %d, max(zoom_level) = %d",
    1707               0 :                      nMinLevel, nMaxLevel);
    1708                 :             goto end;
    1709                 :         }
    1710                 : 
    1711               4 :         if (bHasMinMaxLevel && nMaxLevel > 22)
    1712                 :         {
    1713                 :             CPLError(CE_Failure, CPLE_NotSupported,
    1714               0 :                      "zoom_level > 22 not supported");
    1715                 :             goto end;
    1716                 :         }
    1717                 : 
    1718               4 :         if (!bHasMinMaxLevel)
    1719                 :         {
    1720               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot find min and max zoom_level");
    1721                 :             goto end;
    1722                 :         }
    1723                 : 
    1724                 : /* -------------------------------------------------------------------- */
    1725                 : /*      Get bounds                                                      */
    1726                 : /* -------------------------------------------------------------------- */
    1727                 : 
    1728                 :         bHasBounds = MBTilesGetBounds(hDS, nMinLevel, nMaxLevel,
    1729                 :                                       nMinTileRow, nMaxTileRow,
    1730               4 :                                       nMinTileCol, nMaxTileCol);
    1731               4 :         if (!bHasBounds)
    1732                 :         {
    1733               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot find min and max tile numbers");
    1734                 :             goto end;
    1735                 :         }
    1736                 : 
    1737                 : /* -------------------------------------------------------------------- */
    1738                 : /*      Get number of bands                                             */
    1739                 : /* -------------------------------------------------------------------- */
    1740                 : 
    1741               4 :         pszBandCount = CPLGetConfigOption("MBTILES_BAND_COUNT", "-1");
    1742               4 :         nBands = atoi(pszBandCount);
    1743                 : 
    1744               4 :         if( ! (nBands == 1 || nBands == 3 || nBands == 4) )
    1745                 :         {
    1746                 :             nBands = MBTilesGetBandCount(hDS, nMinLevel, nMaxLevel,
    1747                 :                                          nMinTileRow, nMaxTileRow,
    1748               4 :                                          nMinTileCol, nMaxTileCol);
    1749               4 :             if (nBands < 0)
    1750                 :                 goto end;
    1751                 :         }
    1752                 : 
    1753                 : /* -------------------------------------------------------------------- */
    1754                 : /*      Set dataset attributes                                          */
    1755                 : /* -------------------------------------------------------------------- */
    1756                 : 
    1757               4 :         poDS = new MBTilesDataset();
    1758               4 :         poDS->eAccess = poOpenInfo->eAccess;
    1759               4 :         poDS->hDS = hDS;
    1760                 : 
    1761                 :         /* poDS will release it from now */
    1762               4 :         hDS = NULL;
    1763                 : 
    1764                 : /* -------------------------------------------------------------------- */
    1765                 : /*      Store resolutions                                               */
    1766                 : /* -------------------------------------------------------------------- */
    1767               4 :         poDS->nMinLevel = nMinLevel;
    1768               4 :         poDS->nResolutions = nResolutions = nMaxLevel - nMinLevel;
    1769                 : 
    1770                 : /* -------------------------------------------------------------------- */
    1771                 : /*      Round bounds to the lowest zoom level                           */
    1772                 : /* -------------------------------------------------------------------- */
    1773                 : 
    1774                 :         //CPLDebug("MBTILES", "%d %d %d %d", nMinTileCol, nMinTileRow, nMaxTileCol, nMaxTileRow);
    1775               4 :         nMinTileCol = (int)(1.0 * nMinTileCol / (1 << nResolutions)) * (1 << nResolutions);
    1776               4 :         nMinTileRow = (int)(1.0 * nMinTileRow / (1 << nResolutions)) * (1 << nResolutions);
    1777               4 :         nMaxTileCol = (int)ceil(1.0 * nMaxTileCol / (1 << nResolutions)) * (1 << nResolutions);
    1778               4 :         nMaxTileRow = (int)ceil(1.0 * nMaxTileRow / (1 << nResolutions)) * (1 << nResolutions);
    1779                 : 
    1780                 : /* -------------------------------------------------------------------- */
    1781                 : /*      Compute raster size, geotransform and projection                */
    1782                 : /* -------------------------------------------------------------------- */
    1783               4 :         poDS->nMinTileCol = nMinTileCol;
    1784               4 :         poDS->nMinTileRow = nMinTileRow;
    1785               4 :         poDS->nRasterXSize = (nMaxTileCol-nMinTileCol) * 256;
    1786               4 :         poDS->nRasterYSize = (nMaxTileRow-nMinTileRow) * 256;
    1787                 : 
    1788               4 :         nBlockXSize = nBlockYSize = 256;
    1789               4 :         eDataType = GDT_Byte;
    1790                 : 
    1791                 : /* -------------------------------------------------------------------- */
    1792                 : /*      Add bands                                                       */
    1793                 : /* -------------------------------------------------------------------- */
    1794                 : 
    1795              16 :         for(iBand=0;iBand<nBands;iBand++)
    1796                 :             poDS->SetBand(iBand+1, new MBTilesBand(poDS, iBand+1, eDataType,
    1797              12 :                                                   nBlockXSize, nBlockYSize));
    1798                 : 
    1799                 : /* -------------------------------------------------------------------- */
    1800                 : /*      Add overview levels as internal datasets                        */
    1801                 : /* -------------------------------------------------------------------- */
    1802               4 :         if (nResolutions >= 1)
    1803                 :         {
    1804                 :             poDS->papoOverviews = (MBTilesDataset**)
    1805               4 :                 CPLCalloc(nResolutions, sizeof(MBTilesDataset*));
    1806                 :             int nLev;
    1807              22 :             for(nLev=1;nLev<=nResolutions;nLev++)
    1808                 :             {
    1809              18 :                 poDS->papoOverviews[nLev-1] = new MBTilesDataset(poDS, nLev);
    1810                 : 
    1811              72 :                 for(iBand=0;iBand<nBands;iBand++)
    1812                 :                 {
    1813              54 :                     poDS->papoOverviews[nLev-1]->SetBand(iBand+1,
    1814                 :                         new MBTilesBand(poDS->papoOverviews[nLev-1], iBand+1, eDataType,
    1815             108 :                                            nBlockXSize, nBlockYSize));
    1816                 :                 }
    1817                 :             }
    1818                 :         }
    1819                 : 
    1820               4 :         poDS->SetMetadata(poDS->papszImageStructure, "IMAGE_STRUCTURE");
    1821                 : 
    1822                 : /* -------------------------------------------------------------------- */
    1823                 : /*      Initialize any PAM information.                                 */
    1824                 : /* -------------------------------------------------------------------- */
    1825               4 :         poDS->SetDescription( poOpenInfo->pszFilename );
    1826                 : 
    1827               4 :         if ( !EQUALN(poOpenInfo->pszFilename, "/vsicurl/", 9) )
    1828               2 :             poDS->TryLoadXML();
    1829                 :         else
    1830                 :         {
    1831               2 :             poDS->SetPamFlags(poDS->GetPamFlags() & ~GPF_DIRTY);
    1832               0 :         }
    1833                 :     }
    1834                 : 
    1835                 : end:
    1836               4 :     if (hDS)
    1837               0 :         OGRReleaseDataSource(hDS);
    1838                 : 
    1839               4 :     return poDS;
    1840                 : }
    1841                 : 
    1842                 : /************************************************************************/
    1843                 : /*                       GDALRegister_MBTiles()                         */
    1844                 : /************************************************************************/
    1845                 : 
    1846            1135 : void GDALRegister_MBTiles()
    1847                 : 
    1848                 : {
    1849                 :     GDALDriver  *poDriver;
    1850                 : 
    1851            1135 :     if (! GDAL_CHECK_VERSION("MBTiles driver"))
    1852               0 :         return;
    1853                 : 
    1854            1135 :     if( GDALGetDriverByName( "MBTiles" ) == NULL )
    1855                 :     {
    1856            1093 :         poDriver = new GDALDriver();
    1857                 : 
    1858            1093 :         poDriver->SetDescription( "MBTiles" );
    1859                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    1860            1093 :                                    "MBTiles" );
    1861                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
    1862            1093 :                                    "frmt_mbtiles.html" );
    1863            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mbtiles" );
    1864                 : 
    1865            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1866                 : 
    1867            1093 :         poDriver->pfnOpen = MBTilesDataset::Open;
    1868            1093 :         poDriver->pfnIdentify = MBTilesDataset::Identify;
    1869                 : 
    1870            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1871                 :     }
    1872                 : }

Generated by: LCOV version 1.7