Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements translation of Shapefile shapes into OGR
5 : * representation.
6 : * Author: Frank Warmerdam, warmerda@home.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Les Technologies SoftMap Inc.
10 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "ogrshape.h"
33 :
34 : #include <cmath>
35 : #include <cstdio>
36 : #include <cstdlib>
37 : #include <cstring>
38 : #include <algorithm>
39 : #include <limits>
40 : #include <memory>
41 : #include <utility>
42 :
43 : #include "cpl_conv.h"
44 : #include "cpl_error.h"
45 : #include "cpl_string.h"
46 : #include "ogr_core.h"
47 : #include "ogr_feature.h"
48 : #include "ogr_geometry.h"
49 : #include "ogrpgeogeometry.h"
50 : #include "ogrshape.h"
51 : #include "shapefil.h"
52 :
53 : /************************************************************************/
54 : /* RingStartEnd */
55 : /* Set first and last vertex for given ring. */
56 : /************************************************************************/
57 32248 : static void RingStartEnd(SHPObject *psShape, int ring, int *start, int *end)
58 : {
59 32248 : if (psShape->panPartStart == nullptr)
60 : {
61 0 : *start = 0;
62 0 : *end = psShape->nVertices - 1;
63 : }
64 : else
65 : {
66 32248 : *start = psShape->panPartStart[ring];
67 :
68 32248 : if (ring == psShape->nParts - 1)
69 32036 : *end = psShape->nVertices - 1;
70 : else
71 212 : *end = psShape->panPartStart[ring + 1] - 1;
72 : }
73 32248 : }
74 :
75 : /************************************************************************/
76 : /* CreateLinearRing */
77 : /************************************************************************/
78 32248 : static OGRLinearRing *CreateLinearRing(SHPObject *psShape, int ring, bool bHasZ,
79 : bool bHasM)
80 : {
81 32248 : int nRingStart = 0;
82 32248 : int nRingEnd = 0;
83 32248 : RingStartEnd(psShape, ring, &nRingStart, &nRingEnd);
84 :
85 32248 : OGRLinearRing *const poRing = new OGRLinearRing();
86 32248 : if (!(nRingEnd >= nRingStart))
87 0 : return poRing;
88 :
89 32248 : const int nRingPoints = nRingEnd - nRingStart + 1;
90 :
91 32248 : if (bHasZ && bHasM)
92 36 : poRing->setPoints(
93 42 : nRingPoints, psShape->padfX + nRingStart,
94 42 : psShape->padfY + nRingStart, psShape->padfZ + nRingStart,
95 42 : psShape->padfM ? psShape->padfM + nRingStart : nullptr);
96 32206 : else if (bHasM)
97 3 : poRing->setPointsM(nRingPoints, psShape->padfX + nRingStart,
98 12 : psShape->padfY + nRingStart,
99 12 : psShape->padfM ? psShape->padfM + nRingStart
100 : : nullptr);
101 : else
102 32194 : poRing->setPoints(nRingPoints, psShape->padfX + nRingStart,
103 32194 : psShape->padfY + nRingStart);
104 :
105 32248 : return poRing;
106 : }
107 :
108 : /************************************************************************/
109 : /* SHPReadOGRObject() */
110 : /* */
111 : /* Read an item in a shapefile, and translate to OGR geometry */
112 : /* representation. */
113 : /************************************************************************/
114 :
115 87751 : OGRGeometry *SHPReadOGRObject(SHPHandle hSHP, int iShape, SHPObject *psShape,
116 : bool &bHasWarnedWrongWindingOrder)
117 : {
118 : #if DEBUG_VERBOSE
119 : CPLDebug("Shape", "SHPReadOGRObject( iShape=%d )", iShape);
120 : #endif
121 :
122 87751 : if (psShape == nullptr)
123 57616 : psShape = SHPReadObject(hSHP, iShape);
124 :
125 87751 : if (psShape == nullptr)
126 : {
127 11 : return nullptr;
128 : }
129 :
130 87740 : OGRGeometry *poOGR = nullptr;
131 :
132 : /* -------------------------------------------------------------------- */
133 : /* Point. */
134 : /* -------------------------------------------------------------------- */
135 87740 : if (psShape->nSHPType == SHPT_POINT)
136 : {
137 6329 : poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0]);
138 : }
139 81411 : else if (psShape->nSHPType == SHPT_POINTZ)
140 : {
141 43942 : if (psShape->bMeasureIsUsed)
142 : {
143 7 : poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0],
144 7 : psShape->padfZ[0], psShape->padfM[0]);
145 : }
146 : else
147 : {
148 43935 : poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0],
149 43935 : psShape->padfZ[0]);
150 : }
151 : }
152 37469 : else if (psShape->nSHPType == SHPT_POINTM)
153 : {
154 10 : poOGR = new OGRPoint(psShape->padfX[0], psShape->padfY[0], 0.0,
155 5 : psShape->padfM[0]);
156 5 : poOGR->set3D(FALSE);
157 : }
158 : /* -------------------------------------------------------------------- */
159 : /* Multipoint. */
160 : /* -------------------------------------------------------------------- */
161 37464 : else if (psShape->nSHPType == SHPT_MULTIPOINT ||
162 37452 : psShape->nSHPType == SHPT_MULTIPOINTM ||
163 37450 : psShape->nSHPType == SHPT_MULTIPOINTZ)
164 : {
165 22 : if (psShape->nVertices == 0)
166 : {
167 1 : poOGR = nullptr;
168 : }
169 : else
170 : {
171 21 : OGRMultiPoint *poOGRMPoint = new OGRMultiPoint();
172 :
173 54 : for (int i = 0; i < psShape->nVertices; i++)
174 : {
175 33 : OGRPoint *poPoint = nullptr;
176 :
177 33 : if (psShape->nSHPType == SHPT_MULTIPOINTZ)
178 : {
179 12 : if (psShape->padfM)
180 : {
181 2 : poPoint =
182 2 : new OGRPoint(psShape->padfX[i], psShape->padfY[i],
183 2 : psShape->padfZ[i], psShape->padfM[i]);
184 : }
185 : else
186 : {
187 10 : poPoint =
188 10 : new OGRPoint(psShape->padfX[i], psShape->padfY[i],
189 10 : psShape->padfZ[i]);
190 : }
191 : }
192 21 : else if (psShape->nSHPType == SHPT_MULTIPOINTM &&
193 2 : psShape->padfM)
194 : {
195 4 : poPoint = new OGRPoint(psShape->padfX[i], psShape->padfY[i],
196 2 : 0.0, psShape->padfM[i]);
197 2 : poPoint->set3D(FALSE);
198 : }
199 : else
200 : {
201 19 : poPoint =
202 19 : new OGRPoint(psShape->padfX[i], psShape->padfY[i]);
203 : }
204 :
205 33 : poOGRMPoint->addGeometry(poPoint);
206 :
207 33 : delete poPoint;
208 : }
209 :
210 21 : poOGR = poOGRMPoint;
211 22 : }
212 : }
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Arc (LineString) */
216 : /* */
217 : /* Ignoring parts though they can apply to arcs as well. */
218 : /* -------------------------------------------------------------------- */
219 37442 : else if (psShape->nSHPType == SHPT_ARC || psShape->nSHPType == SHPT_ARCM ||
220 34629 : psShape->nSHPType == SHPT_ARCZ)
221 : {
222 4693 : if (psShape->nParts == 0)
223 : {
224 1 : poOGR = nullptr;
225 : }
226 4692 : else if (psShape->nParts == 1)
227 : {
228 4668 : OGRLineString *poOGRLine = new OGRLineString();
229 4668 : poOGR = poOGRLine;
230 :
231 4668 : if (psShape->nSHPType == SHPT_ARCZ)
232 1873 : poOGRLine->setPoints(psShape->nVertices, psShape->padfX,
233 1873 : psShape->padfY, psShape->padfZ,
234 1873 : psShape->padfM);
235 2795 : else if (psShape->nSHPType == SHPT_ARCM)
236 4 : poOGRLine->setPointsM(psShape->nVertices, psShape->padfX,
237 4 : psShape->padfY, psShape->padfM);
238 : else
239 2791 : poOGRLine->setPoints(psShape->nVertices, psShape->padfX,
240 2791 : psShape->padfY);
241 : }
242 : else
243 : {
244 24 : OGRMultiLineString *poOGRMulti = new OGRMultiLineString();
245 24 : poOGR = poOGRMulti;
246 :
247 73 : for (int iRing = 0; iRing < psShape->nParts; iRing++)
248 : {
249 49 : int nRingPoints = 0;
250 49 : int nRingStart = 0;
251 :
252 49 : OGRLineString *poLine = new OGRLineString();
253 :
254 49 : if (psShape->panPartStart == nullptr)
255 : {
256 0 : nRingPoints = psShape->nVertices;
257 0 : nRingStart = 0;
258 : }
259 : else
260 : {
261 49 : if (iRing == psShape->nParts - 1)
262 24 : nRingPoints =
263 24 : psShape->nVertices - psShape->panPartStart[iRing];
264 : else
265 25 : nRingPoints = psShape->panPartStart[iRing + 1] -
266 25 : psShape->panPartStart[iRing];
267 49 : nRingStart = psShape->panPartStart[iRing];
268 : }
269 :
270 49 : if (psShape->nSHPType == SHPT_ARCZ)
271 10 : poLine->setPoints(
272 14 : nRingPoints, psShape->padfX + nRingStart,
273 14 : psShape->padfY + nRingStart,
274 14 : psShape->padfZ + nRingStart,
275 14 : psShape->padfM ? psShape->padfM + nRingStart : nullptr);
276 35 : else if (psShape->nSHPType == SHPT_ARCM &&
277 8 : psShape->padfM != nullptr)
278 6 : poLine->setPointsM(nRingPoints, psShape->padfX + nRingStart,
279 6 : psShape->padfY + nRingStart,
280 6 : psShape->padfM + nRingStart);
281 : else
282 29 : poLine->setPoints(nRingPoints, psShape->padfX + nRingStart,
283 29 : psShape->padfY + nRingStart);
284 :
285 49 : poOGRMulti->addGeometryDirectly(poLine);
286 : }
287 4693 : }
288 : }
289 :
290 : /* -------------------------------------------------------------------- */
291 : /* Polygon */
292 : /* */
293 : /* As for now Z coordinate is not handled correctly */
294 : /* -------------------------------------------------------------------- */
295 32749 : else if (psShape->nSHPType == SHPT_POLYGON ||
296 738 : psShape->nSHPType == SHPT_POLYGONM ||
297 730 : psShape->nSHPType == SHPT_POLYGONZ)
298 : {
299 32037 : const bool bHasZ = psShape->nSHPType == SHPT_POLYGONZ;
300 32037 : const bool bHasM = bHasZ || psShape->nSHPType == SHPT_POLYGONM;
301 :
302 : #if DEBUG_VERBOSE
303 : CPLDebug("Shape", "Shape type: polygon with nParts=%d",
304 : psShape->nParts);
305 : #endif
306 :
307 32037 : if (psShape->nParts == 0)
308 : {
309 1 : poOGR = nullptr;
310 : }
311 32036 : else if (psShape->nParts == 1)
312 : {
313 : // Surely outer ring.
314 31917 : OGRPolygon *poOGRPoly = new OGRPolygon();
315 31917 : poOGR = poOGRPoly;
316 :
317 31917 : OGRLinearRing *poRing = CreateLinearRing(psShape, 0, bHasZ, bHasM);
318 31917 : poOGRPoly->addRingDirectly(poRing);
319 : }
320 : else
321 : {
322 119 : OGRPolygon **tabPolygons = new OGRPolygon *[psShape->nParts];
323 450 : for (int iRing = 0; iRing < psShape->nParts; iRing++)
324 : {
325 331 : tabPolygons[iRing] = new OGRPolygon();
326 662 : tabPolygons[iRing]->addRingDirectly(
327 331 : CreateLinearRing(psShape, iRing, bHasZ, bHasM));
328 : }
329 :
330 : // Tries to detect bad geometries where a multi-part multipolygon is
331 : // written as a single-part multipolygon with its parts as inner
332 : // rings, like done by QGIS <= 3.28.11 with GDAL >= 3.7
333 : // Cf https://github.com/qgis/QGIS/issues/54537
334 119 : bool bUseSlowMethod = false;
335 119 : if (!bHasZ && !bHasM)
336 : {
337 105 : bool bFoundCW = false;
338 225 : for (int iRing = 1; iRing < psShape->nParts; iRing++)
339 : {
340 161 : if (tabPolygons[iRing]->getExteriorRing()->isClockwise())
341 : {
342 41 : bFoundCW = true;
343 41 : break;
344 : }
345 : }
346 105 : if (!bFoundCW)
347 : {
348 : // Only inner rings
349 64 : OGREnvelope sFirstEnvelope;
350 64 : OGREnvelope sCurEnvelope;
351 64 : auto poExteriorRing = tabPolygons[0]->getExteriorRing();
352 64 : tabPolygons[0]->getEnvelope(&sFirstEnvelope);
353 129 : for (int iRing = 1; iRing < psShape->nParts; iRing++)
354 : {
355 67 : tabPolygons[iRing]->getEnvelope(&sCurEnvelope);
356 67 : if (!sFirstEnvelope.Intersects(sCurEnvelope))
357 : {
358 : // If the envelopes of the rings don't intersect,
359 : // then it is clearly a multi-part polygon
360 1 : bUseSlowMethod = true;
361 1 : break;
362 : }
363 : else
364 : {
365 : // Otherwise take 4 points at each extremity of
366 : // the inner rings and check if there are in the
367 : // outer ring. If none are within it, then it is
368 : // very likely a outer ring (or an invalid ring
369 : // which is neither a outer nor a inner ring)
370 66 : auto poRing = tabPolygons[iRing]->getExteriorRing();
371 66 : const auto nNumPoints = poRing->getNumPoints();
372 66 : OGRPoint p;
373 : OGRPoint leftPoint(
374 66 : std::numeric_limits<double>::infinity(), 0);
375 : OGRPoint rightPoint(
376 66 : -std::numeric_limits<double>::infinity(), 0);
377 : OGRPoint bottomPoint(
378 66 : 0, std::numeric_limits<double>::infinity());
379 : OGRPoint topPoint(
380 66 : 0, -std::numeric_limits<double>::infinity());
381 9098 : for (int iPoint = 0; iPoint < nNumPoints - 1;
382 : ++iPoint)
383 : {
384 9032 : poRing->getPoint(iPoint, &p);
385 20108 : if (p.getX() < leftPoint.getX() ||
386 11076 : (p.getX() == leftPoint.getX() &&
387 4399 : p.getY() < leftPoint.getY()))
388 : {
389 4550 : leftPoint = p;
390 : }
391 20188 : if (p.getX() > rightPoint.getX() ||
392 11156 : (p.getX() == rightPoint.getX() &&
393 2209 : p.getY() > rightPoint.getY()))
394 : {
395 2291 : rightPoint = p;
396 : }
397 20202 : if (p.getY() < bottomPoint.getY() ||
398 11170 : (p.getY() == bottomPoint.getY() &&
399 2254 : p.getX() > bottomPoint.getX()))
400 : {
401 2321 : bottomPoint = p;
402 : }
403 17959 : if (p.getY() > topPoint.getY() ||
404 8927 : (p.getY() == topPoint.getY() &&
405 2220 : p.getX() < topPoint.getX()))
406 : {
407 4531 : topPoint = p;
408 : }
409 : }
410 66 : if (!poExteriorRing->isPointInRing(&leftPoint) &&
411 1 : !poExteriorRing->isPointInRing(&rightPoint) &&
412 68 : !poExteriorRing->isPointInRing(&bottomPoint) &&
413 1 : !poExteriorRing->isPointInRing(&topPoint))
414 : {
415 1 : bUseSlowMethod = true;
416 1 : break;
417 : }
418 : }
419 : }
420 64 : if (bUseSlowMethod && !bHasWarnedWrongWindingOrder)
421 : {
422 1 : bHasWarnedWrongWindingOrder = true;
423 1 : CPLError(CE_Warning, CPLE_AppDefined,
424 : "%s contains polygon(s) with rings with "
425 : "invalid winding order. Autocorrecting them, "
426 : "but that shapefile should be corrected using "
427 : "ogr2ogr for example.",
428 : VSI_SHP_GetFilename(hSHP->fpSHP));
429 : }
430 : }
431 : }
432 :
433 119 : int isValidGeometry = FALSE;
434 119 : const char *papszOptions[] = {
435 119 : bUseSlowMethod ? "METHOD=DEFAULT" : "METHOD=ONLY_CCW", nullptr};
436 119 : OGRGeometry **tabGeom =
437 : reinterpret_cast<OGRGeometry **>(tabPolygons);
438 119 : poOGR = OGRGeometryFactory::organizePolygons(
439 : tabGeom, psShape->nParts, &isValidGeometry, papszOptions);
440 :
441 119 : if (!isValidGeometry)
442 : {
443 0 : CPLError(
444 : CE_Warning, CPLE_AppDefined,
445 : "Geometry of polygon of fid %d cannot be translated to "
446 : "Simple Geometry. "
447 : "All polygons will be contained in a multipolygon.",
448 : iShape);
449 : }
450 :
451 119 : delete[] tabPolygons;
452 32037 : }
453 : }
454 :
455 : /* -------------------------------------------------------------------- */
456 : /* MultiPatch */
457 : /* -------------------------------------------------------------------- */
458 712 : else if (psShape->nSHPType == SHPT_MULTIPATCH)
459 : {
460 12 : poOGR = OGRCreateFromMultiPatch(
461 12 : psShape->nParts, psShape->panPartStart, psShape->panPartType,
462 12 : psShape->nVertices, psShape->padfX, psShape->padfY, psShape->padfZ);
463 : }
464 :
465 : /* -------------------------------------------------------------------- */
466 : /* Otherwise for now we just ignore the object. */
467 : /* -------------------------------------------------------------------- */
468 : else
469 : {
470 700 : if (psShape->nSHPType != SHPT_NULL)
471 : {
472 0 : CPLDebug("OGR", "Unsupported shape type in SHPReadOGRObject()");
473 : }
474 :
475 : // Nothing returned.
476 : }
477 :
478 : /* -------------------------------------------------------------------- */
479 : /* Cleanup shape, and set feature id. */
480 : /* -------------------------------------------------------------------- */
481 87740 : SHPDestroyObject(psShape);
482 :
483 87740 : return poOGR;
484 : }
485 :
486 : /************************************************************************/
487 : /* CheckNonFiniteCoordinates() */
488 : /************************************************************************/
489 :
490 125872 : static bool CheckNonFiniteCoordinates(const double *v, size_t vsize)
491 : {
492 103 : static bool bAllowNonFiniteCoordinates = CPLTestBool(
493 125975 : CPLGetConfigOption("OGR_SHAPE_ALLOW_NON_FINITE_COORDINATES", "NO"));
494 : // Do not document this. Only for edge case testing
495 125872 : if (bAllowNonFiniteCoordinates)
496 : {
497 0 : return true;
498 : }
499 575864 : for (size_t i = 0; i < vsize; ++i)
500 : {
501 449996 : if (!std::isfinite(v[i]))
502 : {
503 4 : CPLError(CE_Failure, CPLE_NotSupported,
504 : "Coordinates with non-finite values are not allowed");
505 4 : return false;
506 : }
507 : }
508 125868 : return true;
509 : }
510 :
511 125836 : static bool CheckNonFiniteCoordinates(const std::vector<double> &v)
512 : {
513 125836 : return CheckNonFiniteCoordinates(v.data(), v.size());
514 : }
515 :
516 : /************************************************************************/
517 : /* SHPWriteOGRObject() */
518 : /************************************************************************/
519 76835 : static OGRErr SHPWriteOGRObject(SHPHandle hSHP, int iShape,
520 : const OGRGeometry *poGeom, bool bRewind,
521 : OGRwkbGeometryType eLayerGeomType)
522 :
523 : {
524 : /* ==================================================================== */
525 : /* Write "shape" with no geometry or with empty geometry */
526 : /* ==================================================================== */
527 76835 : if (poGeom == nullptr || poGeom->IsEmpty())
528 : {
529 : SHPObject *psShape =
530 615 : SHPCreateObject(SHPT_NULL, -1, 0, nullptr, nullptr, 0, nullptr,
531 : nullptr, nullptr, nullptr);
532 615 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
533 615 : SHPDestroyObject(psShape);
534 615 : if (nReturnedShapeID == -1)
535 : {
536 : // Assuming error is reported by SHPWriteObject().
537 0 : return OGRERR_FAILURE;
538 : }
539 : }
540 :
541 : /* ==================================================================== */
542 : /* Write point geometry. */
543 : /* ==================================================================== */
544 76220 : else if (hSHP->nShapeType == SHPT_POINT ||
545 75460 : hSHP->nShapeType == SHPT_POINTM || hSHP->nShapeType == SHPT_POINTZ)
546 : {
547 44708 : if (wkbFlatten(poGeom->getGeometryType()) != wkbPoint)
548 : {
549 8 : CPLError(CE_Failure, CPLE_AppDefined,
550 : "Attempt to write non-point (%s) geometry to"
551 : " point shapefile.",
552 8 : poGeom->getGeometryName());
553 :
554 9 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
555 : }
556 :
557 44700 : const OGRPoint *poPoint = poGeom->toPoint();
558 44700 : const double dfX = poPoint->getX();
559 44700 : const double dfY = poPoint->getY();
560 44700 : const double dfZ = poPoint->getZ();
561 44700 : double dfM = -std::numeric_limits<double>::max();
562 44700 : double *pdfM = nullptr;
563 44705 : if (wkbHasM(eLayerGeomType) && (hSHP->nShapeType == SHPT_POINTM ||
564 5 : hSHP->nShapeType == SHPT_POINTZ))
565 : {
566 10 : if (poGeom->IsMeasured())
567 10 : dfM = poPoint->getM();
568 10 : pdfM = &dfM;
569 : }
570 89400 : if ((!std::isfinite(dfX) || !std::isfinite(dfY) ||
571 89401 : !std::isfinite(dfZ) || (pdfM && !std::isfinite(*pdfM))) &&
572 1 : !CPLTestBool(CPLGetConfigOption(
573 : "OGR_SHAPE_ALLOW_NON_FINITE_COORDINATES", "NO")))
574 : {
575 1 : CPLError(CE_Failure, CPLE_NotSupported,
576 : "Coordinates with non-finite values are not allowed");
577 1 : return OGRERR_FAILURE;
578 : }
579 : SHPObject *psShape =
580 44699 : SHPCreateObject(hSHP->nShapeType, -1, 0, nullptr, nullptr, 1, &dfX,
581 : &dfY, &dfZ, pdfM);
582 44699 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
583 44699 : SHPDestroyObject(psShape);
584 44699 : if (nReturnedShapeID == -1)
585 44699 : return OGRERR_FAILURE;
586 : }
587 : /* ==================================================================== */
588 : /* MultiPoint. */
589 : /* ==================================================================== */
590 31512 : else if (hSHP->nShapeType == SHPT_MULTIPOINT ||
591 31498 : hSHP->nShapeType == SHPT_MULTIPOINTM ||
592 31495 : hSHP->nShapeType == SHPT_MULTIPOINTZ)
593 : {
594 31 : if (wkbFlatten(poGeom->getGeometryType()) != wkbMultiPoint)
595 : {
596 8 : CPLError(CE_Failure, CPLE_AppDefined,
597 : "Attempt to write non-multipoint (%s) geometry to "
598 : "multipoint shapefile.",
599 8 : poGeom->getGeometryName());
600 :
601 8 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
602 : }
603 :
604 23 : const OGRMultiPoint *poMP = poGeom->toMultiPoint();
605 23 : const int nNumGeometries = poMP->getNumGeometries();
606 43 : const bool bHasZ = (hSHP->nShapeType == SHPT_MULTIPOINTM ||
607 20 : hSHP->nShapeType == SHPT_MULTIPOINTZ);
608 23 : const bool bHasM = wkbHasM(eLayerGeomType) && bHasZ;
609 23 : const bool bIsGeomMeasured = CPL_TO_BOOL(poGeom->IsMeasured());
610 :
611 23 : std::vector<double> adfX;
612 23 : std::vector<double> adfY;
613 23 : std::vector<double> adfZ;
614 23 : std::vector<double> adfM;
615 : try
616 : {
617 23 : adfX.reserve(nNumGeometries);
618 23 : adfY.reserve(nNumGeometries);
619 23 : if (bHasZ)
620 14 : adfZ.reserve(nNumGeometries);
621 23 : if (bHasM)
622 6 : adfM.reserve(nNumGeometries);
623 : }
624 0 : catch (const std::exception &e)
625 : {
626 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
627 0 : return OGRERR_FAILURE;
628 : }
629 :
630 57 : for (const OGRPoint *poPoint : *poMP)
631 : {
632 : // Ignore POINT EMPTY.
633 34 : if (!poPoint->IsEmpty())
634 : {
635 33 : adfX.push_back(poPoint->getX());
636 33 : adfY.push_back(poPoint->getY());
637 33 : if (bHasZ)
638 20 : adfZ.push_back(poPoint->getZ());
639 33 : if (bHasM)
640 : {
641 8 : if (bIsGeomMeasured)
642 8 : adfM.push_back(poPoint->getM());
643 : else
644 0 : adfM.push_back(-std::numeric_limits<double>::max());
645 : }
646 : }
647 : else
648 : {
649 1 : CPLDebug("OGR",
650 : "Ignored POINT EMPTY inside MULTIPOINT in shapefile "
651 : "writer.");
652 : }
653 : }
654 23 : if (!CheckNonFiniteCoordinates(adfX) ||
655 23 : !CheckNonFiniteCoordinates(adfY) ||
656 69 : !CheckNonFiniteCoordinates(adfZ) ||
657 23 : !CheckNonFiniteCoordinates(adfM))
658 : {
659 0 : return OGRERR_FAILURE;
660 : }
661 :
662 52 : SHPObject *psShape = SHPCreateObject(
663 : hSHP->nShapeType, -1, 0, nullptr, nullptr,
664 23 : static_cast<int>(adfX.size()), adfX.data(), adfY.data(),
665 20 : bHasZ ? adfZ.data() : nullptr, bHasM ? adfM.data() : nullptr);
666 23 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
667 23 : SHPDestroyObject(psShape);
668 :
669 23 : if (nReturnedShapeID == -1)
670 23 : return OGRERR_FAILURE;
671 : }
672 :
673 : /* ==================================================================== */
674 : /* Arcs */
675 : /* ==================================================================== */
676 31481 : else if (hSHP->nShapeType == SHPT_ARC || hSHP->nShapeType == SHPT_ARCM ||
677 15209 : hSHP->nShapeType == SHPT_ARCZ)
678 : {
679 0 : std::unique_ptr<OGRGeometry> poGeomToDelete; // keep in that scope
680 18160 : const OGRMultiLineString *poML = nullptr;
681 18160 : OGRMultiLineString oMLFromLineString;
682 18160 : const auto eFlatGeomType = wkbFlatten(poGeom->getGeometryType());
683 18160 : if (eFlatGeomType == wkbMultiLineString)
684 : {
685 27 : poML = poGeom->toMultiLineString();
686 : }
687 18133 : else if (eFlatGeomType == wkbLineString)
688 : {
689 : // Borrow the geometry
690 18116 : oMLFromLineString.addGeometryDirectly(
691 18116 : const_cast<OGRLineString *>(poGeom->toLineString()));
692 18116 : poML = &oMLFromLineString;
693 : }
694 : else
695 : {
696 34 : poGeomToDelete = std::unique_ptr<OGRGeometry>(
697 34 : OGRGeometryFactory::forceToMultiLineString(poGeom->clone()));
698 17 : if (wkbFlatten(poGeomToDelete->getGeometryType()) !=
699 : wkbMultiLineString)
700 : {
701 13 : CPLError(CE_Failure, CPLE_AppDefined,
702 : "Attempt to write non-linestring (%s) geometry to "
703 : "ARC type shapefile.",
704 13 : poGeom->getGeometryName());
705 :
706 13 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
707 : }
708 4 : poML = poGeomToDelete->toMultiLineString();
709 : }
710 :
711 18147 : const int nNumGeometries = poML->getNumGeometries();
712 :
713 18147 : int nTotalPoints = 0;
714 36313 : for (const auto poArc : poML)
715 : {
716 18166 : const int nNumPoints = poArc->getNumPoints();
717 18166 : if (nTotalPoints > std::numeric_limits<int>::max() - nNumPoints)
718 : {
719 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too big geometry");
720 0 : return OGRERR_FAILURE;
721 : }
722 18166 : nTotalPoints += nNumPoints;
723 : }
724 :
725 18147 : std::vector<int> anRingStart;
726 18147 : std::vector<double> adfX;
727 18147 : std::vector<double> adfY;
728 18147 : std::vector<double> adfZ;
729 18147 : std::vector<double> adfM;
730 18147 : const bool bHasZ =
731 18147 : (hSHP->nShapeType == SHPT_ARCM || hSHP->nShapeType == SHPT_ARCZ);
732 18147 : const bool bHasM = wkbHasM(eLayerGeomType) && bHasZ;
733 18147 : const bool bIsGeomMeasured = CPL_TO_BOOL(poGeom->IsMeasured());
734 :
735 : try
736 : {
737 18147 : anRingStart.reserve(nNumGeometries);
738 :
739 18147 : adfX.reserve(nTotalPoints);
740 18147 : adfY.reserve(nTotalPoints);
741 18147 : if (bHasZ)
742 : {
743 1889 : adfZ.reserve(nTotalPoints);
744 : }
745 18147 : if (bHasM)
746 : {
747 10 : adfM.reserve(nTotalPoints);
748 : }
749 : }
750 0 : catch (const std::exception &e)
751 : {
752 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
753 : // Give back the borrowed line string
754 0 : if (eFlatGeomType == wkbLineString)
755 0 : oMLFromLineString.removeGeometry(0, /* bDelete=*/false);
756 0 : return OGRERR_FAILURE;
757 : }
758 :
759 36313 : for (const auto poArc : poML)
760 : {
761 18166 : const int nNumPoints = poArc->getNumPoints();
762 :
763 : // Ignore LINESTRING EMPTY.
764 18166 : if (nNumPoints == 0)
765 : {
766 1 : CPLDebug("OGR",
767 : "Ignore LINESTRING EMPTY inside MULTILINESTRING in "
768 : "shapefile writer.");
769 1 : continue;
770 : }
771 :
772 18165 : anRingStart.push_back(static_cast<int>(adfX.size()));
773 :
774 117936 : for (int iPoint = 0; iPoint < nNumPoints; iPoint++)
775 : {
776 99771 : adfX.push_back(poArc->getX(iPoint));
777 99771 : adfY.push_back(poArc->getY(iPoint));
778 99771 : if (bHasZ)
779 : {
780 49829 : adfZ.push_back(poArc->getZ(iPoint));
781 : }
782 99771 : if (bHasM)
783 : {
784 28 : if (bIsGeomMeasured)
785 28 : adfM.push_back(poArc->getM(iPoint));
786 : else
787 0 : adfM.push_back(-std::numeric_limits<double>::max());
788 : }
789 : }
790 : }
791 :
792 : // Give back the borrowed line string
793 18147 : if (eFlatGeomType == wkbLineString)
794 18116 : oMLFromLineString.removeGeometry(0, /* bDelete=*/false);
795 :
796 18147 : if (!CheckNonFiniteCoordinates(adfX) ||
797 18147 : !CheckNonFiniteCoordinates(adfY) ||
798 54439 : !CheckNonFiniteCoordinates(adfZ) ||
799 18145 : !CheckNonFiniteCoordinates(adfM))
800 : {
801 2 : return OGRERR_FAILURE;
802 : }
803 :
804 36300 : SHPObject *psShape = SHPCreateObject(
805 18145 : hSHP->nShapeType, iShape, static_cast<int>(anRingStart.size()),
806 18145 : anRingStart.data(), nullptr, static_cast<int>(adfX.size()),
807 18145 : adfX.data(), adfY.data(), bHasZ ? adfZ.data() : nullptr,
808 10 : bHasM ? adfM.data() : nullptr);
809 18145 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
810 18145 : SHPDestroyObject(psShape);
811 :
812 18145 : if (nReturnedShapeID == -1)
813 18145 : return OGRERR_FAILURE;
814 : }
815 :
816 : /* ==================================================================== */
817 : /* Polygons/MultiPolygons */
818 : /* ==================================================================== */
819 13321 : else if (hSHP->nShapeType == SHPT_POLYGON ||
820 100 : hSHP->nShapeType == SHPT_POLYGONM ||
821 95 : hSHP->nShapeType == SHPT_POLYGONZ)
822 : {
823 : // bool = true means outer ring
824 13308 : std::vector<std::pair<const OGRLinearRing *, bool>> apoRings;
825 13308 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
826 0 : std::unique_ptr<OGRGeometry> poGeomToDelete;
827 :
828 13308 : if (eType == wkbPolygon || eType == wkbTriangle)
829 : {
830 13201 : const OGRPolygon *poPoly = poGeom->toPolygon();
831 :
832 26402 : if (poPoly->getExteriorRing() == nullptr ||
833 13201 : poPoly->getExteriorRing()->IsEmpty())
834 : {
835 1 : CPLDebug("OGR", "Ignore POLYGON EMPTY in shapefile writer.");
836 : }
837 : else
838 : {
839 13200 : const int nSrcRings = poPoly->getNumInteriorRings() + 1;
840 13200 : apoRings.reserve(nSrcRings);
841 13200 : bool bFirstRing = true;
842 26411 : for (const auto poRing : poPoly)
843 : {
844 13211 : const int nNumPoints = poRing->getNumPoints();
845 :
846 : // Ignore LINEARRING EMPTY.
847 13211 : if (nNumPoints != 0)
848 : {
849 13210 : apoRings.push_back(std::make_pair(poRing, bFirstRing));
850 : }
851 : else
852 : {
853 1 : CPLDebug("OGR",
854 : "Ignore LINEARRING EMPTY inside POLYGON in "
855 : "shapefile writer.");
856 : }
857 13211 : bFirstRing = false;
858 : }
859 13201 : }
860 : }
861 107 : else if (eType == wkbMultiPolygon || eType == wkbGeometryCollection ||
862 14 : eType == wkbPolyhedralSurface || eType == wkbTIN)
863 : {
864 : const OGRGeometryCollection *poGC;
865 : // for PolyhedralSurface and TIN
866 93 : if (eType == wkbPolyhedralSurface || eType == wkbTIN)
867 : {
868 : poGeomToDelete =
869 0 : std::unique_ptr<OGRGeometry>(OGRGeometryFactory::forceTo(
870 0 : poGeom->clone(), wkbMultiPolygon, nullptr));
871 0 : poGC = poGeomToDelete->toGeometryCollection();
872 : }
873 :
874 : else
875 93 : poGC = poGeom->toGeometryCollection();
876 :
877 : // Shouldn't happen really, but to please x86_64-w64-mingw32-g++ -O2
878 : // -Wnull-dereference
879 93 : if (poGC == nullptr)
880 3 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
881 :
882 224 : for (const auto poSubGeom : poGC)
883 : {
884 134 : if (wkbFlatten(poSubGeom->getGeometryType()) != wkbPolygon)
885 : {
886 3 : CPLError(CE_Failure, CPLE_AppDefined,
887 : "Attempt to write non-polygon (%s) geometry to "
888 : "POLYGON type shapefile.",
889 3 : poSubGeom->getGeometryName());
890 :
891 3 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
892 : }
893 131 : const OGRPolygon *poPoly = poSubGeom->toPolygon();
894 :
895 : // Ignore POLYGON EMPTY.
896 261 : if (poPoly->getExteriorRing() == nullptr ||
897 130 : poPoly->getExteriorRing()->IsEmpty())
898 : {
899 1 : CPLDebug("OGR",
900 : "Ignore POLYGON EMPTY inside MULTIPOLYGON in "
901 : "shapefile writer.");
902 1 : continue;
903 : }
904 :
905 130 : const int nNumInteriorRings = poPoly->getNumInteriorRings();
906 : // to avoid coverity scan warning: "To avoid a quadratic time
907 : // penalty when using reserve(), always increase the capacity
908 : /// by a multiple of its current value"
909 130 : if (apoRings.size() + nNumInteriorRings + 1 >
910 253 : apoRings.capacity() &&
911 123 : apoRings.size() < std::numeric_limits<size_t>::max() / 2)
912 : {
913 123 : apoRings.reserve(std::max(
914 123 : 2 * apoRings.size(), apoRings.size() + apoRings.size() +
915 246 : nNumInteriorRings + 1));
916 : }
917 130 : bool bFirstRing = true;
918 308 : for (const auto poRing : poPoly)
919 : {
920 178 : const int nNumPoints = poRing->getNumPoints();
921 :
922 : // Ignore LINEARRING EMPTY.
923 178 : if (nNumPoints != 0)
924 : {
925 177 : apoRings.push_back(std::make_pair(poRing, bFirstRing));
926 : }
927 : else
928 : {
929 1 : CPLDebug("OGR",
930 : "Ignore LINEARRING EMPTY inside POLYGON in "
931 : "shapefile writer.");
932 : }
933 178 : bFirstRing = false;
934 : }
935 90 : }
936 : }
937 : else
938 : {
939 14 : CPLError(CE_Failure, CPLE_AppDefined,
940 : "Attempt to write non-polygon (%s) geometry to "
941 : "POLYGON type shapefile.",
942 14 : poGeom->getGeometryName());
943 :
944 14 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
945 : }
946 :
947 : /* --------------------------------------------------------------------
948 : */
949 : /* If we only had emptypolygons or unacceptable geometries */
950 : /* write NULL geometry object. */
951 : /* --------------------------------------------------------------------
952 : */
953 13291 : if (apoRings.empty())
954 : {
955 : SHPObject *psShape =
956 1 : SHPCreateObject(SHPT_NULL, -1, 0, nullptr, nullptr, 0, nullptr,
957 : nullptr, nullptr, nullptr);
958 1 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
959 1 : SHPDestroyObject(psShape);
960 :
961 1 : if (nReturnedShapeID == -1)
962 0 : return OGRERR_FAILURE;
963 :
964 1 : return OGRERR_NONE;
965 : }
966 :
967 : // Count vertices.
968 13290 : int nVertex = 0;
969 26677 : for (const auto &ring : apoRings)
970 13387 : nVertex += ring.first->getNumPoints();
971 :
972 26575 : const bool bHasZ = (hSHP->nShapeType == SHPT_POLYGONM ||
973 13285 : hSHP->nShapeType == SHPT_POLYGONZ);
974 13290 : const bool bHasM = wkbHasM(eLayerGeomType) && bHasZ;
975 13290 : const bool bIsGeomMeasured = CPL_TO_BOOL(poGeom->IsMeasured());
976 :
977 13290 : std::vector<int> anRingStart;
978 13290 : std::vector<double> adfX;
979 13290 : std::vector<double> adfY;
980 13290 : std::vector<double> adfZ;
981 13290 : std::vector<double> adfM;
982 : try
983 : {
984 13290 : anRingStart.reserve(apoRings.size());
985 13290 : adfX.reserve(nVertex);
986 13290 : adfY.reserve(nVertex);
987 13290 : if (bHasZ)
988 81 : adfZ.reserve(nVertex);
989 13290 : if (bHasM)
990 10 : adfM.reserve(nVertex);
991 : }
992 0 : catch (const std::exception &e)
993 : {
994 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
995 0 : return OGRERR_FAILURE;
996 : }
997 :
998 : // Collect vertices.
999 26677 : for (const auto &ring : apoRings)
1000 : {
1001 13387 : const auto poRing = ring.first;
1002 13387 : const bool bIsOuterRing = ring.second;
1003 13387 : anRingStart.push_back(static_cast<int>(adfX.size()));
1004 :
1005 13387 : const int nNumPoints = poRing->getNumPoints();
1006 : // Exterior ring must be clockwise oriented in shapefiles
1007 : const bool bInvertOrder =
1008 13444 : !bRewind && CPL_TO_BOOL(bIsOuterRing ? !poRing->isClockwise()
1009 57 : : poRing->isClockwise());
1010 112804 : for (int i = 0; i < nNumPoints; i++)
1011 : {
1012 99417 : const int iPoint = bInvertOrder ? nNumPoints - 1 - i : i;
1013 99417 : adfX.push_back(poRing->getX(iPoint));
1014 99417 : adfY.push_back(poRing->getY(iPoint));
1015 99417 : if (bHasZ)
1016 1461 : adfZ.push_back(poRing->getZ(iPoint));
1017 99417 : if (bHasM)
1018 : {
1019 56 : adfM.push_back(bIsGeomMeasured
1020 56 : ? poRing->getM(iPoint)
1021 0 : : -std::numeric_limits<double>::max());
1022 : }
1023 : }
1024 : }
1025 13290 : if (!CheckNonFiniteCoordinates(adfX) ||
1026 13290 : !CheckNonFiniteCoordinates(adfY) ||
1027 39868 : !CheckNonFiniteCoordinates(adfZ) ||
1028 13288 : !CheckNonFiniteCoordinates(adfM))
1029 : {
1030 2 : return OGRERR_FAILURE;
1031 : }
1032 :
1033 26586 : SHPObject *psShape = SHPCreateObject(
1034 13288 : hSHP->nShapeType, iShape, static_cast<int>(anRingStart.size()),
1035 13288 : anRingStart.data(), nullptr, static_cast<int>(adfX.size()),
1036 13288 : adfX.data(), adfY.data(), bHasZ ? adfZ.data() : nullptr,
1037 10 : bHasM ? adfM.data() : nullptr);
1038 13288 : if (bRewind)
1039 0 : SHPRewindObject(hSHP, psShape);
1040 13288 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
1041 13288 : SHPDestroyObject(psShape);
1042 :
1043 13288 : if (nReturnedShapeID == -1)
1044 13288 : return OGRERR_FAILURE;
1045 : }
1046 :
1047 : /* ==================================================================== */
1048 : /* Multipatch */
1049 : /* ==================================================================== */
1050 13 : else if (hSHP->nShapeType == SHPT_MULTIPATCH)
1051 : {
1052 13 : int nParts = 0;
1053 13 : std::vector<int> anPartStart;
1054 13 : std::vector<int> anPartType;
1055 13 : int nPoints = 0;
1056 13 : std::vector<OGRRawPoint> aoPoints;
1057 13 : std::vector<double> adfZ;
1058 13 : OGRErr eErr = OGRCreateMultiPatch(poGeom,
1059 : FALSE, // no SHPP_TRIANGLES
1060 : nParts, anPartStart, anPartType,
1061 : nPoints, aoPoints, adfZ);
1062 13 : if (eErr != OGRERR_NONE)
1063 1 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1064 :
1065 12 : std::vector<double> adfX(nPoints);
1066 12 : std::vector<double> adfY(nPoints);
1067 64 : for (int i = 0; i < nPoints; ++i)
1068 : {
1069 52 : adfX[i] = aoPoints[i].x;
1070 52 : adfY[i] = aoPoints[i].y;
1071 : }
1072 :
1073 12 : if (!CheckNonFiniteCoordinates(adfX.data(), nPoints) ||
1074 24 : !CheckNonFiniteCoordinates(adfY.data(), nPoints) ||
1075 12 : !CheckNonFiniteCoordinates(adfZ.data(), nPoints))
1076 : {
1077 0 : return OGRERR_FAILURE;
1078 : }
1079 :
1080 : SHPObject *psShape =
1081 12 : SHPCreateObject(hSHP->nShapeType, iShape, nParts,
1082 12 : anPartStart.data(), anPartType.data(), nPoints,
1083 12 : adfX.data(), adfY.data(), adfZ.data(), nullptr);
1084 12 : if (bRewind)
1085 5 : SHPRewindObject(hSHP, psShape);
1086 12 : const int nReturnedShapeID = SHPWriteObject(hSHP, iShape, psShape);
1087 12 : SHPDestroyObject(psShape);
1088 :
1089 12 : if (nReturnedShapeID == -1)
1090 0 : return OGRERR_FAILURE;
1091 : }
1092 :
1093 : else
1094 : {
1095 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1096 : }
1097 :
1098 76782 : return OGRERR_NONE;
1099 : }
1100 :
1101 : /************************************************************************/
1102 : /* SHPReadOGRFeatureDefn() */
1103 : /************************************************************************/
1104 :
1105 5010 : OGRFeatureDefn *SHPReadOGRFeatureDefn(const char *pszName, SHPHandle hSHP,
1106 : DBFHandle hDBF,
1107 : const char *pszSHPEncoding,
1108 : int bAdjustType)
1109 :
1110 : {
1111 5010 : int nAdjustableFields = 0;
1112 5010 : const int nFieldCount = hDBF ? DBFGetFieldCount(hDBF) : 0;
1113 :
1114 5010 : OGRFeatureDefn *const poDefn = new OGRFeatureDefn(pszName);
1115 5010 : poDefn->Reference();
1116 :
1117 11335 : for (int iField = 0; iField < nFieldCount; iField++)
1118 : {
1119 : // On reading we support up to 11 characters
1120 6325 : char szFieldName[XBASE_FLDNAME_LEN_READ + 1] = {};
1121 6325 : int nWidth = 0;
1122 6325 : int nPrecision = 0;
1123 : DBFFieldType eDBFType =
1124 6325 : DBFGetFieldInfo(hDBF, iField, szFieldName, &nWidth, &nPrecision);
1125 :
1126 12650 : OGRFieldDefn oField("", OFTInteger);
1127 6325 : if (strlen(pszSHPEncoding) > 0)
1128 : {
1129 : char *const pszUTF8Field =
1130 4287 : CPLRecode(szFieldName, pszSHPEncoding, CPL_ENC_UTF8);
1131 4287 : oField.SetName(pszUTF8Field);
1132 4287 : CPLFree(pszUTF8Field);
1133 : }
1134 : else
1135 : {
1136 2038 : oField.SetName(szFieldName);
1137 : }
1138 :
1139 6325 : oField.SetWidth(nWidth);
1140 6325 : oField.SetPrecision(nPrecision);
1141 :
1142 6325 : if (eDBFType == FTDate)
1143 : {
1144 : // Shapefile date has following 8-chars long format:
1145 : //
1146 : // 20060101.
1147 : //
1148 : // Split as YYYY/MM/DD, so 2 additional characters are required.
1149 60 : oField.SetWidth(nWidth + 2);
1150 60 : oField.SetType(OFTDate);
1151 : }
1152 6265 : else if (eDBFType == FTDouble)
1153 : {
1154 2316 : nAdjustableFields += (nPrecision == 0);
1155 2316 : if (nPrecision == 0 && nWidth < 19)
1156 1396 : oField.SetType(OFTInteger64);
1157 : else
1158 920 : oField.SetType(OFTReal);
1159 : }
1160 3949 : else if (eDBFType == FTInteger)
1161 844 : oField.SetType(OFTInteger);
1162 3105 : else if (eDBFType == FTLogical)
1163 : {
1164 1 : oField.SetType(OFTInteger);
1165 1 : oField.SetSubType(OFSTBoolean);
1166 : }
1167 : else
1168 3104 : oField.SetType(OFTString);
1169 :
1170 6325 : poDefn->AddFieldDefn(&oField);
1171 : }
1172 :
1173 : // Do an optional past if requested and needed to demote Integer64->Integer
1174 : // or Real->Integer64/Integer.
1175 5010 : if (nAdjustableFields && bAdjustType)
1176 : {
1177 : int *panAdjustableField =
1178 1 : static_cast<int *>(CPLCalloc(sizeof(int), nFieldCount));
1179 3 : for (int iField = 0; iField < nFieldCount; iField++)
1180 : {
1181 2 : OGRFieldType eType = poDefn->GetFieldDefn(iField)->GetType();
1182 3 : if (poDefn->GetFieldDefn(iField)->GetPrecision() == 0 &&
1183 1 : (eType == OFTInteger64 || eType == OFTReal))
1184 : {
1185 2 : panAdjustableField[iField] = TRUE;
1186 2 : poDefn->GetFieldDefn(iField)->SetType(OFTInteger);
1187 : }
1188 : }
1189 :
1190 1 : const int nRowCount = DBFGetRecordCount(hDBF);
1191 2 : for (int iRow = 0; iRow < nRowCount && nAdjustableFields; iRow++)
1192 : {
1193 3 : for (int iField = 0; iField < nFieldCount; iField++)
1194 : {
1195 2 : if (panAdjustableField[iField])
1196 : {
1197 : const char *pszValue =
1198 2 : DBFReadStringAttribute(hDBF, iRow, iField);
1199 2 : const int nValueLength = static_cast<int>(strlen(pszValue));
1200 2 : if (nValueLength >= 10)
1201 : {
1202 2 : int bOverflow = FALSE;
1203 : const GIntBig nVal =
1204 2 : CPLAtoGIntBigEx(pszValue, FALSE, &bOverflow);
1205 2 : if (bOverflow)
1206 : {
1207 0 : poDefn->GetFieldDefn(iField)->SetType(OFTReal);
1208 0 : panAdjustableField[iField] = FALSE;
1209 0 : nAdjustableFields--;
1210 : }
1211 2 : else if (!CPL_INT64_FITS_ON_INT32(nVal))
1212 : {
1213 1 : poDefn->GetFieldDefn(iField)->SetType(OFTInteger64);
1214 1 : if (poDefn->GetFieldDefn(iField)->GetWidth() <= 18)
1215 : {
1216 0 : panAdjustableField[iField] = FALSE;
1217 0 : nAdjustableFields--;
1218 : }
1219 : }
1220 : }
1221 : }
1222 : }
1223 : }
1224 :
1225 1 : CPLFree(panAdjustableField);
1226 : }
1227 :
1228 5010 : if (hSHP == nullptr)
1229 : {
1230 366 : poDefn->SetGeomType(wkbNone);
1231 : }
1232 : else
1233 : {
1234 4644 : switch (hSHP->nShapeType)
1235 : {
1236 1111 : case SHPT_POINT:
1237 1111 : poDefn->SetGeomType(wkbPoint);
1238 1111 : break;
1239 :
1240 70 : case SHPT_POINTZ:
1241 70 : poDefn->SetGeomType(wkbPointZM);
1242 70 : break;
1243 :
1244 9 : case SHPT_POINTM:
1245 9 : poDefn->SetGeomType(wkbPointM);
1246 9 : break;
1247 :
1248 2206 : case SHPT_ARC:
1249 2206 : poDefn->SetGeomType(wkbLineString);
1250 2206 : break;
1251 :
1252 88 : case SHPT_ARCZ:
1253 88 : poDefn->SetGeomType(wkbLineStringZM);
1254 88 : break;
1255 :
1256 12 : case SHPT_ARCM:
1257 12 : poDefn->SetGeomType(wkbLineStringM);
1258 12 : break;
1259 :
1260 61 : case SHPT_MULTIPOINT:
1261 61 : poDefn->SetGeomType(wkbMultiPoint);
1262 61 : break;
1263 :
1264 48 : case SHPT_MULTIPOINTZ:
1265 48 : poDefn->SetGeomType(wkbMultiPointZM);
1266 48 : break;
1267 :
1268 6 : case SHPT_MULTIPOINTM:
1269 6 : poDefn->SetGeomType(wkbMultiPointM);
1270 6 : break;
1271 :
1272 924 : case SHPT_POLYGON:
1273 924 : poDefn->SetGeomType(wkbPolygon);
1274 924 : break;
1275 :
1276 78 : case SHPT_POLYGONZ:
1277 78 : poDefn->SetGeomType(wkbPolygonZM);
1278 78 : break;
1279 :
1280 12 : case SHPT_POLYGONM:
1281 12 : poDefn->SetGeomType(wkbPolygonM);
1282 12 : break;
1283 :
1284 19 : case SHPT_MULTIPATCH:
1285 19 : poDefn->SetGeomType(wkbUnknown); // not ideal
1286 19 : break;
1287 : }
1288 : }
1289 :
1290 5010 : return poDefn;
1291 : }
1292 :
1293 : /************************************************************************/
1294 : /* SHPReadOGRFeature() */
1295 : /************************************************************************/
1296 :
1297 91657 : OGRFeature *SHPReadOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
1298 : OGRFeatureDefn *poDefn, int iShape,
1299 : SHPObject *psShape, const char *pszSHPEncoding,
1300 : bool &bHasWarnedWrongWindingOrder)
1301 :
1302 : {
1303 91657 : if (iShape < 0 || (hSHP != nullptr && iShape >= hSHP->nRecords) ||
1304 91600 : (hDBF != nullptr && iShape >= hDBF->nRecords))
1305 : {
1306 15 : CPLError(CE_Failure, CPLE_AppDefined,
1307 : "Attempt to read shape with feature id (%d) out of available"
1308 : " range.",
1309 : iShape);
1310 15 : return nullptr;
1311 : }
1312 :
1313 91642 : if (hDBF && DBFIsRecordDeleted(hDBF, iShape))
1314 : {
1315 2 : CPLError(CE_Failure, CPLE_AppDefined,
1316 : "Attempt to read shape with feature id (%d), "
1317 : "but it is marked deleted.",
1318 : iShape);
1319 2 : if (psShape != nullptr)
1320 0 : SHPDestroyObject(psShape);
1321 2 : return nullptr;
1322 : }
1323 :
1324 91640 : OGRFeature *poFeature = new OGRFeature(poDefn);
1325 :
1326 : /* -------------------------------------------------------------------- */
1327 : /* Fetch geometry from Shapefile to OGRFeature. */
1328 : /* -------------------------------------------------------------------- */
1329 91640 : if (hSHP != nullptr)
1330 : {
1331 87937 : if (!poDefn->IsGeometryIgnored())
1332 : {
1333 87211 : OGRGeometry *poGeometry = SHPReadOGRObject(
1334 : hSHP, iShape, psShape, bHasWarnedWrongWindingOrder);
1335 :
1336 : // Two possibilities are expected here (both are tested by
1337 : // GDAL Autotests):
1338 : // 1. Read valid geometry and assign it directly.
1339 : // 2. Read and assign null geometry if it can not be read
1340 : // correctly from a shapefile.
1341 : //
1342 : // It is NOT required here to test poGeometry == NULL.
1343 :
1344 87211 : if (poGeometry)
1345 : {
1346 : // Set/unset flags.
1347 : const OGRwkbGeometryType eMyGeomType =
1348 86497 : poFeature->GetDefnRef()->GetGeomFieldDefn(0)->GetType();
1349 :
1350 86497 : if (eMyGeomType != wkbUnknown)
1351 : {
1352 : OGRwkbGeometryType eGeomInType =
1353 86485 : poGeometry->getGeometryType();
1354 86485 : if (wkbHasZ(eMyGeomType) && !wkbHasZ(eGeomInType))
1355 : {
1356 0 : poGeometry->set3D(TRUE);
1357 : }
1358 86485 : else if (!wkbHasZ(eMyGeomType) && wkbHasZ(eGeomInType))
1359 : {
1360 0 : poGeometry->set3D(FALSE);
1361 : }
1362 86485 : if (wkbHasM(eMyGeomType) && !wkbHasM(eGeomInType))
1363 : {
1364 0 : poGeometry->setMeasured(TRUE);
1365 : }
1366 86485 : else if (!wkbHasM(eMyGeomType) && wkbHasM(eGeomInType))
1367 : {
1368 1 : poGeometry->setMeasured(FALSE);
1369 : }
1370 : }
1371 : }
1372 :
1373 87211 : poFeature->SetGeometryDirectly(poGeometry);
1374 : }
1375 726 : else if (psShape != nullptr)
1376 : {
1377 10 : SHPDestroyObject(psShape);
1378 : }
1379 : }
1380 :
1381 : /* -------------------------------------------------------------------- */
1382 : /* Fetch feature attributes to OGRFeature fields. */
1383 : /* -------------------------------------------------------------------- */
1384 :
1385 219033 : for (int iField = 0; hDBF != nullptr && iField < poDefn->GetFieldCount();
1386 : iField++)
1387 : {
1388 127393 : const OGRFieldDefn *const poFieldDefn = poDefn->GetFieldDefn(iField);
1389 127393 : if (poFieldDefn->IsIgnored())
1390 1848 : continue;
1391 :
1392 125545 : switch (poFieldDefn->GetType())
1393 : {
1394 10467 : case OFTString:
1395 : {
1396 : const char *const pszFieldVal =
1397 10467 : DBFReadStringAttribute(hDBF, iShape, iField);
1398 10467 : if (pszFieldVal != nullptr && pszFieldVal[0] != '\0')
1399 : {
1400 8984 : if (pszSHPEncoding[0] != '\0')
1401 : {
1402 3995 : char *const pszUTF8Field = CPLRecode(
1403 : pszFieldVal, pszSHPEncoding, CPL_ENC_UTF8);
1404 3995 : poFeature->SetField(iField, pszUTF8Field);
1405 3995 : CPLFree(pszUTF8Field);
1406 : }
1407 : else
1408 8984 : poFeature->SetField(iField, pszFieldVal);
1409 : }
1410 : else
1411 : {
1412 1483 : poFeature->SetFieldNull(iField);
1413 : }
1414 10467 : break;
1415 : }
1416 115040 : case OFTInteger:
1417 : case OFTInteger64:
1418 : case OFTReal:
1419 : {
1420 115040 : if (DBFIsAttributeNULL(hDBF, iShape, iField))
1421 : {
1422 69 : poFeature->SetFieldNull(iField);
1423 : }
1424 : else
1425 : {
1426 114971 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1427 : {
1428 : const char *pszVal =
1429 2 : DBFReadLogicalAttribute(hDBF, iShape, iField);
1430 2 : poFeature->SetField(
1431 2 : iField, pszVal[0] == 'T' || pszVal[0] == 't' ||
1432 1 : pszVal[0] == 'Y' || pszVal[0] == 'y'
1433 : ? 1
1434 : : 0);
1435 : }
1436 : else
1437 : {
1438 : const char *pszVal =
1439 114969 : DBFReadStringAttribute(hDBF, iShape, iField);
1440 114969 : poFeature->SetField(iField, pszVal);
1441 : }
1442 : }
1443 115040 : break;
1444 : }
1445 38 : case OFTDate:
1446 : {
1447 38 : if (DBFIsAttributeNULL(hDBF, iShape, iField))
1448 : {
1449 29 : poFeature->SetFieldNull(iField);
1450 29 : continue;
1451 : }
1452 :
1453 : const char *const pszDateValue =
1454 9 : DBFReadStringAttribute(hDBF, iShape, iField);
1455 :
1456 : OGRField sFld;
1457 9 : memset(&sFld, 0, sizeof(sFld));
1458 :
1459 9 : if (strlen(pszDateValue) >= 10 && pszDateValue[2] == '/' &&
1460 1 : pszDateValue[5] == '/')
1461 : {
1462 1 : sFld.Date.Month =
1463 1 : static_cast<GByte>(atoi(pszDateValue + 0));
1464 1 : sFld.Date.Day = static_cast<GByte>(atoi(pszDateValue + 3));
1465 1 : sFld.Date.Year =
1466 1 : static_cast<GInt16>(atoi(pszDateValue + 6));
1467 : }
1468 : else
1469 : {
1470 8 : const int nFullDate = atoi(pszDateValue);
1471 8 : sFld.Date.Year = static_cast<GInt16>(nFullDate / 10000);
1472 8 : sFld.Date.Month =
1473 8 : static_cast<GByte>((nFullDate / 100) % 100);
1474 8 : sFld.Date.Day = static_cast<GByte>(nFullDate % 100);
1475 : }
1476 :
1477 9 : poFeature->SetField(iField, &sFld);
1478 : }
1479 9 : break;
1480 :
1481 0 : default:
1482 0 : CPLAssert(false);
1483 : }
1484 : }
1485 :
1486 91640 : if (poFeature != nullptr)
1487 91640 : poFeature->SetFID(iShape);
1488 :
1489 91640 : return poFeature;
1490 : }
1491 :
1492 : /************************************************************************/
1493 : /* GrowField() */
1494 : /************************************************************************/
1495 :
1496 6 : static OGRErr GrowField(DBFHandle hDBF, int iField, OGRFieldDefn *poFieldDefn,
1497 : int nNewSize)
1498 : {
1499 6 : char szFieldName[20] = {};
1500 6 : int nOriWidth = 0;
1501 6 : int nPrecision = 0;
1502 6 : DBFGetFieldInfo(hDBF, iField, szFieldName, &nOriWidth, &nPrecision);
1503 :
1504 6 : CPLDebug("SHAPE", "Extending field %d (%s) from %d to %d characters",
1505 : iField, poFieldDefn->GetNameRef(), nOriWidth, nNewSize);
1506 :
1507 6 : const char chNativeType = DBFGetNativeFieldType(hDBF, iField);
1508 6 : if (!DBFAlterFieldDefn(hDBF, iField, szFieldName, chNativeType, nNewSize,
1509 : nPrecision))
1510 : {
1511 0 : CPLError(CE_Failure, CPLE_AppDefined,
1512 : "Extending field %d (%s) from %d to %d characters failed",
1513 : iField, poFieldDefn->GetNameRef(), nOriWidth, nNewSize);
1514 0 : return OGRERR_FAILURE;
1515 : }
1516 :
1517 6 : auto oTemporaryUnsealer(poFieldDefn->GetTemporaryUnsealer());
1518 6 : poFieldDefn->SetWidth(nNewSize);
1519 6 : return OGRERR_NONE;
1520 : }
1521 :
1522 : /************************************************************************/
1523 : /* SHPWriteOGRFeature() */
1524 : /* */
1525 : /* Write to an existing feature in a shapefile, or create a new */
1526 : /* feature. */
1527 : /************************************************************************/
1528 :
1529 77304 : OGRErr SHPWriteOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
1530 : OGRFeatureDefn *poDefn, OGRFeature *poFeature,
1531 : const char *pszSHPEncoding,
1532 : bool *pbTruncationWarningEmitted, bool bRewind)
1533 :
1534 : {
1535 : /* -------------------------------------------------------------------- */
1536 : /* Write the geometry. */
1537 : /* -------------------------------------------------------------------- */
1538 77304 : if (hSHP != nullptr)
1539 : {
1540 76835 : const OGRErr eErr = SHPWriteOGRObject(
1541 76835 : hSHP, static_cast<int>(poFeature->GetFID()),
1542 76835 : poFeature->GetGeometryRef(), bRewind, poDefn->GetGeomType());
1543 76835 : if (eErr != OGRERR_NONE)
1544 52 : return eErr;
1545 : }
1546 :
1547 : /* -------------------------------------------------------------------- */
1548 : /* If there is no DBF, the job is done now. */
1549 : /* -------------------------------------------------------------------- */
1550 77252 : if (hDBF == nullptr)
1551 : {
1552 : /* --------------------------------------------------------------------
1553 : */
1554 : /* If this is a new feature, establish its feature id. */
1555 : /* --------------------------------------------------------------------
1556 : */
1557 15 : if (hSHP != nullptr && poFeature->GetFID() == OGRNullFID)
1558 1 : poFeature->SetFID(hSHP->nRecords - 1);
1559 :
1560 15 : return OGRERR_NONE;
1561 : }
1562 :
1563 : /* -------------------------------------------------------------------- */
1564 : /* If this is a new feature, establish its feature id. */
1565 : /* -------------------------------------------------------------------- */
1566 77237 : if (poFeature->GetFID() == OGRNullFID)
1567 77195 : poFeature->SetFID(DBFGetRecordCount(hDBF));
1568 :
1569 : /* -------------------------------------------------------------------- */
1570 : /* If this is the first feature to be written, verify that we */
1571 : /* have at least one attribute in the DBF file. If not, create */
1572 : /* a dummy FID attribute to satisfy the requirement that there */
1573 : /* be at least one attribute. */
1574 : /* -------------------------------------------------------------------- */
1575 77237 : if (DBFGetRecordCount(hDBF) == 0 && DBFGetFieldCount(hDBF) == 0)
1576 : {
1577 230 : CPLDebug(
1578 : "OGR",
1579 : "Created dummy FID field for shapefile since schema is empty.");
1580 230 : DBFAddField(hDBF, "FID", FTInteger, 11, 0);
1581 : }
1582 :
1583 : /* -------------------------------------------------------------------- */
1584 : /* Write out dummy field value if it exists. */
1585 : /* -------------------------------------------------------------------- */
1586 77237 : if (poDefn->GetFieldCount() == 0)
1587 : {
1588 56478 : if (DBFGetFieldCount(hDBF) == 1)
1589 : {
1590 56477 : DBFWriteIntegerAttribute(hDBF,
1591 56477 : static_cast<int>(poFeature->GetFID()), 0,
1592 56477 : static_cast<int>(poFeature->GetFID()));
1593 : }
1594 1 : else if (DBFGetFieldCount(hDBF) == 0)
1595 : {
1596 : // Far from being nominal... Could happen if deleting all fields
1597 : // of a DBF with rows
1598 1 : DBFWriteAttributeDirectly(
1599 1 : hDBF, static_cast<int>(poFeature->GetFID()), -1, nullptr);
1600 : }
1601 : }
1602 :
1603 : /* -------------------------------------------------------------------- */
1604 : /* Write all the fields. */
1605 : /* -------------------------------------------------------------------- */
1606 107407 : for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
1607 : {
1608 30170 : if (!poFeature->IsFieldSetAndNotNull(iField))
1609 : {
1610 588 : DBFWriteNULLAttribute(hDBF, static_cast<int>(poFeature->GetFID()),
1611 : iField);
1612 588 : continue;
1613 : }
1614 :
1615 29582 : OGRFieldDefn *const poFieldDefn = poDefn->GetFieldDefn(iField);
1616 :
1617 29582 : switch (poFieldDefn->GetType())
1618 : {
1619 4087 : case OFTString:
1620 : {
1621 4087 : const char *pszStr = poFeature->GetFieldAsString(iField);
1622 4087 : char *pszEncoded = nullptr;
1623 4087 : if (pszSHPEncoding[0] != '\0')
1624 : {
1625 : pszEncoded =
1626 4079 : CPLRecode(pszStr, CPL_ENC_UTF8, pszSHPEncoding);
1627 4079 : pszStr = pszEncoded;
1628 : }
1629 :
1630 4087 : int nStrLen = static_cast<int>(strlen(pszStr));
1631 4087 : if (nStrLen > OGR_DBF_MAX_FIELD_WIDTH)
1632 : {
1633 3 : if (!(*pbTruncationWarningEmitted))
1634 : {
1635 2 : *pbTruncationWarningEmitted = true;
1636 2 : CPLError(
1637 : CE_Warning, CPLE_AppDefined,
1638 : "Value '%s' of field %s has been truncated to %d "
1639 : "characters. This warning will not be emitted any "
1640 : "more for that layer.",
1641 : poFeature->GetFieldAsString(iField),
1642 : poFieldDefn->GetNameRef(), OGR_DBF_MAX_FIELD_WIDTH);
1643 : }
1644 :
1645 3 : nStrLen = OGR_DBF_MAX_FIELD_WIDTH;
1646 :
1647 3 : if (pszEncoded != nullptr && // For Coverity.
1648 3 : EQUAL(pszSHPEncoding, CPL_ENC_UTF8))
1649 : {
1650 : // Truncate string by making sure we don't cut in the
1651 : // middle of a UTF-8 multibyte character
1652 : // Continuation bytes of such characters are of the form
1653 : // 10xxxxxx (0x80), whereas single-byte are 0xxxxxxx
1654 : // and the start of a multi-byte is 11xxxxxx
1655 2 : const char *p = pszStr + nStrLen;
1656 2 : while (nStrLen > 0)
1657 : {
1658 2 : if ((*p & 0xc0) != 0x80)
1659 : {
1660 2 : break;
1661 : }
1662 :
1663 0 : nStrLen--;
1664 0 : p--;
1665 : }
1666 :
1667 2 : pszEncoded[nStrLen] = 0;
1668 : }
1669 : }
1670 :
1671 4087 : if (nStrLen > poFieldDefn->GetWidth())
1672 : {
1673 2 : if (GrowField(hDBF, iField, poFieldDefn, nStrLen) !=
1674 : OGRERR_NONE)
1675 : {
1676 0 : CPLFree(pszEncoded);
1677 0 : return OGRERR_FAILURE;
1678 : }
1679 : }
1680 :
1681 4087 : DBFWriteStringAttribute(hDBF,
1682 4087 : static_cast<int>(poFeature->GetFID()),
1683 : iField, pszStr);
1684 :
1685 4087 : CPLFree(pszEncoded);
1686 4087 : break;
1687 : }
1688 24295 : case OFTInteger:
1689 : case OFTInteger64:
1690 : {
1691 24295 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1692 : {
1693 4 : DBFWriteAttributeDirectly(
1694 2 : hDBF, static_cast<int>(poFeature->GetFID()), iField,
1695 2 : poFeature->GetFieldAsInteger(iField) ? "T" : "F");
1696 : }
1697 : else
1698 : {
1699 24293 : char szValue[32] = {};
1700 24293 : const int nFieldWidth = poFieldDefn->GetWidth();
1701 24293 : snprintf(szValue, sizeof(szValue),
1702 : "%*" CPL_FRMT_GB_WITHOUT_PREFIX "d",
1703 : std::min(nFieldWidth,
1704 24293 : static_cast<int>(sizeof(szValue)) - 1),
1705 : poFeature->GetFieldAsInteger64(iField));
1706 :
1707 24293 : const int nStrLen = static_cast<int>(strlen(szValue));
1708 24293 : if (nStrLen > nFieldWidth)
1709 : {
1710 4 : if (GrowField(hDBF, iField, poFieldDefn, nStrLen) !=
1711 : OGRERR_NONE)
1712 : {
1713 0 : return OGRERR_FAILURE;
1714 : }
1715 : }
1716 :
1717 24293 : DBFWriteAttributeDirectly(
1718 24293 : hDBF, static_cast<int>(poFeature->GetFID()), iField,
1719 : szValue);
1720 : }
1721 :
1722 24295 : break;
1723 : }
1724 :
1725 1129 : case OFTReal:
1726 : {
1727 1129 : const double dfVal = poFeature->GetFieldAsDouble(iField);
1728 : // IEEE754 doubles can store exact values of all integers
1729 : // below 2^53.
1730 1131 : if (poFieldDefn->GetPrecision() == 0 &&
1731 2 : fabs(dfVal) > (static_cast<GIntBig>(1) << 53))
1732 : {
1733 : static int nCounter = 0;
1734 1 : if (nCounter <= 10)
1735 : {
1736 1 : CPLError(CE_Warning, CPLE_AppDefined,
1737 : "Value %.18g of field %s with 0 decimal of "
1738 : "feature " CPL_FRMT_GIB
1739 : " is bigger than 2^53. "
1740 : "Precision loss likely occurred or going to "
1741 : "happen.%s",
1742 : dfVal, poFieldDefn->GetNameRef(),
1743 : poFeature->GetFID(),
1744 1 : (nCounter == 10) ? " This warning will not be "
1745 : "emitted anymore."
1746 : : "");
1747 1 : nCounter++;
1748 : }
1749 : }
1750 1129 : int ret = DBFWriteDoubleAttribute(
1751 1129 : hDBF, static_cast<int>(poFeature->GetFID()), iField, dfVal);
1752 1129 : if (!ret)
1753 : {
1754 7 : CPLError(CE_Warning, CPLE_AppDefined,
1755 : "Value %.18g of field %s of feature " CPL_FRMT_GIB
1756 : " not "
1757 : "successfully written. Possibly due to too larger "
1758 : "number "
1759 : "with respect to field width",
1760 : dfVal, poFieldDefn->GetNameRef(),
1761 : poFeature->GetFID());
1762 : }
1763 1129 : break;
1764 : }
1765 71 : case OFTDate:
1766 : {
1767 : const OGRField *const psField =
1768 71 : poFeature->GetRawFieldRef(iField);
1769 :
1770 71 : if (psField->Date.Year < 0 || psField->Date.Year > 9999)
1771 : {
1772 0 : CPLError(
1773 : CE_Warning, CPLE_NotSupported,
1774 : "Year < 0 or > 9999 is not a valid date for shapefile");
1775 : }
1776 71 : else if (psField->Date.Year == 0 && psField->Date.Month == 0 &&
1777 0 : psField->Date.Day == 0)
1778 : {
1779 0 : DBFWriteNULLAttribute(
1780 0 : hDBF, static_cast<int>(poFeature->GetFID()), iField);
1781 : }
1782 : else
1783 : {
1784 71 : DBFWriteIntegerAttribute(
1785 71 : hDBF, static_cast<int>(poFeature->GetFID()), iField,
1786 71 : psField->Date.Year * 10000 + psField->Date.Month * 100 +
1787 71 : psField->Date.Day);
1788 : }
1789 : }
1790 71 : break;
1791 :
1792 0 : default:
1793 : {
1794 : // Ignore fields of other types.
1795 0 : break;
1796 : }
1797 : }
1798 : }
1799 :
1800 77237 : return OGRERR_NONE;
1801 : }
|