1 /******************************************************************************
2 *
3 * Project: OGR/DODS Interface
4 * Purpose: Implements OGRDODSDataSource class.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 2004, Frank Warmerdam
9 * Copyright (c) 2010, Even Rouault <even dot rouault at spatialys.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 "ogr_dods.h"
31 #include "cpl_conv.h"
32 #include "cpl_string.h"
33
34 CPL_CVSID("$Id: ogrdodsdatasource.cpp b1c9c12ad373e40b955162b45d704070d4ebf7b0 2019-06-19 16:50:15 +0200 Even Rouault $")
35 /************************************************************************/
36 /* OGRDODSDataSource() */
37 /************************************************************************/
38
OGRDODSDataSource()39 OGRDODSDataSource::OGRDODSDataSource() :
40 papoLayers(nullptr),
41 nLayers(0),
42 pszName(nullptr),
43 poConnection(nullptr),
44 poBTF(new BaseTypeFactory())
45 {
46 // TODO: This implies that the order in the class declaration is wrong.
47 poDDS = new DDS( poBTF );
48 }
49
50 /************************************************************************/
51 /* ~OGRDODSDataSource() */
52 /************************************************************************/
53
~OGRDODSDataSource()54 OGRDODSDataSource::~OGRDODSDataSource()
55
56 {
57 CPLFree( pszName );
58
59 for( int i = 0; i < nLayers; i++ )
60 delete papoLayers[i];
61
62 CPLFree( papoLayers );
63
64 if( poConnection != nullptr )
65 delete poConnection;
66
67 delete poDDS;
68 delete poBTF;
69 }
70
71 /************************************************************************/
72 /* Open() */
73 /************************************************************************/
74
Open(const char * pszNewName)75 int OGRDODSDataSource::Open( const char * pszNewName )
76
77 {
78 CPLAssert( nLayers == 0 );
79
80 pszName = CPLStrdup( pszNewName );
81
82 /* -------------------------------------------------------------------- */
83 /* Parse the URL into a base url, projection and constraint */
84 /* expression. */
85 /* -------------------------------------------------------------------- */
86 char *pszWrkURL = CPLStrdup( pszNewName + 5 );
87 char *pszFound = strstr(pszWrkURL, "&");
88 if( pszFound )
89 {
90 oConstraints = pszFound;
91 *pszFound = '\0';
92 }
93
94 pszFound = strstr(pszWrkURL,"?");
95 if( pszFound )
96 {
97 oProjection = pszFound+1;
98 *pszFound = '\0';
99 }
100
101 // Trim common requests.
102 int nLen = static_cast<int>(strlen(pszWrkURL));
103 if( strcmp(pszWrkURL+nLen-4,".das") == 0 )
104 pszWrkURL[nLen-4] = '\0';
105 else if( strcmp(pszWrkURL+nLen-4,".dds") == 0 )
106 pszWrkURL[nLen-4] = '\0';
107 else if( strcmp(pszWrkURL+nLen-4,".asc") == 0 )
108 pszWrkURL[nLen-4] = '\0';
109 else if( strcmp(pszWrkURL+nLen-5,".dods") == 0 )
110 pszWrkURL[nLen-5] = '\0';
111 else if( strcmp(pszWrkURL+nLen-5,".html") == 0 )
112 pszWrkURL[nLen-5] = '\0';
113
114 oBaseURL = pszWrkURL;
115 CPLFree( pszWrkURL );
116
117 /* -------------------------------------------------------------------- */
118 /* Do we want to override the .dodsrc file setting? Only do */
119 /* the putenv() if there isn't already a DODS_CONF in the */
120 /* environment. */
121 /* -------------------------------------------------------------------- */
122 if( CPLGetConfigOption( "DODS_CONF", nullptr ) != nullptr
123 && getenv("DODS_CONF") == nullptr )
124 {
125 const int knBufSize = 1000;
126 static char szDODS_CONF[knBufSize];
127
128 snprintf( szDODS_CONF, knBufSize, "DODS_CONF=%.980s",
129 CPLGetConfigOption( "DODS_CONF", "" ) );
130 // coverity[tainted_string]
131 putenv( szDODS_CONF );
132 }
133
134 /* -------------------------------------------------------------------- */
135 /* If we have a overriding AIS file location, apply it now. */
136 /* -------------------------------------------------------------------- */
137 if( CPLGetConfigOption( "DODS_AIS_FILE", nullptr ) != nullptr )
138 {
139 string oAISFile = CPLGetConfigOption( "DODS_AIS_FILE", "" );
140 RCReader::instance()->set_ais_database( oAISFile );
141 }
142
143 /* -------------------------------------------------------------------- */
144 /* Connect to the server. */
145 /* -------------------------------------------------------------------- */
146 string version;
147
148 try
149 {
150 poConnection = new AISConnect( oBaseURL );
151 version = poConnection->request_version();
152 }
153 catch (Error &e)
154 {
155 CPLError(CE_Failure, CPLE_OpenFailed,
156 "%s", e.get_error_message().c_str() );
157 return FALSE;
158 }
159
160 /* -------------------------------------------------------------------- */
161 /* We presume we only work with version 3 servers. */
162 /* -------------------------------------------------------------------- */
163
164 if (version.empty() || version.find("/3.") == string::npos)
165 {
166 CPLError( CE_Warning, CPLE_AppDefined,
167 "I connected to the URL but could not get a DAP 3.x version string\n"
168 "from the server. I will continue to connect but access may fail.");
169 }
170
171 /* -------------------------------------------------------------------- */
172 /* Fetch the DAS and DDS info about the server. */
173 /* -------------------------------------------------------------------- */
174 try
175 {
176 poConnection->request_das( oDAS );
177 poConnection->request_dds( *poDDS, oProjection + oConstraints );
178 }
179 catch (Error &e)
180 {
181 CPLError(CE_Failure, CPLE_AppDefined,
182 "Error fetching DAS or DDS:\n%s",
183 e.get_error_message().c_str() );
184 return FALSE;
185 }
186
187 /* -------------------------------------------------------------------- */
188 /* Do we have any ogr_layer_info attributes in the DAS? If so, */
189 /* use them to define the layers. */
190 /* -------------------------------------------------------------------- */
191 AttrTable::Attr_iter dv_i;
192
193 #ifdef LIBDAP_39
194 AttrTable* poTable = oDAS.container();
195 if (poTable == nullptr)
196 {
197 CPLError(CE_Failure, CPLE_AppDefined, "Cannot get container");
198 return FALSE;
199 }
200 #else
201 AttrTable* poTable = &oDAS;
202 #endif
203
204 for( dv_i = poTable->attr_begin(); dv_i != poTable->attr_end(); dv_i++ )
205 {
206 if( STARTS_WITH_CI(poTable->get_name(dv_i).c_str(), "ogr_layer_info")
207 && poTable->is_container( dv_i ) )
208 {
209 AttrTable *poAttr = poTable->get_attr_table( dv_i );
210 string target_container = poAttr->get_attr( "target_container" );
211 BaseType *poVar = poDDS->var( target_container.c_str() );
212
213 if( poVar == nullptr )
214 {
215 CPLError( CE_Warning, CPLE_AppDefined,
216 "Unable to find variable '%s' named in\n"
217 "ogr_layer_info.target_container, skipping.",
218 target_container.c_str() );
219 continue;
220 }
221
222 if( poVar->type() == dods_sequence_c )
223 AddLayer(
224 new OGRDODSSequenceLayer(this,
225 target_container.c_str(),
226 poAttr) );
227 else if( poVar->type() == dods_grid_c
228 || poVar->type() == dods_array_c )
229 AddLayer( new OGRDODSGridLayer(this,target_container.c_str(),
230 poAttr) );
231 }
232 }
233
234 /* -------------------------------------------------------------------- */
235 /* Walk through the DODS variables looking for easily targeted */
236 /* ones. Eventually this will need to be driven by the AIS info. */
237 /* -------------------------------------------------------------------- */
238 if( nLayers == 0 )
239 {
240 DDS::Vars_iter v_i;
241
242 for( v_i = poDDS->var_begin(); v_i != poDDS->var_end(); v_i++ )
243 {
244 BaseType *poVar = *v_i;
245
246 if( poVar->type() == dods_sequence_c )
247 AddLayer( new OGRDODSSequenceLayer(this,poVar->name().c_str(),
248 nullptr) );
249 else if( poVar->type() == dods_grid_c
250 || poVar->type() == dods_array_c )
251 AddLayer( new OGRDODSGridLayer(this,poVar->name().c_str(),
252 nullptr) );
253 }
254 }
255
256 return TRUE;
257 }
258
259 /************************************************************************/
260 /* AddLayer() */
261 /************************************************************************/
262
AddLayer(OGRDODSLayer * poLayer)263 void OGRDODSDataSource::AddLayer( OGRDODSLayer *poLayer )
264
265 {
266 papoLayers = (OGRDODSLayer **)
267 CPLRealloc( papoLayers, sizeof(OGRDODSLayer *) * (nLayers+1) );
268 papoLayers[nLayers++] = poLayer;
269 }
270
271 /************************************************************************/
272 /* TestCapability() */
273 /************************************************************************/
274
TestCapability(const char * pszCap)275 int OGRDODSDataSource::TestCapability( const char * pszCap )
276
277 {
278 return EQUAL(pszCap,ODsCCreateLayer);
279 }
280
281 /************************************************************************/
282 /* GetLayer() */
283 /************************************************************************/
284
GetLayer(int iLayer)285 OGRLayer *OGRDODSDataSource::GetLayer( int iLayer )
286
287 {
288 if( iLayer < 0 || iLayer >= nLayers )
289 return nullptr;
290 else
291 return papoLayers[iLayer];
292 }
293