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 : }
|