1 : /******************************************************************************
2 : * $Id: rasterband.cpp 24233 2012-04-14 13:17:49Z rouault $
3 : *
4 : * Project: WMS Client Driver
5 : * Purpose: Implementation of Dataset and RasterBand classes for WMS
6 : * and other similar services.
7 : * Author: Adam Nowacki, nowak@xpam.de
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2007, Adam Nowacki
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "stdinc.h"
32 :
33 695 : GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, double scale) {
34 : // printf("[%p] GDALWMSRasterBand::GDALWMSRasterBand(%p, %d, %f)\n", this, parent_dataset, band, scale);
35 695 : m_parent_dataset = parent_dataset;
36 695 : m_scale = scale;
37 695 : m_overview = -1;
38 695 : m_color_interp = GCI_Undefined;
39 :
40 695 : poDS = parent_dataset;
41 695 : nRasterXSize = static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale + 0.5);
42 695 : nRasterYSize = static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale + 0.5);
43 695 : nBand = band;
44 695 : eDataType = m_parent_dataset->m_data_type;
45 695 : nBlockXSize = m_parent_dataset->m_block_size_x;
46 695 : nBlockYSize = m_parent_dataset->m_block_size_y;
47 695 : }
48 :
49 695 : GDALWMSRasterBand::~GDALWMSRasterBand() {
50 1352 : for (std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin(); it != m_overviews.end(); ++it) {
51 657 : GDALWMSRasterBand *p = *it;
52 657 : delete p;
53 : }
54 695 : }
55 :
56 7 : char** GDALWMSRasterBand::BuildHTTPRequestOpts()
57 : {
58 7 : char **http_request_opts = NULL;
59 7 : if (m_parent_dataset->m_http_timeout != -1) {
60 7 : CPLString http_request_optstr;
61 7 : http_request_optstr.Printf("TIMEOUT=%d", m_parent_dataset->m_http_timeout);
62 7 : http_request_opts = CSLAddString(http_request_opts, http_request_optstr.c_str());
63 : }
64 :
65 7 : if (m_parent_dataset->m_osUserAgent.size() != 0)
66 : {
67 0 : CPLString osUserAgentOptStr("USERAGENT=");
68 0 : osUserAgentOptStr += m_parent_dataset->m_osUserAgent;
69 0 : http_request_opts = CSLAddString(http_request_opts, osUserAgentOptStr.c_str());
70 : }
71 7 : if (m_parent_dataset->m_osReferer.size() != 0)
72 : {
73 0 : CPLString osRefererOptStr("REFERER=");
74 0 : osRefererOptStr += m_parent_dataset->m_osReferer;
75 0 : http_request_opts = CSLAddString(http_request_opts, osRefererOptStr.c_str());
76 : }
77 7 : if (m_parent_dataset->m_unsafeSsl >= 1) {
78 0 : http_request_opts = CSLAddString(http_request_opts, "UNSAFESSL=1");
79 : }
80 :
81 7 : return http_request_opts;
82 : }
83 :
84 5 : CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1, int by1, int advise_read) {
85 5 : CPLErr ret = CE_None;
86 : int i;
87 :
88 5 : int max_request_count = (bx1 - bx0 + 1) * (by1 - by0 + 1);
89 5 : int request_count = 0;
90 5 : CPLHTTPRequest *download_requests = NULL;
91 5 : GDALWMSCache *cache = m_parent_dataset->m_cache;
92 : struct BlockXY {
93 : int x, y;
94 5 : } *download_blocks = NULL;
95 5 : if (!m_parent_dataset->m_offline_mode) {
96 5 : download_requests = new CPLHTTPRequest[max_request_count];
97 5 : download_blocks = new BlockXY[max_request_count];
98 : }
99 :
100 5 : char **http_request_opts = BuildHTTPRequestOpts();
101 :
102 10 : for (int iy = by0; iy <= by1; ++iy) {
103 14 : for (int ix = bx0; ix <= bx1; ++ix) {
104 9 : bool need_this_block = false;
105 9 : if (!advise_read) {
106 32 : for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
107 28 : if ((ix == x) && (iy == y) && (ib == nBand)) {
108 5 : need_this_block = true;
109 : } else {
110 18 : GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
111 18 : if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
112 18 : if (!band->IsBlockInCache(ix, iy)) need_this_block = true;
113 : }
114 : }
115 : } else {
116 0 : need_this_block = true;
117 : }
118 9 : CPLString url;
119 9 : if (need_this_block) {
120 9 : CPLString file_name;
121 9 : AskMiniDriverForBlock(&url, ix, iy);
122 9 : if ((cache != NULL) && (cache->Read(url.c_str(), &file_name) == CE_None)) {
123 2 : if (advise_read) {
124 0 : need_this_block = false;
125 : } else {
126 2 : void *p = 0;
127 2 : if ((ix == x) && (iy == y)) p = buffer;
128 2 : if (ReadBlockFromFile(ix, iy, file_name.c_str(), nBand, p, 0) == CE_None) need_this_block = false;
129 : }
130 9 : }
131 : }
132 9 : if (need_this_block) {
133 7 : if (m_parent_dataset->m_offline_mode) {
134 0 : if (!advise_read) {
135 0 : void *p = 0;
136 0 : if ((ix == x) && (iy == y)) p = buffer;
137 0 : if (ZeroBlock(ix, iy, nBand, p) != CE_None) {
138 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
139 0 : ret = CE_Failure;
140 : }
141 : }
142 : } else {
143 7 : CPLHTTPInitializeRequest(&download_requests[request_count], url.c_str(), http_request_opts);
144 7 : download_blocks[request_count].x = ix;
145 7 : download_blocks[request_count].y = iy;
146 7 : ++request_count;
147 : }
148 : }
149 : }
150 : }
151 5 : if (http_request_opts != NULL) {
152 5 : CSLDestroy(http_request_opts);
153 : }
154 :
155 5 : if (request_count > 0) {
156 4 : char **opts = NULL;
157 4 : CPLString optstr;
158 4 : if (m_parent_dataset->m_http_max_conn != -1) {
159 4 : optstr.Printf("MAXCONN=%d", m_parent_dataset->m_http_max_conn);
160 4 : opts = CSLAddString(opts, optstr.c_str());
161 : }
162 4 : if (CPLHTTPFetchMulti(download_requests, request_count, opts) != CE_None) {
163 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: CPLHTTPFetchMulti failed.");
164 0 : ret = CE_Failure;
165 : }
166 4 : if (opts != NULL) {
167 4 : CSLDestroy(opts);
168 4 : }
169 : }
170 :
171 12 : for (i = 0; i < request_count; ++i) {
172 7 : if (ret == CE_None) {
173 14 : if ((download_requests[i].nStatus == 200) && (download_requests[i].pabyData != NULL) && (download_requests[i].nDataLen > 0)) {
174 7 : CPLString file_name(BufferToVSIFile(download_requests[i].pabyData, download_requests[i].nDataLen));
175 7 : if (file_name.size() > 0) {
176 7 : bool wms_exception = false;
177 : /* check for error xml */
178 7 : if (download_requests[i].nDataLen >= 20) {
179 7 : const char *download_data = reinterpret_cast<char *>(download_requests[i].pabyData);
180 7 : if (EQUALN(download_data, "<?xml ", 6)
181 : || EQUALN(download_data, "<!DOCTYPE ", 10)
182 : || EQUALN(download_data, "<ServiceException", 17)) {
183 0 : if (ReportWMSException(file_name.c_str()) != CE_None) {
184 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned unknown exception.");
185 : }
186 0 : wms_exception = true;
187 0 : ret = CE_Failure;
188 : }
189 : }
190 7 : if (ret == CE_None) {
191 7 : if (advise_read && !m_parent_dataset->m_verify_advise_read) {
192 0 : if (cache != NULL) {
193 0 : cache->Write(download_requests[i].pszURL, file_name);
194 : }
195 : } else {
196 7 : void *p = 0;
197 7 : if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
198 7 : if (ReadBlockFromFile(download_blocks[i].x, download_blocks[i].y, file_name.c_str(), nBand, p, advise_read) == CE_None) {
199 7 : if (cache != NULL) {
200 2 : cache->Write(download_requests[i].pszURL, file_name);
201 : }
202 : } else {
203 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ReadBlockFromFile (%s) failed.",
204 0 : download_requests[i].pszURL);
205 0 : ret = CE_Failure;
206 : }
207 : }
208 0 : } else if( wms_exception && m_parent_dataset->m_zeroblock_on_serverexceptions ) {
209 0 : void *p = 0;
210 0 : if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
211 0 : if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) {
212 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
213 : } else {
214 0 : ret = CE_None;
215 : }
216 :
217 : }
218 7 : VSIUnlink(file_name.c_str());
219 7 : }
220 : } else {
221 : std::vector<int>::iterator zero_it = std::find(
222 : m_parent_dataset->m_http_zeroblock_codes.begin(),
223 : m_parent_dataset->m_http_zeroblock_codes.end(),
224 0 : download_requests[i].nStatus);
225 0 : if ( zero_it != m_parent_dataset->m_http_zeroblock_codes.end() ) {
226 0 : if (!advise_read) {
227 0 : void *p = 0;
228 0 : if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
229 0 : if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) {
230 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
231 0 : ret = CE_Failure;
232 : }
233 : }
234 : } else {
235 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to download block %d, %d.\n URL: %s\n HTTP status code: %d, error: %s.",
236 0 : download_blocks[i].x, download_blocks[i].y, download_requests[i].pszURL, download_requests[i].nStatus,
237 0 : download_requests[i].pszError ? download_requests[i].pszError : "(null)");
238 0 : ret = CE_Failure;
239 : }
240 : }
241 : }
242 7 : CPLHTTPCleanupRequest(&download_requests[i]);
243 : }
244 5 : if (!m_parent_dataset->m_offline_mode) {
245 5 : delete[] download_blocks;
246 5 : delete[] download_requests;
247 : }
248 :
249 5 : return ret;
250 : }
251 :
252 5 : CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer) {
253 5 : int bx0 = x;
254 5 : int by0 = y;
255 5 : int bx1 = x;
256 5 : int by1 = y;
257 :
258 5 : if ((m_parent_dataset->m_hint.m_valid) && (m_parent_dataset->m_hint.m_overview == m_overview)) {
259 5 : int tbx0 = m_parent_dataset->m_hint.m_x0 / nBlockXSize;
260 5 : int tby0 = m_parent_dataset->m_hint.m_y0 / nBlockYSize;
261 5 : int tbx1 = (m_parent_dataset->m_hint.m_x0 + m_parent_dataset->m_hint.m_sx - 1) / nBlockXSize;
262 5 : int tby1 = (m_parent_dataset->m_hint.m_y0 + m_parent_dataset->m_hint.m_sy - 1) / nBlockYSize;
263 5 : if ((tbx0 <= bx0) && (tby0 <= by0) && (tbx1 >= bx1) && (tby1 >= by1)) {
264 5 : bx0 = tbx0;
265 5 : by0 = tby0;
266 5 : bx1 = tbx1;
267 5 : by1 = tby1;
268 : }
269 : }
270 :
271 5 : CPLErr eErr = ReadBlocks(x, y, buffer, bx0, by0, bx1, by1, 0);
272 :
273 5 : if ((m_parent_dataset->m_hint.m_valid) && (m_parent_dataset->m_hint.m_overview == m_overview))
274 : {
275 5 : m_parent_dataset->m_hint.m_valid = false;
276 : }
277 :
278 5 : return eErr;
279 : }
280 :
281 220 : CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int pixel_space, int line_space) {
282 : CPLErr ret;
283 :
284 220 : if (rw != GF_Read) return CE_Failure;
285 220 : if (buffer == NULL) return CE_Failure;
286 220 : if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0)) return CE_None;
287 :
288 220 : m_parent_dataset->m_hint.m_x0 = x0;
289 220 : m_parent_dataset->m_hint.m_y0 = y0;
290 220 : m_parent_dataset->m_hint.m_sx = sx;
291 220 : m_parent_dataset->m_hint.m_sy = sy;
292 220 : m_parent_dataset->m_hint.m_overview = m_overview;
293 220 : m_parent_dataset->m_hint.m_valid = true;
294 220 : ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, pixel_space, line_space);
295 220 : m_parent_dataset->m_hint.m_valid = false;
296 :
297 220 : return ret;
298 : }
299 :
300 0 : int GDALWMSRasterBand::HasArbitraryOverviews() {
301 : // return m_parent_dataset->m_mini_driver_caps.m_has_arb_overviews;
302 0 : return 0; // not implemented yet
303 : }
304 :
305 8 : int GDALWMSRasterBand::GetOverviewCount() {
306 8 : return m_overviews.size();
307 : }
308 :
309 106 : GDALRasterBand *GDALWMSRasterBand::GetOverview(int n) {
310 106 : if ((m_overviews.size() > 0) && (static_cast<size_t>(n) < m_overviews.size())) return m_overviews[n];
311 0 : else return NULL;
312 : }
313 :
314 657 : void GDALWMSRasterBand::AddOverview(double scale) {
315 657 : GDALWMSRasterBand *overview = new GDALWMSRasterBand(m_parent_dataset, nBand, scale);
316 657 : std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin();
317 6193 : for (; it != m_overviews.end(); ++it) {
318 5536 : GDALWMSRasterBand *p = *it;
319 5536 : if (p->m_scale < scale) break;
320 : }
321 657 : m_overviews.insert(it, overview);
322 657 : it = m_overviews.begin();
323 6850 : for (int i = 0; it != m_overviews.end(); ++it, ++i) {
324 6193 : GDALWMSRasterBand *p = *it;
325 6193 : p->m_overview = i;
326 : }
327 657 : }
328 :
329 36 : bool GDALWMSRasterBand::IsBlockInCache(int x, int y) {
330 36 : bool ret = false;
331 36 : GDALRasterBlock *b = TryGetLockedBlockRef(x, y);
332 36 : if (b != NULL) {
333 0 : ret = true;
334 0 : b->DropLock();
335 : }
336 36 : return ret;
337 : }
338 :
339 : // This is the function that calculates the block coordinates for the fetch
340 9 : void GDALWMSRasterBand::AskMiniDriverForBlock(CPLString *url, int x, int y)
341 : {
342 : GDALWMSImageRequestInfo iri;
343 : GDALWMSTiledImageRequestInfo tiri;
344 :
345 9 : ComputeRequestInfo(iri, tiri, x, y);
346 :
347 9 : m_parent_dataset->m_mini_driver->TiledImageRequest(url, iri, tiri);
348 9 : }
349 :
350 13 : void GDALWMSRasterBand::ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
351 : GDALWMSTiledImageRequestInfo &tiri,
352 : int x, int y)
353 : {
354 13 : int x0 = MAX(0, x * nBlockXSize);
355 13 : int y0 = MAX(0, y * nBlockYSize);
356 13 : int x1 = MAX(0, (x + 1) * nBlockXSize);
357 13 : int y1 = MAX(0, (y + 1) * nBlockYSize);
358 13 : if (m_parent_dataset->m_clamp_requests) {
359 11 : x0 = MIN(x0, nRasterXSize);
360 11 : y0 = MIN(y0, nRasterYSize);
361 11 : x1 = MIN(x1, nRasterXSize);
362 11 : y1 = MIN(y1, nRasterYSize);
363 : }
364 :
365 13 : const double rx = (m_parent_dataset->m_data_window.m_x1 - m_parent_dataset->m_data_window.m_x0) / static_cast<double>(nRasterXSize);
366 13 : const double ry = (m_parent_dataset->m_data_window.m_y1 - m_parent_dataset->m_data_window.m_y0) / static_cast<double>(nRasterYSize);
367 : /* Use different method for x0,y0 and x1,y1 to make sure calculated values are exact for corner requests */
368 13 : iri.m_x0 = x0 * rx + m_parent_dataset->m_data_window.m_x0;
369 13 : iri.m_y0 = y0 * ry + m_parent_dataset->m_data_window.m_y0;
370 13 : iri.m_x1 = m_parent_dataset->m_data_window.m_x1 - (nRasterXSize - x1) * rx;
371 13 : iri.m_y1 = m_parent_dataset->m_data_window.m_y1 - (nRasterYSize - y1) * ry;
372 13 : iri.m_sx = x1 - x0;
373 13 : iri.m_sy = y1 - y0;
374 :
375 13 : int level = m_overview + 1;
376 13 : tiri.m_x = (m_parent_dataset->m_data_window.m_tx >> level) + x;
377 13 : tiri.m_y = (m_parent_dataset->m_data_window.m_ty >> level) + y;
378 13 : tiri.m_level = m_parent_dataset->m_data_window.m_tlevel - level;
379 13 : }
380 :
381 65 : const char *GDALWMSRasterBand::GetMetadataItem( const char * pszName,
382 : const char * pszDomain )
383 : {
384 : /* ==================================================================== */
385 : /* LocationInfo handling. */
386 : /* ==================================================================== */
387 65 : if( pszDomain != NULL
388 : && EQUAL(pszDomain,"LocationInfo")
389 : && (EQUALN(pszName,"Pixel_",6) || EQUALN(pszName,"GeoPixel_",9)) )
390 : {
391 : int iPixel, iLine;
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* What pixel are we aiming at? */
395 : /* -------------------------------------------------------------------- */
396 5 : if( EQUALN(pszName,"Pixel_",6) )
397 : {
398 0 : if( sscanf( pszName+6, "%d_%d", &iPixel, &iLine ) != 2 )
399 0 : return NULL;
400 : }
401 5 : else if( EQUALN(pszName,"GeoPixel_",9) )
402 : {
403 : double adfGeoTransform[6];
404 : double adfInvGeoTransform[6];
405 : double dfGeoX, dfGeoY;
406 :
407 : {
408 5 : CPLLocaleC oLocaleEnforcer;
409 5 : if( sscanf( pszName+9, "%lf_%lf", &dfGeoX, &dfGeoY ) != 2 )
410 0 : return NULL;
411 : }
412 :
413 5 : if( GetDataset() == NULL )
414 0 : return NULL;
415 :
416 5 : if( GetDataset()->GetGeoTransform( adfGeoTransform ) != CE_None )
417 0 : return NULL;
418 :
419 5 : if( !GDALInvGeoTransform( adfGeoTransform, adfInvGeoTransform ) )
420 0 : return NULL;
421 :
422 : iPixel = (int) floor(
423 5 : adfInvGeoTransform[0]
424 5 : + adfInvGeoTransform[1] * dfGeoX
425 5 : + adfInvGeoTransform[2] * dfGeoY );
426 : iLine = (int) floor(
427 5 : adfInvGeoTransform[3]
428 5 : + adfInvGeoTransform[4] * dfGeoX
429 5 : + adfInvGeoTransform[5] * dfGeoY );
430 :
431 : /* The GetDataset() for the WMS driver is always the main overview level, so rescale */
432 : /* the values if we are an overview */
433 5 : if (m_overview >= 0)
434 : {
435 1 : iPixel = (int) (1.0 * iPixel * GetXSize() / GetDataset()->GetRasterBand(1)->GetXSize());
436 1 : iLine = (int) (1.0 * iLine * GetYSize() / GetDataset()->GetRasterBand(1)->GetYSize());
437 : }
438 : }
439 : else
440 0 : return NULL;
441 :
442 5 : if( iPixel < 0 || iLine < 0
443 : || iPixel >= GetXSize()
444 : || iLine >= GetYSize() )
445 0 : return NULL;
446 :
447 5 : if (nBand != 1)
448 : {
449 1 : GDALRasterBand* poFirstBand = m_parent_dataset->GetRasterBand(1);
450 1 : if (m_overview >= 0)
451 0 : poFirstBand = poFirstBand->GetOverview(m_overview);
452 1 : if (poFirstBand)
453 1 : return poFirstBand->GetMetadataItem(pszName, pszDomain);
454 : }
455 :
456 : GDALWMSImageRequestInfo iri;
457 : GDALWMSTiledImageRequestInfo tiri;
458 4 : int nBlockXOff = iPixel / nBlockXSize;
459 4 : int nBlockYOff = iLine / nBlockYSize;
460 :
461 4 : ComputeRequestInfo(iri, tiri, nBlockXOff, nBlockYOff);
462 :
463 4 : CPLString url;
464 : m_parent_dataset->m_mini_driver->GetTiledImageInfo(&url,
465 : iri, tiri,
466 : iPixel % nBlockXSize,
467 4 : iLine % nBlockXSize);
468 :
469 :
470 4 : char* pszRes = NULL;
471 :
472 4 : if (url.size() != 0)
473 : {
474 4 : if (url == osMetadataItemURL)
475 : {
476 2 : return osMetadataItem.size() != 0 ? osMetadataItem.c_str() : NULL;
477 : }
478 2 : osMetadataItemURL = url;
479 :
480 2 : char **http_request_opts = BuildHTTPRequestOpts();
481 2 : CPLHTTPResult* psResult = CPLHTTPFetch( url.c_str(), http_request_opts);
482 2 : if( psResult && psResult->pabyData )
483 2 : pszRes = CPLStrdup((const char*) psResult->pabyData);
484 2 : CPLHTTPDestroyResult(psResult);
485 2 : CSLDestroy(http_request_opts);
486 : }
487 :
488 2 : if (pszRes)
489 : {
490 2 : osMetadataItem = "<LocationInfo>";
491 2 : CPLPushErrorHandler(CPLQuietErrorHandler);
492 2 : CPLXMLNode* psXML = CPLParseXMLString(pszRes);
493 2 : CPLPopErrorHandler();
494 4 : if (psXML != NULL && psXML->eType == CXT_Element)
495 : {
496 2 : if (strcmp(psXML->pszValue, "?xml") == 0)
497 : {
498 2 : if (psXML->psNext)
499 : {
500 2 : char* pszXML = CPLSerializeXMLTree(psXML->psNext);
501 2 : osMetadataItem += pszXML;
502 2 : CPLFree(pszXML);
503 : }
504 : }
505 : else
506 : {
507 0 : osMetadataItem += pszRes;
508 : }
509 : }
510 : else
511 : {
512 0 : char* pszEscapedXML = CPLEscapeString(pszRes, -1, CPLES_XML_BUT_QUOTES);
513 0 : osMetadataItem += pszEscapedXML;
514 0 : CPLFree(pszEscapedXML);
515 : }
516 2 : if (psXML != NULL)
517 2 : CPLDestroyXMLNode(psXML);
518 :
519 2 : osMetadataItem += "</LocationInfo>";
520 2 : CPLFree(pszRes);
521 2 : return osMetadataItem.c_str();
522 : }
523 : else
524 : {
525 0 : osMetadataItem = "";
526 0 : return NULL;
527 0 : }
528 : }
529 :
530 60 : return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
531 : }
532 :
533 9 : CPLErr GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name, int to_buffer_band, void *buffer, int advise_read) {
534 9 : CPLErr ret = CE_None;
535 9 : GDALDataset *ds = 0;
536 9 : GByte *color_table = NULL;
537 : int i;
538 :
539 : //CPLDebug("WMS", "ReadBlockFromFile: to_buffer_band=%d, (x,y)=(%d, %d)", to_buffer_band, x, y);
540 :
541 : /* expected size */
542 9 : const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) - MIN(MAX(0, x * nBlockXSize), nRasterXSize);
543 9 : const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) - MIN(MAX(0, y * nBlockYSize), nRasterYSize);
544 9 : ds = reinterpret_cast<GDALDataset*>(GDALOpen(file_name, GA_ReadOnly));
545 9 : if (ds != NULL) {
546 9 : int sx = ds->GetRasterXSize();
547 9 : int sy = ds->GetRasterYSize();
548 9 : bool accepted_as_no_alpha = false; // if the request is for 4 bands but the wms returns 3
549 : /* Allow bigger than expected so pre-tiled constant size images work on corners */
550 9 : if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy)) {
551 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect size %d x %d of downloaded block, expected %d x %d, max %d x %d.",
552 0 : sx, sy, esx, esy, nBlockXSize, nBlockYSize);
553 0 : ret = CE_Failure;
554 : }
555 9 : if (ret == CE_None) {
556 9 : int nDSRasterCount = ds->GetRasterCount();
557 9 : if (nDSRasterCount != m_parent_dataset->nBands) {
558 : /* Maybe its an image with color table */
559 6 : bool accepted_as_ct = false;
560 6 : if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1)) {
561 0 : GDALRasterBand *rb = ds->GetRasterBand(1);
562 0 : if (rb->GetRasterDataType() == GDT_Byte) {
563 0 : GDALColorTable *ct = rb->GetColorTable();
564 0 : if (ct != NULL) {
565 0 : accepted_as_ct = true;
566 0 : if (!advise_read) {
567 0 : color_table = new GByte[256 * 4];
568 0 : const int count = MIN(256, ct->GetColorEntryCount());
569 0 : for (i = 0; i < count; ++i) {
570 : GDALColorEntry ce;
571 0 : ct->GetColorEntryAsRGB(i, &ce);
572 0 : color_table[i] = static_cast<GByte>(ce.c1);
573 0 : color_table[i + 256] = static_cast<GByte>(ce.c2);
574 0 : color_table[i + 512] = static_cast<GByte>(ce.c3);
575 0 : color_table[i + 768] = static_cast<GByte>(ce.c4);
576 : }
577 0 : for (i = count; i < 256; ++i) {
578 0 : color_table[i] = 0;
579 0 : color_table[i + 256] = 0;
580 0 : color_table[i + 512] = 0;
581 0 : color_table[i + 768] = 0;
582 : }
583 : }
584 : }
585 : }
586 : }
587 :
588 6 : if (nDSRasterCount == 4 && m_parent_dataset->nBands == 3)
589 : {
590 : /* metacarta TMS service sometimes return a 4 band PNG instead of the expected 3 band... */
591 : }
592 0 : else if (!accepted_as_ct) {
593 0 : if (ds->GetRasterCount()==3 && m_parent_dataset->nBands == 4 && (eDataType == GDT_Byte))
594 : { // WMS returned a file with no alpha so we will fill the alpha band with "opaque"
595 0 : accepted_as_no_alpha = true;
596 : }
597 : else
598 : {
599 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
600 0 : nDSRasterCount, m_parent_dataset->nBands);
601 0 : ret = CE_Failure;
602 : }
603 : }
604 : }
605 : }
606 9 : if (!advise_read) {
607 32 : for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
608 23 : if (ret == CE_None) {
609 23 : void *p = NULL;
610 23 : GDALRasterBlock *b = NULL;
611 28 : if ((buffer != NULL) && (ib == to_buffer_band)) {
612 5 : p = buffer;
613 : } else {
614 18 : GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
615 18 : if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
616 18 : if (!band->IsBlockInCache(x, y)) {
617 18 : b = band->GetLockedBlockRef(x, y, true);
618 18 : if (b != NULL) {
619 18 : p = b->GetDataRef();
620 18 : if (p == NULL) {
621 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
622 0 : ret = CE_Failure;
623 : }
624 : }
625 : }
626 : else
627 : {
628 : //CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d) already in cache", band->GetBand(), x, y);
629 : }
630 : }
631 23 : if (p != NULL) {
632 23 : int pixel_space = GDALGetDataTypeSize(eDataType) / 8;
633 23 : int line_space = pixel_space * nBlockXSize;
634 23 : if (color_table == NULL) {
635 23 : if( ib <= ds->GetRasterCount()) {
636 23 : GDALDataType dt=eDataType;
637 : // Get the data from the PNG as stored instead of converting, if the server asks for that
638 : // TODO: This hack is from #3493 - not sure it really belongs here.
639 23 : if ((GDT_Int16==dt)&&(GDT_UInt16==ds->GetRasterBand(ib)->GetRasterDataType()))
640 2 : dt=GDT_UInt16;
641 23 : if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, dt, 1, &ib, pixel_space, line_space, 0) != CE_None) {
642 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
643 0 : ret = CE_Failure;
644 : }
645 : }
646 : else
647 : { // parent expects 4 bands but file only has 3 so generate a all "opaque" 4th band
648 0 : if (accepted_as_no_alpha)
649 : {
650 : // the file had 3 bands and we are reading band 4 (Alpha) so fill with 255 (no alpha)
651 0 : GByte *byte_buffer = reinterpret_cast<GByte *>(p);
652 0 : for (int y = 0; y < sy; ++y) {
653 0 : for (int x = 0; x < sx; ++x) {
654 0 : const int offset = x + y * line_space;
655 0 : byte_buffer[offset] = 255; // fill with opaque
656 : }
657 : }
658 : }
659 : else
660 : { // we should never get here because this case was caught above
661 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
662 0 : ds->GetRasterCount(), m_parent_dataset->nBands);
663 0 : ret = CE_Failure;
664 : }
665 : }
666 0 : } else if (ib <= 4) {
667 0 : if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0) != CE_None) {
668 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
669 0 : ret = CE_Failure;
670 : }
671 0 : if (ret == CE_None) {
672 0 : GByte *band_color_table = color_table + 256 * (ib - 1);
673 0 : GByte *byte_buffer = reinterpret_cast<GByte *>(p);
674 0 : for (int y = 0; y < sy; ++y) {
675 0 : for (int x = 0; x < sx; ++x) {
676 0 : const int offset = x + y * line_space;
677 0 : byte_buffer[offset] = band_color_table[byte_buffer[offset]];
678 : }
679 : }
680 : }
681 : } else {
682 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Color table supports at most 4 components.");
683 0 : ret = CE_Failure;
684 : }
685 : }
686 23 : if (b != NULL) {
687 18 : b->DropLock();
688 : }
689 : }
690 : }
691 : }
692 9 : GDALClose(ds);
693 : } else {
694 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to open downloaded block.");
695 0 : ret = CE_Failure;
696 : }
697 :
698 9 : if (color_table != NULL) {
699 0 : delete[] color_table;
700 : }
701 :
702 9 : return ret;
703 : }
704 :
705 0 : CPLErr GDALWMSRasterBand::ZeroBlock(int x, int y, int to_buffer_band, void *buffer) {
706 0 : CPLErr ret = CE_None;
707 :
708 0 : for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
709 0 : if (ret == CE_None) {
710 0 : void *p = NULL;
711 0 : GDALRasterBlock *b = NULL;
712 0 : if ((buffer != NULL) && (ib == to_buffer_band)) {
713 0 : p = buffer;
714 : } else {
715 0 : GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
716 0 : if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
717 0 : if (!band->IsBlockInCache(x, y)) {
718 0 : b = band->GetLockedBlockRef(x, y, true);
719 0 : if (b != NULL) {
720 0 : p = b->GetDataRef();
721 0 : if (p == NULL) {
722 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
723 0 : ret = CE_Failure;
724 : }
725 : }
726 : }
727 : }
728 0 : if (p != NULL) {
729 0 : unsigned char *b = reinterpret_cast<unsigned char *>(p);
730 0 : int block_size = nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8);
731 0 : for (int i = 0; i < block_size; ++i) b[i] = 0;
732 : }
733 0 : if (b != NULL) {
734 0 : b->DropLock();
735 : }
736 : }
737 : }
738 :
739 0 : return ret;
740 : }
741 :
742 0 : CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name) {
743 0 : CPLErr ret = CE_None;
744 0 : int reported_errors_count = 0;
745 :
746 0 : CPLXMLNode *orig_root = CPLParseXMLFile(file_name);
747 0 : CPLXMLNode *root = orig_root;
748 0 : if (root != NULL) {
749 0 : root = CPLGetXMLNode(root, "=ServiceExceptionReport");
750 : }
751 0 : if (root != NULL) {
752 0 : CPLXMLNode *n = CPLGetXMLNode(root, "ServiceException");
753 0 : while (n != NULL) {
754 0 : const char *exception = CPLGetXMLValue(n, "=ServiceException", "");
755 0 : const char *exception_code = CPLGetXMLValue(n, "=ServiceException.code", "");
756 0 : if (exception[0] != '\0') {
757 0 : if (exception_code[0] != '\0') {
758 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception code '%s': %s", exception_code, exception);
759 0 : ++reported_errors_count;
760 : } else {
761 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception: %s", exception);
762 0 : ++reported_errors_count;
763 : }
764 0 : } else if (exception_code[0] != '\0') {
765 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception code '%s'.", exception_code);
766 0 : ++reported_errors_count;
767 : }
768 :
769 0 : n = n->psNext;
770 0 : if (n != NULL) {
771 0 : n = CPLGetXMLNode(n, "=ServiceException");
772 : }
773 : }
774 : } else {
775 0 : ret = CE_Failure;
776 : }
777 0 : if (orig_root != NULL) {
778 0 : CPLDestroyXMLNode(orig_root);
779 : }
780 :
781 0 : if (reported_errors_count == 0) {
782 0 : ret = CE_Failure;
783 : }
784 :
785 0 : return ret;
786 : }
787 :
788 :
789 0 : CPLErr GDALWMSRasterBand::AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy, GDALDataType bdt, char **options) {
790 : // printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
791 0 : if (m_parent_dataset->m_offline_mode || !m_parent_dataset->m_use_advise_read) return CE_None;
792 0 : if (m_parent_dataset->m_cache == NULL) return CE_Failure;
793 :
794 0 : int bx0 = x0 / nBlockXSize;
795 0 : int by0 = y0 / nBlockYSize;
796 0 : int bx1 = (x0 + sx - 1) / nBlockXSize;
797 0 : int by1 = (y0 + sy - 1) / nBlockYSize;
798 :
799 0 : return ReadBlocks(0, 0, NULL, bx0, by0, bx1, by1, 1);
800 : }
801 :
802 0 : GDALColorInterp GDALWMSRasterBand::GetColorInterpretation() {
803 0 : return m_color_interp;
804 : }
805 :
806 5 : CPLErr GDALWMSRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
807 : {
808 5 : m_color_interp = eNewInterp;
809 5 : return CE_None;
810 : }
811 :
812 : // Utility function, returns a value from a vector corresponding to the band index
813 : // or the first entry
814 0 : static double getBandValue(std::vector<double> &v,size_t idx)
815 : {
816 0 : idx--;
817 0 : if (v.size()>idx) return v[idx];
818 0 : return v[0];
819 : }
820 :
821 0 : double GDALWMSRasterBand::GetNoDataValue( int *pbSuccess)
822 : {
823 0 : std::vector<double> &v=m_parent_dataset->vNoData;
824 0 : if (v.size()==0)
825 0 : return GDALPamRasterBand::GetNoDataValue(pbSuccess);
826 0 : if (pbSuccess) *pbSuccess=TRUE;
827 0 : return getBandValue(v,nBand);
828 : }
829 :
830 0 : double GDALWMSRasterBand::GetMinimum( int *pbSuccess)
831 : {
832 0 : std::vector<double> &v=m_parent_dataset->vMin;
833 0 : if (v.size()==0)
834 0 : return GDALPamRasterBand::GetMinimum(pbSuccess);
835 0 : if (pbSuccess) *pbSuccess=TRUE;
836 0 : return getBandValue(v,nBand);
837 : }
838 :
839 0 : double GDALWMSRasterBand::GetMaximum( int *pbSuccess)
840 : {
841 0 : std::vector<double> &v=m_parent_dataset->vMax;
842 0 : if (v.size()==0)
843 0 : return GDALPamRasterBand::GetMaximum(pbSuccess);
844 0 : if (pbSuccess) *pbSuccess=TRUE;
845 0 : return getBandValue(v,nBand);
846 : }
847 :
848 1 : GDALColorTable *GDALWMSRasterBand::GetColorTable()
849 : {
850 1 : return m_parent_dataset->m_poColorTable;
851 : }
|