diff options
Diffstat (limited to 'navit/map')
-rw-r--r-- | navit/map/shapefile/Makefile.am | 9 | ||||
-rw-r--r-- | navit/map/shapefile/dbfopen.c | 1869 | ||||
-rw-r--r-- | navit/map/shapefile/shapefil.h | 609 | ||||
-rw-r--r-- | navit/map/shapefile/shpopen.c | 2283 | ||||
-rw-r--r-- | navit/map/shapefile/shptree.c | 1050 |
5 files changed, 5 insertions, 5815 deletions
diff --git a/navit/map/shapefile/Makefile.am b/navit/map/shapefile/Makefile.am index 35e420e84..ba6e22886 100644 --- a/navit/map/shapefile/Makefile.am +++ b/navit/map/shapefile/Makefile.am @@ -5,10 +5,11 @@ if PLUGINS else noinst_LTLIBRARIES = libmap_shapefile.la endif -if HAVE_SYSTEM_SHAPEFILELIB libmap_shapefile_la_SOURCES = shapefile.c -libmap_shapefile_la_LDFLAGS = -module -avoid-version @NAVIT_MODULE_LDFLAGS@ @SHAPEFILE_LIBS@ -else -libmap_shapefile_la_SOURCES = shapefile.c dbfopen.c shpopen.c shptree.c shapefil.h libmap_shapefile_la_LDFLAGS = -module -avoid-version @NAVIT_MODULE_LDFLAGS@ +if HAVE_SYSTEM_SHAPEFILELIB +libmap_shapefile_la_LDFLAGS += @SHAPEFILE_LIBS@ +else +AM_CPPFLAGS += -I$(top_srcdir)/navit/support/shapefile +libmap_shapefile_la_LDFLAGS += $(top_srcdir)/navit/support/shapefile/libsupport_shapefile.la endif diff --git a/navit/map/shapefile/dbfopen.c b/navit/map/shapefile/dbfopen.c deleted file mode 100644 index 51944fc53..000000000 --- a/navit/map/shapefile/dbfopen.c +++ /dev/null @@ -1,1869 +0,0 @@ -/****************************************************************************** - * $Id: dbfopen.c,v 1.83 2008/11/12 14:28:15 fwarmerdam Exp $ - * - * Project: Shapelib - * Purpose: Implementation of .dbf access API documented in dbf_api.html. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************** - * - * $Log: dbfopen.c,v $ - * Revision 1.83 2008/11/12 14:28:15 fwarmerdam - * DBFCreateField() now works on files with records - * - * Revision 1.82 2008/11/11 17:47:09 fwarmerdam - * added DBFDeleteField() function - * - * Revision 1.81 2008/01/03 17:48:13 bram - * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI) - * instead of LDID/3. This seems to be the same as what ESRI - * would be doing by default. - * - * Revision 1.80 2007/12/30 14:36:39 fwarmerdam - * avoid syntax issue with last comment. - * - * Revision 1.79 2007/12/30 14:35:48 fwarmerdam - * Avoid char* / unsigned char* warnings. - * - * Revision 1.78 2007/12/18 18:28:07 bram - * - create hook for client specific atof (bugzilla ticket 1615) - * - check for NULL handle before closing cpCPG file, and close after reading. - * - * Revision 1.77 2007/12/15 20:25:21 bram - * dbfopen.c now reads the Code Page information from the DBF file, and exports - * this information as a string through the DBFGetCodePage function. This is - * either the number from the LDID header field ("LDID/<number>") or as the - * content of an accompanying .CPG file. When creating a DBF file, the code can - * be set using DBFCreateEx. - * - * Revision 1.76 2007/12/12 22:21:32 bram - * DBFClose: check for NULL psDBF handle before trying to close it. - * - * Revision 1.75 2007/12/06 13:58:19 fwarmerdam - * make sure file offset calculations are done in as SAOffset - * - * Revision 1.74 2007/12/06 07:00:25 fwarmerdam - * dbfopen now using SAHooks for fileio - * - * Revision 1.73 2007/09/03 19:48:11 fwarmerdam - * move DBFReadAttribute() static dDoubleField into dbfinfo - * - * Revision 1.72 2007/09/03 19:34:06 fwarmerdam - * Avoid use of static tuple buffer in DBFReadTuple() - * - * Revision 1.71 2006/06/22 14:37:18 fwarmerdam - * avoid memory leak if dbfopen fread fails - * - * Revision 1.70 2006/06/17 17:47:05 fwarmerdam - * use calloc() for dbfinfo in DBFCreate - * - * Revision 1.69 2006/06/17 15:34:32 fwarmerdam - * disallow creating fields wider than 255 - * - * Revision 1.68 2006/06/17 15:12:40 fwarmerdam - * Fixed C++ style comments. - * - * Revision 1.67 2006/06/17 00:24:53 fwarmerdam - * Don't treat non-zero decimals values as high order byte for length - * for strings. It causes serious corruption for some files. - * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202 - * - * Revision 1.66 2006/03/29 18:26:20 fwarmerdam - * fixed bug with size of pachfieldtype in dbfcloneempty - * - * Revision 1.65 2006/02/15 01:14:30 fwarmerdam - * added DBFAddNativeFieldType - * - * Revision 1.64 2006/02/09 00:29:04 fwarmerdam - * Changed to put spaces into string fields that are NULL as - * per http://bugzilla.maptools.org/show_bug.cgi?id=316. - * - * Revision 1.63 2006/01/25 15:35:43 fwarmerdam - * check success on DBFFlushRecord - * - * Revision 1.62 2006/01/10 16:28:03 fwarmerdam - * Fixed typo in CPLError. - * - * Revision 1.61 2006/01/10 16:26:29 fwarmerdam - * Push loading record buffer into DBFLoadRecord. - * Implement CPL error reporting if USE_CPL defined. - * - * Revision 1.60 2006/01/05 01:27:27 fwarmerdam - * added dbf deletion mark/fetch - * - * Revision 1.59 2005/03/14 15:20:28 fwarmerdam - * Fixed last change. - * - * Revision 1.58 2005/03/14 15:18:54 fwarmerdam - * Treat very wide fields with no decimals as double. This is - * more than 32bit integer fields. - * - * Revision 1.57 2005/02/10 20:16:54 fwarmerdam - * Make the pszStringField buffer for DBFReadAttribute() static char [256] - * as per bug 306. - * - * Revision 1.56 2005/02/10 20:07:56 fwarmerdam - * Fixed bug 305 in DBFCloneEmpty() - header length problem. - * - * Revision 1.55 2004/09/26 20:23:46 fwarmerdam - * avoid warnings with rcsid and signed/unsigned stuff - * - * Revision 1.54 2004/09/15 16:26:10 fwarmerdam - * Treat all blank numeric fields as null too. - */ - -#include "shapefil.h" - -#include <math.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> - -#ifndef FALSE -# define FALSE 0 -# define TRUE 1 -#endif - -/************************************************************************/ -/* SfRealloc() */ -/* */ -/* A realloc cover function that will access a NULL pointer as */ -/* a valid input. */ -/************************************************************************/ - -static void * SfRealloc( void * pMem, int nNewSize ) - -{ - if( pMem == NULL ) - return( (void *) malloc(nNewSize) ); - else - return( (void *) realloc(pMem,nNewSize) ); -} - -/************************************************************************/ -/* DBFWriteHeader() */ -/* */ -/* This is called to write out the file header, and field */ -/* descriptions before writing any actual data records. This */ -/* also computes all the DBFDataSet field offset/size/decimals */ -/* and so forth values. */ -/************************************************************************/ - -static void DBFWriteHeader(DBFHandle psDBF) - -{ - unsigned char abyHeader[XBASE_FLDHDR_SZ]; - int i; - - if( !psDBF->bNoHeader ) - return; - - psDBF->bNoHeader = FALSE; - -/* -------------------------------------------------------------------- */ -/* Initialize the file header information. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < XBASE_FLDHDR_SZ; i++ ) - abyHeader[i] = 0; - - abyHeader[0] = 0x03; /* memo field? - just copying */ - - /* write out a dummy date */ - abyHeader[1] = 95; /* YY */ - abyHeader[2] = 7; /* MM */ - abyHeader[3] = 26; /* DD */ - - /* record count preset at zero */ - - abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256); - abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256); - - abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256); - abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256); - - abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver); - -/* -------------------------------------------------------------------- */ -/* Write the initial 32 byte file header, and all the field */ -/* descriptions. */ -/* -------------------------------------------------------------------- */ - psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); - psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp ); - psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, - psDBF->fp ); - -/* -------------------------------------------------------------------- */ -/* Write out the newline character if there is room for it. */ -/* -------------------------------------------------------------------- */ - if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 ) - { - char cNewline; - - cNewline = 0x0d; - psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp ); - } -} - -/************************************************************************/ -/* DBFFlushRecord() */ -/* */ -/* Write out the current record if there is one. */ -/************************************************************************/ - -static int DBFFlushRecord( DBFHandle psDBF ) - -{ - SAOffset nRecordOffset; - - if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 ) - { - psDBF->bCurrentRecordModified = FALSE; - - nRecordOffset = - psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord - + psDBF->nHeaderLength; - - if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 - || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, - psDBF->nRecordLength, - 1, psDBF->fp ) != 1 ) - { -#ifdef USE_CPL - CPLError( CE_Failure, CPLE_FileIO, - "Failure writing DBF record %d.", - psDBF->nCurrentRecord ); -#else - fprintf( stderr, "Failure writing DBF record %d.", - psDBF->nCurrentRecord ); -#endif - return FALSE; - } - } - - return TRUE; -} - -/************************************************************************/ -/* DBFLoadRecord() */ -/************************************************************************/ - -static int DBFLoadRecord( DBFHandle psDBF, int iRecord ) - -{ - if( psDBF->nCurrentRecord != iRecord ) - { - SAOffset nRecordOffset; - - if( !DBFFlushRecord( psDBF ) ) - return FALSE; - - nRecordOffset = - psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; - - if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 ) - { -#ifdef USE_CPL - CPLError( CE_Failure, CPLE_FileIO, - "fseek(%ld) failed on DBF file.\n", - (long) nRecordOffset ); -#else - fprintf( stderr, "fseek(%ld) failed on DBF file.\n", - (long) nRecordOffset ); -#endif - return FALSE; - } - - if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, - psDBF->nRecordLength, 1, psDBF->fp ) != 1 ) - { -#ifdef USE_CPL - CPLError( CE_Failure, CPLE_FileIO, - "fread(%d) failed on DBF file.\n", - psDBF->nRecordLength ); -#else - fprintf( stderr, "fread(%d) failed on DBF file.\n", - psDBF->nRecordLength ); -#endif - return FALSE; - } - - psDBF->nCurrentRecord = iRecord; - } - - return TRUE; -} - -/************************************************************************/ -/* DBFUpdateHeader() */ -/************************************************************************/ - -void SHPAPI_CALL -DBFUpdateHeader( DBFHandle psDBF ) - -{ - unsigned char abyFileHeader[32]; - - if( psDBF->bNoHeader ) - DBFWriteHeader( psDBF ); - - DBFFlushRecord( psDBF ); - - psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); - psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp ); - - abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256); - abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256); - abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256); - abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256); - - psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); - psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp ); - - psDBF->sHooks.FFlush( psDBF->fp ); -} - -/************************************************************************/ -/* DBFOpen() */ -/* */ -/* Open a .dbf file. */ -/************************************************************************/ - -DBFHandle SHPAPI_CALL -DBFOpen( const char * pszFilename, const char * pszAccess ) - -{ - SAHooks sHooks; - - SASetupDefaultHooks( &sHooks ); - - return DBFOpenLL( pszFilename, pszAccess, &sHooks ); -} - -/************************************************************************/ -/* DBFOpen() */ -/* */ -/* Open a .dbf file. */ -/************************************************************************/ - -DBFHandle SHPAPI_CALL -DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks ) - -{ - DBFHandle psDBF; - SAFile pfCPG; - unsigned char *pabyBuf; - int nFields, nHeadLen, iField, i; - char *pszBasename, *pszFullname; - int nBufSize = 500; - -/* -------------------------------------------------------------------- */ -/* We only allow the access strings "rb" and "r+". */ -/* -------------------------------------------------------------------- */ - if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 - && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0 - && strcmp(pszAccess,"r+b") != 0 ) - return( NULL ); - - if( strcmp(pszAccess,"r") == 0 ) - pszAccess = "rb"; - - if( strcmp(pszAccess,"r+") == 0 ) - pszAccess = "rb+"; - -/* -------------------------------------------------------------------- */ -/* Compute the base (layer) name. If there is any extension */ -/* on the passed in filename we will strip it off. */ -/* -------------------------------------------------------------------- */ - pszBasename = (char *) malloc(strlen(pszFilename)+5); - strcpy( pszBasename, pszFilename ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - pszFullname = (char *) malloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s.dbf", pszBasename ); - - psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) ); - psDBF->fp = psHooks->FOpen( pszFullname, pszAccess ); - memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) ); - - if( psDBF->fp == NULL ) - { - sprintf( pszFullname, "%s.DBF", pszBasename ); - psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess ); - } - - sprintf( pszFullname, "%s.cpg", pszBasename ); - pfCPG = psHooks->FOpen( pszFullname, "r" ); - if( pfCPG == NULL ) - { - sprintf( pszFullname, "%s.CPG", pszBasename ); - pfCPG = psHooks->FOpen( pszFullname, "r" ); - } - - free( pszBasename ); - free( pszFullname ); - - if( psDBF->fp == NULL ) - { - free( psDBF ); - if( pfCPG ) psHooks->FClose( pfCPG ); - return( NULL ); - } - - psDBF->bNoHeader = FALSE; - psDBF->nCurrentRecord = -1; - psDBF->bCurrentRecordModified = FALSE; - -/* -------------------------------------------------------------------- */ -/* Read Table Header info */ -/* -------------------------------------------------------------------- */ - pabyBuf = (unsigned char *) malloc(nBufSize); - if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 ) - { - psDBF->sHooks.FClose( psDBF->fp ); - if( pfCPG ) psDBF->sHooks.FClose( pfCPG ); - free( pabyBuf ); - free( psDBF ); - return NULL; - } - - psDBF->nRecords = - pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; - - psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; - psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256; - psDBF->iLanguageDriver = pabyBuf[29]; - - psDBF->nFields = nFields = (nHeadLen - 32) / 32; - - psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength); - -/* -------------------------------------------------------------------- */ -/* Figure out the code page from the LDID and CPG */ -/* -------------------------------------------------------------------- */ - - psDBF->pszCodePage = NULL; - if( pfCPG ) - { - size_t n; - char *buffer = (char *) pabyBuf; - buffer[0] = '\0'; - psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG ); - n = strcspn( (char *) pabyBuf, "\n\r" ); - if( n > 0 ) - { - pabyBuf[n] = '\0'; - psDBF->pszCodePage = (char *) malloc(n + 1); - memcpy( psDBF->pszCodePage, pabyBuf, n + 1 ); - } - psDBF->sHooks.FClose( pfCPG ); - } - if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 ) - { - sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver ); - psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1); - strcpy( psDBF->pszCodePage, (char *) pabyBuf ); - } - -/* -------------------------------------------------------------------- */ -/* Read in Field Definitions */ -/* -------------------------------------------------------------------- */ - - pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen); - psDBF->pszHeader = (char *) pabyBuf; - - psDBF->sHooks.FSeek( psDBF->fp, 32, 0 ); - if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 ) - { - psDBF->sHooks.FClose( psDBF->fp ); - free( pabyBuf ); - free( psDBF->pszCurrentRecord ); - free( psDBF ); - return NULL; - } - - psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); - psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); - psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields); - psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields); - - for( iField = 0; iField < nFields; iField++ ) - { - unsigned char *pabyFInfo; - - pabyFInfo = pabyBuf+iField*32; - - if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' ) - { - psDBF->panFieldSize[iField] = pabyFInfo[16]; - psDBF->panFieldDecimals[iField] = pabyFInfo[17]; - } - else - { - psDBF->panFieldSize[iField] = pabyFInfo[16]; - psDBF->panFieldDecimals[iField] = 0; - -/* -** The following seemed to be used sometimes to handle files with long -** string fields, but in other cases (such as bug 1202) the decimals field -** just seems to indicate some sort of preferred formatting, not very -** wide fields. So I have disabled this code. FrankW. - psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256; - psDBF->panFieldDecimals[iField] = 0; -*/ - } - - psDBF->pachFieldType[iField] = (char) pabyFInfo[11]; - if( iField == 0 ) - psDBF->panFieldOffset[iField] = 1; - else - psDBF->panFieldOffset[iField] = - psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1]; - } - - return( psDBF ); -} - -/************************************************************************/ -/* DBFClose() */ -/************************************************************************/ - -void SHPAPI_CALL -DBFClose(DBFHandle psDBF) -{ - if( psDBF == NULL ) - return; - -/* -------------------------------------------------------------------- */ -/* Write out header if not already written. */ -/* -------------------------------------------------------------------- */ - if( psDBF->bNoHeader ) - DBFWriteHeader( psDBF ); - - DBFFlushRecord( psDBF ); - -/* -------------------------------------------------------------------- */ -/* Update last access date, and number of records if we have */ -/* write access. */ -/* -------------------------------------------------------------------- */ - if( psDBF->bUpdated ) - DBFUpdateHeader( psDBF ); - -/* -------------------------------------------------------------------- */ -/* Close, and free resources. */ -/* -------------------------------------------------------------------- */ - psDBF->sHooks.FClose( psDBF->fp ); - - if( psDBF->panFieldOffset != NULL ) - { - free( psDBF->panFieldOffset ); - free( psDBF->panFieldSize ); - free( psDBF->panFieldDecimals ); - free( psDBF->pachFieldType ); - } - - if( psDBF->pszWorkField != NULL ) - free( psDBF->pszWorkField ); - - free( psDBF->pszHeader ); - free( psDBF->pszCurrentRecord ); - free( psDBF->pszCodePage ); - - free( psDBF ); -} - -/************************************************************************/ -/* DBFCreate() */ -/* */ -/* Create a new .dbf file with default code page LDID/87 (0x57) */ -/************************************************************************/ - -DBFHandle SHPAPI_CALL -DBFCreate( const char * pszFilename ) - -{ - return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57 -} - -/************************************************************************/ -/* DBFCreateEx() */ -/* */ -/* Create a new .dbf file. */ -/************************************************************************/ - -DBFHandle SHPAPI_CALL -DBFCreateEx( const char * pszFilename, const char* pszCodePage ) - -{ - SAHooks sHooks; - - SASetupDefaultHooks( &sHooks ); - - return DBFCreateLL( pszFilename, pszCodePage , &sHooks ); -} - -/************************************************************************/ -/* DBFCreate() */ -/* */ -/* Create a new .dbf file. */ -/************************************************************************/ - -DBFHandle SHPAPI_CALL -DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks ) - -{ - DBFHandle psDBF; - SAFile fp; - char *pszFullname, *pszBasename; - int i, ldid = -1; - char chZero = '\0'; - -/* -------------------------------------------------------------------- */ -/* Compute the base (layer) name. If there is any extension */ -/* on the passed in filename we will strip it off. */ -/* -------------------------------------------------------------------- */ - pszBasename = (char *) malloc(strlen(pszFilename)+5); - strcpy( pszBasename, pszFilename ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - pszFullname = (char *) malloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s.dbf", pszBasename ); - -/* -------------------------------------------------------------------- */ -/* Create the file. */ -/* -------------------------------------------------------------------- */ - fp = psHooks->FOpen( pszFullname, "wb" ); - if( fp == NULL ) - return( NULL ); - - psHooks->FWrite( &chZero, 1, 1, fp ); - psHooks->FClose( fp ); - - fp = psHooks->FOpen( pszFullname, "rb+" ); - if( fp == NULL ) - return( NULL ); - - - sprintf( pszFullname, "%s.cpg", pszBasename ); - if( pszCodePage != NULL ) - { - if( strncmp( pszCodePage, "LDID/", 5 ) == 0 ) - { - ldid = atoi( pszCodePage + 5 ); - if( ldid > 255 ) - ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one - } - if( ldid < 0 ) - { - SAFile fpCPG = psHooks->FOpen( pszFullname, "w" ); - psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG ); - psHooks->FClose( fpCPG ); - } - } - if( pszCodePage == NULL || ldid >= 0 ) - { - psHooks->Remove( pszFullname ); - } - - free( pszBasename ); - free( pszFullname ); - -/* -------------------------------------------------------------------- */ -/* Create the info structure. */ -/* -------------------------------------------------------------------- */ - psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo)); - - memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) ); - psDBF->fp = fp; - psDBF->nRecords = 0; - psDBF->nFields = 0; - psDBF->nRecordLength = 1; - psDBF->nHeaderLength = 33; - - psDBF->panFieldOffset = NULL; - psDBF->panFieldSize = NULL; - psDBF->panFieldDecimals = NULL; - psDBF->pachFieldType = NULL; - psDBF->pszHeader = NULL; - - psDBF->nCurrentRecord = -1; - psDBF->bCurrentRecordModified = FALSE; - psDBF->pszCurrentRecord = NULL; - - psDBF->bNoHeader = TRUE; - - psDBF->iLanguageDriver = ldid > 0 ? ldid : 0; - psDBF->pszCodePage = NULL; - if( pszCodePage ) - { - psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 ); - strcpy( psDBF->pszCodePage, pszCodePage ); - } - - return( psDBF ); -} - -/************************************************************************/ -/* DBFAddField() */ -/* */ -/* Add a field to a newly created .dbf or to an existing one */ -/************************************************************************/ - -int SHPAPI_CALL -DBFAddField(DBFHandle psDBF, const char * pszFieldName, - DBFFieldType eType, int nWidth, int nDecimals ) - -{ - char chNativeType = 'C'; - - if( eType == FTLogical ) - chNativeType = 'L'; - else if( eType == FTString ) - chNativeType = 'C'; - else - chNativeType = 'N'; - - return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, - nWidth, nDecimals ); -} - -/************************************************************************/ -/* DBFAddField() */ -/* */ -/* Add a field to a newly created .dbf file before any records */ -/* are written. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, - char chType, int nWidth, int nDecimals ) - -{ - char *pszFInfo; - int i; - int nOldRecordLength, nOldHeaderLength; - char *pszRecord; - char chFieldFill; - SAOffset nRecordOffset; - -/* -------------------------------------------------------------------- */ -/* Do some checking to ensure we can add records to this file. */ -/* -------------------------------------------------------------------- */ - if( nWidth < 1 ) - return -1; - - if( nWidth > 255 ) - nWidth = 255; - - nOldRecordLength = psDBF->nRecordLength; - nOldHeaderLength = psDBF->nHeaderLength; - -/* -------------------------------------------------------------------- */ -/* SfRealloc all the arrays larger to hold the additional field */ -/* information. */ -/* -------------------------------------------------------------------- */ - psDBF->nFields++; - - psDBF->panFieldOffset = (int *) - SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); - - psDBF->panFieldSize = (int *) - SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); - - psDBF->panFieldDecimals = (int *) - SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); - - psDBF->pachFieldType = (char *) - SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); - -/* -------------------------------------------------------------------- */ -/* Assign the new field information fields. */ -/* -------------------------------------------------------------------- */ - psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength; - psDBF->nRecordLength += nWidth; - psDBF->panFieldSize[psDBF->nFields-1] = nWidth; - psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; - psDBF->pachFieldType[psDBF->nFields-1] = chType; - -/* -------------------------------------------------------------------- */ -/* Extend the required header information. */ -/* -------------------------------------------------------------------- */ - psDBF->nHeaderLength += 32; - psDBF->bUpdated = FALSE; - - psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); - - pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1); - - for( i = 0; i < 32; i++ ) - pszFInfo[i] = '\0'; - - if( (int) strlen(pszFieldName) < 10 ) - strncpy( pszFInfo, pszFieldName, strlen(pszFieldName)); - else - strncpy( pszFInfo, pszFieldName, 10); - - pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1]; - - if( chType == 'C' ) - { - pszFInfo[16] = (unsigned char) (nWidth % 256); - pszFInfo[17] = (unsigned char) (nWidth / 256); - } - else - { - pszFInfo[16] = (unsigned char) nWidth; - pszFInfo[17] = (unsigned char) nDecimals; - } - -/* -------------------------------------------------------------------- */ -/* Make the current record buffer appropriately larger. */ -/* -------------------------------------------------------------------- */ - psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, - psDBF->nRecordLength); - - /* we're done if dealing with new .dbf */ - if( psDBF->bNoHeader ) - return( psDBF->nFields - 1 ); - -/* -------------------------------------------------------------------- */ -/* For existing .dbf file, shift records */ -/* -------------------------------------------------------------------- */ - - /* alloc record */ - pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength); - - switch (chType) - { - case 'N': - case 'F': - chFieldFill = '*'; - break; - case 'D': - chFieldFill = '0'; - break; - case 'L': - chFieldFill = '?'; - break; - default: - chFieldFill = ' '; - break; - } - - for (i = psDBF->nRecords-1; i >= 0; --i) - { - nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength; - - /* load record */ - psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); - psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp ); - - /* set new field's value to NULL */ - memset(pszRecord + nOldRecordLength, chFieldFill, nWidth); - - nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength; - - /* move record to the new place*/ - psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); - psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp ); - } - - /* free record */ - free(pszRecord); - - /* force update of header with new header, record length and new field */ - psDBF->bNoHeader = TRUE; - DBFUpdateHeader( psDBF ); - - return( psDBF->nFields-1 ); -} - -/************************************************************************/ -/* DBFReadAttribute() */ -/* */ -/* Read one of the attribute fields of a record. */ -/************************************************************************/ - -static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, - char chReqType ) - -{ - unsigned char *pabyRec; - void *pReturnField = NULL; - -/* -------------------------------------------------------------------- */ -/* Verify selection. */ -/* -------------------------------------------------------------------- */ - if( hEntity < 0 || hEntity >= psDBF->nRecords ) - return( NULL ); - - if( iField < 0 || iField >= psDBF->nFields ) - return( NULL ); - -/* -------------------------------------------------------------------- */ -/* Have we read the record? */ -/* -------------------------------------------------------------------- */ - if( !DBFLoadRecord( psDBF, hEntity ) ) - return NULL; - - pabyRec = (unsigned char *) psDBF->pszCurrentRecord; - -/* -------------------------------------------------------------------- */ -/* Ensure we have room to extract the target field. */ -/* -------------------------------------------------------------------- */ - if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength ) - { - psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100; - if( psDBF->pszWorkField == NULL ) - psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength); - else - psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField, - psDBF->nWorkFieldLength); - } - -/* -------------------------------------------------------------------- */ -/* Extract the requested field. */ -/* -------------------------------------------------------------------- */ - strncpy( psDBF->pszWorkField, - ((const char *) pabyRec) + psDBF->panFieldOffset[iField], - psDBF->panFieldSize[iField] ); - psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0'; - - pReturnField = psDBF->pszWorkField; - -/* -------------------------------------------------------------------- */ -/* Decode the field. */ -/* -------------------------------------------------------------------- */ - if( chReqType == 'N' ) - { - psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField); - - pReturnField = &(psDBF->dfDoubleField); - } - -/* -------------------------------------------------------------------- */ -/* Should we trim white space off the string attribute value? */ -/* -------------------------------------------------------------------- */ -#ifdef TRIM_DBF_WHITESPACE - else - { - char *pchSrc, *pchDst; - - pchDst = pchSrc = psDBF->pszWorkField; - while( *pchSrc == ' ' ) - pchSrc++; - - while( *pchSrc != '\0' ) - *(pchDst++) = *(pchSrc++); - *pchDst = '\0'; - - while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' ) - *pchDst = '\0'; - } -#endif - - return( pReturnField ); -} - -/************************************************************************/ -/* DBFReadIntAttribute() */ -/* */ -/* Read an integer attribute. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField ) - -{ - double *pdValue; - - pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); - - if( pdValue == NULL ) - return 0; - else - return( (int) *pdValue ); -} - -/************************************************************************/ -/* DBFReadDoubleAttribute() */ -/* */ -/* Read a double attribute. */ -/************************************************************************/ - -double SHPAPI_CALL -DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField ) - -{ - double *pdValue; - - pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); - - if( pdValue == NULL ) - return 0.0; - else - return( *pdValue ); -} - -/************************************************************************/ -/* DBFReadStringAttribute() */ -/* */ -/* Read a string attribute. */ -/************************************************************************/ - -const char SHPAPI_CALL1(*) -DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField ) - -{ - return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) ); -} - -/************************************************************************/ -/* DBFReadLogicalAttribute() */ -/* */ -/* Read a logical attribute. */ -/************************************************************************/ - -const char SHPAPI_CALL1(*) -DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField ) - -{ - return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) ); -} - -/************************************************************************/ -/* DBFIsAttributeNULL() */ -/* */ -/* Return TRUE if value for field is NULL. */ -/* */ -/* Contributed by Jim Matthews. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) - -{ - const char *pszValue; - int i; - - pszValue = DBFReadStringAttribute( psDBF, iRecord, iField ); - - if( pszValue == NULL ) - return TRUE; - - switch(psDBF->pachFieldType[iField]) - { - case 'N': - case 'F': - /* - ** We accept all asterisks or all blanks as NULL - ** though according to the spec I think it should be all - ** asterisks. - */ - if( pszValue[0] == '*' ) - return TRUE; - - for( i = 0; pszValue[i] != '\0'; i++ ) - { - if( pszValue[i] != ' ' ) - return FALSE; - } - return TRUE; - - case 'D': - /* NULL date fields have value "00000000" */ - return strncmp(pszValue,"00000000",8) == 0; - - case 'L': - /* NULL boolean fields have value "?" */ - return pszValue[0] == '?'; - - default: - /* empty string fields are considered NULL */ - return strlen(pszValue) == 0; - } -} - -/************************************************************************/ -/* DBFGetFieldCount() */ -/* */ -/* Return the number of fields in this table. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFGetFieldCount( DBFHandle psDBF ) - -{ - return( psDBF->nFields ); -} - -/************************************************************************/ -/* DBFGetRecordCount() */ -/* */ -/* Return the number of records in this table. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFGetRecordCount( DBFHandle psDBF ) - -{ - return( psDBF->nRecords ); -} - -/************************************************************************/ -/* DBFGetFieldInfo() */ -/* */ -/* Return any requested information about the field. */ -/************************************************************************/ - -DBFFieldType SHPAPI_CALL -DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, - int * pnWidth, int * pnDecimals ) - -{ - if( iField < 0 || iField >= psDBF->nFields ) - return( FTInvalid ); - - if( pnWidth != NULL ) - *pnWidth = psDBF->panFieldSize[iField]; - - if( pnDecimals != NULL ) - *pnDecimals = psDBF->panFieldDecimals[iField]; - - if( pszFieldName != NULL ) - { - int i; - - strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 ); - pszFieldName[11] = '\0'; - for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- ) - pszFieldName[i] = '\0'; - } - - if ( psDBF->pachFieldType[iField] == 'L' ) - return( FTLogical); - - else if( psDBF->pachFieldType[iField] == 'N' - || psDBF->pachFieldType[iField] == 'F' ) - { - if( psDBF->panFieldDecimals[iField] > 0 - || psDBF->panFieldSize[iField] > 10 ) - return( FTDouble ); - else - return( FTInteger ); - } - else - { - return( FTString ); - } -} - -/************************************************************************/ -/* DBFWriteAttribute() */ -/* */ -/* Write an attribute record to the file. */ -/************************************************************************/ - -static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, - void * pValue ) - -{ - int i, j, nRetResult = TRUE; - unsigned char *pabyRec; - char szSField[400], szFormat[20]; - -/* -------------------------------------------------------------------- */ -/* Is this a valid record? */ -/* -------------------------------------------------------------------- */ - if( hEntity < 0 || hEntity > psDBF->nRecords ) - return( FALSE ); - - if( psDBF->bNoHeader ) - DBFWriteHeader(psDBF); - -/* -------------------------------------------------------------------- */ -/* Is this a brand new record? */ -/* -------------------------------------------------------------------- */ - if( hEntity == psDBF->nRecords ) - { - if( !DBFFlushRecord( psDBF ) ) - return FALSE; - - psDBF->nRecords++; - for( i = 0; i < psDBF->nRecordLength; i++ ) - psDBF->pszCurrentRecord[i] = ' '; - - psDBF->nCurrentRecord = hEntity; - } - -/* -------------------------------------------------------------------- */ -/* Is this an existing record, but different than the last one */ -/* we accessed? */ -/* -------------------------------------------------------------------- */ - if( !DBFLoadRecord( psDBF, hEntity ) ) - return FALSE; - - pabyRec = (unsigned char *) psDBF->pszCurrentRecord; - - psDBF->bCurrentRecordModified = TRUE; - psDBF->bUpdated = TRUE; - -/* -------------------------------------------------------------------- */ -/* Translate NULL value to valid DBF file representation. */ -/* */ -/* Contributed by Jim Matthews. */ -/* -------------------------------------------------------------------- */ - if( pValue == NULL ) - { - switch(psDBF->pachFieldType[iField]) - { - case 'N': - case 'F': - /* NULL numeric fields have value "****************" */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', - psDBF->panFieldSize[iField] ); - break; - - case 'D': - /* NULL date fields have value "00000000" */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', - psDBF->panFieldSize[iField] ); - break; - - case 'L': - /* NULL boolean fields have value "?" */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', - psDBF->panFieldSize[iField] ); - break; - - default: - /* empty string fields are considered NULL */ - memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ', - psDBF->panFieldSize[iField] ); - break; - } - return TRUE; - } - -/* -------------------------------------------------------------------- */ -/* Assign all the record fields. */ -/* -------------------------------------------------------------------- */ - switch( psDBF->pachFieldType[iField] ) - { - case 'D': - case 'N': - case 'F': - if( psDBF->panFieldDecimals[iField] == 0 ) - { - int nWidth = psDBF->panFieldSize[iField]; - - if( (int) sizeof(szSField)-2 < nWidth ) - nWidth = sizeof(szSField)-2; - - sprintf( szFormat, "%%%dd", nWidth ); - sprintf(szSField, szFormat, (int) *((double *) pValue) ); - if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) - { - szSField[psDBF->panFieldSize[iField]] = '\0'; - nRetResult = FALSE; - } - - strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), - szSField, strlen(szSField) ); - } - else - { - int nWidth = psDBF->panFieldSize[iField]; - - if( (int) sizeof(szSField)-2 < nWidth ) - nWidth = sizeof(szSField)-2; - - sprintf( szFormat, "%%%d.%df", - nWidth, psDBF->panFieldDecimals[iField] ); - sprintf(szSField, szFormat, *((double *) pValue) ); - if( (int) strlen(szSField) > psDBF->panFieldSize[iField] ) - { - szSField[psDBF->panFieldSize[iField]] = '\0'; - nRetResult = FALSE; - } - strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), - szSField, strlen(szSField) ); - } - break; - - case 'L': - if (psDBF->panFieldSize[iField] >= 1 && - (*(char*)pValue == 'F' || *(char*)pValue == 'T')) - *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue; - break; - - default: - if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] ) - { - j = psDBF->panFieldSize[iField]; - nRetResult = FALSE; - } - else - { - memset( pabyRec+psDBF->panFieldOffset[iField], ' ', - psDBF->panFieldSize[iField] ); - j = strlen((char *) pValue); - } - - strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), - (char *) pValue, j ); - break; - } - - return( nRetResult ); -} - -/************************************************************************/ -/* DBFWriteAttributeDirectly() */ -/* */ -/* Write an attribute record to the file, but without any */ -/* reformatting based on type. The provided buffer is written */ -/* as is to the field position in the record. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, - void * pValue ) - -{ - int i, j; - unsigned char *pabyRec; - -/* -------------------------------------------------------------------- */ -/* Is this a valid record? */ -/* -------------------------------------------------------------------- */ - if( hEntity < 0 || hEntity > psDBF->nRecords ) - return( FALSE ); - - if( psDBF->bNoHeader ) - DBFWriteHeader(psDBF); - -/* -------------------------------------------------------------------- */ -/* Is this a brand new record? */ -/* -------------------------------------------------------------------- */ - if( hEntity == psDBF->nRecords ) - { - if( !DBFFlushRecord( psDBF ) ) - return FALSE; - - psDBF->nRecords++; - for( i = 0; i < psDBF->nRecordLength; i++ ) - psDBF->pszCurrentRecord[i] = ' '; - - psDBF->nCurrentRecord = hEntity; - } - -/* -------------------------------------------------------------------- */ -/* Is this an existing record, but different than the last one */ -/* we accessed? */ -/* -------------------------------------------------------------------- */ - if( !DBFLoadRecord( psDBF, hEntity ) ) - return FALSE; - - pabyRec = (unsigned char *) psDBF->pszCurrentRecord; - -/* -------------------------------------------------------------------- */ -/* Assign all the record fields. */ -/* -------------------------------------------------------------------- */ - if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) - j = psDBF->panFieldSize[iField]; - else - { - memset( pabyRec+psDBF->panFieldOffset[iField], ' ', - psDBF->panFieldSize[iField] ); - j = strlen((char *) pValue); - } - - strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), - (char *) pValue, j ); - - psDBF->bCurrentRecordModified = TRUE; - psDBF->bUpdated = TRUE; - - return( TRUE ); -} - -/************************************************************************/ -/* DBFWriteDoubleAttribute() */ -/* */ -/* Write a double attribute. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField, - double dValue ) - -{ - return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); -} - -/************************************************************************/ -/* DBFWriteIntegerAttribute() */ -/* */ -/* Write a integer attribute. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField, - int nValue ) - -{ - double dValue = nValue; - - return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); -} - -/************************************************************************/ -/* DBFWriteStringAttribute() */ -/* */ -/* Write a string attribute. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField, - const char * pszValue ) - -{ - return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) ); -} - -/************************************************************************/ -/* DBFWriteNULLAttribute() */ -/* */ -/* Write a string attribute. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField ) - -{ - return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) ); -} - -/************************************************************************/ -/* DBFWriteLogicalAttribute() */ -/* */ -/* Write a logical attribute. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField, - const char lValue) - -{ - return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) ); -} - -/************************************************************************/ -/* DBFWriteTuple() */ -/* */ -/* Write an attribute record to the file. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ) - -{ - int i; - unsigned char *pabyRec; - -/* -------------------------------------------------------------------- */ -/* Is this a valid record? */ -/* -------------------------------------------------------------------- */ - if( hEntity < 0 || hEntity > psDBF->nRecords ) - return( FALSE ); - - if( psDBF->bNoHeader ) - DBFWriteHeader(psDBF); - -/* -------------------------------------------------------------------- */ -/* Is this a brand new record? */ -/* -------------------------------------------------------------------- */ - if( hEntity == psDBF->nRecords ) - { - if( !DBFFlushRecord( psDBF ) ) - return FALSE; - - psDBF->nRecords++; - for( i = 0; i < psDBF->nRecordLength; i++ ) - psDBF->pszCurrentRecord[i] = ' '; - - psDBF->nCurrentRecord = hEntity; - } - -/* -------------------------------------------------------------------- */ -/* Is this an existing record, but different than the last one */ -/* we accessed? */ -/* -------------------------------------------------------------------- */ - if( !DBFLoadRecord( psDBF, hEntity ) ) - return FALSE; - - pabyRec = (unsigned char *) psDBF->pszCurrentRecord; - - memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength ); - - psDBF->bCurrentRecordModified = TRUE; - psDBF->bUpdated = TRUE; - - return( TRUE ); -} - -/************************************************************************/ -/* DBFReadTuple() */ -/* */ -/* Read a complete record. Note that the result is only valid */ -/* till the next record read for any reason. */ -/************************************************************************/ - -const char SHPAPI_CALL1(*) -DBFReadTuple(DBFHandle psDBF, int hEntity ) - -{ - if( hEntity < 0 || hEntity >= psDBF->nRecords ) - return( NULL ); - - if( !DBFLoadRecord( psDBF, hEntity ) ) - return NULL; - - return (const char *) psDBF->pszCurrentRecord; -} - -/************************************************************************/ -/* DBFCloneEmpty() */ -/* */ -/* Read one of the attribute fields of a record. */ -/************************************************************************/ - -DBFHandle SHPAPI_CALL -DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) -{ - DBFHandle newDBF; - - newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage ); - if ( newDBF == NULL ) return ( NULL ); - - newDBF->nFields = psDBF->nFields; - newDBF->nRecordLength = psDBF->nRecordLength; - newDBF->nHeaderLength = psDBF->nHeaderLength; - - newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength ); - memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength ); - - newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); - memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); - newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields ); - memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); - newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields ); - memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); - newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields ); - memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields ); - - newDBF->bNoHeader = TRUE; - newDBF->bUpdated = TRUE; - - DBFWriteHeader ( newDBF ); - DBFClose ( newDBF ); - - newDBF = DBFOpen ( pszFilename, "rb+" ); - - return ( newDBF ); -} - -/************************************************************************/ -/* DBFGetNativeFieldType() */ -/* */ -/* Return the DBase field type for the specified field. */ -/* */ -/* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */ -/* 'N' (Numeric, with or without decimal), */ -/* 'L' (Logical), */ -/* 'M' (Memo: 10 digits .DBT block ptr) */ -/************************************************************************/ - -char SHPAPI_CALL -DBFGetNativeFieldType( DBFHandle psDBF, int iField ) - -{ - if( iField >=0 && iField < psDBF->nFields ) - return psDBF->pachFieldType[iField]; - - return ' '; -} - -/************************************************************************/ -/* str_to_upper() */ -/************************************************************************/ - -static void str_to_upper (char *string) -{ - int len; - short i = -1; - - len = strlen (string); - - while (++i < len) - if (isalpha(string[i]) && islower(string[i])) - string[i] = (char) toupper ((int)string[i]); -} - -/************************************************************************/ -/* DBFGetFieldIndex() */ -/* */ -/* Get the index number for a field in a .dbf file. */ -/* */ -/* Contributed by Jim Matthews. */ -/************************************************************************/ - -int SHPAPI_CALL -DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) - -{ - char name[12], name1[12], name2[12]; - int i; - - strncpy(name1, pszFieldName,11); - name1[11] = '\0'; - str_to_upper(name1); - - for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) - { - DBFGetFieldInfo( psDBF, i, name, NULL, NULL ); - strncpy(name2,name,11); - str_to_upper(name2); - - if(!strncmp(name1,name2,10)) - return(i); - } - return(-1); -} - -/************************************************************************/ -/* DBFIsRecordDeleted() */ -/* */ -/* Returns TRUE if the indicated record is deleted, otherwise */ -/* it returns FALSE. */ -/************************************************************************/ - -int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape ) - -{ -/* -------------------------------------------------------------------- */ -/* Verify selection. */ -/* -------------------------------------------------------------------- */ - if( iShape < 0 || iShape >= psDBF->nRecords ) - return TRUE; - -/* -------------------------------------------------------------------- */ -/* Have we read the record? */ -/* -------------------------------------------------------------------- */ - if( !DBFLoadRecord( psDBF, iShape ) ) - return FALSE; - -/* -------------------------------------------------------------------- */ -/* '*' means deleted. */ -/* -------------------------------------------------------------------- */ - return psDBF->pszCurrentRecord[0] == '*'; -} - -/************************************************************************/ -/* DBFMarkRecordDeleted() */ -/************************************************************************/ - -int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, - int bIsDeleted ) - -{ - char chNewFlag; - -/* -------------------------------------------------------------------- */ -/* Verify selection. */ -/* -------------------------------------------------------------------- */ - if( iShape < 0 || iShape >= psDBF->nRecords ) - return FALSE; - -/* -------------------------------------------------------------------- */ -/* Is this an existing record, but different than the last one */ -/* we accessed? */ -/* -------------------------------------------------------------------- */ - if( !DBFLoadRecord( psDBF, iShape ) ) - return FALSE; - -/* -------------------------------------------------------------------- */ -/* Assign value, marking record as dirty if it changes. */ -/* -------------------------------------------------------------------- */ - if( bIsDeleted ) - chNewFlag = '*'; - else - chNewFlag = ' '; - - if( psDBF->pszCurrentRecord[0] != chNewFlag ) - { - psDBF->bCurrentRecordModified = TRUE; - psDBF->bUpdated = TRUE; - psDBF->pszCurrentRecord[0] = chNewFlag; - } - - return TRUE; -} - -/************************************************************************/ -/* DBFGetCodePage */ -/************************************************************************/ - -const char SHPAPI_CALL1(*) -DBFGetCodePage(DBFHandle psDBF ) -{ - if( psDBF == NULL ) - return NULL; - return psDBF->pszCodePage; -} - -/************************************************************************/ -/* DBFDeleteField() */ -/* */ -/* Remove a field from a .dbf file */ -/************************************************************************/ - -int SHPAPI_CALL -DBFDeleteField(DBFHandle psDBF, int iField) -{ - int nOldRecordLength, nOldHeaderLength; - int nDeletedFieldOffset, nDeletedFieldSize; - SAOffset nRecordOffset; - char* pszRecord; - int i, iRecord; - - if (iField < 0 || iField >= psDBF->nFields) - return FALSE; - - /* make sure that everything is written in .dbf */ - if( !DBFFlushRecord( psDBF ) ) - return FALSE; - - /* get information about field to be deleted */ - nOldRecordLength = psDBF->nRecordLength; - nOldHeaderLength = psDBF->nHeaderLength; - nDeletedFieldOffset = psDBF->panFieldOffset[iField]; - nDeletedFieldSize = psDBF->panFieldSize[iField]; - - /* update fields info */ - for (i = iField + 1; i < psDBF->nFields; i++) - { - psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize; - psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i]; - psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i]; - psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i]; - } - - /* resize fields arrays */ - psDBF->nFields--; - - psDBF->panFieldOffset = (int *) - SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); - - psDBF->panFieldSize = (int *) - SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); - - psDBF->panFieldDecimals = (int *) - SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); - - psDBF->pachFieldType = (char *) - SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); - - /* update header information */ - psDBF->nHeaderLength -= 32; - psDBF->nRecordLength -= nDeletedFieldSize; - - /* overwrite field information in header */ - memcpy(psDBF->pszHeader + iField*32, - psDBF->pszHeader + (iField+1)*32, - sizeof(char) * (psDBF->nFields - iField)*32); - - psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); - - /* update size of current record appropriately */ - psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, - psDBF->nRecordLength); - - /* we're done if we're dealing with not yet created .dbf */ - if ( psDBF->bNoHeader && psDBF->nRecords == 0 ) - return TRUE; - - /* force update of header with new header and record length */ - psDBF->bNoHeader = TRUE; - DBFUpdateHeader( psDBF ); - - /* alloc record */ - pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength); - - /* shift records to their new positions */ - for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++) - { - nRecordOffset = - nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength; - - /* load record */ - psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); - psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp ); - - nRecordOffset = - psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; - - /* move record in two steps */ - psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); - psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp ); - psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize, - nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize, - 1, psDBF->fp ); - - } - - /* TODO: truncate file */ - - /* free record */ - free(pszRecord); - - return TRUE; -} diff --git a/navit/map/shapefile/shapefil.h b/navit/map/shapefile/shapefil.h deleted file mode 100644 index 059244b03..000000000 --- a/navit/map/shapefile/shapefil.h +++ /dev/null @@ -1,609 +0,0 @@ -#ifndef SHAPEFILE_H_INCLUDED -#define SHAPEFILE_H_INCLUDED - -/****************************************************************************** - * $Id: shapefil.h 15715 2008-11-12 15:15:21Z warmerdam $ - * - * Project: Shapelib - * Purpose: Primary include file for Shapelib. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************** - * - * $Log: shapefil.h,v $ - * Revision 1.46 2008/11/12 14:28:15 fwarmerdam - * DBFCreateField() now works on files with records - * - * Revision 1.45 2008/11/11 17:47:10 fwarmerdam - * added DBFDeleteField() function - * - * Revision 1.44 2008/01/16 20:05:19 bram - * Add file hooks that accept UTF-8 encoded filenames on some platforms. Use SASetupUtf8Hooks - * tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability. Currently, this - * is only available on the Windows platform that decodes the UTF-8 filenames to wide - * character strings and feeds them to _wfopen and _wremove. - * - * Revision 1.43 2008/01/10 16:35:30 fwarmerdam - * avoid _ prefix on #defined symbols (bug 1840) - * - * Revision 1.42 2007/12/18 18:28:14 bram - * - create hook for client specific atof (bugzilla ticket 1615) - * - check for NULL handle before closing cpCPG file, and close after reading. - * - * Revision 1.41 2007/12/15 20:25:32 bram - * dbfopen.c now reads the Code Page information from the DBF file, and exports - * this information as a string through the DBFGetCodePage function. This is - * either the number from the LDID header field ("LDID/<number>") or as the - * content of an accompanying .CPG file. When creating a DBF file, the code can - * be set using DBFCreateEx. - * - * Revision 1.40 2007/12/06 07:00:25 fwarmerdam - * dbfopen now using SAHooks for fileio - * - * Revision 1.39 2007/12/04 20:37:56 fwarmerdam - * preliminary implementation of hooks api for io and errors - * - * Revision 1.38 2007/11/21 22:39:56 fwarmerdam - * close shx file in readonly mode (GDAL #1956) - * - * Revision 1.37 2007/10/27 03:31:14 fwarmerdam - * limit default depth of tree to 12 levels (gdal ticket #1594) - * - * Revision 1.36 2007/09/10 23:33:15 fwarmerdam - * Upstreamed support for visibility flag in SHPAPI_CALL for the needs - * of GDAL (gdal ticket #1810). - * - * Revision 1.35 2007/09/03 19:48:10 fwarmerdam - * move DBFReadAttribute() static dDoubleField into dbfinfo - * - * Revision 1.34 2006/06/17 15:33:32 fwarmerdam - * added pszWorkField - bug 1202 (rso) - * - * Revision 1.33 2006/02/15 01:14:30 fwarmerdam - * added DBFAddNativeFieldType - * - * Revision 1.32 2006/01/26 15:07:32 fwarmerdam - * add bMeasureIsUsed flag from Craig Bruce: Bug 1249 - * - * Revision 1.31 2006/01/05 01:27:27 fwarmerdam - * added dbf deletion mark/fetch - * - * Revision 1.30 2005/01/03 22:30:13 fwarmerdam - * added support for saved quadtrees - * - * Revision 1.29 2004/09/26 20:09:35 fwarmerdam - * avoid rcsid warnings - * - * Revision 1.28 2003/12/29 06:02:18 fwarmerdam - * added cpl_error.h option - * - * Revision 1.27 2003/04/21 18:30:37 warmerda - * added header write/update public methods - * - * Revision 1.26 2002/09/29 00:00:08 warmerda - * added FTLogical and logical attribute read/write calls - * - * Revision 1.25 2002/05/07 13:46:30 warmerda - * added DBFWriteAttributeDirectly(). - * - * Revision 1.24 2002/04/10 16:59:54 warmerda - * added SHPRewindObject - * - * Revision 1.23 2002/01/15 14:36:07 warmerda - * updated email address - * - * Revision 1.22 2002/01/15 14:32:00 warmerda - * try to improve SHPAPI_CALL docs - */ - -#include <stdio.h> - -#ifdef USE_DBMALLOC -#include <dbmalloc.h> -#endif - -#ifdef USE_CPL -#include "cpl_error.h" -#include "cpl_vsi.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/************************************************************************/ -/* Configuration options. */ -/************************************************************************/ - -/* -------------------------------------------------------------------- */ -/* Should the DBFReadStringAttribute() strip leading and */ -/* trailing white space? */ -/* -------------------------------------------------------------------- */ -#define TRIM_DBF_WHITESPACE - -/* -------------------------------------------------------------------- */ -/* Should we write measure values to the Multipatch object? */ -/* Reportedly ArcView crashes if we do write it, so for now it */ -/* is disabled. */ -/* -------------------------------------------------------------------- */ -#define DISABLE_MULTIPATCH_MEASURE - -/* -------------------------------------------------------------------- */ -/* SHPAPI_CALL */ -/* */ -/* The following two macros are present to allow forcing */ -/* various calling conventions on the Shapelib API. */ -/* */ -/* To force __stdcall conventions (needed to call Shapelib */ -/* from Visual Basic and/or Dephi I believe) the makefile could */ -/* be modified to define: */ -/* */ -/* /DSHPAPI_CALL=__stdcall */ -/* */ -/* If it is desired to force export of the Shapelib API without */ -/* using the shapelib.def file, use the following definition. */ -/* */ -/* /DSHAPELIB_DLLEXPORT */ -/* */ -/* To get both at once it will be necessary to hack this */ -/* include file to define: */ -/* */ -/* #define SHPAPI_CALL __declspec(dllexport) __stdcall */ -/* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */ -/* */ -/* The complexity of the situtation is partly caused by the */ -/* peculiar requirement of Visual C++ that __stdcall appear */ -/* after any "*"'s in the return value of a function while the */ -/* __declspec(dllexport) must appear before them. */ -/* -------------------------------------------------------------------- */ - -#ifdef SHAPELIB_DLLEXPORT -# define SHPAPI_CALL __declspec(dllexport) -# define SHPAPI_CALL1(x) __declspec(dllexport) x -#endif - -#ifndef SHPAPI_CALL -# if defined(USE_GCC_VISIBILITY_FLAG) -# define SHPAPI_CALL __attribute__ ((visibility("default"))) -# define SHPAPI_CALL1(x) __attribute__ ((visibility("default"))) x -# else -# define SHPAPI_CALL -# endif -#endif - -#ifndef SHPAPI_CALL1 -# define SHPAPI_CALL1(x) x SHPAPI_CALL -#endif - -/* -------------------------------------------------------------------- */ -/* Macros for controlling CVSID and ensuring they don't appear */ -/* as unreferenced variables resulting in lots of warnings. */ -/* -------------------------------------------------------------------- */ -#ifndef DISABLE_CVSID -# define SHP_CVSID(string) static char cpl_cvsid[] = string; \ -static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); } -#else -# define SHP_CVSID(string) -#endif - -/* -------------------------------------------------------------------- */ -/* On some platforms, additional file IO hooks are defined that */ -/* UTF-8 encoded filenames Unicode filenames */ -/* -------------------------------------------------------------------- */ -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# define SHPAPI_WINDOWS -# define SHPAPI_UTF8_HOOKS -#endif - -/* -------------------------------------------------------------------- */ -/* IO/Error hook functions. */ -/* -------------------------------------------------------------------- */ -typedef int *SAFile; - -#ifndef SAOffset -typedef unsigned long SAOffset; -#endif - -typedef struct { - SAFile (*FOpen) ( const char *filename, const char *access); - SAOffset (*FRead) ( void *p, SAOffset size, SAOffset nmemb, SAFile file); - SAOffset (*FWrite)( void *p, SAOffset size, SAOffset nmemb, SAFile file); - SAOffset (*FSeek) ( SAFile file, SAOffset offset, int whence ); - SAOffset (*FTell) ( SAFile file ); - int (*FFlush)( SAFile file ); - int (*FClose)( SAFile file ); - int (*Remove) ( const char *filename ); - - void (*Error) ( const char *message ); - double (*Atof) ( const char *str ); -} SAHooks; - -void SHPAPI_CALL SASetupDefaultHooks( SAHooks *psHooks ); -#ifdef SHPAPI_UTF8_HOOKS -void SHPAPI_CALL SASetupUtf8Hooks( SAHooks *psHooks ); -#endif - -/************************************************************************/ -/* SHP Support. */ -/************************************************************************/ -typedef struct -{ - SAHooks sHooks; - - SAFile fpSHP; - SAFile fpSHX; - - int nShapeType; /* SHPT_* */ - - int nFileSize; /* SHP file */ - - int nRecords; - int nMaxRecords; - int *panRecOffset; - int *panRecSize; - - double adBoundsMin[4]; - double adBoundsMax[4]; - - int bUpdated; - - unsigned char *pabyRec; - int nBufSize; -} SHPInfo; - -typedef SHPInfo * SHPHandle; - -/* -------------------------------------------------------------------- */ -/* Shape types (nSHPType) */ -/* -------------------------------------------------------------------- */ -#define SHPT_NULL 0 -#define SHPT_POINT 1 -#define SHPT_ARC 3 -#define SHPT_POLYGON 5 -#define SHPT_MULTIPOINT 8 -#define SHPT_POINTZ 11 -#define SHPT_ARCZ 13 -#define SHPT_POLYGONZ 15 -#define SHPT_MULTIPOINTZ 18 -#define SHPT_POINTM 21 -#define SHPT_ARCM 23 -#define SHPT_POLYGONM 25 -#define SHPT_MULTIPOINTM 28 -#define SHPT_MULTIPATCH 31 - - -/* -------------------------------------------------------------------- */ -/* Part types - everything but SHPT_MULTIPATCH just uses */ -/* SHPP_RING. */ -/* -------------------------------------------------------------------- */ - -#define SHPP_TRISTRIP 0 -#define SHPP_TRIFAN 1 -#define SHPP_OUTERRING 2 -#define SHPP_INNERRING 3 -#define SHPP_FIRSTRING 4 -#define SHPP_RING 5 - -/* -------------------------------------------------------------------- */ -/* SHPObject - represents on shape (without attributes) read */ -/* from the .shp file. */ -/* -------------------------------------------------------------------- */ -typedef struct -{ - int nSHPType; - - int nShapeId; /* -1 is unknown/unassigned */ - - int nParts; - int *panPartStart; - int *panPartType; - - int nVertices; - double *padfX; - double *padfY; - double *padfZ; - double *padfM; - - double dfXMin; - double dfYMin; - double dfZMin; - double dfMMin; - - double dfXMax; - double dfYMax; - double dfZMax; - double dfMMax; - - int bMeasureIsUsed; -} SHPObject; - -/* -------------------------------------------------------------------- */ -/* SHP API Prototypes */ -/* -------------------------------------------------------------------- */ - -/* If pszAccess is read-only, the fpSHX field of the returned structure */ -/* will be NULL as it is not necessary to keep the SHX file open */ -SHPHandle SHPAPI_CALL - SHPOpen( const char * pszShapeFile, const char * pszAccess ); -SHPHandle SHPAPI_CALL - SHPOpenLL( const char *pszShapeFile, const char *pszAccess, - SAHooks *psHooks ); -SHPHandle SHPAPI_CALL - SHPCreate( const char * pszShapeFile, int nShapeType ); -SHPHandle SHPAPI_CALL - SHPCreateLL( const char * pszShapeFile, int nShapeType, - SAHooks *psHooks ); -void SHPAPI_CALL - SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType, - double * padfMinBound, double * padfMaxBound ); - -SHPObject SHPAPI_CALL1(*) - SHPReadObject( SHPHandle hSHP, int iShape ); -int SHPAPI_CALL - SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject * psObject ); - -void SHPAPI_CALL - SHPDestroyObject( SHPObject * psObject ); -void SHPAPI_CALL - SHPComputeExtents( SHPObject * psObject ); -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 SHPAPI_CALL1(*) - SHPCreateSimpleObject( int nSHPType, int nVertices, - const double * padfX, - const double * padfY, - const double * padfZ ); - -int SHPAPI_CALL - SHPRewindObject( SHPHandle hSHP, SHPObject * psObject ); - -void SHPAPI_CALL SHPClose( SHPHandle hSHP ); -void SHPAPI_CALL SHPWriteHeader( SHPHandle hSHP ); - -const char SHPAPI_CALL1(*) - SHPTypeName( int nSHPType ); -const char SHPAPI_CALL1(*) - SHPPartTypeName( int nPartType ); - -/* -------------------------------------------------------------------- */ -/* Shape quadtree indexing API. */ -/* -------------------------------------------------------------------- */ - -/* this can be two or four for binary or quad tree */ -#define MAX_SUBNODE 4 - -/* upper limit of tree levels for automatic estimation */ -#define MAX_DEFAULT_TREE_DEPTH 12 - -typedef struct shape_tree_node -{ - /* region covered by this node */ - double adfBoundsMin[4]; - double adfBoundsMax[4]; - - /* list of shapes stored at this node. The papsShapeObj pointers - or the whole list can be NULL */ - int nShapeCount; - int *panShapeIds; - SHPObject **papsShapeObj; - - int nSubNodes; - struct shape_tree_node *apsSubNode[MAX_SUBNODE]; - -} SHPTreeNode; - -typedef struct -{ - SHPHandle hSHP; - - int nMaxDepth; - int nDimension; - int nTotalCount; - - SHPTreeNode *psRoot; -} SHPTree; - -SHPTree SHPAPI_CALL1(*) - SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth, - double *padfBoundsMin, double *padfBoundsMax ); -void SHPAPI_CALL - SHPDestroyTree( SHPTree * hTree ); - -int SHPAPI_CALL - SHPWriteTree( SHPTree *hTree, const char * pszFilename ); -SHPTree SHPAPI_CALL - SHPReadTree( const char * pszFilename ); - -int SHPAPI_CALL - SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject ); -int SHPAPI_CALL - SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject ); -int SHPAPI_CALL - SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId ); - -void SHPAPI_CALL - SHPTreeTrimExtraNodes( SHPTree * hTree ); - -int SHPAPI_CALL1(*) - SHPTreeFindLikelyShapes( SHPTree * hTree, - double * padfBoundsMin, - double * padfBoundsMax, - int * ); -int SHPAPI_CALL - SHPCheckBoundsOverlap( double *, double *, double *, double *, int ); - -int SHPAPI_CALL1(*) -SHPSearchDiskTree( FILE *fp, - double *padfBoundsMin, double *padfBoundsMax, - int *pnShapeCount ); - -/************************************************************************/ -/* DBF Support. */ -/************************************************************************/ -typedef struct -{ - SAHooks sHooks; - - SAFile fp; - - int nRecords; - - int nRecordLength; - int nHeaderLength; - int nFields; - int *panFieldOffset; - int *panFieldSize; - int *panFieldDecimals; - char *pachFieldType; - - char *pszHeader; - - int nCurrentRecord; - int bCurrentRecordModified; - char *pszCurrentRecord; - - int nWorkFieldLength; - char *pszWorkField; - - int bNoHeader; - int bUpdated; - - double dfDoubleField; - - int iLanguageDriver; - char *pszCodePage; -} DBFInfo; - -typedef DBFInfo * DBFHandle; - -typedef enum { - FTString, - FTInteger, - FTDouble, - FTLogical, - FTInvalid -} DBFFieldType; - -#define XBASE_FLDHDR_SZ 32 - - -DBFHandle SHPAPI_CALL - DBFOpen( const char * pszDBFFile, const char * pszAccess ); -DBFHandle SHPAPI_CALL - DBFOpenLL( const char * pszDBFFile, const char * pszAccess, - SAHooks *psHooks ); -DBFHandle SHPAPI_CALL - DBFCreate( const char * pszDBFFile ); -DBFHandle SHPAPI_CALL - DBFCreateEx( const char * pszDBFFile, const char * pszCodePage ); -DBFHandle SHPAPI_CALL - DBFCreateLL( const char * pszDBFFile, const char * pszCodePage, SAHooks *psHooks ); - -int SHPAPI_CALL - DBFGetFieldCount( DBFHandle psDBF ); -int SHPAPI_CALL - DBFGetRecordCount( DBFHandle psDBF ); -int SHPAPI_CALL - DBFAddField( DBFHandle hDBF, const char * pszFieldName, - DBFFieldType eType, int nWidth, int nDecimals ); - -int SHPAPI_CALL - DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName, - char chType, int nWidth, int nDecimals ); - -int SHPAPI_CALL - DBFDeleteField( DBFHandle hDBF, int iField ); - -DBFFieldType SHPAPI_CALL - DBFGetFieldInfo( DBFHandle psDBF, int iField, - char * pszFieldName, int * pnWidth, int * pnDecimals ); - -int SHPAPI_CALL - DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName); - -int SHPAPI_CALL - DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField ); -double SHPAPI_CALL - DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField ); -const char SHPAPI_CALL1(*) - DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField ); -const char SHPAPI_CALL1(*) - DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField ); -int SHPAPI_CALL - DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField ); - -int SHPAPI_CALL - DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, - int nFieldValue ); -int SHPAPI_CALL - DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField, - double dFieldValue ); -int SHPAPI_CALL - DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField, - const char * pszFieldValue ); -int SHPAPI_CALL - DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField ); - -int SHPAPI_CALL - DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField, - const char lFieldValue); -int SHPAPI_CALL - DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, - void * pValue ); -const char SHPAPI_CALL1(*) - DBFReadTuple(DBFHandle psDBF, int hEntity ); -int SHPAPI_CALL - DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ); - -int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape ); -int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, - int bIsDeleted ); - -DBFHandle SHPAPI_CALL - DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ); - -void SHPAPI_CALL - DBFClose( DBFHandle hDBF ); -void SHPAPI_CALL - DBFUpdateHeader( DBFHandle hDBF ); -char SHPAPI_CALL - DBFGetNativeFieldType( DBFHandle hDBF, int iField ); - -const char SHPAPI_CALL1(*) - DBFGetCodePage(DBFHandle psDBF ); - -#ifdef __cplusplus -} -#endif - -#endif /* ndef SHAPEFILE_H_INCLUDED */ diff --git a/navit/map/shapefile/shpopen.c b/navit/map/shapefile/shpopen.c deleted file mode 100644 index da5365281..000000000 --- a/navit/map/shapefile/shpopen.c +++ /dev/null @@ -1,2283 +0,0 @@ -/****************************************************************************** - * $Id: shpopen.c,v 1.59 2008/03/14 05:25:31 fwarmerdam Exp $ - * - * Project: Shapelib - * Purpose: Implementation of core Shapefile read/write functions. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, 2001, Frank Warmerdam - * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************** - * - * $Log: shpopen.c,v $ - * Revision 1.59 2008/03/14 05:25:31 fwarmerdam - * Correct crash on buggy geometries (gdal #2218) - * - * Revision 1.58 2008/01/08 23:28:26 bram - * on line 2095, use a float instead of a double to avoid a compiler warning - * - * Revision 1.57 2007/12/06 07:00:25 fwarmerdam - * dbfopen now using SAHooks for fileio - * - * Revision 1.56 2007/12/04 20:37:56 fwarmerdam - * preliminary implementation of hooks api for io and errors - * - * Revision 1.55 2007/11/21 22:39:56 fwarmerdam - * close shx file in readonly mode (GDAL #1956) - * - * Revision 1.54 2007/11/15 00:12:47 mloskot - * Backported recent changes from GDAL (Ticket #1415) to Shapelib. - * - * Revision 1.53 2007/11/14 22:31:08 fwarmerdam - * checks after mallocs to detect for corrupted/voluntary broken shapefiles. - * http://trac.osgeo.org/gdal/ticket/1991 - * - * Revision 1.52 2007/06/21 15:58:33 fwarmerdam - * fix for SHPRewindObject when rings touch at one vertex (gdal #976) - * - * Revision 1.51 2006/09/04 15:24:01 fwarmerdam - * Fixed up log message for 1.49. - * - * Revision 1.50 2006/09/04 15:21:39 fwarmerdam - * fix of last fix - * - * Revision 1.49 2006/09/04 15:21:00 fwarmerdam - * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated - * files. The problem was discovered by Tim Sutton and reported here - * https://svn.qgis.org/trac/ticket/200 - * - * Revision 1.48 2006/01/26 15:07:32 fwarmerdam - * add bMeasureIsUsed flag from Craig Bruce: Bug 1249 - * - * Revision 1.47 2006/01/04 20:07:23 fwarmerdam - * In SHPWriteObject() make sure that the record length is updated - * when rewriting an existing record. - * - * Revision 1.46 2005/02/11 17:17:46 fwarmerdam - * added panPartStart[0] validation - * - * Revision 1.45 2004/09/26 20:09:48 fwarmerdam - * const correctness changes - * - * Revision 1.44 2003/12/29 00:18:39 fwarmerdam - * added error checking for failed IO and optional CPL error reporting - * - * Revision 1.43 2003/12/01 16:20:08 warmerda - * be careful of zero vertex shapes - * - * Revision 1.42 2003/12/01 14:58:27 warmerda - * added degenerate object check in SHPRewindObject() - * - * Revision 1.41 2003/07/08 15:22:43 warmerda - * avoid warning - * - * Revision 1.40 2003/04/21 18:30:37 warmerda - * added header write/update public methods - * - * Revision 1.39 2002/08/26 06:46:56 warmerda - * avoid c++ comments - * - * Revision 1.38 2002/05/07 16:43:39 warmerda - * Removed debugging printf. - * - * Revision 1.37 2002/04/10 17:35:22 warmerda - * fixed bug in ring reversal code - * - * Revision 1.36 2002/04/10 16:59:54 warmerda - * added SHPRewindObject - * - * Revision 1.35 2001/12/07 15:10:44 warmerda - * fix if .shx fails to open - * - * Revision 1.34 2001/11/01 16:29:55 warmerda - * move pabyRec into SHPInfo for thread safety - * - * Revision 1.33 2001/07/03 12:18:15 warmerda - * Improved cleanup if SHX not found, provied by Riccardo Cohen. - * - * Revision 1.32 2001/06/22 01:58:07 warmerda - * be more careful about establishing initial bounds in face of NULL shapes - * - * Revision 1.31 2001/05/31 19:35:29 warmerda - * added support for writing null shapes - * - * Revision 1.30 2001/05/28 12:46:29 warmerda - * Add some checking on reasonableness of record count when opening. - * - * Revision 1.29 2001/05/23 13:36:52 warmerda - * added use of SHPAPI_CALL - * - * Revision 1.28 2001/02/06 22:25:06 warmerda - * fixed memory leaks when SHPOpen() fails - * - * Revision 1.27 2000/07/18 15:21:33 warmerda - * added better enforcement of -1 for append in SHPWriteObject - * - * Revision 1.26 2000/02/16 16:03:51 warmerda - * added null shape support - * - * Revision 1.25 1999/12/15 13:47:07 warmerda - * Fixed record size settings in .shp file (was 4 words too long) - * Added stdlib.h. - * - * Revision 1.24 1999/11/05 14:12:04 warmerda - * updated license terms - * - * Revision 1.23 1999/07/27 00:53:46 warmerda - * added support for rewriting shapes - * - * Revision 1.22 1999/06/11 19:19:11 warmerda - * Cleanup pabyRec static buffer on SHPClose(). - * - * Revision 1.21 1999/06/02 14:57:56 kshih - * Remove unused variables - * - * Revision 1.20 1999/04/19 21:04:17 warmerda - * Fixed syntax error. - * - * Revision 1.19 1999/04/19 21:01:57 warmerda - * Force access string to binary in SHPOpen(). - * - * Revision 1.18 1999/04/01 18:48:07 warmerda - * Try upper case extensions if lower case doesn't work. - * - * Revision 1.17 1998/12/31 15:29:39 warmerda - * Disable writing measure values to multipatch objects if - * DISABLE_MULTIPATCH_MEASURE is defined. - * - * Revision 1.16 1998/12/16 05:14:33 warmerda - * Added support to write MULTIPATCH. Fixed reading Z coordinate of - * MULTIPATCH. Fixed record size written for all feature types. - * - * Revision 1.15 1998/12/03 16:35:29 warmerda - * r+b is proper binary access string, not rb+. - * - * Revision 1.14 1998/12/03 15:47:56 warmerda - * Fixed setting of nVertices in SHPCreateObject(). - * - * Revision 1.13 1998/12/03 15:33:54 warmerda - * Made SHPCalculateExtents() separately callable. - * - * Revision 1.12 1998/11/11 20:01:50 warmerda - * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines. - * - * Revision 1.11 1998/11/09 20:56:44 warmerda - * Fixed up handling of file wide bounds. - * - * Revision 1.10 1998/11/09 20:18:51 warmerda - * Converted to support 3D shapefiles, and use of SHPObject. - * - * Revision 1.9 1998/02/24 15:09:05 warmerda - * Fixed memory leak. - * - * Revision 1.8 1997/12/04 15:40:29 warmerda - * Fixed byte swapping of record number, and record length fields in the - * .shp file. - * - * Revision 1.7 1995/10/21 03:15:58 warmerda - * Added support for binary file access, the magic cookie 9997 - * and tried to improve the int32 selection logic for 16bit systems. - * - * Revision 1.6 1995/09/04 04:19:41 warmerda - * Added fix for file bounds. - * - * Revision 1.5 1995/08/25 15:16:44 warmerda - * Fixed a couple of problems with big endian systems ... one with bounds - * and the other with multipart polygons. - * - * Revision 1.4 1995/08/24 18:10:17 warmerda - * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc() - * functions (such as on the Sun). - * - * Revision 1.3 1995/08/23 02:23:15 warmerda - * Added support for reading bounds, and fixed up problems in setting the - * file wide bounds. - * - * Revision 1.2 1995/08/04 03:16:57 warmerda - * Added header. - * - */ - -#include "shapefil.h" - -#include <math.h> -#include <limits.h> -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <glib.h> - -typedef unsigned char uchar; - -#if UINT_MAX == 65535 -typedef long int32; -#else -typedef int int32; -#endif - -#ifndef FALSE -# define FALSE 0 -# define TRUE 1 -#endif - -#define ByteCopy( a, b, c ) memcpy( b, a, c ) -#ifndef MAX -# define MIN(a,b) ((a<b) ? a : b) -# define MAX(a,b) ((a>b) ? a : b) -#endif - -static int bBigEndian; - - -/************************************************************************/ -/* SwapWord() */ -/* */ -/* Swap a 2, 4 or 8 byte word. */ -/************************************************************************/ - -static void SwapWord( int length, void * wordP ) - -{ - int i; - uchar temp; - - for( i=0; i < length/2; i++ ) - { - temp = ((uchar *) wordP)[i]; - ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1]; - ((uchar *) wordP)[length-i-1] = temp; - } -} - -/************************************************************************/ -/* SfRealloc() */ -/* */ -/* A realloc cover function that will access a NULL pointer as */ -/* a valid input. */ -/************************************************************************/ - -static void * SfRealloc( void * pMem, int nNewSize ) - -{ - if( pMem == NULL ) - return( (void *) malloc(nNewSize) ); - else - return( (void *) realloc(pMem,nNewSize) ); -} - -/************************************************************************/ -/* SHPWriteHeader() */ -/* */ -/* Write out a header for the .shp and .shx files as well as the */ -/* contents of the index (.shx) file. */ -/************************************************************************/ - -void SHPWriteHeader( SHPHandle psSHP ) - -{ - uchar abyHeader[100]; - int i; - int32 i32; - double dValue; - int32 *panSHX; - - if (psSHP->fpSHX == NULL) - { - psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed"); - return; - } - -/* -------------------------------------------------------------------- */ -/* Prepare header block for .shp file. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < 100; i++ ) - abyHeader[i] = 0; - - abyHeader[2] = 0x27; /* magic cookie */ - abyHeader[3] = 0x0a; - - i32 = psSHP->nFileSize/2; /* file size */ - ByteCopy( &i32, abyHeader+24, 4 ); - if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); - - i32 = 1000; /* version */ - ByteCopy( &i32, abyHeader+28, 4 ); - if( bBigEndian ) SwapWord( 4, abyHeader+28 ); - - i32 = psSHP->nShapeType; /* shape type */ - ByteCopy( &i32, abyHeader+32, 4 ); - if( bBigEndian ) SwapWord( 4, abyHeader+32 ); - - dValue = psSHP->adBoundsMin[0]; /* set bounds */ - ByteCopy( &dValue, abyHeader+36, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+36 ); - - dValue = psSHP->adBoundsMin[1]; - ByteCopy( &dValue, abyHeader+44, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+44 ); - - dValue = psSHP->adBoundsMax[0]; - ByteCopy( &dValue, abyHeader+52, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+52 ); - - dValue = psSHP->adBoundsMax[1]; - ByteCopy( &dValue, abyHeader+60, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+60 ); - - dValue = psSHP->adBoundsMin[2]; /* z */ - ByteCopy( &dValue, abyHeader+68, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+68 ); - - dValue = psSHP->adBoundsMax[2]; - ByteCopy( &dValue, abyHeader+76, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+76 ); - - dValue = psSHP->adBoundsMin[3]; /* m */ - ByteCopy( &dValue, abyHeader+84, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+84 ); - - dValue = psSHP->adBoundsMax[3]; - ByteCopy( &dValue, abyHeader+92, 8 ); - if( bBigEndian ) SwapWord( 8, abyHeader+92 ); - -/* -------------------------------------------------------------------- */ -/* Write .shp file header. */ -/* -------------------------------------------------------------------- */ - if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0 - || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 ) - { - psSHP->sHooks.Error( "Failure writing .shp header" ); - return; - } - -/* -------------------------------------------------------------------- */ -/* Prepare, and write .shx file header. */ -/* -------------------------------------------------------------------- */ - i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */ - ByteCopy( &i32, abyHeader+24, 4 ); - if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); - - if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0 - || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 ) - { - psSHP->sHooks.Error( "Failure writing .shx header" ); - return; - } - -/* -------------------------------------------------------------------- */ -/* Write out the .shx contents. */ -/* -------------------------------------------------------------------- */ - panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords); - - for( i = 0; i < psSHP->nRecords; i++ ) - { - panSHX[i*2 ] = psSHP->panRecOffset[i]/2; - panSHX[i*2+1] = psSHP->panRecSize[i]/2; - if( !bBigEndian ) SwapWord( 4, panSHX+i*2 ); - if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 ); - } - - if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX ) - != psSHP->nRecords ) - { - psSHP->sHooks.Error( "Failure writing .shx contents" ); - } - - free( panSHX ); - -/* -------------------------------------------------------------------- */ -/* Flush to disk. */ -/* -------------------------------------------------------------------- */ - psSHP->sHooks.FFlush( psSHP->fpSHP ); - psSHP->sHooks.FFlush( psSHP->fpSHX ); -} - -/************************************************************************/ -/* SHPOpen() */ -/************************************************************************/ - -SHPHandle SHPAPI_CALL -SHPOpen( const char * pszLayer, const char * pszAccess ) - -{ - SAHooks sHooks; - - SASetupDefaultHooks( &sHooks ); - - return SHPOpenLL( pszLayer, pszAccess, &sHooks ); -} - -/************************************************************************/ -/* SHPOpen() */ -/* */ -/* Open the .shp and .shx files based on the basename of the */ -/* files or either file name. */ -/************************************************************************/ - -SHPHandle SHPAPI_CALL -SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) - -{ - char *pszFullname, *pszBasename; - SHPHandle psSHP; - - uchar *pabyBuf; - int i; - double dValue; - -/* -------------------------------------------------------------------- */ -/* Ensure the access string is one of the legal ones. We */ -/* ensure the result string indicates binary to avoid common */ -/* problems on Windows. */ -/* -------------------------------------------------------------------- */ - if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0 - || strcmp(pszAccess,"r+") == 0 ) - pszAccess = "r+b"; - else - pszAccess = "rb"; - -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this machine. */ -/* -------------------------------------------------------------------- */ - i = 1; - if( *((uchar *) &i) == 1 ) - bBigEndian = FALSE; - else - bBigEndian = TRUE; - -/* -------------------------------------------------------------------- */ -/* Initialize the info structure. */ -/* -------------------------------------------------------------------- */ - psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1); - - psSHP->bUpdated = FALSE; - memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) ); - -/* -------------------------------------------------------------------- */ -/* Compute the base (layer) name. If there is any extension */ -/* on the passed in filename we will strip it off. */ -/* -------------------------------------------------------------------- */ - pszBasename = (char *) malloc(strlen(pszLayer)+5); - strcpy( pszBasename, pszLayer ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - -/* -------------------------------------------------------------------- */ -/* Open the .shp and .shx files. Note that files pulled from */ -/* a PC to Unix with upper case filenames won't work! */ -/* -------------------------------------------------------------------- */ - pszFullname = (char *) malloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s.shp", pszBasename ) ; - psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess ); - if( psSHP->fpSHP == NULL ) - { - sprintf( pszFullname, "%s.SHP", pszBasename ); - psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess ); - } - - if( psSHP->fpSHP == NULL ) - { -#ifdef USE_CPL - CPLError( CE_Failure, CPLE_OpenFailed, - "Unable to open %s.shp or %s.SHP.", - pszBasename, pszBasename ); -#endif - free( psSHP ); - free( pszBasename ); - free( pszFullname ); - return( NULL ); - } - - sprintf( pszFullname, "%s.shx", pszBasename ); - psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess ); - if( psSHP->fpSHX == NULL ) - { - sprintf( pszFullname, "%s.SHX", pszBasename ); - psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess ); - } - - if( psSHP->fpSHX == NULL ) - { -#ifdef USE_CPL - CPLError( CE_Failure, CPLE_OpenFailed, - "Unable to open %s.shx or %s.SHX.", - pszBasename, pszBasename ); -#endif - psSHP->sHooks.FClose( psSHP->fpSHP ); - free( psSHP ); - free( pszBasename ); - free( pszFullname ); - return( NULL ); - } - - free( pszFullname ); - free( pszBasename ); - -/* -------------------------------------------------------------------- */ -/* Read the file size from the SHP file. */ -/* -------------------------------------------------------------------- */ - pabyBuf = (uchar *) malloc(100); - psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP ); - - psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256 - + pabyBuf[25] * 256 * 256 - + pabyBuf[26] * 256 - + pabyBuf[27]) * 2; - -/* -------------------------------------------------------------------- */ -/* Read SHX file Header info */ -/* -------------------------------------------------------------------- */ - if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1 - || pabyBuf[0] != 0 - || pabyBuf[1] != 0 - || pabyBuf[2] != 0x27 - || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) ) - { - psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." ); - psSHP->sHooks.FClose( psSHP->fpSHP ); - psSHP->sHooks.FClose( psSHP->fpSHX ); - free( psSHP ); - - return( NULL ); - } - - psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256 - + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256; - psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8; - - psSHP->nShapeType = pabyBuf[32]; - - if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 ) - { - char szError[200]; - - sprintf( szError, - "Record count in .shp header is %d, which seems\n" - "unreasonable. Assuming header is corrupt.", - psSHP->nRecords ); - psSHP->sHooks.Error( szError ); - psSHP->sHooks.FClose( psSHP->fpSHP ); - psSHP->sHooks.FClose( psSHP->fpSHX ); - free( psSHP ); - free(pabyBuf); - - return( NULL ); - } - -/* -------------------------------------------------------------------- */ -/* Read the bounds. */ -/* -------------------------------------------------------------------- */ - if( bBigEndian ) SwapWord( 8, pabyBuf+36 ); - memcpy( &dValue, pabyBuf+36, 8 ); - psSHP->adBoundsMin[0] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+44 ); - memcpy( &dValue, pabyBuf+44, 8 ); - psSHP->adBoundsMin[1] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+52 ); - memcpy( &dValue, pabyBuf+52, 8 ); - psSHP->adBoundsMax[0] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+60 ); - memcpy( &dValue, pabyBuf+60, 8 ); - psSHP->adBoundsMax[1] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */ - memcpy( &dValue, pabyBuf+68, 8 ); - psSHP->adBoundsMin[2] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+76 ); - memcpy( &dValue, pabyBuf+76, 8 ); - psSHP->adBoundsMax[2] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */ - memcpy( &dValue, pabyBuf+84, 8 ); - psSHP->adBoundsMin[3] = dValue; - - if( bBigEndian ) SwapWord( 8, pabyBuf+92 ); - memcpy( &dValue, pabyBuf+92, 8 ); - psSHP->adBoundsMax[3] = dValue; - - free( pabyBuf ); - -/* -------------------------------------------------------------------- */ -/* Read the .shx file to get the offsets to each record in */ -/* the .shp file. */ -/* -------------------------------------------------------------------- */ - psSHP->nMaxRecords = psSHP->nRecords; - - psSHP->panRecOffset = - (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) ); - psSHP->panRecSize = - (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) ); - pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) ); - - if (psSHP->panRecOffset == NULL || - psSHP->panRecSize == NULL || - pabyBuf == NULL) - { - char szError[200]; - - sprintf(szError, - "Not enough memory to allocate requested memory (nRecords=%d).\n" - "Probably broken SHP file", - psSHP->nRecords ); - psSHP->sHooks.Error( szError ); - psSHP->sHooks.FClose( psSHP->fpSHP ); - psSHP->sHooks.FClose( psSHP->fpSHX ); - if (psSHP->panRecOffset) free( psSHP->panRecOffset ); - if (psSHP->panRecSize) free( psSHP->panRecSize ); - if (pabyBuf) free( pabyBuf ); - free( psSHP ); - return( NULL ); - } - - if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) - != psSHP->nRecords ) - { - char szError[200]; - - sprintf( szError, - "Failed to read all values for %d records in .shx file.", - psSHP->nRecords ); - psSHP->sHooks.Error( szError ); - - /* SHX is short or unreadable for some reason. */ - psSHP->sHooks.FClose( psSHP->fpSHP ); - psSHP->sHooks.FClose( psSHP->fpSHX ); - free( psSHP->panRecOffset ); - free( psSHP->panRecSize ); - free( pabyBuf ); - free( psSHP ); - - return( NULL ); - } - - /* In read-only mode, we can close the SHX now */ - if (strcmp(pszAccess, "rb") == 0) - { - psSHP->sHooks.FClose( psSHP->fpSHX ); - psSHP->fpSHX = NULL; - } - - for( i = 0; i < psSHP->nRecords; i++ ) - { - int32 nOffset, nLength; - - memcpy( &nOffset, pabyBuf + i * 8, 4 ); - if( !bBigEndian ) SwapWord( 4, &nOffset ); - - memcpy( &nLength, pabyBuf + i * 8 + 4, 4 ); - if( !bBigEndian ) SwapWord( 4, &nLength ); - - psSHP->panRecOffset[i] = nOffset*2; - psSHP->panRecSize[i] = nLength*2; - } - free( pabyBuf ); - - return( psSHP ); -} - -/************************************************************************/ -/* SHPClose() */ -/* */ -/* Close the .shp and .shx files. */ -/************************************************************************/ - -void SHPAPI_CALL -SHPClose(SHPHandle psSHP ) - -{ - if( psSHP == NULL ) - return; - -/* -------------------------------------------------------------------- */ -/* Update the header if we have modified anything. */ -/* -------------------------------------------------------------------- */ - if( psSHP->bUpdated ) - SHPWriteHeader( psSHP ); - -/* -------------------------------------------------------------------- */ -/* Free all resources, and close files. */ -/* -------------------------------------------------------------------- */ - free( psSHP->panRecOffset ); - free( psSHP->panRecSize ); - - if ( psSHP->fpSHX != NULL) - psSHP->sHooks.FClose( psSHP->fpSHX ); - psSHP->sHooks.FClose( psSHP->fpSHP ); - - if( psSHP->pabyRec != NULL ) - { - free( psSHP->pabyRec ); - } - - free( psSHP ); -} - -/************************************************************************/ -/* SHPGetInfo() */ -/* */ -/* Fetch general information about the shape file. */ -/************************************************************************/ - -void SHPAPI_CALL -SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType, - double * padfMinBound, double * padfMaxBound ) - -{ - int i; - - if( psSHP == NULL ) - return; - - if( pnEntities != NULL ) - *pnEntities = psSHP->nRecords; - - if( pnShapeType != NULL ) - *pnShapeType = psSHP->nShapeType; - - for( i = 0; i < 4; i++ ) - { - if( padfMinBound != NULL ) - padfMinBound[i] = psSHP->adBoundsMin[i]; - if( padfMaxBound != NULL ) - padfMaxBound[i] = psSHP->adBoundsMax[i]; - } -} - -/************************************************************************/ -/* SHPCreate() */ -/* */ -/* Create a new shape file and return a handle to the open */ -/* shape file with read/write access. */ -/************************************************************************/ - -SHPHandle SHPAPI_CALL -SHPCreate( const char * pszLayer, int nShapeType ) - -{ - SAHooks sHooks; - - SASetupDefaultHooks( &sHooks ); - - return SHPCreateLL( pszLayer, nShapeType, &sHooks ); -} - -/************************************************************************/ -/* SHPCreate() */ -/* */ -/* Create a new shape file and return a handle to the open */ -/* shape file with read/write access. */ -/************************************************************************/ - -SHPHandle SHPAPI_CALL -SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) - -{ - char *pszBasename, *pszFullname; - int i; - SAFile fpSHP, fpSHX; - uchar abyHeader[100]; - int32 i32; - double dValue; - -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this system. */ -/* -------------------------------------------------------------------- */ - i = 1; - if( *((uchar *) &i) == 1 ) - bBigEndian = FALSE; - else - bBigEndian = TRUE; - -/* -------------------------------------------------------------------- */ -/* Compute the base (layer) name. If there is any extension */ -/* on the passed in filename we will strip it off. */ -/* -------------------------------------------------------------------- */ - pszBasename = (char *) malloc(strlen(pszLayer)+5); - strcpy( pszBasename, pszLayer ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - -/* -------------------------------------------------------------------- */ -/* Open the two files so we can write their headers. */ -/* -------------------------------------------------------------------- */ - pszFullname = (char *) malloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s.shp", pszBasename ); - fpSHP = psHooks->FOpen(pszFullname, "wb" ); - if( fpSHP == NULL ) - { - psHooks->Error( "Failed to create file .shp file." ); - return( NULL ); - } - - sprintf( pszFullname, "%s.shx", pszBasename ); - fpSHX = psHooks->FOpen(pszFullname, "wb" ); - if( fpSHX == NULL ) - { - psHooks->Error( "Failed to create file .shx file." ); - return( NULL ); - } - - free( pszFullname ); - free( pszBasename ); - -/* -------------------------------------------------------------------- */ -/* Prepare header block for .shp file. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < 100; i++ ) - abyHeader[i] = 0; - - abyHeader[2] = 0x27; /* magic cookie */ - abyHeader[3] = 0x0a; - - i32 = 50; /* file size */ - ByteCopy( &i32, abyHeader+24, 4 ); - if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); - - i32 = 1000; /* version */ - ByteCopy( &i32, abyHeader+28, 4 ); - if( bBigEndian ) SwapWord( 4, abyHeader+28 ); - - i32 = nShapeType; /* shape type */ - ByteCopy( &i32, abyHeader+32, 4 ); - if( bBigEndian ) SwapWord( 4, abyHeader+32 ); - - dValue = 0.0; /* set bounds */ - ByteCopy( &dValue, abyHeader+36, 8 ); - ByteCopy( &dValue, abyHeader+44, 8 ); - ByteCopy( &dValue, abyHeader+52, 8 ); - ByteCopy( &dValue, abyHeader+60, 8 ); - -/* -------------------------------------------------------------------- */ -/* Write .shp file header. */ -/* -------------------------------------------------------------------- */ - if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 ) - { - psHooks->Error( "Failed to write .shp header." ); - return NULL; - } - -/* -------------------------------------------------------------------- */ -/* Prepare, and write .shx file header. */ -/* -------------------------------------------------------------------- */ - i32 = 50; /* file size */ - ByteCopy( &i32, abyHeader+24, 4 ); - if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); - - if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 ) - { - psHooks->Error( "Failed to write .shx header." ); - return NULL; - } - -/* -------------------------------------------------------------------- */ -/* Close the files, and then open them as regular existing files. */ -/* -------------------------------------------------------------------- */ - psHooks->FClose( fpSHP ); - psHooks->FClose( fpSHX ); - - return( SHPOpenLL( pszLayer, "r+b", psHooks ) ); -} - -/************************************************************************/ -/* _SHPSetBounds() */ -/* */ -/* Compute a bounds rectangle for a shape, and set it into the */ -/* indicated location in the record. */ -/************************************************************************/ - -static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape ) - -{ - ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 ); - ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 ); - ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 ); - ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 ); - - if( bBigEndian ) - { - SwapWord( 8, pabyRec + 0 ); - SwapWord( 8, pabyRec + 8 ); - SwapWord( 8, pabyRec + 16 ); - SwapWord( 8, pabyRec + 24 ); - } -} - -/************************************************************************/ -/* SHPComputeExtents() */ -/* */ -/* Recompute the extents of a shape. Automatically done by */ -/* SHPCreateObject(). */ -/************************************************************************/ - -void SHPAPI_CALL -SHPComputeExtents( SHPObject * psObject ) - -{ - int i; - -/* -------------------------------------------------------------------- */ -/* Build extents for this object. */ -/* -------------------------------------------------------------------- */ - if( psObject->nVertices > 0 ) - { - psObject->dfXMin = psObject->dfXMax = psObject->padfX[0]; - psObject->dfYMin = psObject->dfYMax = psObject->padfY[0]; - psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0]; - psObject->dfMMin = psObject->dfMMax = psObject->padfM[0]; - } - - for( i = 0; i < psObject->nVertices; i++ ) - { - psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]); - psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]); - psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]); - psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]); - - psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]); - psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]); - psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]); - psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]); - } -} - -/************************************************************************/ -/* SHPCreateObject() */ -/* */ -/* Create a shape object. It should be freed with */ -/* SHPDestroyObject(). */ -/************************************************************************/ - -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 = (SHPObject *) calloc(1,sizeof(SHPObject)); - psObject->nSHPType = nSHPType; - psObject->nShapeId = nShapeId; - psObject->bMeasureIsUsed = FALSE; - -/* -------------------------------------------------------------------- */ -/* Establish whether this shape type has M, and Z values. */ -/* -------------------------------------------------------------------- */ - if( nSHPType == SHPT_ARCM - || nSHPType == SHPT_POINTM - || nSHPType == SHPT_POLYGONM - || nSHPType == SHPT_MULTIPOINTM ) - { - bHasM = TRUE; - bHasZ = FALSE; - } - else if( nSHPType == SHPT_ARCZ - || nSHPType == SHPT_POINTZ - || nSHPType == SHPT_POLYGONZ - || nSHPType == SHPT_MULTIPOINTZ - || nSHPType == SHPT_MULTIPATCH ) - { - bHasM = TRUE; - bHasZ = TRUE; - } - else - { - bHasM = FALSE; - bHasZ = FALSE; - } - -/* -------------------------------------------------------------------- */ -/* Capture parts. Note that part type is optional, and */ -/* defaults to ring. */ -/* -------------------------------------------------------------------- */ - if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON - || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM - || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ - || nSHPType == SHPT_MULTIPATCH ) - { - psObject->nParts = MAX(1,nParts); - - psObject->panPartStart = (int *) - malloc(sizeof(int) * psObject->nParts); - psObject->panPartType = (int *) - malloc(sizeof(int) * psObject->nParts); - - psObject->panPartStart[0] = 0; - psObject->panPartType[0] = SHPP_RING; - - for( i = 0; i < nParts; i++ ) - { - psObject->panPartStart[i] = panPartStart[i]; - - if( panPartType != NULL ) - psObject->panPartType[i] = panPartType[i]; - else - psObject->panPartType[i] = SHPP_RING; - } - - if( psObject->panPartStart[0] != 0 ) - psObject->panPartStart[0] = 0; - } - -/* -------------------------------------------------------------------- */ -/* Capture vertices. Note that Z and M are optional, but X and */ -/* Y are not. */ -/* -------------------------------------------------------------------- */ - if( nVertices > 0 ) - { - psObject->padfX = (double *) calloc(sizeof(double),nVertices); - psObject->padfY = (double *) calloc(sizeof(double),nVertices); - psObject->padfZ = (double *) calloc(sizeof(double),nVertices); - psObject->padfM = (double *) calloc(sizeof(double),nVertices); - - assert( padfX != NULL ); - assert( padfY != NULL ); - - for( i = 0; i < nVertices; i++ ) - { - psObject->padfX[i] = padfX[i]; - psObject->padfY[i] = padfY[i]; - if( padfZ != NULL && bHasZ ) - psObject->padfZ[i] = padfZ[i]; - if( padfM != NULL && bHasM ) - psObject->padfM[i] = padfM[i]; - } - if( padfM != NULL && bHasM ) - psObject->bMeasureIsUsed = TRUE; - } - -/* -------------------------------------------------------------------- */ -/* Compute the extents. */ -/* -------------------------------------------------------------------- */ - psObject->nVertices = nVertices; - SHPComputeExtents( psObject ); - - return( psObject ); -} - -/************************************************************************/ -/* SHPCreateSimpleObject() */ -/* */ -/* Create a simple (common) shape object. Destroy with */ -/* SHPDestroyObject(). */ -/************************************************************************/ - -SHPObject SHPAPI_CALL1(*) -SHPCreateSimpleObject( int nSHPType, int nVertices, - const double * padfX, const double * padfY, - const double * padfZ ) - -{ - return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL, - nVertices, padfX, padfY, padfZ, NULL ) ); -} - -/************************************************************************/ -/* SHPWriteObject() */ -/* */ -/* Write out the vertices of a new structure. Note that it is */ -/* only possible to write vertices at the end of the file. */ -/************************************************************************/ - -int SHPAPI_CALL -SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) - -{ - int nRecordOffset, i, nRecordSize=0; - uchar *pabyRec; - int32 i32; - - psSHP->bUpdated = TRUE; - -/* -------------------------------------------------------------------- */ -/* Ensure that shape object matches the type of the file it is */ -/* being written to. */ -/* -------------------------------------------------------------------- */ - assert( psObject->nSHPType == psSHP->nShapeType - || psObject->nSHPType == SHPT_NULL ); - -/* -------------------------------------------------------------------- */ -/* Ensure that -1 is used for appends. Either blow an */ -/* assertion, or if they are disabled, set the shapeid to -1 */ -/* for appends. */ -/* -------------------------------------------------------------------- */ - assert( nShapeId == -1 - || (nShapeId >= 0 && nShapeId < psSHP->nRecords) ); - - if( nShapeId != -1 && nShapeId >= psSHP->nRecords ) - nShapeId = -1; - -/* -------------------------------------------------------------------- */ -/* Add the new entity to the in memory index. */ -/* -------------------------------------------------------------------- */ - if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords ) - { - psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100); - - psSHP->panRecOffset = (int *) - SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords ); - psSHP->panRecSize = (int *) - SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords ); - } - -/* -------------------------------------------------------------------- */ -/* Initialize record. */ -/* -------------------------------------------------------------------- */ - pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) - + psObject->nParts * 8 + 128); - -/* -------------------------------------------------------------------- */ -/* Extract vertices for a Polygon or Arc. */ -/* -------------------------------------------------------------------- */ - if( psObject->nSHPType == SHPT_POLYGON - || psObject->nSHPType == SHPT_POLYGONZ - || psObject->nSHPType == SHPT_POLYGONM - || psObject->nSHPType == SHPT_ARC - || psObject->nSHPType == SHPT_ARCZ - || psObject->nSHPType == SHPT_ARCM - || psObject->nSHPType == SHPT_MULTIPATCH ) - { - int32 nPoints, nParts; - int i; - - nPoints = psObject->nVertices; - nParts = psObject->nParts; - - _SHPSetBounds( pabyRec + 12, psObject ); - - if( bBigEndian ) SwapWord( 4, &nPoints ); - if( bBigEndian ) SwapWord( 4, &nParts ); - - ByteCopy( &nPoints, pabyRec + 40 + 8, 4 ); - ByteCopy( &nParts, pabyRec + 36 + 8, 4 ); - - nRecordSize = 52; - - /* - * Write part start positions. - */ - ByteCopy( psObject->panPartStart, pabyRec + 44 + 8, - 4 * psObject->nParts ); - for( i = 0; i < psObject->nParts; i++ ) - { - if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i ); - nRecordSize += 4; - } - - /* - * Write multipatch part types if needed. - */ - if( psObject->nSHPType == SHPT_MULTIPATCH ) - { - memcpy( pabyRec + nRecordSize, psObject->panPartType, - 4*psObject->nParts ); - for( i = 0; i < psObject->nParts; i++ ) - { - if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize ); - nRecordSize += 4; - } - } - - /* - * Write the (x,y) vertex values. - */ - for( i = 0; i < psObject->nVertices; i++ ) - { - ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 ); - ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 ); - - if( bBigEndian ) - SwapWord( 8, pabyRec + nRecordSize ); - - if( bBigEndian ) - SwapWord( 8, pabyRec + nRecordSize + 8 ); - - nRecordSize += 2 * 8; - } - - /* - * Write the Z coordinates (if any). - */ - if( psObject->nSHPType == SHPT_POLYGONZ - || psObject->nSHPType == SHPT_ARCZ - || psObject->nSHPType == SHPT_MULTIPATCH ) - { - ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - for( i = 0; i < psObject->nVertices; i++ ) - { - ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - } - } - - /* - * Write the M values, if any. - */ - if( psObject->bMeasureIsUsed - && (psObject->nSHPType == SHPT_POLYGONM - || psObject->nSHPType == SHPT_ARCM -#ifndef DISABLE_MULTIPATCH_MEASURE - || psObject->nSHPType == SHPT_MULTIPATCH -#endif - || psObject->nSHPType == SHPT_POLYGONZ - || psObject->nSHPType == SHPT_ARCZ) ) - { - ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - for( i = 0; i < psObject->nVertices; i++ ) - { - ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - } - } - } - -/* -------------------------------------------------------------------- */ -/* Extract vertices for a MultiPoint. */ -/* -------------------------------------------------------------------- */ - else if( psObject->nSHPType == SHPT_MULTIPOINT - || psObject->nSHPType == SHPT_MULTIPOINTZ - || psObject->nSHPType == SHPT_MULTIPOINTM ) - { - int32 nPoints; - int i; - - nPoints = psObject->nVertices; - - _SHPSetBounds( pabyRec + 12, psObject ); - - if( bBigEndian ) SwapWord( 4, &nPoints ); - ByteCopy( &nPoints, pabyRec + 44, 4 ); - - for( i = 0; i < psObject->nVertices; i++ ) - { - ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 ); - ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 ); - - if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 ); - if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 ); - } - - nRecordSize = 48 + 16 * psObject->nVertices; - - if( psObject->nSHPType == SHPT_MULTIPOINTZ ) - { - ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - for( i = 0; i < psObject->nVertices; i++ ) - { - ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - } - } - - if( psObject->bMeasureIsUsed - && (psObject->nSHPType == SHPT_MULTIPOINTZ - || psObject->nSHPType == SHPT_MULTIPOINTM) ) - { - ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - - for( i = 0; i < psObject->nVertices; i++ ) - { - ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - } - } - } - -/* -------------------------------------------------------------------- */ -/* Write point. */ -/* -------------------------------------------------------------------- */ - else if( psObject->nSHPType == SHPT_POINT - || psObject->nSHPType == SHPT_POINTZ - || psObject->nSHPType == SHPT_POINTM ) - { - ByteCopy( psObject->padfX, pabyRec + 12, 8 ); - ByteCopy( psObject->padfY, pabyRec + 20, 8 ); - - if( bBigEndian ) SwapWord( 8, pabyRec + 12 ); - if( bBigEndian ) SwapWord( 8, pabyRec + 20 ); - - nRecordSize = 28; - - if( psObject->nSHPType == SHPT_POINTZ ) - { - ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - } - - if( psObject->bMeasureIsUsed - && (psObject->nSHPType == SHPT_POINTZ - || psObject->nSHPType == SHPT_POINTM) ) - { - ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 ); - if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); - nRecordSize += 8; - } - } - -/* -------------------------------------------------------------------- */ -/* Not much to do for null geometries. */ -/* -------------------------------------------------------------------- */ - else if( psObject->nSHPType == SHPT_NULL ) - { - nRecordSize = 12; - } - - else - { - /* unknown type */ - assert( FALSE ); - } - -/* -------------------------------------------------------------------- */ -/* Establish where we are going to put this record. If we are */ -/* rewriting and existing record, and it will fit, then put it */ -/* back where the original came from. Otherwise write at the end. */ -/* -------------------------------------------------------------------- */ - if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 ) - { - if( nShapeId == -1 ) - nShapeId = psSHP->nRecords++; - - psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize; - psSHP->panRecSize[nShapeId] = nRecordSize-8; - psSHP->nFileSize += nRecordSize; - } - else - { - nRecordOffset = psSHP->panRecOffset[nShapeId]; - psSHP->panRecSize[nShapeId] = nRecordSize-8; - } - -/* -------------------------------------------------------------------- */ -/* Set the shape type, record number, and record size. */ -/* -------------------------------------------------------------------- */ - i32 = nShapeId+1; /* record # */ - if( !bBigEndian ) SwapWord( 4, &i32 ); - ByteCopy( &i32, pabyRec, 4 ); - - i32 = (nRecordSize-8)/2; /* record size */ - if( !bBigEndian ) SwapWord( 4, &i32 ); - ByteCopy( &i32, pabyRec + 4, 4 ); - - i32 = psObject->nSHPType; /* shape type */ - if( bBigEndian ) SwapWord( 4, &i32 ); - ByteCopy( &i32, pabyRec + 8, 4 ); - -/* -------------------------------------------------------------------- */ -/* Write out record. */ -/* -------------------------------------------------------------------- */ - if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 - || psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 ) - { - psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() or fwrite() writing object to .shp file." ); - free( pabyRec ); - return -1; - } - - free( pabyRec ); - -/* -------------------------------------------------------------------- */ -/* Expand file wide bounds based on this shape. */ -/* -------------------------------------------------------------------- */ - if( psSHP->adBoundsMin[0] == 0.0 - && psSHP->adBoundsMax[0] == 0.0 - && psSHP->adBoundsMin[1] == 0.0 - && psSHP->adBoundsMax[1] == 0.0 ) - { - if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 ) - { - psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0; - psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0; - psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0; - psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0; - } - else - { - psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0]; - psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0]; - psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0]; - psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0]; - } - } - - for( i = 0; i < psObject->nVertices; i++ ) - { - psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]); - psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]); - psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]); - psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]); - psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]); - psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]); - psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]); - psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]); - } - - return( nShapeId ); -} - -/************************************************************************/ -/* SHPReadObject() */ -/* */ -/* Read the vertices, parts, and other non-attribute information */ -/* for one shape. */ -/************************************************************************/ - -SHPObject SHPAPI_CALL1(*) -SHPReadObject( SHPHandle psSHP, int hEntity ) - -{ - int nEntitySize, nRequiredSize; - SHPObject *psShape; - char pszErrorMsg[128]; - -/* -------------------------------------------------------------------- */ -/* Validate the record/entity number. */ -/* -------------------------------------------------------------------- */ - if( hEntity < 0 || hEntity >= psSHP->nRecords ) - return( NULL ); - -/* -------------------------------------------------------------------- */ -/* Ensure our record buffer is large enough. */ -/* -------------------------------------------------------------------- */ - nEntitySize = psSHP->panRecSize[hEntity]+8; - if( nEntitySize > psSHP->nBufSize ) - { - psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize); - if (psSHP->pabyRec == NULL) - { - char szError[200]; - - /* Reallocate previous successfull size for following features */ - psSHP->pabyRec = malloc(psSHP->nBufSize); - - sprintf( szError, - "Not enough memory to allocate requested memory (nBufSize=%d). " - "Probably broken SHP file", psSHP->nBufSize ); - psSHP->sHooks.Error( szError ); - return NULL; - } - - /* Only set new buffer size after successfull alloc */ - psSHP->nBufSize = nEntitySize; - } - - /* In case we were not able to reallocate the buffer on a previous step */ - if (psSHP->pabyRec == NULL) - { - return NULL; - } - -/* -------------------------------------------------------------------- */ -/* Read the record. */ -/* -------------------------------------------------------------------- */ - if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 - || psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, - psSHP->fpSHP ) != 1 ) - { - /* - * TODO - mloskot: Consider detailed diagnostics of shape file, - * for example to detect if file is truncated. - */ - - psSHP->sHooks.Error( "Error in fseek() or fread() reading object from .shp file." ); - return NULL; - } - -/* -------------------------------------------------------------------- */ -/* Allocate and minimally initialize the object. */ -/* -------------------------------------------------------------------- */ - psShape = (SHPObject *) calloc(1,sizeof(SHPObject)); - psShape->nShapeId = hEntity; - psShape->bMeasureIsUsed = FALSE; - - if ( 8 + 4 > nEntitySize ) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d", - hEntity, nEntitySize); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 ); - - if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) ); - -/* ==================================================================== */ -/* Extract vertices for a Polygon or Arc. */ -/* ==================================================================== */ - if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC - || psShape->nSHPType == SHPT_POLYGONZ - || psShape->nSHPType == SHPT_POLYGONM - || psShape->nSHPType == SHPT_ARCZ - || psShape->nSHPType == SHPT_ARCM - || psShape->nSHPType == SHPT_MULTIPATCH ) - { - int32 nPoints, nParts; - int i, nOffset; - - if ( 40 + 8 + 4 > nEntitySize ) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d", - hEntity, nEntitySize); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } -/* -------------------------------------------------------------------- */ -/* Get the X/Y bounds. */ -/* -------------------------------------------------------------------- */ - memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 ); - memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 ); - memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 ); - memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 ); - - if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) ); - -/* -------------------------------------------------------------------- */ -/* Extract part/point count, and build vertex and part arrays */ -/* to proper size. */ -/* -------------------------------------------------------------------- */ - memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 ); - memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 ); - - if( bBigEndian ) SwapWord( 4, &nPoints ); - if( bBigEndian ) SwapWord( 4, &nParts ); - - if (nPoints < 0 || nParts < 0 || - nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.", - hEntity, nPoints, nParts); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - - /* With the previous checks on nPoints and nParts, */ - /* we should not overflow here and after */ - /* since 50 M * (16 + 8 + 8) = 1 600 MB */ - nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints; - if ( psShape->nSHPType == SHPT_POLYGONZ - || psShape->nSHPType == SHPT_ARCZ - || psShape->nSHPType == SHPT_MULTIPATCH ) - { - nRequiredSize += 16 + 8 * nPoints; - } - if( psShape->nSHPType == SHPT_MULTIPATCH ) - { - nRequiredSize += 4 * nParts; - } - if (nRequiredSize > nEntitySize) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.", - hEntity, nPoints, nParts, nEntitySize); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - - psShape->nVertices = nPoints; - psShape->padfX = (double *) calloc(nPoints,sizeof(double)); - psShape->padfY = (double *) calloc(nPoints,sizeof(double)); - psShape->padfZ = (double *) calloc(nPoints,sizeof(double)); - psShape->padfM = (double *) calloc(nPoints,sizeof(double)); - - psShape->nParts = nParts; - psShape->panPartStart = (int *) calloc(nParts,sizeof(int)); - psShape->panPartType = (int *) calloc(nParts,sizeof(int)); - - if (psShape->padfX == NULL || - psShape->padfY == NULL || - psShape->padfZ == NULL || - psShape->padfM == NULL || - psShape->panPartStart == NULL || - psShape->panPartType == NULL) - { - g_snprintf(pszErrorMsg, 128, - "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. " - "Probably broken SHP file", hEntity, nPoints, nParts ); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - - for( i = 0; i < nParts; i++ ) - psShape->panPartType[i] = SHPP_RING; - -/* -------------------------------------------------------------------- */ -/* Copy out the part array from the record. */ -/* -------------------------------------------------------------------- */ - memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts ); - for( i = 0; i < nParts; i++ ) - { - if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i ); - - /* We check that the offset is inside the vertex array */ - if (psShape->panPartStart[i] < 0 || - psShape->panPartStart[i] >= psShape->nVertices) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d", - hEntity, i, psShape->panPartStart[i], psShape->nVertices); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1]) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d", - hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - } - - nOffset = 44 + 8 + 4*nParts; - -/* -------------------------------------------------------------------- */ -/* If this is a multipatch, we will also have parts types. */ -/* -------------------------------------------------------------------- */ - if( psShape->nSHPType == SHPT_MULTIPATCH ) - { - memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts ); - for( i = 0; i < nParts; i++ ) - { - if( bBigEndian ) SwapWord( 4, psShape->panPartType+i ); - } - - nOffset += 4*nParts; - } - -/* -------------------------------------------------------------------- */ -/* Copy out the vertices from the record. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < nPoints; i++ ) - { - memcpy(psShape->padfX + i, - psSHP->pabyRec + nOffset + i * 16, - 8 ); - - memcpy(psShape->padfY + i, - psSHP->pabyRec + nOffset + i * 16 + 8, - 8 ); - - if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); - if( bBigEndian ) SwapWord( 8, psShape->padfY + i ); - } - - nOffset += 16*nPoints; - -/* -------------------------------------------------------------------- */ -/* If we have a Z coordinate, collect that now. */ -/* -------------------------------------------------------------------- */ - if( psShape->nSHPType == SHPT_POLYGONZ - || psShape->nSHPType == SHPT_ARCZ - || psShape->nSHPType == SHPT_MULTIPATCH ) - { - memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 ); - - if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) ); - - for( i = 0; i < nPoints; i++ ) - { - memcpy( psShape->padfZ + i, - psSHP->pabyRec + nOffset + 16 + i*8, 8 ); - if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); - } - - nOffset += 16 + 8*nPoints; - } - -/* -------------------------------------------------------------------- */ -/* If we have a M measure value, then read it now. We assume */ -/* that the measure can be present for any shape if the size is */ -/* big enough, but really it will only occur for the Z shapes */ -/* (options), and the M shapes. */ -/* -------------------------------------------------------------------- */ - if( nEntitySize >= nOffset + 16 + 8*nPoints ) - { - memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 ); - - if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) ); - - for( i = 0; i < nPoints; i++ ) - { - memcpy( psShape->padfM + i, - psSHP->pabyRec + nOffset + 16 + i*8, 8 ); - if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); - } - psShape->bMeasureIsUsed = TRUE; - } - } - -/* ==================================================================== */ -/* Extract vertices for a MultiPoint. */ -/* ==================================================================== */ - else if( psShape->nSHPType == SHPT_MULTIPOINT - || psShape->nSHPType == SHPT_MULTIPOINTM - || psShape->nSHPType == SHPT_MULTIPOINTZ ) - { - int32 nPoints; - int i, nOffset; - - if ( 44 + 4 > nEntitySize ) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d", - hEntity, nEntitySize); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - memcpy( &nPoints, psSHP->pabyRec + 44, 4 ); - - if( bBigEndian ) SwapWord( 4, &nPoints ); - - if (nPoints < 0 || nPoints > 50 * 1000 * 1000) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d", - hEntity, nPoints); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - - nRequiredSize = 48 + nPoints * 16; - if( psShape->nSHPType == SHPT_MULTIPOINTZ ) - { - nRequiredSize += 16 + nPoints * 8; - } - if (nRequiredSize > nEntitySize) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d", - hEntity, nPoints, nEntitySize); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - - psShape->nVertices = nPoints; - psShape->padfX = (double *) calloc(nPoints,sizeof(double)); - psShape->padfY = (double *) calloc(nPoints,sizeof(double)); - psShape->padfZ = (double *) calloc(nPoints,sizeof(double)); - psShape->padfM = (double *) calloc(nPoints,sizeof(double)); - - if (psShape->padfX == NULL || - psShape->padfY == NULL || - psShape->padfZ == NULL || - psShape->padfM == NULL) - { - g_snprintf(pszErrorMsg, 128, - "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. " - "Probably broken SHP file", hEntity, nPoints ); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - - for( i = 0; i < nPoints; i++ ) - { - memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 ); - memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 ); - - if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); - if( bBigEndian ) SwapWord( 8, psShape->padfY + i ); - } - - nOffset = 48 + 16*nPoints; - -/* -------------------------------------------------------------------- */ -/* Get the X/Y bounds. */ -/* -------------------------------------------------------------------- */ - memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 ); - memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 ); - memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 ); - memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 ); - - if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) ); - -/* -------------------------------------------------------------------- */ -/* If we have a Z coordinate, collect that now. */ -/* -------------------------------------------------------------------- */ - if( psShape->nSHPType == SHPT_MULTIPOINTZ ) - { - memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 ); - - if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) ); - - for( i = 0; i < nPoints; i++ ) - { - memcpy( psShape->padfZ + i, - psSHP->pabyRec + nOffset + 16 + i*8, 8 ); - if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); - } - - nOffset += 16 + 8*nPoints; - } - -/* -------------------------------------------------------------------- */ -/* If we have a M measure value, then read it now. We assume */ -/* that the measure can be present for any shape if the size is */ -/* big enough, but really it will only occur for the Z shapes */ -/* (options), and the M shapes. */ -/* -------------------------------------------------------------------- */ - if( nEntitySize >= nOffset + 16 + 8*nPoints ) - { - memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 ); - - if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) ); - if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) ); - - for( i = 0; i < nPoints; i++ ) - { - memcpy( psShape->padfM + i, - psSHP->pabyRec + nOffset + 16 + i*8, 8 ); - if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); - } - psShape->bMeasureIsUsed = TRUE; - } - } - -/* ==================================================================== */ -/* Extract vertices for a point. */ -/* ==================================================================== */ - else if( psShape->nSHPType == SHPT_POINT - || psShape->nSHPType == SHPT_POINTM - || psShape->nSHPType == SHPT_POINTZ ) - { - int nOffset; - - psShape->nVertices = 1; - psShape->padfX = (double *) calloc(1,sizeof(double)); - psShape->padfY = (double *) calloc(1,sizeof(double)); - psShape->padfZ = (double *) calloc(1,sizeof(double)); - psShape->padfM = (double *) calloc(1,sizeof(double)); - - if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize) - { - g_snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d", - hEntity, nEntitySize); - psSHP->sHooks.Error( pszErrorMsg ); - SHPDestroyObject(psShape); - return NULL; - } - memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 ); - memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 ); - - if( bBigEndian ) SwapWord( 8, psShape->padfX ); - if( bBigEndian ) SwapWord( 8, psShape->padfY ); - - nOffset = 20 + 8; - -/* -------------------------------------------------------------------- */ -/* If we have a Z coordinate, collect that now. */ -/* -------------------------------------------------------------------- */ - if( psShape->nSHPType == SHPT_POINTZ ) - { - memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 ); - - if( bBigEndian ) SwapWord( 8, psShape->padfZ ); - - nOffset += 8; - } - -/* -------------------------------------------------------------------- */ -/* If we have a M measure value, then read it now. We assume */ -/* that the measure can be present for any shape if the size is */ -/* big enough, but really it will only occur for the Z shapes */ -/* (options), and the M shapes. */ -/* -------------------------------------------------------------------- */ - if( nEntitySize >= nOffset + 8 ) - { - memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 ); - - if( bBigEndian ) SwapWord( 8, psShape->padfM ); - psShape->bMeasureIsUsed = TRUE; - } - -/* -------------------------------------------------------------------- */ -/* Since no extents are supplied in the record, we will apply */ -/* them from the single vertex. */ -/* -------------------------------------------------------------------- */ - psShape->dfXMin = psShape->dfXMax = psShape->padfX[0]; - psShape->dfYMin = psShape->dfYMax = psShape->padfY[0]; - psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0]; - psShape->dfMMin = psShape->dfMMax = psShape->padfM[0]; - } - - return( psShape ); -} - -/************************************************************************/ -/* SHPTypeName() */ -/************************************************************************/ - -const char SHPAPI_CALL1(*) -SHPTypeName( int nSHPType ) - -{ - switch( nSHPType ) - { - case SHPT_NULL: - return "NullShape"; - - case SHPT_POINT: - return "Point"; - - case SHPT_ARC: - return "Arc"; - - case SHPT_POLYGON: - return "Polygon"; - - case SHPT_MULTIPOINT: - return "MultiPoint"; - - case SHPT_POINTZ: - return "PointZ"; - - case SHPT_ARCZ: - return "ArcZ"; - - case SHPT_POLYGONZ: - return "PolygonZ"; - - case SHPT_MULTIPOINTZ: - return "MultiPointZ"; - - case SHPT_POINTM: - return "PointM"; - - case SHPT_ARCM: - return "ArcM"; - - case SHPT_POLYGONM: - return "PolygonM"; - - case SHPT_MULTIPOINTM: - return "MultiPointM"; - - case SHPT_MULTIPATCH: - return "MultiPatch"; - - default: - return "UnknownShapeType"; - } -} - -/************************************************************************/ -/* SHPPartTypeName() */ -/************************************************************************/ - -const char SHPAPI_CALL1(*) -SHPPartTypeName( int nPartType ) - -{ - switch( nPartType ) - { - case SHPP_TRISTRIP: - return "TriangleStrip"; - - case SHPP_TRIFAN: - return "TriangleFan"; - - case SHPP_OUTERRING: - return "OuterRing"; - - case SHPP_INNERRING: - return "InnerRing"; - - case SHPP_FIRSTRING: - return "FirstRing"; - - case SHPP_RING: - return "Ring"; - - default: - return "UnknownPartType"; - } -} - -/************************************************************************/ -/* SHPDestroyObject() */ -/************************************************************************/ - -void SHPAPI_CALL -SHPDestroyObject( SHPObject * psShape ) - -{ - if( psShape == NULL ) - return; - - if( psShape->padfX != NULL ) - free( psShape->padfX ); - if( psShape->padfY != NULL ) - free( psShape->padfY ); - if( psShape->padfZ != NULL ) - free( psShape->padfZ ); - if( psShape->padfM != NULL ) - free( psShape->padfM ); - - if( psShape->panPartStart != NULL ) - free( psShape->panPartStart ); - if( psShape->panPartType != NULL ) - free( psShape->panPartType ); - - free( psShape ); -} - -/************************************************************************/ -/* SHPRewindObject() */ -/* */ -/* Reset the winding of polygon objects to adhere to the */ -/* specification. */ -/************************************************************************/ - -int SHPAPI_CALL -SHPRewindObject( SHPHandle hSHP, SHPObject * psObject ) - -{ - int iOpRing, bAltered = 0; - -/* -------------------------------------------------------------------- */ -/* Do nothing if this is not a polygon object. */ -/* -------------------------------------------------------------------- */ - if( psObject->nSHPType != SHPT_POLYGON - && psObject->nSHPType != SHPT_POLYGONZ - && psObject->nSHPType != SHPT_POLYGONM ) - return 0; - - if( psObject->nVertices == 0 || psObject->nParts == 0 ) - return 0; - -/* -------------------------------------------------------------------- */ -/* Process each of the rings. */ -/* -------------------------------------------------------------------- */ - for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ ) - { - int bInner, iVert, nVertCount, nVertStart, iCheckRing; - double dfSum, dfTestX, dfTestY; - -/* -------------------------------------------------------------------- */ -/* Determine if this ring is an inner ring or an outer ring */ -/* relative to all the other rings. For now we assume the */ -/* first ring is outer and all others are inner, but eventually */ -/* we need to fix this to handle multiple island polygons and */ -/* unordered sets of rings. */ -/* */ -/* -------------------------------------------------------------------- */ - - /* Use point in the middle of segment to avoid testing - * common points of rings. - */ - dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]] - + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2; - dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]] - + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2; - - bInner = FALSE; - for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ ) - { - int iEdge; - - if( iCheckRing == iOpRing ) - continue; - - nVertStart = psObject->panPartStart[iCheckRing]; - - if( iCheckRing == psObject->nParts-1 ) - nVertCount = psObject->nVertices - - psObject->panPartStart[iCheckRing]; - else - nVertCount = psObject->panPartStart[iCheckRing+1] - - psObject->panPartStart[iCheckRing]; - - for( iEdge = 0; iEdge < nVertCount; iEdge++ ) - { - int iNext; - - if( iEdge < nVertCount-1 ) - iNext = iEdge+1; - else - iNext = 0; - - /* Rule #1: - * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY) - * The rule #1 also excludes edges collinear with the ray. - */ - if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY - && dfTestY <= psObject->padfY[iNext+nVertStart] ) - || ( psObject->padfY[iNext+nVertStart] < dfTestY - && dfTestY <= psObject->padfY[iEdge+nVertStart] ) ) - { - /* Rule #2: - * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY) - */ - double const intersect = - ( psObject->padfX[iEdge+nVertStart] - + ( dfTestY - psObject->padfY[iEdge+nVertStart] ) - / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] ) - * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) ); - - if (intersect < dfTestX) - { - bInner = !bInner; - } - } - } - } /* for iCheckRing */ - -/* -------------------------------------------------------------------- */ -/* Determine the current order of this ring so we will know if */ -/* it has to be reversed. */ -/* -------------------------------------------------------------------- */ - nVertStart = psObject->panPartStart[iOpRing]; - - if( iOpRing == psObject->nParts-1 ) - nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing]; - else - nVertCount = psObject->panPartStart[iOpRing+1] - - psObject->panPartStart[iOpRing]; - - dfSum = 0.0; - for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ ) - { - dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1] - - psObject->padfY[iVert] * psObject->padfX[iVert+1]; - } - - dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart] - - psObject->padfY[iVert] * psObject->padfX[nVertStart]; - -/* -------------------------------------------------------------------- */ -/* Reverse if necessary. */ -/* -------------------------------------------------------------------- */ - if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) ) - { - int i; - - bAltered++; - for( i = 0; i < nVertCount/2; i++ ) - { - double dfSaved; - - /* Swap X */ - dfSaved = psObject->padfX[nVertStart+i]; - psObject->padfX[nVertStart+i] = - psObject->padfX[nVertStart+nVertCount-i-1]; - psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved; - - /* Swap Y */ - dfSaved = psObject->padfY[nVertStart+i]; - psObject->padfY[nVertStart+i] = - psObject->padfY[nVertStart+nVertCount-i-1]; - psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved; - - /* Swap Z */ - if( psObject->padfZ ) - { - dfSaved = psObject->padfZ[nVertStart+i]; - psObject->padfZ[nVertStart+i] = - psObject->padfZ[nVertStart+nVertCount-i-1]; - psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved; - } - - /* Swap M */ - if( psObject->padfM ) - { - dfSaved = psObject->padfM[nVertStart+i]; - psObject->padfM[nVertStart+i] = - psObject->padfM[nVertStart+nVertCount-i-1]; - psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved; - } - } - } - } - - return bAltered; -} diff --git a/navit/map/shapefile/shptree.c b/navit/map/shapefile/shptree.c deleted file mode 100644 index 56d33b227..000000000 --- a/navit/map/shapefile/shptree.c +++ /dev/null @@ -1,1050 +0,0 @@ -/****************************************************************************** - * $Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $ - * - * Project: Shapelib - * Purpose: Implementation of quadtree building and searching functions. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * This software is available under the following "MIT Style" license, - * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This - * option is discussed in more detail in shapelib.html. - * - * -- - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************** - * - * $Log: shptree.c,v $ - * Revision 1.12 2008/11/12 15:39:50 fwarmerdam - * improve safety in face of buggy .shp file. - * - * Revision 1.11 2007/10/27 03:31:14 fwarmerdam - * limit default depth of tree to 12 levels (gdal ticket #1594) - * - * Revision 1.10 2005/01/03 22:30:13 fwarmerdam - * added support for saved quadtrees - * - * Revision 1.9 2003/01/28 15:53:41 warmerda - * Avoid build warnings. - * - * Revision 1.8 2002/05/07 13:07:45 warmerda - * use qsort() - patch from Bernhard Herzog - * - * Revision 1.7 2002/01/15 14:36:07 warmerda - * updated email address - * - * Revision 1.6 2001/05/23 13:36:52 warmerda - * added use of SHPAPI_CALL - * - * Revision 1.5 1999/11/05 14:12:05 warmerda - * updated license terms - * - * Revision 1.4 1999/06/02 18:24:21 warmerda - * added trimming code - * - * Revision 1.3 1999/06/02 17:56:12 warmerda - * added quad'' subnode support for trees - * - * Revision 1.2 1999/05/18 19:11:11 warmerda - * Added example searching capability - * - * Revision 1.1 1999/05/18 17:49:20 warmerda - * New - * - */ - -#include "shapefil.h" - -#include <math.h> -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#ifdef USE_CPL -#include <cpl_error.h> -#endif - -#if 0 -SHP_CVSID("$Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $") -#endif - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -static int bBigEndian = 0; - -void SHPAPI_CALL SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn, double *padfBoundsMin1, double * padfBoundsMax1, double *padfBoundsMin2, double * padfBoundsMax2 ); -void SHPAPI_CALL SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode, double * padfBoundsMin, double * padfBoundsMax, int * pnShapeCount, int * pnMaxShapes, int ** ppanShapeList ); - - -/* -------------------------------------------------------------------- */ -/* If the following is 0.5, nodes will be split in half. If it */ -/* is 0.6 then each subnode will contain 60% of the parent */ -/* node, with 20% representing overlap. This can be help to */ -/* prevent small objects on a boundary from shifting too high */ -/* up the tree. */ -/* -------------------------------------------------------------------- */ - -#define SHP_SPLIT_RATIO 0.55 - -/************************************************************************/ -/* SfRealloc() */ -/* */ -/* A realloc cover function that will access a NULL pointer as */ -/* a valid input. */ -/************************************************************************/ - -static void * SfRealloc( void * pMem, int nNewSize ) - -{ - if( pMem == NULL ) - return( (void *) malloc(nNewSize) ); - else - return( (void *) realloc(pMem,nNewSize) ); -} - -/************************************************************************/ -/* SHPTreeNodeInit() */ -/* */ -/* Initialize a tree node. */ -/************************************************************************/ - -static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin, - double * padfBoundsMax ) - -{ - SHPTreeNode *psTreeNode; - - psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode)); - if( NULL == psTreeNode ) - { -#ifdef USE_CPL - CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure"); -#endif - return NULL; - } - - psTreeNode->nShapeCount = 0; - psTreeNode->panShapeIds = NULL; - psTreeNode->papsShapeObj = NULL; - - psTreeNode->nSubNodes = 0; - - if( padfBoundsMin != NULL ) - memcpy( psTreeNode->adfBoundsMin, padfBoundsMin, sizeof(double) * 4 ); - - if( padfBoundsMax != NULL ) - memcpy( psTreeNode->adfBoundsMax, padfBoundsMax, sizeof(double) * 4 ); - - return psTreeNode; -} - - -/************************************************************************/ -/* SHPCreateTree() */ -/************************************************************************/ - -SHPTree SHPAPI_CALL1(*) -SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth, - double *padfBoundsMin, double *padfBoundsMax ) - -{ - SHPTree *psTree; - - if( padfBoundsMin == NULL && hSHP == NULL ) - return NULL; - -/* -------------------------------------------------------------------- */ -/* Allocate the tree object */ -/* -------------------------------------------------------------------- */ - psTree = (SHPTree *) malloc(sizeof(SHPTree)); - if( NULL == psTree ) - { -#ifdef USE_CPL - CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure"); -#endif - return NULL; - } - - psTree->hSHP = hSHP; - psTree->nMaxDepth = nMaxDepth; - psTree->nDimension = nDimension; - psTree->nTotalCount = 0; - -/* -------------------------------------------------------------------- */ -/* If no max depth was defined, try to select a reasonable one */ -/* that implies approximately 8 shapes per node. */ -/* -------------------------------------------------------------------- */ - if( psTree->nMaxDepth == 0 && hSHP != NULL ) - { - int nMaxNodeCount = 1; - int nShapeCount; - - SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL ); - while( nMaxNodeCount*4 < nShapeCount ) - { - psTree->nMaxDepth += 1; - nMaxNodeCount = nMaxNodeCount * 2; - } - -#ifdef USE_CPL - CPLDebug( "Shape", - "Estimated spatial index tree depth: %d", - psTree->nMaxDepth ); -#endif - - /* NOTE: Due to problems with memory allocation for deep trees, - * automatically estimated depth is limited up to 12 levels. - * See Ticket #1594 for detailed discussion. - */ - if( psTree->nMaxDepth > MAX_DEFAULT_TREE_DEPTH ) - { - psTree->nMaxDepth = MAX_DEFAULT_TREE_DEPTH; - -#ifdef USE_CPL - CPLDebug( "Shape", - "Falling back to max number of allowed index tree levels (%d).", - MAX_DEFAULT_TREE_DEPTH ); -#endif - } - } - -/* -------------------------------------------------------------------- */ -/* Allocate the root node. */ -/* -------------------------------------------------------------------- */ - psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax ); - if( NULL == psTree->psRoot ) - { - return NULL; - } - -/* -------------------------------------------------------------------- */ -/* Assign the bounds to the root node. If none are passed in, */ -/* use the bounds of the provided file otherwise the create */ -/* function will have already set the bounds. */ -/* -------------------------------------------------------------------- */ - assert( NULL != psTree ); - assert( NULL != psTree->psRoot ); - - if( padfBoundsMin == NULL ) - { - SHPGetInfo( hSHP, NULL, NULL, - psTree->psRoot->adfBoundsMin, - psTree->psRoot->adfBoundsMax ); - } - -/* -------------------------------------------------------------------- */ -/* If we have a file, insert all it's shapes into the tree. */ -/* -------------------------------------------------------------------- */ - if( hSHP != NULL ) - { - int iShape, nShapeCount; - - SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL ); - - for( iShape = 0; iShape < nShapeCount; iShape++ ) - { - SHPObject *psShape; - - psShape = SHPReadObject( hSHP, iShape ); - if( psShape != NULL ) - { - SHPTreeAddShapeId( psTree, psShape ); - SHPDestroyObject( psShape ); - } - } - } - - return psTree; -} - -/************************************************************************/ -/* SHPDestroyTreeNode() */ -/************************************************************************/ - -static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode ) - -{ - int i; - - assert( NULL != psTreeNode ); - - for( i = 0; i < psTreeNode->nSubNodes; i++ ) - { - if( psTreeNode->apsSubNode[i] != NULL ) - SHPDestroyTreeNode( psTreeNode->apsSubNode[i] ); - } - - if( psTreeNode->panShapeIds != NULL ) - free( psTreeNode->panShapeIds ); - - if( psTreeNode->papsShapeObj != NULL ) - { - for( i = 0; i < psTreeNode->nShapeCount; i++ ) - { - if( psTreeNode->papsShapeObj[i] != NULL ) - SHPDestroyObject( psTreeNode->papsShapeObj[i] ); - } - - free( psTreeNode->papsShapeObj ); - } - - free( psTreeNode ); -} - -/************************************************************************/ -/* SHPDestroyTree() */ -/************************************************************************/ - -void SHPAPI_CALL -SHPDestroyTree( SHPTree * psTree ) - -{ - SHPDestroyTreeNode( psTree->psRoot ); - free( psTree ); -} - -/************************************************************************/ -/* SHPCheckBoundsOverlap() */ -/* */ -/* Do the given boxes overlap at all? */ -/************************************************************************/ - -int SHPAPI_CALL -SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max, - double * padfBox2Min, double * padfBox2Max, - int nDimension ) - -{ - int iDim; - - for( iDim = 0; iDim < nDimension; iDim++ ) - { - if( padfBox2Max[iDim] < padfBox1Min[iDim] ) - return FALSE; - - if( padfBox1Max[iDim] < padfBox2Min[iDim] ) - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* SHPCheckObjectContained() */ -/* */ -/* Does the given shape fit within the indicated extents? */ -/************************************************************************/ - -static int SHPCheckObjectContained( SHPObject * psObject, int nDimension, - double * padfBoundsMin, double * padfBoundsMax ) - -{ - if( psObject->dfXMin < padfBoundsMin[0] - || psObject->dfXMax > padfBoundsMax[0] ) - return FALSE; - - if( psObject->dfYMin < padfBoundsMin[1] - || psObject->dfYMax > padfBoundsMax[1] ) - return FALSE; - - if( nDimension == 2 ) - return TRUE; - - if( psObject->dfZMin < padfBoundsMin[2] - || psObject->dfZMax < padfBoundsMax[2] ) - return FALSE; - - if( nDimension == 3 ) - return TRUE; - - if( psObject->dfMMin < padfBoundsMin[3] - || psObject->dfMMax < padfBoundsMax[3] ) - return FALSE; - - return TRUE; -} - -/************************************************************************/ -/* SHPTreeSplitBounds() */ -/* */ -/* Split a region into two subregion evenly, cutting along the */ -/* longest dimension. */ -/************************************************************************/ - -void SHPAPI_CALL -SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn, - double *padfBoundsMin1, double * padfBoundsMax1, - double *padfBoundsMin2, double * padfBoundsMax2 ) - -{ -/* -------------------------------------------------------------------- */ -/* The output bounds will be very similar to the input bounds, */ -/* so just copy over to start. */ -/* -------------------------------------------------------------------- */ - memcpy( padfBoundsMin1, padfBoundsMinIn, sizeof(double) * 4 ); - memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 ); - memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 ); - memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 ); - -/* -------------------------------------------------------------------- */ -/* Split in X direction. */ -/* -------------------------------------------------------------------- */ - if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0]) - > (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) ) - { - double dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0]; - - padfBoundsMax1[0] = padfBoundsMinIn[0] + dfRange * SHP_SPLIT_RATIO; - padfBoundsMin2[0] = padfBoundsMaxIn[0] - dfRange * SHP_SPLIT_RATIO; - } - -/* -------------------------------------------------------------------- */ -/* Otherwise split in Y direction. */ -/* -------------------------------------------------------------------- */ - else - { - double dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1]; - - padfBoundsMax1[1] = padfBoundsMinIn[1] + dfRange * SHP_SPLIT_RATIO; - padfBoundsMin2[1] = padfBoundsMaxIn[1] - dfRange * SHP_SPLIT_RATIO; - } -} - -/************************************************************************/ -/* SHPTreeNodeAddShapeId() */ -/************************************************************************/ - -static int -SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject, - int nMaxDepth, int nDimension ) - -{ - int i; - -/* -------------------------------------------------------------------- */ -/* If there are subnodes, then consider wiether this object */ -/* will fit in them. */ -/* -------------------------------------------------------------------- */ - if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 ) - { - for( i = 0; i < psTreeNode->nSubNodes; i++ ) - { - if( SHPCheckObjectContained(psObject, nDimension, - psTreeNode->apsSubNode[i]->adfBoundsMin, - psTreeNode->apsSubNode[i]->adfBoundsMax)) - { - return SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[i], - psObject, nMaxDepth-1, - nDimension ); - } - } - } - -/* -------------------------------------------------------------------- */ -/* Otherwise, consider creating four subnodes if could fit into */ -/* them, and adding to the appropriate subnode. */ -/* -------------------------------------------------------------------- */ -#if MAX_SUBNODE == 4 - else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 ) - { - double adfBoundsMinH1[4], adfBoundsMaxH1[4]; - double adfBoundsMinH2[4], adfBoundsMaxH2[4]; - double adfBoundsMin1[4], adfBoundsMax1[4]; - double adfBoundsMin2[4], adfBoundsMax2[4]; - double adfBoundsMin3[4], adfBoundsMax3[4]; - double adfBoundsMin4[4], adfBoundsMax4[4]; - - SHPTreeSplitBounds( psTreeNode->adfBoundsMin, - psTreeNode->adfBoundsMax, - adfBoundsMinH1, adfBoundsMaxH1, - adfBoundsMinH2, adfBoundsMaxH2 ); - - SHPTreeSplitBounds( adfBoundsMinH1, adfBoundsMaxH1, - adfBoundsMin1, adfBoundsMax1, - adfBoundsMin2, adfBoundsMax2 ); - - SHPTreeSplitBounds( adfBoundsMinH2, adfBoundsMaxH2, - adfBoundsMin3, adfBoundsMax3, - adfBoundsMin4, adfBoundsMax4 ); - - if( SHPCheckObjectContained(psObject, nDimension, - adfBoundsMin1, adfBoundsMax1) - || SHPCheckObjectContained(psObject, nDimension, - adfBoundsMin2, adfBoundsMax2) - || SHPCheckObjectContained(psObject, nDimension, - adfBoundsMin3, adfBoundsMax3) - || SHPCheckObjectContained(psObject, nDimension, - adfBoundsMin4, adfBoundsMax4) ) - { - psTreeNode->nSubNodes = 4; - psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1, - adfBoundsMax1 ); - psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2, - adfBoundsMax2 ); - psTreeNode->apsSubNode[2] = SHPTreeNodeCreate( adfBoundsMin3, - adfBoundsMax3 ); - psTreeNode->apsSubNode[3] = SHPTreeNodeCreate( adfBoundsMin4, - adfBoundsMax4 ); - - /* recurse back on this node now that it has subnodes */ - return( SHPTreeNodeAddShapeId( psTreeNode, psObject, - nMaxDepth, nDimension ) ); - } - } -#endif /* MAX_SUBNODE == 4 */ - -/* -------------------------------------------------------------------- */ -/* Otherwise, consider creating two subnodes if could fit into */ -/* them, and adding to the appropriate subnode. */ -/* -------------------------------------------------------------------- */ -#if MAX_SUBNODE == 2 - else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 ) - { - double adfBoundsMin1[4], adfBoundsMax1[4]; - double adfBoundsMin2[4], adfBoundsMax2[4]; - - SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax, - adfBoundsMin1, adfBoundsMax1, - adfBoundsMin2, adfBoundsMax2 ); - - if( SHPCheckObjectContained(psObject, nDimension, - adfBoundsMin1, adfBoundsMax1)) - { - psTreeNode->nSubNodes = 2; - psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1, - adfBoundsMax1 ); - psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2, - adfBoundsMax2 ); - - return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[0], psObject, - nMaxDepth - 1, nDimension ) ); - } - else if( SHPCheckObjectContained(psObject, nDimension, - adfBoundsMin2, adfBoundsMax2) ) - { - psTreeNode->nSubNodes = 2; - psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1, - adfBoundsMax1 ); - psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2, - adfBoundsMax2 ); - - return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[1], psObject, - nMaxDepth - 1, nDimension ) ); - } - } -#endif /* MAX_SUBNODE == 2 */ - -/* -------------------------------------------------------------------- */ -/* If none of that worked, just add it to this nodes list. */ -/* -------------------------------------------------------------------- */ - psTreeNode->nShapeCount++; - - psTreeNode->panShapeIds = (int *) - SfRealloc( psTreeNode->panShapeIds, - sizeof(int) * psTreeNode->nShapeCount ); - psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId; - - if( psTreeNode->papsShapeObj != NULL ) - { - psTreeNode->papsShapeObj = (SHPObject **) - SfRealloc( psTreeNode->papsShapeObj, - sizeof(void *) * psTreeNode->nShapeCount ); - psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL; - } - - return TRUE; -} - -/************************************************************************/ -/* SHPTreeAddShapeId() */ -/* */ -/* Add a shape to the tree, but don't keep a pointer to the */ -/* object data, just keep the shapeid. */ -/************************************************************************/ - -int SHPAPI_CALL -SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject ) - -{ - psTree->nTotalCount++; - - return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject, - psTree->nMaxDepth, psTree->nDimension ) ); -} - -/************************************************************************/ -/* SHPTreeCollectShapesIds() */ -/* */ -/* Work function implementing SHPTreeFindLikelyShapes() on a */ -/* tree node by tree node basis. */ -/************************************************************************/ - -void SHPAPI_CALL -SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode, - double * padfBoundsMin, double * padfBoundsMax, - int * pnShapeCount, int * pnMaxShapes, - int ** ppanShapeList ) - -{ - int i; - -/* -------------------------------------------------------------------- */ -/* Does this node overlap the area of interest at all? If not, */ -/* return without adding to the list at all. */ -/* -------------------------------------------------------------------- */ - if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin, - psTreeNode->adfBoundsMax, - padfBoundsMin, - padfBoundsMax, - hTree->nDimension ) ) - return; - -/* -------------------------------------------------------------------- */ -/* Grow the list to hold the shapes on this node. */ -/* -------------------------------------------------------------------- */ - if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes ) - { - *pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20; - *ppanShapeList = (int *) - SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes); - } - -/* -------------------------------------------------------------------- */ -/* Add the local nodes shapeids to the list. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < psTreeNode->nShapeCount; i++ ) - { - (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i]; - } - -/* -------------------------------------------------------------------- */ -/* Recurse to subnodes if they exist. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < psTreeNode->nSubNodes; i++ ) - { - if( psTreeNode->apsSubNode[i] != NULL ) - SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i], - padfBoundsMin, padfBoundsMax, - pnShapeCount, pnMaxShapes, - ppanShapeList ); - } -} - -/************************************************************************/ -/* SHPTreeFindLikelyShapes() */ -/* */ -/* Find all shapes within tree nodes for which the tree node */ -/* bounding box overlaps the search box. The return value is */ -/* an array of shapeids terminated by a -1. The shapeids will */ -/* be in order, as hopefully this will result in faster (more */ -/* sequential) reading from the file. */ -/************************************************************************/ - -/* helper for qsort */ -static int -compare_ints( const void * a, const void * b) -{ - return (*(int*)a) - (*(int*)b); -} - -int SHPAPI_CALL1(*) -SHPTreeFindLikelyShapes( SHPTree * hTree, - double * padfBoundsMin, double * padfBoundsMax, - int * pnShapeCount ) - -{ - int *panShapeList=NULL, nMaxShapes = 0; - -/* -------------------------------------------------------------------- */ -/* Perform the search by recursive descent. */ -/* -------------------------------------------------------------------- */ - *pnShapeCount = 0; - - SHPTreeCollectShapeIds( hTree, hTree->psRoot, - padfBoundsMin, padfBoundsMax, - pnShapeCount, &nMaxShapes, - &panShapeList ); - -/* -------------------------------------------------------------------- */ -/* Sort the id array */ -/* -------------------------------------------------------------------- */ - - qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints); - - return panShapeList; -} - -/************************************************************************/ -/* SHPTreeNodeTrim() */ -/* */ -/* This is the recurve version of SHPTreeTrimExtraNodes() that */ -/* walks the tree cleaning it up. */ -/************************************************************************/ - -static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode ) - -{ - int i; - -/* -------------------------------------------------------------------- */ -/* Trim subtrees, and free subnodes that come back empty. */ -/* -------------------------------------------------------------------- */ - for( i = 0; i < psTreeNode->nSubNodes; i++ ) - { - if( SHPTreeNodeTrim( psTreeNode->apsSubNode[i] ) ) - { - SHPDestroyTreeNode( psTreeNode->apsSubNode[i] ); - - psTreeNode->apsSubNode[i] = - psTreeNode->apsSubNode[psTreeNode->nSubNodes-1]; - - psTreeNode->nSubNodes--; - - i--; /* process the new occupant of this subnode entry */ - } - } - -/* -------------------------------------------------------------------- */ -/* We should be trimmed if we have no subnodes, and no shapes. */ -/* -------------------------------------------------------------------- */ - return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 ); -} - -/************************************************************************/ -/* SHPTreeTrimExtraNodes() */ -/* */ -/* Trim empty nodes from the tree. Note that we never trim an */ -/* empty root node. */ -/************************************************************************/ - -void SHPAPI_CALL -SHPTreeTrimExtraNodes( SHPTree * hTree ) - -{ - SHPTreeNodeTrim( hTree->psRoot ); -} - -/************************************************************************/ -/* SwapWord() */ -/* */ -/* Swap a 2, 4 or 8 byte word. */ -/************************************************************************/ - -static void SwapWord( int length, void * wordP ) - -{ - int i; - unsigned char temp; - - for( i=0; i < length/2; i++ ) - { - temp = ((unsigned char *) wordP)[i]; - ((unsigned char *)wordP)[i] = ((unsigned char *) wordP)[length-i-1]; - ((unsigned char *) wordP)[length-i-1] = temp; - } -} - -/************************************************************************/ -/* SHPSearchDiskTreeNode() */ -/************************************************************************/ - -static int -SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax, - int **ppanResultBuffer, int *pnBufferMax, - int *pnResultCount, int bNeedSwap ) - -{ - int i; - int offset; - int numshapes, numsubnodes; - double adfNodeBoundsMin[2], adfNodeBoundsMax[2]; - -/* -------------------------------------------------------------------- */ -/* Read and unswap first part of node info. */ -/* -------------------------------------------------------------------- */ - fread( &offset, 4, 1, fp ); - if ( bNeedSwap ) SwapWord ( 4, &offset ); - - fread( adfNodeBoundsMin, sizeof(double), 2, fp ); - fread( adfNodeBoundsMax, sizeof(double), 2, fp ); - if ( bNeedSwap ) - { - SwapWord( 8, adfNodeBoundsMin + 0 ); - SwapWord( 8, adfNodeBoundsMin + 1 ); - SwapWord( 8, adfNodeBoundsMax + 0 ); - SwapWord( 8, adfNodeBoundsMax + 1 ); - } - - fread( &numshapes, 4, 1, fp ); - if ( bNeedSwap ) SwapWord ( 4, &numshapes ); - -/* -------------------------------------------------------------------- */ -/* If we don't overlap this node at all, we can just fseek() */ -/* pass this node info and all subnodes. */ -/* -------------------------------------------------------------------- */ - if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax, - padfBoundsMin, padfBoundsMax, 2 ) ) - { - offset += numshapes*sizeof(int) + sizeof(int); - fseek(fp, offset, SEEK_CUR); - return TRUE; - } - -/* -------------------------------------------------------------------- */ -/* Add all the shapeids at this node to our list. */ -/* -------------------------------------------------------------------- */ - if(numshapes > 0) - { - if( *pnResultCount + numshapes > *pnBufferMax ) - { - *pnBufferMax = (int) ((*pnResultCount + numshapes + 100) * 1.25); - *ppanResultBuffer = (int *) - SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) ); - } - - fread( *ppanResultBuffer + *pnResultCount, - sizeof(int), numshapes, fp ); - - if (bNeedSwap ) - { - for( i=0; i<numshapes; i++ ) - SwapWord( 4, *ppanResultBuffer + *pnResultCount + i ); - } - - *pnResultCount += numshapes; - } - -/* -------------------------------------------------------------------- */ -/* Process the subnodes. */ -/* -------------------------------------------------------------------- */ - fread( &numsubnodes, 4, 1, fp ); - if ( bNeedSwap ) SwapWord ( 4, &numsubnodes ); - - for(i=0; i<numsubnodes; i++) - { - if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax, - ppanResultBuffer, pnBufferMax, - pnResultCount, bNeedSwap ) ) - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* SHPSearchDiskTree() */ -/************************************************************************/ - -int SHPAPI_CALL1(*) -SHPSearchDiskTree( FILE *fp, - double *padfBoundsMin, double *padfBoundsMax, - int *pnShapeCount ) - -{ - int i, bNeedSwap, nBufferMax = 0; - unsigned char abyBuf[16]; - int *panResultBuffer = NULL; - - *pnShapeCount = 0; - -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this machine. */ -/* -------------------------------------------------------------------- */ - i = 1; - if( *((unsigned char *) &i) == 1 ) - bBigEndian = FALSE; - else - bBigEndian = TRUE; - -/* -------------------------------------------------------------------- */ -/* Read the header. */ -/* -------------------------------------------------------------------- */ - fseek( fp, 0, SEEK_SET ); - fread( abyBuf, 16, 1, fp ); - - if( memcmp( abyBuf, "SQT", 3 ) != 0 ) - return NULL; - - if( (abyBuf[3] == 2 && bBigEndian) - || (abyBuf[3] == 1 && !bBigEndian) ) - bNeedSwap = FALSE; - else - bNeedSwap = TRUE; - -/* -------------------------------------------------------------------- */ -/* Search through root node and it's decendents. */ -/* -------------------------------------------------------------------- */ - if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax, - &panResultBuffer, &nBufferMax, - pnShapeCount, bNeedSwap ) ) - { - if( panResultBuffer != NULL ) - free( panResultBuffer ); - *pnShapeCount = 0; - return NULL; - } -/* -------------------------------------------------------------------- */ -/* Sort the id array */ -/* -------------------------------------------------------------------- */ - qsort(panResultBuffer, *pnShapeCount, sizeof(int), compare_ints); - - return panResultBuffer; -} - -/************************************************************************/ -/* SHPGetSubNodeOffset() */ -/* */ -/* Determine how big all the subnodes of this node (and their */ -/* children) will be. This will allow disk based searchers to */ -/* seek past them all efficiently. */ -/************************************************************************/ - -static int SHPGetSubNodeOffset( SHPTreeNode *node) -{ - int i; - long offset=0; - - for(i=0; i<node->nSubNodes; i++ ) - { - if(node->apsSubNode[i]) - { - offset += 4*sizeof(double) - + (node->apsSubNode[i]->nShapeCount+3)*sizeof(int); - offset += SHPGetSubNodeOffset(node->apsSubNode[i]); - } - } - - return(offset); -} - -/************************************************************************/ -/* SHPWriteTreeNode() */ -/************************************************************************/ - -static void SHPWriteTreeNode( FILE *fp, SHPTreeNode *node) -{ - int i,j; - int offset; - unsigned char *pabyRec = NULL; - assert( NULL != node ); - - offset = SHPGetSubNodeOffset(node); - - pabyRec = (unsigned char *) - malloc(sizeof(double) * 4 - + (3 * sizeof(int)) + (node->nShapeCount * sizeof(int)) ); - if( NULL == pabyRec ) - { -#ifdef USE_CPL - CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure"); -#endif - assert( 0 ); - } - assert( NULL != pabyRec ); - - memcpy( pabyRec, &offset, 4); - - /* minx, miny, maxx, maxy */ - memcpy( pabyRec+ 4, node->adfBoundsMin+0, sizeof(double) ); - memcpy( pabyRec+12, node->adfBoundsMin+1, sizeof(double) ); - memcpy( pabyRec+20, node->adfBoundsMax+0, sizeof(double) ); - memcpy( pabyRec+28, node->adfBoundsMax+1, sizeof(double) ); - - memcpy( pabyRec+36, &node->nShapeCount, 4); - j = node->nShapeCount * sizeof(int); - memcpy( pabyRec+40, node->panShapeIds, j); - memcpy( pabyRec+j+40, &node->nSubNodes, 4); - - fwrite( pabyRec, 44+j, 1, fp ); - free (pabyRec); - - for(i=0; i<node->nSubNodes; i++ ) - { - if(node->apsSubNode[i]) - SHPWriteTreeNode( fp, node->apsSubNode[i]); - } -} - -/************************************************************************/ -/* SHPWriteTree() */ -/************************************************************************/ - -int SHPWriteTree(SHPTree *tree, const char *filename ) -{ - char signature[4] = "SQT"; - int i; - char abyBuf[32]; - FILE *fp; - -/* -------------------------------------------------------------------- */ -/* Open the output file. */ -/* -------------------------------------------------------------------- */ - fp = fopen(filename, "wb"); - if( fp == NULL ) - { - return FALSE; - } - -/* -------------------------------------------------------------------- */ -/* Establish the byte order on this machine. */ -/* -------------------------------------------------------------------- */ - i = 1; - if( *((unsigned char *) &i) == 1 ) - bBigEndian = FALSE; - else - bBigEndian = TRUE; - -/* -------------------------------------------------------------------- */ -/* Write the header. */ -/* -------------------------------------------------------------------- */ - memcpy( abyBuf+0, signature, 3 ); - - if( bBigEndian ) - abyBuf[3] = 2; /* New MSB */ - else - abyBuf[3] = 1; /* New LSB */ - - abyBuf[4] = 1; /* version */ - abyBuf[5] = 0; /* next 3 reserved */ - abyBuf[6] = 0; - abyBuf[7] = 0; - - fwrite( abyBuf, 8, 1, fp ); - - fwrite( &(tree->nTotalCount), 4, 1, fp ); - - /* write maxdepth */ - - fwrite( &(tree->nMaxDepth), 4, 1, fp ); - -/* -------------------------------------------------------------------- */ -/* Write all the nodes "in order". */ -/* -------------------------------------------------------------------- */ - - SHPWriteTreeNode( fp, tree->psRoot ); - - fclose( fp ); - - return TRUE; -} |