# Sources
# ========
+ADD_SUBDIRECTORY (src/shapelib)
ADD_SUBDIRECTORY (src/HYDROData)
ADD_SUBDIRECTORY (src/HYDROGUI)
ADD_SUBDIRECTORY (src/HYDROPy)
HYDROData_LinearInterpolator.h
HYDROData_InterpolatorsFactory.h
HYDROData_SinusX.h
- shapelib/shapefil.h
)
set(PROJECT_SOURCES
HYDROData_LinearInterpolator.cxx
HYDROData_InterpolatorsFactory.cxx
HYDROData_SinusX.cxx
- shapelib/dbfopen.c
- shapelib/safileio.c
- shapelib/shpopen.c
- shapelib/shptree.c
- shapelib/shputils.c
-)
+ )
add_definitions(
-DHYDRODATA_EXPORTS
${CMAKE_CURRENT_SOURCE_DIR}
# ${GUI_ROOT_DIR}/include/salome
${GUI_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../shapelib
)
add_library(HYDROData SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
${QT_LIBRARIES} ${GUI_ImageComposer} ${CAS_TKHLR} ${GEOM_GEOM} ${GEOM_GEOMBase} ${GEOM_CurveCreator} )
INSTALL(TARGETS HYDROData EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
-set(PROJECT_LIBRARIES HYDROData)
+set(PROJECT_LIBRARIES shapelib HYDROData)
# tests
if(SALOME_BUILD_TESTS)
+++ /dev/null
-/******************************************************************************
- * $Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 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.89 2011-07-24 05:59:25 fwarmerdam
- * minimize use of CPLError in favor of SAHooks.Error()
- *
- * Revision 1.88 2011-05-13 17:35:17 fwarmerdam
- * added DBFReorderFields() and DBFAlterFields() functions (from Even)
- *
- * Revision 1.87 2011-05-07 22:41:02 fwarmerdam
- * ensure pending record is flushed when adding a native field (GDAL #4073)
- *
- * Revision 1.86 2011-04-17 15:15:29 fwarmerdam
- * Removed unused variable.
- *
- * Revision 1.85 2010-12-06 16:09:34 fwarmerdam
- * fix buffer read overrun fetching code page (bug 2276)
- *
- * Revision 1.84 2009-10-29 19:59:48 fwarmerdam
- * avoid crash on truncated header (gdal #3093)
- *
- * 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>
-
-SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $")
-
-#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 )
- {
- char szMessage[128];
- sprintf( szMessage, "Failure writing DBF record %d.",
- psDBF->nCurrentRecord );
- psDBF->sHooks.Error( szMessage );
- 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 )
- {
- char szMessage[128];
- sprintf( szMessage, "fseek(%ld) failed on DBF file.\n",
- (long) nRecordOffset );
- psDBF->sHooks.Error( szMessage );
- return FALSE;
- }
-
- if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
- psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
- {
- char szMessage[128];
- sprintf( szMessage, "fread(%d) failed on DBF file.\n",
- psDBF->nRecordLength );
- psDBF->sHooks.Error( szMessage );
- 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];
-
- if (nHeadLen < 32)
- {
- psDBF->sHooks.FClose( psDBF->fp );
- if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
- free( pabyBuf );
- free( psDBF );
- return NULL;
- }
-
- 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;
- memset( pabyBuf, 0, nBufSize);
- 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 );
-}
-
-/************************************************************************/
-/* DBFGetNullCharacter() */
-/************************************************************************/
-
-static char DBFGetNullCharacter(char chType)
-{
- switch (chType)
- {
- case 'N':
- case 'F':
- return '*';
- case 'D':
- return '0';
- case 'L':
- return '?';
- default:
- return ' ';
- }
-}
-
-/************************************************************************/
-/* 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;
-
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return -1;
-
-/* -------------------------------------------------------------------- */
-/* 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);
-
- chFieldFill = DBFGetNullCharacter(chType);
-
- 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 );
-
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
-
- 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' ) );
-}
-
-
-/************************************************************************/
-/* DBFIsValueNULL() */
-/* */
-/* Return TRUE if the passed string is NULL. */
-/************************************************************************/
-
-static int DBFIsValueNULL( char chType, const char* pszValue )
-{
- int i;
-
- if( pszValue == NULL )
- return TRUE;
-
- switch(chType)
- {
- 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;
- }
-}
-
-/************************************************************************/
-/* 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;
-
- pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
-
- if( pszValue == NULL )
- return TRUE;
-
- return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
-}
-
-/************************************************************************/
-/* 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 )
- {
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
- DBFGetNullCharacter(psDBF->pachFieldType[iField]),
- psDBF->panFieldSize[iField] );
- 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 */
- memmove(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);
-
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
-
- return TRUE;
-}
-
-/************************************************************************/
-/* DBFReorderFields() */
-/* */
-/* Reorder the fields of a .dbf file */
-/* */
-/* panMap must be exactly psDBF->nFields long and be a permutation */
-/* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
-/* code of DBFReorderFields. */
-/************************************************************************/
-
-int SHPAPI_CALL
-DBFReorderFields( DBFHandle psDBF, int* panMap )
-{
- SAOffset nRecordOffset;
- int i, iRecord;
- int *panFieldOffsetNew;
- int *panFieldSizeNew;
- int *panFieldDecimalsNew;
- char *pachFieldTypeNew;
- char *pszHeaderNew;
- char *pszRecord;
- char *pszRecordNew;
-
- if ( psDBF->nFields == 0 )
- return TRUE;
-
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
-
- panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields);
- pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields);
-
- /* shuffle fields definitions */
- for(i=0; i < psDBF->nFields; i++)
- {
- panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
- panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
- pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
- memcpy(pszHeaderNew + i * 32,
- psDBF->pszHeader + panMap[i] * 32, 32);
- }
- panFieldOffsetNew[0] = 1;
- for(i=1; i < psDBF->nFields; i++)
- {
- panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
- }
-
- free(psDBF->pszHeader);
- psDBF->pszHeader = pszHeaderNew;
-
- /* we're done if we're dealing with not yet created .dbf */
- if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
- {
- /* force update of header with new header and record length */
- psDBF->bNoHeader = TRUE;
- DBFUpdateHeader( psDBF );
-
- /* alloc record */
- pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
-
- /* shuffle fields in records */
- for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
- {
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
-
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
-
- pszRecordNew[0] = pszRecord[0];
-
- for(i=0; i < psDBF->nFields; i++)
- {
- memcpy(pszRecordNew + panFieldOffsetNew[i],
- pszRecord + psDBF->panFieldOffset[panMap[i]],
- psDBF->panFieldSize[panMap[i]]);
- }
-
- /* write record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
- }
-
- /* free record */
- free(pszRecord);
- free(pszRecordNew);
- }
-
- free(psDBF->panFieldOffset);
- free(psDBF->panFieldSize);
- free(psDBF->panFieldDecimals);
- free(psDBF->pachFieldType);
-
- psDBF->panFieldOffset = panFieldOffsetNew;
- psDBF->panFieldSize = panFieldSizeNew;
- psDBF->panFieldDecimals =panFieldDecimalsNew;
- psDBF->pachFieldType = pachFieldTypeNew;
-
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
-
- return TRUE;
-}
-
-
-/************************************************************************/
-/* DBFAlterFieldDefn() */
-/* */
-/* Alter a field definition in a .dbf file */
-/************************************************************************/
-
-int SHPAPI_CALL
-DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
- char chType, int nWidth, int nDecimals )
-{
- int i;
- int iRecord;
- int nOffset;
- int nOldWidth;
- int nOldRecordLength;
- int nRecordOffset;
- char* pszFInfo;
- char chOldType;
- int bIsNULL;
- char chFieldFill;
-
- if (iField < 0 || iField >= psDBF->nFields)
- return FALSE;
-
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
-
- chFieldFill = DBFGetNullCharacter(chType);
-
- chOldType = psDBF->pachFieldType[iField];
- nOffset = psDBF->panFieldOffset[iField];
- nOldWidth = psDBF->panFieldSize[iField];
- nOldRecordLength = psDBF->nRecordLength;
-
-/* -------------------------------------------------------------------- */
-/* Do some checking to ensure we can add records to this file. */
-/* -------------------------------------------------------------------- */
- if( nWidth < 1 )
- return -1;
-
- if( nWidth > 255 )
- nWidth = 255;
-
-/* -------------------------------------------------------------------- */
-/* Assign the new field information fields. */
-/* -------------------------------------------------------------------- */
- psDBF->panFieldSize[iField] = nWidth;
- psDBF->panFieldDecimals[iField] = nDecimals;
- psDBF->pachFieldType[iField] = chType;
-
-/* -------------------------------------------------------------------- */
-/* Update the header information. */
-/* -------------------------------------------------------------------- */
- pszFInfo = psDBF->pszHeader + 32 * iField;
-
- 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[iField];
-
- 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;
- }
-
-/* -------------------------------------------------------------------- */
-/* Update offsets */
-/* -------------------------------------------------------------------- */
- if (nWidth != nOldWidth)
- {
- for (i = iField + 1; i < psDBF->nFields; i++)
- psDBF->panFieldOffset[i] += nWidth - nOldWidth;
- psDBF->nRecordLength += nWidth - nOldWidth;
-
- 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 );
-
- if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
- {
- char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
- char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
-
- pszOldField[nOldWidth] = 0;
-
- /* move records to their new positions */
- for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
- {
- nRecordOffset =
- nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
-
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
-
- memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
- bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
-
- if (nWidth != nOldWidth)
- {
- if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
- {
- /* Strip leading spaces when truncating a numeric field */
- memmove( pszRecord + nOffset,
- pszRecord + nOffset + nOldWidth - nWidth,
- nWidth );
- }
- if (nOffset + nOldWidth < nOldRecordLength)
- {
- memmove( pszRecord + nOffset + nWidth,
- pszRecord + nOffset + nOldWidth,
- nOldRecordLength - (nOffset + nOldWidth));
- }
- }
-
- /* Convert null value to the appropriate value of the new type */
- if (bIsNULL)
- {
- memset( pszRecord + nOffset, chFieldFill, nWidth);
- }
-
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
-
- /* write record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
- }
-
- free(pszRecord);
- free(pszOldField);
- }
- else if (nWidth > nOldWidth)
- {
- char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
-
- pszOldField[nOldWidth] = 0;
-
- /* move records to their new positions */
- for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
- {
- nRecordOffset =
- nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
-
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
-
- memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
- bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
-
- if (nOffset + nOldWidth < nOldRecordLength)
- {
- memmove( pszRecord + nOffset + nWidth,
- pszRecord + nOffset + nOldWidth,
- nOldRecordLength - (nOffset + nOldWidth));
- }
-
- /* Convert null value to the appropriate value of the new type */
- if (bIsNULL)
- {
- memset( pszRecord + nOffset, chFieldFill, nWidth);
- }
- else
- {
- if ((chOldType == 'N' || chOldType == 'F'))
- {
- /* Add leading spaces when expanding a numeric field */
- memmove( pszRecord + nOffset + nWidth - nOldWidth,
- pszRecord + nOffset, nOldWidth );
- memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
- }
- else
- {
- /* Add trailing spaces */
- memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
- }
- }
-
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
-
- /* write record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
- }
-
- free(pszRecord);
- free(pszOldField);
- }
-
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
-
- return TRUE;
-}
+++ /dev/null
-/******************************************************************************
- * $Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $
- *
- * Project: Shapelib
- * Purpose: Default implementation of file io based on stdio.
- * Author: Frank Warmerdam, warmerdam@pobox.com
- *
- ******************************************************************************
- * Copyright (c) 2007, 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: safileio.c,v $
- * Revision 1.4 2008-01-16 20:05:14 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.3 2007/12/18 18:28:11 bram
- * - create hook for client specific atof (bugzilla ticket 1615)
- * - check for NULL handle before closing cpCPG file, and close after reading.
- *
- * Revision 1.2 2007/12/15 20:25:30 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.1 2007/12/06 06:56:41 fwarmerdam
- * new
- *
- */
-
-#include "shapefil.h"
-
-#include <math.h>
-#include <limits.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-SHP_CVSID("$Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $");
-
-#ifdef SHPAPI_UTF8_HOOKS
-# ifdef SHPAPI_WINDOWS
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <windows.h>
-# pragma comment(lib, "kernel32.lib")
-# endif
-#endif
-
-/************************************************************************/
-/* SADFOpen() */
-/************************************************************************/
-
-SAFile SADFOpen( const char *pszFilename, const char *pszAccess )
-
-{
- return (SAFile) fopen( pszFilename, pszAccess );
-}
-
-/************************************************************************/
-/* SADFRead() */
-/************************************************************************/
-
-SAOffset SADFRead( void *p, SAOffset size, SAOffset nmemb, SAFile file )
-
-{
- return (SAOffset) fread( p, (size_t) size, (size_t) nmemb,
- (FILE *) file );
-}
-
-/************************************************************************/
-/* SADFWrite() */
-/************************************************************************/
-
-SAOffset SADFWrite( void *p, SAOffset size, SAOffset nmemb, SAFile file )
-
-{
- return (SAOffset) fwrite( p, (size_t) size, (size_t) nmemb,
- (FILE *) file );
-}
-
-/************************************************************************/
-/* SADFSeek() */
-/************************************************************************/
-
-SAOffset SADFSeek( SAFile file, SAOffset offset, int whence )
-
-{
- return (SAOffset) fseek( (FILE *) file, (long) offset, whence );
-}
-
-/************************************************************************/
-/* SADFTell() */
-/************************************************************************/
-
-SAOffset SADFTell( SAFile file )
-
-{
- return (SAOffset) ftell( (FILE *) file );
-}
-
-/************************************************************************/
-/* SADFFlush() */
-/************************************************************************/
-
-int SADFFlush( SAFile file )
-
-{
- return fflush( (FILE *) file );
-}
-
-/************************************************************************/
-/* SADFClose() */
-/************************************************************************/
-
-int SADFClose( SAFile file )
-
-{
- return fclose( (FILE *) file );
-}
-
-/************************************************************************/
-/* SADFClose() */
-/************************************************************************/
-
-int SADRemove( const char *filename )
-
-{
- return remove( filename );
-}
-
-/************************************************************************/
-/* SADError() */
-/************************************************************************/
-
-void SADError( const char *message )
-
-{
- fprintf( stderr, "%s\n", message );
-}
-
-/************************************************************************/
-/* SASetupDefaultHooks() */
-/************************************************************************/
-
-void SASetupDefaultHooks( SAHooks *psHooks )
-
-{
- psHooks->FOpen = SADFOpen;
- psHooks->FRead = SADFRead;
- psHooks->FWrite = SADFWrite;
- psHooks->FSeek = SADFSeek;
- psHooks->FTell = SADFTell;
- psHooks->FFlush = SADFFlush;
- psHooks->FClose = SADFClose;
- psHooks->Remove = SADRemove;
-
- psHooks->Error = SADError;
- psHooks->Atof = atof;
-}
-
-
-
-
-#ifdef SHPAPI_WINDOWS
-
-/************************************************************************/
-/* Utf8ToWideChar */
-/************************************************************************/
-
-const wchar_t* Utf8ToWideChar( const char *pszFilename )
-{
- int nMulti, nWide;
- wchar_t *pwszFileName;
-
- nMulti = strlen(pszFilename) + 1;
- nWide = MultiByteToWideChar( CP_UTF8, 0, pszFilename, nMulti, 0, 0);
- if( nWide == 0 )
- {
- return NULL;
- }
- pwszFileName = (wchar_t*) malloc(nWide * sizeof(wchar_t));
- if ( pwszFileName == NULL )
- {
- return NULL;
- }
- if( MultiByteToWideChar( CP_UTF8, 0, pszFilename, nMulti, pwszFileName, nWide ) == 0 )
- {
- free( pwszFileName );
- return NULL;
- }
- return pwszFileName;
-}
-
-/************************************************************************/
-/* SAUtf8WFOpen */
-/************************************************************************/
-
-SAFile SAUtf8WFOpen( const char *pszFilename, const char *pszAccess )
-{
- SAFile file = NULL;
- const wchar_t *pwszFileName, *pwszAccess;
- pwszFileName = Utf8ToWideChar( pszFilename );
- pwszAccess = Utf8ToWideChar( pszAccess );
- if( pwszFileName != NULL && pwszFileName != NULL)
- {
- file = (SAFile) _wfopen( pwszFileName, pwszAccess );
- }
- free ((wchar_t*) pwszFileName);
- free ((wchar_t*) pwszAccess);
- return file;
-}
-
-/************************************************************************/
-/* SAUtf8WRemove() */
-/************************************************************************/
-
-int SAUtf8WRemove( const char *pszFilename )
-{
- const wchar_t *pwszFileName = Utf8ToWideChar( pszFilename );
- int rc = -1;
- if( pwszFileName != NULL )
- {
- rc = _wremove( pwszFileName );
- }
- free ((wchar_t*) pwszFileName);
- return rc;
-}
-
-#endif
-
-#ifdef SHPAPI_UTF8_HOOKS
-
-/************************************************************************/
-/* SASetupUtf8Hooks() */
-/************************************************************************/
-
-void SASetupUtf8Hooks( SAHooks *psHooks )
-{
-#ifdef SHPAPI_WINDOWS
- psHooks->FOpen = SAUtf8WFOpen;
- psHooks->Remove = SAUtf8WRemove;
-#else
-# error "no implementations of UTF-8 hooks available for this platform"
-#endif
- psHooks->FRead = SADFRead;
- psHooks->FWrite = SADFWrite;
- psHooks->FSeek = SADFSeek;
- psHooks->FTell = SADFTell;
- psHooks->FFlush = SADFFlush;
- psHooks->FClose = SADFClose;
-
- psHooks->Error = SADError;
- psHooks->Atof = atof;
-}
-
-#endif
+++ /dev/null
-#ifndef SHAPEFILE_H_INCLUDED
-#define SHAPEFILE_H_INCLUDED
-
-/******************************************************************************
- * $Id: shapefil.h,v 1.52 2011-12-11 22:26:46 fwarmerdam Exp $
- *
- * 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.52 2011-12-11 22:26:46 fwarmerdam
- * upgrade .qix access code to use SAHooks (gdal #3365)
- *
- * Revision 1.51 2011-07-24 05:59:25 fwarmerdam
- * minimize use of CPLError in favor of SAHooks.Error()
- *
- * Revision 1.50 2011-05-13 17:35:17 fwarmerdam
- * added DBFReorderFields() and DBFAlterFields() functions (from Even)
- *
- * Revision 1.49 2011-04-16 14:38:21 fwarmerdam
- * avoid warnings with gcc on SHP_CVSID
- *
- * Revision 1.48 2010-08-27 23:42:52 fwarmerdam
- * add SHPAPI_CALL attribute in code
- *
- * Revision 1.47 2010-01-28 11:34:34 fwarmerdam
- * handle the shape file length limits more gracefully (#3236)
- *
- * 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 __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 WIN32
- #define SHAPELIB_DLLEXPORT 1
-#endif
-
-#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
-# if defined(__GNUC__) && __GNUC__ >= 4
-# define SHP_CVSID(string) static char cpl_cvsid[] __attribute__((used)) = string;
-# else
-# define SHP_CVSID(string) static char cpl_cvsid[] = string; \
-static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
-# endif
-#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_* */
-
- unsigned int nFileSize; /* SHP file */
-
- int nRecords;
- int nMaxRecords;
- unsigned int *panRecOffset;
- unsigned 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 );
-
-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 );
-
-
-typedef struct SHPDiskTreeInfo* SHPTreeDiskHandle;
-
-SHPTreeDiskHandle SHPAPI_CALL
- SHPOpenDiskTree( const char* pszQIXFilename,
- SAHooks *psHooks );
-
-void SHPAPI_CALL
- SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree );
-
-int SHPAPI_CALL1(*)
-SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
- double *padfBoundsMin, double *padfBoundsMax,
- int *pnShapeCount );
-
-int SHPAPI_CALL
- SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, SAHooks *psHooks );
-
-/************************************************************************/
-/* 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 );
-
-int SHPAPI_CALL
- DBFReorderFields( DBFHandle psDBF, int* panMap );
-
-int SHPAPI_CALL
- DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
- char chType, int nWidth, int nDecimals );
-
-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 */
+++ /dev/null
-/******************************************************************************
- * $Id: shpopen.c,v 1.73 2012-01-24 22:33:01 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.73 2012-01-24 22:33:01 fwarmerdam
- * fix memory leak on failure to open .shp (gdal #4410)
- *
- * Revision 1.72 2011-12-11 22:45:28 fwarmerdam
- * fix failure return from SHPOpenLL.
- *
- * Revision 1.71 2011-09-15 03:33:58 fwarmerdam
- * fix missing cast (#2344)
- *
- * Revision 1.70 2011-07-24 05:59:25 fwarmerdam
- * minimize use of CPLError in favor of SAHooks.Error()
- *
- * Revision 1.69 2011-07-24 03:24:22 fwarmerdam
- * fix memory leaks in error cases creating shapefiles (#2061)
- *
- * Revision 1.68 2010-08-27 23:42:52 fwarmerdam
- * add SHPAPI_CALL attribute in code
- *
- * Revision 1.67 2010-07-01 08:15:48 fwarmerdam
- * do not error out on an object with zero vertices
- *
- * Revision 1.66 2010-07-01 07:58:57 fwarmerdam
- * minor cleanup of error handling
- *
- * Revision 1.65 2010-07-01 07:27:13 fwarmerdam
- * white space formatting adjustments
- *
- * Revision 1.64 2010-01-28 11:34:34 fwarmerdam
- * handle the shape file length limits more gracefully (#3236)
- *
- * Revision 1.63 2010-01-28 04:04:40 fwarmerdam
- * improve numerical accuracy of SHPRewind() algs (gdal #3363)
- *
- * Revision 1.62 2010-01-17 05:34:13 fwarmerdam
- * Remove asserts on x/y being null (#2148).
- *
- * Revision 1.61 2010-01-16 05:07:42 fwarmerdam
- * allow 0/nulls in shpcreateobject (#2148)
- *
- * Revision 1.60 2009-09-17 20:50:02 bram
- * on Win32, define snprintf as alias to _snprintf
- *
- * 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>
-
-SHP_CVSID("$Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $")
-
-typedef unsigned char uchar;
-
-#if UINT_MAX == 65535
-typedef unsigned long int32;
-#else
-typedef unsigned 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
-
-#if defined(WIN32) || defined(_WIN32)
-# ifndef snprintf
-# define snprintf _snprintf
-# endif
-#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 SHPAPI_CALL 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 )
- {
- char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
- sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.",
- pszBasename, pszBasename );
- psHooks->Error( pszMessage );
- free( pszMessage );
-
- 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 )
- {
- char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
- sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.",
- pszBasename, pszBasename );
- psHooks->Error( pszMessage );
- free( pszMessage );
-
- 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 = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
- + (unsigned int)pabyBuf[25] * 256 * 256
- + (unsigned int)pabyBuf[26] * 256
- + (unsigned int)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 = (unsigned int *)
- malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
- psSHP->panRecSize = (unsigned int *)
- malloc(sizeof(unsigned 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 = NULL, *pszFullname = NULL;
- int i;
- SAFile fpSHP = NULL, fpSHX = NULL;
- 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." );
- goto error;
- }
-
- sprintf( pszFullname, "%s.shx", pszBasename );
- fpSHX = psHooks->FOpen(pszFullname, "wb" );
- if( fpSHX == NULL )
- {
- psHooks->Error( "Failed to create file .shx file." );
- goto error;
- }
-
- free( pszFullname ); pszFullname = NULL;
- free( pszBasename ); pszBasename = NULL;
-
-/* -------------------------------------------------------------------- */
-/* 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." );
- goto error;
- }
-
-/* -------------------------------------------------------------------- */
-/* 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." );
- goto error;
- }
-
-/* -------------------------------------------------------------------- */
-/* Close the files, and then open them as regular existing files. */
-/* -------------------------------------------------------------------- */
- psHooks->FClose( fpSHP );
- psHooks->FClose( fpSHX );
-
- return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
-
-error:
- if (pszFullname) free(pszFullname);
- if (pszBasename) free(pszBasename);
- if (fpSHP) psHooks->FClose( fpSHP );
- if (fpSHX) psHooks->FClose( fpSHX );
- return NULL;
-}
-
-/************************************************************************/
-/* _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 *)
- calloc(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++ )
- {
- if( psObject->panPartStart != NULL )
- 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 X, Y, Z and M are optional. */
-/* -------------------------------------------------------------------- */
- 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);
-
- for( i = 0; i < nVertices; i++ )
- {
- if( padfX != NULL )
- psObject->padfX[i] = padfX[i];
- if( padfY != NULL )
- 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 )
-
-{
- unsigned int nRecordOffset, nRecordSize=0;
- int i;
- 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 = (unsigned int *)
- SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * psSHP->nMaxRecords );
- psSHP->panRecSize = (unsigned int *)
- SfRealloc(psSHP->panRecSize,sizeof(unsigned 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 )
- {
- unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
- if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
- {
- char str[128];
- sprintf( str, "Failed to write shape object. "
- "File size cannot reach %u + %u.",
- psSHP->nFileSize, nRecordSize );
- psSHP->sHooks.Error( str );
- free( pabyRec );
- return -1;
- }
-
- 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.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
- free( pabyRec );
- return -1;
- }
- if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
- {
- psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while 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 szErrorMsg[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 = (uchar *) 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 )
- {
- /*
- * TODO - mloskot: Consider detailed diagnostics of shape file,
- * for example to detect if file is truncated.
- */
- char str[128];
- sprintf( str,
- "Error in fseek() reading object from .shp file at offset %u",
- psSHP->panRecOffset[hEntity]);
-
- psSHP->sHooks.Error( str );
- return NULL;
- }
-
- if( 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.
- */
- char str[128];
- sprintf( str,
- "Error in fread() reading object of size %u at offset %u from .shp file",
- nEntitySize, psSHP->panRecOffset[hEntity] );
-
- psSHP->sHooks.Error( str );
- return NULL;
- }
-
-/* -------------------------------------------------------------------- */
-/* Allocate and minimally initialize the object. */
-/* -------------------------------------------------------------------- */
- psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
- psShape->nShapeId = hEntity;
- psShape->bMeasureIsUsed = FALSE;
-
- if ( 8 + 4 > nEntitySize )
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( szErrorMsg );
- 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 )
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( szErrorMsg );
- 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)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
- hEntity, nPoints, nParts);
- psSHP->sHooks.Error( szErrorMsg );
- 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)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
- hEntity, nPoints, nParts, nEntitySize);
- psSHP->sHooks.Error( szErrorMsg );
- 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)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints, nParts );
- psSHP->sHooks.Error( szErrorMsg );
- 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
- && psShape->nVertices > 0) )
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
- hEntity, i, psShape->panPartStart[i], psShape->nVertices);
- psSHP->sHooks.Error( szErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "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( szErrorMsg );
- 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 )
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( szErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
-
- if( bBigEndian ) SwapWord( 4, &nPoints );
-
- if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nPoints = %d",
- hEntity, nPoints);
- psSHP->sHooks.Error( szErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
-
- nRequiredSize = 48 + nPoints * 16;
- if( psShape->nSHPType == SHPT_MULTIPOINTZ )
- {
- nRequiredSize += 16 + nPoints * 8;
- }
- if (nRequiredSize > nEntitySize)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
- hEntity, nPoints, nEntitySize);
- psSHP->sHooks.Error( szErrorMsg );
- 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)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints );
- psSHP->sHooks.Error( szErrorMsg );
- 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)
- {
- snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( szErrorMsg );
- 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];
-
- if (nVertCount < 2)
- continue;
-
- dfSum = psObject->padfX[nVertStart] * (psObject->padfY[nVertStart+1] - psObject->padfY[nVertStart+nVertCount-1]);
- for( iVert = nVertStart + 1; iVert < nVertStart+nVertCount-1; iVert++ )
- {
- dfSum += psObject->padfX[iVert] * (psObject->padfY[iVert+1] - psObject->padfY[iVert-1]);
- }
-
- dfSum += psObject->padfX[iVert] * (psObject->padfY[nVertStart] - psObject->padfY[iVert-1]);
-
-/* -------------------------------------------------------------------- */
-/* 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;
-}
+++ /dev/null
-/******************************************************************************
- * $Id: shptree.c,v 1.17 2012-01-27 21:09:26 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.17 2012-01-27 21:09:26 fwarmerdam
- * optimize .qix output (gdal #4472)
- *
- * Revision 1.16 2011-12-11 22:26:46 fwarmerdam
- * upgrade .qix access code to use SAHooks (gdal #3365)
- *
- * Revision 1.15 2011-07-24 05:59:25 fwarmerdam
- * minimize use of CPLError in favor of SAHooks.Error()
- *
- * Revision 1.14 2010-08-27 23:43:27 fwarmerdam
- * add SHPAPI_CALL attribute in code
- *
- * Revision 1.13 2010-06-29 05:50:15 fwarmerdam
- * fix sign of Z/M comparisons in SHPCheckObjectContained (#2223)
- *
- * 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
-
-SHP_CVSID("$Id: shptree.c,v 1.17 2012-01-27 21:09:26 fwarmerdam Exp $")
-
-#ifndef TRUE
-# define TRUE 1
-# define FALSE 0
-#endif
-
-static int bBigEndian = 0;
-
-
-/* -------------------------------------------------------------------- */
-/* 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 )
- 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 )
- {
- 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 */
- }
- }
-
-/* -------------------------------------------------------------------- */
-/* If the current node has 1 subnode and no shapes, promote that */
-/* subnode to the current node position. */
-/* -------------------------------------------------------------------- */
- if( psTreeNode->nSubNodes == 1 && psTreeNode->nShapeCount == 0)
- {
- SHPTreeNode* psSubNode = psTreeNode->apsSubNode[0];
-
- memcpy(psTreeNode->adfBoundsMin, psSubNode->adfBoundsMin,
- sizeof(psSubNode->adfBoundsMin));
- memcpy(psTreeNode->adfBoundsMax, psSubNode->adfBoundsMax,
- sizeof(psSubNode->adfBoundsMax));
- psTreeNode->nShapeCount = psSubNode->nShapeCount;
- assert(psTreeNode->panShapeIds == NULL);
- psTreeNode->panShapeIds = psSubNode->panShapeIds;
- assert(psTreeNode->papsShapeObj == NULL);
- psTreeNode->papsShapeObj = psSubNode->papsShapeObj;
- psTreeNode->nSubNodes = psSubNode->nSubNodes;
- for( i = 0; i < psSubNode->nSubNodes; i++ )
- psTreeNode->apsSubNode[i] = psSubNode->apsSubNode[i];
- free(psSubNode);
- }
-
-/* -------------------------------------------------------------------- */
-/* 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;
- }
-}
-
-
-struct SHPDiskTreeInfo
-{
- SAHooks sHooks;
- SAFile fpQIX;
-};
-
-/************************************************************************/
-/* SHPOpenDiskTree() */
-/************************************************************************/
-
-SHPTreeDiskHandle SHPOpenDiskTree( const char* pszQIXFilename,
- SAHooks *psHooks )
-{
- SHPTreeDiskHandle hDiskTree;
-
- hDiskTree = (SHPTreeDiskHandle) calloc(sizeof(struct SHPDiskTreeInfo),1);
-
- if (psHooks == NULL)
- SASetupDefaultHooks( &(hDiskTree->sHooks) );
- else
- memcpy( &(hDiskTree->sHooks), psHooks, sizeof(SAHooks) );
-
- hDiskTree->fpQIX = hDiskTree->sHooks.FOpen(pszQIXFilename, "rb");
- if (hDiskTree->fpQIX == NULL)
- {
- free(hDiskTree);
- return NULL;
- }
-
- return hDiskTree;
-}
-
-/***********************************************************************/
-/* SHPCloseDiskTree() */
-/************************************************************************/
-
-void SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree )
-{
- if (hDiskTree == NULL)
- return;
-
- hDiskTree->sHooks.FClose(hDiskTree->fpQIX);
- free(hDiskTree);
-}
-
-/************************************************************************/
-/* SHPSearchDiskTreeNode() */
-/************************************************************************/
-
-static int
-SHPSearchDiskTreeNode( SHPTreeDiskHandle hDiskTree, 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. */
-/* -------------------------------------------------------------------- */
- hDiskTree->sHooks.FRead( &offset, 4, 1, hDiskTree->fpQIX );
- if ( bNeedSwap ) SwapWord ( 4, &offset );
-
- hDiskTree->sHooks.FRead( adfNodeBoundsMin, sizeof(double), 2, hDiskTree->fpQIX );
- hDiskTree->sHooks.FRead( adfNodeBoundsMax, sizeof(double), 2, hDiskTree->fpQIX );
- if ( bNeedSwap )
- {
- SwapWord( 8, adfNodeBoundsMin + 0 );
- SwapWord( 8, adfNodeBoundsMin + 1 );
- SwapWord( 8, adfNodeBoundsMax + 0 );
- SwapWord( 8, adfNodeBoundsMax + 1 );
- }
-
- hDiskTree->sHooks.FRead( &numshapes, 4, 1, hDiskTree->fpQIX );
- 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);
- hDiskTree->sHooks.FSeek(hDiskTree->fpQIX, 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) );
- }
-
- hDiskTree->sHooks.FRead( *ppanResultBuffer + *pnResultCount,
- sizeof(int), numshapes, hDiskTree->fpQIX );
-
- if (bNeedSwap )
- {
- for( i=0; i<numshapes; i++ )
- SwapWord( 4, *ppanResultBuffer + *pnResultCount + i );
- }
-
- *pnResultCount += numshapes;
- }
-
-/* -------------------------------------------------------------------- */
-/* Process the subnodes. */
-/* -------------------------------------------------------------------- */
- hDiskTree->sHooks.FRead( &numsubnodes, 4, 1, hDiskTree->fpQIX );
- if ( bNeedSwap ) SwapWord ( 4, &numsubnodes );
-
- for(i=0; i<numsubnodes; i++)
- {
- if( !SHPSearchDiskTreeNode( hDiskTree, padfBoundsMin, padfBoundsMax,
- ppanResultBuffer, pnBufferMax,
- pnResultCount, bNeedSwap ) )
- return FALSE;
- }
-
- return TRUE;
-}
-
-/************************************************************************/
-/* SHPTreeReadLibc() */
-/************************************************************************/
-
-static
-SAOffset SHPTreeReadLibc( void *p, SAOffset size, SAOffset nmemb, SAFile file )
-
-{
- return (SAOffset) fread( p, (size_t) size, (size_t) nmemb,
- (FILE *) file );
-}
-
-/************************************************************************/
-/* SHPTreeSeekLibc() */
-/************************************************************************/
-
-static
-SAOffset SHPTreeSeekLibc( SAFile file, SAOffset offset, int whence )
-
-{
- return (SAOffset) fseek( (FILE *) file, (long) offset, whence );
-}
-
-/************************************************************************/
-/* SHPSearchDiskTree() */
-/************************************************************************/
-
-int SHPAPI_CALL1(*)
-SHPSearchDiskTree( FILE *fp,
- double *padfBoundsMin, double *padfBoundsMax,
- int *pnShapeCount )
-{
- struct SHPDiskTreeInfo sDiskTree;
- memset(&sDiskTree.sHooks, 0, sizeof(sDiskTree.sHooks));
-
- /* We do not use SASetupDefaultHooks() because the FILE* */
- /* is a libc FILE* */
- sDiskTree.sHooks.FSeek = SHPTreeSeekLibc;
- sDiskTree.sHooks.FRead = SHPTreeReadLibc;
-
- sDiskTree.fpQIX = (SAFile)fp;
-
- return SHPSearchDiskTreeEx( &sDiskTree, padfBoundsMin, padfBoundsMax,
- pnShapeCount );
-}
-
-/***********************************************************************/
-/* SHPSearchDiskTreeEx() */
-/************************************************************************/
-
-int* SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
- 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. */
-/* -------------------------------------------------------------------- */
- hDiskTree->sHooks.FSeek( hDiskTree->fpQIX, 0, SEEK_SET );
- hDiskTree->sHooks.FRead( abyBuf, 16, 1, hDiskTree->fpQIX );
-
- 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( hDiskTree, 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( SAFile fp, SHPTreeNode *node, SAHooks* psHooks)
-{
- 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 );
- return;
- }
-
- 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);
-
- psHooks->FWrite( pabyRec, 44+j, 1, fp );
- free (pabyRec);
-
- for(i=0; i<node->nSubNodes; i++ )
- {
- if(node->apsSubNode[i])
- SHPWriteTreeNode( fp, node->apsSubNode[i], psHooks);
- }
-}
-
-/************************************************************************/
-/* SHPWriteTree() */
-/************************************************************************/
-
-int SHPAPI_CALL SHPWriteTree(SHPTree *tree, const char *filename )
-{
- SAHooks sHooks;
-
- SASetupDefaultHooks( &sHooks );
-
- return SHPWriteTreeLL(tree, filename, &sHooks);
-}
-
-/************************************************************************/
-/* SHPWriteTreeLL() */
-/************************************************************************/
-
-int SHPWriteTreeLL(SHPTree *tree, const char *filename, SAHooks* psHooks )
-{
- char signature[4] = "SQT";
- int i;
- char abyBuf[32];
- SAFile fp;
-
- SAHooks sHooks;
- if (psHooks == NULL)
- {
- SASetupDefaultHooks( &sHooks );
- psHooks = &sHooks;
- }
-
-/* -------------------------------------------------------------------- */
-/* Open the output file. */
-/* -------------------------------------------------------------------- */
- fp = psHooks->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;
-
- psHooks->FWrite( abyBuf, 8, 1, fp );
-
- psHooks->FWrite( &(tree->nTotalCount), 4, 1, fp );
-
- /* write maxdepth */
-
- psHooks->FWrite( &(tree->nMaxDepth), 4, 1, fp );
-
-/* -------------------------------------------------------------------- */
-/* Write all the nodes "in order". */
-/* -------------------------------------------------------------------- */
-
- SHPWriteTreeNode( fp, tree->psRoot, psHooks );
-
- psHooks->FClose( fp );
-
- return TRUE;
-}
+++ /dev/null
-/******************************************************************************
- * $Id: shputils.c,v 1.10 2007-12-13 19:59:23 fwarmerdam Exp $
- *
- * Project: Shapelib
- * Purpose:
- * Altered "shpdump" and "dbfdump" to allow two files to be appended.
- * Other Functions:
- * Selecting from the DBF before the write occurs.
- * Change the UNITS between Feet and Meters and Shift X,Y.
- * Clip and Erase boundary. The program only passes thru the
- * data once.
- *
- * Bill Miller North Carolina - Department of Transporation
- * Feb. 1997 -- bmiller@dot.state.nc.us
- * There was not a lot of time to debug hidden problems;
- * And the code is not very well organized or documented.
- * The clip/erase function was not well tested.
- * Oct. 2000 -- bmiller@dot.state.nc.us
- * Fixed the problem when select is using numbers
- * larger than short integer. It now reads long integer.
- * NOTE: DBF files created using windows NT will read as a string with
- * a length of 381 characters. This is a bug in "dbfopen".
- *
- *
- * Author: Bill Miller (bmiller@dot.state.nc.us)
- *
- ******************************************************************************
- * 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: shputils.c,v $
- * Revision 1.10 2007-12-13 19:59:23 fwarmerdam
- * reindent code, avoid some warnings.
- *
- * Revision 1.9 2004/01/14 14:56:00 fwarmerdam
- * Some cleanlyness improvements.
- *
- * Revision 1.8 2004/01/14 14:40:22 fwarmerdam
- * Fixed exit() call to include code.
- *
- * Revision 1.7 2003/02/25 17:20:22 warmerda
- * Set psCShape to NULL after SHPDestroyObject() to avoid multi-frees of
- * the same memory ... as submitted by Fred Fox.
- *
- * Revision 1.6 2001/08/28 13:57:14 warmerda
- * fixed DBFAddField return value check
- *
- * Revision 1.5 2000/11/02 13:52:48 warmerda
- * major upgrade from Bill Miller
- *
- * Revision 1.4 1999/11/05 14:12:05 warmerda
- * updated license terms
- *
- * Revision 1.3 1998/12/03 15:47:39 warmerda
- * Did a bunch of rewriting to make it work with the V1.2 API.
- *
- * Revision 1.2 1998/06/18 01:19:49 warmerda
- * Made C++ compilable.
- *
- * Revision 1.1 1997/05/27 20:40:27 warmerda
- * Initial revision
- */
-
-#include "shapefil.h"
-#include "string.h"
-#include <stdlib.h>
-
-SHP_CVSID("$Id: shputils.c,v 1.10 2007-12-13 19:59:23 fwarmerdam Exp $")
-
-#ifndef FALSE
-# define FALSE 0
-# define TRUE 1
-#endif
-
-char infile[80], outfile[80], temp[400];
-
-/* Variables for shape files */
-SHPHandle hSHP;
-SHPHandle hSHPappend;
-int nShapeType, nEntities, iPart;
-int nShapeTypeAppend, nEntitiesAppend;
-SHPObject *psCShape;
-double adfBoundsMin[4], adfBoundsMax[4];
-
-
-/* Variables for DBF files */
-DBFHandle hDBF;
-DBFHandle hDBFappend;
-
-DBFFieldType iType;
-DBFFieldType jType;
-
-char iszTitle[12];
-char jszTitle[12];
-
-int *pt;
-char iszFormat[32], iszField[1024];
-char jszFormat[32], jszField[1024];
-int i, ti, iWidth, iDecimals, iRecord;
-int j, tj, jWidth, jDecimals, jRecord;
-
-
-int clip_boundary();
-double findunit(char *unit);
-void openfiles(void);
-void setext(char *pt, char *ext);
-int strncasecmp2(char *s1, char *s2, int n);
-void mergefields(void);
-void findselect(void);
-void showitems(void);
-int selectrec();
-void check_theme_bnd();
-int clip_boundary();
-void error();
-
-
-/* -------------------------------------------------------------------- */
-/* Variables for the DESCRIBE function */
-/* -------------------------------------------------------------------- */
- int ilist = FALSE, iall = FALSE;
-/* -------------------------------------------------------------------- */
-/* Variables for the SELECT function */
-/* -------------------------------------------------------------------- */
- int found = FALSE, newdbf = FALSE;
- char selectitem[40], *cpt;
- long int selectvalues[150], selcount=0;
- int iselect = FALSE, iselectitem = -1;
- int iunselect = FALSE;
-
-/* -------------------------------------------------------------------- */
-/* Variables for the CLIP and ERASE functions */
-/* -------------------------------------------------------------------- */
- double cxmin, cymin, cxmax, cymax;
- int iclip = FALSE, ierase = FALSE;
- int itouch = FALSE, iinside = FALSE, icut = FALSE;
- int ibound = FALSE, ipoly = FALSE;
- char clipfile[80];
-
-/* -------------------------------------------------------------------- */
-/* Variables for the FACTOR function */
-/* -------------------------------------------------------------------- */
- double infactor,outfactor,factor = 0; /* NO FACTOR */
- int iunit = FALSE;
- int ifactor = FALSE;
-
-
-/* -------------------------------------------------------------------- */
-/* Variables for the SHIFT function */
-/* -------------------------------------------------------------------- */
- double xshift = 0, yshift = 0; /* NO SHIFT */
-
-int main( int argc, char ** argv )
-{
-
-/* -------------------------------------------------------------------- */
-/* Check command line usage. */
-/* -------------------------------------------------------------------- */
- if( argc < 2 ) error();
- strcpy(infile, argv[1]);
- if (argc > 2) {
- strcpy(outfile,argv[2]);
- if (strncasecmp2(outfile, "LIST",0) == 0) { ilist = TRUE; }
- if (strncasecmp2(outfile, "ALL",0) == 0) { iall = TRUE; }
- }
- if (ilist || iall || argc == 2 ) {
- setext(infile, "shp");
- printf("DESCRIBE: %s\n",infile);
- strcpy(outfile,"");
- }
-/* -------------------------------------------------------------------- */
-/* Look for other functions on the command line. (SELECT, UNIT) */
-/* -------------------------------------------------------------------- */
- for (i = 3; i < argc; i++)
- {
- if ((strncasecmp2(argv[i], "SEL",3) == 0) ||
- (strncasecmp2(argv[i], "UNSEL",5) == 0))
- {
- if (strncasecmp2(argv[i], "UNSEL",5) == 0) iunselect=TRUE;
- i++;
- if (i >= argc) error();
- strcpy(selectitem,argv[i]);
- i++;
- if (i >= argc) error();
- selcount=0;
- strcpy(temp,argv[i]);
- cpt=temp;
- tj = atoi(cpt);
- ti = 0;
- while (tj>0) {
- selectvalues[selcount] = tj;
- while( *cpt >= '0' && *cpt <= '9')
- cpt++;
- while( *cpt > '\0' && (*cpt < '0' || *cpt > '9') )
- cpt++;
- tj=atoi(cpt);
- selcount++;
- }
- iselect=TRUE;
- } /*** End SEL & UNSEL ***/
- else
- if ((strncasecmp2(argv[i], "CLIP",4) == 0) ||
- (strncasecmp2(argv[i], "ERASE",5) == 0))
- {
- if (strncasecmp2(argv[i], "ERASE",5) == 0) ierase=TRUE;
- i++;
- if (i >= argc) error();
- strcpy(clipfile,argv[i]);
- sscanf(argv[i],"%lf",&cxmin);
- i++;
- if (i >= argc) error();
- if (strncasecmp2(argv[i], "BOUND",5) == 0) {
- setext(clipfile, "shp");
- hSHP = SHPOpen( clipfile, "rb" );
- if( hSHP == NULL )
- {
- printf( "ERROR: Unable to open the clip shape file:%s\n", clipfile );
- exit( 1 );
- }
- SHPGetInfo( hSHPappend, NULL, NULL,
- adfBoundsMin, adfBoundsMax );
- cxmin = adfBoundsMin[0];
- cymin = adfBoundsMin[1];
- cxmax = adfBoundsMax[0];
- cymax = adfBoundsMax[1];
- printf("Theme Clip Boundary: (%lf,%lf) - (%lf,%lf)\n",
- cxmin, cymin, cxmax, cymax);
- ibound=TRUE;
- } else { /*** xmin,ymin,xmax,ymax ***/
- sscanf(argv[i],"%lf",&cymin);
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&cxmax);
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&cymax);
- printf("Clip Box: (%lf,%lf) - (%lf,%lf)\n",cxmin, cymin, cxmax, cymax);
- }
- i++;
- if (i >= argc) error();
- if (strncasecmp2(argv[i], "CUT",3) == 0) icut=TRUE;
- else if (strncasecmp2(argv[i], "TOUCH",5) == 0) itouch=TRUE;
- else if (strncasecmp2(argv[i], "INSIDE",6) == 0) iinside=TRUE;
- else error();
- iclip=TRUE;
- } /*** End CLIP & ERASE ***/
- else if (strncasecmp2(argv[i], "FACTOR",0) == 0)
- {
- i++;
- if (i >= argc) error();
- infactor=findunit(argv[i]);
- if (infactor == 0) error();
- iunit=TRUE;
- i++;
- if (i >= argc) error();
- outfactor=findunit(argv[i]);
- if (outfactor == 0)
- {
- sscanf(argv[i],"%lf",&factor);
- if (factor == 0) error();
- }
- if (factor == 0)
- {
- if (infactor ==0)
- { puts("ERROR: Input unit must be defined before output unit"); exit(1); }
- factor=infactor/outfactor;
- }
- printf("Output file coordinate values will be factored by %lg\n",factor);
- ifactor=(factor != 1); /* True if a valid factor */
- } /*** End FACTOR ***/
- else if (strncasecmp2(argv[i],"SHIFT",5) == 0)
- {
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&xshift);
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&yshift);
- iunit=TRUE;
- printf("X Shift: %lg Y Shift: %lg\n",xshift,yshift);
- } /*** End SHIFT ***/
- else {
- printf("ERROR: Unknown function %s\n",argv[i]); error();
- }
- }
-/* -------------------------------------------------------------------- */
-/* If there is no data in this file let the user know. */
-/* -------------------------------------------------------------------- */
- openfiles(); /* Open the infile and the outfile for shape and dbf. */
- if( DBFGetFieldCount(hDBF) == 0 )
- {
- puts( "There are no fields in this table!" );
- exit( 1 );
- }
-/* -------------------------------------------------------------------- */
-/* Print out the file bounds. */
-/* -------------------------------------------------------------------- */
- iRecord = DBFGetRecordCount( hDBF );
- SHPGetInfo( hSHP, NULL, NULL, adfBoundsMin, adfBoundsMax );
-
- printf( "Input Bounds: (%lg,%lg) - (%lg,%lg) Entities: %d DBF: %d\n",
- adfBoundsMin[0], adfBoundsMin[1],
- adfBoundsMax[0], adfBoundsMax[1],
- nEntities, iRecord );
-
- if (strcmp(outfile,"") == 0) /* Describe the shapefile; No other functions */
- {
- ti = DBFGetFieldCount( hDBF );
- showitems();
- exit(0);
- }
-
- if (iclip) check_theme_bnd();
-
- jRecord = DBFGetRecordCount( hDBFappend );
- SHPGetInfo( hSHPappend, NULL, NULL, adfBoundsMin, adfBoundsMax );
- if (nEntitiesAppend == 0)
- puts("New Output File\n");
- else
- printf( "Append Bounds: (%lg,%lg)-(%lg,%lg) Entities: %d DBF: %d\n",
- adfBoundsMin[0], adfBoundsMin[1],
- adfBoundsMax[0], adfBoundsMax[1],
- nEntitiesAppend, jRecord );
-
-/* -------------------------------------------------------------------- */
-/* Find matching fields in the append file or add new items. */
-/* -------------------------------------------------------------------- */
- mergefields();
-/* -------------------------------------------------------------------- */
-/* Find selection field if needed. */
-/* -------------------------------------------------------------------- */
- if (iselect) findselect();
-
-/* -------------------------------------------------------------------- */
-/* Read all the records */
-/* -------------------------------------------------------------------- */
- jRecord = DBFGetRecordCount( hDBFappend );
- for( iRecord = 0; iRecord < nEntities; iRecord++) /** DBFGetRecordCount(hDBF) **/
- {
-/* -------------------------------------------------------------------- */
-/* SELECT for values if needed. (Can the record be skipped.) */
-/* -------------------------------------------------------------------- */
- if (iselect)
- if (selectrec() == 0) goto SKIP_RECORD; /** SKIP RECORD **/
-
-/* -------------------------------------------------------------------- */
-/* Read a Shape record */
-/* -------------------------------------------------------------------- */
- psCShape = SHPReadObject( hSHP, iRecord );
-
-/* -------------------------------------------------------------------- */
-/* Clip coordinates of shapes if needed. */
-/* -------------------------------------------------------------------- */
- if (iclip)
- if (clip_boundary() == 0) goto SKIP_RECORD; /** SKIP RECORD **/
-
-/* -------------------------------------------------------------------- */
-/* Read a DBF record and copy each field. */
-/* -------------------------------------------------------------------- */
- for( i = 0; i < DBFGetFieldCount(hDBF); i++ )
- {
-/* -------------------------------------------------------------------- */
-/* Store the record according to the type and formatting */
-/* information implicit in the DBF field description. */
-/* -------------------------------------------------------------------- */
- if (pt[i] > -1) /* if the current field exists in output file */
- {
- switch( DBFGetFieldInfo( hDBF, i, NULL, &iWidth, &iDecimals ) )
- {
- case FTString:
- case FTLogical:
- DBFWriteStringAttribute(hDBFappend, jRecord, pt[i],
- (DBFReadStringAttribute( hDBF, iRecord, i )) );
- break;
-
- case FTInteger:
- DBFWriteIntegerAttribute(hDBFappend, jRecord, pt[i],
- (DBFReadIntegerAttribute( hDBF, iRecord, i )) );
- break;
-
- case FTDouble:
- DBFWriteDoubleAttribute(hDBFappend, jRecord, pt[i],
- (DBFReadDoubleAttribute( hDBF, iRecord, i )) );
- break;
-
- case FTInvalid:
- break;
- }
- }
- }
- jRecord++;
-/* -------------------------------------------------------------------- */
-/* Change FACTOR and SHIFT coordinates of shapes if needed. */
-/* -------------------------------------------------------------------- */
- if (iunit)
- {
- for( j = 0; j < psCShape->nVertices; j++ )
- {
- psCShape->padfX[j] = psCShape->padfX[j] * factor + xshift;
- psCShape->padfY[j] = psCShape->padfY[j] * factor + yshift;
- }
- }
-
-/* -------------------------------------------------------------------- */
-/* Write the Shape record after recomputing current extents. */
-/* -------------------------------------------------------------------- */
- SHPComputeExtents( psCShape );
- SHPWriteObject( hSHPappend, -1, psCShape );
-
- SKIP_RECORD:
- SHPDestroyObject( psCShape );
- psCShape = NULL;
- j=0;
- }
-
-/* -------------------------------------------------------------------- */
-/* Print out the # of Entities and the file bounds. */
-/* -------------------------------------------------------------------- */
- jRecord = DBFGetRecordCount( hDBFappend );
- SHPGetInfo( hSHPappend, &nEntitiesAppend, &nShapeTypeAppend,
- adfBoundsMin, adfBoundsMax );
-
- printf( "Output Bounds: (%lg,%lg) - (%lg,%lg) Entities: %d DBF: %d\n\n",
- adfBoundsMin[0], adfBoundsMin[1],
- adfBoundsMax[0], adfBoundsMax[1],
- nEntitiesAppend, jRecord );
-
-/* -------------------------------------------------------------------- */
-/* Close the both shapefiles. */
-/* -------------------------------------------------------------------- */
- SHPClose( hSHP );
- SHPClose( hSHPappend );
- DBFClose( hDBF );
- DBFClose( hDBFappend );
- if (nEntitiesAppend == 0) {
- puts("Remove the output files.");
- setext(outfile, "dbf");
- remove(outfile);
- setext(outfile, "shp");
- remove(outfile);
- setext(outfile, "shx");
- remove(outfile);
- }
- return( 0 );
-}
-
-
-/************************************************************************/
-/* openfiles() */
-/************************************************************************/
-
-void openfiles() {
-/* -------------------------------------------------------------------- */
-/* Open the DBF file. */
-/* -------------------------------------------------------------------- */
- setext(infile, "dbf");
- hDBF = DBFOpen( infile, "rb" );
- if( hDBF == NULL )
- {
- printf( "ERROR: Unable to open the input DBF:%s\n", infile );
- exit( 1 );
- }
-/* -------------------------------------------------------------------- */
-/* Open the append DBF file. */
-/* -------------------------------------------------------------------- */
- if (strcmp(outfile,"")) {
- setext(outfile, "dbf");
- hDBFappend = DBFOpen( outfile, "rb+" );
- newdbf=0;
- if( hDBFappend == NULL )
- {
- newdbf=1;
- hDBFappend = DBFCreate( outfile );
- if( hDBFappend == NULL )
- {
- printf( "ERROR: Unable to open the append DBF:%s\n", outfile );
- exit( 1 );
- }
- }
- }
-/* -------------------------------------------------------------------- */
-/* Open the passed shapefile. */
-/* -------------------------------------------------------------------- */
- setext(infile, "shp");
- hSHP = SHPOpen( infile, "rb" );
-
- if( hSHP == NULL )
- {
- printf( "ERROR: Unable to open the input shape file:%s\n", infile );
- exit( 1 );
- }
-
- SHPGetInfo( hSHP, &nEntities, &nShapeType, NULL, NULL );
-
-/* -------------------------------------------------------------------- */
-/* Open the passed append shapefile. */
-/* -------------------------------------------------------------------- */
- if (strcmp(outfile,"")) {
- setext(outfile, "shp");
- hSHPappend = SHPOpen( outfile, "rb+" );
-
- if( hSHPappend == NULL )
- {
- hSHPappend = SHPCreate( outfile, nShapeType );
- if( hSHPappend == NULL )
- {
- printf( "ERROR: Unable to open the append shape file:%s\n",
- outfile );
- exit( 1 );
- }
- }
- SHPGetInfo( hSHPappend, &nEntitiesAppend, &nShapeTypeAppend,
- NULL, NULL );
-
- if (nShapeType != nShapeTypeAppend)
- {
- puts( "ERROR: Input and Append shape files are of different types.");
- exit( 1 );
- }
- }
-}
-
-/* -------------------------------------------------------------------- */
-/* Change the extension. If there is any extension on the */
-/* filename, strip it off and add the new extension */
-/* -------------------------------------------------------------------- */
-void setext(char *pt, char *ext)
-{
-int i;
- for( i = strlen(pt)-1;
- i > 0 && pt[i] != '.' && pt[i] != '/' && pt[i] != '\\';
- i-- ) {}
-
- if( pt[i] == '.' )
- pt[i] = '\0';
-
- strcat(pt,".");
- strcat(pt,ext);
-}
-
-
-
-/* -------------------------------------------------------------------- */
-/* Find matching fields in the append file. */
-/* Output file must have zero records to add any new fields. */
-/* -------------------------------------------------------------------- */
-void mergefields()
-{
- int i,j;
- ti = DBFGetFieldCount( hDBF );
- tj = DBFGetFieldCount( hDBFappend );
- /* Create a pointer array for the max # of fields in the output file */
- pt = (int *) malloc( (ti+tj+1) * sizeof(int) );
-
- for( i = 0; i < ti; i++ )
- {
- pt[i]= -1; /* Initial pt values to -1 */
- }
- /* DBF must be empty before adding items */
- jRecord = DBFGetRecordCount( hDBFappend );
- for( i = 0; i < ti; i++ )
- {
- iType = DBFGetFieldInfo( hDBF, i, iszTitle, &iWidth, &iDecimals );
- found=FALSE;
- {
- for( j = 0; j < tj; j++ ) /* Search all field names for a match */
- {
- jType = DBFGetFieldInfo( hDBFappend, j, jszTitle, &jWidth, &jDecimals );
- if (iType == jType && (strcmp(iszTitle, jszTitle) == 0) )
- {
- if (found || newdbf)
- {
- if (i == j) pt[i]=j;
- printf("Warning: Duplicate field name found (%s)\n",iszTitle);
- /* Duplicate field name
- (Try to guess the correct field by position) */
- }
- else
- {
- pt[i]=j; found=TRUE;
- }
- }
- }
- }
-
- if (pt[i] == -1 && (! found) ) /* Try to force into an existing field */
- { /* Ignore the field name, width, and decimal places */
- jType = DBFGetFieldInfo( hDBFappend, j, jszTitle, &jWidth, &jDecimals );
- if (iType == jType)
- {
- pt[i]=i; found=1;
- }
- }
- if ( (! found) && jRecord == 0) /* Add missing field to the append table */
- { /* The output DBF must be is empty */
- pt[i]=tj;
- tj++;
- if( DBFAddField( hDBFappend, iszTitle, iType, iWidth, iDecimals )
- == -1 )
- {
- printf( "Warning: DBFAddField(%s, TYPE:%d, WIDTH:%d DEC:%d, ITEM#:%d of %d) failed.\n",
- iszTitle, iType, iWidth, iDecimals, (i+1), (ti+1) );
- pt[i]=-1;
- }
- }
- }
-}
-
-
-void findselect()
-{
- /* Find the select field name */
- iselectitem = -1;
- for( i = 0; i < ti && iselectitem < 0; i++ )
- {
- iType = DBFGetFieldInfo( hDBF, i, iszTitle, &iWidth, &iDecimals );
- if (strncasecmp2(iszTitle, selectitem, 0) == 0) iselectitem = i;
- }
- if (iselectitem == -1)
- {
- printf("Warning: Item not found for selection (%s)\n",selectitem);
- iselect = FALSE;
- iall = FALSE;
- showitems();
- printf("Continued... (Selecting entire file)\n");
- }
- /* Extract all of the select values (by field type) */
-
-}
-
-void showitems()
-{
- char stmp[40],slow[40],shigh[40];
- double dtmp,dlow,dhigh,dsum,mean;
- long int itmp,ilow,ihigh,isum;
- long int maxrec;
- char *pt;
-
- printf("Available Items: (%d)",ti);
- maxrec = DBFGetRecordCount(hDBF);
- if (maxrec > 5000 && ! iall)
- { maxrec=5000; printf(" ** ESTIMATED RANGES (MEAN) For more records use \"All\""); }
- else { printf(" RANGES (MEAN)"); }
-
- for( i = 0; i < ti; i++ )
- {
- switch( DBFGetFieldInfo( hDBF, i, iszTitle, &iWidth, &iDecimals ) )
- {
- case FTString:
- case FTLogical:
- strcpy(slow, "~");
- strcpy(shigh,"\0");
- printf("\n String %3d %-16s",iWidth,iszTitle);
- for( iRecord = 0; iRecord < maxrec; iRecord++ ) {
- strncpy(stmp,DBFReadStringAttribute( hDBF, iRecord, i ),39);
- if (strcmp(stmp,"!!") > 0) {
- if (strncasecmp2(stmp,slow,0) < 0) strncpy(slow, stmp,39);
- if (strncasecmp2(stmp,shigh,0) > 0) strncpy(shigh,stmp,39);
- }
- }
- pt=slow+strlen(slow)-1;
- while(*pt == ' ') { *pt='\0'; pt--; }
- pt=shigh+strlen(shigh)-1;
- while(*pt == ' ') { *pt='\0'; pt--; }
- if (strncasecmp2(slow,shigh,0) < 0) printf("%s to %s",slow,shigh);
- else if (strncasecmp2(slow,shigh,0) == 0) printf("= %s",slow);
- else printf("No Values");
- break;
- case FTInteger:
- printf("\n Integer %3d %-16s",iWidth,iszTitle);
- ilow = 1999999999;
- ihigh= -1999999999;
- isum = 0;
- for( iRecord = 0; iRecord < maxrec; iRecord++ ) {
- itmp = DBFReadIntegerAttribute( hDBF, iRecord, i );
- if (ilow > itmp) ilow = itmp;
- if (ihigh < itmp) ihigh = itmp;
- isum = isum + itmp;
- }
- mean=isum/maxrec;
- if (ilow < ihigh) printf("%ld to %ld \t(%.1f)",ilow,ihigh,mean);
- else if (ilow == ihigh) printf("= %ld",ilow);
- else printf("No Values");
- break;
-
- case FTDouble:
- printf("\n Real %3d,%d %-16s",iWidth,iDecimals,iszTitle);
- dlow = 999999999999999.0;
- dhigh= -999999999999999.0;
- dsum = 0;
- for( iRecord = 0; iRecord < maxrec; iRecord++ ) {
- dtmp = DBFReadDoubleAttribute( hDBF, iRecord, i );
- if (dlow > dtmp) dlow = dtmp;
- if (dhigh < dtmp) dhigh = dtmp;
- dsum = dsum + dtmp;
- }
- mean=dsum/maxrec;
- sprintf(stmp,"%%.%df to %%.%df \t(%%.%df)",iDecimals,iDecimals,iDecimals);
- if (dlow < dhigh) printf(stmp,dlow,dhigh,mean);
- else if (dlow == dhigh) {
- sprintf(stmp,"= %%.%df",iDecimals);
- printf(stmp,dlow);
- }
- else printf("No Values");
- break;
-
- case FTInvalid:
- break;
-
- }
-
- }
- printf("\n");
-}
-
-int selectrec()
-{
- long int value, ty;
-
- ty = DBFGetFieldInfo( hDBF, iselectitem, NULL, &iWidth, &iDecimals);
- switch(ty)
- {
- case FTString:
- puts("Invalid Item");
- iselect=FALSE;
- break;
- case FTInteger:
- value = DBFReadIntegerAttribute( hDBF, iRecord, iselectitem );
- for (j = 0; j<selcount; j++)
- {
- if (selectvalues[j] == value)
- {
- if (iunselect) return(0); /* Keep this record */
- else return(1); /* Skip this record */
- }
- }
- break;
- case FTDouble:
- puts("Invalid Item");
- iselect=FALSE;
- break;
- }
- if (iunselect) return(1); /* Skip this record */
- else return(0); /* Keep this record */
-}
-
-
-void check_theme_bnd()
-{
- if ( (adfBoundsMin[0] >= cxmin) && (adfBoundsMax[0] <= cxmax) &&
- (adfBoundsMin[1] >= cymin) && (adfBoundsMax[1] <= cymax) )
- { /** Theme is totally inside clip area **/
- if (ierase) nEntities=0; /** SKIP THEME **/
- else iclip=FALSE; /** WRITE THEME (Clip not needed) **/
- }
-
- if ( ( (adfBoundsMin[0] < cxmin) && (adfBoundsMax[0] < cxmin) ) ||
- ( (adfBoundsMin[1] < cymin) && (adfBoundsMax[1] < cymin) ) ||
- ( (adfBoundsMin[0] > cxmax) && (adfBoundsMax[0] > cxmax) ) ||
- ( (adfBoundsMin[1] > cymax) && (adfBoundsMax[1] > cymax) ) )
- { /** Theme is totally outside clip area **/
- if (ierase) iclip=FALSE; /** WRITE THEME (Clip not needed) **/
- else nEntities=0; /** SKIP THEME **/
- }
-
- if (nEntities == 0)
- puts("WARNING: Theme is outside the clip area."); /** SKIP THEME **/
-}
-
-int clip_boundary()
-{
- int inside;
- int prev_outside;
- int i2;
- int j2;
-
- /*** FIRST check the boundary of the feature ***/
- if ( ( (psCShape->dfXMin < cxmin) && (psCShape->dfXMax < cxmin) ) ||
- ( (psCShape->dfYMin < cymin) && (psCShape->dfYMax < cymin) ) ||
- ( (psCShape->dfXMin > cxmax) && (psCShape->dfXMax > cxmax) ) ||
- ( (psCShape->dfYMin > cymax) && (psCShape->dfYMax > cymax) ) )
- { /** Feature is totally outside clip area **/
- if (ierase) return(1); /** WRITE RECORD **/
- else return(0); /** SKIP RECORD **/
- }
-
- if ( (psCShape->dfXMin >= cxmin) && (psCShape->dfXMax <= cxmax) &&
- (psCShape->dfYMin >= cymin) && (psCShape->dfYMax <= cymax) )
- { /** Feature is totally inside clip area **/
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
-
- if (iinside)
- { /** INSIDE * Feature might touch the boundary or could be outside **/
- if (ierase) return(1); /** WRITE RECORD **/
- else return(0); /** SKIP RECORD **/
- }
-
- if (itouch)
- { /** TOUCH **/
- if ( ( (psCShape->dfXMin <= cxmin) || (psCShape->dfXMax >= cxmax) ) &&
- (psCShape->dfYMin >= cymin) && (psCShape->dfYMax <= cymax) )
- { /** Feature intersects the clip boundary only on the X axis **/
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
-
- if ( (psCShape->dfXMin >= cxmin) && (psCShape->dfXMax <= cxmax) &&
- ( (psCShape->dfYMin <= cymin) || (psCShape->dfYMax >= cymax) ) )
- { /** Feature intersects the clip boundary only on the Y axis **/
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
-
- for( j2 = 0; j2 < psCShape->nVertices; j2++ )
- { /** At least one vertex must be inside the clip boundary **/
- if ( (psCShape->padfX[j2] >= cxmin && psCShape->padfX[j2] <= cxmax) ||
- (psCShape->padfY[j2] >= cymin && psCShape->padfY[j2] <= cymax) )
- {
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
- }
-
- /** All vertices are outside the clip boundary **/
- if (ierase) return(1); /** WRITE RECORD **/
- else return(0); /** SKIP RECORD **/
- } /** End TOUCH **/
-
- if (icut)
- { /** CUT **/
- /*** Check each vertex in the feature with the Boundary and "CUT" ***/
- /*** THIS CODE WAS NOT COMPLETED! READ NOTE AT THE BOTTOM ***/
- i2=0;
- prev_outside=FALSE;
- for( j2 = 0; j2 < psCShape->nVertices; j2++ )
- {
- inside = psCShape->padfX[j2] >= cxmin && psCShape->padfX[j2] <= cxmax &&
- psCShape->padfY[j2] >= cymin && psCShape->padfY[j2] <= cymax ;
-
- if (ierase) inside=(! inside);
- if (inside)
- {
- if (i2 != j2)
- {
- if (prev_outside)
- {
- /*** AddIntersection(i2); ***/ /*** Add intersection ***/
- prev_outside=FALSE;
- }
- psCShape->padfX[i2]=psCShape->padfX[j2]; /** move vertex **/
- psCShape->padfY[i2]=psCShape->padfY[j2];
- }
- i2++;
- } else {
- if ( (! prev_outside) && (j2 > 0) )
- {
- /*** AddIntersection(i2); ***//*** Add intersection (Watch out for j2==i2-1) ***/
- /*** Also a polygon may overlap twice and will split into a several parts ***/
- prev_outside=TRUE;
- }
- }
- }
-
- printf("Vertices:%d OUT:%d Number of Parts:%d\n",
- psCShape->nVertices,i2, psCShape->nParts );
-
- psCShape->nVertices = i2;
-
- if (i2 < 2) return(0); /** SKIP RECORD **/
- /*** (WE ARE NOT CREATING INTERESECTIONS and some lines could be reduced to one point) **/
-
- if (i2 == 0) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- } /** End CUT **/
-}
-
-
-/************************************************************************/
-/* strncasecmp2() */
-/* */
-/* Compare two strings up to n characters */
-/* If n=0 then s1 and s2 must be an exact match */
-/************************************************************************/
-
-int strncasecmp2(char *s1, char *s2, int n)
-
-{
-int j,i;
- if (n<1) n=strlen(s1)+1;
- for (i=0; i<n; i++)
- {
- if (*s1 != *s2)
- {
- if (*s1 >= 'a' && *s1 <= 'z') {
- j=*s1-32;
- if (j != *s2) return(*s1-*s2);
- } else {
- if (*s1 >= 'A' && *s1 <= 'Z') { j=*s1+32; }
- else { j=*s1; }
- if (j != *s2) return(*s1-*s2);
- }
- }
- s1++;
- s2++;
- }
- return(0);
-}
-
-
-#define NKEYS (sizeof(unitkeytab) / sizeof(struct unitkey))
-double findunit(char *unit)
- {
- struct unitkey {
- char *name;
- double value;
- } unitkeytab[] = {
- "CM", 39.37,
- "CENTIMETER", 39.37,
- "CENTIMETERS", 39.37, /** # of inches * 100 in unit **/
- "METER", 3937,
- "METERS", 3937,
- "KM", 3937000,
- "KILOMETER", 3937000,
- "KILOMETERS", 3937000,
- "INCH", 100,
- "INCHES", 100,
- "FEET", 1200,
- "FOOT", 1200,
- "YARD", 3600,
- "YARDS", 3600,
- "MILE", 6336000,
- "MILES", 6336000
- };
-
- double unitfactor=0;
- for (j = 0; j < NKEYS; j++) {
- if (strncasecmp2(unit, unitkeytab[j].name, 0) == 0) unitfactor=unitkeytab[j].value;
- }
- return(unitfactor);
-}
-
-/* -------------------------------------------------------------------- */
-/* Display a usage message. */
-/* -------------------------------------------------------------------- */
-void error()
-{
- puts( "The program will append to an existing shape file or it will" );
- puts( "create a new file if needed." );
- puts( "Only the items in the first output file will be preserved." );
- puts( "When an item does not match with the append theme then the item");
- puts( "might be placed to an existing item at the same position and type." );
- puts( " OTHER FUNCTIONS:" );
- puts( " - Describe all items in the dbase file (Use ALL for more than 5000 recs.)");
- puts( " - Select a group of shapes from a comma separated selection list.");
- puts( " - UnSelect a group of shapes from a comma separated selection list.");
- puts( " - Clip boundary extent or by theme boundary." );
- puts( " Touch writes all the shapes that touch the boundary.");
- puts( " Inside writes all the shapes that are completely within the boundary.");
- puts( " Boundary clips are only the min and max of a theme boundary." );
- puts( " - Erase boundary extent or by theme boundary." );
- puts( " Erase is the direct opposite of the Clip function." );
- puts( " - Change coordinate value units between meters and feet.");
- puts( " There is no way to determine the input unit of a shape file.");
- puts( " Skip this function if the shape file is already in the correct unit.");
- puts( " Clip and Erase will be done before the unit is changed.");
- puts( " A shift will be done after the unit is changed.");
- puts( " - Shift X and Y coordinates.\n" );
- puts( "Finally, There can only be one select or unselect in the command line.");
- puts( " There can only be one clip or erase in the command line.");
- puts( " There can only be one unit and only one shift in the command line.\n");
- puts( "Ex: shputils in.shp out.shp SELECT countycode 3,5,9,13,17,27");
- puts( " shputils in.shp out.shp CLIP 10 10 90 90 Touch FACTOR Meter Feet");
- puts( " shputils in.shp out.shp FACTOR Meter 3.0");
- puts( " shputils in.shp out.shp CLIP clip.shp Boundary Touch SHIFT 40 40");
- puts( " shputils in.shp out.shp SELECT co 112 CLIP clip.shp Boundary Touch\n");
- puts( "USAGE: shputils <DescribeShape> {ALL}");
- puts( "USAGE: shputils <InputShape> <OutShape|AppendShape>" );
- puts( " { <FACTOR> <FEET|MILES|METERS|KM> <FEET|MILES|METERS|KM|factor> }" );
- puts( " { <SHIFT> <xshift> <yshift> }" );
- puts( " { <SELECT|UNSEL> <Item> <valuelist> }" );
- puts( " { <CLIP|ERASE> <xmin> <ymin> <xmax> <ymax> <TOUCH|INSIDE|CUT> }" );
- puts( " { <CLIP|ERASE> <theme> <BOUNDARY> <TOUCH|INSIDE|CUT> }" );
- puts( " Note: CUT is not complete and does not create intersections.");
- puts( " For more information read programmer comment.");
-
- /**** Clip functions for Polygon and Cut is not supported
- There are several web pages that describe methods of doing this function.
- It seem easy to impliment until you start writting code. I don't have the
- time to add these functions but a did leave a simple cut routine in the
- program that can be called by using CUT instead of TOUCH in the
- CLIP or ERASE functions. It does not add the intersection of the line and
- the clip box, so polygons could look incomplete and lines will come up short.
-
- Information about clipping lines with a box:
- http://www.csclub.uwaterloo.ca/u/mpslager/articles/sutherland/wr.html
- Information about finding the intersection of two lines:
- http://www.whisqu.se/per/docs/math28.htm
-
- THE CODE LOOKS LIKE THIS:
- ********************************************************
- void Intersect_Lines(float x0,float y0,float x1,float y1,
- float x2,float y2,float x3,float y3,
- float *xi,float *yi)
- {
-// this function computes the intersection of the sent lines
-// and returns the intersection point, note that the function assumes
-// the lines intersect. the function can handle vertical as well
-// as horizontal lines. note the function isn't very clever, it simply
-// applies the math, but we don't need speed since this is a
-// pre-processing step
-// The Intersect_lines program came from (http://www.whisqu.se/per/docs/math28.htm)
-
-float a1,b1,c1, // constants of linear equations
-a2,b2,c2,
-det_inv, // the inverse of the determinant of the coefficientmatrix
-m1,m2; // the slopes of each line
-
-// compute slopes, note the cludge for infinity, however, this will
-// be close enough
-if ((x1-x0)!=0)
-m1 = (y1-y0)/(x1-x0);
-else
-m1 = (float)1e+10; // close enough to infinity
-
-
-if ((x3-x2)!=0)
-m2 = (y3-y2)/(x3-x2);
-else
-m2 = (float)1e+10; // close enough to infinity
-
-// compute constants
-a1 = m1;
-a2 = m2;
-b1 = -1;
-b2 = -1;
-c1 = (y0-m1*x0);
-c2 = (y2-m2*x2);
-// compute the inverse of the determinate
-det_inv = 1/(a1*b2 - a2*b1);
-// use Kramers rule to compute xi and yi
-*xi=((b1*c2 - b2*c1)*det_inv);
-*yi=((a2*c1 - a1*c2)*det_inv);
-} // end Intersect_Lines
- **********************************************************/
-
- exit( 1 );
-}
# ${GEOM_ROOT_DIR}/include/salome
${GEOM_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../shapelib
${CMAKE_CURRENT_SOURCE_DIR}/../HYDROData
${VTK_INCLUDE_DIRS}
)
add_library(HYDROGUI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${PROJECT_HEADERS_MOC})
-target_link_libraries(HYDROGUI HYDROData
+target_link_libraries(HYDROGUI HYDROData shapelib
${CAS_TKV3d} ${CAS_TKTopAlgo} ${CAS_TKBrep} ${CAS_TKBO}
${GUI_LightApp} ${GUI_CAM} ${GUI_suit} ${GUI_qtx} ${GUI_ObjBrowser} ${GUI_GraphicsView} ${GUI_std}
${GUI_Event} ${GUI_OCCViewer} ${GEOM_GEOM} ${GEOM_GEOMBase} ${GEOM_CurveCreator}
#include <vector>
//extern "C" {
-#include <shapelib/shapefil.h>
+#include <shapefil.h>
//};
class SUIT_FileDlg;
#include <QMap>
//extern "C" {
-#include <shapelib/shapefil.h>
+#include <shapefil.h>
//};
class SUIT_FileDlg;
#include <vector>
//extern "C" {
-#include <shapelib/shapefil.h>
+#include <shapefil.h>
//};
class SUIT_FileDlg;