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