]> granicus.if.org Git - postgis/commitdiff
shapelib put in sync with gdal cvs
authorSandro Santilli <strk@keybit.net>
Mon, 1 Dec 2003 20:52:00 +0000 (20:52 +0000)
committerSandro Santilli <strk@keybit.net>
Mon, 1 Dec 2003 20:52:00 +0000 (20:52 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@398 b70326c6-7e19-0410-871a-916f4a2858ee

loader/dbfopen.c
loader/shapefil.h
loader/shpopen.c

index 93eb1a5a36f01f3b681ff87427f6bf3ac1091396..280fa01c880b819e05ecf83ac7e7bb84579fdaa5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Project:  Shapelib
  * Purpose:  Implementation of .dbf access API documented in dbf_api.html.
- * Author:   Frank Warmerdam, warmerda@home.com
+ * Author:   Frank Warmerdam, warmerdam@pobox.com
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
  ******************************************************************************
  *
  * $Log$
- * Revision 1.5  2002/10/17 17:06:39  chodgson
- * fixed the last compile warning on solaris/gcc
+ * Revision 1.6  2003/12/01 20:52:00  strk
+ * shapelib put in sync with gdal cvs
  *
- * Revision 1.4  2002/10/17 16:45:04  chodgson
- * - cleaned up all the compiler warnings
- * - for getopt.c, this involved moving the line:
- *       extern char *getenv(const char *name);
- *   outside of the two nested #ifdefs that it was inside, as it is always required (the code that calls it isn't inside any #ifdefs) Perhaps this may break compilation in non-linux/gnu environments?
+ * Revision 1.52  2003/07/08 15:20:03  warmerda
+ * avoid warnings about downcasting to unsigned char
  *
- * Revision 1.3  2002/05/04 22:44:04  pramsey
- * Update shapelib references to 1.2.9.
+ * Revision 1.51  2003/07/08 13:50:15  warmerda
+ * DBFIsAttributeNULL check for pszValue==NULL - bug 360
+ *
+ * Revision 1.50  2003/04/21 18:58:25  warmerda
+ * ensure current record is flushed at same time as header is updated
+ *
+ * Revision 1.49  2003/04/21 18:30:37  warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.48  2003/03/10 14:51:27  warmerda
+ * DBFWrite* calls now return FALSE if they have to truncate
+ *
+ * Revision 1.47  2002/11/20 03:32:22  warmerda
+ * Ensure field name in DBFGetFieldIndex() is properly terminated.
+ *
+ * Revision 1.46  2002/10/09 13:10:21  warmerda
+ * Added check that width is positive.
+ *
+ * Revision 1.45  2002/09/29 00:00:08  warmerda
+ * added FTLogical and logical attribute read/write calls
+ *
+ * Revision 1.44  2002/05/07 13:46:11  warmerda
+ * Added DBFWriteAttributeDirectly().
+ *
+ * Revision 1.43  2002/02/13 19:39:21  warmerda
+ * Fix casting issues in DBFCloneEmpty().
+ *
+ * Revision 1.42  2002/01/15 14:36:07  warmerda
+ * updated email address
+ *
+ * Revision 1.41  2002/01/15 14:31:49  warmerda
+ * compute rather than copying nHeaderLength in DBFCloneEmpty()
+ *
+ * Revision 1.40  2002/01/09 04:32:35  warmerda
+ * fixed to read correct amount of header
+ *
+ * Revision 1.39  2001/12/11 22:41:03  warmerda
+ * improve io related error checking when reading header
+ *
+ * Revision 1.38  2001/11/28 16:07:31  warmerda
+ * Cleanup to avoid compiler warnings as suggested by Richard Hash.
  *
  * Revision 1.37  2001/07/04 05:18:09  warmerda
  * do last fix properly
  * Added header.
  */
 
+static char rcsid[] = 
+  "$Id$";
+
 #include "shapefil.h"
 
 #include <math.h>
@@ -220,13 +259,18 @@ static void DBFWriteHeader(DBFHandle psDBF)
 
     abyHeader[0] = 0x03;               /* memo field? - just copying   */
 
-    /* date updated on close, record count preset at zero */
+    /* write out a dummy date */
+    abyHeader[1] = 95;                 /* YY */
+    abyHeader[2] = 7;                  /* MM */
+    abyHeader[3] = 26;                 /* DD */
 
-    abyHeader[8] = psDBF->nHeaderLength % 256;
-    abyHeader[9] = psDBF->nHeaderLength / 256;
+    /* record count preset at zero */
+
+    abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
+    abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
     
-    abyHeader[10] = psDBF->nRecordLength % 256;
-    abyHeader[11] = psDBF->nRecordLength / 256;
+    abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
+    abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
 
 /* -------------------------------------------------------------------- */
 /*      Write the initial 32 byte file header, and all the field        */
@@ -271,6 +315,35 @@ static void DBFFlushRecord( DBFHandle psDBF )
     }
 }
 
+/************************************************************************/
+/*                          DBFUpdateHeader()                           */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFUpdateHeader( DBFHandle psDBF )
+
+{
+    unsigned char              abyFileHeader[32];
+
+    if( psDBF->bNoHeader )
+        DBFWriteHeader( psDBF );
+
+    DBFFlushRecord( psDBF );
+
+    fseek( psDBF->fp, 0, 0 );
+    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);
+    
+    fseek( psDBF->fp, 0, 0 );
+    fwrite( abyFileHeader, 32, 1, psDBF->fp );
+
+    fflush( psDBF->fp );
+}
+
 /************************************************************************/
 /*                              DBFOpen()                               */
 /*                                                                      */
@@ -283,7 +356,7 @@ DBFOpen( const char * pszFilename, const char * pszAccess )
 {
     DBFHandle          psDBF;
     unsigned char              *pabyBuf;
-    int                        nFields, nRecords, nHeadLen, nRecLen, iField, i;
+    int                        nFields, nHeadLen, nRecLen, iField, i;
     char               *pszBasename, *pszFullname;
 
 /* -------------------------------------------------------------------- */
@@ -343,9 +416,15 @@ DBFOpen( const char * pszFilename, const char * pszAccess )
 /*  Read Table Header info                                              */
 /* -------------------------------------------------------------------- */
     pabyBuf = (unsigned char *) malloc(500);
-    fread( pabyBuf, 32, 1, psDBF->fp );
+    if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+    {
+        fclose( psDBF->fp );
+        free( pabyBuf );
+        free( psDBF );
+        return NULL;
+    }
 
-    psDBF->nRecords = nRecords = 
+    psDBF->nRecords = 
      pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
 
     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
@@ -363,7 +442,13 @@ DBFOpen( const char * pszFilename, const char * pszAccess )
     psDBF->pszHeader = (char *) pabyBuf;
 
     fseek( psDBF->fp, 32, 0 );
-    fread( pabyBuf, nHeadLen, 1, psDBF->fp );
+    if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+    {
+        fclose( psDBF->fp );
+        free( pabyBuf );
+        free( psDBF );
+        return NULL;
+    }
 
     psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
     psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
@@ -418,24 +503,7 @@ DBFClose(DBFHandle psDBF)
 /*     write access.                                                   */
 /* -------------------------------------------------------------------- */
     if( psDBF->bUpdated )
-    {
-       unsigned char           abyFileHeader[32];
-
-       fseek( psDBF->fp, 0, 0 );
-       fread( abyFileHeader, 32, 1, psDBF->fp );
-
-       abyFileHeader[1] = 95;                  /* YY */
-       abyFileHeader[2] = 7;                   /* MM */
-       abyFileHeader[3] = 26;                  /* DD */
-
-       abyFileHeader[4] = psDBF->nRecords % 256;
-       abyFileHeader[5] = (psDBF->nRecords/256) % 256;
-       abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256;
-       abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256;
-
-       fseek( psDBF->fp, 0, 0 );
-       fwrite( abyFileHeader, 32, 1, psDBF->fp );
-    }
+        DBFUpdateHeader( psDBF );
 
 /* -------------------------------------------------------------------- */
 /*      Close, and free resources.                                      */
@@ -565,6 +633,9 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
     if( eType != FTDouble && nDecimals != 0 )
         return( -1 );
 
+    if( nWidth < 1 )
+        return -1;
+
 /* -------------------------------------------------------------------- */
 /*      SfRealloc all the arrays larger to hold the additional field      */
 /*      information.                                                    */
@@ -591,7 +662,9 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
     psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
     psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
 
-    if( eType == FTString )
+    if( eType == FTLogical )
+        psDBF->pachFieldType[psDBF->nFields-1] = 'L';
+    else if( eType == FTString )
         psDBF->pachFieldType[psDBF->nFields-1] = 'C';
     else
         psDBF->pachFieldType[psDBF->nFields-1] = 'N';
@@ -618,13 +691,13 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
 
     if( eType == FTString )
     {
-        pszFInfo[16] = nWidth % 256;
-        pszFInfo[17] = nWidth / 256;
+        pszFInfo[16] = (unsigned char) (nWidth % 256);
+        pszFInfo[17] = (unsigned char) (nWidth / 256);
     }
     else
     {
-        pszFInfo[16] = nWidth;
-        pszFInfo[17] = nDecimals;
+        pszFInfo[16] = (unsigned char) nWidth;
+        pszFInfo[17] = (unsigned char) nDecimals;
     }
     
 /* -------------------------------------------------------------------- */
@@ -796,6 +869,19 @@ DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
     return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
 }
 
+/************************************************************************/
+/*                        DBFReadLogicalAttribute()                     */
+/*                                                                      */
+/*      Read a logical attribute.                                       */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+    return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
+}
+
 /************************************************************************/
 /*                         DBFIsAttributeNULL()                         */
 /*                                                                      */
@@ -812,6 +898,9 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
 
     pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
 
+    if( pszValue == NULL )
+        return TRUE;
+
     switch(psDBF->pachFieldType[iField])
     {
       case 'N':
@@ -831,7 +920,6 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
         /* empty string fields are considered NULL */
         return strlen(pszValue) == 0;
     }
-    return FALSE;
 }
 
 /************************************************************************/
@@ -890,9 +978,12 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
            pszFieldName[i] = '\0';
     }
 
-    if( psDBF->pachFieldType[iField] == 'N' 
-        || psDBF->pachFieldType[iField] == 'F'
-        || psDBF->pachFieldType[iField] == 'D' )
+    if ( psDBF->pachFieldType[iField] == 'L' )
+       return( FTLogical);
+
+    else if( psDBF->pachFieldType[iField] == 'N' 
+             || psDBF->pachFieldType[iField] == 'F'
+             || psDBF->pachFieldType[iField] == 'D' )
     {
        if( psDBF->panFieldDecimals[iField] > 0 )
            return( FTDouble );
@@ -915,7 +1006,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
                             void * pValue )
 
 {
-    int                nRecordOffset, i, j;
+    int                nRecordOffset, i, j, nRetResult = TRUE;
     unsigned char      *pabyRec;
     char       szSField[400], szFormat[20];
 
@@ -1018,7 +1109,10 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
            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) );
@@ -1034,15 +1128,27 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
                      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], ' ',
@@ -1055,6 +1161,83 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
        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 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
+                              void * pValue )
+
+{
+    int                nRecordOffset, 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 )
+    {
+       DBFFlushRecord( psDBF );
+
+       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( psDBF->nCurrentRecord != hEntity )
+    {
+       DBFFlushRecord( psDBF );
+
+       nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
+
+       fseek( psDBF->fp, nRecordOffset, 0 );
+       fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+       psDBF->nCurrentRecord = hEntity;
+    }
+
+    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 );
 }
 
@@ -1115,6 +1298,20 @@ 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()                              */
 /*                                                                     */
@@ -1237,20 +1434,20 @@ DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
    newDBF = DBFCreate ( pszFilename );
    if ( newDBF == NULL ) return ( NULL ); 
    
-   newDBF->pszHeader = (void *) malloc ( 32 * psDBF->nFields );
+   newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
    memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
    
    newDBF->nFields = psDBF->nFields;
    newDBF->nRecordLength = psDBF->nRecordLength;
-   newDBF->nHeaderLength = psDBF->nHeaderLength;
+   newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
     
-   newDBF->panFieldOffset = (void *) malloc ( sizeof(int) * psDBF->nFields ); 
+   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
-   newDBF->panFieldSize = (void *) malloc ( sizeof(int) * psDBF->nFields );
+   newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
-   newDBF->panFieldDecimals = (void *) malloc ( sizeof(int) * psDBF->nFields );
+   newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
-   newDBF->pachFieldType = (void *) malloc ( sizeof(int) * psDBF->nFields );
+   newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
 
    newDBF->bNoHeader = TRUE;
@@ -1297,8 +1494,8 @@ static void str_to_upper (char *string)
     len = strlen (string);
 
     while (++i < len)
-        if (isalpha((unsigned)string[i]) && islower((unsigned)string[i]))
-           string[i] = toupper ((int)string[i]);
+        if (isalpha(string[i]) && islower(string[i]))
+            string[i] = (char) toupper ((int)string[i]);
 }
 
 /************************************************************************/
@@ -1317,6 +1514,7 @@ DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
     int           i;
 
     strncpy(name1, pszFieldName,11);
+    name1[11] = '\0';
     str_to_upper(name1);
 
     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
index bca89b3e1cb48a6675ef2c0653e20b2cf1da3cde..741c826d83014479b94d8ec218beacde3a1dc303 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Project:  Shapelib
  * Purpose:  Primary include file for Shapelib.
- * Author:   Frank Warmerdam, warmerda@home.com
+ * Author:   Frank Warmerdam, warmerdam@pobox.com
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
  ******************************************************************************
  *
  * $Log$
- * Revision 1.3  2002/05/04 22:44:04  pramsey
- * Update shapelib references to 1.2.9.
+ * Revision 1.4  2003/12/01 20:52:00  strk
+ * shapelib put in sync with gdal cvs
+ *
+ * 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
+ *
+ * Revision 1.21  2001/11/01 16:29:55  warmerda
+ * move pabyRec into SHPInfo for thread safety
  *
  * Revision 1.20  2001/07/20 13:06:02  warmerda
  * fixed SHPAPI attribute for SHPTreeFindLikelyShapes
 extern "C" {
 #endif
 
-#ifndef SHPAPI_CALL
-#define SHPAPI_CALL
-#endif
-
-#define SHPAPI_CALL1(x)      * SHPAPI_CALL
-    
 /************************************************************************/
 /*                        Configuration options.                        */
 /************************************************************************/
@@ -132,6 +147,48 @@ extern "C" {
 /* -------------------------------------------------------------------- */
 #define DISABLE_MULTIPATCH_MEASURE
 
+/* -------------------------------------------------------------------- */
+/*      SHPAPI_CALL                                                     */
+/*                                                                      */
+/*      The following two macros are present to allow forcing           */
+/*      various calling conventions on the Shapelib API.                */
+/*                                                                      */
+/*      To force __stdcall conventions (needed to call Shapelib         */
+/*      from Visual Basic and/or Dephi I believe) the makefile could    */
+/*      be modified to define:                                          */
+/*                                                                      */
+/*        /DSHPAPI_CALL=__stdcall                                       */
+/*                                                                      */
+/*      If it is desired to force export of the Shapelib API without    */
+/*      using the shapelib.def file, use the following definition.      */
+/*                                                                      */
+/*        /DSHAPELIB_DLLEXPORT                                          */
+/*                                                                      */
+/*      To get both at once it will be necessary to hack this           */
+/*      include file to define:                                         */
+/*                                                                      */
+/*        #define SHPAPI_CALL __declspec(dllexport) __stdcall           */
+/*        #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall        */
+/*                                                                      */
+/*      The complexity of the situtation is partly caused by the        */
+/*      peculiar requirement of Visual C++ that __stdcall appear        */
+/*      after any "*"'s in the return value of a function while the     */
+/*      __declspec(dllexport) must appear before them.                  */
+/* -------------------------------------------------------------------- */
+
+#ifdef SHAPELIB_DLLEXPORT
+#  define SHPAPI_CALL __declspec(dllexport)
+#  define SHPAPI_CALL1(x)  __declspec(dllexport) x
+#endif
+
+#ifndef SHPAPI_CALL
+#  define SHPAPI_CALL
+#endif
+
+#ifndef SHPAPI_CALL1
+#  define SHPAPI_CALL1(x)      x SHPAPI_CALL
+#endif
+    
 /************************************************************************/
 /*                             SHP Support.                             */
 /************************************************************************/
@@ -153,6 +210,9 @@ typedef     struct
     double     adBoundsMax[4];
 
     int                bUpdated;
+
+    unsigned char *pabyRec;
+    int         nBufSize;
 } SHPInfo;
 
 typedef SHPInfo * SHPHandle;
@@ -248,8 +308,11 @@ SHPObject SHPAPI_CALL1(*)
       SHPCreateSimpleObject( int nSHPType, int nVertices,
                              double * padfX, double * padfY, double * padfZ );
 
-void SHPAPI_CALL
-      SHPClose( SHPHandle hSHP );
+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 );
@@ -352,6 +415,7 @@ typedef enum {
   FTString,
   FTInteger,
   FTDouble,
+  FTLogical,
   FTInvalid
 } DBFFieldType;
 
@@ -383,6 +447,8 @@ 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 );
 
@@ -398,6 +464,12 @@ int SHPAPI_CALL
 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
@@ -408,6 +480,8 @@ DBFHandle SHPAPI_CALL
  
 void   SHPAPI_CALL
       DBFClose( DBFHandle hDBF );
+void    SHPAPI_CALL
+      DBFUpdateHeader( DBFHandle hDBF );
 char    SHPAPI_CALL
       DBFGetNativeFieldType( DBFHandle hDBF, int iField );
 
index 4af4ce0c0a7bb41d795baf317aaa642d1f42895f..599ccaf89b0e67c2eabc205f335b6c8775f29dcc 100644 (file)
  ******************************************************************************
  *
  * $Log$
- * Revision 1.4  2002/10/17 16:45:04  chodgson
- * - cleaned up all the compiler warnings
- * - for getopt.c, this involved moving the line:
- *       extern char *getenv(const char *name);
- *   outside of the two nested #ifdefs that it was inside, as it is always required (the code that calls it isn't inside any #ifdefs) Perhaps this may break compilation in non-linux/gnu environments?
+ * Revision 1.5  2003/12/01 20:52:00  strk
+ * shapelib put in sync with gdal cvs
  *
- * Revision 1.3  2002/05/04 22:44:04  pramsey
- * Update shapelib references to 1.2.9.
+ * 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.
  *
  */
 
+static char rcsid[] = 
+  "$Id$";
+
 #include "shapefil.h"
 
 #include <math.h>
@@ -177,8 +204,6 @@ typedef int       int32;
 #endif
 
 static int     bBigEndian;
-static uchar   *pabyRec = NULL;
-static int     nBufSize = 0;
 
 
 /************************************************************************/
@@ -224,7 +249,7 @@ static void * SfRealloc( void * pMem, int nNewSize )
 /*     contents of the index (.shx) file.                              */
 /************************************************************************/
 
-static void SHPWriteHeader( SHPHandle psSHP )
+void SHPWriteHeader( SHPHandle psSHP )
 
 {
     uchar      abyHeader[100];
@@ -318,6 +343,12 @@ static void SHPWriteHeader( SHPHandle psSHP )
     fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX );
 
     free( panSHX );
+
+/* -------------------------------------------------------------------- */
+/*      Flush to disk.                                                  */
+/* -------------------------------------------------------------------- */
+    fflush( psSHP->fpSHP );
+    fflush( psSHP->fpSHX );
 }
 
 /************************************************************************/
@@ -361,7 +392,7 @@ SHPOpen( const char * pszLayer, const char * pszAccess )
 /* -------------------------------------------------------------------- */
 /*     Initialize the info structure.                                  */
 /* -------------------------------------------------------------------- */
-    psSHP = (SHPHandle) malloc(sizeof(SHPInfo));
+    psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
 
     psSHP->bUpdated = FALSE;
 
@@ -410,7 +441,7 @@ SHPOpen( const char * pszLayer, const char * pszAccess )
     
     if( psSHP->fpSHX == NULL )
     {
-        fclose( psSHP->fpSHX );
+        fclose( psSHP->fpSHP );
         free( psSHP );
         free( pszBasename );
         free( pszFullname );
@@ -547,9 +578,7 @@ SHPClose(SHPHandle psSHP )
 /*     Update the header if we have modified anything.                 */
 /* -------------------------------------------------------------------- */
     if( psSHP->bUpdated )
-    {
        SHPWriteHeader( psSHP );
-    }
 
 /* -------------------------------------------------------------------- */
 /*      Free all resources, and close files.                            */
@@ -560,14 +589,12 @@ SHPClose(SHPHandle psSHP )
     fclose( psSHP->fpSHX );
     fclose( psSHP->fpSHP );
 
-    free( psSHP );
-
-    if( pabyRec != NULL )
+    if( psSHP->pabyRec != NULL )
     {
-        free( pabyRec );
-        pabyRec = NULL;
-        nBufSize = 0;
+        free( psSHP->pabyRec );
     }
+    
+    free( psSHP );
 }
 
 /************************************************************************/
@@ -906,7 +933,7 @@ int SHPAPI_CALL
 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
                      
 {
-    int                nRecordOffset, i, nRecordSize;
+    int                nRecordOffset, i, nRecordSize=0;
     uchar      *pabyRec;
     int32      i32;
 
@@ -1233,13 +1260,22 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
     if( psSHP->adBoundsMin[0] == 0.0
         && psSHP->adBoundsMax[0] == 0.0
         && psSHP->adBoundsMin[1] == 0.0
-        && psSHP->adBoundsMax[1] == 0.0 
-        && psObject->nSHPType != SHPT_NULL )
+        && psSHP->adBoundsMax[1] == 0.0 )
     {
-        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];
+        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++ )
@@ -1279,17 +1315,17 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
 /*      Ensure our record buffer is large enough.                       */
 /* -------------------------------------------------------------------- */
-    if( psSHP->panRecSize[hEntity]+8 > nBufSize )
+    if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )
     {
-       nBufSize = psSHP->panRecSize[hEntity]+8;
-       pabyRec = (uchar *) SfRealloc(pabyRec,nBufSize);
+       psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
+       psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
     }
 
 /* -------------------------------------------------------------------- */
 /*      Read the record.                                                */
 /* -------------------------------------------------------------------- */
     fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );
-    fread( pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
+    fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
 
 /* -------------------------------------------------------------------- */
 /*     Allocate and minimally initialize the object.                   */
@@ -1297,7 +1333,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
     psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
     psShape->nShapeId = hEntity;
 
-    memcpy( &psShape->nSHPType, pabyRec + 8, 4 );
+    memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
     if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
 
 /* ==================================================================== */
@@ -1316,10 +1352,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
 /*     Get the X/Y bounds.                                             */
 /* -------------------------------------------------------------------- */
-        memcpy( &(psShape->dfXMin), pabyRec + 8 +  4, 8 );
-        memcpy( &(psShape->dfYMin), pabyRec + 8 + 12, 8 );
-        memcpy( &(psShape->dfXMax), pabyRec + 8 + 20, 8 );
-        memcpy( &(psShape->dfYMax), pabyRec + 8 + 28, 8 );
+        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) );
@@ -1330,8 +1366,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /*      Extract part/point count, and build vertex and part arrays      */
 /*      to proper size.                                                 */
 /* -------------------------------------------------------------------- */
-       memcpy( &nPoints, pabyRec + 40 + 8, 4 );
-       memcpy( &nParts, pabyRec + 36 + 8, 4 );
+       memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
+       memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
 
        if( bBigEndian ) SwapWord( 4, &nPoints );
        if( bBigEndian ) SwapWord( 4, &nParts );
@@ -1352,7 +1388,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
 /*      Copy out the part array from the record.                        */
 /* -------------------------------------------------------------------- */
-       memcpy( psShape->panPartStart, pabyRec + 44 + 8, 4 * nParts );
+       memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
        for( i = 0; i < nParts; i++ )
        {
            if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
@@ -1365,7 +1401,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
         if( psShape->nSHPType == SHPT_MULTIPATCH )
         {
-            memcpy( psShape->panPartType, pabyRec + nOffset, 4*nParts );
+            memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
             for( i = 0; i < nParts; i++ )
             {
                 if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
@@ -1380,11 +1416,11 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
        for( i = 0; i < nPoints; i++ )
        {
            memcpy(psShape->padfX + i,
-                  pabyRec + nOffset + i * 16,
+                  psSHP->pabyRec + nOffset + i * 16,
                   8 );
 
            memcpy(psShape->padfY + i,
-                  pabyRec + nOffset + i * 16 + 8,
+                  psSHP->pabyRec + nOffset + i * 16 + 8,
                   8 );
 
            if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
@@ -1400,8 +1436,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             || psShape->nSHPType == SHPT_ARCZ
             || psShape->nSHPType == SHPT_MULTIPATCH )
         {
-            memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 );
-            memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 );
+            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) );
@@ -1409,7 +1445,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             for( i = 0; i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
-                        pabyRec + nOffset + 16 + i*8, 8 );
+                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );
                 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
             }
 
@@ -1424,8 +1460,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
         if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
         {
-            memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 );
-            memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 );
+            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) );
@@ -1433,7 +1469,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             for( i = 0; i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
-                        pabyRec + nOffset + 16 + i*8, 8 );
+                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );
                 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
             }
         }
@@ -1450,7 +1486,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
        int32           nPoints;
        int             i, nOffset;
 
-       memcpy( &nPoints, pabyRec + 44, 4 );
+       memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
        if( bBigEndian ) SwapWord( 4, &nPoints );
 
        psShape->nVertices = nPoints;
@@ -1461,8 +1497,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 
        for( i = 0; i < nPoints; i++ )
        {
-           memcpy(psShape->padfX+i, pabyRec + 48 + 16 * i, 8 );
-           memcpy(psShape->padfY+i, pabyRec + 48 + 16 * i + 8, 8 );
+           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 );
@@ -1473,10 +1509,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
 /*     Get the X/Y bounds.                                             */
 /* -------------------------------------------------------------------- */
-        memcpy( &(psShape->dfXMin), pabyRec + 8 +  4, 8 );
-        memcpy( &(psShape->dfYMin), pabyRec + 8 + 12, 8 );
-        memcpy( &(psShape->dfXMax), pabyRec + 8 + 20, 8 );
-        memcpy( &(psShape->dfYMax), pabyRec + 8 + 28, 8 );
+        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) );
@@ -1488,8 +1524,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
         if( psShape->nSHPType == SHPT_MULTIPOINTZ )
         {
-            memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 );
-            memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 );
+            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) );
@@ -1497,7 +1533,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             for( i = 0; i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
-                        pabyRec + nOffset + 16 + i*8, 8 );
+                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );
                 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
             }
 
@@ -1512,8 +1548,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
         if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
         {
-            memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 );
-            memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 );
+            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) );
@@ -1521,7 +1557,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             for( i = 0; i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
-                        pabyRec + nOffset + 16 + i*8, 8 );
+                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );
                 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
             }
         }
@@ -1542,8 +1578,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         psShape->padfZ = (double *) calloc(1,sizeof(double));
         psShape->padfM = (double *) calloc(1,sizeof(double));
 
-       memcpy( psShape->padfX, pabyRec + 12, 8 );
-       memcpy( psShape->padfY, pabyRec + 20, 8 );
+       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 );
@@ -1555,7 +1591,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
         if( psShape->nSHPType == SHPT_POINTZ )
         {
-            memcpy( psShape->padfZ, pabyRec + nOffset, 8 );
+            memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
         
             if( bBigEndian ) SwapWord( 8, psShape->padfZ );
             
@@ -1570,7 +1606,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /* -------------------------------------------------------------------- */
         if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )
         {
-            memcpy( psShape->padfM, pabyRec + nOffset, 8 );
+            memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
         
             if( bBigEndian ) SwapWord( 8, psShape->padfM );
         }
@@ -1705,3 +1741,157 @@ SHPDestroyObject( SHPObject * psShape )
 
     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.                                        */
+/* -------------------------------------------------------------------- */
+        dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]];
+        dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]];
+
+        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;
+
+                if( (psObject->padfY[iEdge+nVertStart] < dfTestY 
+                     && psObject->padfY[iNext+nVertStart] >= dfTestY)
+                    || (psObject->padfY[iNext+nVertStart] < dfTestY 
+                        && psObject->padfY[iEdge+nVertStart] >= dfTestY) )
+                {
+                    if( 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]) < dfTestX )
+                        bInner = !bInner;
+                }
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Determine the current order of this ring so we will know if     */
+/*      it has to be reversed.                                          */
+/* -------------------------------------------------------------------- */
+        nVertStart = psObject->panPartStart[iOpRing];
+
+        if( iOpRing == psObject->nParts-1 )
+            nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
+        else
+            nVertCount = psObject->panPartStart[iOpRing+1] 
+                - psObject->panPartStart[iOpRing];
+
+        dfSum = 0.0;
+        for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
+        {
+            dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
+                - psObject->padfY[iVert] * psObject->padfX[iVert+1];
+        }
+
+        dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
+               - psObject->padfY[iVert] * psObject->padfX[nVertStart];
+
+/* -------------------------------------------------------------------- */
+/*      Reverse if necessary.                                           */
+/* -------------------------------------------------------------------- */
+        if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
+        {
+            int   i;
+
+            bAltered++;
+            for( i = 0; i < nVertCount/2; i++ )
+            {
+                double dfSaved;
+
+                /* Swap X */
+                dfSaved = psObject->padfX[nVertStart+i];
+                psObject->padfX[nVertStart+i] = 
+                    psObject->padfX[nVertStart+nVertCount-i-1];
+                psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
+
+                /* Swap Y */
+                dfSaved = psObject->padfY[nVertStart+i];
+                psObject->padfY[nVertStart+i] = 
+                    psObject->padfY[nVertStart+nVertCount-i-1];
+                psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
+
+                /* Swap Z */
+                if( psObject->padfZ )
+                {
+                    dfSaved = psObject->padfZ[nVertStart+i];
+                    psObject->padfZ[nVertStart+i] = 
+                        psObject->padfZ[nVertStart+nVertCount-i-1];
+                    psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
+                }
+
+                /* Swap M */
+                if( psObject->padfM )
+                {
+                    dfSaved = psObject->padfM[nVertStart+i];
+                    psObject->padfM[nVertStart+i] = 
+                        psObject->padfM[nVertStart+nVertCount-i-1];
+                    psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
+                }
+            }
+        }
+    }
+
+    return bAltered;
+}