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