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