PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ SHPOpenLL()

SHPHandle SHPAPI_CALL SHPOpenLL ( const char *  pszLayer,
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(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 }
#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:879
#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: