PostGIS  3.7.0dev-r@@SVN_REVISION@@
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 
47 SHP_CVSID("$Id$")
48 
49 typedef unsigned char uchar;
50 
51 #if UINT_MAX == 65535
52 typedef unsigned long int32;
53 #else
54 typedef 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
93 static 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 
110 static 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 
131 static 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 
291 SHPOpen( 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 
305 static 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 
329 SHPOpenLL( 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 )
361  bBigEndian = FALSE;
362  else
363  bBigEndian = TRUE;
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 
679 SHPOpenLLEx( 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 
702 int SHPAPI_CALL
703 SHPRestoreSHX ( 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 )
744  bBigEndian = FALSE;
745  else
746  bBigEndian = TRUE;
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 
887 void 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 */
935 void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode )
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 
955 void SHPAPI_CALL
956 SHPGetInfo(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 
988 SHPCreate( 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 
1006 SHPCreateLL( 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 
1133 error:
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 
1147 static 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 
1171 void 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 
1210 SHPCreateObject( 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;
1222  psObject->bMeasureIsUsed = FALSE;
1223 
1224 /* -------------------------------------------------------------------- */
1225 /* Establish whether this shape type has M, and Z values. */
1226 /* -------------------------------------------------------------------- */
1228  || nSHPType == SHPT_POINTM
1229  || nSHPType == SHPT_POLYGONM
1230  || nSHPType == SHPT_MULTIPOINTM )
1231  {
1232  bHasM = TRUE;
1233  bHasZ = FALSE;
1234  }
1235  else if( nSHPType == SHPT_ARCZ
1236  || nSHPType == SHPT_POINTZ
1237  || nSHPType == SHPT_POLYGONZ
1239  || nSHPType == SHPT_MULTIPATCH )
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 /* -------------------------------------------------------------------- */
1254  if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
1257  || nSHPType == SHPT_MULTIPATCH )
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 /* -------------------------------------------------------------------- */
1314  psObject->nVertices = nVertices;
1315  SHPComputeExtents( psObject );
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 
1344 int SHPAPI_CALL
1345 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
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 
1793 static 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 
1812 static 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 
1842 SHPReadObject( SHPHandle psSHP, int hEntity )
1843 
1844 {
1845  int nEntitySize, nRequiredSize;
1846  SHPObject *psShape;
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  }
2021  else if( nBytesRead != nEntitySize )
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 
2048  if( bBigEndian ) SwapWord( 4, &(nSHPType) );
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 
2561 const char SHPAPI_CALL1(*)
2562 SHPTypeName( 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 
2618 const char SHPAPI_CALL1(*)
2619 SHPPartTypeName( 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 
2651 void 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 
2685 static 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 */
2698 static 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 
2777 int 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 *)
SHP_CVSID("$Id$")
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 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
static unsigned char * SHPReallocObjectBufIfNecessary(SHPHandle psSHP, int nObjectBufSize)
Definition: shpopen.c:1812
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 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
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
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)
unsigned char uchar
Definition: shpopen.c:49
static void SwapWord(int length, void *wordP)
Definition: shpopen.c:110
void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
Definition: shpopen.c:147
static int SHPGetLenWithoutExtension(const char *pszBasename)
Definition: shpopen.c:305
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
bHasZ
Definition: shpopen.c:1247
static int SHPGetPartVertexCount(const SHPObject *psObject, int iPart)
Definition: shpopen.c:2685
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))
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
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
void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
Definition: shpopen.c:2652
static void * SHPAllocBuffer(unsigned char **pBuffer, int nSize)
Definition: shpopen.c:1793
static void * SfRealloc(void *pMem, int nNewSize)
Definition: shpopen.c:131
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
#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
const char SHPAPI_CALL1 * SHPPartTypeName(int nPartType){ switch(nPartType
Definition: shpopen.c:2619
static int SHPRewindIsInnerRing(const SHPObject *psObject, int iOpRing, double dfTestX, double dfTestY)
Definition: shpopen.c:2698
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType){ switch(nSHPType
Definition: shpopen.c:2562
#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
int nVertices
Definition: shapefil.h:389
int nShapeId
Definition: shapefil.h:383
double dfYMin
Definition: shapefil.h:396
double * padfY
Definition: shapefil.h:391
int nSHPType
Definition: shapefil.h:381
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