LCOV - code coverage report
Current view: directory - ogr - ogrpgeogeometry.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 536 323 60.3 %
Date: 2012-12-26 Functions: 3 2 66.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpgeogeometry.cpp 23752 2012-01-13 00:34:09Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements decoder of shapebin geometry for PGeo
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *           Paul Ramsey, pramsey at cleverelephant.ca
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      11                 :  * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  *
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  *
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  ****************************************************************************/
      31                 : 
      32                 : #include "ogrpgeogeometry.h"
      33                 : #include "ogr_p.h"
      34                 : #include "cpl_string.h"
      35                 : #include "zlib.h"
      36                 : 
      37                 : CPL_CVSID("$Id: ogrpgeogeometry.cpp 23752 2012-01-13 00:34:09Z rouault $");
      38                 : 
      39                 : #define SHPP_TRISTRIP   0
      40                 : #define SHPP_TRIFAN     1
      41                 : #define SHPP_OUTERRING  2
      42                 : #define SHPP_INNERRING  3
      43                 : #define SHPP_FIRSTRING  4
      44                 : #define SHPP_RING       5
      45                 : #define SHPP_TRIANGLES  6 /* Multipatch 9.0 specific */
      46                 : 
      47                 : 
      48                 : /************************************************************************/
      49                 : /*                     OGRCreateFromMultiPatch()                        */
      50                 : /*                                                                      */
      51                 : /*      Translate a multipatch representation to an OGR geometry        */
      52                 : /*      Mostly copied from shape2ogr.cpp                                */
      53                 : /************************************************************************/
      54                 : 
      55               0 : static OGRGeometry* OGRCreateFromMultiPatch(int nParts,
      56                 :                                             GInt32* panPartStart,
      57                 :                                             GInt32* panPartType,
      58                 :                                             int nPoints,
      59                 :                                             double* padfX,
      60                 :                                             double* padfY,
      61                 :                                             double* padfZ)
      62                 : {
      63               0 :     OGRMultiPolygon *poMP = new OGRMultiPolygon();
      64                 :     int iPart;
      65               0 :     OGRPolygon *poLastPoly = NULL;
      66                 : 
      67               0 :     for( iPart = 0; iPart < nParts; iPart++ )
      68                 :     {
      69                 :         int nPartPoints, nPartStart;
      70                 : 
      71                 :         // Figure out details about this part's vertex list.
      72               0 :         if( panPartStart == NULL )
      73                 :         {
      74               0 :             nPartPoints = nPoints;
      75               0 :             nPartStart = 0;
      76                 :         }
      77                 :         else
      78                 :         {
      79                 : 
      80               0 :             if( iPart == nParts - 1 )
      81                 :                 nPartPoints =
      82               0 :                     nPoints - panPartStart[iPart];
      83                 :             else
      84               0 :                 nPartPoints = panPartStart[iPart+1]
      85               0 :                     - panPartStart[iPart];
      86               0 :             nPartStart = panPartStart[iPart];
      87                 :         }
      88                 : 
      89               0 :         panPartType[iPart] &= 0xf;
      90                 : 
      91               0 :         if( panPartType[iPart] == SHPP_TRISTRIP )
      92                 :         {
      93                 :             int iBaseVert;
      94                 : 
      95               0 :             if( poLastPoly != NULL )
      96                 :             {
      97               0 :                 poMP->addGeometryDirectly( poLastPoly );
      98               0 :                 poLastPoly = NULL;
      99                 :             }
     100                 : 
     101               0 :             for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
     102                 :             {
     103               0 :                 OGRPolygon *poPoly = new OGRPolygon();
     104               0 :                 OGRLinearRing *poRing = new OGRLinearRing();
     105               0 :                 int iSrcVert = iBaseVert + nPartStart;
     106                 : 
     107                 :                 poRing->setPoint( 0,
     108                 :                                 padfX[iSrcVert],
     109                 :                                 padfY[iSrcVert],
     110               0 :                                 padfZ[iSrcVert] );
     111                 :                 poRing->setPoint( 1,
     112                 :                                 padfX[iSrcVert+1],
     113                 :                                 padfY[iSrcVert+1],
     114               0 :                                 padfZ[iSrcVert+1] );
     115                 : 
     116                 :                 poRing->setPoint( 2,
     117                 :                                 padfX[iSrcVert+2],
     118                 :                                 padfY[iSrcVert+2],
     119               0 :                                 padfZ[iSrcVert+2] );
     120                 :                 poRing->setPoint( 3,
     121                 :                                 padfX[iSrcVert],
     122                 :                                 padfY[iSrcVert],
     123               0 :                                 padfZ[iSrcVert] );
     124                 : 
     125               0 :                 poPoly->addRingDirectly( poRing );
     126               0 :                 poMP->addGeometryDirectly( poPoly );
     127                 :             }
     128                 :         }
     129               0 :         else if( panPartType[iPart] == SHPP_TRIFAN )
     130                 :         {
     131                 :             int iBaseVert;
     132                 : 
     133               0 :             if( poLastPoly != NULL )
     134                 :             {
     135               0 :                 poMP->addGeometryDirectly( poLastPoly );
     136               0 :                 poLastPoly = NULL;
     137                 :             }
     138                 : 
     139               0 :             for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert++ )
     140                 :             {
     141               0 :                 OGRPolygon *poPoly = new OGRPolygon();
     142               0 :                 OGRLinearRing *poRing = new OGRLinearRing();
     143               0 :                 int iSrcVert = iBaseVert + nPartStart;
     144                 : 
     145                 :                 poRing->setPoint( 0,
     146                 :                                 padfX[nPartStart],
     147                 :                                 padfY[nPartStart],
     148               0 :                                 padfZ[nPartStart] );
     149                 :                 poRing->setPoint( 1,
     150                 :                                 padfX[iSrcVert+1],
     151                 :                                 padfY[iSrcVert+1],
     152               0 :                                 padfZ[iSrcVert+1] );
     153                 : 
     154                 :                 poRing->setPoint( 2,
     155                 :                                 padfX[iSrcVert+2],
     156                 :                                 padfY[iSrcVert+2],
     157               0 :                                 padfZ[iSrcVert+2] );
     158                 :                 poRing->setPoint( 3,
     159                 :                                 padfX[nPartStart],
     160                 :                                 padfY[nPartStart],
     161               0 :                                 padfZ[nPartStart] );
     162                 : 
     163               0 :                 poPoly->addRingDirectly( poRing );
     164               0 :                 poMP->addGeometryDirectly( poPoly );
     165                 :             }
     166                 :         }
     167               0 :         else if( panPartType[iPart] == SHPP_OUTERRING
     168               0 :                 || panPartType[iPart] == SHPP_INNERRING
     169               0 :                 || panPartType[iPart] == SHPP_FIRSTRING
     170               0 :                 || panPartType[iPart] == SHPP_RING )
     171                 :         {
     172               0 :             if( poLastPoly != NULL
     173               0 :                 && (panPartType[iPart] == SHPP_OUTERRING
     174               0 :                     || panPartType[iPart] == SHPP_FIRSTRING) )
     175                 :             {
     176               0 :                 poMP->addGeometryDirectly( poLastPoly );
     177               0 :                 poLastPoly = NULL;
     178                 :             }
     179                 : 
     180               0 :             if( poLastPoly == NULL )
     181               0 :                 poLastPoly = new OGRPolygon();
     182                 : 
     183               0 :             OGRLinearRing *poRing = new OGRLinearRing;
     184                 : 
     185                 :             poRing->setPoints( nPartPoints,
     186                 :                                 padfX + nPartStart,
     187                 :                                 padfY + nPartStart,
     188               0 :                                 padfZ + nPartStart );
     189                 : 
     190               0 :             poRing->closeRings();
     191                 : 
     192               0 :             poLastPoly->addRingDirectly( poRing );
     193                 :         }
     194               0 :         else if ( panPartType[iPart] == SHPP_TRIANGLES )
     195                 :         {
     196                 :             int iBaseVert;
     197                 : 
     198               0 :             if( poLastPoly != NULL )
     199                 :             {
     200               0 :                 poMP->addGeometryDirectly( poLastPoly );
     201               0 :                 poLastPoly = NULL;
     202                 :             }
     203                 : 
     204               0 :             for( iBaseVert = 0; iBaseVert < nPartPoints-2; iBaseVert+=3 )
     205                 :             {
     206               0 :                 OGRPolygon *poPoly = new OGRPolygon();
     207               0 :                 OGRLinearRing *poRing = new OGRLinearRing();
     208               0 :                 int iSrcVert = iBaseVert + nPartStart;
     209                 : 
     210                 :                 poRing->setPoint( 0,
     211                 :                                 padfX[iSrcVert],
     212                 :                                 padfY[iSrcVert],
     213               0 :                                 padfZ[iSrcVert] );
     214                 :                 poRing->setPoint( 1,
     215                 :                                 padfX[iSrcVert+1],
     216                 :                                 padfY[iSrcVert+1],
     217               0 :                                 padfZ[iSrcVert+1] );
     218                 : 
     219                 :                 poRing->setPoint( 2,
     220                 :                                 padfX[iSrcVert+2],
     221                 :                                 padfY[iSrcVert+2],
     222               0 :                                 padfZ[iSrcVert+2] );
     223                 :                 poRing->setPoint( 3,
     224                 :                                 padfX[iSrcVert],
     225                 :                                 padfY[iSrcVert],
     226               0 :                                 padfZ[iSrcVert] );
     227                 : 
     228               0 :                 poPoly->addRingDirectly( poRing );
     229               0 :                 poMP->addGeometryDirectly( poPoly );
     230                 :             }
     231                 :         }
     232                 :         else
     233                 :             CPLDebug( "OGR", "Unrecognised parttype %d, ignored.",
     234               0 :                     panPartType[iPart] );
     235                 :     }
     236                 : 
     237               0 :     if( poLastPoly != NULL )
     238                 :     {
     239               0 :         poMP->addGeometryDirectly( poLastPoly );
     240               0 :         poLastPoly = NULL;
     241                 :     }
     242                 : 
     243               0 :     return poMP;
     244                 : }
     245                 : 
     246                 : 
     247                 : /************************************************************************/
     248                 : /*                      OGRWriteToShapeBin()                            */
     249                 : /*                                                                      */
     250                 : /*      Translate OGR geometry to a shapefile binary representation     */
     251                 : /************************************************************************/
     252                 : 
     253            1135 : OGRErr OGRWriteToShapeBin( OGRGeometry *poGeom, 
     254                 :                            GByte **ppabyShape,
     255                 :                            int *pnBytes )
     256                 : {
     257            1135 :     GUInt32 nGType = SHPT_NULL;
     258            1135 :     int nShpSize = 4; /* All types start with integer type number */
     259            1135 :     int nShpZSize = 0; /* Z gets tacked onto the end */
     260            1135 :     GUInt32 nPoints = 0;
     261            1135 :     GUInt32 nParts = 0;
     262                 : 
     263                 : /* -------------------------------------------------------------------- */
     264                 : /*      Null or Empty input maps to SHPT_NULL.                          */
     265                 : /* -------------------------------------------------------------------- */
     266            1135 :     if ( ! poGeom || poGeom->IsEmpty() )
     267                 :     {
     268               0 :         *ppabyShape = (GByte*)VSIMalloc(nShpSize);
     269               0 :         GUInt32 zero = SHPT_NULL;
     270               0 :         memcpy(*ppabyShape, &zero, nShpSize);
     271               0 :         *pnBytes = nShpSize;
     272               0 :         return OGRERR_NONE;
     273                 :     }
     274                 : 
     275            1135 :     OGRwkbGeometryType nOGRType = wkbFlatten(poGeom->getGeometryType());
     276            1135 :     int b3d = (poGeom->getGeometryType() & wkb25DBit);
     277            1135 :     int nCoordDims = b3d ? 3 : 2;
     278                 : 
     279                 : /* -------------------------------------------------------------------- */
     280                 : /*      Calculate the shape buffer size                                 */
     281                 : /* -------------------------------------------------------------------- */
     282            1135 :     if ( nOGRType == wkbPoint )
     283                 :     {
     284            1020 :         nShpSize += 8 * nCoordDims;
     285                 :     }
     286             115 :     else if ( nOGRType == wkbLineString )
     287                 :     {
     288              10 :         OGRLineString *poLine = (OGRLineString*)poGeom;
     289              10 :         nPoints = poLine->getNumPoints();
     290              10 :         nParts = 1;
     291              10 :         nShpSize += 16 * nCoordDims; /* xy(z) box */ 
     292              10 :         nShpSize += 4; /* nparts */
     293              10 :         nShpSize += 4; /* npoints */
     294              10 :         nShpSize += 4; /* parts[1] */
     295              10 :         nShpSize += 8 * nCoordDims * nPoints; /* points */
     296              10 :         nShpZSize = 16 + 8 * nPoints;
     297                 :     }
     298             105 :     else if ( nOGRType == wkbPolygon )
     299                 :     {
     300              10 :         poGeom->closeRings();
     301              10 :         OGRPolygon *poPoly = (OGRPolygon*)poGeom;
     302              10 :         nParts = poPoly->getNumInteriorRings() + 1;
     303              20 :         for ( GUInt32 i = 0; i < nParts; i++ )
     304                 :         {
     305                 :             OGRLinearRing *poRing;
     306              10 :             if ( i == 0 )
     307              10 :                 poRing = poPoly->getExteriorRing();
     308                 :             else
     309               0 :                 poRing = poPoly->getInteriorRing(i-1);
     310              10 :             nPoints += poRing->getNumPoints();
     311                 :         }
     312              10 :         nShpSize += 16 * nCoordDims; /* xy(z) box */ 
     313              10 :         nShpSize += 4; /* nparts */
     314              10 :         nShpSize += 4; /* npoints */
     315              10 :         nShpSize += 4 * nParts; /* parts[nparts] */
     316              10 :         nShpSize += 8 * nCoordDims * nPoints; /* points */    
     317              10 :         nShpZSize = 16 + 8 * nPoints;
     318                 :     }
     319              95 :     else if ( nOGRType == wkbMultiPoint )
     320                 :     {
     321              20 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
     322              60 :         for ( int i = 0; i < poMPoint->getNumGeometries(); i++ )
     323                 :         {
     324              40 :             OGRPoint *poPoint = (OGRPoint*)(poMPoint->getGeometryRef(i));
     325              40 :             if ( poPoint->IsEmpty() ) 
     326               0 :                 continue;
     327              40 :             nPoints++;
     328                 :         }
     329              20 :         nShpSize += 16 * nCoordDims; /* xy(z) box */ 
     330              20 :         nShpSize += 4; /* npoints */
     331              20 :         nShpSize += 8 * nCoordDims * nPoints; /* points */    
     332              20 :         nShpZSize = 16 + 8 * nPoints;
     333                 :     }
     334              75 :     else if ( nOGRType == wkbMultiLineString )
     335                 :     {
     336              30 :         OGRMultiLineString *poMLine = (OGRMultiLineString*)poGeom;
     337              60 :         for ( int i = 0; i < poMLine->getNumGeometries(); i++ )
     338                 :         {
     339              30 :             OGRLineString *poLine = (OGRLineString*)(poMLine->getGeometryRef(i));
     340                 :             /* Skip empties */
     341              30 :             if ( poLine->IsEmpty() ) 
     342               0 :                 continue;
     343              30 :             nParts++;
     344              30 :             nPoints += poLine->getNumPoints();
     345                 :         }
     346              30 :         nShpSize += 16 * nCoordDims; /* xy(z) box */ 
     347              30 :         nShpSize += 4; /* nparts */
     348              30 :         nShpSize += 4; /* npoints */
     349              30 :         nShpSize += 4 * nParts; /* parts[nparts] */
     350              30 :         nShpSize += 8 * nCoordDims * nPoints ; /* points */    
     351              30 :         nShpZSize = 16 + 8 * nPoints;
     352                 :     }
     353              45 :     else if ( nOGRType == wkbMultiPolygon )
     354                 :     {
     355              45 :         poGeom->closeRings();
     356              45 :         OGRMultiPolygon *poMPoly = (OGRMultiPolygon*)poGeom;
     357              90 :         for( int j = 0; j < poMPoly->getNumGeometries(); j++ )
     358                 :         {
     359              45 :             OGRPolygon *poPoly = (OGRPolygon*)(poMPoly->getGeometryRef(j));
     360              45 :             int nRings = poPoly->getNumInteriorRings() + 1;
     361                 : 
     362                 :             /* Skip empties */
     363              45 :             if ( poPoly->IsEmpty() ) 
     364               0 :                 continue;
     365                 : 
     366              45 :             nParts += nRings;
     367              90 :             for ( int i = 0; i < nRings; i++ )
     368                 :             {
     369                 :                 OGRLinearRing *poRing;
     370              45 :                 if ( i == 0 )
     371              45 :                     poRing = poPoly->getExteriorRing();
     372                 :                 else
     373               0 :                     poRing = poPoly->getInteriorRing(i-1);
     374              45 :                 nPoints += poRing->getNumPoints();
     375                 :             }
     376                 :         }
     377              45 :         nShpSize += 16 * nCoordDims; /* xy(z) box */ 
     378              45 :         nShpSize += 4; /* nparts */
     379              45 :         nShpSize += 4; /* npoints */
     380              45 :         nShpSize += 4 * nParts; /* parts[nparts] */
     381              45 :         nShpSize += 8 * nCoordDims * nPoints ; /* points */  
     382              45 :         nShpZSize = 16 + 8 * nPoints;
     383                 :     }
     384                 :     else
     385                 :     {
     386               0 :         return OGRERR_UNSUPPORTED_OPERATION;
     387                 :     }
     388                 : 
     389                 :     /* Allocate our shape buffer */
     390            1135 :     *ppabyShape = (GByte*)VSIMalloc(nShpSize);
     391            1135 :     if ( ! *ppabyShape )
     392               0 :         return OGRERR_FAILURE;
     393                 : 
     394                 :     /* Fill in the output size. */
     395            1135 :     *pnBytes = nShpSize;
     396                 : 
     397                 :     /* Set up write pointers */
     398            1135 :     unsigned char *pabyPtr = *ppabyShape;
     399            1135 :     unsigned char *pabyPtrZ = NULL;
     400            1135 :     if ( b3d )
     401              60 :         pabyPtrZ = pabyPtr + nShpSize - nShpZSize;
     402                 : 
     403                 : /* -------------------------------------------------------------------- */
     404                 : /*      Write in the Shape type number now                              */
     405                 : /* -------------------------------------------------------------------- */
     406            1135 :     switch(nOGRType)
     407                 :     {
     408                 :         case wkbPoint:
     409                 :         {
     410            1020 :             nGType = b3d ? SHPT_POINTZ : SHPT_POINT;
     411            1020 :             break;
     412                 :         }
     413                 :         case wkbMultiPoint:
     414                 :         {
     415              20 :             nGType = b3d ? SHPT_MULTIPOINTZ : SHPT_MULTIPOINT;
     416              20 :             break;
     417                 :         }
     418                 :         case wkbLineString:
     419                 :         case wkbMultiLineString:
     420                 :         {
     421              40 :             nGType = b3d ? SHPT_ARCZ : SHPT_ARC;
     422              40 :             break;
     423                 :         }
     424                 :         case wkbPolygon:
     425                 :         case wkbMultiPolygon:
     426                 :         {
     427              55 :             nGType = b3d ? SHPT_POLYGONZ : SHPT_POLYGON;
     428              55 :             break;
     429                 :         }
     430                 :         default:
     431                 :         {
     432               0 :             return OGRERR_UNSUPPORTED_OPERATION;
     433                 :         }
     434                 :     }
     435                 :     /* Write in the type number and advance the pointer */
     436            1135 :     nGType = CPL_LSBWORD32( nGType );
     437            1135 :     memcpy( pabyPtr, &nGType, 4 );
     438            1135 :     pabyPtr += 4;
     439                 : 
     440                 : 
     441                 : /* -------------------------------------------------------------------- */
     442                 : /*      POINT and POINTZ                                                */
     443                 : /* -------------------------------------------------------------------- */
     444            1135 :     if ( nOGRType == wkbPoint )
     445                 :     {
     446            1020 :         OGRPoint *poPoint = (OGRPoint*)poGeom;
     447            1020 :         double x = poPoint->getX();
     448            1020 :         double y = poPoint->getY();
     449                 : 
     450                 :         /* Copy in the raw data. */
     451            1020 :         memcpy( pabyPtr, &x, 8 );
     452            1020 :         memcpy( pabyPtr+8, &y, 8 );
     453            1020 :         if( b3d )
     454                 :         {
     455              10 :             double z = poPoint->getZ();
     456              10 :             memcpy( pabyPtr+8+8, &z, 8 );
     457                 :         }
     458                 : 
     459                 :         /* Swap if needed. Shape doubles always LSB */
     460                 :         if( OGR_SWAP( wkbNDR ) )
     461                 :         {
     462                 :             CPL_SWAPDOUBLE( pabyPtr );
     463                 :             CPL_SWAPDOUBLE( pabyPtr+8 );
     464                 :             if( b3d )
     465                 :                 CPL_SWAPDOUBLE( pabyPtr+8+8 );
     466                 :         }
     467                 : 
     468            1020 :         return OGRERR_NONE;    
     469                 :     }
     470                 : 
     471                 : /* -------------------------------------------------------------------- */
     472                 : /*      All the non-POINT types require an envelope next                */
     473                 : /* -------------------------------------------------------------------- */
     474             115 :     OGREnvelope3D envelope;
     475             115 :     poGeom->getEnvelope(&envelope);
     476             115 :     memcpy( pabyPtr, &(envelope.MinX), 8 );
     477             115 :     memcpy( pabyPtr+8, &(envelope.MinY), 8 );
     478             115 :     memcpy( pabyPtr+8+8, &(envelope.MaxX), 8 );
     479             115 :     memcpy( pabyPtr+8+8+8, &(envelope.MaxY), 8 );
     480                 : 
     481                 :     /* Swap box if needed. Shape doubles are always LSB */
     482                 :     if( OGR_SWAP( wkbNDR ) )
     483                 :     {
     484                 :         for ( int i = 0; i < 4; i++ )
     485                 :             CPL_SWAPDOUBLE( pabyPtr + 8*i );
     486                 :     }
     487             115 :     pabyPtr += 32;
     488                 : 
     489                 :     /* Write in the Z bounds at the end of the XY buffer */
     490             115 :     if ( b3d )
     491                 :     {
     492              50 :         memcpy( pabyPtrZ, &(envelope.MinZ), 8 );
     493              50 :         memcpy( pabyPtrZ+8, &(envelope.MaxZ), 8 );
     494                 : 
     495                 :         /* Swap Z bounds if necessary */
     496                 :         if( OGR_SWAP( wkbNDR ) )
     497                 :         {
     498                 :             for ( int i = 0; i < 2; i++ )
     499                 :                 CPL_SWAPDOUBLE( pabyPtrZ + 8*i );
     500                 :         } 
     501              50 :         pabyPtrZ += 16;
     502                 :     }
     503                 : 
     504                 : /* -------------------------------------------------------------------- */
     505                 : /*      LINESTRING and LINESTRINGZ                                      */
     506                 : /* -------------------------------------------------------------------- */
     507             115 :     if ( nOGRType == wkbLineString )
     508                 :     {
     509              10 :         const OGRLineString *poLine = (OGRLineString*)poGeom;
     510                 : 
     511                 :         /* Write in the nparts (1) */
     512              10 :         GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
     513              10 :         memcpy( pabyPtr, &nPartsLsb, 4 );
     514              10 :         pabyPtr += 4;
     515                 : 
     516                 :         /* Write in the npoints */
     517              10 :         GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
     518              10 :         memcpy( pabyPtr, &nPointsLsb, 4 );
     519              10 :         pabyPtr += 4;
     520                 : 
     521                 :         /* Write in the part index (0) */
     522              10 :         GUInt32 nPartIndex = 0;
     523              10 :         memcpy( pabyPtr, &nPartIndex, 4 );
     524              10 :         pabyPtr += 4;
     525                 : 
     526                 :         /* Write in the point data */
     527              10 :         poLine->getPoints((OGRRawPoint*)pabyPtr, (double*)pabyPtrZ);
     528                 : 
     529                 :         /* Swap if necessary */
     530                 :         if( OGR_SWAP( wkbNDR ) )
     531                 :         {
     532                 :             for( GUInt32 k = 0; k < nPoints; k++ )
     533                 :             {
     534                 :                 CPL_SWAPDOUBLE( pabyPtr + 16*k );
     535                 :                 CPL_SWAPDOUBLE( pabyPtr + 16*k + 8 );
     536                 :                 if( b3d )
     537                 :                     CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
     538                 :             }
     539                 :         }
     540              10 :         return OGRERR_NONE;    
     541                 : 
     542                 :     }
     543                 : /* -------------------------------------------------------------------- */
     544                 : /*      POLYGON and POLYGONZ                                            */
     545                 : /* -------------------------------------------------------------------- */
     546             105 :     else if ( nOGRType == wkbPolygon )
     547                 :     {
     548              10 :         OGRPolygon *poPoly = (OGRPolygon*)poGeom;
     549                 : 
     550                 :         /* Write in the part count */
     551              10 :         GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
     552              10 :         memcpy( pabyPtr, &nPartsLsb, 4 );
     553              10 :         pabyPtr += 4;
     554                 : 
     555                 :         /* Write in the total point count */
     556              10 :         GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
     557              10 :         memcpy( pabyPtr, &nPointsLsb, 4 );
     558              10 :         pabyPtr += 4;
     559                 : 
     560                 : /* -------------------------------------------------------------------- */
     561                 : /*      Now we have to visit each ring and write an index number into   */
     562                 : /*      the parts list, and the coordinates into the points list.       */
     563                 : /*      to do it in one pass, we will use three write pointers.         */
     564                 : /*      pabyPtr writes the part indexes                                 */
     565                 : /*      pabyPoints writes the xy coordinates                            */
     566                 : /*      pabyPtrZ writes the z coordinates                               */
     567                 : /* -------------------------------------------------------------------- */
     568                 : 
     569                 :         /* Just past the partindex[nparts] array */
     570              10 :         unsigned char* pabyPoints = pabyPtr + 4*nParts; 
     571                 : 
     572              10 :         int nPointIndexCount = 0;
     573                 : 
     574              20 :         for( GUInt32 i = 0; i < nParts; i++ )
     575                 :         {
     576                 :             /* Check our Ring and condition it */
     577                 :             OGRLinearRing *poRing;
     578              10 :             if ( i == 0 ) 
     579                 :             {
     580              10 :                 poRing = poPoly->getExteriorRing();
     581                 :                 /* Outer ring must be clockwise */
     582              10 :                 if ( ! poRing->isClockwise() )
     583               0 :                     poRing->reverseWindingOrder();
     584                 :             }
     585                 :             else
     586                 :             {
     587               0 :                 poRing = poPoly->getInteriorRing(i-1);
     588                 :                 /* Inner rings should be anti-clockwise */
     589               0 :                 if ( poRing->isClockwise() )
     590               0 :                     poRing->reverseWindingOrder();
     591                 :             }
     592                 : 
     593              10 :             int nRingNumPoints = poRing->getNumPoints();
     594                 : 
     595                 :             /* Cannot write un-closed rings to shape */
     596              10 :             if( nRingNumPoints <= 2 || ! poRing->get_IsClosed() )
     597               0 :                 return OGRERR_FAILURE;
     598                 : 
     599                 :             /* Write in the part index */
     600              10 :             GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
     601              10 :             memcpy( pabyPtr, &nPartIndex, 4 );
     602                 : 
     603                 :             /* Write in the point data */
     604              10 :             poRing->getPoints((OGRRawPoint*)pabyPoints, (double*)pabyPtrZ);
     605                 : 
     606                 :             /* Swap if necessary */
     607                 :             if( OGR_SWAP( wkbNDR ) )
     608                 :             {
     609                 :                 for( int k = 0; k < nRingNumPoints; k++ )
     610                 :                 {
     611                 :                     CPL_SWAPDOUBLE( pabyPoints + 16*k );
     612                 :                     CPL_SWAPDOUBLE( pabyPoints + 16*k + 8 );
     613                 :                     if( b3d )
     614                 :                         CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
     615                 :                 }
     616                 :             }
     617                 : 
     618              10 :             nPointIndexCount += nRingNumPoints;
     619                 :             /* Advance the write pointers */
     620              10 :             pabyPtr += 4;
     621              10 :             pabyPoints += 16 * nRingNumPoints;
     622              10 :             if ( b3d )
     623               5 :                 pabyPtrZ += 8 * nRingNumPoints; 
     624                 :         }
     625                 : 
     626              10 :         return OGRERR_NONE;
     627                 : 
     628                 :     }
     629                 : /* -------------------------------------------------------------------- */
     630                 : /*      MULTIPOINT and MULTIPOINTZ                                      */
     631                 : /* -------------------------------------------------------------------- */
     632              95 :     else if ( nOGRType == wkbMultiPoint )
     633                 :     {
     634              20 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
     635                 : 
     636                 :         /* Write in the total point count */
     637              20 :         GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
     638              20 :         memcpy( pabyPtr, &nPointsLsb, 4 );
     639              20 :         pabyPtr += 4;
     640                 : 
     641                 : /* -------------------------------------------------------------------- */
     642                 : /*      Now we have to visit each point write it into the points list   */
     643                 : /*      We will use two write pointers.                                 */
     644                 : /*      pabyPtr writes the xy coordinates                               */
     645                 : /*      pabyPtrZ writes the z coordinates                               */
     646                 : /* -------------------------------------------------------------------- */
     647                 : 
     648              60 :         for( GUInt32 i = 0; i < nPoints; i++ )
     649                 :         {
     650              40 :             const OGRPoint *poPt = (OGRPoint*)(poMPoint->getGeometryRef(i));
     651                 : 
     652                 :             /* Skip empties */
     653              40 :             if ( poPt->IsEmpty() ) 
     654               0 :                 continue;
     655                 : 
     656                 :             /* Write the coordinates */
     657              40 :             double x = poPt->getX();
     658              40 :             double y = poPt->getY();
     659              40 :             memcpy(pabyPtr, &x, 8);
     660              40 :             memcpy(pabyPtr+8, &y, 8);
     661              40 :             if ( b3d )
     662                 :             {
     663              20 :                 double z = poPt->getZ();
     664              20 :                 memcpy(pabyPtrZ, &z, 8);
     665                 :             }
     666                 : 
     667                 :             /* Swap if necessary */
     668                 :             if( OGR_SWAP( wkbNDR ) )
     669                 :             {
     670                 :                 CPL_SWAPDOUBLE( pabyPtr );
     671                 :                 CPL_SWAPDOUBLE( pabyPtr + 8 );
     672                 :                 if( b3d )
     673                 :                     CPL_SWAPDOUBLE( pabyPtrZ );
     674                 :             }
     675                 : 
     676                 :             /* Advance the write pointers */
     677              40 :             pabyPtr += 16;
     678              40 :             if ( b3d )
     679              20 :                 pabyPtrZ += 8; 
     680                 :         }    
     681                 : 
     682              20 :         return OGRERR_NONE;
     683                 :     }
     684                 : 
     685                 : /* -------------------------------------------------------------------- */
     686                 : /*      MULTILINESTRING and MULTILINESTRINGZ                            */
     687                 : /* -------------------------------------------------------------------- */
     688              75 :     else if ( nOGRType == wkbMultiLineString )
     689                 :     {
     690              30 :         OGRMultiLineString *poMLine = (OGRMultiLineString*)poGeom;
     691                 : 
     692                 :         /* Write in the part count */
     693              30 :         GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
     694              30 :         memcpy( pabyPtr, &nPartsLsb, 4 );
     695              30 :         pabyPtr += 4;
     696                 : 
     697                 :         /* Write in the total point count */
     698              30 :         GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
     699              30 :         memcpy( pabyPtr, &nPointsLsb, 4 );
     700              30 :         pabyPtr += 4;
     701                 : 
     702                 :         /* Just past the partindex[nparts] array */
     703              30 :         unsigned char* pabyPoints = pabyPtr + 4*nParts; 
     704                 : 
     705              30 :         int nPointIndexCount = 0;
     706                 : 
     707              60 :         for( GUInt32 i = 0; i < nParts; i++ )
     708                 :         {
     709              30 :             const OGRLineString *poLine = (OGRLineString*)(poMLine->getGeometryRef(i));
     710                 : 
     711                 :             /* Skip empties */
     712              30 :             if ( poLine->IsEmpty() ) 
     713               0 :                 continue;
     714                 : 
     715              30 :             int nLineNumPoints = poLine->getNumPoints();
     716                 : 
     717                 :             /* Write in the part index */
     718              30 :             GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
     719              30 :             memcpy( pabyPtr, &nPartIndex, 4 );
     720                 : 
     721                 :             /* Write in the point data */
     722              30 :             poLine->getPoints((OGRRawPoint*)pabyPoints, (double*)pabyPtrZ);
     723                 : 
     724                 :             /* Swap if necessary */
     725                 :             if( OGR_SWAP( wkbNDR ) )
     726                 :             {
     727                 :                 for( int k = 0; k < nLineNumPoints; k++ )
     728                 :                 {
     729                 :                     CPL_SWAPDOUBLE( pabyPoints + 16*k );
     730                 :                     CPL_SWAPDOUBLE( pabyPoints + 16*k + 8 );
     731                 :                     if( b3d )
     732                 :                         CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
     733                 :                 }
     734                 :             }
     735                 : 
     736              30 :             nPointIndexCount += nLineNumPoints;
     737                 : 
     738                 :             /* Advance the write pointers */
     739              30 :             pabyPtr += 4;
     740              30 :             pabyPoints += 16 * nLineNumPoints;
     741              30 :             if ( b3d )
     742              15 :                 pabyPtrZ += 8 * nLineNumPoints; 
     743                 :         }
     744                 : 
     745              30 :         return OGRERR_NONE;      
     746                 : 
     747                 :     }
     748                 : /* -------------------------------------------------------------------- */
     749                 : /*      MULTIPOLYGON and MULTIPOLYGONZ                                  */
     750                 : /* -------------------------------------------------------------------- */
     751              45 :     else if ( nOGRType == wkbMultiPolygon )
     752                 :     {
     753              45 :         OGRMultiPolygon *poMPoly = (OGRMultiPolygon*)poGeom;
     754                 : 
     755                 :         /* Write in the part count */
     756              45 :         GUInt32 nPartsLsb = CPL_LSBWORD32( nParts );
     757              45 :         memcpy( pabyPtr, &nPartsLsb, 4 );
     758              45 :         pabyPtr += 4;
     759                 : 
     760                 :         /* Write in the total point count */
     761              45 :         GUInt32 nPointsLsb = CPL_LSBWORD32( nPoints );
     762              45 :         memcpy( pabyPtr, &nPointsLsb, 4 );
     763              45 :         pabyPtr += 4;
     764                 : 
     765                 : /* -------------------------------------------------------------------- */
     766                 : /*      Now we have to visit each ring and write an index number into   */
     767                 : /*      the parts list, and the coordinates into the points list.       */
     768                 : /*      to do it in one pass, we will use three write pointers.         */
     769                 : /*      pabyPtr writes the part indexes                                 */
     770                 : /*      pabyPoints writes the xy coordinates                            */
     771                 : /*      pabyPtrZ writes the z coordinates                               */
     772                 : /* -------------------------------------------------------------------- */
     773                 : 
     774                 :         /* Just past the partindex[nparts] array */
     775              45 :         unsigned char* pabyPoints = pabyPtr + 4*nParts; 
     776                 : 
     777              45 :         int nPointIndexCount = 0;
     778                 : 
     779              90 :         for( int i = 0; i < poMPoly->getNumGeometries(); i++ )
     780                 :         {
     781              45 :             OGRPolygon *poPoly = (OGRPolygon*)(poMPoly->getGeometryRef(i));
     782                 : 
     783                 :             /* Skip empties */
     784              45 :             if ( poPoly->IsEmpty() ) 
     785               0 :                 continue;
     786                 : 
     787              45 :             int nRings = 1 + poPoly->getNumInteriorRings();
     788                 : 
     789              90 :             for( int j = 0; j < nRings; j++ )
     790                 :             {
     791                 :                 /* Check our Ring and condition it */
     792                 :                 OGRLinearRing *poRing;
     793              45 :                 if ( j == 0 )
     794                 :                 {
     795              45 :                     poRing = poPoly->getExteriorRing();
     796                 :                     /* Outer ring must be clockwise */
     797              45 :                     if ( ! poRing->isClockwise() )
     798               0 :                         poRing->reverseWindingOrder();
     799                 :                 }
     800                 :                 else
     801                 :                 {
     802               0 :                     poRing = poPoly->getInteriorRing(j-1);
     803                 :                     /* Inner rings should be anti-clockwise */
     804               0 :                     if ( poRing->isClockwise() )
     805               0 :                         poRing->reverseWindingOrder();
     806                 :                 }
     807                 : 
     808              45 :                 int nRingNumPoints = poRing->getNumPoints();
     809                 : 
     810                 :                 /* Cannot write closed rings to shape */
     811              45 :                 if( nRingNumPoints <= 2 || ! poRing->get_IsClosed() )
     812               0 :                     return OGRERR_FAILURE;
     813                 : 
     814                 :                 /* Write in the part index */
     815              45 :                 GUInt32 nPartIndex = CPL_LSBWORD32( nPointIndexCount );
     816              45 :                 memcpy( pabyPtr, &nPartIndex, 4 );
     817                 : 
     818                 :                 /* Write in the point data */
     819              45 :                 poRing->getPoints((OGRRawPoint*)pabyPoints, (double*)pabyPtrZ);
     820                 : 
     821                 :                 /* Swap if necessary */
     822                 :                 if( OGR_SWAP( wkbNDR ) )
     823                 :                 {
     824                 :                     for( int k = 0; k < nRingNumPoints; k++ )
     825                 :                     {
     826                 :                         CPL_SWAPDOUBLE( pabyPoints + 16*k );
     827                 :                         CPL_SWAPDOUBLE( pabyPoints + 16*k + 8 );
     828                 :                         if( b3d )
     829                 :                             CPL_SWAPDOUBLE( pabyPtrZ + 8*k );
     830                 :                     }
     831                 :                 }
     832                 : 
     833              45 :                 nPointIndexCount += nRingNumPoints;
     834                 :                 /* Advance the write pointers */
     835              45 :                 pabyPtr += 4;
     836              45 :                 pabyPoints += 16 * nRingNumPoints;
     837              45 :                 if ( b3d )
     838              15 :                     pabyPtrZ += 8 * nRingNumPoints; 
     839                 :             }
     840                 :         }
     841                 : 
     842              45 :         return OGRERR_NONE;
     843                 : 
     844                 :     }
     845                 :     else
     846                 :     {
     847               0 :         return OGRERR_UNSUPPORTED_OPERATION;
     848                 :     }
     849                 : 
     850                 : }  
     851                 : 
     852                 : 
     853                 : /************************************************************************/
     854                 : /*                      OGRCreateFromShapeBin()                         */
     855                 : /*                                                                      */
     856                 : /*      Translate shapefile binary representation to an OGR             */
     857                 : /*      geometry.                                                       */
     858                 : /************************************************************************/
     859                 : 
     860          274306 : OGRErr OGRCreateFromShapeBin( GByte *pabyShape,
     861                 :                               OGRGeometry **ppoGeom,
     862                 :                               int nBytes )
     863                 : 
     864                 : {
     865          274306 :     *ppoGeom = NULL;
     866                 : 
     867          274306 :     if( nBytes < 4 )
     868                 :     {    
     869                 :         CPLError(CE_Failure, CPLE_AppDefined,
     870                 :                  "Shape buffer size (%d) too small",
     871               0 :                  nBytes);
     872               0 :         return OGRERR_FAILURE;
     873                 :     }
     874                 : 
     875                 : /* -------------------------------------------------------------------- */
     876                 : /*  Detect zlib compressed shapes and uncompress buffer if necessary    */
     877                 : /*  NOTE: this seems to be an undocumented feature, even in the         */
     878                 : /*  extended_shapefile_format.pdf found in the FileGDB API documentation*/
     879                 : /* -------------------------------------------------------------------- */
     880          548612 :     if( nBytes >= 14 &&
     881          274306 :         pabyShape[12] == 0x78 && pabyShape[13] == 0xDA /* zlib marker */)
     882                 :     {
     883                 :         GInt32 nUncompressedSize, nCompressedSize;
     884               0 :         memcpy( &nUncompressedSize, pabyShape + 4, 4 );
     885               0 :         memcpy( &nCompressedSize, pabyShape + 8, 4 );
     886                 :         CPL_LSBPTR32( &nUncompressedSize );
     887                 :         CPL_LSBPTR32( &nCompressedSize );
     888               0 :         if (nCompressedSize + 12 == nBytes &&
     889                 :             nUncompressedSize > 0)
     890                 :         {
     891               0 :             GByte* pabyUncompressedBuffer = (GByte*)VSIMalloc(nUncompressedSize);
     892               0 :             if (pabyUncompressedBuffer == NULL)
     893                 :             {
     894                 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
     895                 :                          "Cannot allocate %d bytes to uncompress zlib buffer",
     896               0 :                          nUncompressedSize);
     897               0 :                 return OGRERR_FAILURE;
     898                 :             }
     899                 : 
     900                 :             z_stream      stream;
     901               0 :             stream.zalloc = (alloc_func)0;
     902               0 :             stream.zfree = (free_func)0;
     903               0 :             stream.opaque = (voidpf)0;
     904               0 :             stream.next_in = pabyShape + 12;
     905               0 :             stream.next_out = pabyUncompressedBuffer;
     906               0 :             stream.avail_in = nCompressedSize;
     907               0 :             stream.avail_out = nUncompressedSize;
     908                 :             int err;
     909               0 :             if ( (err = inflateInit(&stream)) != Z_OK )
     910                 :             {
     911                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     912               0 :                          "inflateInit() failed : err code = %d", err);
     913               0 :                 VSIFree(pabyUncompressedBuffer);
     914               0 :                 return OGRERR_FAILURE;
     915                 :             }
     916               0 :             if ( (err = inflate(&stream, Z_NO_FLUSH)) != Z_STREAM_END )
     917                 :             {
     918                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     919               0 :                          "inflate() failed : err code = %d", err);
     920               0 :                 VSIFree(pabyUncompressedBuffer);
     921               0 :                 inflateEnd(&stream);
     922               0 :                 return OGRERR_FAILURE;
     923                 :             }
     924               0 :             if (stream.avail_in != 0)
     925                 :             {
     926                 :                 CPLDebug("OGR", "%d remaining in bytes after zlib uncompression",
     927               0 :                          stream.avail_in);
     928                 :             }
     929               0 :             if (stream.avail_out != 0)
     930                 :             {
     931                 :                 CPLDebug("OGR", "%d remaining out bytes after zlib uncompression",
     932               0 :                          stream.avail_out);
     933                 :             }
     934                 : 
     935               0 :             inflateEnd(&stream);
     936                 : 
     937                 :             OGRErr eErr = OGRCreateFromShapeBin(pabyUncompressedBuffer,
     938                 :                                                 ppoGeom,
     939               0 :                                                 nUncompressedSize - stream.avail_out);
     940                 : 
     941               0 :             VSIFree(pabyUncompressedBuffer);
     942                 : 
     943               0 :             return eErr;
     944                 :         }
     945                 :     }
     946                 : 
     947          274306 :     int nSHPType = pabyShape[0];
     948                 : 
     949                 : /* -------------------------------------------------------------------- */
     950                 : /*      Return a NULL geometry when SHPT_NULL is encountered.           */
     951                 : /*      Watch out, null return does not mean "bad data" it means        */
     952                 : /*      "no geometry here". Watch the OGRErr for the error status       */
     953                 : /* -------------------------------------------------------------------- */
     954          274306 :     if ( nSHPType == SHPT_NULL )
     955                 :     {
     956               0 :       *ppoGeom = NULL;
     957               0 :       return OGRERR_NONE;
     958                 :     }
     959                 : 
     960                 : //    CPLDebug( "PGeo",
     961                 : //              "Shape type read from PGeo data is nSHPType = %d",
     962                 : //              nSHPType );
     963                 : 
     964                 : /* -------------------------------------------------------------------- */
     965                 : /*      TODO: These types include additional attributes including       */
     966                 : /*      non-linear segments and such. They should be handled.           */
     967                 : /*      This is documented in the extended_shapefile_format.pdf         */
     968                 : /*      from the FileGDB API                                            */
     969                 : /* -------------------------------------------------------------------- */
     970          274306 :     switch( nSHPType )
     971                 :     {
     972                 :       case SHPT_GENERALPOLYLINE:
     973               0 :         nSHPType = SHPT_ARC;
     974               0 :         break;
     975                 :       case SHPT_GENERALPOLYGON:
     976               0 :         nSHPType = SHPT_POLYGON;
     977               0 :         break;
     978                 :       case SHPT_GENERALPOINT:
     979               0 :         nSHPType = SHPT_POINT;
     980               0 :         break;
     981                 :       case SHPT_GENERALMULTIPOINT:
     982               0 :         nSHPType = SHPT_MULTIPOINT;
     983               0 :         break;
     984                 :       case SHPT_GENERALMULTIPATCH:
     985               0 :         nSHPType = SHPT_MULTIPATCH;
     986                 :     }
     987                 : 
     988                 : /* ==================================================================== */
     989                 : /*  Extract vertices for a Polygon or Arc.              */
     990                 : /* ==================================================================== */
     991          274306 :     if(    nSHPType == SHPT_ARC
     992                 :         || nSHPType == SHPT_ARCZ
     993                 :         || nSHPType == SHPT_ARCM
     994                 :         || nSHPType == SHPT_ARCZM
     995                 :         || nSHPType == SHPT_POLYGON
     996                 :         || nSHPType == SHPT_POLYGONZ
     997                 :         || nSHPType == SHPT_POLYGONM
     998                 :         || nSHPType == SHPT_POLYGONZM
     999                 :         || nSHPType == SHPT_MULTIPATCH
    1000                 :         || nSHPType == SHPT_MULTIPATCHM)
    1001                 :     {
    1002                 :         GInt32         nPoints, nParts;
    1003                 :         int            i, nOffset;
    1004                 :         GInt32         *panPartStart;
    1005          273791 :         GInt32         *panPartType = NULL;
    1006                 : 
    1007          273791 :         if (nBytes < 44)
    1008                 :         {
    1009                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1010               0 :                      "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
    1011               0 :             return OGRERR_FAILURE;
    1012                 :         }
    1013                 : 
    1014                 : /* -------------------------------------------------------------------- */
    1015                 : /*      Extract part/point count, and build vertex and part arrays      */
    1016                 : /*      to proper size.                                                 */
    1017                 : /* -------------------------------------------------------------------- */
    1018          273791 :         memcpy( &nPoints, pabyShape + 40, 4 );
    1019          273791 :         memcpy( &nParts, pabyShape + 36, 4 );
    1020                 : 
    1021                 :         CPL_LSBPTR32( &nPoints );
    1022                 :         CPL_LSBPTR32( &nParts );
    1023                 : 
    1024          273791 :         if (nPoints < 0 || nParts < 0 ||
    1025                 :             nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
    1026                 :         {
    1027                 :             CPLError(CE_Failure, CPLE_AppDefined, "Corrupted Shape : nPoints=%d, nParts=%d.",
    1028               0 :                      nPoints, nParts);
    1029               0 :             return OGRERR_FAILURE;
    1030                 :         }
    1031                 : 
    1032                 :         int bHasZ = (  nSHPType == SHPT_POLYGONZ
    1033                 :                     || nSHPType == SHPT_POLYGONZM
    1034                 :                     || nSHPType == SHPT_ARCZ
    1035                 :                     || nSHPType == SHPT_ARCZM
    1036                 :                     || nSHPType == SHPT_MULTIPATCH
    1037          273791 :                     || nSHPType == SHPT_MULTIPATCHM );
    1038                 : 
    1039          273791 :         int bIsMultiPatch = ( nSHPType == SHPT_MULTIPATCH || nSHPType == SHPT_MULTIPATCHM );
    1040                 : 
    1041                 :         /* With the previous checks on nPoints and nParts, */
    1042                 :         /* we should not overflow here and after */
    1043                 :         /* since 50 M * (16 + 8 + 8) = 1 600 MB */
    1044          273791 :         int nRequiredSize = 44 + 4 * nParts + 16 * nPoints;
    1045          273791 :         if ( bHasZ )
    1046                 :         {
    1047          273457 :             nRequiredSize += 16 + 8 * nPoints;
    1048                 :         }
    1049          273791 :         if( bIsMultiPatch )
    1050                 :         {
    1051               0 :             nRequiredSize += 4 * nParts;
    1052                 :         }
    1053          273791 :         if (nRequiredSize > nBytes)
    1054                 :         {
    1055                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1056                 :                      "Corrupted Shape : nPoints=%d, nParts=%d, nBytes=%d, nSHPType=%d",
    1057               0 :                      nPoints, nParts, nBytes, nSHPType);
    1058               0 :             return OGRERR_FAILURE;
    1059                 :         }
    1060                 : 
    1061          273791 :         panPartStart = (GInt32 *) VSICalloc(nParts,sizeof(GInt32));
    1062          273791 :         if (panPartStart == NULL)
    1063                 :         {
    1064                 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1065               0 :                      "Not enough memory for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
    1066               0 :             return OGRERR_FAILURE;
    1067                 :         }
    1068                 : 
    1069                 : /* -------------------------------------------------------------------- */
    1070                 : /*      Copy out the part array from the record.                        */
    1071                 : /* -------------------------------------------------------------------- */
    1072          273791 :         memcpy( panPartStart, pabyShape + 44, 4 * nParts );
    1073          547582 :         for( i = 0; i < nParts; i++ )
    1074                 :         {
    1075                 :             CPL_LSBPTR32( panPartStart + i );
    1076                 : 
    1077                 :             /* We check that the offset is inside the vertex array */
    1078          547582 :             if (panPartStart[i] < 0 ||
    1079          273791 :                 panPartStart[i] >= nPoints)
    1080                 :             {
    1081                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1082                 :                         "Corrupted Shape : panPartStart[%d] = %d, nPoints = %d",
    1083               0 :                         i, panPartStart[i], nPoints);
    1084               0 :                 CPLFree(panPartStart);
    1085               0 :                 return OGRERR_FAILURE;
    1086                 :             }
    1087          273791 :             if (i > 0 && panPartStart[i] <= panPartStart[i-1])
    1088                 :             {
    1089                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1090                 :                         "Corrupted Shape : panPartStart[%d] = %d, panPartStart[%d] = %d",
    1091               0 :                         i, panPartStart[i], i - 1, panPartStart[i - 1]);
    1092               0 :                 CPLFree(panPartStart);
    1093               0 :                 return OGRERR_FAILURE;
    1094                 :             }
    1095                 :         }
    1096                 : 
    1097          273791 :         nOffset = 44 + 4*nParts;
    1098                 : 
    1099                 : /* -------------------------------------------------------------------- */
    1100                 : /*      If this is a multipatch, we will also have parts types.         */
    1101                 : /* -------------------------------------------------------------------- */
    1102          273791 :         if( bIsMultiPatch )
    1103                 :         {
    1104               0 :             panPartType = (GInt32 *) VSICalloc(nParts,sizeof(GInt32));
    1105               0 :             if (panPartType == NULL)
    1106                 :             {
    1107                 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    1108               0 :                         "Not enough memory for panPartType for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
    1109               0 :                 CPLFree(panPartStart);
    1110               0 :                 return OGRERR_FAILURE;
    1111                 :             }
    1112                 : 
    1113               0 :             memcpy( panPartType, pabyShape + nOffset, 4*nParts );
    1114               0 :             for( i = 0; i < nParts; i++ )
    1115                 :             {
    1116                 :                 CPL_LSBPTR32( panPartType + i );
    1117                 :             }
    1118               0 :             nOffset += 4*nParts;
    1119                 :         }
    1120                 : 
    1121                 : /* -------------------------------------------------------------------- */
    1122                 : /*      Copy out the vertices from the record.                          */
    1123                 : /* -------------------------------------------------------------------- */
    1124          273791 :         double *padfX = (double *) VSIMalloc(sizeof(double)*nPoints);
    1125          273791 :         double *padfY = (double *) VSIMalloc(sizeof(double)*nPoints);
    1126          273791 :         double *padfZ = (double *) VSICalloc(sizeof(double),nPoints);
    1127          273791 :         if (padfX == NULL || padfY == NULL || padfZ == NULL)
    1128                 :         {
    1129               0 :             CPLFree( panPartStart );
    1130               0 :             CPLFree( panPartType );
    1131               0 :             CPLFree( padfX );
    1132               0 :             CPLFree( padfY );
    1133               0 :             CPLFree( padfZ );
    1134                 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1135               0 :                      "Not enough memory for shape (nPoints=%d, nParts=%d)", nPoints, nParts);
    1136               0 :             return OGRERR_FAILURE;
    1137                 :         }
    1138                 : 
    1139         1324420 :         for( i = 0; i < nPoints; i++ )
    1140                 :         {
    1141         1050629 :             memcpy(padfX + i, pabyShape + nOffset + i * 16, 8 );
    1142         1050629 :             memcpy(padfY + i, pabyShape + nOffset + i * 16 + 8, 8 );
    1143                 :             CPL_LSBPTR64( padfX + i );
    1144                 :             CPL_LSBPTR64( padfY + i );
    1145                 :         }
    1146                 : 
    1147          273791 :         nOffset += 16*nPoints;
    1148                 : 
    1149                 : /* -------------------------------------------------------------------- */
    1150                 : /*      If we have a Z coordinate, collect that now.                    */
    1151                 : /* -------------------------------------------------------------------- */
    1152          273791 :         if( bHasZ )
    1153                 :         {
    1154         1320833 :             for( i = 0; i < nPoints; i++ )
    1155                 :             {
    1156         1047376 :                 memcpy( padfZ + i, pabyShape + nOffset + 16 + i*8, 8 );
    1157                 :                 CPL_LSBPTR64( padfZ + i );
    1158                 :             }
    1159                 : 
    1160          273457 :             nOffset += 16 + 8*nPoints;
    1161                 :         }
    1162                 : 
    1163                 : /* -------------------------------------------------------------------- */
    1164                 : /*      Build corresponding OGR objects.                                */
    1165                 : /* -------------------------------------------------------------------- */
    1166          547163 :         if(    nSHPType == SHPT_ARC
    1167                 :             || nSHPType == SHPT_ARCZ
    1168                 :             || nSHPType == SHPT_ARCM
    1169                 :             || nSHPType == SHPT_ARCZM )
    1170                 :         {
    1171                 : /* -------------------------------------------------------------------- */
    1172                 : /*      Arc - As LineString                                             */
    1173                 : /* -------------------------------------------------------------------- */
    1174          273372 :             if( nParts == 1 )
    1175                 :             {
    1176          273372 :                 OGRLineString *poLine = new OGRLineString();
    1177          273372 :                 *ppoGeom = poLine;
    1178                 : 
    1179          273372 :                 poLine->setPoints( nPoints, padfX, padfY, padfZ );
    1180                 :             }
    1181                 : 
    1182                 : /* -------------------------------------------------------------------- */
    1183                 : /*      Arc - As MultiLineString                                        */
    1184                 : /* -------------------------------------------------------------------- */
    1185                 :             else
    1186                 :             {
    1187               0 :                 OGRMultiLineString *poMulti = new OGRMultiLineString;
    1188               0 :                 *ppoGeom = poMulti;
    1189                 : 
    1190               0 :                 for( i = 0; i < nParts; i++ )
    1191                 :                 {
    1192               0 :                     OGRLineString *poLine = new OGRLineString;
    1193                 :                     int nVerticesInThisPart;
    1194                 : 
    1195               0 :                     if( i == nParts-1 )
    1196               0 :                         nVerticesInThisPart = nPoints - panPartStart[i];
    1197                 :                     else
    1198                 :                         nVerticesInThisPart =
    1199               0 :                             panPartStart[i+1] - panPartStart[i];
    1200                 : 
    1201                 :                     poLine->setPoints( nVerticesInThisPart,
    1202               0 :                                        padfX + panPartStart[i],
    1203               0 :                                        padfY + panPartStart[i],
    1204               0 :                                        padfZ + panPartStart[i] );
    1205                 : 
    1206               0 :                     poMulti->addGeometryDirectly( poLine );
    1207                 :                 }
    1208                 :             }
    1209                 :         } /* ARC */
    1210                 : 
    1211                 : /* -------------------------------------------------------------------- */
    1212                 : /*      Polygon                                                         */
    1213                 : /* -------------------------------------------------------------------- */
    1214             838 :         else if(    nSHPType == SHPT_POLYGON
    1215                 :                  || nSHPType == SHPT_POLYGONZ
    1216                 :                  || nSHPType == SHPT_POLYGONM
    1217                 :                  || nSHPType == SHPT_POLYGONZM )
    1218                 :         {
    1219             419 :             if (nParts != 0)
    1220                 :             {
    1221             419 :                 if (nParts == 1)
    1222                 :                 {
    1223             419 :                     OGRPolygon *poOGRPoly = new OGRPolygon;
    1224             419 :                     *ppoGeom = poOGRPoly;
    1225             838 :                     OGRLinearRing *poRing = new OGRLinearRing;
    1226             419 :                     int nVerticesInThisPart = nPoints - panPartStart[0];
    1227                 : 
    1228                 :                     poRing->setPoints( nVerticesInThisPart,
    1229             419 :                                        padfX + panPartStart[0],
    1230             419 :                                        padfY + panPartStart[0],
    1231            1257 :                                        padfZ + panPartStart[0] );
    1232                 : 
    1233             419 :                     poOGRPoly->addRingDirectly( poRing );
    1234                 :                 }
    1235                 :                 else
    1236                 :                 {
    1237               0 :                     OGRGeometry *poOGR = NULL;
    1238               0 :                     OGRPolygon** tabPolygons = new OGRPolygon*[nParts];
    1239                 : 
    1240               0 :                     for( i = 0; i < nParts; i++ )
    1241                 :                     {
    1242               0 :                         tabPolygons[i] = new OGRPolygon();
    1243               0 :                         OGRLinearRing *poRing = new OGRLinearRing;
    1244                 :                         int nVerticesInThisPart;
    1245                 : 
    1246               0 :                         if( i == nParts-1 )
    1247               0 :                             nVerticesInThisPart = nPoints - panPartStart[i];
    1248                 :                         else
    1249                 :                             nVerticesInThisPart =
    1250               0 :                                 panPartStart[i+1] - panPartStart[i];
    1251                 : 
    1252                 :                         poRing->setPoints( nVerticesInThisPart,
    1253               0 :                                            padfX + panPartStart[i],
    1254               0 :                                            padfY + panPartStart[i],
    1255               0 :                                            padfZ + panPartStart[i] );
    1256               0 :                         tabPolygons[i]->addRingDirectly(poRing);
    1257                 :                     }
    1258                 : 
    1259                 :                     int isValidGeometry;
    1260               0 :                     const char* papszOptions[] = { "METHOD=ONLY_CCW", NULL };
    1261                 :                     poOGR = OGRGeometryFactory::organizePolygons(
    1262               0 :                         (OGRGeometry**)tabPolygons, nParts, &isValidGeometry, papszOptions );
    1263                 : 
    1264               0 :                     if (!isValidGeometry)
    1265                 :                     {
    1266                 :                         CPLError(CE_Warning, CPLE_AppDefined,
    1267                 :                                  "Geometry of polygon cannot be translated to Simple Geometry. "
    1268               0 :                                  "All polygons will be contained in a multipolygon.\n");
    1269                 :                     }
    1270                 : 
    1271               0 :                     *ppoGeom = poOGR;
    1272               0 :                     delete[] tabPolygons;
    1273                 :                 }
    1274                 :             }
    1275                 :         } /* polygon */
    1276                 : 
    1277                 : /* -------------------------------------------------------------------- */
    1278                 : /*      Multipatch                                                      */
    1279                 : /* -------------------------------------------------------------------- */
    1280               0 :         else if( bIsMultiPatch )
    1281                 :         {
    1282                 :             *ppoGeom = OGRCreateFromMultiPatch( nParts,
    1283                 :                                                 panPartStart,
    1284                 :                                                 panPartType,
    1285                 :                                                 nPoints,
    1286                 :                                                 padfX,
    1287                 :                                                 padfY,
    1288               0 :                                                 padfZ );
    1289                 :         }
    1290                 : 
    1291          273791 :         CPLFree( panPartStart );
    1292          273791 :         CPLFree( panPartType );
    1293          273791 :         CPLFree( padfX );
    1294          273791 :         CPLFree( padfY );
    1295          273791 :         CPLFree( padfZ );
    1296                 : 
    1297          273791 :         if (*ppoGeom != NULL)
    1298          273791 :             (*ppoGeom)->setCoordinateDimension( bHasZ ? 3 : 2 );
    1299                 : 
    1300          273791 :         return OGRERR_NONE;
    1301                 :     }
    1302                 : 
    1303                 : /* ==================================================================== */
    1304                 : /*  Extract vertices for a MultiPoint.                  */
    1305                 : /* ==================================================================== */
    1306             515 :     else if(    nSHPType == SHPT_MULTIPOINT
    1307                 :              || nSHPType == SHPT_MULTIPOINTM
    1308                 :              || nSHPType == SHPT_MULTIPOINTZ
    1309                 :              || nSHPType == SHPT_MULTIPOINTZM )
    1310                 :     {
    1311                 :       GInt32 nPoints;
    1312                 :       GInt32 nOffsetZ;
    1313                 :       int i;
    1314                 : 
    1315                 :       int bHasZ = (  nSHPType == SHPT_MULTIPOINTZ
    1316             116 :                   || nSHPType == SHPT_MULTIPOINTZM );
    1317                 : 
    1318                 :                 
    1319             116 :       memcpy( &nPoints, pabyShape + 36, 4 );
    1320                 :       CPL_LSBPTR32( &nPoints );
    1321                 : 
    1322             116 :       if (nPoints < 0 || nPoints > 50 * 1000 * 1000 )
    1323                 :       {
    1324                 :           CPLError(CE_Failure, CPLE_AppDefined, "Corrupted Shape : nPoints=%d.",
    1325               0 :                    nPoints);
    1326               0 :           return OGRERR_FAILURE;
    1327                 :       }
    1328                 : 
    1329             116 :       nOffsetZ = 40 + 2*8*nPoints + 2*8;
    1330                 :     
    1331             116 :       OGRMultiPoint *poMultiPt = new OGRMultiPoint;
    1332             116 :       *ppoGeom = poMultiPt;
    1333                 : 
    1334             348 :       for( i = 0; i < nPoints; i++ )
    1335                 :       {
    1336                 :           double x, y, z;
    1337             232 :           OGRPoint *poPt = new OGRPoint;
    1338                 :         
    1339                 :           /* Copy X */
    1340             232 :           memcpy(&x, pabyShape + 40 + i*16, 8);
    1341                 :           CPL_LSBPTR64(&x);
    1342             232 :           poPt->setX(x);
    1343                 :         
    1344                 :           /* Copy Y */
    1345             232 :           memcpy(&y, pabyShape + 40 + i*16 + 8, 8);
    1346                 :           CPL_LSBPTR64(&y);
    1347             232 :           poPt->setY(y);
    1348                 :         
    1349                 :           /* Copy Z */
    1350             232 :           if ( bHasZ )
    1351                 :           {
    1352             116 :             memcpy(&z, pabyShape + nOffsetZ + i*8, 8);
    1353                 :             CPL_LSBPTR64(&z);
    1354             116 :             poPt->setZ(z);
    1355                 :           }
    1356                 :         
    1357             232 :           poMultiPt->addGeometryDirectly( poPt );
    1358                 :       }
    1359                 :       
    1360             116 :       poMultiPt->setCoordinateDimension( bHasZ ? 3 : 2 );
    1361                 :       
    1362             116 :       return OGRERR_NONE;
    1363                 :     }
    1364                 : 
    1365                 : /* ==================================================================== */
    1366                 : /*      Extract vertices for a point.                                   */
    1367                 : /* ==================================================================== */
    1368             399 :     else if(    nSHPType == SHPT_POINT
    1369                 :              || nSHPType == SHPT_POINTM
    1370                 :              || nSHPType == SHPT_POINTZ
    1371                 :              || nSHPType == SHPT_POINTZM )
    1372                 :     {
    1373                 :         int nOffset;
    1374             399 :         double  dfX, dfY, dfZ = 0;
    1375                 : 
    1376             399 :         int bHasZ = (nSHPType == SHPT_POINTZ || nSHPType == SHPT_POINTZM);
    1377                 : 
    1378             399 :         if (nBytes < 4 + 8 + 8 + ((bHasZ) ? 8 : 0))
    1379                 :         {
    1380                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1381               0 :                      "Corrupted Shape : nBytes=%d, nSHPType=%d", nBytes, nSHPType);
    1382               0 :             return OGRERR_FAILURE;
    1383                 :         }
    1384                 : 
    1385             399 :         memcpy( &dfX, pabyShape + 4, 8 );
    1386             399 :         memcpy( &dfY, pabyShape + 4 + 8, 8 );
    1387                 : 
    1388                 :         CPL_LSBPTR64( &dfX );
    1389                 :         CPL_LSBPTR64( &dfY );
    1390             399 :         nOffset = 20 + 8;
    1391                 : 
    1392             399 :         if( bHasZ )
    1393                 :         {
    1394             335 :             memcpy( &dfZ, pabyShape + 4 + 16, 8 );
    1395                 :             CPL_LSBPTR64( &dfZ );
    1396                 :         }
    1397                 : 
    1398             399 :         *ppoGeom = new OGRPoint( dfX, dfY, dfZ );
    1399             734 :         (*ppoGeom)->setCoordinateDimension( bHasZ ? 3 : 2 );
    1400                 : 
    1401             399 :         return OGRERR_NONE;
    1402                 :     }
    1403                 : 
    1404                 :     CPLError(CE_Failure, CPLE_AppDefined,
    1405                 :              "Unsupported geometry type: %d", 
    1406               0 :               nSHPType );
    1407                 : 
    1408               0 :     return OGRERR_FAILURE;
    1409                 : }

Generated by: LCOV version 1.7