GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
shpopen.c
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Project: Shapelib
4 * Purpose: Implementation of core Shapefile read/write functions.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 1999, 2001, Frank Warmerdam
9 * Copyright (c) 2011-2019, Even Rouault <even dot rouault at spatialys.com>
10 *
11 * This software is available under the following "MIT Style" license,
12 * or at the option of the licensee under the LGPL (see COPYING). This
13 * option is discussed in more detail in shapelib.html.
14 *
15 * --
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a
18 * copy of this software and associated documentation files (the "Software"),
19 * to deal in the Software without restriction, including without limitation
20 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 * and/or sell copies of the Software, and to permit persons to whom the
22 * Software is furnished to do so, subject to the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included
25 * in all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 * DEALINGS IN THE SOFTWARE.
34 ******************************************************************************/
35
36#include "shapefil.h"
37
38#include <assert.h>
39#include <errno.h>
40#include <limits.h>
41#include <math.h>
42#include <stdbool.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47SHP_CVSID("$Id$")
48
49typedef unsigned char uchar;
50
51#if UINT_MAX == 65535
52typedef unsigned long int32;
53#else
54typedef unsigned int int32;
55#endif
56
57#ifndef FALSE
58#define FALSE 0
59#define TRUE 1
60#endif
61
62#define ByteCopy(a, b, c) memcpy(b, a, c)
63#ifndef MAX
64#define MIN(a, b) ((a < b) ? a : b)
65#define MAX(a, b) ((a > b) ? a : b)
66#endif
67
68#ifndef USE_CPL
69#if defined(_MSC_VER)
70#if _MSC_VER < 1900
71#define snprintf _snprintf
72#endif
73#elif defined(WIN32) || defined(_WIN32)
74#ifndef snprintf
75#define snprintf _snprintf
76#endif
77#endif
78#endif
79
80#ifndef CPL_UNUSED
81#if defined(__GNUC__) && __GNUC__ >= 4
82#define CPL_UNUSED __attribute((__unused__))
83#else
84#define CPL_UNUSED
85#endif
86#endif
87
88#if defined(CPL_LSB)
89#define bBigEndian false
90#elif defined(CPL_MSB)
91#define bBigEndian true
92#else
93static bool bBigEndian;
94#endif
95
96#ifdef __cplusplus
97#define STATIC_CAST(type, x) static_cast<type>(x)
98#define SHPLIB_NULLPTR nullptr
99#else
100#define STATIC_CAST(type, x) ((type)(x))
101#define SHPLIB_NULLPTR NULL
102#endif
103
104/************************************************************************/
105/* SwapWord() */
106/* */
107/* Swap a 2, 4 or 8 byte word. */
108/************************************************************************/
109
110static void SwapWord(int length, void *wordP)
111{
112 for (int i = 0; i < length / 2; i++) {
113 const uchar temp = STATIC_CAST(uchar *, wordP)[i];
114 STATIC_CAST(uchar *, wordP)
115 [i] = STATIC_CAST(uchar *, wordP)[length - i - 1];
116 STATIC_CAST(uchar *, wordP)[length - i - 1] = temp;
117 }
118}
119
120/************************************************************************/
121/* SfRealloc() */
122/* */
123/* A realloc cover function that will access a NULL pointer as */
124/* a valid input. */
125/************************************************************************/
126
127static void *SfRealloc(void *pMem, int nNewSize)
128{
129 if (pMem == SHPLIB_NULLPTR)
130 return malloc(nNewSize);
131 else
132 return realloc(pMem, nNewSize);
133}
134
135/************************************************************************/
136/* SHPWriteHeader() */
137/* */
138/* Write out a header for the .shp and .shx files as well as the */
139/* contents of the index (.shx) file. */
140/************************************************************************/
141
143{
144 if (psSHP->fpSHX == SHPLIB_NULLPTR) {
145 psSHP->sHooks.Error("SHPWriteHeader failed : SHX file is closed");
146 return;
147 }
148
149 /* -------------------------------------------------------------------- */
150 /* Prepare header block for .shp file. */
151 /* -------------------------------------------------------------------- */
152
153 uchar abyHeader[100] = {0};
154 abyHeader[2] = 0x27; /* magic cookie */
155 abyHeader[3] = 0x0a;
156
157 int32 i32 = psSHP->nFileSize / 2; /* file size */
158 ByteCopy(&i32, abyHeader + 24, 4);
159 if (!bBigEndian)
160 SwapWord(4, abyHeader + 24);
161
162 i32 = 1000; /* version */
163 ByteCopy(&i32, abyHeader + 28, 4);
164 if (bBigEndian)
165 SwapWord(4, abyHeader + 28);
166
167 i32 = psSHP->nShapeType; /* shape type */
168 ByteCopy(&i32, abyHeader + 32, 4);
169 if (bBigEndian)
170 SwapWord(4, abyHeader + 32);
171
172 double dValue = psSHP->adBoundsMin[0]; /* set bounds */
173 ByteCopy(&dValue, abyHeader + 36, 8);
174 if (bBigEndian)
175 SwapWord(8, abyHeader + 36);
176
177 dValue = psSHP->adBoundsMin[1];
178 ByteCopy(&dValue, abyHeader + 44, 8);
179 if (bBigEndian)
180 SwapWord(8, abyHeader + 44);
181
182 dValue = psSHP->adBoundsMax[0];
183 ByteCopy(&dValue, abyHeader + 52, 8);
184 if (bBigEndian)
185 SwapWord(8, abyHeader + 52);
186
187 dValue = psSHP->adBoundsMax[1];
188 ByteCopy(&dValue, abyHeader + 60, 8);
189 if (bBigEndian)
190 SwapWord(8, abyHeader + 60);
191
192 dValue = psSHP->adBoundsMin[2]; /* z */
193 ByteCopy(&dValue, abyHeader + 68, 8);
194 if (bBigEndian)
195 SwapWord(8, abyHeader + 68);
196
197 dValue = psSHP->adBoundsMax[2];
198 ByteCopy(&dValue, abyHeader + 76, 8);
199 if (bBigEndian)
200 SwapWord(8, abyHeader + 76);
201
202 dValue = psSHP->adBoundsMin[3]; /* m */
203 ByteCopy(&dValue, abyHeader + 84, 8);
204 if (bBigEndian)
205 SwapWord(8, abyHeader + 84);
206
207 dValue = psSHP->adBoundsMax[3];
208 ByteCopy(&dValue, abyHeader + 92, 8);
209 if (bBigEndian)
210 SwapWord(8, abyHeader + 92);
211
212 /* -------------------------------------------------------------------- */
213 /* Write .shp file header. */
214 /* -------------------------------------------------------------------- */
215 if (psSHP->sHooks.FSeek(psSHP->fpSHP, 0, 0) != 0 ||
216 psSHP->sHooks.FWrite(abyHeader, 100, 1, psSHP->fpSHP) != 1) {
217 char szErrorMsg[200];
218
219 snprintf(szErrorMsg, sizeof(szErrorMsg),
220 "Failure writing .shp header: %s", strerror(errno));
221 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
222 psSHP->sHooks.Error(szErrorMsg);
223 return;
224 }
225
226 /* -------------------------------------------------------------------- */
227 /* Prepare, and write .shx file header. */
228 /* -------------------------------------------------------------------- */
229 i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100) / 2; /* file size */
230 ByteCopy(&i32, abyHeader + 24, 4);
231 if (!bBigEndian)
232 SwapWord(4, abyHeader + 24);
233
234 if (psSHP->sHooks.FSeek(psSHP->fpSHX, 0, 0) != 0 ||
235 psSHP->sHooks.FWrite(abyHeader, 100, 1, psSHP->fpSHX) != 1) {
236 char szErrorMsg[200];
237
238 snprintf(szErrorMsg, sizeof(szErrorMsg),
239 "Failure writing .shx header: %s", strerror(errno));
240 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
241 psSHP->sHooks.Error(szErrorMsg);
242
243 return;
244 }
245
246 /* -------------------------------------------------------------------- */
247 /* Write out the .shx contents. */
248 /* -------------------------------------------------------------------- */
249 int32 *panSHX =
250 STATIC_CAST(int32 *, malloc(sizeof(int32) * 2 * psSHP->nRecords));
251 if (panSHX == SHPLIB_NULLPTR) {
252 psSHP->sHooks.Error("Failure allocatin panSHX");
253 return;
254 }
255
256 for (int i = 0; i < psSHP->nRecords; i++) {
257 panSHX[i * 2] = psSHP->panRecOffset[i] / 2;
258 panSHX[i * 2 + 1] = psSHP->panRecSize[i] / 2;
259 if (!bBigEndian)
260 SwapWord(4, panSHX + i * 2);
261 if (!bBigEndian)
262 SwapWord(4, panSHX + i * 2 + 1);
263 }
264
265 if (STATIC_CAST(int, psSHP->sHooks.FWrite(panSHX, sizeof(int32) * 2,
266 psSHP->nRecords, psSHP->fpSHX)) !=
267 psSHP->nRecords) {
268 char szErrorMsg[200];
269
270 snprintf(szErrorMsg, sizeof(szErrorMsg),
271 "Failure writing .shx contents: %s", strerror(errno));
272 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
273 psSHP->sHooks.Error(szErrorMsg);
274 }
275
276 free(panSHX);
277
278 /* -------------------------------------------------------------------- */
279 /* Flush to disk. */
280 /* -------------------------------------------------------------------- */
281 psSHP->sHooks.FFlush(psSHP->fpSHP);
282 psSHP->sHooks.FFlush(psSHP->fpSHX);
283}
284
285/************************************************************************/
286/* SHPOpen() */
287/************************************************************************/
288
289SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
290{
291 SAHooks sHooks;
292
293 SASetupDefaultHooks(&sHooks);
294
295 return SHPOpenLL(pszLayer, pszAccess, &sHooks);
296}
297
298/************************************************************************/
299/* SHPGetLenWithoutExtension() */
300/************************************************************************/
301
302static int SHPGetLenWithoutExtension(const char *pszBasename)
303{
304 const int nLen = STATIC_CAST(int, strlen(pszBasename));
305 for (int i = nLen - 1;
306 i > 0 && pszBasename[i] != '/' && pszBasename[i] != '\\'; i--) {
307 if (pszBasename[i] == '.') {
308 return i;
309 }
310 }
311 return nLen;
312}
313
314/************************************************************************/
315/* SHPOpen() */
316/* */
317/* Open the .shp and .shx files based on the basename of the */
318/* files or either file name. */
319/************************************************************************/
320
321SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess,
322 SAHooks *psHooks)
323{
324 /* -------------------------------------------------------------------- */
325 /* Ensure the access string is one of the legal ones. We */
326 /* ensure the result string indicates binary to avoid common */
327 /* problems on Windows. */
328 /* -------------------------------------------------------------------- */
329 bool bLazySHXLoading = false;
330 if (strcmp(pszAccess, "rb+") == 0 || strcmp(pszAccess, "r+b") == 0 ||
331 strcmp(pszAccess, "r+") == 0) {
332 pszAccess = "r+b";
333 }
334 else {
335 bLazySHXLoading = strchr(pszAccess, 'l') != SHPLIB_NULLPTR;
336 pszAccess = "rb";
337 }
338
339/* -------------------------------------------------------------------- */
340/* Establish the byte order on this machine. */
341/* -------------------------------------------------------------------- */
342#if !defined(bBigEndian)
343 {
344 int i = 1;
345 if (*((uchar *)&i) == 1)
346 bBigEndian = false;
347 else
348 bBigEndian = true;
349 }
350#endif
351
352 /* -------------------------------------------------------------------- */
353 /* Initialize the info structure. */
354 /* -------------------------------------------------------------------- */
355 SHPHandle psSHP = STATIC_CAST(SHPHandle, calloc(sizeof(SHPInfo), 1));
356
357 psSHP->bUpdated = FALSE;
358 memcpy(&(psSHP->sHooks), psHooks, sizeof(SAHooks));
359
360 /* -------------------------------------------------------------------- */
361 /* Open the .shp and .shx files. Note that files pulled from */
362 /* a PC to Unix with upper case filenames won't work! */
363 /* -------------------------------------------------------------------- */
364 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
365 char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
366 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
367 memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
368 psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess);
369 if (psSHP->fpSHP == SHPLIB_NULLPTR) {
370 memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5);
371 psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess);
372 }
373
374 if (psSHP->fpSHP == SHPLIB_NULLPTR) {
375 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
376 char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
377 pszFullname[nLenWithoutExtension] = 0;
378 snprintf(pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
379 pszFullname, pszFullname);
380 psHooks->Error(pszMessage);
381 free(pszMessage);
382
383 free(psSHP);
384 free(pszFullname);
385
386 return SHPLIB_NULLPTR;
387 }
388
389 memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
390 psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess);
391 if (psSHP->fpSHX == SHPLIB_NULLPTR) {
392 memcpy(pszFullname + nLenWithoutExtension, ".SHX", 5);
393 psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess);
394 }
395
396 if (psSHP->fpSHX == SHPLIB_NULLPTR) {
397 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
398 char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
399 pszFullname[nLenWithoutExtension] = 0;
400 snprintf(pszMessage, nMessageLen,
401 "Unable to open %s.shx or %s.SHX. "
402 "Set SHAPE_RESTORE_SHX config option to YES to restore or "
403 "create it.",
404 pszFullname, pszFullname);
405 psHooks->Error(pszMessage);
406 free(pszMessage);
407
408 psSHP->sHooks.FClose(psSHP->fpSHP);
409 free(psSHP);
410 free(pszFullname);
411 return SHPLIB_NULLPTR;
412 }
413
414 free(pszFullname);
415
416 /* -------------------------------------------------------------------- */
417 /* Read the file size from the SHP file. */
418 /* -------------------------------------------------------------------- */
419 uchar *pabyBuf = STATIC_CAST(uchar *, malloc(100));
420 if (psSHP->sHooks.FRead(pabyBuf, 100, 1, psSHP->fpSHP) != 1) {
421 psSHP->sHooks.Error(".shp file is unreadable, or corrupt.");
422 psSHP->sHooks.FClose(psSHP->fpSHP);
423 psSHP->sHooks.FClose(psSHP->fpSHX);
424 free(pabyBuf);
425 free(psSHP);
426
427 return SHPLIB_NULLPTR;
428 }
429
430 psSHP->nFileSize = (STATIC_CAST(unsigned int, pabyBuf[24]) << 24) |
431 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) | pabyBuf[27];
432 if (psSHP->nFileSize < UINT_MAX / 2)
433 psSHP->nFileSize *= 2;
434 else
435 psSHP->nFileSize = (UINT_MAX / 2) * 2;
436
437 /* -------------------------------------------------------------------- */
438 /* Read SHX file Header info */
439 /* -------------------------------------------------------------------- */
440 if (psSHP->sHooks.FRead(pabyBuf, 100, 1, psSHP->fpSHX) != 1 ||
441 pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 ||
442 (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d)) {
443 psSHP->sHooks.Error(".shx file is unreadable, or corrupt.");
444 psSHP->sHooks.FClose(psSHP->fpSHP);
445 psSHP->sHooks.FClose(psSHP->fpSHX);
446 free(pabyBuf);
447 free(psSHP);
448
449 return SHPLIB_NULLPTR;
450 }
451
452 psSHP->nRecords = pabyBuf[27] | (pabyBuf[26] << 8) | (pabyBuf[25] << 16) |
453 ((pabyBuf[24] & 0x7F) << 24);
454 psSHP->nRecords = (psSHP->nRecords - 50) / 4;
455
456 psSHP->nShapeType = pabyBuf[32];
457
458 if (psSHP->nRecords < 0 || psSHP->nRecords > 256000000) {
459 char szErrorMsg[200];
460
461 snprintf(szErrorMsg, sizeof(szErrorMsg),
462 "Record count in .shx header is %d, which seems\n"
463 "unreasonable. Assuming header is corrupt.",
464 psSHP->nRecords);
465 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
466 psSHP->sHooks.Error(szErrorMsg);
467 psSHP->sHooks.FClose(psSHP->fpSHP);
468 psSHP->sHooks.FClose(psSHP->fpSHX);
469 free(psSHP);
470 free(pabyBuf);
471
472 return SHPLIB_NULLPTR;
473 }
474
475 /* If a lot of records are advertized, check that the file is big enough */
476 /* to hold them */
477 if (psSHP->nRecords >= 1024 * 1024) {
478 psSHP->sHooks.FSeek(psSHP->fpSHX, 0, 2);
479 const SAOffset nFileSize = psSHP->sHooks.FTell(psSHP->fpSHX);
480 if (nFileSize > 100 &&
481 nFileSize / 2 < STATIC_CAST(SAOffset, psSHP->nRecords * 4 + 50)) {
482 psSHP->nRecords = STATIC_CAST(int, (nFileSize - 100) / 8);
483 }
484 psSHP->sHooks.FSeek(psSHP->fpSHX, 100, 0);
485 }
486
487 /* -------------------------------------------------------------------- */
488 /* Read the bounds. */
489 /* -------------------------------------------------------------------- */
490 double dValue;
491
492 if (bBigEndian)
493 SwapWord(8, pabyBuf + 36);
494 memcpy(&dValue, pabyBuf + 36, 8);
495 psSHP->adBoundsMin[0] = dValue;
496
497 if (bBigEndian)
498 SwapWord(8, pabyBuf + 44);
499 memcpy(&dValue, pabyBuf + 44, 8);
500 psSHP->adBoundsMin[1] = dValue;
501
502 if (bBigEndian)
503 SwapWord(8, pabyBuf + 52);
504 memcpy(&dValue, pabyBuf + 52, 8);
505 psSHP->adBoundsMax[0] = dValue;
506
507 if (bBigEndian)
508 SwapWord(8, pabyBuf + 60);
509 memcpy(&dValue, pabyBuf + 60, 8);
510 psSHP->adBoundsMax[1] = dValue;
511
512 if (bBigEndian)
513 SwapWord(8, pabyBuf + 68); /* z */
514 memcpy(&dValue, pabyBuf + 68, 8);
515 psSHP->adBoundsMin[2] = dValue;
516
517 if (bBigEndian)
518 SwapWord(8, pabyBuf + 76);
519 memcpy(&dValue, pabyBuf + 76, 8);
520 psSHP->adBoundsMax[2] = dValue;
521
522 if (bBigEndian)
523 SwapWord(8, pabyBuf + 84); /* z */
524 memcpy(&dValue, pabyBuf + 84, 8);
525 psSHP->adBoundsMin[3] = dValue;
526
527 if (bBigEndian)
528 SwapWord(8, pabyBuf + 92);
529 memcpy(&dValue, pabyBuf + 92, 8);
530 psSHP->adBoundsMax[3] = dValue;
531
532 free(pabyBuf);
533
534 /* -------------------------------------------------------------------- */
535 /* Read the .shx file to get the offsets to each record in */
536 /* the .shp file. */
537 /* -------------------------------------------------------------------- */
538 psSHP->nMaxRecords = psSHP->nRecords;
539
540 psSHP->panRecOffset =
541 STATIC_CAST(unsigned int *,
542 malloc(sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords)));
543 psSHP->panRecSize =
544 STATIC_CAST(unsigned int *,
545 malloc(sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords)));
546 if (bLazySHXLoading)
547 pabyBuf = SHPLIB_NULLPTR;
548 else
549 pabyBuf = STATIC_CAST(uchar *, malloc(8 * MAX(1, psSHP->nRecords)));
550
551 if (psSHP->panRecOffset == SHPLIB_NULLPTR ||
552 psSHP->panRecSize == SHPLIB_NULLPTR ||
553 (!bLazySHXLoading && pabyBuf == SHPLIB_NULLPTR)) {
554 char szErrorMsg[200];
555
556 snprintf(
557 szErrorMsg, sizeof(szErrorMsg),
558 "Not enough memory to allocate requested memory (nRecords=%d).\n"
559 "Probably broken SHP file",
560 psSHP->nRecords);
561 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
562 psSHP->sHooks.Error(szErrorMsg);
563 psSHP->sHooks.FClose(psSHP->fpSHP);
564 psSHP->sHooks.FClose(psSHP->fpSHX);
565 if (psSHP->panRecOffset)
566 free(psSHP->panRecOffset);
567 if (psSHP->panRecSize)
568 free(psSHP->panRecSize);
569 if (pabyBuf)
570 free(pabyBuf);
571 free(psSHP);
572 return SHPLIB_NULLPTR;
573 }
574
575 if (bLazySHXLoading) {
576 memset(psSHP->panRecOffset, 0,
577 sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords));
578 memset(psSHP->panRecSize, 0,
579 sizeof(unsigned int) * MAX(1, psSHP->nMaxRecords));
580 free(pabyBuf); // sometimes make cppcheck happy, but
581 return (psSHP);
582 }
583
584 if (STATIC_CAST(int, psSHP->sHooks.FRead(pabyBuf, 8, psSHP->nRecords,
585 psSHP->fpSHX)) !=
586 psSHP->nRecords) {
587 char szErrorMsg[200];
588
589 snprintf(szErrorMsg, sizeof(szErrorMsg),
590 "Failed to read all values for %d records in .shx file: %s.",
591 psSHP->nRecords, strerror(errno));
592 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
593 psSHP->sHooks.Error(szErrorMsg);
594
595 /* SHX is short or unreadable for some reason. */
596 psSHP->sHooks.FClose(psSHP->fpSHP);
597 psSHP->sHooks.FClose(psSHP->fpSHX);
598 free(psSHP->panRecOffset);
599 free(psSHP->panRecSize);
600 free(pabyBuf);
601 free(psSHP);
602
603 return SHPLIB_NULLPTR;
604 }
605
606 /* In read-only mode, we can close the SHX now */
607 if (strcmp(pszAccess, "rb") == 0) {
608 psSHP->sHooks.FClose(psSHP->fpSHX);
609 psSHP->fpSHX = SHPLIB_NULLPTR;
610 }
611
612 for (int i = 0; i < psSHP->nRecords; i++) {
613 unsigned int nOffset;
614 memcpy(&nOffset, pabyBuf + i * 8, 4);
615 if (!bBigEndian)
616 SwapWord(4, &nOffset);
617
618 unsigned int nLength;
619 memcpy(&nLength, pabyBuf + i * 8 + 4, 4);
620 if (!bBigEndian)
621 SwapWord(4, &nLength);
622
623 if (nOffset > STATIC_CAST(unsigned int, INT_MAX)) {
624 char str[128];
625 snprintf(str, sizeof(str), "Invalid offset for entity %d", i);
626 str[sizeof(str) - 1] = '\0';
627
628 psSHP->sHooks.Error(str);
629 SHPClose(psSHP);
630 free(pabyBuf);
631 return SHPLIB_NULLPTR;
632 }
633 if (nLength > STATIC_CAST(unsigned int, INT_MAX / 2 - 4)) {
634 char str[128];
635 snprintf(str, sizeof(str), "Invalid length for entity %d", i);
636 str[sizeof(str) - 1] = '\0';
637
638 psSHP->sHooks.Error(str);
639 SHPClose(psSHP);
640 free(pabyBuf);
641 return SHPLIB_NULLPTR;
642 }
643 psSHP->panRecOffset[i] = nOffset * 2;
644 psSHP->panRecSize[i] = nLength * 2;
645 }
646 free(pabyBuf);
647
648 return (psSHP);
649}
650
651/************************************************************************/
652/* SHPOpenLLEx() */
653/* */
654/* Open the .shp and .shx files based on the basename of the */
655/* files or either file name. It generally invokes SHPRestoreSHX() */
656/* in case when bRestoreSHX equals true. */
657/************************************************************************/
658
659SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess,
660 SAHooks *psHooks, int bRestoreSHX)
661{
662 if (!bRestoreSHX)
663 return SHPOpenLL(pszLayer, pszAccess, psHooks);
664 else {
665 if (SHPRestoreSHX(pszLayer, pszAccess, psHooks)) {
666 return SHPOpenLL(pszLayer, pszAccess, psHooks);
667 }
668 }
669
670 return SHPLIB_NULLPTR;
671}
672
673/************************************************************************/
674/* SHPRestoreSHX() */
675/* */
676/* Restore .SHX file using associated .SHP file. */
677/* */
678/************************************************************************/
679
680int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess,
681 SAHooks *psHooks)
682{
683 /* -------------------------------------------------------------------- */
684 /* Ensure the access string is one of the legal ones. We */
685 /* ensure the result string indicates binary to avoid common */
686 /* problems on Windows. */
687 /* -------------------------------------------------------------------- */
688 if (strcmp(pszAccess, "rb+") == 0 || strcmp(pszAccess, "r+b") == 0 ||
689 strcmp(pszAccess, "r+") == 0) {
690 pszAccess = "r+b";
691 }
692 else {
693 pszAccess = "rb";
694 }
695
696/* -------------------------------------------------------------------- */
697/* Establish the byte order on this machine. */
698/* -------------------------------------------------------------------- */
699#if !defined(bBigEndian)
700 {
701 int i = 1;
702 if (*((uchar *)&i) == 1)
703 bBigEndian = false;
704 else
705 bBigEndian = true;
706 }
707#endif
708
709 /* -------------------------------------------------------------------- */
710 /* Open the .shp file. Note that files pulled from */
711 /* a PC to Unix with upper case filenames won't work! */
712 /* -------------------------------------------------------------------- */
713 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
714 char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
715 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
716 memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
717 SAFile fpSHP = psHooks->FOpen(pszFullname, pszAccess);
718 if (fpSHP == SHPLIB_NULLPTR) {
719 memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5);
720 fpSHP = psHooks->FOpen(pszFullname, pszAccess);
721 }
722
723 if (fpSHP == SHPLIB_NULLPTR) {
724 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
725 char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
726
727 pszFullname[nLenWithoutExtension] = 0;
728 snprintf(pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
729 pszFullname, pszFullname);
730 psHooks->Error(pszMessage);
731 free(pszMessage);
732
733 free(pszFullname);
734
735 return (0);
736 }
737
738 /* -------------------------------------------------------------------- */
739 /* Read the file size from the SHP file. */
740 /* -------------------------------------------------------------------- */
741 uchar *pabyBuf = STATIC_CAST(uchar *, malloc(100));
742 if (psHooks->FRead(pabyBuf, 100, 1, fpSHP) != 1) {
743 psHooks->Error(".shp file is unreadable, or corrupt.");
744 psHooks->FClose(fpSHP);
745
746 free(pabyBuf);
747 free(pszFullname);
748
749 return (0);
750 }
751
752 unsigned int nSHPFilesize = (STATIC_CAST(unsigned int, pabyBuf[24]) << 24) |
753 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) |
754 pabyBuf[27];
755 if (nSHPFilesize < UINT_MAX / 2)
756 nSHPFilesize *= 2;
757 else
758 nSHPFilesize = (UINT_MAX / 2) * 2;
759
760 memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
761 const char pszSHXAccess[] = "w+b";
762 SAFile fpSHX = psHooks->FOpen(pszFullname, pszSHXAccess);
763 if (fpSHX == SHPLIB_NULLPTR) {
764 size_t nMessageLen = strlen(pszFullname) * 2 + 256;
765 char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
766 pszFullname[nLenWithoutExtension] = 0;
767 snprintf(pszMessage, nMessageLen,
768 "Error opening file %s.shx for writing", pszFullname);
769 psHooks->Error(pszMessage);
770 free(pszMessage);
771
772 psHooks->FClose(fpSHP);
773
774 free(pabyBuf);
775 free(pszFullname);
776
777 return (0);
778 }
779
780 /* -------------------------------------------------------------------- */
781 /* Open SHX and create it using SHP file content. */
782 /* -------------------------------------------------------------------- */
783 psHooks->FSeek(fpSHP, 100, 0);
784 char *pabySHXHeader = STATIC_CAST(char *, malloc(100));
785 memcpy(pabySHXHeader, pabyBuf, 100);
786 psHooks->FWrite(pabySHXHeader, 100, 1, fpSHX);
787 free(pabyBuf);
788
789 // unsigned int nCurrentRecordOffset = 0;
790 unsigned int nCurrentSHPOffset = 100;
791 unsigned int nRealSHXContentSize = 100;
792 unsigned int niRecord = 0;
793 unsigned int nRecordLength = 0;
794 unsigned int nRecordOffset = 50;
795 char abyReadRecord[8];
796
797 while (nCurrentSHPOffset < nSHPFilesize) {
798 if (psHooks->FRead(&niRecord, 4, 1, fpSHP) == 1 &&
799 psHooks->FRead(&nRecordLength, 4, 1, fpSHP) == 1) {
800 if (!bBigEndian)
801 SwapWord(4, &nRecordOffset);
802 memcpy(abyReadRecord, &nRecordOffset, 4);
803 memcpy(abyReadRecord + 4, &nRecordLength, 4);
804
805 psHooks->FWrite(abyReadRecord, 8, 1, fpSHX);
806
807 if (!bBigEndian)
808 SwapWord(4, &nRecordOffset);
809 if (!bBigEndian)
810 SwapWord(4, &nRecordLength);
811 nRecordOffset += nRecordLength + 4;
812 // nCurrentRecordOffset += 8;
813 nCurrentSHPOffset += 8 + nRecordLength * 2;
814
815 psHooks->FSeek(fpSHP, nCurrentSHPOffset, 0);
816 nRealSHXContentSize += 8;
817 }
818 else {
819 psHooks->Error("Error parsing .shp to restore .shx");
820
821 psHooks->FClose(fpSHX);
822 psHooks->FClose(fpSHP);
823
824 free(pabySHXHeader);
825 free(pszFullname);
826
827 return (0);
828 }
829 }
830
831 nRealSHXContentSize /= 2; // Bytes counted -> WORDs
832 if (!bBigEndian)
833 SwapWord(4, &nRealSHXContentSize);
834 psHooks->FSeek(fpSHX, 24, 0);
835 psHooks->FWrite(&nRealSHXContentSize, 4, 1, fpSHX);
836
837 psHooks->FClose(fpSHP);
838 psHooks->FClose(fpSHX);
839
840 free(pszFullname);
841 free(pabySHXHeader);
842
843 return (1);
844}
845
846/************************************************************************/
847/* SHPClose() */
848/* */
849/* Close the .shp and .shx files. */
850/************************************************************************/
851
853{
854 if (psSHP == SHPLIB_NULLPTR)
855 return;
856
857 /* -------------------------------------------------------------------- */
858 /* Update the header if we have modified anything. */
859 /* -------------------------------------------------------------------- */
860 if (psSHP->bUpdated)
861 SHPWriteHeader(psSHP);
862
863 /* -------------------------------------------------------------------- */
864 /* Free all resources, and close files. */
865 /* -------------------------------------------------------------------- */
866 free(psSHP->panRecOffset);
867 free(psSHP->panRecSize);
868
869 if (psSHP->fpSHX != SHPLIB_NULLPTR)
870 psSHP->sHooks.FClose(psSHP->fpSHX);
871 psSHP->sHooks.FClose(psSHP->fpSHP);
872
873 if (psSHP->pabyRec != SHPLIB_NULLPTR) {
874 free(psSHP->pabyRec);
875 }
876
877 if (psSHP->pabyObjectBuf != SHPLIB_NULLPTR) {
878 free(psSHP->pabyObjectBuf);
879 }
880 if (psSHP->psCachedObject != SHPLIB_NULLPTR) {
881 free(psSHP->psCachedObject);
882 }
883
884 free(psSHP);
885}
886
887/************************************************************************/
888/* SHPSetFastModeReadObject() */
889/************************************************************************/
890
891/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the
892 * SHPHandle. */
893/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
894/* The SHPObject padfZ and padfM members may be NULL depending on the geometry
895 */
896/* type. It is illegal to free at hand any of the pointer members of the
897 * SHPObject structure */
899{
900 if (bFastMode) {
901 if (hSHP->psCachedObject == SHPLIB_NULLPTR) {
902 hSHP->psCachedObject =
903 STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject)));
905 }
906 }
907
908 hSHP->bFastModeReadObject = bFastMode;
909}
910
911/************************************************************************/
912/* SHPGetInfo() */
913/* */
914/* Fetch general information about the shape file. */
915/************************************************************************/
916
917void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType,
918 double *padfMinBound, double *padfMaxBound)
919{
920 if (psSHP == SHPLIB_NULLPTR)
921 return;
922
923 if (pnEntities != SHPLIB_NULLPTR)
924 *pnEntities = psSHP->nRecords;
925
926 if (pnShapeType != SHPLIB_NULLPTR)
927 *pnShapeType = psSHP->nShapeType;
928
929 for (int i = 0; i < 4; i++) {
930 if (padfMinBound != SHPLIB_NULLPTR)
931 padfMinBound[i] = psSHP->adBoundsMin[i];
932 if (padfMaxBound != SHPLIB_NULLPTR)
933 padfMaxBound[i] = psSHP->adBoundsMax[i];
934 }
935}
936
937/************************************************************************/
938/* SHPCreate() */
939/* */
940/* Create a new shape file and return a handle to the open */
941/* shape file with read/write access. */
942/************************************************************************/
943
944SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
945{
946 SAHooks sHooks;
947
948 SASetupDefaultHooks(&sHooks);
949
950 return SHPCreateLL(pszLayer, nShapeType, &sHooks);
951}
952
953/************************************************************************/
954/* SHPCreate() */
955/* */
956/* Create a new shape file and return a handle to the open */
957/* shape file with read/write access. */
958/************************************************************************/
959
960SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType,
961 SAHooks *psHooks)
962{
963/* -------------------------------------------------------------------- */
964/* Establish the byte order on this system. */
965/* -------------------------------------------------------------------- */
966#if !defined(bBigEndian)
967 {
968 int i = 1;
969 if (*((uchar *)&i) == 1)
970 bBigEndian = false;
971 else
972 bBigEndian = true;
973 }
974#endif
975
976 /* -------------------------------------------------------------------- */
977 /* Open the two files so we can write their headers. */
978 /* -------------------------------------------------------------------- */
979 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
980 char *pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
981 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
982 memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
983 SAFile fpSHP = psHooks->FOpen(pszFullname, "wb");
984 if (fpSHP == SHPLIB_NULLPTR) {
985 char szErrorMsg[200];
986 snprintf(szErrorMsg, sizeof(szErrorMsg), "Failed to create file %s: %s",
987 pszFullname, strerror(errno));
988 psHooks->Error(szErrorMsg);
989
990 free(pszFullname);
991 return NULL;
992 }
993
994 memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
995 SAFile fpSHX = psHooks->FOpen(pszFullname, "wb");
996 if (fpSHX == SHPLIB_NULLPTR) {
997 char szErrorMsg[200];
998 snprintf(szErrorMsg, sizeof(szErrorMsg), "Failed to create file %s: %s",
999 pszFullname, strerror(errno));
1000 psHooks->Error(szErrorMsg);
1001
1002 free(pszFullname);
1003 psHooks->FClose(fpSHP);
1004 return NULL;
1005 }
1006
1007 free(pszFullname);
1008 pszFullname = SHPLIB_NULLPTR;
1009
1010 /* -------------------------------------------------------------------- */
1011 /* Prepare header block for .shp file. */
1012 /* -------------------------------------------------------------------- */
1013 uchar abyHeader[100];
1014 memset(abyHeader, 0, sizeof(abyHeader));
1015
1016 abyHeader[2] = 0x27; /* magic cookie */
1017 abyHeader[3] = 0x0a;
1018
1019 int32 i32 = 50; /* file size */
1020 ByteCopy(&i32, abyHeader + 24, 4);
1021 if (!bBigEndian)
1022 SwapWord(4, abyHeader + 24);
1023
1024 i32 = 1000; /* version */
1025 ByteCopy(&i32, abyHeader + 28, 4);
1026 if (bBigEndian)
1027 SwapWord(4, abyHeader + 28);
1028
1029 i32 = nShapeType; /* shape type */
1030 ByteCopy(&i32, abyHeader + 32, 4);
1031 if (bBigEndian)
1032 SwapWord(4, abyHeader + 32);
1033
1034 double dValue = 0.0; /* set bounds */
1035 ByteCopy(&dValue, abyHeader + 36, 8);
1036 ByteCopy(&dValue, abyHeader + 44, 8);
1037 ByteCopy(&dValue, abyHeader + 52, 8);
1038 ByteCopy(&dValue, abyHeader + 60, 8);
1039
1040 /* -------------------------------------------------------------------- */
1041 /* Write .shp file header. */
1042 /* -------------------------------------------------------------------- */
1043 if (psHooks->FWrite(abyHeader, 100, 1, fpSHP) != 1) {
1044 char szErrorMsg[200];
1045
1046 snprintf(szErrorMsg, sizeof(szErrorMsg),
1047 "Failed to write .shp header: %s", strerror(errno));
1048 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
1049 psHooks->Error(szErrorMsg);
1050
1051 free(pszFullname);
1052 psHooks->FClose(fpSHP);
1053 psHooks->FClose(fpSHX);
1054 return NULL;
1055 }
1056
1057 /* -------------------------------------------------------------------- */
1058 /* Prepare, and write .shx file header. */
1059 /* -------------------------------------------------------------------- */
1060 i32 = 50; /* file size */
1061 ByteCopy(&i32, abyHeader + 24, 4);
1062 if (!bBigEndian)
1063 SwapWord(4, abyHeader + 24);
1064
1065 if (psHooks->FWrite(abyHeader, 100, 1, fpSHX) != 1) {
1066 char szErrorMsg[200];
1067
1068 snprintf(szErrorMsg, sizeof(szErrorMsg),
1069 "Failure writing .shx header: %s", strerror(errno));
1070 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
1071 psHooks->Error(szErrorMsg);
1072
1073 free(pszFullname);
1074 psHooks->FClose(fpSHP);
1075 psHooks->FClose(fpSHX);
1076 return NULL;
1077 }
1078
1079 /* -------------------------------------------------------------------- */
1080 /* Close the files, and then open them as regular existing files. */
1081 /* -------------------------------------------------------------------- */
1082 psHooks->FClose(fpSHP);
1083 psHooks->FClose(fpSHX);
1084
1085 return (SHPOpenLL(pszLayer, "r+b", psHooks));
1086}
1087
1088/************************************************************************/
1089/* _SHPSetBounds() */
1090/* */
1091/* Compute a bounds rectangle for a shape, and set it into the */
1092/* indicated location in the record. */
1093/************************************************************************/
1094
1095static void _SHPSetBounds(uchar *pabyRec, SHPObject *psShape)
1096{
1097 ByteCopy(&(psShape->dfXMin), pabyRec + 0, 8);
1098 ByteCopy(&(psShape->dfYMin), pabyRec + 8, 8);
1099 ByteCopy(&(psShape->dfXMax), pabyRec + 16, 8);
1100 ByteCopy(&(psShape->dfYMax), pabyRec + 24, 8);
1101
1102 if (bBigEndian) {
1103 SwapWord(8, pabyRec + 0);
1104 SwapWord(8, pabyRec + 8);
1105 SwapWord(8, pabyRec + 16);
1106 SwapWord(8, pabyRec + 24);
1107 }
1108}
1109
1110/************************************************************************/
1111/* SHPComputeExtents() */
1112/* */
1113/* Recompute the extents of a shape. Automatically done by */
1114/* SHPCreateObject(). */
1115/************************************************************************/
1116
1118{
1119 /* -------------------------------------------------------------------- */
1120 /* Build extents for this object. */
1121 /* -------------------------------------------------------------------- */
1122 if (psObject->nVertices > 0) {
1123 psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
1124 psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
1125 psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
1126 psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
1127 }
1128
1129 for (int i = 0; i < psObject->nVertices; i++) {
1130 psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
1131 psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
1132 psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
1133 psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
1134
1135 psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
1136 psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
1137 psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
1138 psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
1139 }
1140}
1141
1142/************************************************************************/
1143/* SHPCreateObject() */
1144/* */
1145/* Create a shape object. It should be freed with */
1146/* SHPDestroyObject(). */
1147/************************************************************************/
1148
1150 SHPCreateObject(int nSHPType, int nShapeId, int nParts,
1151 const int *panPartStart, const int *panPartType,
1152 int nVertices, const double *padfX, const double *padfY,
1153 const double *padfZ, const double *padfM)
1154{
1155 SHPObject *psObject =
1156 STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject)));
1157 psObject->nSHPType = nSHPType;
1158 psObject->nShapeId = nShapeId;
1160
1161 /* -------------------------------------------------------------------- */
1162 /* Establish whether this shape type has M, and Z values. */
1163 /* -------------------------------------------------------------------- */
1164 bool bHasM;
1165 bool bHasZ;
1166
1169 bHasM = true;
1170 bHasZ = false;
1171 }
1172 else if (nSHPType == SHPT_ARCZ || nSHPType == SHPT_POINTZ ||
1175 bHasM = true;
1176 bHasZ = true;
1177 }
1178 else {
1179 bHasM = false;
1180 bHasZ = false;
1181 }
1182
1183 /* -------------------------------------------------------------------- */
1184 /* Capture parts. Note that part type is optional, and */
1185 /* defaults to ring. */
1186 /* -------------------------------------------------------------------- */
1187 if (nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON ||
1191 psObject->nParts = MAX(1, nParts);
1192
1193 psObject->panPartStart =
1194 STATIC_CAST(int *, calloc(sizeof(int), psObject->nParts));
1195 psObject->panPartType =
1196 STATIC_CAST(int *, malloc(sizeof(int) * psObject->nParts));
1197
1198 psObject->panPartStart[0] = 0;
1199 psObject->panPartType[0] = SHPP_RING;
1200
1201 for (int i = 0; i < nParts; i++) {
1202 if (panPartStart != SHPLIB_NULLPTR)
1203 psObject->panPartStart[i] = panPartStart[i];
1204
1205 if (panPartType != SHPLIB_NULLPTR)
1206 psObject->panPartType[i] = panPartType[i];
1207 else
1208 psObject->panPartType[i] = SHPP_RING;
1209 }
1210
1211 if (psObject->panPartStart[0] != 0)
1212 psObject->panPartStart[0] = 0;
1213 }
1214
1215 /* -------------------------------------------------------------------- */
1216 /* Capture vertices. Note that X, Y, Z and M are optional. */
1217 /* -------------------------------------------------------------------- */
1218 if (nVertices > 0) {
1219 const size_t nSize = sizeof(double) * nVertices;
1220 psObject->padfX =
1221 STATIC_CAST(double *, padfX ? malloc(nSize)
1222 : calloc(sizeof(double), nVertices));
1223 psObject->padfY =
1224 STATIC_CAST(double *, padfY ? malloc(nSize)
1225 : calloc(sizeof(double), nVertices));
1226 psObject->padfZ = STATIC_CAST(
1227 double *,
1228 padfZ &&bHasZ ? malloc(nSize) : calloc(sizeof(double), nVertices));
1229 psObject->padfM = STATIC_CAST(
1230 double *,
1231 padfM &&bHasM ? malloc(nSize) : calloc(sizeof(double), nVertices));
1232 if (padfX != SHPLIB_NULLPTR)
1233 memcpy(psObject->padfX, padfX, nSize);
1234 if (padfY != SHPLIB_NULLPTR)
1235 memcpy(psObject->padfY, padfY, nSize);
1236 if (padfZ != SHPLIB_NULLPTR && bHasZ)
1237 memcpy(psObject->padfZ, padfZ, nSize);
1238 if (padfM != SHPLIB_NULLPTR && bHasM) {
1239 memcpy(psObject->padfM, padfM, nSize);
1240 psObject->bMeasureIsUsed = TRUE;
1241 }
1242 }
1243
1244 /* -------------------------------------------------------------------- */
1245 /* Compute the extents. */
1246 /* -------------------------------------------------------------------- */
1249
1250 return (psObject);
1251}
1252
1253/************************************************************************/
1254/* SHPCreateSimpleObject() */
1255/* */
1256/* Create a simple (common) shape object. Destroy with */
1257/* SHPDestroyObject(). */
1258/************************************************************************/
1259
1261 SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX,
1262 const double *padfY, const double *padfZ)
1263{
1265 nVertices, padfX, padfY, padfZ, SHPLIB_NULLPTR));
1266}
1267
1268/************************************************************************/
1269/* SHPWriteObject() */
1270/* */
1271/* Write out the vertices of a new structure. Note that it is */
1272/* only possible to write vertices at the end of the file. */
1273/************************************************************************/
1274
1276 SHPObject *psObject)
1277{
1278 psSHP->bUpdated = TRUE;
1279
1280 /* -------------------------------------------------------------------- */
1281 /* Ensure that shape object matches the type of the file it is */
1282 /* being written to. */
1283 /* -------------------------------------------------------------------- */
1284 assert(psObject->nSHPType == psSHP->nShapeType ||
1285 psObject->nSHPType == SHPT_NULL);
1286
1287 /* -------------------------------------------------------------------- */
1288 /* Ensure that -1 is used for appends. Either blow an */
1289 /* assertion, or if they are disabled, set the shapeid to -1 */
1290 /* for appends. */
1291 /* -------------------------------------------------------------------- */
1292 assert(nShapeId == -1 || (nShapeId >= 0 && nShapeId < psSHP->nRecords));
1293
1294 if (nShapeId != -1 && nShapeId >= psSHP->nRecords)
1295 nShapeId = -1;
1296
1297 /* -------------------------------------------------------------------- */
1298 /* Add the new entity to the in memory index. */
1299 /* -------------------------------------------------------------------- */
1300 if (nShapeId == -1 && psSHP->nRecords + 1 > psSHP->nMaxRecords) {
1301 int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
1302 unsigned int *panRecOffsetNew;
1303 unsigned int *panRecSizeNew;
1304
1305 panRecOffsetNew = STATIC_CAST(
1306 unsigned int *, SfRealloc(psSHP->panRecOffset,
1307 sizeof(unsigned int) * nNewMaxRecords));
1308 if (panRecOffsetNew == SHPLIB_NULLPTR)
1309 return -1;
1310 psSHP->panRecOffset = panRecOffsetNew;
1311
1312 panRecSizeNew = STATIC_CAST(
1313 unsigned int *, SfRealloc(psSHP->panRecSize,
1314 sizeof(unsigned int) * nNewMaxRecords));
1315 if (panRecSizeNew == SHPLIB_NULLPTR)
1316 return -1;
1317 psSHP->panRecSize = panRecSizeNew;
1318
1319 psSHP->nMaxRecords = nNewMaxRecords;
1320 }
1321
1322 /* -------------------------------------------------------------------- */
1323 /* Initialize record. */
1324 /* -------------------------------------------------------------------- */
1325 uchar *pabyRec =
1326 STATIC_CAST(uchar *, malloc(psObject->nVertices * 4 * sizeof(double) +
1327 psObject->nParts * 8 + 128));
1328 if (pabyRec == SHPLIB_NULLPTR)
1329 return -1;
1330
1331 /* -------------------------------------------------------------------- */
1332 /* Extract vertices for a Polygon or Arc. */
1333 /* -------------------------------------------------------------------- */
1334 unsigned int nRecordSize = 0;
1335 const bool bFirstFeature = psSHP->nRecords == 0;
1336
1337 if (psObject->nSHPType == SHPT_POLYGON ||
1338 psObject->nSHPType == SHPT_POLYGONZ ||
1339 psObject->nSHPType == SHPT_POLYGONM || psObject->nSHPType == SHPT_ARC ||
1340 psObject->nSHPType == SHPT_ARCZ || psObject->nSHPType == SHPT_ARCM ||
1341 psObject->nSHPType == SHPT_MULTIPATCH) {
1342 int32 nPoints = psObject->nVertices;
1343 int32 nParts = psObject->nParts;
1344
1345 _SHPSetBounds(pabyRec + 12, psObject);
1346
1347 if (bBigEndian)
1348 SwapWord(4, &nPoints);
1349 if (bBigEndian)
1350 SwapWord(4, &nParts);
1351
1352 ByteCopy(&nPoints, pabyRec + 40 + 8, 4);
1353 ByteCopy(&nParts, pabyRec + 36 + 8, 4);
1354
1355 nRecordSize = 52;
1356
1357 /*
1358 * Write part start positions.
1359 */
1360 ByteCopy(psObject->panPartStart, pabyRec + 44 + 8,
1361 4 * psObject->nParts);
1362 for (int i = 0; i < psObject->nParts; i++) {
1363 if (bBigEndian)
1364 SwapWord(4, pabyRec + 44 + 8 + 4 * i);
1365 nRecordSize += 4;
1366 }
1367
1368 /*
1369 * Write multipatch part types if needed.
1370 */
1371 if (psObject->nSHPType == SHPT_MULTIPATCH) {
1372 memcpy(pabyRec + nRecordSize, psObject->panPartType,
1373 4 * psObject->nParts);
1374 for (int i = 0; i < psObject->nParts; i++) {
1375 if (bBigEndian)
1376 SwapWord(4, pabyRec + nRecordSize);
1377 nRecordSize += 4;
1378 }
1379 }
1380
1381 /*
1382 * Write the (x,y) vertex values.
1383 */
1384 for (int i = 0; i < psObject->nVertices; i++) {
1385 ByteCopy(psObject->padfX + i, pabyRec + nRecordSize, 8);
1386 ByteCopy(psObject->padfY + i, pabyRec + nRecordSize + 8, 8);
1387
1388 if (bBigEndian)
1389 SwapWord(8, pabyRec + nRecordSize);
1390
1391 if (bBigEndian)
1392 SwapWord(8, pabyRec + nRecordSize + 8);
1393
1394 nRecordSize += 2 * 8;
1395 }
1396
1397 /*
1398 * Write the Z coordinates (if any).
1399 */
1400 if (psObject->nSHPType == SHPT_POLYGONZ ||
1401 psObject->nSHPType == SHPT_ARCZ ||
1402 psObject->nSHPType == SHPT_MULTIPATCH) {
1403 ByteCopy(&(psObject->dfZMin), pabyRec + nRecordSize, 8);
1404 if (bBigEndian)
1405 SwapWord(8, pabyRec + nRecordSize);
1406 nRecordSize += 8;
1407
1408 ByteCopy(&(psObject->dfZMax), pabyRec + nRecordSize, 8);
1409 if (bBigEndian)
1410 SwapWord(8, pabyRec + nRecordSize);
1411 nRecordSize += 8;
1412
1413 for (int i = 0; i < psObject->nVertices; i++) {
1414 ByteCopy(psObject->padfZ + i, pabyRec + nRecordSize, 8);
1415 if (bBigEndian)
1416 SwapWord(8, pabyRec + nRecordSize);
1417 nRecordSize += 8;
1418 }
1419 }
1420
1421 /*
1422 * Write the M values, if any.
1423 */
1424 if (psObject->bMeasureIsUsed &&
1425 (psObject->nSHPType == SHPT_POLYGONM ||
1426 psObject->nSHPType == SHPT_ARCM
1428 || psObject->nSHPType == SHPT_MULTIPATCH
1429#endif
1430 || psObject->nSHPType == SHPT_POLYGONZ ||
1431 psObject->nSHPType == SHPT_ARCZ)) {
1432 ByteCopy(&(psObject->dfMMin), pabyRec + nRecordSize, 8);
1433 if (bBigEndian)
1434 SwapWord(8, pabyRec + nRecordSize);
1435 nRecordSize += 8;
1436
1437 ByteCopy(&(psObject->dfMMax), pabyRec + nRecordSize, 8);
1438 if (bBigEndian)
1439 SwapWord(8, pabyRec + nRecordSize);
1440 nRecordSize += 8;
1441
1442 for (int i = 0; i < psObject->nVertices; i++) {
1443 ByteCopy(psObject->padfM + i, pabyRec + nRecordSize, 8);
1444 if (bBigEndian)
1445 SwapWord(8, pabyRec + nRecordSize);
1446 nRecordSize += 8;
1447 }
1448 }
1449 }
1450
1451 /* -------------------------------------------------------------------- */
1452 /* Extract vertices for a MultiPoint. */
1453 /* -------------------------------------------------------------------- */
1454 else if (psObject->nSHPType == SHPT_MULTIPOINT ||
1455 psObject->nSHPType == SHPT_MULTIPOINTZ ||
1456 psObject->nSHPType == SHPT_MULTIPOINTM) {
1457 int32 nPoints = psObject->nVertices;
1458
1459 _SHPSetBounds(pabyRec + 12, psObject);
1460
1461 if (bBigEndian)
1462 SwapWord(4, &nPoints);
1463 ByteCopy(&nPoints, pabyRec + 44, 4);
1464
1465 for (int i = 0; i < psObject->nVertices; i++) {
1466 ByteCopy(psObject->padfX + i, pabyRec + 48 + i * 16, 8);
1467 ByteCopy(psObject->padfY + i, pabyRec + 48 + i * 16 + 8, 8);
1468
1469 if (bBigEndian)
1470 SwapWord(8, pabyRec + 48 + i * 16);
1471 if (bBigEndian)
1472 SwapWord(8, pabyRec + 48 + i * 16 + 8);
1473 }
1474
1475 nRecordSize = 48 + 16 * psObject->nVertices;
1476
1477 if (psObject->nSHPType == SHPT_MULTIPOINTZ) {
1478 ByteCopy(&(psObject->dfZMin), pabyRec + nRecordSize, 8);
1479 if (bBigEndian)
1480 SwapWord(8, pabyRec + nRecordSize);
1481 nRecordSize += 8;
1482
1483 ByteCopy(&(psObject->dfZMax), pabyRec + nRecordSize, 8);
1484 if (bBigEndian)
1485 SwapWord(8, pabyRec + nRecordSize);
1486 nRecordSize += 8;
1487
1488 for (int i = 0; i < psObject->nVertices; i++) {
1489 ByteCopy(psObject->padfZ + i, pabyRec + nRecordSize, 8);
1490 if (bBigEndian)
1491 SwapWord(8, pabyRec + nRecordSize);
1492 nRecordSize += 8;
1493 }
1494 }
1495
1496 if (psObject->bMeasureIsUsed &&
1497 (psObject->nSHPType == SHPT_MULTIPOINTZ ||
1498 psObject->nSHPType == SHPT_MULTIPOINTM)) {
1499 ByteCopy(&(psObject->dfMMin), pabyRec + nRecordSize, 8);
1500 if (bBigEndian)
1501 SwapWord(8, pabyRec + nRecordSize);
1502 nRecordSize += 8;
1503
1504 ByteCopy(&(psObject->dfMMax), pabyRec + nRecordSize, 8);
1505 if (bBigEndian)
1506 SwapWord(8, pabyRec + nRecordSize);
1507 nRecordSize += 8;
1508
1509 for (int i = 0; i < psObject->nVertices; i++) {
1510 ByteCopy(psObject->padfM + i, pabyRec + nRecordSize, 8);
1511 if (bBigEndian)
1512 SwapWord(8, pabyRec + nRecordSize);
1513 nRecordSize += 8;
1514 }
1515 }
1516 }
1517
1518 /* -------------------------------------------------------------------- */
1519 /* Write point. */
1520 /* -------------------------------------------------------------------- */
1521 else if (psObject->nSHPType == SHPT_POINT ||
1522 psObject->nSHPType == SHPT_POINTZ ||
1523 psObject->nSHPType == SHPT_POINTM) {
1524 ByteCopy(psObject->padfX, pabyRec + 12, 8);
1525 ByteCopy(psObject->padfY, pabyRec + 20, 8);
1526
1527 if (bBigEndian)
1528 SwapWord(8, pabyRec + 12);
1529 if (bBigEndian)
1530 SwapWord(8, pabyRec + 20);
1531
1532 nRecordSize = 28;
1533
1534 if (psObject->nSHPType == SHPT_POINTZ) {
1535 ByteCopy(psObject->padfZ, pabyRec + nRecordSize, 8);
1536 if (bBigEndian)
1537 SwapWord(8, pabyRec + nRecordSize);
1538 nRecordSize += 8;
1539 }
1540
1541 if (psObject->bMeasureIsUsed && (psObject->nSHPType == SHPT_POINTZ ||
1542 psObject->nSHPType == SHPT_POINTM)) {
1543 ByteCopy(psObject->padfM, pabyRec + nRecordSize, 8);
1544 if (bBigEndian)
1545 SwapWord(8, pabyRec + nRecordSize);
1546 nRecordSize += 8;
1547 }
1548 }
1549
1550 /* -------------------------------------------------------------------- */
1551 /* Not much to do for null geometries. */
1552 /* -------------------------------------------------------------------- */
1553 else if (psObject->nSHPType == SHPT_NULL) {
1554 nRecordSize = 12;
1555 }
1556 else {
1557 /* unknown type */
1558 assert(false);
1559 }
1560
1561 /* -------------------------------------------------------------------- */
1562 /* Establish where we are going to put this record. If we are */
1563 /* rewriting the last record of the file, then we can update it in */
1564 /* place. Otherwise if rewriting an existing record, and it will */
1565 /* fit, then put it back where the original came from. Otherwise */
1566 /* write at the end. */
1567 /* -------------------------------------------------------------------- */
1568 SAOffset nRecordOffset;
1569 bool bAppendToLastRecord = false;
1570 bool bAppendToFile = false;
1571 if (nShapeId != -1 &&
1572 psSHP->panRecOffset[nShapeId] + psSHP->panRecSize[nShapeId] + 8 ==
1573 psSHP->nFileSize) {
1574 nRecordOffset = psSHP->panRecOffset[nShapeId];
1575 bAppendToLastRecord = true;
1576 }
1577 else if (nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize - 8) {
1578 if (psSHP->nFileSize > UINT_MAX - nRecordSize) {
1579 char str[255];
1580 snprintf(str, sizeof(str),
1581 "Failed to write shape object. "
1582 "The maximum file size of %u has been reached. "
1583 "The current record of size %u cannot be added.",
1584 psSHP->nFileSize, nRecordSize);
1585 str[sizeof(str) - 1] = '\0';
1586 psSHP->sHooks.Error(str);
1587 free(pabyRec);
1588 return -1;
1589 }
1590
1591 bAppendToFile = true;
1592 nRecordOffset = psSHP->nFileSize;
1593 }
1594 else {
1595 nRecordOffset = psSHP->panRecOffset[nShapeId];
1596 }
1597
1598 /* -------------------------------------------------------------------- */
1599 /* Set the shape type, record number, and record size. */
1600 /* -------------------------------------------------------------------- */
1601 int32 i32 =
1602 (nShapeId < 0) ? psSHP->nRecords + 1 : nShapeId + 1; /* record # */
1603 if (!bBigEndian)
1604 SwapWord(4, &i32);
1605 ByteCopy(&i32, pabyRec, 4);
1606
1607 i32 = (nRecordSize - 8) / 2; /* record size */
1608 if (!bBigEndian)
1609 SwapWord(4, &i32);
1610 ByteCopy(&i32, pabyRec + 4, 4);
1611
1612 i32 = psObject->nSHPType; /* shape type */
1613 if (bBigEndian)
1614 SwapWord(4, &i32);
1615 ByteCopy(&i32, pabyRec + 8, 4);
1616
1617 /* -------------------------------------------------------------------- */
1618 /* Write out record. */
1619 /* -------------------------------------------------------------------- */
1620
1621 /* -------------------------------------------------------------------- */
1622 /* Guard FSeek with check for whether we're already at position; */
1623 /* no-op FSeeks defeat network filesystems' write buffering. */
1624 /* -------------------------------------------------------------------- */
1625 if (psSHP->sHooks.FTell(psSHP->fpSHP) != nRecordOffset) {
1626 if (psSHP->sHooks.FSeek(psSHP->fpSHP, nRecordOffset, 0) != 0) {
1627 char szErrorMsg[200];
1628
1629 snprintf(szErrorMsg, sizeof(szErrorMsg),
1630 "Error in psSHP->sHooks.FSeek() while writing object to "
1631 ".shp file: %s",
1632 strerror(errno));
1633 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
1634 psSHP->sHooks.Error(szErrorMsg);
1635
1636 free(pabyRec);
1637 return -1;
1638 }
1639 }
1640 if (psSHP->sHooks.FWrite(pabyRec, nRecordSize, 1, psSHP->fpSHP) < 1) {
1641 char szErrorMsg[200];
1642
1643 snprintf(szErrorMsg, sizeof(szErrorMsg),
1644 "Error in psSHP->sHooks.FWrite() while writing object of %u "
1645 "bytes to .shp file: %s",
1646 nRecordSize, strerror(errno));
1647 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
1648 psSHP->sHooks.Error(szErrorMsg);
1649
1650 free(pabyRec);
1651 return -1;
1652 }
1653
1654 free(pabyRec);
1655
1656 if (bAppendToLastRecord) {
1657 psSHP->nFileSize = psSHP->panRecOffset[nShapeId] + nRecordSize;
1658 }
1659 else if (bAppendToFile) {
1660 if (nShapeId == -1)
1661 nShapeId = psSHP->nRecords++;
1662
1663 psSHP->panRecOffset[nShapeId] = psSHP->nFileSize;
1664 psSHP->nFileSize += nRecordSize;
1665 }
1666 psSHP->panRecSize[nShapeId] = nRecordSize - 8;
1667
1668 /* -------------------------------------------------------------------- */
1669 /* Expand file wide bounds based on this shape. */
1670 /* -------------------------------------------------------------------- */
1671 if (bFirstFeature) {
1672 if (psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0) {
1673 psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
1674 psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
1675 psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
1676 psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
1677 }
1678 else {
1679 psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
1680 psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
1681 psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] =
1682 psObject->padfZ ? psObject->padfZ[0] : 0.0;
1683 psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] =
1684 psObject->padfM ? psObject->padfM[0] : 0.0;
1685 }
1686 }
1687
1688 for (int i = 0; i < psObject->nVertices; i++) {
1689 psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0], psObject->padfX[i]);
1690 psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1], psObject->padfY[i]);
1691 psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0], psObject->padfX[i]);
1692 psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1], psObject->padfY[i]);
1693 if (psObject->padfZ) {
1694 psSHP->adBoundsMin[2] =
1695 MIN(psSHP->adBoundsMin[2], psObject->padfZ[i]);
1696 psSHP->adBoundsMax[2] =
1697 MAX(psSHP->adBoundsMax[2], psObject->padfZ[i]);
1698 }
1699 if (psObject->padfM) {
1700 psSHP->adBoundsMin[3] =
1701 MIN(psSHP->adBoundsMin[3], psObject->padfM[i]);
1702 psSHP->adBoundsMax[3] =
1703 MAX(psSHP->adBoundsMax[3], psObject->padfM[i]);
1704 }
1705 }
1706
1707 return (nShapeId);
1708}
1709
1710/************************************************************************/
1711/* SHPAllocBuffer() */
1712/************************************************************************/
1713
1714static void *SHPAllocBuffer(unsigned char **pBuffer, int nSize)
1715{
1716 if (pBuffer == SHPLIB_NULLPTR)
1717 return calloc(1, nSize);
1718
1719 unsigned char *pRet = *pBuffer;
1720 if (pRet == SHPLIB_NULLPTR)
1721 return SHPLIB_NULLPTR;
1722
1723 (*pBuffer) += nSize;
1724 return pRet;
1725}
1726
1727/************************************************************************/
1728/* SHPReallocObjectBufIfNecessary() */
1729/************************************************************************/
1730
1731static unsigned char *SHPReallocObjectBufIfNecessary(SHPHandle psSHP,
1732 int nObjectBufSize)
1733{
1734 if (nObjectBufSize == 0) {
1735 nObjectBufSize = 4 * sizeof(double);
1736 }
1737
1738 unsigned char *pBuffer;
1739 if (nObjectBufSize > psSHP->nObjectBufSize) {
1740 pBuffer = STATIC_CAST(unsigned char *,
1741 realloc(psSHP->pabyObjectBuf, nObjectBufSize));
1742 if (pBuffer != SHPLIB_NULLPTR) {
1743 psSHP->pabyObjectBuf = pBuffer;
1744 psSHP->nObjectBufSize = nObjectBufSize;
1745 }
1746 }
1747 else {
1748 pBuffer = psSHP->pabyObjectBuf;
1749 }
1750
1751 return pBuffer;
1752}
1753
1754/************************************************************************/
1755/* SHPReadObject() */
1756/* */
1757/* Read the vertices, parts, and other non-attribute information */
1758/* for one shape. */
1759/************************************************************************/
1760
1762{
1763 /* -------------------------------------------------------------------- */
1764 /* Validate the record/entity number. */
1765 /* -------------------------------------------------------------------- */
1766 if (hEntity < 0 || hEntity >= psSHP->nRecords)
1767 return SHPLIB_NULLPTR;
1768
1769 /* -------------------------------------------------------------------- */
1770 /* Read offset/length from SHX loading if necessary. */
1771 /* -------------------------------------------------------------------- */
1772 if (psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != SHPLIB_NULLPTR) {
1773 unsigned int nOffset;
1774 unsigned int nLength;
1775
1776 if (psSHP->sHooks.FSeek(psSHP->fpSHX, 100 + 8 * hEntity, 0) != 0 ||
1777 psSHP->sHooks.FRead(&nOffset, 1, 4, psSHP->fpSHX) != 4 ||
1778 psSHP->sHooks.FRead(&nLength, 1, 4, psSHP->fpSHX) != 4) {
1779 char str[128];
1780 snprintf(str, sizeof(str),
1781 "Error in fseek()/fread() reading object from .shx file "
1782 "at offset %d",
1783 100 + 8 * hEntity);
1784 str[sizeof(str) - 1] = '\0';
1785
1786 psSHP->sHooks.Error(str);
1787 return SHPLIB_NULLPTR;
1788 }
1789 if (!bBigEndian)
1790 SwapWord(4, &nOffset);
1791 if (!bBigEndian)
1792 SwapWord(4, &nLength);
1793
1794 if (nOffset > STATIC_CAST(unsigned int, INT_MAX)) {
1795 char str[128];
1796 snprintf(str, sizeof(str), "Invalid offset for entity %d", hEntity);
1797 str[sizeof(str) - 1] = '\0';
1798
1799 psSHP->sHooks.Error(str);
1800 return SHPLIB_NULLPTR;
1801 }
1802 if (nLength > STATIC_CAST(unsigned int, INT_MAX / 2 - 4)) {
1803 char str[128];
1804 snprintf(str, sizeof(str), "Invalid length for entity %d", hEntity);
1805 str[sizeof(str) - 1] = '\0';
1806
1807 psSHP->sHooks.Error(str);
1808 return SHPLIB_NULLPTR;
1809 }
1810
1811 psSHP->panRecOffset[hEntity] = nOffset * 2;
1812 psSHP->panRecSize[hEntity] = nLength * 2;
1813 }
1814
1815 /* -------------------------------------------------------------------- */
1816 /* Ensure our record buffer is large enough. */
1817 /* -------------------------------------------------------------------- */
1818 const int nEntitySize = psSHP->panRecSize[hEntity] + 8;
1819 if (nEntitySize > psSHP->nBufSize) {
1820 int nNewBufSize = nEntitySize;
1821 if (nNewBufSize < INT_MAX - nNewBufSize / 3)
1822 nNewBufSize += nNewBufSize / 3;
1823 else
1824 nNewBufSize = INT_MAX;
1825
1826 /* Before allocating too much memory, check that the file is big enough
1827 */
1828 /* and do not trust the file size in the header the first time we */
1829 /* need to allocate more than 10 MB */
1830 if (nNewBufSize >= 10 * 1024 * 1024) {
1831 if (psSHP->nBufSize < 10 * 1024 * 1024) {
1832 SAOffset nFileSize;
1833 psSHP->sHooks.FSeek(psSHP->fpSHP, 0, 2);
1834 nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
1835 if (nFileSize >= UINT_MAX)
1836 psSHP->nFileSize = UINT_MAX;
1837 else
1838 psSHP->nFileSize = STATIC_CAST(unsigned int, nFileSize);
1839 }
1840
1841 if (psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
1842 /* We should normally use nEntitySize instead of*/
1843 /* psSHP->panRecSize[hEntity] in the below test, but because of
1844 */
1845 /* the case of non conformant .shx files detailed a bit below,
1846 */
1847 /* let be more tolerant */
1848 psSHP->panRecSize[hEntity] >
1849 psSHP->nFileSize - psSHP->panRecOffset[hEntity]) {
1850 char str[128];
1851 snprintf(str, sizeof(str),
1852 "Error in fread() reading object of size %d at offset "
1853 "%u from .shp file",
1854 nEntitySize, psSHP->panRecOffset[hEntity]);
1855 str[sizeof(str) - 1] = '\0';
1856
1857 psSHP->sHooks.Error(str);
1858 return SHPLIB_NULLPTR;
1859 }
1860 }
1861
1862 uchar *pabyRecNew =
1863 STATIC_CAST(uchar *, SfRealloc(psSHP->pabyRec, nNewBufSize));
1864 if (pabyRecNew == SHPLIB_NULLPTR) {
1865 char szErrorMsg[160];
1866 snprintf(szErrorMsg, sizeof(szErrorMsg),
1867 "Not enough memory to allocate requested memory "
1868 "(nNewBufSize=%d). "
1869 "Probably broken SHP file",
1870 nNewBufSize);
1871 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
1872 psSHP->sHooks.Error(szErrorMsg);
1873 return SHPLIB_NULLPTR;
1874 }
1875
1876 /* Only set new buffer size after successful alloc */
1877 psSHP->pabyRec = pabyRecNew;
1878 psSHP->nBufSize = nNewBufSize;
1879 }
1880
1881 /* In case we were not able to reallocate the buffer on a previous step */
1882 if (psSHP->pabyRec == SHPLIB_NULLPTR) {
1883 return SHPLIB_NULLPTR;
1884 }
1885
1886 /* -------------------------------------------------------------------- */
1887 /* Read the record. */
1888 /* -------------------------------------------------------------------- */
1889 if (psSHP->sHooks.FSeek(psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0) !=
1890 0) {
1891 /*
1892 * TODO - mloskot: Consider detailed diagnostics of shape file,
1893 * for example to detect if file is truncated.
1894 */
1895 char str[128];
1896 snprintf(str, sizeof(str),
1897 "Error in fseek() reading object from .shp file at offset %u",
1898 psSHP->panRecOffset[hEntity]);
1899 str[sizeof(str) - 1] = '\0';
1900
1901 psSHP->sHooks.Error(str);
1902 return SHPLIB_NULLPTR;
1903 }
1904
1906 int, psSHP->sHooks.FRead(psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP));
1907
1908 /* Special case for a shapefile whose .shx content length field is not equal
1909 */
1910 /* to the content length field of the .shp, which is a violation of "The */
1911 /* content length stored in the index record is the same as the value stored
1912 * in the main */
1913 /* file record header."
1914 * (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
1915 /* Actually in that case the .shx content length is equal to the .shp
1916 * content length + */
1917 /* 4 (16 bit words), representing the 8 bytes of the record header... */
1919 /* Do a sanity check */
1920 int nSHPContentLength;
1921 memcpy(&nSHPContentLength, psSHP->pabyRec + 4, 4);
1922 if (!bBigEndian)
1923 SwapWord(4, &(nSHPContentLength));
1924 if (nSHPContentLength < 0 || nSHPContentLength > INT_MAX / 2 - 4 ||
1925 2 * nSHPContentLength + 8 != nBytesRead) {
1926 char str[128];
1927 snprintf(str, sizeof(str),
1928 "Sanity check failed when trying to recover from "
1929 "inconsistent .shx/.shp with shape %d",
1930 hEntity);
1931 str[sizeof(str) - 1] = '\0';
1932
1933 psSHP->sHooks.Error(str);
1934 return SHPLIB_NULLPTR;
1935 }
1936 }
1938 /*
1939 * TODO - mloskot: Consider detailed diagnostics of shape file,
1940 * for example to detect if file is truncated.
1941 */
1942 char str[128];
1943 snprintf(str, sizeof(str),
1944 "Error in fread() reading object of size %d at offset %u from "
1945 ".shp file",
1946 nEntitySize, psSHP->panRecOffset[hEntity]);
1947 str[sizeof(str) - 1] = '\0';
1948
1949 psSHP->sHooks.Error(str);
1950 return SHPLIB_NULLPTR;
1951 }
1952
1953 if (8 + 4 > nEntitySize) {
1954 char szErrorMsg[160];
1955 snprintf(szErrorMsg, sizeof(szErrorMsg),
1956 "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity,
1957 nEntitySize);
1958 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
1959 psSHP->sHooks.Error(szErrorMsg);
1960 return SHPLIB_NULLPTR;
1961 }
1962 int nSHPType;
1963 memcpy(&nSHPType, psSHP->pabyRec + 8, 4);
1964
1965 if (bBigEndian)
1966 SwapWord(4, &(nSHPType));
1967
1968 /* -------------------------------------------------------------------- */
1969 /* Allocate and minimally initialize the object. */
1970 /* -------------------------------------------------------------------- */
1971 SHPObject *psShape;
1972 if (psSHP->bFastModeReadObject) {
1973 if (psSHP->psCachedObject->bFastModeReadObject) {
1974 psSHP->sHooks.Error("Invalid read pattern in fast read mode. "
1975 "SHPDestroyObject() should be called.");
1976 return SHPLIB_NULLPTR;
1977 }
1978
1979 psShape = psSHP->psCachedObject;
1980 memset(psShape, 0, sizeof(SHPObject));
1981 }
1982 else {
1983 psShape = STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject)));
1984 }
1985 psShape->nShapeId = hEntity;
1986 psShape->nSHPType = nSHPType;
1987 psShape->bMeasureIsUsed = FALSE;
1989
1990 /* ==================================================================== */
1991 /* Extract vertices for a Polygon or Arc. */
1992 /* ==================================================================== */
1993 if (psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC ||
1994 psShape->nSHPType == SHPT_POLYGONZ ||
1995 psShape->nSHPType == SHPT_POLYGONM || psShape->nSHPType == SHPT_ARCZ ||
1996 psShape->nSHPType == SHPT_ARCM ||
1997 psShape->nSHPType == SHPT_MULTIPATCH) {
1998 if (40 + 8 + 4 > nEntitySize) {
1999 char szErrorMsg[160];
2000 snprintf(szErrorMsg, sizeof(szErrorMsg),
2001 "Corrupted .shp file : shape %d : nEntitySize = %d",
2002 hEntity, nEntitySize);
2003 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2004 psSHP->sHooks.Error(szErrorMsg);
2005 SHPDestroyObject(psShape);
2006 return SHPLIB_NULLPTR;
2007 }
2008 /* --------------------------------------------------------------------
2009 */
2010 /* Get the X/Y bounds. */
2011 /* --------------------------------------------------------------------
2012 */
2013 memcpy(&(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8);
2014 memcpy(&(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8);
2015 memcpy(&(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8);
2016 memcpy(&(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8);
2017
2018 if (bBigEndian)
2019 SwapWord(8, &(psShape->dfXMin));
2020 if (bBigEndian)
2021 SwapWord(8, &(psShape->dfYMin));
2022 if (bBigEndian)
2023 SwapWord(8, &(psShape->dfXMax));
2024 if (bBigEndian)
2025 SwapWord(8, &(psShape->dfYMax));
2026
2027 /* --------------------------------------------------------------------
2028 */
2029 /* Extract part/point count, and build vertex and part arrays */
2030 /* to proper size. */
2031 /* --------------------------------------------------------------------
2032 */
2033 int32 nPoints;
2034 memcpy(&nPoints, psSHP->pabyRec + 40 + 8, 4);
2035 int32 nParts;
2036 memcpy(&nParts, psSHP->pabyRec + 36 + 8, 4);
2037
2038 if (bBigEndian)
2039 SwapWord(4, &nPoints);
2040 if (bBigEndian)
2041 SwapWord(4, &nParts);
2042
2043 /* nPoints and nParts are unsigned */
2044 if (/* nPoints < 0 || nParts < 0 || */
2045 nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000) {
2046 char szErrorMsg[160];
2047 snprintf(szErrorMsg, sizeof(szErrorMsg),
2048 "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u.",
2049 hEntity, nPoints, nParts);
2050 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2051 psSHP->sHooks.Error(szErrorMsg);
2052 SHPDestroyObject(psShape);
2053 return SHPLIB_NULLPTR;
2054 }
2055
2056 /* With the previous checks on nPoints and nParts, */
2057 /* we should not overflow here and after */
2058 /* since 50 M * (16 + 8 + 8) = 1 600 MB */
2059 int nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
2060 if (psShape->nSHPType == SHPT_POLYGONZ ||
2061 psShape->nSHPType == SHPT_ARCZ ||
2062 psShape->nSHPType == SHPT_MULTIPATCH) {
2063 nRequiredSize += 16 + 8 * nPoints;
2064 }
2065 if (psShape->nSHPType == SHPT_MULTIPATCH) {
2066 nRequiredSize += 4 * nParts;
2067 }
2068 if (nRequiredSize > nEntitySize) {
2069 char szErrorMsg[160];
2070 snprintf(szErrorMsg, sizeof(szErrorMsg),
2071 "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u, "
2072 "nEntitySize=%d.",
2073 hEntity, nPoints, nParts, nEntitySize);
2074 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2075 psSHP->sHooks.Error(szErrorMsg);
2076 SHPDestroyObject(psShape);
2077 return SHPLIB_NULLPTR;
2078 }
2079
2080 unsigned char *pBuffer = SHPLIB_NULLPTR;
2081 unsigned char **ppBuffer = SHPLIB_NULLPTR;
2082
2083 if (psShape->bFastModeReadObject) {
2084 const int nObjectBufSize =
2085 4 * sizeof(double) * nPoints + 2 * sizeof(int) * nParts;
2086 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2087 ppBuffer = &pBuffer;
2088 }
2089
2090 psShape->nVertices = nPoints;
2091 psShape->padfX = STATIC_CAST(
2092 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2093 psShape->padfY = STATIC_CAST(
2094 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2095 psShape->padfZ = STATIC_CAST(
2096 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2097 psShape->padfM = STATIC_CAST(
2098 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2099
2100 psShape->nParts = nParts;
2101 psShape->panPartStart =
2102 STATIC_CAST(int *, SHPAllocBuffer(ppBuffer, nParts * sizeof(int)));
2103 psShape->panPartType =
2104 STATIC_CAST(int *, SHPAllocBuffer(ppBuffer, nParts * sizeof(int)));
2105
2106 if (psShape->padfX == SHPLIB_NULLPTR ||
2107 psShape->padfY == SHPLIB_NULLPTR ||
2108 psShape->padfZ == SHPLIB_NULLPTR ||
2109 psShape->padfM == SHPLIB_NULLPTR ||
2110 psShape->panPartStart == SHPLIB_NULLPTR ||
2111 psShape->panPartType == SHPLIB_NULLPTR) {
2112 char szErrorMsg[160];
2113 snprintf(szErrorMsg, sizeof(szErrorMsg),
2114 "Not enough memory to allocate requested memory "
2115 "(nPoints=%u, nParts=%u) for shape %d. "
2116 "Probably broken SHP file",
2117 nPoints, nParts, hEntity);
2118 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2119 psSHP->sHooks.Error(szErrorMsg);
2120 SHPDestroyObject(psShape);
2121 return SHPLIB_NULLPTR;
2122 }
2123
2124 for (int i = 0; STATIC_CAST(int32, i) < nParts; i++)
2125 psShape->panPartType[i] = SHPP_RING;
2126
2127 /* --------------------------------------------------------------------
2128 */
2129 /* Copy out the part array from the record. */
2130 /* --------------------------------------------------------------------
2131 */
2132 memcpy(psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts);
2133 for (int i = 0; STATIC_CAST(int32, i) < nParts; i++) {
2134 if (bBigEndian)
2135 SwapWord(4, psShape->panPartStart + i);
2136
2137 /* We check that the offset is inside the vertex array */
2138 if (psShape->panPartStart[i] < 0 ||
2139 (psShape->panPartStart[i] >= psShape->nVertices &&
2140 psShape->nVertices > 0) ||
2141 (psShape->panPartStart[i] > 0 && psShape->nVertices == 0)) {
2142 char szErrorMsg[160];
2143 snprintf(szErrorMsg, sizeof(szErrorMsg),
2144 "Corrupted .shp file : shape %d : panPartStart[%d] = "
2145 "%d, nVertices = %d",
2146 hEntity, i, psShape->panPartStart[i],
2147 psShape->nVertices);
2148 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2149 psSHP->sHooks.Error(szErrorMsg);
2150 SHPDestroyObject(psShape);
2151 return SHPLIB_NULLPTR;
2152 }
2153 if (i > 0 &&
2154 psShape->panPartStart[i] <= psShape->panPartStart[i - 1]) {
2155 char szErrorMsg[160];
2156 snprintf(szErrorMsg, sizeof(szErrorMsg),
2157 "Corrupted .shp file : shape %d : panPartStart[%d] = "
2158 "%d, panPartStart[%d] = %d",
2159 hEntity, i, psShape->panPartStart[i], i - 1,
2160 psShape->panPartStart[i - 1]);
2161 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2162 psSHP->sHooks.Error(szErrorMsg);
2163 SHPDestroyObject(psShape);
2164 return SHPLIB_NULLPTR;
2165 }
2166 }
2167
2168 int nOffset = 44 + 8 + 4 * nParts;
2169
2170 /* --------------------------------------------------------------------
2171 */
2172 /* If this is a multipatch, we will also have parts types. */
2173 /* --------------------------------------------------------------------
2174 */
2175 if (psShape->nSHPType == SHPT_MULTIPATCH) {
2176 memcpy(psShape->panPartType, psSHP->pabyRec + nOffset, 4 * nParts);
2177 for (int i = 0; STATIC_CAST(int32, i) < nParts; i++) {
2178 if (bBigEndian)
2179 SwapWord(4, psShape->panPartType + i);
2180 }
2181
2182 nOffset += 4 * nParts;
2183 }
2184
2185 /* --------------------------------------------------------------------
2186 */
2187 /* Copy out the vertices from the record. */
2188 /* --------------------------------------------------------------------
2189 */
2190 for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) {
2191 memcpy(psShape->padfX + i, psSHP->pabyRec + nOffset + i * 16, 8);
2192
2193 memcpy(psShape->padfY + i, psSHP->pabyRec + nOffset + i * 16 + 8,
2194 8);
2195
2196 if (bBigEndian)
2197 SwapWord(8, psShape->padfX + i);
2198 if (bBigEndian)
2199 SwapWord(8, psShape->padfY + i);
2200 }
2201
2202 nOffset += 16 * nPoints;
2203
2204 /* --------------------------------------------------------------------
2205 */
2206 /* If we have a Z coordinate, collect that now. */
2207 /* --------------------------------------------------------------------
2208 */
2209 if (psShape->nSHPType == SHPT_POLYGONZ ||
2210 psShape->nSHPType == SHPT_ARCZ ||
2211 psShape->nSHPType == SHPT_MULTIPATCH) {
2212 memcpy(&(psShape->dfZMin), psSHP->pabyRec + nOffset, 8);
2213 memcpy(&(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8);
2214
2215 if (bBigEndian)
2216 SwapWord(8, &(psShape->dfZMin));
2217 if (bBigEndian)
2218 SwapWord(8, &(psShape->dfZMax));
2219
2220 for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) {
2221 memcpy(psShape->padfZ + i,
2222 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2223 if (bBigEndian)
2224 SwapWord(8, psShape->padfZ + i);
2225 }
2226
2227 nOffset += 16 + 8 * nPoints;
2228 }
2229 else if (psShape->bFastModeReadObject) {
2230 psShape->padfZ = SHPLIB_NULLPTR;
2231 }
2232
2233 /* --------------------------------------------------------------------
2234 */
2235 /* If we have a M measure value, then read it now. We assume */
2236 /* that the measure can be present for any shape if the size is */
2237 /* big enough, but really it will only occur for the Z shapes */
2238 /* (options), and the M shapes. */
2239 /* --------------------------------------------------------------------
2240 */
2241 if (nEntitySize >= STATIC_CAST(int, nOffset + 16 + 8 * nPoints)) {
2242 memcpy(&(psShape->dfMMin), psSHP->pabyRec + nOffset, 8);
2243 memcpy(&(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8);
2244
2245 if (bBigEndian)
2246 SwapWord(8, &(psShape->dfMMin));
2247 if (bBigEndian)
2248 SwapWord(8, &(psShape->dfMMax));
2249
2250 for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) {
2251 memcpy(psShape->padfM + i,
2252 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2253 if (bBigEndian)
2254 SwapWord(8, psShape->padfM + i);
2255 }
2256 psShape->bMeasureIsUsed = TRUE;
2257 }
2258 else if (psShape->bFastModeReadObject) {
2259 psShape->padfM = SHPLIB_NULLPTR;
2260 }
2261 }
2262
2263 /* ==================================================================== */
2264 /* Extract vertices for a MultiPoint. */
2265 /* ==================================================================== */
2266 else if (psShape->nSHPType == SHPT_MULTIPOINT ||
2267 psShape->nSHPType == SHPT_MULTIPOINTM ||
2268 psShape->nSHPType == SHPT_MULTIPOINTZ) {
2269 if (44 + 4 > nEntitySize) {
2270 char szErrorMsg[160];
2271 snprintf(szErrorMsg, sizeof(szErrorMsg),
2272 "Corrupted .shp file : shape %d : nEntitySize = %d",
2273 hEntity, nEntitySize);
2274 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2275 psSHP->sHooks.Error(szErrorMsg);
2276 SHPDestroyObject(psShape);
2277 return SHPLIB_NULLPTR;
2278 }
2279 int32 nPoints;
2280 memcpy(&nPoints, psSHP->pabyRec + 44, 4);
2281
2282 if (bBigEndian)
2283 SwapWord(4, &nPoints);
2284
2285 /* nPoints is unsigned */
2286 if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000) {
2287 char szErrorMsg[160];
2288 snprintf(szErrorMsg, sizeof(szErrorMsg),
2289 "Corrupted .shp file : shape %d : nPoints = %u", hEntity,
2290 nPoints);
2291 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2292 psSHP->sHooks.Error(szErrorMsg);
2293 SHPDestroyObject(psShape);
2294 return SHPLIB_NULLPTR;
2295 }
2296
2297 int nRequiredSize = 48 + nPoints * 16;
2298 if (psShape->nSHPType == SHPT_MULTIPOINTZ) {
2299 nRequiredSize += 16 + nPoints * 8;
2300 }
2301 if (nRequiredSize > nEntitySize) {
2302 char szErrorMsg[160];
2303 snprintf(szErrorMsg, sizeof(szErrorMsg),
2304 "Corrupted .shp file : shape %d : nPoints = %u, "
2305 "nEntitySize = %d",
2306 hEntity, nPoints, nEntitySize);
2307 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2308 psSHP->sHooks.Error(szErrorMsg);
2309 SHPDestroyObject(psShape);
2310 return SHPLIB_NULLPTR;
2311 }
2312
2313 unsigned char *pBuffer = SHPLIB_NULLPTR;
2314 unsigned char **ppBuffer = SHPLIB_NULLPTR;
2315
2316 if (psShape->bFastModeReadObject) {
2317 const int nObjectBufSize = 4 * sizeof(double) * nPoints;
2318 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2319 ppBuffer = &pBuffer;
2320 }
2321
2322 psShape->nVertices = nPoints;
2323
2324 psShape->padfX = STATIC_CAST(
2325 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2326 psShape->padfY = STATIC_CAST(
2327 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2328 psShape->padfZ = STATIC_CAST(
2329 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2330 psShape->padfM = STATIC_CAST(
2331 double *, SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints));
2332
2333 if (psShape->padfX == SHPLIB_NULLPTR ||
2334 psShape->padfY == SHPLIB_NULLPTR ||
2335 psShape->padfZ == SHPLIB_NULLPTR ||
2336 psShape->padfM == SHPLIB_NULLPTR) {
2337 char szErrorMsg[160];
2338 snprintf(szErrorMsg, sizeof(szErrorMsg),
2339 "Not enough memory to allocate requested memory "
2340 "(nPoints=%u) for shape %d. "
2341 "Probably broken SHP file",
2342 nPoints, hEntity);
2343 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2344 psSHP->sHooks.Error(szErrorMsg);
2345 SHPDestroyObject(psShape);
2346 return SHPLIB_NULLPTR;
2347 }
2348
2349 for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) {
2350 memcpy(psShape->padfX + i, psSHP->pabyRec + 48 + 16 * i, 8);
2351 memcpy(psShape->padfY + i, psSHP->pabyRec + 48 + 16 * i + 8, 8);
2352
2353 if (bBigEndian)
2354 SwapWord(8, psShape->padfX + i);
2355 if (bBigEndian)
2356 SwapWord(8, psShape->padfY + i);
2357 }
2358
2359 int nOffset = 48 + 16 * nPoints;
2360
2361 /* --------------------------------------------------------------------
2362 */
2363 /* Get the X/Y bounds. */
2364 /* --------------------------------------------------------------------
2365 */
2366 memcpy(&(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8);
2367 memcpy(&(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8);
2368 memcpy(&(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8);
2369 memcpy(&(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8);
2370
2371 if (bBigEndian)
2372 SwapWord(8, &(psShape->dfXMin));
2373 if (bBigEndian)
2374 SwapWord(8, &(psShape->dfYMin));
2375 if (bBigEndian)
2376 SwapWord(8, &(psShape->dfXMax));
2377 if (bBigEndian)
2378 SwapWord(8, &(psShape->dfYMax));
2379
2380 /* --------------------------------------------------------------------
2381 */
2382 /* If we have a Z coordinate, collect that now. */
2383 /* --------------------------------------------------------------------
2384 */
2385 if (psShape->nSHPType == SHPT_MULTIPOINTZ) {
2386 memcpy(&(psShape->dfZMin), psSHP->pabyRec + nOffset, 8);
2387 memcpy(&(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8);
2388
2389 if (bBigEndian)
2390 SwapWord(8, &(psShape->dfZMin));
2391 if (bBigEndian)
2392 SwapWord(8, &(psShape->dfZMax));
2393
2394 for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) {
2395 memcpy(psShape->padfZ + i,
2396 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2397 if (bBigEndian)
2398 SwapWord(8, psShape->padfZ + i);
2399 }
2400
2401 nOffset += 16 + 8 * nPoints;
2402 }
2403 else if (psShape->bFastModeReadObject)
2404 psShape->padfZ = SHPLIB_NULLPTR;
2405
2406 /* --------------------------------------------------------------------
2407 */
2408 /* If we have a M measure value, then read it now. We assume */
2409 /* that the measure can be present for any shape if the size is */
2410 /* big enough, but really it will only occur for the Z shapes */
2411 /* (options), and the M shapes. */
2412 /* --------------------------------------------------------------------
2413 */
2414 if (nEntitySize >= STATIC_CAST(int, nOffset + 16 + 8 * nPoints)) {
2415 memcpy(&(psShape->dfMMin), psSHP->pabyRec + nOffset, 8);
2416 memcpy(&(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8);
2417
2418 if (bBigEndian)
2419 SwapWord(8, &(psShape->dfMMin));
2420 if (bBigEndian)
2421 SwapWord(8, &(psShape->dfMMax));
2422
2423 for (int i = 0; STATIC_CAST(int32, i) < nPoints; i++) {
2424 memcpy(psShape->padfM + i,
2425 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2426 if (bBigEndian)
2427 SwapWord(8, psShape->padfM + i);
2428 }
2429 psShape->bMeasureIsUsed = TRUE;
2430 }
2431 else if (psShape->bFastModeReadObject)
2432 psShape->padfM = SHPLIB_NULLPTR;
2433 }
2434
2435 /* ==================================================================== */
2436 /* Extract vertices for a point. */
2437 /* ==================================================================== */
2438 else if (psShape->nSHPType == SHPT_POINT ||
2439 psShape->nSHPType == SHPT_POINTM ||
2440 psShape->nSHPType == SHPT_POINTZ) {
2441 psShape->nVertices = 1;
2442 if (psShape->bFastModeReadObject) {
2443 psShape->padfX = &(psShape->dfXMin);
2444 psShape->padfY = &(psShape->dfYMin);
2445 psShape->padfZ = &(psShape->dfZMin);
2446 psShape->padfM = &(psShape->dfMMin);
2447 psShape->padfZ[0] = 0.0;
2448 psShape->padfM[0] = 0.0;
2449 }
2450 else {
2451 psShape->padfX = STATIC_CAST(double *, calloc(1, sizeof(double)));
2452 psShape->padfY = STATIC_CAST(double *, calloc(1, sizeof(double)));
2453 psShape->padfZ = STATIC_CAST(double *, calloc(1, sizeof(double)));
2454 psShape->padfM = STATIC_CAST(double *, calloc(1, sizeof(double)));
2455 }
2456
2457 if (20 + 8 + ((psShape->nSHPType == SHPT_POINTZ) ? 8 : 0) >
2458 nEntitySize) {
2459 char szErrorMsg[160];
2460 snprintf(szErrorMsg, sizeof(szErrorMsg),
2461 "Corrupted .shp file : shape %d : nEntitySize = %d",
2462 hEntity, nEntitySize);
2463 szErrorMsg[sizeof(szErrorMsg) - 1] = '\0';
2464 psSHP->sHooks.Error(szErrorMsg);
2465 SHPDestroyObject(psShape);
2466 return SHPLIB_NULLPTR;
2467 }
2468 memcpy(psShape->padfX, psSHP->pabyRec + 12, 8);
2469 memcpy(psShape->padfY, psSHP->pabyRec + 20, 8);
2470
2471 if (bBigEndian)
2472 SwapWord(8, psShape->padfX);
2473 if (bBigEndian)
2474 SwapWord(8, psShape->padfY);
2475
2476 int nOffset = 20 + 8;
2477
2478 /* --------------------------------------------------------------------
2479 */
2480 /* If we have a Z coordinate, collect that now. */
2481 /* --------------------------------------------------------------------
2482 */
2483 if (psShape->nSHPType == SHPT_POINTZ) {
2484 memcpy(psShape->padfZ, psSHP->pabyRec + nOffset, 8);
2485
2486 if (bBigEndian)
2487 SwapWord(8, psShape->padfZ);
2488
2489 nOffset += 8;
2490 }
2491
2492 /* --------------------------------------------------------------------
2493 */
2494 /* If we have a M measure value, then read it now. We assume */
2495 /* that the measure can be present for any shape if the size is */
2496 /* big enough, but really it will only occur for the Z shapes */
2497 /* (options), and the M shapes. */
2498 /* --------------------------------------------------------------------
2499 */
2500 if (nEntitySize >= nOffset + 8) {
2501 memcpy(psShape->padfM, psSHP->pabyRec + nOffset, 8);
2502
2503 if (bBigEndian)
2504 SwapWord(8, psShape->padfM);
2505 psShape->bMeasureIsUsed = TRUE;
2506 }
2507
2508 /* --------------------------------------------------------------------
2509 */
2510 /* Since no extents are supplied in the record, we will apply */
2511 /* them from the single vertex. */
2512 /* --------------------------------------------------------------------
2513 */
2514 psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
2515 psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
2516 psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
2517 psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
2518 }
2519
2520 return (psShape);
2521}
2522
2523/************************************************************************/
2524/* SHPTypeName() */
2525/************************************************************************/
2526
2528{
2529 switch (nSHPType) {
2530 case SHPT_NULL:
2531 return "NullShape";
2532
2533 case SHPT_POINT:
2534 return "Point";
2535
2536 case SHPT_ARC:
2537 return "Arc";
2538
2539 case SHPT_POLYGON:
2540 return "Polygon";
2541
2542 case SHPT_MULTIPOINT:
2543 return "MultiPoint";
2544
2545 case SHPT_POINTZ:
2546 return "PointZ";
2547
2548 case SHPT_ARCZ:
2549 return "ArcZ";
2550
2551 case SHPT_POLYGONZ:
2552 return "PolygonZ";
2553
2554 case SHPT_MULTIPOINTZ:
2555 return "MultiPointZ";
2556
2557 case SHPT_POINTM:
2558 return "PointM";
2559
2560 case SHPT_ARCM:
2561 return "ArcM";
2562
2563 case SHPT_POLYGONM:
2564 return "PolygonM";
2565
2566 case SHPT_MULTIPOINTM:
2567 return "MultiPointM";
2568
2569 case SHPT_MULTIPATCH:
2570 return "MultiPatch";
2571
2572 default:
2573 return "UnknownShapeType";
2574 }
2575}
2576
2577/************************************************************************/
2578/* SHPPartTypeName() */
2579/************************************************************************/
2580
2581const char SHPAPI_CALL1(*) SHPPartTypeName(int nPartType)
2582{
2583 switch (nPartType) {
2584 case SHPP_TRISTRIP:
2585 return "TriangleStrip";
2586
2587 case SHPP_TRIFAN:
2588 return "TriangleFan";
2589
2590 case SHPP_OUTERRING:
2591 return "OuterRing";
2592
2593 case SHPP_INNERRING:
2594 return "InnerRing";
2595
2596 case SHPP_FIRSTRING:
2597 return "FirstRing";
2598
2599 case SHPP_RING:
2600 return "Ring";
2601
2602 default:
2603 return "UnknownPartType";
2604 }
2605}
2606
2607/************************************************************************/
2608/* SHPDestroyObject() */
2609/************************************************************************/
2610
2612{
2613 if (psShape == SHPLIB_NULLPTR)
2614 return;
2615
2616 if (psShape->bFastModeReadObject) {
2617 psShape->bFastModeReadObject = FALSE;
2618 return;
2619 }
2620
2621 if (psShape->padfX != SHPLIB_NULLPTR)
2622 free(psShape->padfX);
2623 if (psShape->padfY != SHPLIB_NULLPTR)
2624 free(psShape->padfY);
2625 if (psShape->padfZ != SHPLIB_NULLPTR)
2626 free(psShape->padfZ);
2627 if (psShape->padfM != SHPLIB_NULLPTR)
2628 free(psShape->padfM);
2629
2630 if (psShape->panPartStart != SHPLIB_NULLPTR)
2631 free(psShape->panPartStart);
2632 if (psShape->panPartType != SHPLIB_NULLPTR)
2633 free(psShape->panPartType);
2634
2635 free(psShape);
2636}
2637
2638/************************************************************************/
2639/* SHPGetPartVertexCount() */
2640/************************************************************************/
2641
2642static int SHPGetPartVertexCount(const SHPObject *psObject, int iPart)
2643{
2644 if (iPart == psObject->nParts - 1)
2645 return psObject->nVertices - psObject->panPartStart[iPart];
2646 else
2647 return psObject->panPartStart[iPart + 1] -
2648 psObject->panPartStart[iPart];
2649}
2650
2651/************************************************************************/
2652/* SHPRewindIsInnerRing() */
2653/************************************************************************/
2654
2655/* Return -1 in case of ambiguity */
2656static int SHPRewindIsInnerRing(const SHPObject *psObject, int iOpRing,
2657 double dfTestX, double dfTestY,
2658 double dfRelativeTolerance, int bSameZ,
2659 double dfTestZ)
2660{
2661 /* -------------------------------------------------------------------- */
2662 /* Determine if this ring is an inner ring or an outer ring */
2663 /* relative to all the other rings. For now we assume the */
2664 /* first ring is outer and all others are inner, but eventually */
2665 /* we need to fix this to handle multiple island polygons and */
2666 /* unordered sets of rings. */
2667 /* */
2668 /* -------------------------------------------------------------------- */
2669
2670 bool bInner = false;
2671 for (int iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++) {
2672 if (iCheckRing == iOpRing)
2673 continue;
2674
2675 const int nVertStartCheck = psObject->panPartStart[iCheckRing];
2676 const int nVertCountCheck = SHPGetPartVertexCount(psObject, iCheckRing);
2677
2678 /* Ignore rings that don't have the same (constant) Z value as the
2679 * point. */
2680 /* As noted in SHPRewindObject(), this is a simplification */
2681 /* of what we should ideally do. */
2682 if (!bSameZ) {
2683 int bZTestOK = TRUE;
2684 for (int iVert = nVertStartCheck + 1;
2685 iVert < nVertStartCheck + nVertCountCheck; ++iVert) {
2686 if (psObject->padfZ[iVert] != dfTestZ) {
2687 bZTestOK = FALSE;
2688 break;
2689 }
2690 }
2691 if (!bZTestOK)
2692 continue;
2693 }
2694
2695 for (int iEdge = 0; iEdge < nVertCountCheck; iEdge++) {
2696 int iNext;
2697 if (iEdge < nVertCountCheck - 1)
2698 iNext = iEdge + 1;
2699 else
2700 iNext = 0;
2701
2702 const double y0 = psObject->padfY[iEdge + nVertStartCheck];
2703 const double y1 = psObject->padfY[iNext + nVertStartCheck];
2704 /* Rule #1:
2705 * Test whether the edge 'straddles' the horizontal ray from
2706 * the test point (dfTestY,dfTestY)
2707 * The rule #1 also excludes edges colinear with the ray.
2708 */
2709 if ((y0 < dfTestY && dfTestY <= y1) ||
2710 (y1 < dfTestY && dfTestY <= y0)) {
2711 /* Rule #2:
2712 * Test if edge-ray intersection is on the right from the
2713 * test point (dfTestY,dfTestY)
2714 */
2715 const double x0 = psObject->padfX[iEdge + nVertStartCheck];
2716 const double x1 = psObject->padfX[iNext + nVertStartCheck];
2717 const double intersect_minus_testX =
2718 (x0 - dfTestX) + (dfTestY - y0) / (y1 - y0) * (x1 - x0);
2719
2720 if (fabs(intersect_minus_testX) <=
2721 dfRelativeTolerance * fabs(dfTestX)) {
2722 /* Potential shared edge, or slightly overlapping polygons
2723 */
2724 return -1;
2725 }
2726 else if (intersect_minus_testX < 0) {
2727 bInner = !bInner;
2728 }
2729 }
2730 }
2731 } /* for iCheckRing */
2732 return bInner;
2733}
2734
2735/************************************************************************/
2736/* SHPRewindObject() */
2737/* */
2738/* Reset the winding of polygon objects to adhere to the */
2739/* specification. */
2740/************************************************************************/
2741
2743{
2744 /* -------------------------------------------------------------------- */
2745 /* Do nothing if this is not a polygon object. */
2746 /* -------------------------------------------------------------------- */
2747 if (psObject->nSHPType != SHPT_POLYGON &&
2748 psObject->nSHPType != SHPT_POLYGONZ &&
2749 psObject->nSHPType != SHPT_POLYGONM)
2750 return 0;
2751
2752 if (psObject->nVertices == 0 || psObject->nParts == 0)
2753 return 0;
2754
2755 /* -------------------------------------------------------------------- */
2756 /* Test if all points have the same Z value. */
2757 /* -------------------------------------------------------------------- */
2758 int bSameZ = TRUE;
2759 if (psObject->nSHPType == SHPT_POLYGONZ ||
2760 psObject->nSHPType == SHPT_POLYGONM) {
2761 for (int iVert = 1; iVert < psObject->nVertices; ++iVert) {
2762 if (psObject->padfZ[iVert] != psObject->padfZ[0]) {
2763 bSameZ = FALSE;
2764 break;
2765 }
2766 }
2767 }
2768
2769 /* -------------------------------------------------------------------- */
2770 /* Process each of the rings. */
2771 /* -------------------------------------------------------------------- */
2772 int bAltered = 0;
2773 for (int iOpRing = 0; iOpRing < psObject->nParts; iOpRing++) {
2774 const int nVertStart = psObject->panPartStart[iOpRing];
2775 const int nVertCount = SHPGetPartVertexCount(psObject, iOpRing);
2776
2777 if (nVertCount < 2)
2778 continue;
2779
2780 /* If a ring has a non-constant Z value, then consider it as an outer */
2781 /* ring. */
2782 /* NOTE: this is a rough approximation. If we were smarter, */
2783 /* we would check that all points of the ring are coplanar, and compare
2784 */
2785 /* that to other rings in the same (oblique) plane. */
2786 int bDoIsInnerRingTest = TRUE;
2787 if (!bSameZ) {
2788 int bPartSameZ = TRUE;
2789 for (int iVert = nVertStart + 1; iVert < nVertStart + nVertCount;
2790 ++iVert) {
2791 if (psObject->padfZ[iVert] != psObject->padfZ[nVertStart]) {
2792 bPartSameZ = FALSE;
2793 break;
2794 }
2795 }
2796 if (!bPartSameZ)
2797 bDoIsInnerRingTest = FALSE;
2798 }
2799
2800 int bInner = FALSE;
2801 if (bDoIsInnerRingTest) {
2802 for (int iTolerance = 0; iTolerance < 2; iTolerance++) {
2803 /* In a first attempt, use a relaxed criterion to decide if a
2804 * point */
2805 /* is inside another ring. If all points of the current ring are
2806 * in the */
2807 /* "grey" zone w.r.t that criterion, which seems really
2808 * unlikely, */
2809 /* then use the strict criterion for another pass. */
2810 const double dfRelativeTolerance = (iTolerance == 0) ? 1e-9 : 0;
2811 for (int iVert = nVertStart;
2812 iVert + 1 < nVertStart + nVertCount; ++iVert) {
2813 /* Use point in the middle of segment to avoid testing
2814 * common points of rings.
2815 */
2816 const double dfTestX =
2817 (psObject->padfX[iVert] + psObject->padfX[iVert + 1]) /
2818 2;
2819 const double dfTestY =
2820 (psObject->padfY[iVert] + psObject->padfY[iVert + 1]) /
2821 2;
2822 const double dfTestZ =
2823 !bSameZ ? psObject->padfZ[nVertStart] : 0;
2824
2825 bInner = SHPRewindIsInnerRing(psObject, iOpRing, dfTestX,
2826 dfTestY, dfRelativeTolerance,
2827 bSameZ, dfTestZ);
2828 if (bInner >= 0)
2829 break;
2830 }
2831 if (bInner >= 0)
2832 break;
2833 }
2834 if (bInner < 0) {
2835 /* Completely degenerate case. Do not bother touching order. */
2836 continue;
2837 }
2838 }
2839
2840 /* --------------------------------------------------------------------
2841 */
2842 /* Determine the current order of this ring so we will know if */
2843 /* it has to be reversed. */
2844 /* --------------------------------------------------------------------
2845 */
2846
2847 double dfSum = psObject->padfX[nVertStart] *
2848 (psObject->padfY[nVertStart + 1] -
2849 psObject->padfY[nVertStart + nVertCount - 1]);
2850 int iVert = nVertStart + 1;
2851 for (; iVert < nVertStart + nVertCount - 1; iVert++) {
2852 dfSum += psObject->padfX[iVert] *
2853 (psObject->padfY[iVert + 1] - psObject->padfY[iVert - 1]);
2854 }
2855
2856 dfSum += psObject->padfX[iVert] *
2857 (psObject->padfY[nVertStart] - psObject->padfY[iVert - 1]);
2858
2859 /* --------------------------------------------------------------------
2860 */
2861 /* Reverse if necessary. */
2862 /* --------------------------------------------------------------------
2863 */
2864 if ((dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner)) {
2865 bAltered++;
2866 for (int i = 0; i < nVertCount / 2; i++) {
2867 /* Swap X */
2868 double dfSaved = psObject->padfX[nVertStart + i];
2869 psObject->padfX[nVertStart + i] =
2870 psObject->padfX[nVertStart + nVertCount - i - 1];
2871 psObject->padfX[nVertStart + nVertCount - i - 1] = dfSaved;
2872
2873 /* Swap Y */
2874 dfSaved = psObject->padfY[nVertStart + i];
2875 psObject->padfY[nVertStart + i] =
2876 psObject->padfY[nVertStart + nVertCount - i - 1];
2877 psObject->padfY[nVertStart + nVertCount - i - 1] = dfSaved;
2878
2879 /* Swap Z */
2880 if (psObject->padfZ) {
2881 dfSaved = psObject->padfZ[nVertStart + i];
2882 psObject->padfZ[nVertStart + i] =
2883 psObject->padfZ[nVertStart + nVertCount - i - 1];
2884 psObject->padfZ[nVertStart + nVertCount - i - 1] = dfSaved;
2885 }
2886
2887 /* Swap M */
2888 if (psObject->padfM) {
2889 dfSaved = psObject->padfM[nVertStart + i];
2890 psObject->padfM[nVertStart + i] =
2891 psObject->padfM[nVertStart + nVertCount - i - 1];
2892 psObject->padfM[nVertStart + nVertCount - i - 1] = dfSaved;
2893 }
2894 }
2895 }
2896 }
2897
2898 return bAltered;
2899}
#define NULL
Definition ccmath.h:32
#define STATIC_CAST(type, x)
Definition dbfopen.c:100
#define TRUE
Definition dbfopen.c:75
#define FALSE
Definition dbfopen.c:74
#define SHPLIB_NULLPTR
Definition dbfopen.c:103
#define assert(condition)
Definition lz4.c:393
#define MAX(a, b)
Definition parson.c:87
void SASetupDefaultHooks(SAHooks *psHooks)
Definition safileio.c:183
#define SHPT_ARCZ
Definition shapefil.h:218
#define SHPT_MULTIPATCH
Definition shapefil.h:225
#define SHPP_OUTERRING
Definition shapefil.h:234
#define SHPT_NULL
Definition shapefil.h:212
#define SHPP_FIRSTRING
Definition shapefil.h:236
#define SHPT_ARCM
Definition shapefil.h:222
#define SHPT_POLYGONM
Definition shapefil.h:223
#define SHP_CVSID(string)
Definition shapefil.h:125
#define SHPT_ARC
Definition shapefil.h:214
#define SHPT_POLYGON
Definition shapefil.h:215
SHPObject SHPAPI_CALL1 * SHPCreateObject(int nSHPType, int nShapeId, int nParts, const int *panPartStart, const int *panPartType, int nVertices, const double *padfX, const double *padfY, const double *padfZ, const double *padfM);SHPObject SHPAPI_CALL1(*) SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX, const double *padfY, const double *padfZ
#define SHPP_RING
Definition shapefil.h:237
#define DISABLE_MULTIPATCH_MEASURE
Definition shapefil.h:67
#define SHPP_TRIFAN
Definition shapefil.h:233
#define SHPT_MULTIPOINT
Definition shapefil.h:216
SHPInfo * SHPHandle
Definition shapefil.h:207
int * SAFile
Definition shapefil.h:148
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle hSHP, int iShape);int SHPAPI_CALL SHPWriteObject(SHPHandle hSHP, int iShape, SHPObject *psObject
Definition shpopen.c:1761
#define SHPT_POINTZ
Definition shapefil.h:217
#define SHPT_MULTIPOINTZ
Definition shapefil.h:220
#define SHPAPI_CALL
Definition shapefil.h:108
#define SHPAPI_CALL1(x)
Definition shapefil.h:113
#define SHPP_TRISTRIP
Definition shapefil.h:232
struct tagSHPObject SHPObject
Definition shapefil.h:176
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType);const char SHPAPI_CALL1(*) SHPPartTypeName(int nPartType
Definition shpopen.c:2527
#define SHPT_MULTIPOINTM
Definition shapefil.h:224
#define SHPT_POINTM
Definition shapefil.h:221
#define SHPT_POINT
Definition shapefil.h:213
#define SHPT_POLYGONZ
Definition shapefil.h:219
#define SHPP_INNERRING
Definition shapefil.h:235
unsigned long SAOffset
Definition shapefil.h:151
SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
Definition shpopen.c:289
SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
Definition shpopen.c:321
psObject nShapeId
Definition shpopen.c:1158
psObject nVertices
Definition shpopen.c:1247
unsigned int int32
Definition shpopen.c:54
const int nEntitySize
Definition shpopen.c:1818
SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
Definition shpopen.c:944
#define MIN(a, b)
Definition shpopen.c:64
void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode)
Definition shpopen.c:898
psObject nSHPType
Definition shpopen.c:1157
SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, SAHooks *psHooks)
Definition shpopen.c:960
#define CPL_UNUSED
Definition shpopen.c:84
void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject)
Definition shpopen.c:1117
unsigned char uchar
Definition shpopen.c:49
if(nSHPType==SHPT_ARCM||nSHPType==SHPT_POINTM||nSHPType==SHPT_POLYGONM||nSHPType==SHPT_MULTIPOINTM)
Definition shpopen.c:1167
const char SHPAPI_CALL1 * SHPPartTypeName(int nPartType){ switch(nPartType
Definition shpopen.c:2581
bool bHasM
Definition shpopen.c:1164
void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
Definition shpopen.c:142
void SHPAPI_CALL SHPClose(SHPHandle psSHP)
Definition shpopen.c:852
void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
Definition shpopen.c:917
#define STATIC_CAST(type, x)
Definition shpopen.c:100
SHPObject SHPAPI_CALL1 * SHPCreateObject(int nSHPType, int nShapeId, int nParts, const int *panPartStart, const int *panPartType, int nVertices, const double *padfX, const double *padfY, const double *padfZ, const double *padfM){ SHPObject *psObject=STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject))
int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
Definition shpopen.c:680
SHPObject SHPAPI_CALL1 * SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX, const double *padfY, const double *padfZ){ return(SHPCreateObject(nSHPType, -1, 0, SHPLIB_NULLPTR, SHPLIB_NULLPTR, nVertices, padfX, padfY, padfZ, SHPLIB_NULLPTR)
bool bHasZ
Definition shpopen.c:1165
int SHPAPI_CALL SHPRewindObject(CPL_UNUSED SHPHandle hSHP, SHPObject *psObject)
Definition shpopen.c:2742
void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
Definition shpopen.c:2611
const int nBytesRead
Definition shpopen.c:1905
int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject *psObject)
Definition shpopen.c:1275
#define ByteCopy(a, b, c)
Definition shpopen.c:62
SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess, SAHooks *psHooks, int bRestoreSHX)
Definition shpopen.c:659
#define MAX(a, b)
Definition shpopen.c:65
void(* Error)(const char *message)
Definition shapefil.h:164
SAFile(* FOpen)(const char *filename, const char *access)
Definition shapefil.h:155
SAOffset(* FTell)(SAFile file)
Definition shapefil.h:159
int(* FFlush)(SAFile file)
Definition shapefil.h:160
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition shapefil.h:157
int(* FClose)(SAFile file)
Definition shapefil.h:161
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition shapefil.h:156
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
Definition shapefil.h:158
SAFile fpSHX
Definition shapefil.h:182
int nShapeType
Definition shapefil.h:184
SAFile fpSHP
Definition shapefil.h:181
int nMaxRecords
Definition shapefil.h:189
SHPObject * psCachedObject
Definition shapefil.h:204
int nBufSize
Definition shapefil.h:199
unsigned int * panRecSize
Definition shapefil.h:191
SAHooks sHooks
Definition shapefil.h:179
double adBoundsMin[4]
Definition shapefil.h:193
int nRecords
Definition shapefil.h:188
unsigned char * pabyObjectBuf
Definition shapefil.h:202
int bUpdated
Definition shapefil.h:196
int nObjectBufSize
Definition shapefil.h:203
unsigned int nFileSize
Definition shapefil.h:186
unsigned int * panRecOffset
Definition shapefil.h:190
int bFastModeReadObject
Definition shapefil.h:201
unsigned char * pabyRec
Definition shapefil.h:198
double adBoundsMax[4]
Definition shapefil.h:194
int bFastModeReadObject
Definition shapefil.h:269
double dfYMax
Definition shapefil.h:264
double * padfX
Definition shapefil.h:253
double dfXMin
Definition shapefil.h:258
int * panPartType
Definition shapefil.h:250
double dfYMin
Definition shapefil.h:259
double * padfY
Definition shapefil.h:254
double dfMMax
Definition shapefil.h:266
double * padfZ
Definition shapefil.h:255
double dfZMax
Definition shapefil.h:265
double dfXMax
Definition shapefil.h:263
int * panPartStart
Definition shapefil.h:249
double * padfM
Definition shapefil.h:256
double dfMMin
Definition shapefil.h:261
double dfZMin
Definition shapefil.h:260
int bMeasureIsUsed
Definition shapefil.h:268