PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ SHPOpenLL()

SHPHandle SHPAPI_CALL SHPOpenLL ( const char *  pszShapeFile,
const char *  pszAccess,
SAHooks psHooks 
)

Definition at line 329 of file shpopen.c.

331 {
332  char *pszFullname;
333  SHPHandle psSHP;
334 
335  uchar *pabyBuf;
336  int i;
337  double dValue;
338  int bLazySHXLoading = FALSE;
339  int nLenWithoutExtension;
340 
341 /* -------------------------------------------------------------------- */
342 /* Ensure the access string is one of the legal ones. We */
343 /* ensure the result string indicates binary to avoid common */
344 /* problems on Windows. */
345 /* -------------------------------------------------------------------- */
346  if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
347  || strcmp(pszAccess,"r+") == 0 )
348  pszAccess = "r+b";
349  else
350  {
351  bLazySHXLoading = strchr(pszAccess, 'l') != SHPLIB_NULLPTR;
352  pszAccess = "rb";
353  }
354 
355 /* -------------------------------------------------------------------- */
356 /* Establish the byte order on this machine. */
357 /* -------------------------------------------------------------------- */
358 #if !defined(bBigEndian)
359  i = 1;
360  if( *((uchar *) &i) == 1 )
361  bBigEndian = FALSE;
362  else
363  bBigEndian = TRUE;
364 #endif
365 
366 /* -------------------------------------------------------------------- */
367 /* Initialize the info structure. */
368 /* -------------------------------------------------------------------- */
369  psSHP = STATIC_CAST(SHPHandle, calloc(1,sizeof(SHPInfo)));
370  if( psSHP == SHPLIB_NULLPTR )
371  return SHPLIB_NULLPTR;
372 
373  psSHP->bUpdated = FALSE;
374  memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
375 
376 /* -------------------------------------------------------------------- */
377 /* Open the .shp and .shx files. Note that files pulled from */
378 /* a PC to Unix with upper case filenames won't work! */
379 /* -------------------------------------------------------------------- */
380  nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
381  pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
382  if( pszFullname == SHPLIB_NULLPTR )
383  {
384  free( psSHP );
385  return SHPLIB_NULLPTR;
386  }
387  memcpy(pszFullname, pszLayer, nLenWithoutExtension);
388  memcpy(pszFullname + nLenWithoutExtension, ".shp", 5);
389  psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
390  if( psSHP->fpSHP == SHPLIB_NULLPTR )
391  {
392  memcpy(pszFullname + nLenWithoutExtension, ".SHP", 5);
393  psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
394  }
395 
396  if( psSHP->fpSHP == SHPLIB_NULLPTR )
397  {
398  size_t nMessageLen = strlen(pszFullname)*2+256;
399  char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
400  pszFullname[nLenWithoutExtension] = 0;
401  snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
402  pszFullname, pszFullname );
403  psHooks->Error( pszMessage );
404  free( pszMessage );
405 
406  free( psSHP );
407  free( pszFullname );
408 
409  return SHPLIB_NULLPTR;
410  }
411 
412  memcpy(pszFullname + nLenWithoutExtension, ".shx", 5);
413  psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
414  if( psSHP->fpSHX == SHPLIB_NULLPTR )
415  {
416  memcpy(pszFullname + nLenWithoutExtension, ".SHX", 5);
417  psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
418  }
419 
420  if( psSHP->fpSHX == SHPLIB_NULLPTR )
421  {
422  size_t nMessageLen = strlen(pszFullname)*2+256;
423  char *pszMessage = STATIC_CAST(char *, malloc(nMessageLen));
424  pszFullname[nLenWithoutExtension] = 0;
425  snprintf( pszMessage, nMessageLen, "Unable to open %s.shx or %s.SHX. "
426  "Set SHAPE_RESTORE_SHX config option to YES to restore or "
427  "create it.", pszFullname, pszFullname );
428  psHooks->Error( pszMessage );
429  free( pszMessage );
430 
431  psSHP->sHooks.FClose( psSHP->fpSHP );
432  free( psSHP );
433  free( pszFullname );
434  return SHPLIB_NULLPTR ;
435  }
436 
437  free( pszFullname );
438 
439 /* -------------------------------------------------------------------- */
440 /* Read the file size from the SHP file. */
441 /* -------------------------------------------------------------------- */
442  pabyBuf = STATIC_CAST(uchar *, malloc(100));
443  if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP ) != 1 )
444  {
445  psSHP->sHooks.Error( ".shp file is unreadable, or corrupt." );
446  psSHP->sHooks.FClose( psSHP->fpSHP );
447  psSHP->sHooks.FClose( psSHP->fpSHX );
448  free( pabyBuf );
449  free( psSHP );
450 
451  return SHPLIB_NULLPTR ;
452  }
453 
454  psSHP->nFileSize = (STATIC_CAST(unsigned int, pabyBuf[24])<<24)|(pabyBuf[25]<<16)|
455  (pabyBuf[26]<<8)|pabyBuf[27];
456  if( psSHP->nFileSize < UINT_MAX / 2 )
457  psSHP->nFileSize *= 2;
458  else
459  psSHP->nFileSize = (UINT_MAX / 2) * 2;
460 
461 /* -------------------------------------------------------------------- */
462 /* Read SHX file Header info */
463 /* -------------------------------------------------------------------- */
464  if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
465  || pabyBuf[0] != 0
466  || pabyBuf[1] != 0
467  || pabyBuf[2] != 0x27
468  || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
469  {
470  psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
471  psSHP->sHooks.FClose( psSHP->fpSHP );
472  psSHP->sHooks.FClose( psSHP->fpSHX );
473  free( pabyBuf );
474  free( psSHP );
475 
476  return SHPLIB_NULLPTR;
477  }
478 
479  psSHP->nRecords = pabyBuf[27]|(pabyBuf[26]<<8)|(pabyBuf[25]<<16)|
480  ((pabyBuf[24] & 0x7F)<<24);
481  psSHP->nRecords = (psSHP->nRecords - 50) / 4;
482 
483  psSHP->nShapeType = pabyBuf[32];
484 
485  if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
486  {
487  char szErrorMsg[200];
488 
489  snprintf( szErrorMsg, sizeof(szErrorMsg),
490  "Record count in .shp header is %d, which seems\n"
491  "unreasonable. Assuming header is corrupt.",
492  psSHP->nRecords );
493  szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
494  psSHP->sHooks.Error( szErrorMsg );
495  psSHP->sHooks.FClose( psSHP->fpSHP );
496  psSHP->sHooks.FClose( psSHP->fpSHX );
497  free( psSHP );
498  free(pabyBuf);
499 
500  return SHPLIB_NULLPTR;
501  }
502 
503  /* If a lot of records are advertised, check that the file is big enough */
504  /* to hold them */
505  if( psSHP->nRecords >= 1024 * 1024 )
506  {
507  SAOffset nFileSize;
508  psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 2 );
509  nFileSize = psSHP->sHooks.FTell( psSHP->fpSHX );
510  if( nFileSize > 100 &&
511  nFileSize/2 < STATIC_CAST(SAOffset, psSHP->nRecords * 4 + 50) )
512  {
513  psSHP->nRecords = STATIC_CAST(int, (nFileSize - 100) / 8);
514  }
515  psSHP->sHooks.FSeek( psSHP->fpSHX, 100, 0 );
516  }
517 
518 /* -------------------------------------------------------------------- */
519 /* Read the bounds. */
520 /* -------------------------------------------------------------------- */
521  if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
522  memcpy( &dValue, pabyBuf+36, 8 );
523  psSHP->adBoundsMin[0] = dValue;
524 
525  if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
526  memcpy( &dValue, pabyBuf+44, 8 );
527  psSHP->adBoundsMin[1] = dValue;
528 
529  if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
530  memcpy( &dValue, pabyBuf+52, 8 );
531  psSHP->adBoundsMax[0] = dValue;
532 
533  if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
534  memcpy( &dValue, pabyBuf+60, 8 );
535  psSHP->adBoundsMax[1] = dValue;
536 
537  if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
538  memcpy( &dValue, pabyBuf+68, 8 );
539  psSHP->adBoundsMin[2] = dValue;
540 
541  if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
542  memcpy( &dValue, pabyBuf+76, 8 );
543  psSHP->adBoundsMax[2] = dValue;
544 
545  if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
546  memcpy( &dValue, pabyBuf+84, 8 );
547  psSHP->adBoundsMin[3] = dValue;
548 
549  if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
550  memcpy( &dValue, pabyBuf+92, 8 );
551  psSHP->adBoundsMax[3] = dValue;
552 
553  free( pabyBuf );
554 
555 /* -------------------------------------------------------------------- */
556 /* Read the .shx file to get the offsets to each record in */
557 /* the .shp file. */
558 /* -------------------------------------------------------------------- */
559  psSHP->nMaxRecords = psSHP->nRecords;
560 
561  psSHP->panRecOffset = STATIC_CAST(unsigned int *,
562  malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) ));
563  psSHP->panRecSize = STATIC_CAST(unsigned int *,
564  malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) ));
565  if( bLazySHXLoading )
566  pabyBuf = SHPLIB_NULLPTR;
567  else
568  pabyBuf = STATIC_CAST(uchar *, malloc(8 * MAX(1,psSHP->nRecords) ));
569 
570  if (psSHP->panRecOffset == SHPLIB_NULLPTR ||
571  psSHP->panRecSize == SHPLIB_NULLPTR ||
572  (!bLazySHXLoading && pabyBuf == SHPLIB_NULLPTR))
573  {
574  char szErrorMsg[200];
575 
576  snprintf( szErrorMsg, sizeof(szErrorMsg),
577  "Not enough memory to allocate requested memory (nRecords=%d).\n"
578  "Probably broken SHP file",
579  psSHP->nRecords );
580  szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
581  psSHP->sHooks.Error( szErrorMsg );
582  psSHP->sHooks.FClose( psSHP->fpSHP );
583  psSHP->sHooks.FClose( psSHP->fpSHX );
584  if (psSHP->panRecOffset) free( psSHP->panRecOffset );
585  if (psSHP->panRecSize) free( psSHP->panRecSize );
586  if (pabyBuf) free( pabyBuf );
587  free( psSHP );
588  return SHPLIB_NULLPTR;
589  }
590 
591  if( bLazySHXLoading )
592  {
593  memset(psSHP->panRecOffset, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
594  memset(psSHP->panRecSize, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
595  free( pabyBuf ); // sometimes make cppcheck happy, but
596  return( psSHP );
597  }
598 
599  if( STATIC_CAST(int, psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ))
600  != psSHP->nRecords )
601  {
602  char szErrorMsg[200];
603 
604  snprintf( szErrorMsg, sizeof(szErrorMsg),
605  "Failed to read all values for %d records in .shx file: %s.",
606  psSHP->nRecords, strerror(errno) );
607  szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
608  psSHP->sHooks.Error( szErrorMsg );
609 
610  /* SHX is short or unreadable for some reason. */
611  psSHP->sHooks.FClose( psSHP->fpSHP );
612  psSHP->sHooks.FClose( psSHP->fpSHX );
613  free( psSHP->panRecOffset );
614  free( psSHP->panRecSize );
615  free( pabyBuf );
616  free( psSHP );
617 
618  return SHPLIB_NULLPTR;
619  }
620 
621  /* In read-only mode, we can close the SHX now */
622  if (strcmp(pszAccess, "rb") == 0)
623  {
624  psSHP->sHooks.FClose( psSHP->fpSHX );
625  psSHP->fpSHX = SHPLIB_NULLPTR;
626  }
627 
628  for( i = 0; i < psSHP->nRecords; i++ )
629  {
630  unsigned int nOffset, nLength;
631 
632  memcpy( &nOffset, pabyBuf + i * 8, 4 );
633  if( !bBigEndian ) SwapWord( 4, &nOffset );
634 
635  memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
636  if( !bBigEndian ) SwapWord( 4, &nLength );
637 
638  if( nOffset > STATIC_CAST(unsigned int, INT_MAX) )
639  {
640  char str[128];
641  snprintf( str, sizeof(str),
642  "Invalid offset for entity %d", i);
643  str[sizeof(str)-1] = '\0';
644 
645  psSHP->sHooks.Error( str );
646  SHPClose(psSHP);
647  free( pabyBuf );
648  return SHPLIB_NULLPTR;
649  }
650  if( nLength > STATIC_CAST(unsigned int, INT_MAX / 2 - 4) )
651  {
652  char str[128];
653  snprintf( str, sizeof(str),
654  "Invalid length for entity %d", i);
655  str[sizeof(str)-1] = '\0';
656 
657  psSHP->sHooks.Error( str );
658  SHPClose(psSHP);
659  free( pabyBuf );
660  return SHPLIB_NULLPTR;
661  }
662  psSHP->panRecOffset[i] = nOffset*2;
663  psSHP->panRecSize[i] = nLength*2;
664  }
665  free( pabyBuf );
666 
667  return( psSHP );
668 }
#define str(s)
void * malloc(YYSIZE_T)
void free(void *)
unsigned long SAOffset
Definition: shapefil.h:286
static int bBigEndian
Definition: shpopen.c:93
unsigned char uchar
Definition: shpopen.c:49
static void SwapWord(int length, void *wordP)
Definition: shpopen.c:110
static int SHPGetLenWithoutExtension(const char *pszBasename)
Definition: shpopen.c:305
void SHPAPI_CALL SHPClose(SHPHandle psSHP)
Definition: shpopen.c:888
#define STATIC_CAST(type, x)
Definition: shpopen.c:100
#define TRUE
Definition: shpopen.c:59
#define FALSE
Definition: shpopen.c:58
#define SHPLIB_NULLPTR
Definition: shpopen.c:101
#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(* 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
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
int bUpdated
Definition: shapefil.h:332
unsigned int nFileSize
Definition: shapefil.h:322
unsigned int * panRecOffset
Definition: shapefil.h:326
double adBoundsMax[4]
Definition: shapefil.h:330

References SHPInfo::adBoundsMax, SHPInfo::adBoundsMin, bBigEndian, SHPInfo::bUpdated, SAHooks::Error, FALSE, SAHooks::FClose, SAHooks::FOpen, SHPInfo::fpSHP, SHPInfo::fpSHX, SAHooks::FRead, free(), SAHooks::FSeek, SAHooks::FTell, malloc(), MAX, SHPInfo::nFileSize, SHPInfo::nMaxRecords, SHPInfo::nRecords, SHPInfo::nShapeType, SHPInfo::panRecOffset, SHPInfo::panRecSize, SHPInfo::sHooks, SHPClose(), SHPGetLenWithoutExtension(), SHPLIB_NULLPTR, STATIC_CAST, str, SwapWord(), and TRUE.

Referenced by SHPCreateLL(), SHPOpen(), and SHPOpenLLEx().

Here is the call graph for this function:
Here is the caller graph for this function: