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