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