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