/src/gdal/ogr/ogrsf_frmts/gmt/ogrgmtlayer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implements OGRGmtLayer class. |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogr_gmt.h" |
14 | | #include "cpl_conv.h" |
15 | | #include "ogr_p.h" |
16 | | |
17 | | #include <algorithm> |
18 | | |
19 | | /************************************************************************/ |
20 | | /* OGRGmtLayer() */ |
21 | | /************************************************************************/ |
22 | | |
23 | | OGRGmtLayer::OGRGmtLayer(GDALDataset *poDS, const char *pszFilename, |
24 | | VSILFILE *fp, const OGRSpatialReference *poSRS, |
25 | | int bUpdateIn) |
26 | 12.5k | : m_poDS(poDS), poFeatureDefn(nullptr), iNextFID(0), |
27 | 12.5k | bUpdate(CPL_TO_BOOL(bUpdateIn)), |
28 | | // Assume header complete in readonly mode. |
29 | 12.5k | bHeaderComplete(CPL_TO_BOOL(!bUpdate)), bRegionComplete(false), |
30 | 12.5k | nRegionOffset(0), |
31 | 12.5k | m_fp(fp ? fp : VSIFOpenL(pszFilename, (bUpdateIn ? "r+" : "r"))), |
32 | 12.5k | papszKeyedValues(nullptr), bValidFile(false) |
33 | 12.5k | { |
34 | 12.5k | if (m_fp == nullptr) |
35 | 135 | return; |
36 | | |
37 | | /* -------------------------------------------------------------------- */ |
38 | | /* Create the feature definition */ |
39 | | /* -------------------------------------------------------------------- */ |
40 | 12.3k | poFeatureDefn = new OGRFeatureDefn(CPLGetBasenameSafe(pszFilename).c_str()); |
41 | 12.3k | SetDescription(poFeatureDefn->GetName()); |
42 | 12.3k | poFeatureDefn->Reference(); |
43 | | |
44 | | /* -------------------------------------------------------------------- */ |
45 | | /* Read the header. */ |
46 | | /* -------------------------------------------------------------------- */ |
47 | 12.3k | if (!STARTS_WITH(pszFilename, "/vsistdout")) |
48 | 12.3k | { |
49 | 12.3k | CPLString osFieldNames; |
50 | 12.3k | CPLString osFieldTypes; |
51 | 12.3k | CPLString osGeometryType; |
52 | 12.3k | CPLString osRegion; |
53 | 12.3k | CPLString osWKT; |
54 | 12.3k | CPLString osProj4; |
55 | 12.3k | CPLString osEPSG; |
56 | 12.3k | vsi_l_offset nStartOfLine = 0; |
57 | | |
58 | 12.3k | VSIFSeekL(m_fp, 0, SEEK_SET); |
59 | | |
60 | 420k | while (ReadLine() && osLine[0] == '#') |
61 | 408k | { |
62 | 408k | if (strstr(osLine, "FEATURE_DATA")) |
63 | 416 | { |
64 | 416 | bHeaderComplete = true; |
65 | 416 | ReadLine(); |
66 | 416 | break; |
67 | 416 | } |
68 | | |
69 | 408k | if (STARTS_WITH_CI(osLine, "# REGION_STUB ")) |
70 | 1.58k | nRegionOffset = nStartOfLine; |
71 | | |
72 | 757k | for (int iKey = 0; papszKeyedValues != nullptr && |
73 | 665k | papszKeyedValues[iKey] != nullptr; |
74 | 408k | iKey++) |
75 | 349k | { |
76 | 349k | if (papszKeyedValues[iKey][0] == 'N') |
77 | 46.1k | osFieldNames = papszKeyedValues[iKey] + 1; |
78 | 349k | if (papszKeyedValues[iKey][0] == 'T') |
79 | 19.2k | osFieldTypes = papszKeyedValues[iKey] + 1; |
80 | 349k | if (papszKeyedValues[iKey][0] == 'G') |
81 | 11.0k | osGeometryType = papszKeyedValues[iKey] + 1; |
82 | 349k | if (papszKeyedValues[iKey][0] == 'R') |
83 | 19.5k | osRegion = papszKeyedValues[iKey] + 1; |
84 | 349k | if (papszKeyedValues[iKey][0] == 'J' && |
85 | 196k | papszKeyedValues[iKey][1] != 0 && |
86 | 193k | papszKeyedValues[iKey][2] != 0) |
87 | 185k | { |
88 | 185k | std::string osArg = papszKeyedValues[iKey] + 2; |
89 | 185k | if (osArg[0] == '"' && osArg.size() >= 2 && |
90 | 62.6k | osArg.back() == '"') |
91 | 23.3k | { |
92 | 23.3k | osArg = osArg.substr(1, osArg.length() - 2); |
93 | 23.3k | char *pszArg = CPLUnescapeString( |
94 | 23.3k | osArg.c_str(), nullptr, CPLES_BackslashQuotable); |
95 | 23.3k | osArg = pszArg; |
96 | 23.3k | CPLFree(pszArg); |
97 | 23.3k | } |
98 | | |
99 | 185k | if (papszKeyedValues[iKey][1] == 'e') |
100 | 7.03k | osEPSG = std::move(osArg); |
101 | 185k | if (papszKeyedValues[iKey][1] == 'p') |
102 | 27.3k | osProj4 = std::move(osArg); |
103 | 185k | if (papszKeyedValues[iKey][1] == 'w') |
104 | 19.9k | osWKT = std::move(osArg); |
105 | 185k | } |
106 | 349k | } |
107 | | |
108 | 408k | nStartOfLine = VSIFTellL(m_fp); |
109 | 408k | } |
110 | | |
111 | | /* -------------------------------------------------------------------- |
112 | | */ |
113 | | /* Handle coordinate system. */ |
114 | | /* -------------------------------------------------------------------- |
115 | | */ |
116 | 12.3k | if (osWKT.length()) |
117 | 1.04k | { |
118 | 1.04k | m_poSRS = new OGRSpatialReference(); |
119 | 1.04k | m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
120 | 1.04k | if (m_poSRS->importFromWkt(osWKT.c_str()) != OGRERR_NONE) |
121 | 955 | { |
122 | 955 | delete m_poSRS; |
123 | 955 | m_poSRS = nullptr; |
124 | 955 | } |
125 | 1.04k | } |
126 | 11.3k | else if (osEPSG.length()) |
127 | 92 | { |
128 | 92 | m_poSRS = new OGRSpatialReference(); |
129 | 92 | m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
130 | 92 | if (m_poSRS->importFromEPSG(atoi(osEPSG)) != OGRERR_NONE) |
131 | 87 | { |
132 | 87 | delete m_poSRS; |
133 | 87 | m_poSRS = nullptr; |
134 | 87 | } |
135 | 92 | } |
136 | 11.2k | else if (osProj4.length()) |
137 | 7.85k | { |
138 | 7.85k | m_poSRS = new OGRSpatialReference(); |
139 | 7.85k | m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
140 | 7.85k | if (m_poSRS->importFromProj4(osProj4) != OGRERR_NONE) |
141 | 5.53k | { |
142 | 5.53k | delete m_poSRS; |
143 | 5.53k | m_poSRS = nullptr; |
144 | 5.53k | } |
145 | 7.85k | } |
146 | | |
147 | 12.3k | if (osGeometryType == "POINT") |
148 | 3 | poFeatureDefn->SetGeomType(wkbPoint); |
149 | 12.3k | else if (osGeometryType == "MULTIPOINT") |
150 | 0 | poFeatureDefn->SetGeomType(wkbMultiPoint); |
151 | 12.3k | else if (osGeometryType == "LINESTRING") |
152 | 3 | poFeatureDefn->SetGeomType(wkbLineString); |
153 | 12.3k | else if (osGeometryType == "MULTILINESTRING") |
154 | 222 | poFeatureDefn->SetGeomType(wkbMultiLineString); |
155 | 12.1k | else if (osGeometryType == "POLYGON") |
156 | 55 | poFeatureDefn->SetGeomType(wkbPolygon); |
157 | 12.1k | else if (osGeometryType == "MULTIPOLYGON") |
158 | 227 | poFeatureDefn->SetGeomType(wkbMultiPolygon); |
159 | | |
160 | | /* -------------------------------------------------------------------- |
161 | | */ |
162 | | /* Process a region line. */ |
163 | | /* -------------------------------------------------------------------- |
164 | | */ |
165 | 12.3k | if (osRegion.length() > 0) |
166 | 767 | { |
167 | 767 | char **papszTokens = |
168 | 767 | CSLTokenizeStringComplex(osRegion.c_str(), "/", FALSE, FALSE); |
169 | | |
170 | 767 | if (CSLCount(papszTokens) == 4) |
171 | 416 | { |
172 | 416 | sRegion.MinX = CPLAtofM(papszTokens[0]); |
173 | 416 | sRegion.MaxX = CPLAtofM(papszTokens[1]); |
174 | 416 | sRegion.MinY = CPLAtofM(papszTokens[2]); |
175 | 416 | sRegion.MaxY = CPLAtofM(papszTokens[3]); |
176 | 416 | } |
177 | | |
178 | 767 | bRegionComplete = true; |
179 | | |
180 | 767 | CSLDestroy(papszTokens); |
181 | 767 | } |
182 | | |
183 | | /* -------------------------------------------------------------------- |
184 | | */ |
185 | | /* Process fields. */ |
186 | | /* -------------------------------------------------------------------- |
187 | | */ |
188 | 12.3k | if (osFieldNames.length() || osFieldTypes.length()) |
189 | 1.30k | { |
190 | 1.30k | char **papszFN = |
191 | 1.30k | CSLTokenizeStringComplex(osFieldNames, "|", TRUE, TRUE); |
192 | 1.30k | char **papszFT = |
193 | 1.30k | CSLTokenizeStringComplex(osFieldTypes, "|", TRUE, TRUE); |
194 | 1.30k | const int nFNCount = CSLCount(papszFN); |
195 | 1.30k | const int nFTCount = CSLCount(papszFT); |
196 | 1.30k | const int nFieldCount = std::max(nFNCount, nFTCount); |
197 | | |
198 | 8.77k | for (int iField = 0; iField < nFieldCount; iField++) |
199 | 7.47k | { |
200 | 7.47k | OGRFieldDefn oField("", OFTString); |
201 | | |
202 | 7.47k | if (iField < nFNCount) |
203 | 3.19k | oField.SetName(papszFN[iField]); |
204 | 4.27k | else |
205 | 4.27k | oField.SetName(CPLString().Printf("Field_%d", iField + 1)); |
206 | | |
207 | 7.47k | if (iField < nFTCount) |
208 | 6.50k | { |
209 | 6.50k | if (EQUAL(papszFT[iField], "integer")) |
210 | 155 | oField.SetType(OFTInteger); |
211 | 6.35k | else if (EQUAL(papszFT[iField], "double")) |
212 | 18 | oField.SetType(OFTReal); |
213 | 6.33k | else if (EQUAL(papszFT[iField], "datetime")) |
214 | 332 | oField.SetType(OFTDateTime); |
215 | 6.50k | } |
216 | | |
217 | 7.47k | poFeatureDefn->AddFieldDefn(&oField); |
218 | 7.47k | } |
219 | | |
220 | 1.30k | CSLDestroy(papszFN); |
221 | 1.30k | CSLDestroy(papszFT); |
222 | 1.30k | } |
223 | 12.3k | } |
224 | 0 | else |
225 | 0 | { |
226 | 0 | if (poSRS) |
227 | 0 | { |
228 | 0 | m_poSRS = poSRS->Clone(); |
229 | 0 | m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | 12.3k | poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS); |
234 | | |
235 | 12.3k | bValidFile = true; |
236 | 12.3k | } |
237 | | |
238 | | /************************************************************************/ |
239 | | /* ~OGRGmtLayer() */ |
240 | | /************************************************************************/ |
241 | | |
242 | | OGRGmtLayer::~OGRGmtLayer() |
243 | | |
244 | 12.5k | { |
245 | 12.5k | if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr) |
246 | 1.97k | { |
247 | 1.97k | CPLDebug("Gmt", "%d features read on layer '%s'.", |
248 | 1.97k | static_cast<int>(m_nFeaturesRead), poFeatureDefn->GetName()); |
249 | 1.97k | } |
250 | | |
251 | | /* -------------------------------------------------------------------- */ |
252 | | /* Write out the region bounds if we know where they go, and we */ |
253 | | /* are in update mode. */ |
254 | | /* -------------------------------------------------------------------- */ |
255 | 12.5k | if (nRegionOffset != 0 && bUpdate) |
256 | 134 | { |
257 | 134 | VSIFSeekL(m_fp, nRegionOffset, SEEK_SET); |
258 | 134 | VSIFPrintfL(m_fp, "# @R%.12g/%.12g/%.12g/%.12g", sRegion.MinX, |
259 | 134 | sRegion.MaxX, sRegion.MinY, sRegion.MaxY); |
260 | 134 | } |
261 | | |
262 | | /* -------------------------------------------------------------------- */ |
263 | | /* Clean up. */ |
264 | | /* -------------------------------------------------------------------- */ |
265 | 12.5k | CSLDestroy(papszKeyedValues); |
266 | | |
267 | 12.5k | if (poFeatureDefn) |
268 | 12.3k | poFeatureDefn->Release(); |
269 | | |
270 | 12.5k | if (m_poSRS) |
271 | 2.41k | m_poSRS->Release(); |
272 | | |
273 | 12.5k | if (m_fp != nullptr) |
274 | 12.3k | VSIFCloseL(m_fp); |
275 | 12.5k | } |
276 | | |
277 | | /************************************************************************/ |
278 | | /* ReadLine() */ |
279 | | /* */ |
280 | | /* Read a line into osLine. If it is a comment line with @ */ |
281 | | /* keyed values, parse out the keyed values into */ |
282 | | /* papszKeyedValues. */ |
283 | | /************************************************************************/ |
284 | | |
285 | | bool OGRGmtLayer::ReadLine() |
286 | | |
287 | 1.35M | { |
288 | | /* -------------------------------------------------------------------- */ |
289 | | /* Clear last line. */ |
290 | | /* -------------------------------------------------------------------- */ |
291 | 1.35M | osLine.erase(); |
292 | 1.35M | if (papszKeyedValues) |
293 | 443k | { |
294 | 443k | CSLDestroy(papszKeyedValues); |
295 | 443k | papszKeyedValues = nullptr; |
296 | 443k | } |
297 | | |
298 | | /* -------------------------------------------------------------------- */ |
299 | | /* Read newline. */ |
300 | | /* -------------------------------------------------------------------- */ |
301 | 1.35M | const char *pszLine = CPLReadLineL(m_fp); |
302 | 1.35M | if (pszLine == nullptr) |
303 | 10.5k | return false; // end of file. |
304 | | |
305 | 1.33M | osLine = pszLine; |
306 | | |
307 | | /* -------------------------------------------------------------------- */ |
308 | | /* If this is a comment line with keyed values, parse them. */ |
309 | | /* -------------------------------------------------------------------- */ |
310 | | |
311 | 1.33M | if (osLine[0] != '#' || osLine.find_first_of('@') == std::string::npos) |
312 | 886k | return true; |
313 | | |
314 | 453k | CPLStringList aosKeyedValues; |
315 | 7.72M | for (size_t i = 0; i < osLine.length(); i++) |
316 | 7.27M | { |
317 | 7.27M | if (osLine[i] == '@' && i + 2 <= osLine.size()) |
318 | 952k | { |
319 | 952k | bool bInQuotes = false; |
320 | | |
321 | 952k | size_t iValEnd = i + 2; // Used after for. |
322 | 30.8M | for (; iValEnd < osLine.length(); iValEnd++) |
323 | 30.4M | { |
324 | 30.4M | if (!bInQuotes && |
325 | 13.7M | isspace(static_cast<unsigned char>(osLine[iValEnd]))) |
326 | 541k | break; |
327 | | |
328 | 29.8M | if (bInQuotes && iValEnd < osLine.length() - 1 && |
329 | 16.5M | osLine[iValEnd] == '\\') |
330 | 40.5k | { |
331 | 40.5k | iValEnd++; |
332 | 40.5k | } |
333 | 29.8M | else if (osLine[iValEnd] == '"') |
334 | 674k | bInQuotes = !bInQuotes; |
335 | 29.8M | } |
336 | | |
337 | 952k | const CPLString osValue = osLine.substr(i + 2, iValEnd - i - 2); |
338 | | |
339 | | // Unecape contents |
340 | 952k | char *pszUEValue = |
341 | 952k | CPLUnescapeString(osValue, nullptr, CPLES_BackslashQuotable); |
342 | | |
343 | 952k | CPLString osKeyValue = osLine.substr(i + 1, 1); |
344 | 952k | osKeyValue += pszUEValue; |
345 | 952k | CPLFree(pszUEValue); |
346 | 952k | aosKeyedValues.AddString(osKeyValue); |
347 | | |
348 | 952k | i = iValEnd; |
349 | 952k | } |
350 | 7.27M | } |
351 | 453k | papszKeyedValues = aosKeyedValues.StealList(); |
352 | | |
353 | 453k | return true; |
354 | 1.33M | } |
355 | | |
356 | | /************************************************************************/ |
357 | | /* ResetReading() */ |
358 | | /************************************************************************/ |
359 | | |
360 | | void OGRGmtLayer::ResetReading() |
361 | | |
362 | 33 | { |
363 | 33 | if (iNextFID == 0) |
364 | 33 | return; |
365 | | |
366 | 0 | iNextFID = 0; |
367 | 0 | VSIFSeekL(m_fp, 0, SEEK_SET); |
368 | 0 | ReadLine(); |
369 | 0 | } |
370 | | |
371 | | /************************************************************************/ |
372 | | /* ScanAheadForHole() */ |
373 | | /* */ |
374 | | /* Scan ahead to see if the next geometry is a hole. If so */ |
375 | | /* return true, otherwise seek back to where we were and return */ |
376 | | /* false. */ |
377 | | /************************************************************************/ |
378 | | |
379 | | bool OGRGmtLayer::ScanAheadForHole() |
380 | | |
381 | 28.5k | { |
382 | 28.5k | CPLString osSavedLine = osLine; |
383 | 28.5k | const vsi_l_offset nSavedLocation = VSIFTellL(m_fp); |
384 | | |
385 | 43.3k | while (ReadLine() && osLine[0] == '#') |
386 | 19.0k | { |
387 | 19.0k | if (papszKeyedValues != nullptr && papszKeyedValues[0][0] == 'H') |
388 | 4.31k | return true; |
389 | 19.0k | } |
390 | | |
391 | 24.2k | VSIFSeekL(m_fp, nSavedLocation, SEEK_SET); |
392 | 24.2k | osLine = std::move(osSavedLine); |
393 | | |
394 | | // We do not actually restore papszKeyedValues, but we |
395 | | // assume it does not matter since this method is only called |
396 | | // when processing the '>' line. |
397 | | |
398 | 24.2k | return false; |
399 | 28.5k | } |
400 | | |
401 | | /************************************************************************/ |
402 | | /* NextIsFeature() */ |
403 | | /* */ |
404 | | /* Returns true if the next line is a feature attribute line. */ |
405 | | /* This generally indicates the end of a multilinestring or */ |
406 | | /* multipolygon feature. */ |
407 | | /************************************************************************/ |
408 | | |
409 | | bool OGRGmtLayer::NextIsFeature() |
410 | | |
411 | 30.4k | { |
412 | 30.4k | CPLString osSavedLine = osLine; |
413 | 30.4k | const vsi_l_offset nSavedLocation = VSIFTellL(m_fp); |
414 | 30.4k | bool bReturn = false; |
415 | | |
416 | 30.4k | ReadLine(); |
417 | | |
418 | 30.4k | if (osLine[0] == '#' && strstr(osLine, "@D") != nullptr) |
419 | 5.87k | bReturn = true; |
420 | | |
421 | 30.4k | VSIFSeekL(m_fp, nSavedLocation, SEEK_SET); |
422 | 30.4k | osLine = std::move(osSavedLine); |
423 | | |
424 | | // We do not actually restore papszKeyedValues, but we |
425 | | // assume it does not matter since this method is only called |
426 | | // when processing the '>' line. |
427 | | |
428 | 30.4k | return bReturn; |
429 | 30.4k | } |
430 | | |
431 | | /************************************************************************/ |
432 | | /* GetNextRawFeature() */ |
433 | | /************************************************************************/ |
434 | | |
435 | | OGRFeature *OGRGmtLayer::GetNextRawFeature() |
436 | | |
437 | 75.8k | { |
438 | | #if 0 |
439 | | bool bMultiVertex = |
440 | | poFeatureDefn->GetGeomType() != wkbPoint |
441 | | && poFeatureDefn->GetGeomType() != wkbUnknown; |
442 | | #endif |
443 | 75.8k | CPLString osFieldData; |
444 | 75.8k | OGRGeometry *poGeom = nullptr; |
445 | | |
446 | | /* -------------------------------------------------------------------- */ |
447 | | /* Read lines associated with this feature. */ |
448 | | /* -------------------------------------------------------------------- */ |
449 | 901k | for (; true; ReadLine()) |
450 | 901k | { |
451 | 901k | if (osLine.length() == 0) |
452 | 11.3k | break; |
453 | | |
454 | 890k | if (osLine[0] == '>') |
455 | 126k | { |
456 | 126k | OGRwkbGeometryType eType = wkbUnknown; |
457 | 126k | if (poGeom) |
458 | 64.3k | eType = wkbFlatten(poGeom->getGeometryType()); |
459 | 126k | if (eType == wkbMultiPolygon) |
460 | 26.0k | { |
461 | 26.0k | OGRMultiPolygon *poMP = poGeom->toMultiPolygon(); |
462 | 26.0k | if (ScanAheadForHole()) |
463 | 3.29k | { |
464 | | // Add a hole to the current polygon. |
465 | 3.29k | poMP->getGeometryRef(poMP->getNumGeometries() - 1) |
466 | 3.29k | ->addRingDirectly(new OGRLinearRing()); |
467 | 3.29k | } |
468 | 22.7k | else if (!NextIsFeature()) |
469 | 20.9k | { |
470 | 20.9k | OGRPolygon *poPoly = new OGRPolygon(); |
471 | | |
472 | 20.9k | poPoly->addRingDirectly(new OGRLinearRing()); |
473 | | |
474 | 20.9k | poMP->addGeometryDirectly(poPoly); |
475 | 20.9k | } |
476 | 1.82k | else |
477 | 1.82k | break; /* done geometry */ |
478 | 26.0k | } |
479 | 100k | else if (eType == wkbPolygon) |
480 | 2.55k | { |
481 | 2.55k | if (ScanAheadForHole()) |
482 | 1.02k | poGeom->toPolygon()->addRingDirectly(new OGRLinearRing()); |
483 | 1.53k | else |
484 | 1.53k | break; /* done geometry */ |
485 | 2.55k | } |
486 | 98.0k | else if (eType == wkbMultiLineString && !NextIsFeature()) |
487 | 3.68k | { |
488 | 3.68k | poGeom->toMultiLineString()->addGeometryDirectly( |
489 | 3.68k | new OGRLineString()); |
490 | 3.68k | } |
491 | 94.3k | else if (poGeom != nullptr) |
492 | 32.0k | { |
493 | 32.0k | break; |
494 | 32.0k | } |
495 | 62.3k | else if (poFeatureDefn->GetGeomType() == wkbUnknown) |
496 | 603 | { |
497 | 603 | poFeatureDefn->SetGeomType(wkbLineString); |
498 | | // bMultiVertex = true; |
499 | 603 | } |
500 | 126k | } |
501 | 763k | else if (osLine[0] == '#') |
502 | 164k | { |
503 | 164k | for (int i = 0; |
504 | 742k | papszKeyedValues != nullptr && papszKeyedValues[i] != nullptr; |
505 | 578k | i++) |
506 | 578k | { |
507 | 578k | if (papszKeyedValues[i][0] == 'D') |
508 | 60.6k | osFieldData = papszKeyedValues[i] + 1; |
509 | 578k | } |
510 | 164k | } |
511 | 599k | else |
512 | 599k | { |
513 | | // Parse point line. |
514 | 599k | double dfX = 0.0; |
515 | 599k | double dfY = 0.0; |
516 | 599k | double dfZ = 0.0; |
517 | 599k | const int nDim = CPLsscanf(osLine, "%lf %lf %lf", &dfX, &dfY, &dfZ); |
518 | | |
519 | 599k | if (nDim >= 2) |
520 | 126k | { |
521 | 126k | if (poGeom == nullptr) |
522 | 65.2k | { |
523 | 65.2k | switch (poFeatureDefn->GetGeomType()) |
524 | 65.2k | { |
525 | 28.3k | case wkbLineString: |
526 | 28.3k | poGeom = new OGRLineString(); |
527 | 28.3k | break; |
528 | | |
529 | 1.56k | case wkbPolygon: |
530 | 1.56k | { |
531 | 1.56k | OGRPolygon *poPoly = new OGRPolygon(); |
532 | 1.56k | poGeom = poPoly; |
533 | 1.56k | poPoly->addRingDirectly(new OGRLinearRing()); |
534 | 1.56k | break; |
535 | 0 | } |
536 | | |
537 | 2.03k | case wkbMultiPolygon: |
538 | 2.03k | { |
539 | 2.03k | OGRPolygon *poPoly = new OGRPolygon(); |
540 | 2.03k | poPoly->addRingDirectly(new OGRLinearRing()); |
541 | | |
542 | 2.03k | OGRMultiPolygon *poMP = new OGRMultiPolygon(); |
543 | 2.03k | poGeom = poMP; |
544 | 2.03k | poMP->addGeometryDirectly(poPoly); |
545 | 2.03k | } |
546 | 2.03k | break; |
547 | | |
548 | 0 | case wkbMultiPoint: |
549 | 0 | poGeom = new OGRMultiPoint(); |
550 | 0 | break; |
551 | | |
552 | 4.20k | case wkbMultiLineString: |
553 | 4.20k | { |
554 | 4.20k | OGRMultiLineString *poMLS = |
555 | 4.20k | new OGRMultiLineString(); |
556 | 4.20k | poGeom = poMLS; |
557 | 4.20k | poMLS->addGeometryDirectly(new OGRLineString()); |
558 | 4.20k | break; |
559 | 0 | } |
560 | | |
561 | 0 | case wkbPoint: |
562 | 29.1k | case wkbUnknown: |
563 | 29.1k | default: |
564 | 29.1k | poGeom = new OGRPoint(); |
565 | 29.1k | break; |
566 | 65.2k | } |
567 | 65.2k | } |
568 | | |
569 | 126k | CPLAssert(poGeom != nullptr); |
570 | | // cppcheck-suppress nullPointerRedundantCheck |
571 | 126k | switch (wkbFlatten(poGeom->getGeometryType())) |
572 | 126k | { |
573 | 29.1k | case wkbPoint: |
574 | 29.1k | { |
575 | 29.1k | OGRPoint *poPoint = poGeom->toPoint(); |
576 | 29.1k | poPoint->setX(dfX); |
577 | 29.1k | poPoint->setY(dfY); |
578 | 29.1k | if (nDim == 3) |
579 | 6.37k | poPoint->setZ(dfZ); |
580 | 29.1k | break; |
581 | 0 | } |
582 | | |
583 | 62.5k | case wkbLineString: |
584 | 62.5k | { |
585 | 62.5k | OGRLineString *poLS = poGeom->toLineString(); |
586 | 62.5k | if (nDim == 3) |
587 | 8.19k | poLS->addPoint(dfX, dfY, dfZ); |
588 | 54.3k | else |
589 | 54.3k | poLS->addPoint(dfX, dfY); |
590 | 62.5k | break; |
591 | 0 | } |
592 | | |
593 | 4.44k | case wkbPolygon: |
594 | 25.4k | case wkbMultiPolygon: |
595 | 25.4k | { |
596 | 25.4k | OGRPolygon *poPoly = nullptr; |
597 | | |
598 | 25.4k | if (wkbFlatten(poGeom->getGeometryType()) == |
599 | 25.4k | wkbMultiPolygon) |
600 | 21.0k | { |
601 | 21.0k | OGRMultiPolygon *poMP = poGeom->toMultiPolygon(); |
602 | 21.0k | poPoly = poMP->getGeometryRef( |
603 | 21.0k | poMP->getNumGeometries() - 1); |
604 | 21.0k | } |
605 | 4.44k | else |
606 | 4.44k | poPoly = poGeom->toPolygon(); |
607 | | |
608 | 25.4k | OGRLinearRing *poRing = nullptr; |
609 | 25.4k | if (poPoly->getNumInteriorRings() == 0) |
610 | 16.0k | poRing = poPoly->getExteriorRing(); |
611 | 9.38k | else |
612 | 9.38k | poRing = poPoly->getInteriorRing( |
613 | 9.38k | poPoly->getNumInteriorRings() - 1); |
614 | | |
615 | 25.4k | if (nDim == 3) |
616 | 4.21k | poRing->addPoint(dfX, dfY, dfZ); |
617 | 21.2k | else |
618 | 21.2k | poRing->addPoint(dfX, dfY); |
619 | 25.4k | } |
620 | 25.4k | break; |
621 | | |
622 | 8.98k | case wkbMultiLineString: |
623 | 8.98k | { |
624 | 8.98k | OGRMultiLineString *poML = poGeom->toMultiLineString(); |
625 | 8.98k | OGRLineString *poLine = |
626 | 8.98k | poML->getGeometryRef(poML->getNumGeometries() - 1); |
627 | | |
628 | 8.98k | if (nDim == 3) |
629 | 859 | poLine->addPoint(dfX, dfY, dfZ); |
630 | 8.12k | else |
631 | 8.12k | poLine->addPoint(dfX, dfY); |
632 | 8.98k | } |
633 | 8.98k | break; |
634 | | |
635 | 0 | default: |
636 | 0 | CPLAssert(false); |
637 | 126k | } |
638 | 126k | } |
639 | 599k | } |
640 | | |
641 | 855k | if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint) |
642 | 29.1k | { |
643 | 29.1k | ReadLine(); |
644 | 29.1k | break; |
645 | 29.1k | } |
646 | 855k | } |
647 | | |
648 | 75.8k | if (poGeom == nullptr) |
649 | 10.6k | return nullptr; |
650 | | |
651 | | /* -------------------------------------------------------------------- */ |
652 | | /* Create feature. */ |
653 | | /* -------------------------------------------------------------------- */ |
654 | 65.2k | OGRFeature *poFeature = new OGRFeature(poFeatureDefn); |
655 | 65.2k | poGeom->assignSpatialReference(m_poSRS); |
656 | 65.2k | poFeature->SetGeometryDirectly(poGeom); |
657 | 65.2k | poFeature->SetFID(iNextFID++); |
658 | | |
659 | | /* -------------------------------------------------------------------- */ |
660 | | /* Process field values. */ |
661 | | /* -------------------------------------------------------------------- */ |
662 | 65.2k | char **papszFD = CSLTokenizeStringComplex(osFieldData, "|", TRUE, TRUE); |
663 | | |
664 | 95.6k | for (int iField = 0; papszFD != nullptr && papszFD[iField] != nullptr; |
665 | 65.2k | iField++) |
666 | 37.3k | { |
667 | 37.3k | if (iField >= poFeatureDefn->GetFieldCount()) |
668 | 6.91k | break; |
669 | | |
670 | 30.4k | poFeature->SetField(iField, papszFD[iField]); |
671 | 30.4k | } |
672 | | |
673 | 65.2k | CSLDestroy(papszFD); |
674 | | |
675 | 65.2k | m_nFeaturesRead++; |
676 | | |
677 | 65.2k | return poFeature; |
678 | 75.8k | } |
679 | | |
680 | | /************************************************************************/ |
681 | | /* CompleteHeader() */ |
682 | | /* */ |
683 | | /* Finish writing out the header with field definitions and the */ |
684 | | /* layer geometry type. */ |
685 | | /************************************************************************/ |
686 | | |
687 | | OGRErr OGRGmtLayer::CompleteHeader(OGRGeometry *poThisGeom) |
688 | | |
689 | 127 | { |
690 | | /* -------------------------------------------------------------------- */ |
691 | | /* If we do not already have a geometry type, try to work one */ |
692 | | /* out and write it now. */ |
693 | | /* -------------------------------------------------------------------- */ |
694 | 127 | if (poFeatureDefn->GetGeomType() == wkbUnknown && poThisGeom != nullptr) |
695 | 9 | { |
696 | 9 | poFeatureDefn->SetGeomType(wkbFlatten(poThisGeom->getGeometryType())); |
697 | | |
698 | 9 | const char *pszGeom = nullptr; |
699 | 9 | switch (wkbFlatten(poFeatureDefn->GetGeomType())) |
700 | 9 | { |
701 | 0 | case wkbPoint: |
702 | 0 | pszGeom = " @GPOINT"; |
703 | 0 | break; |
704 | 0 | case wkbLineString: |
705 | 0 | pszGeom = " @GLINESTRING"; |
706 | 0 | break; |
707 | 0 | case wkbPolygon: |
708 | 0 | pszGeom = " @GPOLYGON"; |
709 | 0 | break; |
710 | 0 | case wkbMultiPoint: |
711 | 0 | pszGeom = " @GMULTIPOINT"; |
712 | 0 | break; |
713 | 9 | case wkbMultiLineString: |
714 | 9 | pszGeom = " @GMULTILINESTRING"; |
715 | 9 | break; |
716 | 0 | case wkbMultiPolygon: |
717 | 0 | pszGeom = " @GMULTIPOLYGON"; |
718 | 0 | break; |
719 | 0 | default: |
720 | 0 | pszGeom = ""; |
721 | 0 | break; |
722 | 9 | } |
723 | | |
724 | 9 | VSIFPrintfL(m_fp, "#%s\n", pszGeom); |
725 | 9 | } |
726 | | |
727 | | /* -------------------------------------------------------------------- */ |
728 | | /* Prepare and write the field names and types. */ |
729 | | /* -------------------------------------------------------------------- */ |
730 | 127 | CPLString osFieldNames; |
731 | 127 | CPLString osFieldTypes; |
732 | | |
733 | 1.70k | for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++) |
734 | 1.57k | { |
735 | 1.57k | if (iField > 0) |
736 | 1.45k | { |
737 | 1.45k | osFieldNames += "|"; |
738 | 1.45k | osFieldTypes += "|"; |
739 | 1.45k | } |
740 | | |
741 | 1.57k | osFieldNames += poFeatureDefn->GetFieldDefn(iField)->GetNameRef(); |
742 | 1.57k | switch (poFeatureDefn->GetFieldDefn(iField)->GetType()) |
743 | 1.57k | { |
744 | 4 | case OFTInteger: |
745 | 4 | osFieldTypes += "integer"; |
746 | 4 | break; |
747 | | |
748 | 9 | case OFTReal: |
749 | 9 | osFieldTypes += "double"; |
750 | 9 | break; |
751 | | |
752 | 0 | case OFTDateTime: |
753 | 0 | osFieldTypes += "datetime"; |
754 | 0 | break; |
755 | | |
756 | 1.56k | default: |
757 | 1.56k | osFieldTypes += "string"; |
758 | 1.56k | break; |
759 | 1.57k | } |
760 | 1.57k | } |
761 | | |
762 | 127 | if (poFeatureDefn->GetFieldCount() > 0) |
763 | 126 | { |
764 | 126 | VSIFPrintfL(m_fp, "# @N%s\n", osFieldNames.c_str()); |
765 | 126 | VSIFPrintfL(m_fp, "# @T%s\n", osFieldTypes.c_str()); |
766 | 126 | } |
767 | | |
768 | | /* -------------------------------------------------------------------- */ |
769 | | /* Mark the end of the header, and start of feature data. */ |
770 | | /* -------------------------------------------------------------------- */ |
771 | 127 | VSIFPrintfL(m_fp, "# FEATURE_DATA\n"); |
772 | | |
773 | 127 | bHeaderComplete = true; |
774 | 127 | bRegionComplete = true; // no feature written, so we know them all! |
775 | | |
776 | 127 | return OGRERR_NONE; |
777 | 127 | } |
778 | | |
779 | | /************************************************************************/ |
780 | | /* ICreateFeature() */ |
781 | | /************************************************************************/ |
782 | | |
783 | | OGRErr OGRGmtLayer::ICreateFeature(OGRFeature *poFeature) |
784 | | |
785 | 46.4k | { |
786 | 46.4k | if (!bUpdate) |
787 | 0 | { |
788 | 0 | CPLError(CE_Failure, CPLE_NoWriteAccess, |
789 | 0 | "Cannot create features on read-only dataset."); |
790 | 0 | return OGRERR_FAILURE; |
791 | 0 | } |
792 | | |
793 | | /* -------------------------------------------------------------------- */ |
794 | | /* Do we need to write the header describing the fields? */ |
795 | | /* -------------------------------------------------------------------- */ |
796 | 46.4k | if (!bHeaderComplete) |
797 | 127 | { |
798 | 127 | OGRErr eErr = CompleteHeader(poFeature->GetGeometryRef()); |
799 | | |
800 | 127 | if (eErr != OGRERR_NONE) |
801 | 0 | return eErr; |
802 | 127 | } |
803 | | |
804 | | /* -------------------------------------------------------------------- */ |
805 | | /* Write out the feature */ |
806 | | /* -------------------------------------------------------------------- */ |
807 | 46.4k | OGRGeometry *poGeom = poFeature->GetGeometryRef(); |
808 | | |
809 | 46.4k | if (poGeom == nullptr) |
810 | 44.8k | { |
811 | 44.8k | CPLError(CE_Failure, CPLE_AppDefined, |
812 | 44.8k | "Features without geometry not supported by GMT writer."); |
813 | 44.8k | return OGRERR_FAILURE; |
814 | 44.8k | } |
815 | | |
816 | 1.54k | if (poFeatureDefn->GetGeomType() == wkbUnknown) |
817 | 55 | poFeatureDefn->SetGeomType(wkbFlatten(poGeom->getGeometryType())); |
818 | | |
819 | | // Do we need a vertex collection marker grouping vertices. |
820 | 1.54k | if (poFeatureDefn->GetGeomType() != wkbPoint) |
821 | 1.48k | VSIFPrintfL(m_fp, ">\n"); |
822 | | |
823 | | /* -------------------------------------------------------------------- */ |
824 | | /* Write feature properties() */ |
825 | | /* -------------------------------------------------------------------- */ |
826 | 1.54k | if (poFeatureDefn->GetFieldCount() > 0) |
827 | 1.54k | { |
828 | 1.54k | CPLString osFieldData; |
829 | | |
830 | 5.92k | for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++) |
831 | 4.38k | { |
832 | 4.38k | OGRFieldType eFType = |
833 | 4.38k | poFeatureDefn->GetFieldDefn(iField)->GetType(); |
834 | 4.38k | const char *pszRawValue = poFeature->GetFieldAsString(iField); |
835 | | |
836 | 4.38k | if (iField > 0) |
837 | 2.84k | osFieldData += "|"; |
838 | | |
839 | | // We do not want prefix spaces for numeric values. |
840 | 4.38k | if (eFType == OFTInteger || eFType == OFTReal) |
841 | 8 | while (*pszRawValue == ' ') |
842 | 0 | pszRawValue++; |
843 | | |
844 | 4.38k | if (strchr(pszRawValue, ' ') || strchr(pszRawValue, '|') || |
845 | 3.86k | strchr(pszRawValue, '\t') || strchr(pszRawValue, '\n')) |
846 | 959 | { |
847 | 959 | osFieldData += "\""; |
848 | | |
849 | 959 | char *pszEscapedVal = |
850 | 959 | CPLEscapeString(pszRawValue, -1, CPLES_BackslashQuotable); |
851 | 959 | osFieldData += pszEscapedVal; |
852 | 959 | CPLFree(pszEscapedVal); |
853 | | |
854 | 959 | osFieldData += "\""; |
855 | 959 | } |
856 | 3.42k | else |
857 | 3.42k | osFieldData += pszRawValue; |
858 | 4.38k | } |
859 | | |
860 | 1.54k | VSIFPrintfL(m_fp, "# @D%s\n", osFieldData.c_str()); |
861 | 1.54k | } |
862 | | |
863 | | /* -------------------------------------------------------------------- */ |
864 | | /* Write Geometry */ |
865 | | /* -------------------------------------------------------------------- */ |
866 | 1.54k | return WriteGeometry(OGRGeometry::ToHandle(poGeom), true); |
867 | 46.4k | } |
868 | | |
869 | | /************************************************************************/ |
870 | | /* WriteGeometry() */ |
871 | | /* */ |
872 | | /* Write a geometry to the file. If bHaveAngle is true it */ |
873 | | /* means the angle bracket preceding the point stream has */ |
874 | | /* already been written out. */ |
875 | | /* */ |
876 | | /* We use the C API for geometry access because of its */ |
877 | | /* simplified access to vertices and children geometries. */ |
878 | | /************************************************************************/ |
879 | | |
880 | | OGRErr OGRGmtLayer::WriteGeometry(OGRGeometryH hGeom, bool bHaveAngle) |
881 | | |
882 | 1.88k | { |
883 | | /* -------------------------------------------------------------------- */ |
884 | | /* This is a geometry with sub-geometries. */ |
885 | | /* -------------------------------------------------------------------- */ |
886 | 1.88k | if (OGR_G_GetGeometryCount(hGeom) > 0) |
887 | 232 | { |
888 | 232 | OGRErr eErr = OGRERR_NONE; |
889 | | |
890 | 232 | for (int iGeom = 0; |
891 | 572 | iGeom < OGR_G_GetGeometryCount(hGeom) && eErr == OGRERR_NONE; |
892 | 340 | iGeom++) |
893 | 340 | { |
894 | | // We need to emit polygon @P and @H items while we still |
895 | | // know this is a polygon and which is the outer and inner |
896 | | // ring. |
897 | 340 | if (wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPolygon) |
898 | 130 | { |
899 | 130 | if (!bHaveAngle) |
900 | 38 | { |
901 | 38 | VSIFPrintfL(m_fp, ">\n"); |
902 | 38 | bHaveAngle = true; |
903 | 38 | } |
904 | 130 | if (iGeom == 0) |
905 | 92 | VSIFPrintfL(m_fp, "# @P\n"); |
906 | 38 | else |
907 | 38 | VSIFPrintfL(m_fp, "# @H\n"); |
908 | 130 | } |
909 | | |
910 | 340 | eErr = |
911 | 340 | WriteGeometry(OGR_G_GetGeometryRef(hGeom, iGeom), bHaveAngle); |
912 | 340 | bHaveAngle = false; |
913 | 340 | } |
914 | 232 | return eErr; |
915 | 232 | } |
916 | | |
917 | | /* -------------------------------------------------------------------- */ |
918 | | /* If this is not a point we need to have an angle bracket to */ |
919 | | /* mark the vertex list. */ |
920 | | /* -------------------------------------------------------------------- */ |
921 | 1.64k | if (wkbFlatten(OGR_G_GetGeometryType(hGeom)) != wkbPoint && !bHaveAngle) |
922 | 70 | VSIFPrintfL(m_fp, ">\n"); |
923 | | |
924 | | /* -------------------------------------------------------------------- */ |
925 | | /* Dump vertices. */ |
926 | | /* -------------------------------------------------------------------- */ |
927 | 1.64k | const int nPointCount = OGR_G_GetPointCount(hGeom); |
928 | 1.64k | const int nDim = OGR_G_GetCoordinateDimension(hGeom); |
929 | | // For testing only. Ticket #6453 |
930 | 1.64k | const bool bUseTab = |
931 | 1.64k | CPLTestBool(CPLGetConfigOption("GMT_USE_TAB", "FALSE")); |
932 | | |
933 | 4.20k | for (int iPoint = 0; iPoint < nPointCount; iPoint++) |
934 | 2.55k | { |
935 | 2.55k | const double dfX = OGR_G_GetX(hGeom, iPoint); |
936 | 2.55k | const double dfY = OGR_G_GetY(hGeom, iPoint); |
937 | 2.55k | const double dfZ = OGR_G_GetZ(hGeom, iPoint); |
938 | | |
939 | 2.55k | sRegion.Merge(dfX, dfY); |
940 | 2.55k | char szLine[128]; |
941 | 2.55k | OGRMakeWktCoordinate(szLine, dfX, dfY, dfZ, nDim); |
942 | 2.55k | if (bUseTab) |
943 | 0 | { |
944 | 0 | for (char *szPtr = szLine; *szPtr != '\0'; ++szPtr) |
945 | 0 | { |
946 | 0 | if (*szPtr == ' ') |
947 | 0 | *szPtr = '\t'; |
948 | 0 | } |
949 | 0 | } |
950 | 2.55k | if (VSIFPrintfL(m_fp, "%s\n", szLine) < 1) |
951 | 0 | { |
952 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Gmt write failure: %s", |
953 | 0 | VSIStrerror(errno)); |
954 | 0 | return OGRERR_FAILURE; |
955 | 0 | } |
956 | 2.55k | } |
957 | | |
958 | 1.64k | return OGRERR_NONE; |
959 | 1.64k | } |
960 | | |
961 | | /************************************************************************/ |
962 | | /* IGetExtent() */ |
963 | | /* */ |
964 | | /* Fetch extent of the data currently stored in the dataset. */ |
965 | | /* The bForce flag has no effect on SHO files since that value */ |
966 | | /* is always in the header. */ |
967 | | /* */ |
968 | | /* Returns OGRERR_NONE/OGRRERR_FAILURE. */ |
969 | | /************************************************************************/ |
970 | | |
971 | | OGRErr OGRGmtLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, |
972 | | bool bForce) |
973 | | |
974 | 0 | { |
975 | 0 | if (bRegionComplete && sRegion.IsInit()) |
976 | 0 | { |
977 | 0 | *psExtent = sRegion; |
978 | 0 | return OGRERR_NONE; |
979 | 0 | } |
980 | | |
981 | 0 | return OGRLayer::IGetExtent(iGeomField, psExtent, bForce); |
982 | 0 | } |
983 | | |
984 | | /************************************************************************/ |
985 | | /* TestCapability() */ |
986 | | /************************************************************************/ |
987 | | |
988 | | int OGRGmtLayer::TestCapability(const char *pszCap) const |
989 | | |
990 | 421 | { |
991 | 421 | if (EQUAL(pszCap, OLCRandomRead)) |
992 | 0 | return FALSE; |
993 | | |
994 | 421 | if (EQUAL(pszCap, OLCSequentialWrite)) |
995 | 0 | return TRUE; |
996 | | |
997 | 421 | if (EQUAL(pszCap, OLCFastSpatialFilter)) |
998 | 0 | return FALSE; |
999 | | |
1000 | 421 | if (EQUAL(pszCap, OLCFastGetExtent)) |
1001 | 0 | return bRegionComplete; |
1002 | | |
1003 | 421 | if (EQUAL(pszCap, OLCCreateField)) |
1004 | 0 | return TRUE; |
1005 | | |
1006 | 421 | if (EQUAL(pszCap, OLCZGeometries)) |
1007 | 0 | return TRUE; |
1008 | | |
1009 | 421 | return FALSE; |
1010 | 421 | } |
1011 | | |
1012 | | /************************************************************************/ |
1013 | | /* CreateField() */ |
1014 | | /************************************************************************/ |
1015 | | |
1016 | | OGRErr OGRGmtLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK) |
1017 | | |
1018 | 1.81k | { |
1019 | 1.81k | if (!bUpdate) |
1020 | 0 | { |
1021 | 0 | CPLError(CE_Failure, CPLE_NoWriteAccess, |
1022 | 0 | "Cannot create fields on read-only dataset."); |
1023 | 0 | return OGRERR_FAILURE; |
1024 | 0 | } |
1025 | | |
1026 | 1.81k | if (bHeaderComplete) |
1027 | 0 | { |
1028 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1029 | 0 | "Unable to create fields after features have been created."); |
1030 | 0 | return OGRERR_FAILURE; |
1031 | 0 | } |
1032 | | |
1033 | 1.81k | switch (poField->GetType()) |
1034 | 1.81k | { |
1035 | 4 | case OFTInteger: |
1036 | 13 | case OFTReal: |
1037 | 1.81k | case OFTString: |
1038 | 1.81k | case OFTDateTime: |
1039 | 1.81k | poFeatureDefn->AddFieldDefn(poField); |
1040 | 1.81k | return OGRERR_NONE; |
1041 | | |
1042 | 0 | default: |
1043 | 0 | if (!bApproxOK) |
1044 | 0 | { |
1045 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1046 | 0 | "Field %s is of unsupported type %s.", |
1047 | 0 | poField->GetNameRef(), |
1048 | 0 | poField->GetFieldTypeName(poField->GetType())); |
1049 | 0 | return OGRERR_FAILURE; |
1050 | 0 | } |
1051 | 0 | else if (poField->GetType() == OFTDate || |
1052 | 0 | poField->GetType() == OFTTime) |
1053 | 0 | { |
1054 | 0 | OGRFieldDefn oModDef(poField); |
1055 | 0 | oModDef.SetType(OFTDateTime); |
1056 | 0 | poFeatureDefn->AddFieldDefn(poField); |
1057 | 0 | return OGRERR_NONE; |
1058 | 0 | } |
1059 | 0 | else |
1060 | 0 | { |
1061 | 0 | OGRFieldDefn oModDef(poField); |
1062 | 0 | oModDef.SetType(OFTString); |
1063 | 0 | poFeatureDefn->AddFieldDefn(poField); |
1064 | 0 | return OGRERR_NONE; |
1065 | 0 | } |
1066 | 1.81k | } |
1067 | 1.81k | } |