1 /******************************************************************************
2 *
3 * Project: OGDI Bridge
4 * Purpose: Implements OGROGDIDataSource class.
5 * Author: Daniel Morissette, danmo@videotron.ca
6 * (Based on some code contributed by Frank Warmerdam :)
7 *
8 ******************************************************************************
9 * Copyright (c) 2000, Daniel Morissette
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 "ogrogdi.h"
31
32 #include "cpl_conv.h"
33 #include "cpl_string.h"
34
35 CPL_CVSID("$Id: ogrogdidatasource.cpp b000bcc06dc07ed1b24f5102eda21dc5bd725620 2019-02-28 18:02:02 +0100 Even Rouault $")
36
37 /************************************************************************/
38 /* OGROGDIDataSource() */
39 /************************************************************************/
40
OGROGDIDataSource()41 OGROGDIDataSource::OGROGDIDataSource() :
42 m_papoLayers(nullptr),
43 m_nLayers(0),
44 m_nClientID(-1),
45 m_poSpatialRef(nullptr),
46 m_poCurrentLayer(nullptr),
47 m_pszFullName(nullptr),
48 m_bLaunderLayerNames(
49 CPLTestBool(CPLGetConfigOption("OGR_OGDI_LAUNDER_LAYER_NAMES", "NO")))
50 {
51 m_sGlobalBounds.north = 0.0;
52 m_sGlobalBounds.south = 0.0;
53 m_sGlobalBounds.east = 0.0;
54 m_sGlobalBounds.west = 0.0;
55 m_sGlobalBounds.ns_res = 0.0;
56 m_sGlobalBounds.ew_res = 0.0;
57 }
58
59 /************************************************************************/
60 /* ~OGROGDIDataSource() */
61 /************************************************************************/
62
~OGROGDIDataSource()63 OGROGDIDataSource::~OGROGDIDataSource()
64
65 {
66 CPLFree(m_pszFullName );
67
68 for( int i = 0; i < m_nLayers; i++ )
69 delete m_papoLayers[i];
70 CPLFree( m_papoLayers );
71
72 if (m_nClientID != -1)
73 {
74 ecs_Result *psResult = cln_DestroyClient( m_nClientID );
75 ecs_CleanUp( psResult );
76 }
77
78 if (m_poSpatialRef)
79 m_poSpatialRef->Release();
80 }
81
82 /************************************************************************/
83 /* Open() */
84 /************************************************************************/
85
Open(const char * pszNewName)86 int OGROGDIDataSource::Open( const char * pszNewName )
87
88 {
89 CPLAssert( m_nLayers == 0 );
90
91 /* -------------------------------------------------------------------- */
92 /* Parse the dataset name. */
93 /* i.e. */
94 /* gltp://<hostname>/<format>/<path_to_dataset>[:<layer_name>:<Family>] */
95 /* */
96 /* Where <Family> is one of: Line, Area, Point, and Text */
97 /* -------------------------------------------------------------------- */
98 if( !STARTS_WITH_CI(pszNewName, "gltp:") )
99 return FALSE;
100
101 char *pszWorkingName = CPLStrdup( pszNewName );
102
103 char *pszFamily = strrchr(pszWorkingName, ':');
104
105 // Don't treat drive name colon as family separator. It is assumed
106 // that drive names are on character long, and preceded by a
107 // forward or backward slash.
108 if( pszFamily < pszWorkingName+2
109 || pszFamily[-2] == '/'
110 || pszFamily[-2] == '\\' )
111 pszFamily = nullptr;
112
113 char *pszLyrName = nullptr;
114 if (pszFamily && pszFamily != pszWorkingName + 4)
115 {
116 *pszFamily = '\0';
117 pszFamily++;
118
119 pszLyrName = strrchr(pszWorkingName, ':');
120 if (pszLyrName == pszWorkingName + 4)
121 pszLyrName = nullptr;
122
123 if( pszLyrName != nullptr )
124 {
125 *pszLyrName = '\0';
126 pszLyrName++;
127 }
128 }
129
130 /* -------------------------------------------------------------------- */
131 /* Open the client interface. */
132 /* -------------------------------------------------------------------- */
133 ecs_Result *psResult = cln_CreateClient(&m_nClientID, pszWorkingName);
134
135 if( ECSERROR( psResult ) )
136 {
137 CPLError( CE_Failure, CPLE_AppDefined,
138 "OGDI DataSource Open Failed: %s\n",
139 psResult->message ? psResult->message : "(no message string)");
140 CPLFree( pszWorkingName );
141 return FALSE;
142 }
143
144 m_pszFullName = CPLStrdup(pszNewName);
145
146 /* -------------------------------------------------------------------- */
147 /* Capture some information from the file. */
148 /* -------------------------------------------------------------------- */
149 psResult = cln_GetGlobalBound( m_nClientID );
150 if( ECSERROR(psResult) )
151 {
152 CPLError( CE_Failure, CPLE_AppDefined,
153 "GetGlobalBound failed: %s",
154 psResult->message ? psResult->message : "(no message string)");
155 CPLFree( pszWorkingName );
156 return FALSE;
157 }
158
159 m_sGlobalBounds = ECSREGION(psResult);
160
161 psResult = cln_GetServerProjection(m_nClientID);
162 if( ECSERROR(psResult) )
163 {
164 CPLError( CE_Failure, CPLE_AppDefined,
165 "GetServerProjection failed: %s",
166 psResult->message ? psResult->message : "(no message string)");
167 CPLFree( pszWorkingName );
168 return FALSE;
169 }
170
171 m_poSpatialRef = new OGRSpatialReference;
172 m_poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
173
174 CPLString osProjString( ECSTEXT(psResult) );
175 osProjString.replaceAll("datum=wgs84", "datum=WGS84");
176 if( m_poSpatialRef->importFromProj4(osProjString) != OGRERR_NONE )
177 {
178 CPLError( CE_Warning, CPLE_NotSupported,
179 "untranslatable PROJ.4 projection: %s\n",
180 ECSTEXT(psResult) ? ECSTEXT(psResult): "(no message string)" );
181 delete m_poSpatialRef;
182 m_poSpatialRef = nullptr;
183 }
184
185 /* -------------------------------------------------------------------- */
186 /* Select the global region. */
187 /* -------------------------------------------------------------------- */
188 psResult = cln_SelectRegion( m_nClientID, &m_sGlobalBounds );
189 if( ECSERROR(psResult) )
190 {
191 CPLError( CE_Failure, CPLE_AppDefined,
192 "SelectRegion failed: %s",
193 psResult->message ? psResult->message : "(no message string)");
194 CPLFree( pszWorkingName );
195 return FALSE;
196 }
197
198 /* -------------------------------------------------------------------- */
199 /* If an explicit layer was selected, just create that layer. */
200 /* -------------------------------------------------------------------- */
201 m_poCurrentLayer = nullptr;
202
203 if( pszLyrName != nullptr )
204 {
205 ecs_Family eFamily;
206
207 if (EQUAL(pszFamily, "Line"))
208 eFamily = Line;
209 else if (EQUAL(pszFamily, "Area"))
210 eFamily = Area;
211 else if (EQUAL(pszFamily, "Point"))
212 eFamily = Point;
213 else if (EQUAL(pszFamily, "Text"))
214 eFamily = Text;
215 else
216 {
217 CPLError( CE_Failure, CPLE_AppDefined,
218 "Invalid or unsupported family name (%s) in URL %s\n",
219 pszFamily, m_pszFullName);
220 CPLFree( pszWorkingName );
221 return FALSE;
222 }
223
224 IAddLayer( pszLyrName, eFamily );
225 }
226
227 /* -------------------------------------------------------------------- */
228 /* Otherwise create a layer for every layer in the capabilities. */
229 /* -------------------------------------------------------------------- */
230 else
231 {
232 // Call cln_UpdateDictionary so as to be able to report errors
233 // since cln_GetLayerCapabilities() cannot do that
234 // Help in the case of DNC17/COA17A that has a missing env/fcs file
235 char* szEmpty = CPLStrdup("");
236 psResult = cln_UpdateDictionary( m_nClientID, szEmpty );
237 CPLFree(szEmpty);
238 if( ECSERROR(psResult) )
239 {
240 CPLError( CE_Failure, CPLE_AppDefined,
241 "UpdateDictionary failed: %s",
242 psResult->message ? psResult->message : "(no message string)");
243 CPLFree( pszWorkingName );
244 return FALSE;
245 }
246
247 const ecs_LayerCapabilities *psLayerCap = nullptr;
248 for( int i = 0;
249 (psLayerCap = cln_GetLayerCapabilities(m_nClientID,i)) != nullptr;
250 i++ )
251 {
252 if( psLayerCap->families[Point] )
253 IAddLayer( psLayerCap->name, Point );
254 if( psLayerCap->families[Line] )
255 IAddLayer( psLayerCap->name, Line );
256 if( psLayerCap->families[Area] )
257 IAddLayer( psLayerCap->name, Area );
258 if( psLayerCap->families[Text] )
259 IAddLayer( psLayerCap->name, Text );
260 }
261 }
262
263 CPLFree( pszWorkingName );
264
265 return TRUE;
266 }
267
268 /************************************************************************/
269 /* IAddLayer() */
270 /* */
271 /* Internal helper function for adding one existing layer to */
272 /* the datasource. */
273 /************************************************************************/
274
IAddLayer(const char * pszLayerName,ecs_Family eFamily)275 void OGROGDIDataSource::IAddLayer( const char *pszLayerName,
276 ecs_Family eFamily )
277
278 {
279 m_papoLayers = (OGROGDILayer**)
280 CPLRealloc( m_papoLayers, (m_nLayers+1) * sizeof(OGROGDILayer*));
281
282 m_papoLayers[m_nLayers++] = new OGROGDILayer(this, pszLayerName, eFamily);
283 }
284
285 /************************************************************************/
286 /* TestCapability() */
287 /************************************************************************/
288
TestCapability(CPL_UNUSED const char * pszCap)289 int OGROGDIDataSource::TestCapability( CPL_UNUSED const char * pszCap )
290
291 {
292 return FALSE;
293 }
294
295 /************************************************************************/
296 /* GetLayer() */
297 /************************************************************************/
298
GetLayer(int iLayer)299 OGRLayer *OGROGDIDataSource::GetLayer( int iLayer )
300
301 {
302 if( iLayer < 0 || iLayer >= m_nLayers )
303 return nullptr;
304 else
305 return m_papoLayers[iLayer];
306 }
307