1 : /******************************************************************************
2 : * $Id: dataset.cpp 18020 2009-11-14 14:33:20Z 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 5 : GDALWMSDataset::GDALWMSDataset() {
34 5 : m_mini_driver = 0;
35 5 : m_cache = 0;
36 5 : m_hint.m_valid = false;
37 5 : m_data_type = GDT_Byte;
38 5 : m_clamp_requests = true;
39 5 : }
40 :
41 10 : GDALWMSDataset::~GDALWMSDataset() {
42 5 : if (m_mini_driver) delete m_mini_driver;
43 5 : if (m_cache) delete m_cache;
44 10 : }
45 5 : CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) {
46 5 : CPLErr ret = CE_None;
47 :
48 5 : if (ret == CE_None) {
49 5 : const char *max_conn = CPLGetXMLValue(config, "MaxConnections", "");
50 5 : if (max_conn[0] != '\0') {
51 0 : m_http_max_conn = atoi(max_conn);
52 : } else {
53 5 : m_http_max_conn = 2;
54 : }
55 : }
56 5 : if (ret == CE_None) {
57 5 : const char *timeout = CPLGetXMLValue(config, "Timeout", "");
58 5 : if (timeout[0] != '\0') {
59 0 : m_http_timeout = atoi(timeout);
60 : } else {
61 5 : m_http_timeout = 300;
62 : }
63 : }
64 5 : if (ret == CE_None) {
65 5 : const char *offline_mode = CPLGetXMLValue(config, "OfflineMode", "");
66 5 : if (offline_mode[0] != '\0') {
67 0 : const int offline_mode_bool = StrToBool(offline_mode);
68 0 : if (offline_mode_bool == -1) {
69 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of OfflineMode, true / false expected.");
70 0 : ret = CE_Failure;
71 : } else {
72 0 : m_offline_mode = offline_mode_bool;
73 : }
74 : } else {
75 5 : m_offline_mode = 0;
76 : }
77 : }
78 5 : if (ret == CE_None) {
79 5 : const char *advise_read = CPLGetXMLValue(config, "AdviseRead", "");
80 5 : if (advise_read[0] != '\0') {
81 0 : const int advise_read_bool = StrToBool(advise_read);
82 0 : if (advise_read_bool == -1) {
83 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of AdviseRead, true / false expected.");
84 0 : ret = CE_Failure;
85 : } else {
86 0 : m_use_advise_read = advise_read_bool;
87 : }
88 : } else {
89 5 : m_use_advise_read = 0;
90 : }
91 : }
92 5 : if (ret == CE_None) {
93 5 : const char *verify_advise_read = CPLGetXMLValue(config, "VerifyAdviseRead", "");
94 5 : if (m_use_advise_read) {
95 0 : if (verify_advise_read[0] != '\0') {
96 0 : const int verify_advise_read_bool = StrToBool(verify_advise_read);
97 0 : if (verify_advise_read_bool == -1) {
98 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of VerifyAdviseRead, true / false expected.");
99 0 : ret = CE_Failure;
100 : } else {
101 0 : m_verify_advise_read = verify_advise_read_bool;
102 : }
103 : } else {
104 0 : m_verify_advise_read = 1;
105 : }
106 : }
107 : }
108 5 : if (ret == CE_None) {
109 5 : const char *block_size_x = CPLGetXMLValue(config, "BlockSizeX", "1024");
110 5 : const char *block_size_y = CPLGetXMLValue(config, "BlockSizeY", "1024");
111 5 : m_block_size_x = atoi(block_size_x);
112 5 : m_block_size_y = atoi(block_size_y);
113 5 : if (m_block_size_x <= 0 || m_block_size_y <= 0)
114 : {
115 : CPLError( CE_Failure, CPLE_AppDefined,
116 0 : "GDALWMS: Invalid value in BlockSizeX or BlockSizeY" );
117 0 : ret = CE_Failure;
118 : }
119 : }
120 5 : if (ret == CE_None)
121 : {
122 5 : const char *data_type = CPLGetXMLValue(config, "DataType", "Byte");
123 5 : m_data_type = GDALGetDataTypeByName( data_type );
124 5 : if ( m_data_type == GDT_Unknown || m_data_type >= GDT_TypeCount )
125 : {
126 : CPLError( CE_Failure, CPLE_AppDefined,
127 0 : "GDALWMS: Invalid value in DataType. Data type \"%s\" is not supported.", data_type );
128 0 : ret = CE_Failure;
129 : }
130 : }
131 5 : if (ret == CE_None) {
132 5 : const int clamp_requests_bool = StrToBool(CPLGetXMLValue(config, "ClampRequests", "true"));
133 5 : if (clamp_requests_bool == -1) {
134 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of ClampRequests, true / false expected.");
135 0 : ret = CE_Failure;
136 : } else {
137 5 : m_clamp_requests = clamp_requests_bool;
138 : }
139 : }
140 5 : if (ret == CE_None) {
141 5 : CPLXMLNode *data_window_node = CPLGetXMLNode(config, "DataWindow");
142 5 : if (data_window_node == NULL) {
143 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow missing.");
144 0 : ret = CE_Failure;
145 : } else {
146 5 : const char *overview_count = CPLGetXMLValue(config, "OverviewCount", "");
147 5 : const char *ulx = CPLGetXMLValue(data_window_node, "UpperLeftX", "-180.0");
148 5 : const char *uly = CPLGetXMLValue(data_window_node, "UpperLeftY", "90.0");
149 5 : const char *lrx = CPLGetXMLValue(data_window_node, "LowerRightX", "180.0");
150 5 : const char *lry = CPLGetXMLValue(data_window_node, "LowerRightY", "-90.0");
151 5 : const char *sx = CPLGetXMLValue(data_window_node, "SizeX", "");
152 5 : const char *sy = CPLGetXMLValue(data_window_node, "SizeY", "");
153 5 : const char *tx = CPLGetXMLValue(data_window_node, "TileX", "0");
154 5 : const char *ty = CPLGetXMLValue(data_window_node, "TileY", "0");
155 5 : const char *tlevel = CPLGetXMLValue(data_window_node, "TileLevel", "");
156 5 : const char *str_tile_count_x = CPLGetXMLValue(data_window_node, "TileCountX", "1");
157 5 : const char *str_tile_count_y = CPLGetXMLValue(data_window_node, "TileCountY", "1");
158 5 : const char *y_origin = CPLGetXMLValue(data_window_node, "YOrigin", "default");
159 :
160 5 : if (ret == CE_None) {
161 10 : if ((ulx[0] != '\0') && (uly[0] != '\0') && (lrx[0] != '\0') && (lry[0] != '\0')) {
162 5 : m_data_window.m_x0 = atof(ulx);
163 5 : m_data_window.m_y0 = atof(uly);
164 5 : m_data_window.m_x1 = atof(lrx);
165 5 : m_data_window.m_y1 = atof(lry);
166 : } else {
167 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: UpperLeftX, UpperLeftY, LowerRightX, LowerRightY.");
168 0 : ret = CE_Failure;
169 : }
170 : }
171 5 : if (ret == CE_None) {
172 5 : if (tlevel[0] != '\0') {
173 3 : m_data_window.m_tlevel = atoi(tlevel);
174 : } else {
175 2 : m_data_window.m_tlevel = 0;
176 : }
177 : }
178 5 : if (ret == CE_None) {
179 8 : if ((sx[0] != '\0') && (sy[0] != '\0')) {
180 3 : m_data_window.m_sx = atoi(sx);
181 3 : m_data_window.m_sy = atoi(sy);
182 4 : } else if ((tlevel[0] != '\0') && (str_tile_count_x[0] != '\0') && (str_tile_count_y[0] != '\0')) {
183 2 : int tile_count_x = atoi(str_tile_count_x);
184 2 : int tile_count_y = atoi(str_tile_count_y);
185 2 : m_data_window.m_sx = tile_count_x * m_block_size_x * (1 << m_data_window.m_tlevel);
186 2 : m_data_window.m_sy = tile_count_y * m_block_size_y * (1 << m_data_window.m_tlevel);
187 : } else {
188 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: SizeX, SizeY.");
189 0 : ret = CE_Failure;
190 : }
191 : }
192 5 : if (ret == CE_None) {
193 10 : if ((tx[0] != '\0') && (ty[0] != '\0')) {
194 5 : m_data_window.m_tx = atoi(tx);
195 5 : m_data_window.m_ty = atoi(ty);
196 : } else {
197 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: TileX, TileY.");
198 0 : ret = CE_Failure;
199 : }
200 : }
201 5 : if (ret == CE_None) {
202 5 : if (overview_count[0] != '\0') {
203 1 : m_overview_count = atoi(overview_count);
204 4 : } else if (tlevel[0] != '\0') {
205 2 : m_overview_count = m_data_window.m_tlevel;
206 : } else {
207 2 : const int min_overview_size = MAX(32, MIN(m_block_size_x, m_block_size_y));
208 : double a = log(static_cast<double>(MIN(m_data_window.m_sx, m_data_window.m_sy))) / log(2.0)
209 2 : - log(static_cast<double>(min_overview_size)) / log(2.0);
210 2 : m_overview_count = MAX(0, MIN(static_cast<int>(ceil(a)), 32));
211 : }
212 : }
213 5 : if (ret == CE_None) {
214 5 : CPLString y_origin_str = y_origin;
215 5 : if (y_origin_str == "top") {
216 0 : m_data_window.m_y_origin = GDALWMSDataWindow::TOP;
217 5 : } else if (y_origin_str == "bottom") {
218 0 : m_data_window.m_y_origin = GDALWMSDataWindow::BOTTOM;
219 5 : } else if (y_origin_str == "default") {
220 5 : m_data_window.m_y_origin = GDALWMSDataWindow::DEFAULT;
221 : } else {
222 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow YOrigin must be set to "
223 0 : "one of 'default', 'top', or 'bottom', not '%s'.", y_origin_str.c_str());
224 0 : ret = CE_Failure;
225 5 : }
226 : }
227 : }
228 : }
229 5 : if (ret == CE_None) {
230 5 : const char *proj = CPLGetXMLValue(config, "Projection", "");
231 5 : if (proj[0] != '\0') {
232 5 : m_projection = ProjToWKT(proj);
233 5 : if (m_projection.size() == 0) {
234 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Bad projection specified.");
235 0 : ret = CE_Failure;
236 : }
237 : }
238 : }
239 :
240 5 : const char *bands_count = CPLGetXMLValue(config, "BandsCount", "3");
241 5 : int nBandCount = atoi(bands_count);
242 :
243 5 : if (ret == CE_None) {
244 5 : CPLXMLNode *cache_node = CPLGetXMLNode(config, "Cache");
245 5 : if (cache_node != NULL) {
246 1 : m_cache = new GDALWMSCache();
247 1 : if (m_cache->Initialize(cache_node) != CE_None) {
248 0 : delete m_cache;
249 0 : m_cache = NULL;
250 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize cache.");
251 0 : ret = CE_Failure;
252 : }
253 : }
254 : }
255 5 : if (ret == CE_None) {
256 5 : CPLXMLNode *service_node = CPLGetXMLNode(config, "Service");
257 5 : if (service_node != NULL) {
258 5 : const char *service_name = CPLGetXMLValue(service_node, "name", "");
259 5 : if (service_name[0] != '\0') {
260 5 : GDALWMSMiniDriverManager *const mdm = GetGDALWMSMiniDriverManager();
261 5 : GDALWMSMiniDriverFactory *const mdf = mdm->Find(CPLString(service_name));
262 5 : if (mdf != NULL) {
263 5 : m_mini_driver = mdf->New();
264 5 : m_mini_driver->m_parent_dataset = this;
265 5 : if (m_mini_driver->Initialize(service_node) == CE_None) {
266 5 : m_mini_driver_caps.m_capabilities_version = -1;
267 5 : m_mini_driver->GetCapabilities(&m_mini_driver_caps);
268 5 : if (m_mini_driver_caps.m_capabilities_version == -1) {
269 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Internal error, mini-driver capabilities version not set.");
270 0 : ret = CE_Failure;
271 : }
272 : } else {
273 0 : delete m_mini_driver;
274 0 : m_mini_driver = NULL;
275 :
276 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize minidriver.");
277 0 : ret = CE_Failure;
278 : }
279 : } else {
280 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No mini-driver registered for '%s'.", service_name);
281 0 : ret = CE_Failure;
282 : }
283 : } else {
284 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified.");
285 0 : ret = CE_Failure;
286 : }
287 : } else {
288 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified.");
289 0 : ret = CE_Failure;
290 : }
291 : }
292 5 : if (ret == CE_None) {
293 5 : nRasterXSize = m_data_window.m_sx;
294 5 : nRasterYSize = m_data_window.m_sy;
295 :
296 5 : if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) ||
297 : !GDALCheckBandCount(nBandCount, TRUE))
298 : {
299 0 : return CE_Failure;
300 : }
301 :
302 20 : for (int i = 0; i < nBandCount; ++i) {
303 15 : GDALWMSRasterBand *band = new GDALWMSRasterBand(this, i, 1.0);
304 15 : SetBand(i + 1, band);
305 15 : double scale = 0.5;
306 222 : for (int j = 0; j < m_overview_count; ++j) {
307 207 : band->AddOverview(scale);
308 207 : scale *= 0.5;
309 : }
310 : }
311 : }
312 :
313 5 : if (ret == CE_None) {
314 : /* If we dont have projection already set ask mini-driver. */
315 5 : if (!m_projection.size()) {
316 0 : const char *proj = m_mini_driver->GetProjectionInWKT();
317 0 : if (proj != NULL) {
318 0 : m_projection = proj;
319 : }
320 : }
321 : }
322 :
323 5 : return ret;
324 : }
325 :
326 0 : CPLErr GDALWMSDataset::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int band_count, int *band_map, int pixel_space, int line_space, int band_space) {
327 : CPLErr ret;
328 :
329 0 : if (rw != GF_Read) return CE_Failure;
330 0 : if (buffer == NULL) return CE_Failure;
331 0 : if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0) || (band_count == 0)) return CE_None;
332 :
333 0 : m_hint.m_x0 = x0;
334 0 : m_hint.m_y0 = y0;
335 0 : m_hint.m_sx = sx;
336 0 : m_hint.m_sy = sy;
337 0 : m_hint.m_overview = -1;
338 0 : m_hint.m_valid = true;
339 : // printf("[%p] GDALWMSDataset::IRasterIO(x0: %d, y0: %d, sx: %d, sy: %d, bsx: %d, bsy: %d, band_count: %d, band_map: %p)\n", this, x0, y0, sx, sy, bsx, bsy, band_count, band_map);
340 0 : ret = GDALDataset::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, band_count, band_map, pixel_space, line_space, band_space);
341 0 : m_hint.m_valid = false;
342 :
343 0 : return ret;
344 : }
345 :
346 1 : const char *GDALWMSDataset::GetProjectionRef() {
347 1 : return m_projection.c_str();
348 : }
349 :
350 0 : CPLErr GDALWMSDataset::SetProjection(const char *proj) {
351 0 : return CE_Failure;
352 : }
353 :
354 1 : CPLErr GDALWMSDataset::GetGeoTransform(double *gt) {
355 1 : gt[0] = m_data_window.m_x0;
356 1 : gt[1] = (m_data_window.m_x1 - m_data_window.m_x0) / static_cast<double>(m_data_window.m_sx);
357 1 : gt[2] = 0.0;
358 1 : gt[3] = m_data_window.m_y0;
359 1 : gt[4] = 0.0;
360 1 : gt[5] = (m_data_window.m_y1 - m_data_window.m_y0) / static_cast<double>(m_data_window.m_sy);
361 1 : return CE_None;
362 : }
363 :
364 0 : CPLErr GDALWMSDataset::SetGeoTransform(double *gt) {
365 0 : return CE_Failure;
366 : }
367 :
368 4 : const GDALWMSDataWindow *GDALWMSDataset::WMSGetDataWindow() const {
369 4 : return &m_data_window;
370 : }
371 :
372 0 : int GDALWMSDataset::WMSGetBlockSizeX() const {
373 0 : return m_block_size_x;
374 : }
375 :
376 0 : int GDALWMSDataset::WMSGetBlockSizeY() const {
377 0 : return m_block_size_y;
378 : }
379 :
380 0 : CPLErr GDALWMSDataset::AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy, GDALDataType bdt, int band_count, int *band_map, char **options) {
381 : // printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
382 0 : if (m_offline_mode || !m_use_advise_read) return CE_None;
383 0 : if (m_cache == NULL) return CE_Failure;
384 :
385 0 : GDALRasterBand *band = GetRasterBand(1);
386 0 : if (band == NULL) return CE_Failure;
387 0 : return band->AdviseRead(x0, y0, sx, sy, bsx, bsy, bdt, options);
388 : }
|