LCOV - code coverage report
Current view: directory - frmts/kmlsuperoverlay - kmlsuperoverlaydataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 955 834 87.3 %
Date: 2012-12-26 Functions: 39 29 74.4 %

       1                 : /******************************************************************************
       2                 :  * $Id$
       3                 :  *
       4                 :  * Project:  KmlSuperOverlay
       5                 :  * Purpose:  Implements write support for KML superoverlay - KMZ.
       6                 :  * Author:   Harsh Govind, harsh.govind@spadac.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, SPADAC Inc. <harsh.govind@spadac.com>
      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 "kmlsuperoverlaydataset.h"
      31                 : 
      32                 : #include <cmath>   /* fabs */
      33                 : #include <cstring> /* strdup */
      34                 : #include <iostream>
      35                 : #include <sstream>
      36                 : #include <math.h>
      37                 : #include <algorithm>
      38                 : #include <fstream>
      39                 : 
      40                 : #include "cpl_error.h"
      41                 : #include "cpl_string.h"
      42                 : #include "cpl_conv.h"
      43                 : #include "cpl_vsi.h"
      44                 : #include "ogr_spatialref.h"
      45                 : #include "../vrt/gdal_vrt.h"
      46                 : #include "../vrt/vrtdataset.h"
      47                 : 
      48                 : using namespace std;
      49                 : 
      50                 : /************************************************************************/
      51                 : /*                           GenerateTiles()                            */
      52                 : /************************************************************************/
      53              30 : void GenerateTiles(std::string filename, 
      54                 :                    int zoom, int rxsize, 
      55                 :                    int rysize, int ix, int iy, 
      56                 :                    int rx, int ry, int dxsize, 
      57                 :                    int dysize, int bands,
      58                 :                    GDALDataset* poSrcDs,
      59                 :                    GDALDriver* poOutputTileDriver, 
      60                 :                    GDALDriver* poMemDriver,
      61                 :                    bool isJpegDriver)
      62                 : {
      63              30 :     GDALDataset* poTmpDataset = NULL;
      64              30 :     GDALRasterBand* alphaBand = NULL;
      65                 :    
      66              30 :     GByte* pafScanline = new GByte[dxsize];
      67              30 :     bool* hadnoData = new bool[dxsize];
      68                 : 
      69              30 :     if (isJpegDriver && bands == 4)
      70               1 :         bands = 3;
      71                 :    
      72              30 :     poTmpDataset = poMemDriver->Create("", dxsize, dysize, bands, GDT_Byte, NULL);
      73                 :    
      74              30 :     if (isJpegDriver == false)//Jpeg dataset only has one or three bands
      75                 :     {
      76               7 :         if (bands < 4)//add transparency to files with one band or three bands
      77                 :         {
      78               7 :             poTmpDataset->AddBand(GDT_Byte);
      79               7 :             alphaBand = poTmpDataset->GetRasterBand(poTmpDataset->GetRasterCount());
      80                 :         }
      81                 :     }
      82                 : 
      83              30 :     int rowOffset = rysize/dysize;
      84              30 :     int loopCount = rysize/rowOffset;
      85            4120 :     for (int row = 0; row < loopCount; row++)
      86                 :     {
      87            4090 :         if (isJpegDriver == false)
      88                 :         {
      89          561400 :             for (int i = 0; i < dxsize; i++)
      90                 :             {
      91          560000 :                 hadnoData[i] = false;
      92                 :             }
      93                 :         }
      94                 : 
      95           11020 :         for (int band = 1; band <= bands; band++)
      96                 :         {
      97            6930 :             GDALRasterBand* poBand = poSrcDs->GetRasterBand(band);
      98                 : 
      99            6930 :             int hasNoData = 0;
     100            6930 :             bool isSigned = false;
     101            6930 :             double noDataValue = poBand->GetNoDataValue(&hasNoData);
     102            6930 :             const char* pixelType = poBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
     103            6930 :             if (pixelType)
     104                 :             {
     105               0 :                 if (strcmp(pixelType, "SIGNEDBYTE") == 0)
     106                 :                 {
     107               0 :                     isSigned = true; 
     108                 :                 }
     109                 :             }
     110                 : 
     111            6930 :             GDALRasterBand* poBandtmp = NULL;
     112            6930 :             if (poTmpDataset)
     113                 :             {
     114            6930 :                 poBandtmp = poTmpDataset->GetRasterBand(band);
     115                 :             }
     116                 : 
     117            6930 :             int yOffset = ry + row * rowOffset;
     118            6930 :             bool bReadFailed = false;
     119            6930 :             if (poBand)
     120                 :             {
     121                 :                 CPLErr errTest = 
     122            6930 :                     poBand->RasterIO( GF_Read, rx, yOffset, rxsize, rowOffset, pafScanline, dxsize, 1, GDT_Byte, 0, 0);
     123                 : 
     124            6930 :                 if ( errTest == CE_Failure )
     125                 :                 {
     126               0 :                     hasNoData = 1;
     127               0 :                     bReadFailed = true;
     128                 :                 }
     129                 :             }
     130                 : 
     131                 : 
     132                 :             //fill the true or false for hadnoData array if the source data has nodata value
     133            6930 :             if (isJpegDriver == false)
     134                 :             {
     135            4200 :                 if (hasNoData == 1)
     136                 :                 {
     137               0 :                     for (int j = 0; j < dxsize; j++)
     138                 :                     {
     139               0 :                         double v = pafScanline[j];
     140               0 :                         double tmpv = v;
     141               0 :                         if (isSigned)
     142                 :                         {
     143               0 :                             tmpv -= 128;
     144                 :                         }
     145               0 :                         if (tmpv == noDataValue || bReadFailed == true)
     146                 :                         {
     147               0 :                             hadnoData[j] = true;
     148                 :                         }
     149                 :                     }
     150                 :                 }
     151                 :             }
     152                 : 
     153            6930 :             if (poBandtmp && bReadFailed == false)
     154                 :             {
     155                 :                 poBandtmp->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte, 
     156            6930 :                                     0, 0);
     157                 :             }
     158                 :         } 
     159                 : 
     160                 :         //fill the values for alpha band
     161            4090 :         if (isJpegDriver == false)
     162                 :         {
     163            1400 :             if (alphaBand)
     164                 :             {
     165          561400 :                 for (int i = 0; i < dxsize; i++)
     166                 :                 {
     167          560000 :                     if (hadnoData[i] == true)
     168                 :                     {
     169               0 :                         pafScanline[i] = 0;
     170                 :                     }
     171                 :                     else
     172                 :                     {
     173          560000 :                         pafScanline[i] = 255;
     174                 :                     }
     175                 :                 }    
     176                 : 
     177                 :                 alphaBand->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte, 
     178            1400 :                                     0, 0);
     179                 :             }
     180                 :         }
     181                 :     }
     182                 : 
     183              30 :     delete [] pafScanline;
     184              30 :     delete [] hadnoData;
     185                 : 
     186              30 :     GDALDataset* outDs = poOutputTileDriver->CreateCopy(filename.c_str(), poTmpDataset, FALSE, NULL, NULL, NULL);
     187                 : 
     188              30 :     GDALClose(poTmpDataset);
     189              30 :     if (outDs)
     190              30 :         GDALClose(outDs);
     191              30 : }
     192                 : 
     193                 : /************************************************************************/
     194                 : /*                          GenerateRootKml()                           */
     195                 : /************************************************************************/
     196                 : 
     197                 : static
     198              18 : int  GenerateRootKml(const char* filename, 
     199                 :                      const char* kmlfilename,
     200                 :                      double north, 
     201                 :                      double south, 
     202                 :                      double east, 
     203                 :                      double west, 
     204                 :                      int tilesize)
     205                 : {
     206              18 :     VSILFILE* fp = VSIFOpenL(filename, "wb");
     207              18 :     if (fp == NULL)
     208                 :     {
     209                 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
     210               0 :                  filename);
     211               0 :         return FALSE;
     212                 :     }
     213              18 :     int minlodpixels = tilesize/2;
     214                 : 
     215              18 :     const char* tmpfilename = CPLGetBasename(kmlfilename);
     216                 :     // If we haven't writen any features yet, output the layer's schema
     217              18 :     VSIFPrintfL(fp, "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
     218              18 :     VSIFPrintfL(fp, "\t<Document>\n");
     219              18 :     VSIFPrintfL(fp, "\t\t<name>%s</name>\n", tmpfilename);
     220              18 :     VSIFPrintfL(fp, "\t\t<description></description>\n");
     221              18 :     VSIFPrintfL(fp, "\t\t<Style>\n");
     222              18 :     VSIFPrintfL(fp, "\t\t\t<ListStyle id=\"hideChildren\">\n");
     223              18 :     VSIFPrintfL(fp, "\t\t\t\t<listItemType>checkHideChildren</listItemType>\n");
     224              18 :     VSIFPrintfL(fp, "\t\t\t</ListStyle>\n");
     225              18 :     VSIFPrintfL(fp, "\t\t</Style>\n");
     226              18 :     VSIFPrintfL(fp, "\t\t<Region>\n \t\t<LatLonAltBox>\n");
     227              18 :     VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", north);
     228              18 :     VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", south);
     229              18 :     VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", east);
     230              18 :     VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", west);
     231              18 :     VSIFPrintfL(fp, "\t\t\t</LatLonAltBox>\n");
     232              18 :     VSIFPrintfL(fp, "\t\t</Region>\n");
     233              18 :     VSIFPrintfL(fp, "\t\t<NetworkLink>\n");
     234              18 :     VSIFPrintfL(fp, "\t\t\t<open>1</open>\n");
     235              18 :     VSIFPrintfL(fp, "\t\t\t<Region>\n");
     236              18 :     VSIFPrintfL(fp, "\t\t\t\t<Lod>\n");
     237              18 :     VSIFPrintfL(fp, "\t\t\t\t\t<minLodPixels>%d</minLodPixels>\n", minlodpixels);
     238              18 :     VSIFPrintfL(fp, "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>\n");
     239              18 :     VSIFPrintfL(fp, "\t\t\t\t</Lod>\n");
     240              18 :     VSIFPrintfL(fp, "\t\t\t\t<LatLonAltBox>\n");
     241              18 :     VSIFPrintfL(fp, "\t\t\t\t\t<north>%f</north>\n", north);
     242              18 :     VSIFPrintfL(fp, "\t\t\t\t\t<south>%f</south>\n", south);
     243              18 :     VSIFPrintfL(fp, "\t\t\t\t\t<east>%f</east>\n", east);
     244              18 :     VSIFPrintfL(fp, "\t\t\t\t\t<west>%f</west>\n", west);
     245              18 :     VSIFPrintfL(fp, "\t\t\t\t</LatLonAltBox>\n");
     246              18 :     VSIFPrintfL(fp, "\t\t\t</Region>\n");
     247              18 :     VSIFPrintfL(fp, "\t\t\t<Link>\n");
     248              18 :     VSIFPrintfL(fp, "\t\t\t\t<href>0/0/0.kml</href>\n");
     249              18 :     VSIFPrintfL(fp, "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>\n");
     250              18 :     VSIFPrintfL(fp, "\t\t\t</Link>\n");
     251              18 :     VSIFPrintfL(fp, "\t\t</NetworkLink>\n");
     252              18 :     VSIFPrintfL(fp, "\t</Document>\n");
     253              18 :     VSIFPrintfL(fp, "</kml>\n");
     254                 : 
     255              18 :     VSIFCloseL(fp);
     256              18 :     return TRUE;
     257                 : }
     258                 : 
     259                 : /************************************************************************/
     260                 : /*                          GenerateChildKml()                          */
     261                 : /************************************************************************/
     262                 : 
     263                 : static
     264              30 : int  GenerateChildKml(std::string filename, 
     265                 :                       int zoom, int ix, int iy, 
     266                 :                       double zoomxpixel, double zoomypixel, int dxsize, int dysize, 
     267                 :                       double south, double west, int xsize, 
     268                 :                       int ysize, int maxzoom, 
     269                 :                       OGRCoordinateTransformation * poTransform,
     270                 :                       std::string fileExt,
     271                 :                       bool fixAntiMeridian)
     272                 : {
     273              30 :     double tnorth = south + zoomypixel *((iy + 1)*dysize);
     274              30 :     double tsouth = south + zoomypixel *(iy*dysize);
     275              30 :     double teast = west + zoomxpixel*((ix+1)*dxsize);
     276              30 :     double twest = west + zoomxpixel*ix*dxsize;
     277                 : 
     278              30 :     double upperleftT = twest;
     279              30 :     double lowerleftT = twest;
     280                 : 
     281              30 :     double rightbottomT = tsouth;
     282              30 :     double leftbottomT = tsouth;
     283                 : 
     284              30 :     double lefttopT = tnorth;
     285              30 :     double righttopT = tnorth;
     286                 : 
     287              30 :     double lowerrightT = teast;
     288              30 :     double upperrightT = teast;
     289                 : 
     290              30 :     if (poTransform)
     291                 :     {
     292              10 :         poTransform->Transform(1, &twest, &tsouth);
     293              10 :         poTransform->Transform(1, &teast, &tnorth);
     294                 : 
     295              10 :         poTransform->Transform(1, &upperleftT, &lefttopT);
     296              10 :         poTransform->Transform(1, &upperrightT, &righttopT);
     297              10 :         poTransform->Transform(1, &lowerrightT, &rightbottomT);
     298              10 :         poTransform->Transform(1, &lowerleftT, &leftbottomT);
     299                 :     }
     300                 : 
     301              30 :     if ( fixAntiMeridian && teast < twest)
     302                 :     {
     303               3 :         teast += 360;
     304               3 :         lowerrightT += 360;
     305               3 :         upperrightT += 360;
     306                 :     }
     307                 : 
     308              30 :     std::vector<int> xchildren;
     309              30 :     std::vector<int> ychildern;
     310                 : 
     311              30 :     int minLodPixels = 128;
     312              30 :     if (zoom == 0)
     313                 :     {
     314              18 :         minLodPixels = 1;
     315                 :     }
     316                 : 
     317              30 :     int maxLodPix = -1;
     318              30 :     if ( zoom < maxzoom )
     319                 :     {
     320               3 :         double zareasize = pow(2.0, (maxzoom - zoom - 1))*dxsize;
     321               3 :         double zareasize1 = pow(2.0, (maxzoom - zoom - 1))*dysize;
     322               3 :         xchildren.push_back(ix*2);
     323               3 :         int tmp = ix*2 + 1;
     324               3 :         int tmp1 = (int)ceil(xsize / zareasize);
     325               3 :         if (tmp < tmp1)
     326                 :         {
     327               3 :             xchildren.push_back(ix*2+1);
     328                 :         }
     329               3 :         ychildern.push_back(iy*2);
     330               3 :         tmp = iy*2 + 1;
     331               3 :         tmp1 = (int)ceil(ysize / zareasize1);
     332               3 :         if (tmp < tmp1)
     333                 :         {
     334               3 :             ychildern.push_back(iy*2+1);
     335                 :         }     
     336               3 :         maxLodPix = 2048;
     337                 :     }
     338                 : 
     339              30 :     VSILFILE* fp = VSIFOpenL(filename.c_str(), "wb");
     340              30 :     if (fp == NULL)
     341                 :     {
     342                 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
     343               0 :                  filename.c_str());
     344               0 :         return FALSE;
     345                 :     }
     346                 : 
     347              30 :     VSIFPrintfL(fp, "<kml xmlns=\"http://earth.google.com/kml/2.1\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\">\n");
     348              30 :     VSIFPrintfL(fp, "\t<Document>\n");
     349              30 :     VSIFPrintfL(fp, "\t\t<name>%d/%d/%d.kml</name>\n", zoom, ix, iy);
     350              30 :     VSIFPrintfL(fp, "\t\t<Style>\n");
     351              30 :     VSIFPrintfL(fp, "\t\t\t<ListStyle id=\"hideChildren\">\n");
     352              30 :     VSIFPrintfL(fp, "\t\t\t\t<listItemType>checkHideChildren</listItemType>\n");
     353              30 :     VSIFPrintfL(fp, "\t\t\t</ListStyle>\n");
     354              30 :     VSIFPrintfL(fp, "\t\t</Style>\n");
     355              30 :     VSIFPrintfL(fp, "\t\t<Region>\n");
     356              30 :     VSIFPrintfL(fp, "\t\t\t<Lod>\n");
     357              30 :     VSIFPrintfL(fp, "\t\t\t\t<minLodPixels>%d</minLodPixels>\n", minLodPixels);
     358              30 :     VSIFPrintfL(fp, "\t\t\t\t<maxLodPixels>%d</maxLodPixels>\n", maxLodPix);
     359              30 :     VSIFPrintfL(fp, "\t\t\t</Lod>\n");
     360              30 :     VSIFPrintfL(fp, "\t\t\t<LatLonAltBox>\n");
     361              30 :     VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", tnorth);
     362              30 :     VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", tsouth);
     363              30 :     VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", teast);
     364              30 :     VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", twest);
     365              30 :     VSIFPrintfL(fp, "\t\t\t</LatLonAltBox>\n");
     366              30 :     VSIFPrintfL(fp, "\t\t</Region>\n");
     367              30 :     VSIFPrintfL(fp, "\t\t<GroundOverlay>\n");
     368              30 :     VSIFPrintfL(fp, "\t\t\t<drawOrder>%d</drawOrder>\n", zoom);
     369              30 :     VSIFPrintfL(fp, "\t\t\t<Icon>\n");
     370              30 :     VSIFPrintfL(fp, "\t\t\t\t<href>%d%s</href>\n", iy, fileExt.c_str());
     371              30 :     VSIFPrintfL(fp, "\t\t\t</Icon>\n");
     372                 : 
     373                 :     /* When possible, use <LatLonBox>. I've noticed otherwise that */
     374                 :     /* if using <gx:LatLonQuad> with extents of the size of a country or */
     375                 :     /* continent, the overlay is really bad placed in GoogleEarth */
     376              55 :     if( lowerleftT == upperleftT && lowerrightT == upperrightT &&
     377                 :         leftbottomT == rightbottomT && righttopT == lefttopT )
     378                 :     {
     379              25 :         VSIFPrintfL(fp, "\t\t\t<LatLonBox>\n");
     380              25 :         VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", tnorth);
     381              25 :         VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", tsouth);
     382              25 :         VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", teast);
     383              25 :         VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", twest);
     384              25 :         VSIFPrintfL(fp, "\t\t\t</LatLonBox>\n");
     385                 :     }
     386                 :     else
     387                 :     {
     388               5 :         VSIFPrintfL(fp, "\t\t\t<gx:LatLonQuad>\n");
     389               5 :         VSIFPrintfL(fp, "\t\t\t\t<coordinates>\n");
     390               5 :         VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", lowerleftT, leftbottomT);
     391               5 :         VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", lowerrightT, rightbottomT);
     392               5 :         VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", upperrightT, righttopT);
     393               5 :         VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", upperleftT, lefttopT);
     394               5 :         VSIFPrintfL(fp, "\t\t\t\t</coordinates>\n");
     395               5 :         VSIFPrintfL(fp, "\t\t\t</gx:LatLonQuad>\n");
     396                 :     }
     397              30 :     VSIFPrintfL(fp, "\t\t</GroundOverlay>\n");
     398                 : 
     399              36 :     for (unsigned int i = 0; i < xchildren.size(); i++)
     400                 :     {
     401               6 :         int cx = xchildren[i];
     402              18 :         for (unsigned int j = 0; j < ychildern.size(); j++)
     403                 :         {
     404              12 :             int cy = ychildern[j];
     405                 : 
     406              12 :             double cnorth = south + zoomypixel/2 *((cy + 1)*dysize);
     407              12 :             double csouth = south + zoomypixel/2 *(cy*dysize);
     408              12 :             double ceast = west + zoomxpixel/2*((cx+1)*dxsize);
     409              12 :             double cwest = west + zoomxpixel/2*cx*dxsize;
     410                 : 
     411              12 :             if (poTransform)
     412                 :             {
     413               8 :                 poTransform->Transform(1, &cwest, &csouth);
     414               8 :                 poTransform->Transform(1, &ceast, &cnorth);
     415                 :             }
     416                 : 
     417              12 :             if ( fixAntiMeridian && ceast < cwest )
     418                 :             {
     419               2 :                 ceast += 360;
     420                 :             }
     421                 : 
     422              12 :             VSIFPrintfL(fp, "\t\t<NetworkLink>\n");
     423              12 :             VSIFPrintfL(fp, "\t\t\t<name>%d/%d/%d%s</name>\n", zoom+1, cx, cy, fileExt.c_str());
     424              12 :             VSIFPrintfL(fp, "\t\t\t<Region>\n");
     425              12 :             VSIFPrintfL(fp, "\t\t\t\t<Lod>\n");
     426              12 :             VSIFPrintfL(fp, "\t\t\t\t\t<minLodPixels>128</minLodPixels>\n");
     427              12 :             VSIFPrintfL(fp, "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>\n");
     428              12 :             VSIFPrintfL(fp, "\t\t\t\t</Lod>\n");
     429              12 :             VSIFPrintfL(fp, "\t\t\t\t<LatLonAltBox>\n");
     430              12 :             VSIFPrintfL(fp, "\t\t\t\t\t<north>%f</north>\n", cnorth);
     431              12 :             VSIFPrintfL(fp, "\t\t\t\t\t<south>%f</south>\n", csouth);
     432              12 :             VSIFPrintfL(fp, "\t\t\t\t\t<east>%f</east>\n", ceast);
     433              12 :             VSIFPrintfL(fp, "\t\t\t\t\t<west>%f</west>\n", cwest);
     434              12 :             VSIFPrintfL(fp, "\t\t\t\t</LatLonAltBox>\n");
     435              12 :             VSIFPrintfL(fp, "\t\t\t</Region>\n");
     436              12 :             VSIFPrintfL(fp, "\t\t\t<Link>\n");
     437              12 :             VSIFPrintfL(fp, "\t\t\t\t<href>../../%d/%d/%d.kml</href>\n", zoom+1, cx, cy);
     438              12 :             VSIFPrintfL(fp, "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>\n");
     439              12 :             VSIFPrintfL(fp, "\t\t\t\t<viewFormat/>\n");
     440              12 :             VSIFPrintfL(fp, "\t\t\t</Link>\n");
     441              12 :             VSIFPrintfL(fp, "\t\t</NetworkLink>\n");
     442                 :         }
     443                 :     }
     444                 : 
     445              30 :     VSIFPrintfL(fp, "\t</Document>\n");
     446              30 :     VSIFPrintfL(fp, "</kml>\n");
     447              30 :     VSIFCloseL(fp);
     448                 :     
     449              30 :     return TRUE;
     450                 : }
     451                 : 
     452                 : /************************************************************************/
     453                 : /*                           zipWithMinizip()                           */
     454                 : /************************************************************************/
     455              15 : bool zipWithMinizip(std::vector<std::string> srcFiles, std::string srcDirectory, std::string targetFile)
     456                 : {
     457              15 :     void  *zipfile = CPLCreateZip(targetFile.c_str(), NULL);
     458              15 :     if (!zipfile)
     459                 :     {
     460                 :         CPLError( CE_Failure, CPLE_FileIO,
     461               0 :                   "Unable to open target zip file.." );
     462               0 :         return false;
     463                 :     }
     464                 : 
     465              15 :     std::vector <std::string>::iterator v1_Iter;
     466              15 :     for(v1_Iter = srcFiles.begin(); v1_Iter != srcFiles.end(); v1_Iter++)
     467                 :     {
     468              53 :         std::string fileRead = *v1_Iter;
     469                 : 
     470                 :         // Find relative path and open new file with zip file
     471              53 :         std::string relativeFileReadPath = fileRead;
     472              53 :         int remNumChars = srcDirectory.size();
     473              53 :         if(remNumChars > 0)
     474                 :         {
     475              53 :             int f = fileRead.find(srcDirectory);
     476              53 :             if( f >= 0 )
     477                 :             {
     478              53 :                 relativeFileReadPath.erase(f, remNumChars + 1); // 1 added for backslash at the end
     479                 :             }      
     480                 :         }
     481                 : 
     482              53 :         std::basic_string<char>::iterator iter1;
     483             106 :         for (iter1 = relativeFileReadPath.begin(); iter1 != relativeFileReadPath.end(); iter1++)
     484                 :         {
     485              53 :             int f = relativeFileReadPath.find("\\");
     486              53 :             if (f >= 0)
     487                 :             {
     488               0 :                 relativeFileReadPath.replace(f, 1, "/");
     489                 :             }
     490                 :             else
     491                 :             {
     492              53 :                 break;
     493                 :             }
     494                 :         }
     495              53 :         if (CPLCreateFileInZip(zipfile, relativeFileReadPath.c_str(), NULL) != CE_None)
     496                 :         {
     497                 :             CPLError( CE_Failure, CPLE_FileIO,
     498               0 :                       "Unable to create file within the zip file.." );
     499               0 :             return false;
     500                 :         }
     501                 : 
     502                 :         // Read source file and write to zip file
     503              53 :         VSILFILE* fp = VSIFOpenL(fileRead.c_str(), "rb");
     504              53 :         if (fp == NULL)
     505                 :         {
     506                 :             CPLError( CE_Failure, CPLE_FileIO,
     507               0 :                       "Could not open source file.." );
     508               0 :             return false;
     509                 :         }
     510                 : 
     511                 :         // Read file in buffer
     512              53 :         std::string fileData;
     513              53 :         const unsigned int bufSize = 1024;
     514                 :         char buf[bufSize];
     515                 :         int nRead;
     516             453 :         while((nRead = VSIFReadL(buf, 1, bufSize, fp)) != 0)
     517                 :         {
     518             347 :             if ( CPLWriteFileInZip(zipfile, buf, nRead) != CE_None )
     519                 :             {
     520                 :                 CPLError( CE_Failure, CPLE_FileIO,
     521               0 :                         "Could not write to file within zip file.." );
     522               0 :                 CPLCloseFileInZip(zipfile);
     523               0 :                 CPLCloseZip(zipfile);
     524               0 :                 VSIFCloseL(fp);
     525               0 :                 return false;
     526                 :             }
     527                 :         }
     528                 : 
     529              53 :         VSIFCloseL(fp);
     530                 : 
     531                 :         // Close one src file zipped completely
     532              53 :         if ( CPLCloseFileInZip(zipfile) != CE_None )
     533                 :         {
     534                 :             CPLError( CE_Failure, CPLE_FileIO,
     535               0 :                       "Could not close file written within zip file.." );
     536               0 :             CPLCloseZip(zipfile);
     537               0 :             return false;
     538                 :         }
     539                 :     }
     540                 : 
     541              15 :     CPLCloseZip(zipfile);
     542                 : 
     543              15 :     return true;
     544                 : }
     545                 : 
     546                 : /************************************************************************/
     547                 : /*                   KMLSuperOverlayRecursiveUnlink()                   */
     548                 : /************************************************************************/
     549                 : 
     550              48 : static void KMLSuperOverlayRecursiveUnlink( const char *pszName )
     551                 : 
     552                 : {
     553                 :     char **papszFileList;
     554                 :     int i;
     555                 : 
     556              48 :     papszFileList = CPLReadDir( pszName );
     557                 : 
     558             134 :     for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
     559                 :     {
     560                 :         VSIStatBufL  sStatBuf;
     561                 : 
     562             164 :         if( EQUAL(papszFileList[i],".") || EQUAL(papszFileList[i],"..") )
     563              78 :             continue;
     564                 : 
     565                 :         CPLString osFullFilename =
     566              86 :                  CPLFormFilename( pszName, papszFileList[i], NULL );
     567                 : 
     568              86 :         VSIStatL( osFullFilename, &sStatBuf );
     569                 : 
     570              86 :         if( VSI_ISREG( sStatBuf.st_mode ) )
     571                 :         {
     572              53 :             VSIUnlink( osFullFilename );
     573                 :         }
     574              33 :         else if( VSI_ISDIR( sStatBuf.st_mode ) )
     575                 :         {
     576              33 :             KMLSuperOverlayRecursiveUnlink( osFullFilename );
     577                 :         }
     578                 :     }
     579                 : 
     580              48 :     CSLDestroy( papszFileList );
     581                 : 
     582              48 :     VSIRmdir( pszName );
     583              48 : }
     584                 : 
     585                 : /************************************************************************/
     586                 : /*                           CreateCopy()                               */
     587                 : /************************************************************************/
     588                 : 
     589                 : class KmlSuperOverlayDummyDataset: public GDALDataset
     590               1 : {
     591                 :     public:
     592               1 :         KmlSuperOverlayDummyDataset() {}
     593                 : };
     594                 : 
     595                 : static
     596              23 : GDALDataset *KmlSuperOverlayCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     597                 :                                         int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData)
     598                 : {
     599              23 :     bool isKmz = false;
     600                 : 
     601              23 :     int bands = poSrcDS->GetRasterCount();
     602              23 :     if (bands != 1 && bands != 3 && bands != 4)
     603               3 :         return NULL;
     604                 :    
     605                 :     //correct the file and get the directory
     606              20 :     char* output_dir = NULL;
     607              20 :     if (pszFilename == NULL)
     608                 :     {
     609               0 :         output_dir = CPLGetCurrentDir();
     610               0 :         pszFilename = CPLFormFilename(output_dir, "doc", "kml");
     611                 :     }
     612                 :     else
     613                 :     {
     614              20 :         const char* extension = CPLGetExtension(pszFilename);
     615              20 :         if (!EQUAL(extension,"kml") && !EQUAL(extension,"kmz"))
     616                 :         {
     617                 :             CPLError( CE_Failure, CPLE_None,
     618               0 :                       "File extension should be kml or kmz." );
     619               0 :             return NULL;
     620                 :         }
     621              20 :         if (EQUAL(extension,"kmz"))
     622                 :         {
     623              17 :             isKmz = true;
     624                 :         }
     625                 :     
     626              20 :         output_dir = CPLStrdup(CPLGetPath(pszFilename));
     627              20 :         if (strcmp(output_dir, "") == 0)
     628                 :         {
     629               0 :             CPLFree(output_dir);
     630               0 :             output_dir = CPLGetCurrentDir();
     631                 :         }
     632                 :     }
     633              20 :     CPLString outDir = output_dir;
     634              20 :     CPLFree(output_dir);
     635              20 :     output_dir = NULL;
     636                 : 
     637              20 :     if (isKmz)
     638                 :     {
     639              17 :         outDir = CPLFormFilename(outDir, CPLSPrintf("kmlsuperoverlaytmp_%p", pszFilename) , NULL);
     640              17 :         if (VSIMkdir(outDir, 0755) != 0)
     641                 :         {
     642                 :             CPLError( CE_Failure, CPLE_None,
     643               2 :                     "Cannot create %s", outDir.c_str() );
     644               2 :             return NULL;
     645                 :         }
     646                 :     }
     647                 : 
     648              18 :     GDALDriver* poOutputTileDriver = NULL;
     649              18 :     bool isJpegDriver = true;
     650                 : 
     651              18 :     const char* pszFormat = CSLFetchNameValueDef(papszOptions, "FORMAT", "JPEG");
     652              18 :     if (EQUAL(pszFormat, "PNG"))
     653                 :     {
     654               3 :         isJpegDriver = false;
     655                 :     }
     656                 : 
     657              18 :     GDALDriver* poMemDriver = GetGDALDriverManager()->GetDriverByName("MEM");
     658              18 :     poOutputTileDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
     659                 : 
     660              18 :     if( poMemDriver == NULL || poOutputTileDriver == NULL)
     661                 :     {
     662                 :         CPLError( CE_Failure, CPLE_None,
     663               0 :                   "Image export driver was not found.." );
     664               0 :         if (isKmz)
     665               0 :             KMLSuperOverlayRecursiveUnlink(outDir);
     666               0 :         return NULL;
     667                 :     }
     668                 : 
     669              18 :     int xsize = poSrcDS->GetRasterXSize();
     670              18 :     int ysize = poSrcDS->GetRasterYSize();
     671                 : 
     672              18 :     double north = 0.0;
     673              18 :     double south = 0.0;
     674              18 :     double east = 0.0;
     675              18 :     double west = 0.0;
     676                 : 
     677                 :     double  adfGeoTransform[6];
     678                 : 
     679              18 :     if( poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None )
     680                 :     {
     681              18 :         north = adfGeoTransform[3];
     682              18 :         south = adfGeoTransform[3] + adfGeoTransform[5]*ysize;
     683              18 :         east = adfGeoTransform[0] + adfGeoTransform[1]*xsize;
     684              18 :         west = adfGeoTransform[0];
     685                 :     }
     686                 : 
     687              18 :     OGRCoordinateTransformation * poTransform = NULL;
     688              18 :     if (poSrcDS->GetProjectionRef() != NULL)
     689                 :     {
     690              18 :         OGRSpatialReference poDsUTM;
     691                 :      
     692              18 :         char* projStr = (char*)poSrcDS->GetProjectionRef();
     693                 :      
     694              18 :         if (poDsUTM.importFromWkt(&projStr) == OGRERR_NONE)
     695                 :         {
     696              18 :             if (poDsUTM.IsProjected())
     697                 :             {
     698               2 :                 OGRSpatialReference poLatLong;
     699               2 :                 poLatLong.SetWellKnownGeogCS( "WGS84" );
     700                 :            
     701               2 :                 poTransform = OGRCreateCoordinateTransformation( &poDsUTM, &poLatLong );
     702               2 :                 if( poTransform != NULL )
     703                 :                 {
     704               2 :                     poTransform->Transform(1, &west, &south);
     705               2 :                     poTransform->Transform(1, &east, &north);
     706               2 :                 }
     707                 :             }
     708              18 :         }
     709                 :     }
     710                 : 
     711              18 :     bool fixAntiMeridian = CSLFetchBoolean( papszOptions, "FIX_ANTIMERIDIAN", FALSE );
     712              18 :     if ( fixAntiMeridian && east < west )
     713                 :     {
     714               1 :         east += 360;
     715                 :     }
     716                 : 
     717                 :     //Zoom levels of the pyramid.
     718                 :     int maxzoom;
     719                 :     int tilexsize;
     720                 :     int tileysize;
     721                 :     // Let the longer side determine the max zoom level and x/y tilesizes.
     722              18 :     if ( xsize >= ysize )
     723                 :     {
     724              18 :         double dtilexsize = xsize;
     725              39 :         while (dtilexsize > 400) //calculate x tile size
     726                 :         {
     727               3 :             dtilexsize = dtilexsize/2;
     728                 :         }
     729                 : 
     730              18 :         maxzoom   = static_cast<int>(log( (double)xsize / dtilexsize ) / log(2.0));
     731              18 :         tilexsize = (int)dtilexsize;
     732              18 :         tileysize = (int)( (double)(dtilexsize * ysize) / xsize );
     733                 :     }
     734                 :     else
     735                 :     {
     736               0 :         double dtileysize = ysize;
     737               0 :         while (dtileysize > 400) //calculate y tile size
     738                 :         {
     739               0 :             dtileysize = dtileysize/2;
     740                 :         }
     741                 : 
     742               0 :         maxzoom   = static_cast<int>(log( (double)ysize / dtileysize ) / log(2.0));
     743               0 :         tileysize = (int)dtileysize;
     744               0 :         tilexsize = (int)( (double)(dtileysize * xsize) / ysize );
     745                 :     }
     746                 : 
     747              18 :     std::vector<double> zoomxpixels;
     748              18 :     std::vector<double> zoomypixels;
     749              39 :     for (int zoom = 0; zoom < maxzoom + 1; zoom++)
     750                 :     {
     751              21 :         zoomxpixels.push_back(adfGeoTransform[1] * pow(2.0, (maxzoom - zoom)));
     752                 :         // zoomypixels.push_back(abs(adfGeoTransform[5]) * pow(2.0, (maxzoom - zoom)));
     753              21 :         zoomypixels.push_back(fabs(adfGeoTransform[5]) * pow(2.0, (maxzoom - zoom)));
     754                 :     }
     755                 : 
     756              18 :     std::string tmpFileName; 
     757              18 :     std::vector<std::string> fileVector;
     758                 :     int nRet;
     759              18 :     if (isKmz)
     760                 :     {
     761              15 :         tmpFileName = CPLFormFilename(outDir, "tmp.kml", NULL);
     762              15 :         nRet = GenerateRootKml(tmpFileName.c_str(), pszFilename, north, south, east, west, (int)tilexsize);
     763              15 :         fileVector.push_back(tmpFileName);
     764                 :     }
     765                 :     else
     766                 :     {
     767               3 :         nRet = GenerateRootKml(pszFilename, pszFilename, north, south, east, west, (int)tilexsize);
     768                 :     }
     769                 :     
     770              18 :     if (nRet == FALSE)
     771                 :     {
     772               0 :         OGRCoordinateTransformation::DestroyCT( poTransform );
     773               0 :         if (isKmz)
     774               0 :             KMLSuperOverlayRecursiveUnlink(outDir);
     775               0 :         return NULL;
     776                 :     }
     777                 : 
     778              39 :     for (int zoom = maxzoom; zoom >= 0; --zoom)
     779                 :     {
     780              21 :         int rmaxxsize = static_cast<int>(pow(2.0, (maxzoom-zoom)) * tilexsize);
     781              21 :         int rmaxysize = static_cast<int>(pow(2.0, (maxzoom-zoom)) * tileysize);
     782                 : 
     783              21 :         int xloop = (int)xsize/rmaxxsize;
     784              21 :         int yloop = (int)ysize/rmaxysize;
     785                 : 
     786              21 :         xloop = xloop>0 ? xloop : 1;
     787              21 :         yloop = yloop>0 ? yloop : 1;
     788              45 :         for (int ix = 0; ix < xloop; ix++)
     789                 :         {
     790              24 :             int rxsize = (int)(rmaxxsize);
     791              24 :             int rx = (int)(ix * rmaxxsize);
     792                 : 
     793              54 :             for (int iy = 0; iy < yloop; iy++)
     794                 :             {
     795              30 :                 int rysize = (int)(rmaxysize);
     796              30 :                 int ry = (int)(ysize - (iy * rmaxysize)) - rysize;
     797                 : 
     798              30 :                 int dxsize = (int)(rxsize/rmaxxsize * tilexsize);
     799              30 :                 int dysize = (int)(rysize/rmaxysize * tileysize);
     800                 : 
     801              30 :                 std::stringstream zoomStr;
     802              30 :                 std::stringstream ixStr;
     803              30 :                 std::stringstream iyStr;
     804                 : 
     805              30 :                 zoomStr << zoom;
     806              30 :                 ixStr << ix;
     807              30 :                 iyStr << iy;
     808                 : 
     809              30 :                 std::string zoomDir = outDir;
     810              30 :                 zoomDir+= "/" + zoomStr.str();
     811              30 :                 VSIMkdir(zoomDir.c_str(), 0775);
     812                 :         
     813                 : 
     814              30 :                 zoomDir = zoomDir + "/" + ixStr.str();
     815              30 :                 VSIMkdir(zoomDir.c_str(), 0775);
     816                 : 
     817              30 :                 std::string fileExt = ".jpg";
     818              30 :                 if (isJpegDriver == false)
     819                 :                 {
     820               7 :                     fileExt = ".png";
     821                 :                 }
     822              30 :                 std::string filename = zoomDir + "/" + iyStr.str() + fileExt;
     823              30 :                 if (isKmz)
     824                 :                 {
     825              19 :                     fileVector.push_back(filename);
     826                 :                 }
     827                 : 
     828                 :                 GenerateTiles(filename, zoom, rxsize, rysize, ix, iy, rx, ry, dxsize, 
     829              30 :                               dysize, bands, poSrcDS, poOutputTileDriver, poMemDriver, isJpegDriver);
     830              30 :                 std::string childKmlfile = zoomDir + "/" + iyStr.str() + ".kml";
     831              30 :                 if (isKmz)
     832                 :                 {
     833              19 :                     fileVector.push_back(childKmlfile);
     834                 :                 }
     835                 : 
     836              30 :                 double tmpSouth = adfGeoTransform[3] + adfGeoTransform[5]*ysize;
     837              30 :                 double zoomxpix = zoomxpixels[zoom];
     838              30 :                 double zoomypix = zoomypixels[zoom];
     839              30 :                 if (zoomxpix == 0)
     840                 :                 {
     841               0 :                     zoomxpix = 1;
     842                 :                 }
     843                 : 
     844              30 :                 if (zoomypix == 0)
     845                 :                 {
     846               0 :                     zoomypix = 1;
     847                 :                 }
     848                 : 
     849                 :                 GenerateChildKml(childKmlfile, zoom, ix, iy, zoomxpix, zoomypix, 
     850              30 :                                  dxsize, dysize, tmpSouth, adfGeoTransform[0], xsize, ysize, maxzoom, poTransform, fileExt, fixAntiMeridian);
     851                 :             }
     852                 :         }
     853                 :     }
     854                 : 
     855              18 :     OGRCoordinateTransformation::DestroyCT( poTransform );
     856              18 :     poTransform = NULL;
     857                 :     
     858              18 :     if (isKmz)
     859                 :     {
     860              15 :         std::string outputfile = pszFilename;
     861              15 :         bool zipDone = true;
     862              30 :         if (zipWithMinizip(fileVector, outDir, outputfile) == false)
     863                 :         {
     864                 :             CPLError( CE_Failure, CPLE_FileIO,
     865               0 :                       "Unable to do zip.." );
     866               0 :             zipDone = false;
     867                 :         }
     868                 : 
     869              15 :         KMLSuperOverlayRecursiveUnlink(outDir);
     870                 : 
     871              15 :         if (zipDone == false)
     872                 :         {
     873               0 :             return NULL;
     874               0 :         }
     875                 :     }
     876                 : 
     877              18 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     878              18 :     GDALDataset* poDS = KmlSuperOverlayReadDataset::Open(&oOpenInfo);
     879              18 :     if( poDS == NULL )
     880               1 :         poDS = new KmlSuperOverlayDummyDataset();
     881              18 :     return poDS;
     882                 : }
     883                 : 
     884                 : 
     885                 : /************************************************************************/
     886                 : /*                            KMLRemoveSlash()                          */
     887                 : /************************************************************************/
     888                 : 
     889                 : /* replace "a/b/../c" pattern by "a/c" */
     890             861 : static CPLString KMLRemoveSlash(const char* pszPathIn)
     891                 : {
     892             861 :     char* pszPath = CPLStrdup(pszPathIn);
     893                 : 
     894            1604 :     while(TRUE)
     895                 :     {
     896            2465 :         char* pszSlashDotDot = strstr(pszPath, "/../");
     897            2465 :         if (pszSlashDotDot == NULL || pszSlashDotDot == pszPath)
     898             861 :             break;
     899            1604 :         char* pszSlashBefore = pszSlashDotDot-1;
     900            4812 :         while(pszSlashBefore > pszPath && *pszSlashBefore != '/')
     901            1604 :             pszSlashBefore --;
     902            1604 :         if (pszSlashBefore == pszPath)
     903               0 :             break;
     904                 :         memmove(pszSlashBefore + 1, pszSlashDotDot + 4,
     905            1604 :                 strlen(pszSlashDotDot + 4) + 1);
     906                 :     }
     907             861 :     CPLString osRet = pszPath;
     908             861 :     CPLFree(pszPath);
     909               0 :     return osRet;
     910                 : }
     911                 : 
     912                 : /************************************************************************/
     913                 : /*                      KmlSuperOverlayReadDataset()                    */
     914                 : /************************************************************************/
     915                 : 
     916              25 : KmlSuperOverlayReadDataset::KmlSuperOverlayReadDataset()
     917                 : 
     918                 : {
     919              25 :     nFactor = 1;
     920              25 :     psRoot = NULL;
     921              25 :     psDocument = NULL;
     922              25 :     poDSIcon = NULL;
     923              25 :     adfGeoTransform[0] = 0;
     924              25 :     adfGeoTransform[1] = 1;
     925              25 :     adfGeoTransform[2] = 0;
     926              25 :     adfGeoTransform[3] = 0;
     927              25 :     adfGeoTransform[4] = 0;
     928              25 :     adfGeoTransform[5] = 1;
     929                 : 
     930              25 :     nOverviewCount = 0;
     931              25 :     papoOverviewDS = NULL;
     932              25 :     bIsOvr = FALSE;
     933                 : 
     934              25 :     poParent = NULL;
     935              25 :     psFirstLink = NULL;
     936              25 :     psLastLink = NULL;
     937              25 : }
     938                 : 
     939                 : /************************************************************************/
     940                 : /*                     ~KmlSuperOverlayReadDataset()                    */
     941                 : /************************************************************************/
     942                 : 
     943              25 : KmlSuperOverlayReadDataset::~KmlSuperOverlayReadDataset()
     944                 : 
     945                 : {
     946              25 :     if( psRoot != NULL )
     947              23 :         CPLDestroyXMLNode( psRoot );
     948              25 :     CloseDependentDatasets();
     949              25 : }
     950                 : 
     951                 : /************************************************************************/
     952                 : /*                         CloseDependentDatasets()                     */
     953                 : /************************************************************************/
     954                 : 
     955              25 : int KmlSuperOverlayReadDataset::CloseDependentDatasets()
     956                 : {
     957              25 :     int bRet = FALSE;
     958              25 :     if( poDSIcon != NULL )
     959                 :     {
     960              23 :         CPLString osFilename(poDSIcon->GetDescription());
     961              23 :         delete poDSIcon;
     962              23 :         VSIUnlink(osFilename);
     963              23 :         poDSIcon = NULL;
     964              23 :         bRet = TRUE;
     965                 :     }
     966                 : 
     967              25 :     LinkedDataset* psCur = psFirstLink;
     968              25 :     psFirstLink = NULL;
     969              25 :     psLastLink = NULL;
     970                 : 
     971              54 :     while( psCur != NULL )
     972                 :     {
     973               4 :         LinkedDataset* psNext = psCur->psNext;
     974               4 :         if( psCur->poDS->nRefCount == 1 )
     975               4 :             bRet = TRUE;
     976               4 :         GDALClose(psCur->poDS);
     977               4 :         delete psCur;
     978               4 :         psCur = psNext;
     979                 :     }
     980                 : 
     981              25 :     if( nOverviewCount > 0 )
     982                 :     {
     983               2 :         bRet = TRUE;
     984               4 :         for(int i = 0; i < nOverviewCount; i++)
     985               2 :             delete papoOverviewDS[i];
     986               2 :         CPLFree(papoOverviewDS);
     987               2 :         nOverviewCount = 0;
     988               2 :         papoOverviewDS = NULL;
     989                 :     }
     990                 : 
     991              25 :     return bRet;
     992                 : }
     993                 : 
     994                 : /************************************************************************/
     995                 : /*                          GetProjectionRef()                          */
     996                 : /************************************************************************/
     997                 : 
     998               0 : const char *KmlSuperOverlayReadDataset::GetProjectionRef()
     999                 : 
    1000                 : {
    1001               0 :     return SRS_WKT_WGS84;
    1002                 : }
    1003                 : 
    1004                 : /************************************************************************/
    1005                 : /*                          GetGeoTransform()                           */
    1006                 : /************************************************************************/
    1007                 : 
    1008               0 : CPLErr KmlSuperOverlayReadDataset::GetGeoTransform( double * padfGeoTransform )
    1009                 : {
    1010               0 :     memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
    1011               0 :     return CE_None;
    1012                 : }
    1013                 : 
    1014                 : /************************************************************************/
    1015                 : /*                        KmlSuperOverlayRasterBand()                   */
    1016                 : /************************************************************************/
    1017                 : 
    1018             100 : KmlSuperOverlayRasterBand::KmlSuperOverlayRasterBand(KmlSuperOverlayReadDataset* poDS, int nBand)
    1019                 : {
    1020             100 :     nRasterXSize = poDS->nRasterXSize;
    1021             100 :     nRasterYSize = poDS->nRasterYSize;
    1022             100 :     eDataType = GDT_Byte;
    1023             100 :     nBlockXSize = 256;
    1024             100 :     nBlockYSize = 256;
    1025             100 : }
    1026                 : 
    1027                 : /************************************************************************/
    1028                 : /*                       ~KmlSuperOverlayRasterBand()                   */
    1029                 : /************************************************************************/
    1030                 : 
    1031               8 : CPLErr KmlSuperOverlayRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData )
    1032                 : {
    1033               8 :     int nXOff = nBlockXOff * nBlockXSize;
    1034               8 :     int nYOff = nBlockYOff * nBlockYSize;
    1035               8 :     int nXSize = nBlockXSize;
    1036               8 :     int nYSize = nBlockYSize;
    1037               8 :     if( nXOff + nXSize > nRasterXSize )
    1038               4 :         nXSize = nRasterXSize - nXOff;
    1039               8 :     if( nYOff + nYSize > nRasterYSize )
    1040               8 :         nYSize = nRasterYSize - nYOff;
    1041                 :     return IRasterIO( GF_Read,
    1042                 :                       nXOff,
    1043                 :                       nYOff,
    1044                 :                       nXSize,
    1045                 :                       nYSize,
    1046                 :                       pData,
    1047                 :                       nXSize,
    1048                 :                       nYSize,
    1049                 :                       eDataType,
    1050                 :                       1,
    1051               8 :                       nBlockXSize );
    1052                 : }
    1053                 : 
    1054                 : /************************************************************************/
    1055                 : /*                          GetColorInterpretation()                    */
    1056                 : /************************************************************************/
    1057                 : 
    1058               0 : GDALColorInterp  KmlSuperOverlayRasterBand::GetColorInterpretation()
    1059                 : {
    1060               0 :     return (GDALColorInterp)(GCI_RedBand + nBand - 1);
    1061                 : }
    1062                 : 
    1063                 : /************************************************************************/
    1064                 : /*                            IRasterIO()                               */
    1065                 : /************************************************************************/
    1066                 : 
    1067            2208 : CPLErr KmlSuperOverlayRasterBand::IRasterIO( GDALRWFlag eRWFlag,
    1068                 :                                              int nXOff, int nYOff, int nXSize, int nYSize,
    1069                 :                                              void * pData, int nBufXSize, int nBufYSize,
    1070                 :                                              GDALDataType eBufType,
    1071                 :                                              int nPixelSpace, int nLineSpace )
    1072                 : {
    1073            2208 :     KmlSuperOverlayReadDataset* poGDS = (KmlSuperOverlayReadDataset* )poDS;
    1074                 : 
    1075                 :     return poGDS->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1076                 :                             pData, nBufXSize, nBufYSize, eBufType,
    1077                 :                             1, &nBand,
    1078            2208 :                             nPixelSpace, nLineSpace, 0 );
    1079                 : }
    1080                 : 
    1081                 : /************************************************************************/
    1082                 : /*                          GetOverviewCount()                          */
    1083                 : /************************************************************************/
    1084                 : 
    1085               1 : int KmlSuperOverlayRasterBand::GetOverviewCount()
    1086                 : {
    1087               1 :     KmlSuperOverlayReadDataset* poGDS = (KmlSuperOverlayReadDataset* )poDS;
    1088                 : 
    1089               1 :     return poGDS->nOverviewCount;
    1090                 : }
    1091                 : 
    1092                 : /************************************************************************/
    1093                 : /*                           GetOverview()                              */
    1094                 : /************************************************************************/
    1095                 : 
    1096               1 : GDALRasterBand *KmlSuperOverlayRasterBand::GetOverview(int iOvr)
    1097                 : {
    1098               1 :     KmlSuperOverlayReadDataset* poGDS = (KmlSuperOverlayReadDataset* )poDS;
    1099                 : 
    1100               1 :     if( iOvr < 0 || iOvr >= poGDS->nOverviewCount )
    1101               0 :         return NULL;
    1102                 : 
    1103               1 :     return poGDS->papoOverviewDS[iOvr]->GetRasterBand(nBand);
    1104                 : }
    1105                 : 
    1106                 : /************************************************************************/
    1107                 : /*                     KmlSuperOverlayGetBoundingBox()                  */
    1108                 : /************************************************************************/
    1109                 : 
    1110                 : static
    1111            1624 : int KmlSuperOverlayGetBoundingBox(CPLXMLNode* psNode, double* adfExtents)
    1112                 : {
    1113            1624 :     CPLXMLNode* psBox = CPLGetXMLNode(psNode, "LatLonBox");
    1114            1624 :     if( psBox == NULL )
    1115            1601 :         psBox = CPLGetXMLNode(psNode, "LatLonAltBox");
    1116            1624 :     if( psBox == NULL )
    1117               1 :         return FALSE;
    1118                 :     
    1119            1623 :     const char* pszNorth = CPLGetXMLValue(psBox, "north", NULL);
    1120            1623 :     const char* pszSouth = CPLGetXMLValue(psBox, "south", NULL);
    1121            1623 :     const char* pszEast = CPLGetXMLValue(psBox, "east", NULL);
    1122            1623 :     const char* pszWest = CPLGetXMLValue(psBox, "west", NULL);
    1123            1623 :     if( pszNorth == NULL || pszSouth == NULL || pszEast == NULL || pszWest == NULL )
    1124               0 :         return FALSE;
    1125                 :     
    1126            1623 :     adfExtents[0] = CPLAtof(pszWest);
    1127            1623 :     adfExtents[1] = CPLAtof(pszSouth);
    1128            1623 :     adfExtents[2] = CPLAtof(pszEast);
    1129            1623 :     adfExtents[3] = CPLAtof(pszNorth);
    1130            1623 :     return TRUE;
    1131                 : }
    1132                 : 
    1133                 : /************************************************************************/
    1134                 : /*                            IRasterIO()                               */
    1135                 : /************************************************************************/
    1136                 : 
    1137                 : class SubImageDesc
    1138               0 : {
    1139                 :     public:
    1140                 :         GDALDataset* poDS;
    1141                 :         double       adfExtents[4];
    1142                 : };
    1143                 : 
    1144            2408 : CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
    1145                 :                                int nXOff, int nYOff, int nXSize, int nYSize,
    1146                 :                                void * pData, int nBufXSize, int nBufYSize,
    1147                 :                                GDALDataType eBufType, 
    1148                 :                                int nBandCount, int *panBandMap,
    1149                 :                                int nPixelSpace, int nLineSpace, int nBandSpace)
    1150                 : {
    1151            2408 :     if( eRWFlag == GF_Write )
    1152               0 :         return CE_Failure;
    1153                 :     
    1154            2408 :     if( bIsOvr )
    1155                 :         return poParent->IRasterIO( eRWFlag,
    1156                 :                                     nXOff * (poParent->nFactor / nFactor),
    1157                 :                                     nYOff * (poParent->nFactor / nFactor),
    1158                 :                                     nXSize * (poParent->nFactor / nFactor),
    1159                 :                                     nYSize * (poParent->nFactor / nFactor),
    1160                 :                                     pData, nBufXSize, nBufYSize,
    1161                 :                                     eBufType, 
    1162                 :                                     nBandCount, panBandMap,
    1163             200 :                                     nPixelSpace, nLineSpace, nBandSpace);
    1164                 :     
    1165            2208 :     double dfXOff = 1.0 * nXOff / nFactor;
    1166            2208 :     double dfYOff = 1.0 * nYOff / nFactor;
    1167            2208 :     double dfXSize = 1.0 * nXSize / nFactor;
    1168            2208 :     double dfYSize = 1.0 * nYSize / nFactor;
    1169                 : 
    1170            2208 :     int nIconCount = poDSIcon->GetRasterCount();
    1171                 : 
    1172            2208 :     if( nBufXSize > dfXSize || nBufYSize > dfYSize )
    1173                 :     {
    1174             400 :         double dfRequestXMin = adfGeoTransform[0] + nXOff * adfGeoTransform[1];
    1175             400 :         double dfRequestXMax = adfGeoTransform[0] + (nXOff + nXSize) * adfGeoTransform[1];
    1176             400 :         double dfRequestYMin = adfGeoTransform[3] + (nYOff + nYSize) * adfGeoTransform[5];
    1177             400 :         double dfRequestYMax = adfGeoTransform[3] + nYOff * adfGeoTransform[5];
    1178                 : 
    1179             400 :         CPLXMLNode* psIter = psDocument->psChild;
    1180             400 :         std::vector<SubImageDesc> aosImages;
    1181             400 :         double dfXRes = adfGeoTransform[1] * nFactor;
    1182             400 :         double dfYRes = -adfGeoTransform[5] * nFactor;
    1183             400 :         double dfNewXRes = dfXRes;
    1184             400 :         double dfNewYRes = dfYRes;
    1185                 : 
    1186            4000 :         while( psIter != NULL )
    1187                 :         {
    1188            3200 :             CPLXMLNode* psRegion = NULL;
    1189            3200 :             CPLXMLNode* psLink = NULL;
    1190                 :             double adfExtents[4];
    1191            3200 :             const char* pszHref = NULL;
    1192            3200 :             if( psIter->eType == CXT_Element &&
    1193                 :                 strcmp(psIter->pszValue, "NetworkLink") == 0 &&
    1194                 :                 (psRegion = CPLGetXMLNode(psIter, "Region")) != NULL &&
    1195                 :                 (psLink = CPLGetXMLNode(psIter, "Link")) != NULL &&
    1196                 :                 KmlSuperOverlayGetBoundingBox(psRegion, adfExtents) &&
    1197                 :                 (pszHref = CPLGetXMLValue(psLink, "href", NULL)) != NULL )
    1198                 :             {
    1199            4400 :                 if( dfRequestXMin < adfExtents[2] && dfRequestXMax > adfExtents[0] &&
    1200            2800 :                     dfRequestYMin < adfExtents[3] && dfRequestYMax > adfExtents[1] )
    1201                 :                 {
    1202             800 :                     CPLString osSubFilename;
    1203             800 :                     if( strncmp(pszHref, "http", 4) == 0)
    1204               0 :                         osSubFilename = CPLSPrintf("/vsicurl_streaming/%s", pszHref);
    1205                 :                     else
    1206                 :                     {
    1207             800 :                         const char* pszBaseFilename = osFilename.c_str();
    1208             800 :                         if( EQUAL(CPLGetExtension(pszBaseFilename), "kmz") &&
    1209                 :                             strncmp(pszBaseFilename, "/vsizip/", 8) != 0 )
    1210                 :                         {
    1211               0 :                             osSubFilename = "/vsizip/";
    1212               0 :                             osSubFilename += CPLGetPath(pszBaseFilename);
    1213               0 :                             osSubFilename += "/";
    1214               0 :                             osSubFilename += pszHref;
    1215                 :                         }
    1216                 :                         else
    1217                 :                         {
    1218             800 :                             osSubFilename = CPLGetPath(pszBaseFilename);
    1219             800 :                             osSubFilename += "/";
    1220             800 :                             osSubFilename += pszHref;
    1221                 :                         }
    1222             800 :                         osSubFilename = KMLRemoveSlash(osSubFilename);
    1223                 :                     }
    1224                 : 
    1225             800 :                     KmlSuperOverlayReadDataset* poSubImageDS = NULL;
    1226             800 :                     if( EQUAL(CPLGetExtension(osSubFilename), "kml") )
    1227                 :                     {
    1228             800 :                         KmlSuperOverlayReadDataset* poRoot = poParent ? poParent : this;
    1229             800 :                         LinkedDataset* psLink = poRoot->oMapChildren[osSubFilename];
    1230             800 :                         if( psLink == NULL )
    1231                 :                         {
    1232               4 :                             if( poRoot->oMapChildren.size() == 64 )
    1233                 :                             {
    1234               0 :                                 psLink = poRoot->psLastLink;
    1235               0 :                                 CPLAssert(psLink);
    1236               0 :                                 poRoot->oMapChildren.erase(psLink->osSubFilename);
    1237               0 :                                 GDALClose(psLink->poDS);
    1238               0 :                                 if( psLink->psPrev != NULL )
    1239                 :                                 {
    1240               0 :                                     poRoot->psLastLink = psLink->psPrev;
    1241               0 :                                     psLink->psPrev->psNext = NULL;
    1242                 :                                 }
    1243                 :                                 else
    1244                 :                                 {
    1245               0 :                                     CPLAssert(psLink == poRoot->psFirstLink);
    1246               0 :                                     poRoot->psFirstLink = poRoot->psLastLink = NULL;
    1247                 :                                 }
    1248                 :                             }
    1249                 :                             else
    1250               4 :                                 psLink = new LinkedDataset();
    1251                 : 
    1252               4 :                             poRoot->oMapChildren[osSubFilename] = psLink;
    1253                 :                             poSubImageDS = (KmlSuperOverlayReadDataset*)
    1254               4 :                                 KmlSuperOverlayReadDataset::Open(osSubFilename, poRoot);
    1255               4 :                             if( poSubImageDS )
    1256               4 :                                 poSubImageDS->MarkAsShared();
    1257               4 :                             psLink->osSubFilename = osSubFilename;
    1258               4 :                             psLink->poDS = poSubImageDS;
    1259               4 :                             psLink->psPrev = NULL;
    1260               4 :                             psLink->psNext = poRoot->psFirstLink;
    1261               4 :                             if( poRoot->psFirstLink != NULL )
    1262                 :                             {
    1263               3 :                                 CPLAssert(poRoot->psFirstLink->psPrev == NULL);
    1264               3 :                                 poRoot->psFirstLink->psPrev = psLink;
    1265                 :                             }
    1266                 :                             else
    1267               1 :                                 poRoot->psLastLink = psLink;
    1268               4 :                             poRoot->psFirstLink = psLink;
    1269                 :                         }
    1270                 :                         else
    1271                 :                         {
    1272             796 :                             poSubImageDS = psLink->poDS;
    1273             796 :                             if( psLink != poRoot->psFirstLink )
    1274                 :                             {
    1275             796 :                                 if( psLink == poRoot->psLastLink )
    1276                 :                                 {
    1277             398 :                                     poRoot->psLastLink = psLink->psPrev;
    1278             398 :                                     CPLAssert(poRoot->psLastLink != NULL );
    1279             398 :                                     poRoot->psLastLink->psNext = NULL;
    1280                 :                                 }
    1281                 :                                 else
    1282             398 :                                     psLink->psNext->psPrev = psLink->psPrev;
    1283             796 :                                 CPLAssert( psLink->psPrev != NULL );
    1284             796 :                                 psLink->psPrev->psNext = psLink->psNext;
    1285             796 :                                 psLink->psPrev = NULL;
    1286             796 :                                 poRoot->psFirstLink->psPrev = psLink;
    1287             796 :                                 psLink->psNext = poRoot->psFirstLink;
    1288             796 :                                 poRoot->psFirstLink = psLink;
    1289                 :                             }
    1290                 :                         }
    1291                 :                     }
    1292             800 :                     if( poSubImageDS )
    1293                 :                     {
    1294             800 :                         int nSubImageXSize = poSubImageDS->GetRasterXSize();
    1295             800 :                         int nSubImageYSize = poSubImageDS->GetRasterYSize();
    1296             800 :                         adfExtents[0] = poSubImageDS->adfGeoTransform[0];
    1297             800 :                         adfExtents[1] = poSubImageDS->adfGeoTransform[3] + nSubImageYSize * poSubImageDS->adfGeoTransform[5];
    1298             800 :                         adfExtents[2] = poSubImageDS->adfGeoTransform[0] + nSubImageXSize * poSubImageDS->adfGeoTransform[1];
    1299             800 :                         adfExtents[3] = poSubImageDS->adfGeoTransform[3];
    1300                 : 
    1301             800 :                         double dfSubXRes = (adfExtents[2] - adfExtents[0]) / nSubImageXSize;
    1302             800 :                         double dfSubYRes = (adfExtents[3] - adfExtents[1]) / nSubImageYSize;
    1303                 : 
    1304             800 :                         if( dfSubXRes < dfNewXRes ) dfNewXRes = dfSubXRes;
    1305             800 :                         if( dfSubYRes < dfNewYRes ) dfNewYRes = dfSubYRes;
    1306                 : 
    1307                 :                         SubImageDesc oImageDesc;
    1308             800 :                         oImageDesc.poDS = poSubImageDS;
    1309             800 :                         poSubImageDS->Reference();
    1310             800 :                         memcpy(oImageDesc.adfExtents, adfExtents, 4 * sizeof(double));
    1311             800 :                         aosImages.push_back(oImageDesc);
    1312             800 :                     }
    1313                 :                 }
    1314                 :             }
    1315            3200 :             psIter = psIter->psNext;
    1316                 :         }
    1317                 : 
    1318             400 :         if( dfNewXRes < dfXRes || dfNewYRes < dfYRes )
    1319                 :         {
    1320                 :             int i;
    1321             400 :             double dfXFactor = dfXRes / dfNewXRes;
    1322             400 :             double dfYFactor = dfYRes / dfNewYRes;
    1323                 :             VRTDataset* poVRTDS = new VRTDataset(
    1324                 :                 (int)(nRasterXSize * dfXFactor + 0.5),
    1325             400 :                 (int)(nRasterYSize * dfYFactor + 0.5));
    1326                 : 
    1327            2000 :             for(int iBandIdx = 0; iBandIdx < 4; iBandIdx++ )
    1328                 :             {
    1329            1600 :                 VRTAddBand( (VRTDatasetH) poVRTDS, GDT_Byte, NULL );
    1330                 : 
    1331            1600 :                 int nBand = iBandIdx + 1;
    1332            3200 :                 if( nBand <= nIconCount || (nIconCount == 1 && nBand != 4) )
    1333                 :                 {
    1334                 :                     VRTAddSimpleSource( (VRTSourcedRasterBandH) poVRTDS->GetRasterBand(iBandIdx + 1),
    1335                 :                                         (GDALRasterBandH) poDSIcon->GetRasterBand(nBand <= nIconCount ? nBand : 1),
    1336                 :                                         0, 0,
    1337                 :                                         nRasterXSize,
    1338                 :                                         nRasterYSize,
    1339                 :                                         0, 0,
    1340                 :                                         poVRTDS->GetRasterXSize(),
    1341                 :                                         poVRTDS->GetRasterYSize(),
    1342            1600 :                                         NULL, VRT_NODATA_UNSET);
    1343                 :                 }
    1344                 :                 else
    1345                 :                 {
    1346                 :                     VRTAddComplexSource( (VRTSourcedRasterBandH) poVRTDS->GetRasterBand(iBandIdx + 1),
    1347                 :                                         (GDALRasterBandH) poDSIcon->GetRasterBand(1),
    1348                 :                                         0, 0,
    1349                 :                                         nRasterXSize,
    1350                 :                                         nRasterYSize,
    1351                 :                                         0, 0,
    1352                 :                                         poVRTDS->GetRasterXSize(),
    1353                 :                                         poVRTDS->GetRasterYSize(),
    1354               0 :                                         VRT_NODATA_UNSET, 0, 255);
    1355                 :                 }
    1356                 :             }
    1357                 : 
    1358            1200 :             for(i=0; i < (int)aosImages.size(); i++)
    1359                 :             {
    1360             800 :                 int nDstXOff = (int)((aosImages[i].adfExtents[0] - adfGeoTransform[0]) / dfNewXRes + 0.5);
    1361             800 :                 int nDstYOff = (int)((adfGeoTransform[3] - aosImages[i].adfExtents[3]) / dfNewYRes + 0.5);
    1362             800 :                 int nDstXSize = (int)((aosImages[i].adfExtents[2] - aosImages[i].adfExtents[0]) / dfNewXRes + 0.5);
    1363             800 :                 int nDstYSize = (int)((aosImages[i].adfExtents[3] - aosImages[i].adfExtents[1]) / dfNewYRes + 0.5);
    1364                 : 
    1365             800 :                 int nSrcBandCount = aosImages[i].poDS->GetRasterCount();
    1366            4000 :                 for(int iBandIdx = 0; iBandIdx < 4; iBandIdx++ )
    1367                 :                 {
    1368            3200 :                     int nBand = iBandIdx + 1;
    1369            6400 :                     if( nBand <= nSrcBandCount || (nSrcBandCount == 1 && nBand != 4) )
    1370                 :                     {
    1371                 :                         VRTAddSimpleSource( (VRTSourcedRasterBandH) poVRTDS->GetRasterBand(iBandIdx + 1),
    1372                 :                                             (GDALRasterBandH) aosImages[i].poDS->GetRasterBand(nBand <= nSrcBandCount ? nBand : 1),
    1373                 :                                             0, 0,
    1374                 :                                             aosImages[i].poDS->GetRasterXSize(),
    1375                 :                                             aosImages[i].poDS->GetRasterYSize(),
    1376                 :                                             nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1377            3200 :                                             NULL, VRT_NODATA_UNSET);
    1378                 :                     }
    1379                 :                     else
    1380                 :                     {
    1381                 :                         VRTAddComplexSource( (VRTSourcedRasterBandH) poVRTDS->GetRasterBand(iBandIdx + 1),
    1382                 :                                             (GDALRasterBandH) aosImages[i].poDS->GetRasterBand(1),
    1383                 :                                             0, 0,
    1384                 :                                             aosImages[i].poDS->GetRasterXSize(),
    1385                 :                                             aosImages[i].poDS->GetRasterYSize(),
    1386                 :                                             nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1387               0 :                                             VRT_NODATA_UNSET, 0, 255);
    1388                 :                     }
    1389                 :                 }
    1390                 :             }
    1391                 : 
    1392             400 :             int nReqXOff = (int)(dfXOff * dfXFactor + 0.5);
    1393             400 :             int nReqYOff = (int)(dfYOff * dfYFactor + 0.5);
    1394             400 :             int nReqXSize = (int)(dfXSize * dfXFactor + 0.5);
    1395             400 :             int nReqYSize = (int)(dfYSize * dfYFactor + 0.5);
    1396             400 :             if( nReqXOff + nReqXSize > poVRTDS->GetRasterXSize() )
    1397               0 :                 nReqXSize = poVRTDS->GetRasterXSize() - nReqXOff;
    1398             400 :             if( nReqYOff + nReqYSize > poVRTDS->GetRasterYSize() )
    1399               0 :                 nReqYSize = poVRTDS->GetRasterYSize() - nReqYOff;
    1400                 : 
    1401                 :             CPLErr eErr = poVRTDS->RasterIO( eRWFlag,
    1402                 :                                              nReqXOff,
    1403                 :                                              nReqYOff,
    1404                 :                                              nReqXSize,
    1405                 :                                              nReqYSize,
    1406                 :                                              pData, nBufXSize, nBufYSize, eBufType,
    1407                 :                                              nBandCount, panBandMap,
    1408             400 :                                              nPixelSpace, nLineSpace, nBandSpace );
    1409                 : 
    1410            1200 :             for(i=0; i < (int)aosImages.size(); i++)
    1411                 :             {
    1412             800 :                  aosImages[i].poDS->Dereference();
    1413                 :             }
    1414                 : 
    1415             400 :             delete poVRTDS;
    1416                 : 
    1417             400 :             return eErr;
    1418               0 :         }
    1419                 :     }
    1420                 : 
    1421            3616 :     for(int iBandIdx = 0; iBandIdx < nBandCount; iBandIdx++ )
    1422                 :     {
    1423            1808 :         int nBand = panBandMap[iBandIdx];
    1424                 : 
    1425            1808 :         if( (nIconCount > 1 || nBand == 4) && nBand > nIconCount )
    1426                 :         {
    1427               0 :             GByte nVal = (nBand == 4) ? 255 : 0;
    1428               0 :             for(int j = 0; j < nBufYSize; j ++ )
    1429                 :             {
    1430                 :                 GDALCopyWords( &nVal, GDT_Byte, 0,
    1431                 :                             ((GByte*) pData) + j * nLineSpace + iBandIdx * nBandSpace, eBufType, nPixelSpace,
    1432               0 :                             nBufXSize );
    1433                 :             }
    1434               0 :             continue;
    1435                 :         }
    1436                 : 
    1437            1808 :         int nIconBand = (nIconCount == 1) ? 1 : nBand;
    1438                 : 
    1439            1808 :         int nReqXOff = (int)(dfXOff + 0.5);
    1440            1808 :         int nReqYOff = (int)(dfYOff + 0.5);
    1441            1808 :         int nReqXSize = (int)(dfXSize + 0.5);
    1442            1808 :         int nReqYSize = (int)(dfYSize + 0.5);
    1443            1808 :         if( nReqXOff + nReqXSize > poDSIcon->GetRasterXSize() )
    1444               0 :             nReqXSize = poDSIcon->GetRasterXSize() - nReqXOff;
    1445            1808 :         if( nReqYOff + nReqYSize > poDSIcon->GetRasterYSize() )
    1446               0 :             nReqYSize = poDSIcon->GetRasterYSize() - nReqYOff;
    1447                 : 
    1448                 :         poDSIcon->GetRasterBand(nIconBand)->RasterIO( eRWFlag,
    1449                 :                                                       nReqXOff,
    1450                 :                                                       nReqYOff,
    1451                 :                                                       nReqXSize,
    1452                 :                                                       nReqYSize,
    1453                 :                                                       ((GByte*) pData) + nBandSpace * iBandIdx,
    1454                 :                                                       nBufXSize, nBufYSize, eBufType,
    1455            1808 :                                                       nPixelSpace, nLineSpace );
    1456                 :     }
    1457                 : 
    1458            1808 :     return CE_None;
    1459                 : 
    1460                 : }
    1461                 : 
    1462                 : /************************************************************************/
    1463                 : /*                    KmlSuperOverlayFindRegionStart()                  */
    1464                 : /************************************************************************/
    1465                 : 
    1466                 : static
    1467             552 : int KmlSuperOverlayFindRegionStart(CPLXMLNode* psNode,
    1468                 :                                    CPLXMLNode** ppsRegion,
    1469                 :                                    CPLXMLNode** ppsDocument,
    1470                 :                                    CPLXMLNode** ppsGroundOverlay,
    1471                 :                                    CPLXMLNode** ppsLink)
    1472                 : {
    1473             552 :     if( psNode == NULL || psNode->eType != CXT_Element )
    1474               0 :         return FALSE;
    1475                 : 
    1476             552 :     CPLXMLNode* psRegion = NULL;
    1477             552 :     CPLXMLNode* psLink = NULL;
    1478             552 :     CPLXMLNode* psGroundOverlay = NULL;
    1479             552 :     if( strcmp(psNode->pszValue, "NetworkLink") == 0 &&
    1480                 :         (psRegion = CPLGetXMLNode(psNode, "Region")) != NULL &&
    1481                 :         (psLink = CPLGetXMLNode(psNode, "Link")) != NULL )
    1482                 :     {
    1483              20 :         *ppsRegion = psRegion;
    1484              20 :         *ppsLink = psLink;
    1485              20 :         return TRUE;
    1486                 :     }
    1487             532 :     if( strcmp(psNode->pszValue, "Document") == 0 &&
    1488                 :         (psRegion = CPLGetXMLNode(psNode, "Region")) != NULL &&
    1489                 :         (psGroundOverlay = CPLGetXMLNode(psNode, "GroundOverlay")) != NULL )
    1490                 :     {
    1491              26 :         *ppsDocument = psNode;
    1492              26 :         *ppsRegion = psRegion;
    1493              26 :         *ppsGroundOverlay = psGroundOverlay;
    1494              26 :         return TRUE;
    1495                 :     }
    1496                 : 
    1497             506 :     CPLXMLNode* psIter = psNode->psChild;
    1498            1584 :     while(psIter != NULL)
    1499                 :     {
    1500             638 :         if( psIter->eType == CXT_Element )
    1501                 :         {
    1502             206 :             if( KmlSuperOverlayFindRegionStart(psIter, ppsRegion, ppsDocument,
    1503                 :                                                ppsGroundOverlay, ppsLink) )
    1504              66 :                 return TRUE;
    1505                 :         }
    1506                 : 
    1507             572 :         psIter = psIter->psNext;
    1508                 :     }
    1509                 : 
    1510             440 :     psIter = psNode->psNext;
    1511            1100 :     while(psIter != NULL)
    1512                 :     {
    1513             300 :         if( psIter->eType == CXT_Element )
    1514                 :         {
    1515             300 :             if( KmlSuperOverlayFindRegionStart(psIter, ppsRegion, ppsDocument,
    1516                 :                                                ppsGroundOverlay, ppsLink) )
    1517              80 :                 return TRUE;
    1518                 :         }
    1519                 : 
    1520             220 :         psIter = psIter->psNext;
    1521                 :     }
    1522                 : 
    1523             360 :     return FALSE;
    1524                 : }
    1525                 : 
    1526                 : 
    1527                 : /************************************************************************/
    1528                 : /*                             Identify()                               */
    1529                 : /************************************************************************/
    1530                 : 
    1531           11651 : int KmlSuperOverlayReadDataset::Identify(GDALOpenInfo * poOpenInfo)
    1532                 : 
    1533                 : {
    1534           11651 :     const char* pszExt = CPLGetExtension(poOpenInfo->pszFilename);
    1535           11651 :     if( EQUAL(pszExt, "kmz") )
    1536              36 :         return TRUE;
    1537           11615 :     if( poOpenInfo->nHeaderBytes == 0 )
    1538           11216 :         return FALSE;
    1539             399 :     if( EQUAL(pszExt, "kml") &&
    1540                 :         strstr((const char*)poOpenInfo->pabyHeader, "<kml") != NULL )
    1541               4 :         return TRUE;
    1542             395 :     return FALSE;
    1543                 : }
    1544                 : 
    1545                 : /************************************************************************/
    1546                 : /*                                Open()                                */
    1547                 : /************************************************************************/
    1548                 : 
    1549            1567 : GDALDataset *KmlSuperOverlayReadDataset::Open(GDALOpenInfo * poOpenInfo)
    1550                 : 
    1551                 : {
    1552            1567 :     if( !Identify(poOpenInfo) )
    1553            1547 :         return NULL;
    1554                 : 
    1555              20 :     return Open(poOpenInfo->pszFilename);
    1556                 : }
    1557                 : 
    1558                 : /************************************************************************/
    1559                 : /*                         KmlSuperOverlayLoadIcon()                    */
    1560                 : /************************************************************************/
    1561                 : 
    1562                 : #define BUFFER_SIZE 100000
    1563                 : 
    1564                 : static
    1565              23 : GDALDataset* KmlSuperOverlayLoadIcon(const char* pszBaseFilename, const char* pszIcon)
    1566                 : {
    1567              23 :     const char* pszExt = CPLGetExtension(pszIcon);
    1568              23 :     if( !EQUAL(pszExt, "png") && !EQUAL(pszExt, "jpg") && !EQUAL(pszExt, "jpeg") )
    1569                 :     {
    1570               0 :         return NULL;
    1571                 :     }
    1572                 : 
    1573              23 :     CPLString osSubFilename;
    1574              23 :     if( strncmp(pszIcon, "http", 4) == 0)
    1575               0 :         osSubFilename = CPLSPrintf("/vsicurl_streaming/%s", pszIcon);
    1576                 :     else
    1577                 :     {
    1578              23 :         osSubFilename = CPLGetPath(pszBaseFilename);
    1579              23 :         osSubFilename += "/";
    1580              23 :         osSubFilename += pszIcon;
    1581              23 :         osSubFilename = KMLRemoveSlash(osSubFilename);
    1582                 :     }
    1583                 : 
    1584              23 :     VSILFILE* fp = VSIFOpenL(osSubFilename, "rb");
    1585              23 :     if( fp == NULL )
    1586                 :     {
    1587               0 :         return NULL;
    1588                 :     }
    1589              23 :     GByte* pabyBuffer = (GByte*) CPLMalloc(BUFFER_SIZE);
    1590              23 :     int nRead = (int)VSIFReadL(pabyBuffer, 1, BUFFER_SIZE, fp);
    1591              23 :     VSIFCloseL(fp);
    1592              23 :     if( nRead == BUFFER_SIZE )
    1593                 :     {
    1594               0 :         CPLFree(pabyBuffer);
    1595               0 :         return NULL;
    1596                 :     }
    1597                 : 
    1598                 :     static int nInc = 0;
    1599              23 :     osSubFilename = CPLSPrintf("/vsimem/kmlsuperoverlay/%d_%p", nInc++, pszBaseFilename);
    1600              23 :     VSIFCloseL(VSIFileFromMemBuffer( osSubFilename, pabyBuffer, nRead, TRUE) );
    1601                 : 
    1602              23 :     GDALDataset* poDSIcon = (GDALDataset* )GDALOpen(osSubFilename, GA_ReadOnly);
    1603              23 :     if( poDSIcon == NULL )
    1604                 :     {
    1605               0 :         VSIUnlink(osSubFilename);
    1606               0 :         return NULL;
    1607                 :     }
    1608                 : 
    1609              23 :     return poDSIcon;
    1610                 : }
    1611                 : 
    1612                 : 
    1613                 : /************************************************************************/
    1614                 : /*                    KmlSuperOverlayComputeDepth()                     */
    1615                 : /************************************************************************/
    1616                 : 
    1617              21 : static void KmlSuperOverlayComputeDepth(CPLString osFilename,
    1618                 :                                         CPLXMLNode* psDocument,
    1619                 :                                         int& nLevel)
    1620                 : {
    1621              21 :     CPLXMLNode* psIter = psDocument->psChild;
    1622             126 :     while(psIter != NULL)
    1623                 :     {
    1624              86 :         const char* pszHref = NULL;
    1625              86 :         if( psIter->eType == CXT_Element &&
    1626                 :             strcmp(psIter->pszValue, "NetworkLink") == 0 &&
    1627                 :             CPLGetXMLNode(psIter, "Region") != NULL &&
    1628                 :             (pszHref = CPLGetXMLValue(psIter, "Link.href", NULL)) != NULL )
    1629                 :         {
    1630               2 :             const char* pszExt = CPLGetExtension(pszHref);
    1631               2 :             if( EQUAL(pszExt, "kml") )
    1632                 :             {
    1633               2 :                 CPLString osSubFilename;
    1634               2 :                 if( strncmp(pszHref, "http", 4) == 0)
    1635               0 :                     osSubFilename = CPLSPrintf("/vsicurl_streaming/%s", pszHref);
    1636                 :                 else
    1637                 :                 {
    1638               2 :                     osSubFilename = CPLGetPath(osFilename);
    1639               2 :                     osSubFilename += "/";
    1640               2 :                     osSubFilename += pszHref;
    1641               2 :                     osSubFilename = KMLRemoveSlash(osSubFilename);
    1642                 :                 }
    1643                 : 
    1644               2 :                 VSILFILE* fp = VSIFOpenL(osSubFilename, "rb");
    1645               2 :                 if( fp != NULL )
    1646                 :                 {
    1647               2 :                     char* pszBuffer = (char*) CPLMalloc(BUFFER_SIZE+1);
    1648               2 :                     int nRead = (int)VSIFReadL(pszBuffer, 1, BUFFER_SIZE, fp);
    1649               2 :                     pszBuffer[nRead] = '\0';
    1650               2 :                     VSIFCloseL(fp);
    1651               2 :                     if( nRead == BUFFER_SIZE )
    1652                 :                     {
    1653               0 :                         CPLFree(pszBuffer);
    1654                 :                     }
    1655                 :                     else
    1656                 :                     {
    1657               2 :                         CPLXMLNode* psNode = CPLParseXMLString(pszBuffer);
    1658               2 :                         CPLFree(pszBuffer);
    1659               2 :                         if( psNode != NULL )
    1660                 :                         {
    1661               2 :                             CPLXMLNode* psRegion = NULL;
    1662               2 :                             CPLXMLNode* psNewDocument = NULL;
    1663               2 :                             CPLXMLNode* psGroundOverlay = NULL;
    1664               2 :                             CPLXMLNode* psLink = NULL;
    1665               2 :                             if( KmlSuperOverlayFindRegionStart(psNode, &psRegion,
    1666                 :                                             &psNewDocument, &psGroundOverlay, &psLink) &&
    1667                 :                                 psNewDocument != NULL && nLevel < 20 )
    1668                 :                             {
    1669               2 :                                 nLevel ++;
    1670               2 :                                 KmlSuperOverlayComputeDepth(osSubFilename, psNewDocument, nLevel);
    1671                 :                             }
    1672               2 :                             CPLDestroyXMLNode(psNode);
    1673                 :                             break;
    1674                 :                         }
    1675                 :                     }
    1676               0 :                 }
    1677                 :             }
    1678                 :         }
    1679              84 :         psIter = psIter->psNext;
    1680                 :     }
    1681              21 : }
    1682                 : 
    1683                 : /************************************************************************/
    1684                 : /*                                Open()                                */
    1685                 : /************************************************************************/
    1686                 : 
    1687              44 : GDALDataset *KmlSuperOverlayReadDataset::Open(const char* pszFilename,
    1688                 :                                               KmlSuperOverlayReadDataset* poParent,
    1689                 :                                               int nRec)
    1690                 : 
    1691                 : {
    1692              44 :     if( nRec == 2 )
    1693               0 :         return NULL;
    1694              44 :     CPLString osFilename(pszFilename);
    1695              44 :     const char* pszExt = CPLGetExtension(pszFilename);
    1696              44 :     if( EQUAL(pszExt, "kmz") )
    1697                 :     {
    1698              16 :         if( strncmp(pszFilename, "/vsizip/", 8) != 0 )
    1699              16 :             osFilename = CPLSPrintf("/vsizip/%s", pszFilename);
    1700              16 :         char** papszFiles = CPLReadDir(osFilename);
    1701              16 :         if( papszFiles == NULL )
    1702               0 :             return NULL;
    1703              16 :         char** papszIter = papszFiles;
    1704              16 :         for(; *papszIter != NULL; papszIter ++)
    1705                 :         {
    1706              16 :             pszExt = CPLGetExtension(*papszIter);
    1707              16 :             if( EQUAL(pszExt, "kml") )
    1708                 :             {
    1709              16 :                 osFilename = CPLFormFilename(osFilename, *papszIter, NULL);
    1710              16 :                 osFilename = KMLRemoveSlash(osFilename);
    1711              16 :                 break;
    1712                 :             }
    1713                 :         }
    1714              16 :         CSLDestroy(papszFiles);
    1715                 :     }
    1716              44 :     VSILFILE* fp = VSIFOpenL(osFilename, "rb");
    1717              44 :     if( fp == NULL )
    1718               0 :         return NULL;
    1719              44 :     char* pszBuffer = (char*) CPLMalloc(BUFFER_SIZE+1);
    1720              44 :     int nRead = (int)VSIFReadL(pszBuffer, 1, BUFFER_SIZE, fp);
    1721              44 :     pszBuffer[nRead] = '\0';
    1722              44 :     VSIFCloseL(fp);
    1723              44 :     if( nRead == BUFFER_SIZE )
    1724                 :     {
    1725               0 :         CPLFree(pszBuffer);
    1726               0 :         return NULL;
    1727                 :     }
    1728                 : 
    1729              44 :     CPLXMLNode* psNode = CPLParseXMLString(pszBuffer);
    1730              44 :     CPLFree(pszBuffer);
    1731              44 :     if( psNode == NULL )
    1732               0 :         return NULL;
    1733                 : 
    1734              44 :     CPLXMLNode* psRegion = NULL;
    1735              44 :     CPLXMLNode* psDocument = NULL;
    1736              44 :     CPLXMLNode* psGroundOverlay = NULL;
    1737              44 :     CPLXMLNode* psLink = NULL;
    1738              44 :     if( !KmlSuperOverlayFindRegionStart(psNode, &psRegion,
    1739                 :                                         &psDocument, &psGroundOverlay, &psLink) )
    1740                 :     {
    1741               0 :         CPLDestroyXMLNode(psNode);
    1742               0 :         return NULL;
    1743                 :     }
    1744                 : 
    1745              44 :     if( psLink != NULL )
    1746                 :     {
    1747              20 :         const char* pszHref = CPLGetXMLValue(psLink, "href", NULL);
    1748              20 :         if( pszHref == NULL || !EQUAL(CPLGetExtension(pszHref), "kml") )
    1749                 :         {
    1750               0 :             CPLDestroyXMLNode(psNode);
    1751               0 :             return NULL;
    1752                 :         }
    1753                 : 
    1754              20 :         CPLString osSubFilename;
    1755              20 :         if( strncmp(pszHref, "http", 4) == 0)
    1756               0 :             osSubFilename = CPLSPrintf("/vsicurl_streaming/%s", pszHref);
    1757                 :         else
    1758                 :         {
    1759              20 :             osSubFilename = CPLGetPath(osFilename);
    1760              20 :             osSubFilename += "/";
    1761              20 :             osSubFilename += pszHref;
    1762              20 :             osSubFilename = KMLRemoveSlash(osSubFilename);
    1763                 :         }
    1764              20 :         CPLDestroyXMLNode(psNode);
    1765                 : 
    1766                 :         // FIXME
    1767              20 :         GDALDataset* poDS = Open(osSubFilename, poParent, nRec + 1);
    1768              20 :         if( poDS != NULL )
    1769              19 :             poDS->SetDescription(pszFilename);
    1770              20 :         return poDS;
    1771                 :     }
    1772                 : 
    1773              24 :     CPLAssert(psDocument != NULL);
    1774              24 :     CPLAssert(psGroundOverlay != NULL);
    1775              24 :     CPLAssert(psRegion != NULL);
    1776                 : 
    1777                 :     double adfExtents[4];
    1778              24 :     if( !KmlSuperOverlayGetBoundingBox(psGroundOverlay, adfExtents) )
    1779                 :     {
    1780               1 :         CPLDestroyXMLNode(psNode);
    1781               1 :         return NULL;
    1782                 :     }
    1783                 : 
    1784              23 :     const char* pszIcon = CPLGetXMLValue(psGroundOverlay, "Icon.href", NULL);
    1785              23 :     if( pszIcon == NULL )
    1786                 :     {
    1787               0 :         CPLDestroyXMLNode(psNode);
    1788               0 :         return NULL;
    1789                 :     }
    1790              23 :     GDALDataset* poDSIcon = KmlSuperOverlayLoadIcon(pszFilename,  pszIcon);
    1791              23 :     if( poDSIcon == NULL )
    1792                 :     {
    1793               0 :         CPLDestroyXMLNode(psNode);
    1794               0 :         return NULL;
    1795                 :     }
    1796                 : 
    1797                 :     int nFactor;
    1798              23 :     if( poParent != NULL )
    1799               4 :         nFactor = poParent->nFactor / 2;
    1800                 :     else
    1801                 :     {
    1802              19 :         int nDepth = 0;
    1803              19 :         KmlSuperOverlayComputeDepth(pszFilename, psDocument, nDepth);
    1804              19 :         nFactor = 1 << nDepth;
    1805                 :     }
    1806                 : 
    1807              23 :     KmlSuperOverlayReadDataset* poDS = new KmlSuperOverlayReadDataset();
    1808              46 :     poDS->osFilename = pszFilename;
    1809              23 :     poDS->psRoot = psNode;
    1810              23 :     poDS->psDocument = psDocument;
    1811              23 :     poDS->poDSIcon = poDSIcon;
    1812              23 :     poDS->poParent = poParent;
    1813              23 :     poDS->nFactor = nFactor;
    1814              23 :     poDS->nRasterXSize = nFactor * poDSIcon->GetRasterXSize();
    1815              23 :     poDS->nRasterYSize = nFactor * poDSIcon->GetRasterYSize();
    1816              23 :     poDS->adfGeoTransform[0] = adfExtents[0];
    1817              23 :     poDS->adfGeoTransform[1] = (adfExtents[2] - adfExtents[0]) / poDS->nRasterXSize;
    1818              23 :     poDS->adfGeoTransform[3] = adfExtents[3];
    1819              23 :     poDS->adfGeoTransform[5] = -(adfExtents[3] - adfExtents[1]) / poDS->nRasterYSize;
    1820              23 :     poDS->nBands = 4;
    1821             115 :     for(int i=0;i<4;i++)
    1822              92 :         poDS->SetBand(i+1, new KmlSuperOverlayRasterBand(poDS, i+1));
    1823              23 :     poDS->SetDescription(pszFilename);
    1824              23 :     poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    1825                 : 
    1826              48 :     while( poDS->poParent == NULL && nFactor > 1 )
    1827                 :     {
    1828               2 :         nFactor /= 2;
    1829                 : 
    1830               2 :         KmlSuperOverlayReadDataset* poOvrDS = new KmlSuperOverlayReadDataset();
    1831                 : 
    1832                 :         poDS->papoOverviewDS = (KmlSuperOverlayReadDataset**) CPLRealloc(
    1833               4 :             poDS->papoOverviewDS, (poDS->nOverviewCount + 1) * sizeof(KmlSuperOverlayReadDataset*));
    1834               2 :         poDS->papoOverviewDS[poDS->nOverviewCount ++] = poOvrDS;
    1835                 : 
    1836               2 :         poOvrDS->bIsOvr = TRUE;
    1837               2 :         poOvrDS->poParent = poDS;
    1838               2 :         poOvrDS->nFactor = nFactor;
    1839               2 :         poOvrDS->nRasterXSize = nFactor * poDSIcon->GetRasterXSize();
    1840               2 :         poOvrDS->nRasterYSize = nFactor * poDSIcon->GetRasterYSize();
    1841               2 :         poOvrDS->adfGeoTransform[0] = adfExtents[0];
    1842               2 :         poOvrDS->adfGeoTransform[1] = (adfExtents[2] - adfExtents[0]) / poOvrDS->nRasterXSize;
    1843               2 :         poOvrDS->adfGeoTransform[3] = adfExtents[3];
    1844               2 :         poOvrDS->adfGeoTransform[5] = -(adfExtents[3] - adfExtents[1]) / poOvrDS->nRasterYSize;
    1845               2 :         poOvrDS->nBands = 4;
    1846              10 :         for(int i=0;i<4;i++)
    1847               8 :             poOvrDS->SetBand(i+1, new KmlSuperOverlayRasterBand(poOvrDS, i+1));
    1848               2 :         poOvrDS->SetDescription(pszFilename);
    1849               2 :         poOvrDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    1850                 :     }
    1851                 : 
    1852              23 :     return poDS;
    1853                 : }
    1854                 : 
    1855                 : /************************************************************************/
    1856                 : /*                    KmlSuperOverlayDatasetDelete()                    */
    1857                 : /************************************************************************/
    1858                 : 
    1859              22 : static CPLErr KmlSuperOverlayDatasetDelete(const char* fileName)
    1860                 : {
    1861                 :     /* Null implementation, so that people can Delete("MEM:::") */
    1862              22 :     return CE_None;
    1863                 : }
    1864                 : 
    1865                 : /************************************************************************/
    1866                 : /*                    GDALRegister_KMLSUPEROVERLAY()                    */
    1867                 : /************************************************************************/
    1868                 : 
    1869             582 : void GDALRegister_KMLSUPEROVERLAY()
    1870                 :    
    1871                 : {
    1872                 :     GDALDriver  *poDriver;
    1873                 :    
    1874             582 :     if( GDALGetDriverByName( "KMLSUPEROVERLAY" ) == NULL )
    1875                 :     {
    1876             561 :         poDriver = new GDALDriver();
    1877                 :       
    1878             561 :         poDriver->SetDescription( "KMLSUPEROVERLAY" );
    1879                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1880             561 :                                    "Kml Super Overlay" );
    1881                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    1882             561 :                                    "Byte Int16 UInt16 Int32 UInt32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64" );
    1883                 : 
    1884                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    1885                 : "<CreationOptionList>"
    1886                 : "   <Option name='FORMAT' type='string-select' default='JPEG' description='Force of the tiles'>"
    1887                 : "       <Value>PNG</Value>"
    1888                 : "       <Value>JPEG</Value>"
    1889                 : "   </Option>"
    1890                 : "   <Option name='FIX_ANTIMERIDIAN' type='boolean' description='Fix for images crossing the antimeridian causing errors in Google Earth' />"
    1891             561 : "</CreationOptionList>" );
    1892                 : 
    1893             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1894                 : 
    1895             561 :         poDriver->pfnIdentify = KmlSuperOverlayReadDataset::Identify;
    1896             561 :         poDriver->pfnOpen = KmlSuperOverlayReadDataset::Open;
    1897             561 :         poDriver->pfnCreateCopy = KmlSuperOverlayCreateCopy;
    1898             561 :         poDriver->pfnDelete = KmlSuperOverlayDatasetDelete;
    1899                 :       
    1900             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1901                 :     }
    1902            2721 : }
    1903                 : 

Generated by: LCOV version 1.7