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