From 45032afbe7ee1223eb2460fd2023627cc2ba8482 Mon Sep 17 00:00:00 2001 From: isn Date: Fri, 26 Jun 2015 12:17:37 +0300 Subject: [PATCH] move shapelib to sep. lib (cmake errors) --- CMakeLists.txt | 1 + src/HYDROData/CMakeLists.txt | 11 +- src/HYDROData/shapelib/dbfopen.c | 2221 ------------------- src/HYDROData/shapelib/safileio.c | 286 --- src/HYDROData/shapelib/shapefil.h | 651 ------ src/HYDROData/shapelib/shpopen.c | 2388 --------------------- src/HYDROData/shapelib/shptree.c | 1187 ---------- src/HYDROData/shapelib/shputils.c | 1072 --------- src/HYDROGUI/CMakeLists.txt | 3 +- src/HYDROGUI/HYDROGUI_ExportFileOp.h | 2 +- src/HYDROGUI/HYDROGUI_ImportLandCoverOp.h | 2 +- src/HYDROGUI/HYDROGUI_ImportPolylineOp.h | 2 +- 12 files changed, 9 insertions(+), 7817 deletions(-) delete mode 100644 src/HYDROData/shapelib/dbfopen.c delete mode 100644 src/HYDROData/shapelib/safileio.c delete mode 100644 src/HYDROData/shapelib/shapefil.h delete mode 100644 src/HYDROData/shapelib/shpopen.c delete mode 100644 src/HYDROData/shapelib/shptree.c delete mode 100644 src/HYDROData/shapelib/shputils.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a66ea384..7be94504 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,6 +172,7 @@ MARK_AS_ADVANCED( # Sources # ======== +ADD_SUBDIRECTORY (src/shapelib) ADD_SUBDIRECTORY (src/HYDROData) ADD_SUBDIRECTORY (src/HYDROGUI) ADD_SUBDIRECTORY (src/HYDROPy) diff --git a/src/HYDROData/CMakeLists.txt b/src/HYDROData/CMakeLists.txt index 05da2c67..36dcd976 100644 --- a/src/HYDROData/CMakeLists.txt +++ b/src/HYDROData/CMakeLists.txt @@ -54,7 +54,6 @@ set(PROJECT_HEADERS HYDROData_LinearInterpolator.h HYDROData_InterpolatorsFactory.h HYDROData_SinusX.h - shapelib/shapefil.h ) set(PROJECT_SOURCES @@ -109,12 +108,7 @@ 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 @@ -132,6 +126,7 @@ include_directories( ${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}) @@ -140,7 +135,7 @@ target_link_libraries(HYDROData ${GEOM_GEOMUtils} ${CAS_OCAF} ${CAS_OCAFVIS} ${C ${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) diff --git a/src/HYDROData/shapelib/dbfopen.c b/src/HYDROData/shapelib/dbfopen.c deleted file mode 100644 index fbe7b065..00000000 --- a/src/HYDROData/shapelib/dbfopen.c +++ /dev/null @@ -1,2221 +0,0 @@ -/****************************************************************************** - * $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/") 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 -#include -#include -#include - -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; -} diff --git a/src/HYDROData/shapelib/safileio.c b/src/HYDROData/shapelib/safileio.c deleted file mode 100644 index f3affe2e..00000000 --- a/src/HYDROData/shapelib/safileio.c +++ /dev/null @@ -1,286 +0,0 @@ -/****************************************************************************** - * $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/") 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 -#include -#include -#include -#include -#include - -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 -# 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 diff --git a/src/HYDROData/shapelib/shapefil.h b/src/HYDROData/shapelib/shapefil.h deleted file mode 100644 index 1df356cf..00000000 --- a/src/HYDROData/shapelib/shapefil.h +++ /dev/null @@ -1,651 +0,0 @@ -#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/") 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 - -#ifdef USE_DBMALLOC -#include -#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 */ diff --git a/src/HYDROData/shapelib/shpopen.c b/src/HYDROData/shapelib/shpopen.c deleted file mode 100644 index ee9fce58..00000000 --- a/src/HYDROData/shapelib/shpopen.c +++ /dev/null @@ -1,2388 +0,0 @@ -/****************************************************************************** - * $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 -#include -#include -#include -#include -#include - -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) ((ab) ? 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; -} diff --git a/src/HYDROData/shapelib/shptree.c b/src/HYDROData/shapelib/shptree.c deleted file mode 100644 index 409134e2..00000000 --- a/src/HYDROData/shapelib/shptree.c +++ /dev/null @@ -1,1187 +0,0 @@ -/****************************************************************************** - * $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 -#include -#include -#include - -#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; isHooks.FRead( &numsubnodes, 4, 1, hDiskTree->fpQIX ); - if ( bNeedSwap ) SwapWord ( 4, &numsubnodes ); - - for(i=0; isHooks.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; inSubNodes; 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; inSubNodes; 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; -} diff --git a/src/HYDROData/shapelib/shputils.c b/src/HYDROData/shapelib/shputils.c deleted file mode 100644 index b2c7f06e..00000000 --- a/src/HYDROData/shapelib/shputils.c +++ /dev/null @@ -1,1072 +0,0 @@ -/****************************************************************************** - * $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 - -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= 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= '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 {ALL}"); - puts( "USAGE: shputils " ); - puts( " { }" ); - puts( " { }" ); - puts( " { }" ); - puts( " { }" ); - puts( " { }" ); - 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 ); -} diff --git a/src/HYDROGUI/CMakeLists.txt b/src/HYDROGUI/CMakeLists.txt index b0363832..ed9f63e8 100644 --- a/src/HYDROGUI/CMakeLists.txt +++ b/src/HYDROGUI/CMakeLists.txt @@ -292,13 +292,14 @@ include_directories( # ${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} diff --git a/src/HYDROGUI/HYDROGUI_ExportFileOp.h b/src/HYDROGUI/HYDROGUI_ExportFileOp.h index 886424df..3fd45f81 100644 --- a/src/HYDROGUI/HYDROGUI_ExportFileOp.h +++ b/src/HYDROGUI/HYDROGUI_ExportFileOp.h @@ -27,7 +27,7 @@ #include //extern "C" { -#include +#include //}; class SUIT_FileDlg; diff --git a/src/HYDROGUI/HYDROGUI_ImportLandCoverOp.h b/src/HYDROGUI/HYDROGUI_ImportLandCoverOp.h index 35c8ef84..62fe7301 100644 --- a/src/HYDROGUI/HYDROGUI_ImportLandCoverOp.h +++ b/src/HYDROGUI/HYDROGUI_ImportLandCoverOp.h @@ -28,7 +28,7 @@ #include //extern "C" { -#include +#include //}; class SUIT_FileDlg; diff --git a/src/HYDROGUI/HYDROGUI_ImportPolylineOp.h b/src/HYDROGUI/HYDROGUI_ImportPolylineOp.h index 15733625..203b8c8f 100644 --- a/src/HYDROGUI/HYDROGUI_ImportPolylineOp.h +++ b/src/HYDROGUI/HYDROGUI_ImportPolylineOp.h @@ -27,7 +27,7 @@ #include //extern "C" { -#include +#include //}; class SUIT_FileDlg; -- 2.39.2