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