LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/osm - osm_parser.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 974 711 73.0 %
Date: 2012-12-26 Functions: 28 22 78.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: osm_parser.cpp 25191 2012-10-29 22:47:59Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       6                 :  * Purpose:  OSM XML and OSM PBF parser
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2012, Even Rouault, <even dot rouault at mines dash paris dot org>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "osm_parser.h"
      31                 : #include "gpb.h"
      32                 : 
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_string.h"
      35                 : #include "cpl_vsi.h"
      36                 : 
      37                 : #include <zlib.h>
      38                 : 
      39                 : #ifdef HAVE_EXPAT
      40                 : #include "ogr_expat.h"
      41                 : #endif
      42                 : 
      43                 : /* The buffer that are passed to GPB decoding are extended with 0's */
      44                 : /* to be sure that we will be able to read a single 64bit value without */
      45                 : /* doing checks for each byte */
      46                 : #define EXTRA_BYTES     1
      47                 : 
      48                 : #define XML_BUFSIZE 64*1024
      49                 : 
      50                 : CPL_CVSID("$Id: osm_parser.cpp 25191 2012-10-29 22:47:59Z rouault $");
      51                 : 
      52                 : /************************************************************************/
      53                 : /*                            INIT_INFO()                               */
      54                 : /************************************************************************/
      55                 : 
      56                 : #define INIT_INFO(sInfo) \
      57                 :     sInfo.ts.nTimeStamp = 0; \
      58                 :     sInfo.nChangeset = 0; \
      59                 :     sInfo.nVersion = 0; \
      60                 :     sInfo.nUID = 0; \
      61                 :     sInfo.bTimeStampIsStr = 0; \
      62                 :     sInfo.pszUserSID = NULL;
      63                 : /*    \    sInfo.nVisible = 1; */
      64                 : 
      65                 : 
      66                 : /************************************************************************/
      67                 : /*                            _OSMContext                               */
      68                 : /************************************************************************/
      69                 : 
      70                 : struct _OSMContext
      71                 : {
      72                 :     char          *pszStrBuf;
      73                 :     int           *panStrOff;
      74                 :     unsigned int   nStrCount;
      75                 :     unsigned int   nStrAllocated;
      76                 : 
      77                 :     OSMNode       *pasNodes;
      78                 :     unsigned int   nNodesAllocated;
      79                 : 
      80                 :     OSMTag        *pasTags;
      81                 :     unsigned int   nTagsAllocated;
      82                 : 
      83                 :     OSMMember     *pasMembers;
      84                 :     unsigned int   nMembersAllocated;
      85                 : 
      86                 :     GIntBig       *panNodeRefs;
      87                 :     unsigned int   nNodeRefsAllocated;
      88                 : 
      89                 :     int            nGranularity;
      90                 :     int            nDateGranularity;
      91                 :     GIntBig        nLatOffset;
      92                 :     GIntBig        nLonOffset;
      93                 : 
      94                 :     unsigned int   nBlobSizeAllocated;
      95                 :     GByte         *pabyBlob;
      96                 : 
      97                 :     GByte         *pabyUncompressed;
      98                 :     unsigned int   nUncompressedAllocated;
      99                 : 
     100                 : #ifdef HAVE_EXPAT
     101                 :     XML_Parser     hXMLParser;
     102                 :     int            bEOF;
     103                 :     int            bStopParsing;
     104                 :     int            bHasFoundFeature;
     105                 :     int            nWithoutEventCounter;
     106                 :     int            nDataHandlerCounter;
     107                 : 
     108                 :     unsigned int   nStrLength;
     109                 :     unsigned int   nTags;
     110                 : 
     111                 :     int            bInNode;
     112                 :     int            bInWay;
     113                 :     int            bInRelation;
     114                 : 
     115                 :     OSMWay         sWay;
     116                 :     OSMRelation    sRelation;
     117                 : 
     118                 :     int            bTryToFetchBounds;
     119                 : #endif
     120                 : 
     121                 :     VSILFILE      *fp;
     122                 : 
     123                 :     int            bPBF;
     124                 : 
     125                 :     double         dfLeft;
     126                 :     double         dfRight;
     127                 :     double         dfTop;
     128                 :     double         dfBottom;
     129                 : 
     130                 :     GUIntBig        nBytesRead;
     131                 : 
     132                 :     NotifyNodesFunc     pfnNotifyNodes;
     133                 :     NotifyWayFunc       pfnNotifyWay;
     134                 :     NotifyRelationFunc  pfnNotifyRelation;
     135                 :     NotifyBoundsFunc    pfnNotifyBounds;
     136                 :     void               *user_data;
     137                 : };
     138                 : 
     139                 : /************************************************************************/
     140                 : /*                          ReadBlobHeader()                            */
     141                 : /************************************************************************/
     142                 : 
     143                 : #define BLOBHEADER_IDX_TYPE         1
     144                 : #define BLOBHEADER_IDX_INDEXDATA    2
     145                 : #define BLOBHEADER_IDX_DATASIZE     3
     146                 : 
     147                 : typedef enum
     148                 : {
     149                 :     BLOB_UNKNOW,
     150                 :     BLOB_OSMHEADER,
     151                 :     BLOB_OSMDATA
     152                 : } BlobType;
     153                 : 
     154                 : static
     155              38 : int ReadBlobHeader(GByte* pabyData, GByte* pabyDataLimit,
     156                 :                    unsigned int* pnBlobSize, BlobType* peBlobType)
     157                 : {
     158              38 :     *pnBlobSize = 0;
     159              38 :     *peBlobType = BLOB_UNKNOW;
     160                 : 
     161             152 :     while(pabyData < pabyDataLimit)
     162                 :     {
     163                 :         int nKey;
     164              76 :         READ_FIELD_KEY(nKey);
     165                 : 
     166              76 :         if (nKey == MAKE_KEY(BLOBHEADER_IDX_TYPE, WT_DATA))
     167                 :         {
     168                 :             unsigned int nDataLength;
     169              38 :             READ_SIZE(pabyData, pabyDataLimit, nDataLength);
     170                 : 
     171              57 :             if (nDataLength == 7 && memcmp(pabyData, "OSMData", 7) == 0)
     172                 :             {
     173              19 :                 *peBlobType = BLOB_OSMDATA;
     174                 :             }
     175              19 :             else if (nDataLength == 9 && memcmp(pabyData, "OSMHeader", 9) == 0)
     176                 :             {
     177              19 :                 *peBlobType = BLOB_OSMHEADER;
     178                 :             }
     179                 : 
     180              38 :             pabyData += nDataLength;
     181                 :         }
     182              38 :         else if (nKey == MAKE_KEY(BLOBHEADER_IDX_INDEXDATA, WT_DATA))
     183                 :         {
     184                 :             /* Ignored if found */
     185                 :             unsigned int nDataLength;
     186               0 :             READ_SIZE(pabyData, pabyDataLimit, nDataLength);
     187               0 :             pabyData += nDataLength;
     188                 :         }
     189              38 :         else if (nKey == MAKE_KEY(BLOBHEADER_IDX_DATASIZE, WT_VARINT))
     190                 :         {
     191                 :             unsigned int nBlobSize;
     192              38 :             READ_VARUINT32(pabyData, pabyDataLimit, nBlobSize);
     193                 :             /* printf("nBlobSize = %d\n", nBlobSize); */
     194              38 :             *pnBlobSize = nBlobSize;
     195                 :         }
     196                 :         else
     197                 :         {
     198               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     199                 :         }
     200                 :     }
     201                 : 
     202              38 :     return pabyData == pabyDataLimit;
     203                 : 
     204                 : end_error:
     205               0 :     return FALSE;
     206                 : }
     207                 : 
     208                 : /************************************************************************/
     209                 : /*                          ReadHeaderBBox()                            */
     210                 : /************************************************************************/
     211                 : 
     212                 : #define HEADERBBOX_IDX_LEFT     1
     213                 : #define HEADERBBOX_IDX_RIGHT    2
     214                 : #define HEADERBBOX_IDX_TOP      3
     215                 : #define HEADERBBOX_IDX_BOTTOM   4
     216                 : 
     217                 : static
     218               0 : int ReadHeaderBBox(GByte* pabyData, GByte* pabyDataLimit,
     219                 :                    OSMContext* psCtxt)
     220                 : {
     221               0 :     psCtxt->dfLeft = 0.0;
     222               0 :     psCtxt->dfRight = 0.0;
     223               0 :     psCtxt->dfTop = 0.0;
     224               0 :     psCtxt->dfBottom = 0.0;
     225                 : 
     226                 :     /* printf(">ReadHeaderBBox\n"); */
     227                 : 
     228               0 :     while(pabyData < pabyDataLimit)
     229                 :     {
     230                 :         int nKey;
     231               0 :         READ_FIELD_KEY(nKey);
     232                 : 
     233               0 :         if (nKey == MAKE_KEY(HEADERBBOX_IDX_LEFT, WT_VARINT))
     234                 :         {
     235                 :             GIntBig nLeft;
     236               0 :             READ_VARSINT64(pabyData, pabyDataLimit, nLeft);
     237               0 :             psCtxt->dfLeft = nLeft * 1e-9;
     238                 :         }
     239               0 :         else if (nKey == MAKE_KEY(HEADERBBOX_IDX_RIGHT, WT_VARINT))
     240                 :         {
     241                 :             GIntBig nRight;
     242               0 :             READ_VARSINT64(pabyData, pabyDataLimit, nRight);
     243               0 :             psCtxt->dfRight = nRight * 1e-9;
     244                 :         }
     245               0 :         else if (nKey == MAKE_KEY(HEADERBBOX_IDX_TOP, WT_VARINT))
     246                 :         {
     247                 :             GIntBig nTop;
     248               0 :             READ_VARSINT64(pabyData, pabyDataLimit, nTop);
     249               0 :             psCtxt->dfTop = nTop * 1e-9;
     250                 :         }
     251               0 :         else if (nKey == MAKE_KEY(HEADERBBOX_IDX_BOTTOM, WT_VARINT))
     252                 :         {
     253                 :             GIntBig nBottom;
     254               0 :             READ_VARSINT64(pabyData, pabyDataLimit, nBottom);
     255               0 :             psCtxt->dfBottom = nBottom * 1e-9;
     256                 :         }
     257                 :         else
     258                 :         {
     259               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     260                 :         }
     261                 :     }
     262                 : 
     263                 :     psCtxt->pfnNotifyBounds(psCtxt->dfLeft, psCtxt->dfBottom,
     264                 :                             psCtxt->dfRight, psCtxt->dfTop,
     265               0 :                             psCtxt, psCtxt->user_data);
     266                 : 
     267                 :     /* printf("<ReadHeaderBBox\n"); */
     268               0 :     return pabyData == pabyDataLimit;
     269                 : 
     270                 : end_error:
     271                 :     /* printf("<ReadHeaderBBox\n"); */
     272               0 :     return FALSE;
     273                 : }
     274                 : 
     275                 : /************************************************************************/
     276                 : /*                          ReadOSMHeader()                             */
     277                 : /************************************************************************/
     278                 : 
     279                 : #define OSMHEADER_IDX_BBOX                  1
     280                 : #define OSMHEADER_IDX_REQUIRED_FEATURES     4
     281                 : #define OSMHEADER_IDX_OPTIONAL_FEATURES     5
     282                 : #define OSMHEADER_IDX_WRITING_PROGRAM       16
     283                 : #define OSMHEADER_IDX_SOURCE                17
     284                 : 
     285                 : static
     286              19 : int ReadOSMHeader(GByte* pabyData, GByte* pabyDataLimit,
     287                 :                   OSMContext* psCtxt)
     288                 : {
     289                 :     char* pszTxt;
     290                 : 
     291              95 :     while(pabyData < pabyDataLimit)
     292                 :     {
     293                 :         int nKey;
     294              57 :         READ_FIELD_KEY(nKey);
     295                 : 
     296              57 :         if (nKey == MAKE_KEY(OSMHEADER_IDX_BBOX, WT_DATA))
     297                 :         {
     298                 :             unsigned int nBBOXSize;
     299               0 :             READ_SIZE(pabyData, pabyDataLimit, nBBOXSize);
     300                 : 
     301               0 :             if (!ReadHeaderBBox(pabyData, pabyData + nBBOXSize, psCtxt)) GOTO_END_ERROR;
     302                 : 
     303               0 :             pabyData += nBBOXSize;
     304                 :         }
     305              57 :         else if (nKey == MAKE_KEY(OSMHEADER_IDX_REQUIRED_FEATURES, WT_DATA))
     306                 :         {
     307              38 :             READ_TEXT(pabyData, pabyDataLimit, pszTxt);
     308                 :             /* printf("OSMHEADER_IDX_REQUIRED_FEATURES = %s\n", pszTxt); */
     309              38 :             if (!(strcmp(pszTxt, "OsmSchema-V0.6") == 0 ||
     310                 :                   strcmp(pszTxt, "DenseNodes") == 0))
     311                 :             {
     312               0 :                 fprintf(stderr, "Error: unsupported required feature : %s\n", pszTxt);
     313               0 :                 VSIFree(pszTxt);
     314               0 :                 GOTO_END_ERROR;
     315                 :             }
     316              38 :             VSIFree(pszTxt);
     317                 :         }
     318              19 :         else if (nKey == MAKE_KEY(OSMHEADER_IDX_OPTIONAL_FEATURES, WT_DATA))
     319                 :         {
     320               0 :             READ_TEXT(pabyData, pabyDataLimit, pszTxt);
     321                 :             /* printf("OSMHEADER_IDX_OPTIONAL_FEATURES = %s\n", pszTxt); */
     322               0 :             VSIFree(pszTxt);
     323                 :         }
     324              19 :         else if (nKey == MAKE_KEY(OSMHEADER_IDX_WRITING_PROGRAM, WT_DATA))
     325                 :         {
     326              19 :             READ_TEXT(pabyData, pabyDataLimit, pszTxt);
     327                 :             /* printf("OSMHEADER_IDX_WRITING_PROGRAM = %s\n", pszTxt); */
     328              19 :             VSIFree(pszTxt);
     329                 :         }
     330               0 :         else if (nKey == MAKE_KEY(OSMHEADER_IDX_SOURCE, WT_DATA))
     331                 :         {
     332               0 :             READ_TEXT(pabyData, pabyDataLimit, pszTxt);
     333                 :             /* printf("OSMHEADER_IDX_SOURCE = %s\n", pszTxt); */
     334               0 :             VSIFree(pszTxt);
     335                 :         }
     336                 :         else
     337                 :         {
     338               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     339                 :         }
     340                 :     }
     341                 : 
     342              19 :     return pabyData == pabyDataLimit;
     343                 : 
     344                 : end_error:
     345               0 :     return FALSE;
     346                 : }
     347                 : 
     348                 : /************************************************************************/
     349                 : /*                         ReadStringTable()                            */
     350                 : /************************************************************************/
     351                 : 
     352                 : #define READSTRINGTABLE_IDX_STRING  1
     353                 : 
     354                 : static
     355              19 : int ReadStringTable(GByte* pabyData, GByte* pabyDataLimit,
     356                 :                     OSMContext* psCtxt)
     357                 : {
     358              19 :     char* pszStrBuf = (char*)pabyData;
     359                 : 
     360              19 :     unsigned int nStrCount = 0;
     361              19 :     int* panStrOff = psCtxt->panStrOff;
     362                 : 
     363              19 :     psCtxt->pszStrBuf = pszStrBuf;
     364                 : 
     365              19 :     if (pabyDataLimit - pabyData > psCtxt->nStrAllocated)
     366                 :     {
     367                 :         int* panStrOffNew;
     368                 :         psCtxt->nStrAllocated = MAX(psCtxt->nStrAllocated * 2,
     369               9 :                                           pabyDataLimit - pabyData);
     370                 :         panStrOffNew = (int*) VSIRealloc(
     371               9 :             panStrOff, psCtxt->nStrAllocated * sizeof(int));
     372               9 :         if( panStrOffNew == NULL )
     373               0 :             GOTO_END_ERROR;
     374               9 :         panStrOff = panStrOffNew;
     375                 :     }
     376                 : 
     377              57 :     while(pabyData < pabyDataLimit)
     378                 :     {
     379                 :         int nKey;
     380              19 :         READ_FIELD_KEY(nKey);
     381                 : 
     382             437 :         while (nKey == MAKE_KEY(READSTRINGTABLE_IDX_STRING, WT_DATA))
     383                 :         {
     384                 :             GByte* pbSaved;
     385                 :             unsigned int nDataLength;
     386             418 :             READ_SIZE(pabyData, pabyDataLimit, nDataLength);
     387                 : 
     388             418 :             panStrOff[nStrCount ++] = pabyData - (GByte*)pszStrBuf;
     389             418 :             pbSaved = &pabyData[nDataLength];
     390                 : 
     391             418 :             pabyData += nDataLength;
     392                 : 
     393             418 :             if (pabyData < pabyDataLimit)
     394                 :             {
     395             399 :                 READ_FIELD_KEY(nKey);
     396             399 :                 *pbSaved = 0;
     397                 :                 /* printf("string[%d] = %s\n", nStrCount-1, pbSaved - nDataLength); */
     398                 :             }
     399                 :             else
     400                 :             {
     401              19 :                 *pbSaved = 0;
     402                 :                 /* printf("string[%d] = %s\n", nStrCount-1, pbSaved - nDataLength); */
     403              19 :                 break;
     404                 :             }
     405                 :         }
     406                 : 
     407              19 :         if (pabyData < pabyDataLimit)
     408                 :         {
     409               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     410                 :         }
     411                 :     }
     412                 : 
     413              19 :     psCtxt->panStrOff = panStrOff;
     414              19 :     psCtxt->nStrCount = nStrCount;
     415                 : 
     416              19 :     return pabyData == pabyDataLimit;
     417                 : 
     418                 : end_error:
     419                 : 
     420               0 :     psCtxt->panStrOff = panStrOff;
     421               0 :     psCtxt->nStrCount = nStrCount;
     422                 : 
     423               0 :     return FALSE;
     424                 : }
     425                 : 
     426                 : /************************************************************************/
     427                 : /*                         ReadDenseNodes()                             */
     428                 : /************************************************************************/
     429                 : 
     430                 : #define DENSEINFO_IDX_VERSION     1
     431                 : #define DENSEINFO_IDX_TIMESTAMP   2
     432                 : #define DENSEINFO_IDX_CHANGESET   3
     433                 : #define DENSEINFO_IDX_UID         4
     434                 : #define DENSEINFO_IDX_USER_SID    5
     435                 : #define DENSEINFO_IDX_VISIBLE     6
     436                 : 
     437                 : #define DENSENODES_IDX_ID           1
     438                 : #define DENSENODES_IDX_DENSEINFO    5
     439                 : #define DENSENODES_IDX_LAT          8
     440                 : #define DENSENODES_IDX_LON          9
     441                 : #define DENSENODES_IDX_KEYVALS      10
     442                 : 
     443                 : static
     444              19 : int ReadDenseNodes(GByte* pabyData, GByte* pabyDataLimit,
     445                 :                    OSMContext* psCtxt)
     446                 : {
     447              19 :     GByte* pabyDataIDs = NULL;
     448              19 :     GByte* pabyDataIDsLimit = NULL;
     449              19 :     GByte* pabyDataLat = NULL;
     450              19 :     GByte* pabyDataLon = NULL;
     451              19 :     GByte* apabyData[DENSEINFO_IDX_VISIBLE] = {NULL, NULL, NULL, NULL, NULL, NULL};
     452              19 :     GByte* pabyDataKeyVal = NULL;
     453                 : 
     454                 :     /* printf(">ReadDenseNodes\n"); */
     455             133 :     while(pabyData < pabyDataLimit)
     456                 :     {
     457                 :         int nKey;
     458              95 :         READ_FIELD_KEY(nKey);
     459                 : 
     460              95 :         if( nKey == MAKE_KEY(DENSENODES_IDX_ID, WT_DATA) )
     461                 :         {
     462                 :             unsigned int nSize;
     463                 : 
     464              19 :             if (pabyDataIDs != NULL)
     465               0 :                 GOTO_END_ERROR;
     466              19 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     467                 : 
     468              19 :             if (nSize > psCtxt->nNodesAllocated)
     469                 :             {
     470                 :                 OSMNode* pasNodesNew;
     471                 :                 psCtxt->nNodesAllocated = MAX(psCtxt->nNodesAllocated * 2,
     472               9 :                                                  nSize);
     473                 :                 pasNodesNew = (OSMNode*) VSIRealloc(
     474               9 :                     psCtxt->pasNodes, psCtxt->nNodesAllocated * sizeof(OSMNode));
     475               9 :                 if( pasNodesNew == NULL )
     476               0 :                     GOTO_END_ERROR;
     477               9 :                 psCtxt->pasNodes = pasNodesNew;
     478                 :             }
     479                 : 
     480              19 :             pabyDataIDs = pabyData;
     481              19 :             pabyDataIDsLimit = pabyData + nSize;
     482              19 :             pabyData += nSize;
     483                 :         }
     484              76 :         else if( nKey == MAKE_KEY(DENSENODES_IDX_DENSEINFO, WT_DATA) )
     485                 :         {
     486                 :             unsigned int nSize;
     487                 :             GByte* pabyDataNewLimit;
     488                 :  
     489              19 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     490                 : 
     491                 :             /* Inline reading of DenseInfo structure */
     492                 : 
     493              19 :             pabyDataNewLimit = pabyData + nSize;
     494             133 :             while(pabyData < pabyDataNewLimit)
     495                 :             {
     496                 :                 int nFieldNumber;
     497              95 :                 READ_FIELD_KEY(nKey);
     498                 : 
     499              95 :                 nFieldNumber = GET_FIELDNUMBER(nKey);
     500             190 :                 if (GET_WIRETYPE(nKey) == WT_DATA &&
     501                 :                     nFieldNumber >= DENSEINFO_IDX_VERSION && nFieldNumber <= DENSEINFO_IDX_VISIBLE)
     502                 :                 {
     503              95 :                     if( apabyData[nFieldNumber - 1] != NULL) GOTO_END_ERROR;
     504              95 :                     READ_SIZE(pabyData, pabyDataNewLimit, nSize);
     505                 : 
     506              95 :                     apabyData[nFieldNumber - 1] = pabyData;
     507              95 :                     pabyData += nSize;
     508                 :                 }
     509                 :                 else
     510                 :                 {
     511               0 :                     SKIP_UNKNOWN_FIELD(pabyData, pabyDataNewLimit, TRUE);
     512                 :                 }
     513                 :             }
     514                 : 
     515              19 :             if( pabyData != pabyDataNewLimit )
     516               0 :                 GOTO_END_ERROR;
     517                 :         }
     518              57 :         else if( nKey == MAKE_KEY(DENSENODES_IDX_LAT, WT_DATA) )
     519                 :         {
     520                 :             unsigned int nSize;
     521              19 :             if (pabyDataLat != NULL)
     522               0 :                 GOTO_END_ERROR;
     523              19 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     524              19 :             pabyDataLat = pabyData;
     525              19 :             pabyData += nSize;
     526                 :         }
     527              38 :         else if( nKey == MAKE_KEY(DENSENODES_IDX_LON, WT_DATA) )
     528                 :         {
     529                 :             unsigned int nSize;
     530              19 :             if (pabyDataLon != NULL)
     531               0 :                 GOTO_END_ERROR;
     532              19 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     533              19 :             pabyDataLon = pabyData;
     534              19 :             pabyData += nSize;
     535                 :         }
     536              19 :         else if( nKey == MAKE_KEY(DENSENODES_IDX_KEYVALS, WT_DATA) )
     537                 :         {
     538                 :             unsigned int nSize;
     539              19 :             if( pabyDataKeyVal != NULL )
     540               0 :                 GOTO_END_ERROR;
     541              19 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     542                 : 
     543              19 :             pabyDataKeyVal = pabyData;
     544                 : 
     545              19 :             if (nSize > psCtxt->nTagsAllocated)
     546                 :             {
     547                 :                 OSMTag* pasTagsNew;
     548                 : 
     549                 :                 psCtxt->nTagsAllocated = MAX(
     550               9 :                     psCtxt->nTagsAllocated * 2, nSize);
     551                 :                 pasTagsNew = (OSMTag*) VSIRealloc(
     552                 :                     psCtxt->pasTags,
     553               9 :                     psCtxt->nTagsAllocated * sizeof(OSMTag));
     554               9 :                 if( pasTagsNew == NULL )
     555               0 :                     GOTO_END_ERROR;
     556               9 :                 psCtxt->pasTags = pasTagsNew;
     557                 :             }
     558                 : 
     559              19 :             pabyData += nSize;
     560                 :         }
     561                 :         else
     562                 :         {
     563               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     564                 :         }
     565                 :     }
     566                 : 
     567              19 :     if( pabyData != pabyDataLimit )
     568               0 :         GOTO_END_ERROR;
     569                 : 
     570              19 :     if( pabyDataIDs != NULL && pabyDataLat != NULL && pabyDataLon != NULL )
     571                 :     {
     572              19 :         GByte* pabyDataVersion = apabyData[DENSEINFO_IDX_VERSION - 1];
     573              19 :         GByte* pabyDataTimeStamp = apabyData[DENSEINFO_IDX_TIMESTAMP - 1];
     574              19 :         GByte* pabyDataChangeset = apabyData[DENSEINFO_IDX_CHANGESET - 1];
     575              19 :         GByte* pabyDataUID = apabyData[DENSEINFO_IDX_UID - 1];
     576              19 :         GByte* pabyDataUserSID = apabyData[DENSEINFO_IDX_USER_SID - 1];
     577                 :         /* GByte* pabyDataVisible = apabyData[DENSEINFO_IDX_VISIBLE - 1]; */
     578                 : 
     579              19 :         GIntBig nID = 0;
     580              19 :         GIntBig nLat = 0;
     581              19 :         GIntBig nLon = 0;
     582              19 :         GIntBig nTimeStamp = 0;
     583              19 :         GIntBig nChangeset = 0;
     584              19 :         int nUID = 0;
     585              19 :         unsigned int nUserSID = 0;
     586              19 :         int nTags = 0;
     587              19 :         int nNodes = 0;
     588                 : 
     589              19 :         const char* pszStrBuf = psCtxt->pszStrBuf;
     590              19 :         int* panStrOff = psCtxt->panStrOff;
     591              19 :         const unsigned int nStrCount = psCtxt->nStrCount;
     592              19 :         OSMTag* pasTags = psCtxt->pasTags;
     593              19 :         OSMNode* pasNodes = psCtxt->pasNodes;
     594                 : 
     595              19 :         int nVersion = 0;
     596                 :         /* int nVisible = 1; */
     597                 : 
     598             209 :         while(pabyDataIDs < pabyDataIDsLimit)
     599                 :         {
     600                 :             GIntBig nDelta1, nDelta2;
     601             171 :             int nKVIndexStart = nTags;
     602                 : 
     603             171 :             READ_VARSINT64_NOCHECK(pabyDataIDs, pabyDataIDsLimit, nDelta1);
     604             171 :             READ_VARSINT64(pabyDataLat, pabyDataLimit, nDelta2);
     605             171 :             nID += nDelta1;
     606             171 :             nLat += nDelta2;
     607                 : 
     608             171 :             READ_VARSINT64(pabyDataLon, pabyDataLimit, nDelta1);
     609             171 :             nLon += nDelta1;
     610                 : 
     611             171 :             if( pabyDataTimeStamp )
     612                 :             {
     613             171 :                 READ_VARSINT64(pabyDataTimeStamp, pabyDataLimit, nDelta2);
     614             171 :                 nTimeStamp += nDelta2;
     615                 :             }
     616             171 :             if( pabyDataChangeset )
     617                 :             {
     618             171 :                 READ_VARSINT64(pabyDataChangeset, pabyDataLimit, nDelta1);
     619             171 :                 nChangeset += nDelta1;
     620                 :             }
     621             171 :             if( pabyDataVersion )
     622                 :             {
     623             171 :                 READ_VARINT32(pabyDataVersion, pabyDataLimit, nVersion);
     624                 :             }
     625             171 :             if( pabyDataUID )
     626                 :             {
     627                 :                 int nDeltaUID;
     628             171 :                 READ_VARSINT32(pabyDataUID, pabyDataLimit, nDeltaUID);
     629             171 :                 nUID += nDeltaUID;
     630                 :             }
     631             171 :             if( pabyDataUserSID )
     632                 :             {
     633                 :                 int nDeltaUserSID;
     634             171 :                 READ_VARSINT32(pabyDataUserSID, pabyDataLimit, nDeltaUserSID);
     635             171 :                 nUserSID += nDeltaUserSID;
     636             171 :                 if (nUserSID >= nStrCount)
     637               0 :                     GOTO_END_ERROR;
     638                 :             }
     639                 :             /* if( pabyDataVisible )
     640                 :                 READ_VARINT32(pabyDataVisible, pabyDataLimit, nVisible); */
     641                 : 
     642             171 :             if( pabyDataKeyVal )
     643                 :             {
     644              19 :                 while (TRUE)
     645                 :                 {
     646                 :                     unsigned int nKey, nVal;
     647             190 :                     READ_VARUINT32(pabyDataKeyVal, pabyDataLimit, nKey);
     648             190 :                     if (nKey == 0)
     649             171 :                         break;
     650              19 :                     if (nKey >= nStrCount)
     651               0 :                         GOTO_END_ERROR;
     652                 : 
     653              19 :                     READ_VARUINT32(pabyDataKeyVal, pabyDataLimit, nVal);
     654              19 :                     if (nVal >= nStrCount)
     655               0 :                         GOTO_END_ERROR;
     656                 : 
     657              19 :                     pasTags[nTags].pszK = pszStrBuf + panStrOff[nKey];
     658              19 :                     pasTags[nTags].pszV = pszStrBuf + panStrOff[nVal];
     659              19 :                     nTags ++;
     660                 : 
     661                 :                     /* printf("nKey = %d, nVal = %d\n", nKey, nVal); */
     662                 :                 }
     663                 :             }
     664                 : 
     665             171 :             if( nTags > nKVIndexStart )
     666              19 :                 pasNodes[nNodes].pasTags = pasTags + nKVIndexStart;
     667                 :             else
     668             152 :                 pasNodes[nNodes].pasTags = NULL;
     669             171 :             pasNodes[nNodes].nTags = nTags - nKVIndexStart;
     670                 : 
     671             171 :             pasNodes[nNodes].nID = nID;
     672             171 :             pasNodes[nNodes].dfLat = .000000001 * (psCtxt->nLatOffset + (psCtxt->nGranularity * nLat));
     673             171 :             pasNodes[nNodes].dfLon = .000000001 * (psCtxt->nLonOffset + (psCtxt->nGranularity * nLon));
     674             171 :             pasNodes[nNodes].sInfo.bTimeStampIsStr = FALSE;
     675             171 :             pasNodes[nNodes].sInfo.ts.nTimeStamp = nTimeStamp;
     676             171 :             pasNodes[nNodes].sInfo.nChangeset = nChangeset;
     677             171 :             pasNodes[nNodes].sInfo.nVersion = nVersion;
     678             171 :             pasNodes[nNodes].sInfo.nUID = nUID;
     679             171 :             pasNodes[nNodes].sInfo.pszUserSID = pszStrBuf + panStrOff[nUserSID];
     680                 :             /* pasNodes[nNodes].sInfo.nVisible = nVisible; */
     681             171 :             nNodes ++;
     682                 :             /* printf("nLat = " CPL_FRMT_GIB "\n", nLat); printf("nLon = " CPL_FRMT_GIB "\n", nLon); */
     683                 :         }
     684                 : 
     685              19 :         psCtxt->pfnNotifyNodes(nNodes, pasNodes, psCtxt, psCtxt->user_data);
     686                 : 
     687              19 :         if(pabyDataIDs != pabyDataIDsLimit)
     688               0 :             GOTO_END_ERROR;
     689                 :     }
     690                 : 
     691                 :     /* printf("<ReadDenseNodes\n"); */
     692                 : 
     693              19 :     return TRUE;
     694                 : 
     695                 : end_error:
     696                 :     /* printf("<ReadDenseNodes\n"); */
     697                 : 
     698               0 :     return FALSE;
     699                 : }
     700                 : 
     701                 : /************************************************************************/
     702                 : /*                           ReadOSMInfo()                              */
     703                 : /************************************************************************/
     704                 : 
     705                 : #define INFO_IDX_VERSION     1
     706                 : #define INFO_IDX_TIMESTAMP   2
     707                 : #define INFO_IDX_CHANGESET   3
     708                 : #define INFO_IDX_UID         4
     709                 : #define INFO_IDX_USER_SID    5
     710                 : #define INFO_IDX_VISIBLE     6
     711                 : 
     712                 : static
     713                 : int ReadOSMInfo(GByte* pabyData, GByte* pabyDataLimit,
     714                 :              OSMInfo* psInfo, OSMContext* psContext) CPL_NO_INLINE;
     715                 : 
     716                 : static
     717             247 : int ReadOSMInfo(GByte* pabyData, GByte* pabyDataLimit,
     718                 :              OSMInfo* psInfo, OSMContext* psContext)
     719                 : {
     720                 :     /* printf(">ReadOSMInfo\n"); */
     721            1729 :     while(pabyData < pabyDataLimit)
     722                 :     {
     723                 :         int nKey;
     724            1235 :         READ_FIELD_KEY(nKey);
     725                 : 
     726            1235 :         if (nKey == MAKE_KEY(INFO_IDX_VERSION, WT_VARINT))
     727                 :         {
     728             247 :             READ_VARINT32(pabyData, pabyDataLimit, psInfo->nVersion);
     729                 :         }
     730             988 :         else if (nKey == MAKE_KEY(INFO_IDX_TIMESTAMP, WT_VARINT))
     731                 :         {
     732             247 :             READ_VARINT64(pabyData, pabyDataLimit, psInfo->ts.nTimeStamp);
     733                 :         }
     734             741 :         else if (nKey == MAKE_KEY(INFO_IDX_CHANGESET, WT_VARINT))
     735                 :         {
     736             247 :             READ_VARINT64(pabyData, pabyDataLimit, psInfo->nChangeset);
     737                 :         }
     738             494 :         else if (nKey == MAKE_KEY(INFO_IDX_UID, WT_VARINT))
     739                 :         {
     740             247 :             READ_VARINT32(pabyData, pabyDataLimit, psInfo->nUID);
     741                 :         }
     742             247 :         else if (nKey == MAKE_KEY(INFO_IDX_USER_SID, WT_VARINT))
     743                 :         {
     744                 :             unsigned int nUserSID;
     745             247 :             READ_VARUINT32(pabyData, pabyDataLimit, nUserSID);
     746             247 :             if( nUserSID < psContext->nStrCount)
     747                 :                 psInfo->pszUserSID = psContext->pszStrBuf +
     748             247 :                                      psContext->panStrOff[nUserSID];
     749                 :         }
     750               0 :         else if (nKey == MAKE_KEY(INFO_IDX_VISIBLE, WT_VARINT))
     751                 :         {
     752                 :             int nVisible;
     753               0 :             READ_VARINT32(pabyData, pabyDataLimit, /*psInfo->*/nVisible);
     754                 :         }
     755                 :         else
     756                 :         {
     757               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     758                 :         }
     759                 :     }
     760                 :     /* printf("<ReadOSMInfo\n"); */
     761                 : 
     762             247 :     return pabyData == pabyDataLimit;
     763                 : 
     764                 : end_error:
     765                 :     /* printf("<ReadOSMInfo\n"); */
     766                 : 
     767               0 :     return FALSE;
     768                 : }
     769                 : 
     770                 : /************************************************************************/
     771                 : /*                             ReadNode()                               */
     772                 : /************************************************************************/
     773                 : 
     774                 : #define NODE_IDX_ID      1
     775                 : #define NODE_IDX_LAT     7
     776                 : #define NODE_IDX_LON     8
     777                 : #define NODE_IDX_KEYS    9
     778                 : #define NODE_IDX_VALS    10
     779                 : #define NODE_IDX_INFO    11
     780                 : 
     781                 : static
     782               0 : int ReadNode(GByte* pabyData, GByte* pabyDataLimit,
     783                 :              OSMContext* psCtxt)
     784                 : {
     785                 :     OSMNode sNode;
     786                 : 
     787               0 :     sNode.nID = 0;
     788               0 :     INIT_INFO(sNode.sInfo);
     789                 : 
     790                 :     /* printf(">ReadNode\n"); */
     791               0 :     while(pabyData < pabyDataLimit)
     792                 :     {
     793                 :         int nKey;
     794               0 :         READ_FIELD_KEY(nKey);
     795                 : 
     796               0 :         if (nKey == MAKE_KEY(NODE_IDX_ID, WT_VARINT))
     797                 :         {
     798               0 :             READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, sNode.nID);
     799                 :         }
     800               0 :         else if (nKey == MAKE_KEY(NODE_IDX_LAT, WT_VARINT))
     801                 :         {
     802                 :             GIntBig nLat;
     803               0 :             READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nLat);
     804               0 :             sNode.dfLat = .000000001 * (psCtxt->nLatOffset + (psCtxt->nGranularity * nLat));
     805                 :         }
     806               0 :         else if (nKey == MAKE_KEY(NODE_IDX_LON, WT_VARINT))
     807                 :         {
     808                 :             GIntBig nLon;
     809               0 :             READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nLon);
     810               0 :             sNode.dfLon = .000000001 * (psCtxt->nLonOffset + (psCtxt->nGranularity * nLon));
     811                 :         }
     812               0 :         else if (nKey == MAKE_KEY(NODE_IDX_KEYS, WT_DATA))
     813                 :         {
     814                 :             unsigned int nSize;
     815                 :             GByte* pabyDataNewLimit;
     816               0 :             if (sNode.nTags != 0)
     817               0 :                 GOTO_END_ERROR;
     818               0 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     819                 : 
     820               0 :             if (nSize > psCtxt->nTagsAllocated)
     821                 :             {
     822                 :                 OSMTag* pasTagsNew;
     823                 : 
     824                 :                 psCtxt->nTagsAllocated = MAX(
     825               0 :                     psCtxt->nTagsAllocated * 2, nSize);
     826                 :                 pasTagsNew = (OSMTag*) VSIRealloc(
     827                 :                     psCtxt->pasTags,
     828               0 :                     psCtxt->nTagsAllocated * sizeof(OSMTag));
     829               0 :                 if( pasTagsNew == NULL )
     830               0 :                     GOTO_END_ERROR;
     831               0 :                 psCtxt->pasTags = pasTagsNew;
     832                 :             }
     833                 : 
     834               0 :             pabyDataNewLimit = pabyData + nSize;
     835               0 :             while (pabyData < pabyDataNewLimit)
     836                 :             {
     837                 :                 unsigned int nKey;
     838               0 :                 READ_VARUINT32(pabyData, pabyDataNewLimit, nKey);
     839                 : 
     840               0 :                 if (nKey >= psCtxt->nStrCount)
     841               0 :                     GOTO_END_ERROR;
     842                 : 
     843               0 :                 psCtxt->pasTags[sNode.nTags].pszK = psCtxt->pszStrBuf +
     844               0 :                                               psCtxt->panStrOff[nKey];
     845               0 :                 psCtxt->pasTags[sNode.nTags].pszV = NULL;
     846               0 :                 sNode.nTags ++;
     847                 :             }
     848               0 :             if (pabyData != pabyDataNewLimit)
     849               0 :                 GOTO_END_ERROR;
     850                 :         }
     851               0 :         else if (nKey == MAKE_KEY(NODE_IDX_VALS, WT_DATA))
     852                 :         {
     853                 :             unsigned int nSize;
     854               0 :             unsigned int nIter = 0;
     855               0 :             if (sNode.nTags == 0)
     856               0 :                 GOTO_END_ERROR;
     857               0 :             READ_VARUINT32(pabyData, pabyDataLimit, nSize);
     858                 : 
     859               0 :             for(; nIter < sNode.nTags; nIter ++)
     860                 :             {
     861                 :                 unsigned int nVal;
     862               0 :                 READ_VARUINT32(pabyData, pabyDataLimit, nVal);
     863                 : 
     864               0 :                 if (nVal >= psCtxt->nStrCount)
     865               0 :                     GOTO_END_ERROR;
     866                 : 
     867               0 :                 psCtxt->pasTags[nIter].pszV = psCtxt->pszStrBuf +
     868               0 :                                               psCtxt->panStrOff[nVal];
     869                 :             }
     870                 :         }
     871               0 :         else if (nKey == MAKE_KEY(NODE_IDX_INFO, WT_DATA))
     872                 :         {
     873                 :             unsigned int nSize;
     874               0 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     875                 : 
     876               0 :             if (!ReadOSMInfo(pabyData, pabyDataLimit + nSize, &sNode.sInfo, psCtxt))
     877               0 :                 GOTO_END_ERROR;
     878                 : 
     879               0 :             pabyData += nSize;
     880                 :         }
     881                 :         else
     882                 :         {
     883               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
     884                 :         }
     885                 :     }
     886                 : 
     887               0 :     if( pabyData != pabyDataLimit )
     888               0 :         GOTO_END_ERROR;
     889                 : 
     890               0 :     if (sNode.nTags)
     891               0 :         sNode.pasTags = psCtxt->pasTags;
     892                 :     else
     893               0 :         sNode.pasTags = NULL;
     894               0 :     psCtxt->pfnNotifyNodes(1, &sNode, psCtxt, psCtxt->user_data);
     895                 : 
     896                 :     /* printf("<ReadNode\n"); */
     897                 : 
     898               0 :     return TRUE;
     899                 : 
     900                 : end_error:
     901                 :     /* printf("<ReadNode\n"); */
     902                 : 
     903               0 :     return FALSE;
     904                 : }
     905                 : 
     906                 : 
     907                 : /************************************************************************/
     908                 : /*                              ReadWay()                               */
     909                 : /************************************************************************/
     910                 : 
     911                 : #define WAY_IDX_ID      1
     912                 : #define WAY_IDX_KEYS    2
     913                 : #define WAY_IDX_VALS    3
     914                 : #define WAY_IDX_INFO    4
     915                 : #define WAY_IDX_REFS    8
     916                 : 
     917                 : static
     918             152 : int ReadWay(GByte* pabyData, GByte* pabyDataLimit,
     919                 :             OSMContext* psCtxt)
     920                 : {
     921                 :     OSMWay sWay;
     922             152 :     sWay.nID = 0;
     923             152 :     INIT_INFO(sWay.sInfo);
     924             152 :     sWay.nTags = 0;
     925             152 :     sWay.nRefs = 0;
     926                 : 
     927                 :     /* printf(">ReadWay\n"); */
     928            1026 :     while(pabyData < pabyDataLimit)
     929                 :     {
     930                 :         int nKey;
     931             722 :         READ_FIELD_KEY(nKey);
     932                 : 
     933             722 :         if (nKey == MAKE_KEY(WAY_IDX_ID, WT_VARINT))
     934                 :         {
     935             152 :             READ_VARINT64(pabyData, pabyDataLimit, sWay.nID);
     936                 :         }
     937             570 :         else if (nKey == MAKE_KEY(WAY_IDX_KEYS, WT_DATA))
     938                 :         {
     939                 :             unsigned int nSize;
     940                 :             GByte* pabyDataNewLimit;
     941             133 :             if (sWay.nTags != 0)
     942               0 :                 GOTO_END_ERROR;
     943             133 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
     944                 : 
     945             133 :             if (nSize > psCtxt->nTagsAllocated)
     946                 :             {
     947                 :                 OSMTag* pasTagsNew;
     948                 : 
     949                 :                 psCtxt->nTagsAllocated = MAX(
     950               0 :                     psCtxt->nTagsAllocated * 2, nSize);
     951                 :                 pasTagsNew = (OSMTag*) VSIRealloc(
     952                 :                     psCtxt->pasTags,
     953               0 :                     psCtxt->nTagsAllocated * sizeof(OSMTag));
     954               0 :                 if( pasTagsNew == NULL )
     955               0 :                     GOTO_END_ERROR;
     956               0 :                 psCtxt->pasTags = pasTagsNew;
     957                 :             }
     958                 : 
     959             133 :             pabyDataNewLimit = pabyData + nSize;
     960             437 :             while (pabyData < pabyDataNewLimit)
     961                 :             {
     962                 :                 unsigned int nKey;
     963             171 :                 READ_VARUINT32(pabyData, pabyDataNewLimit, nKey);
     964                 : 
     965             171 :                 if (nKey >= psCtxt->nStrCount)
     966               0 :                     GOTO_END_ERROR;
     967                 : 
     968             171 :                 psCtxt->pasTags[sWay.nTags].pszK = psCtxt->pszStrBuf +
     969             171 :                                                    psCtxt->panStrOff[nKey];
     970             171 :                 psCtxt->pasTags[sWay.nTags].pszV = NULL;
     971             171 :                 sWay.nTags ++;
     972                 :             }
     973             133 :             if (pabyData != pabyDataNewLimit)
     974               0 :                 GOTO_END_ERROR;
     975                 :         }
     976             437 :         else if (nKey == MAKE_KEY(WAY_IDX_VALS, WT_DATA))
     977                 :         {
     978                 :             unsigned int nSize;
     979             133 :             unsigned int nIter = 0;
     980             133 :             if (sWay.nTags == 0)
     981               0 :                 GOTO_END_ERROR;
     982             133 :             READ_VARUINT32(pabyData, pabyDataLimit, nSize);
     983                 : 
     984             304 :             for(; nIter < sWay.nTags; nIter ++)
     985                 :             {
     986                 :                 unsigned int nVal;
     987             171 :                 READ_VARUINT32(pabyData, pabyDataLimit, nVal);
     988                 : 
     989             171 :                 if (nVal >= psCtxt->nStrCount)
     990               0 :                     GOTO_END_ERROR;
     991                 : 
     992             171 :                 psCtxt->pasTags[nIter].pszV = psCtxt->pszStrBuf +
     993             171 :                                               psCtxt->panStrOff[nVal];
     994                 :             }
     995                 :         }
     996             304 :         else if (nKey == MAKE_KEY(WAY_IDX_INFO, WT_DATA))
     997                 :         {
     998                 :             unsigned int nSize;
     999             152 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1000                 : 
    1001             152 :             if (!ReadOSMInfo(pabyData, pabyData + nSize, &sWay.sInfo, psCtxt))
    1002               0 :                 GOTO_END_ERROR;
    1003                 : 
    1004             152 :             pabyData += nSize;
    1005                 :         }
    1006             152 :         else if (nKey == MAKE_KEY(WAY_IDX_REFS, WT_DATA))
    1007                 :         {
    1008             152 :             GIntBig nRefVal = 0;
    1009                 :             unsigned int nSize;
    1010                 :             GByte* pabyDataNewLimit;
    1011             152 :             if (sWay.nRefs != 0)
    1012               0 :                 GOTO_END_ERROR;
    1013             152 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1014                 : 
    1015             152 :             if (nSize > psCtxt->nNodeRefsAllocated)
    1016                 :             {
    1017                 :                 GIntBig* panNodeRefsNew;
    1018                 :                 psCtxt->nNodeRefsAllocated =
    1019              27 :                     MAX(psCtxt->nNodeRefsAllocated * 2, nSize);
    1020                 :                 panNodeRefsNew = (GIntBig*) VSIRealloc(
    1021                 :                         psCtxt->panNodeRefs,
    1022              27 :                         psCtxt->nNodeRefsAllocated * sizeof(GIntBig));
    1023              27 :                 if( panNodeRefsNew == NULL )
    1024               0 :                     GOTO_END_ERROR;
    1025              27 :                 psCtxt->panNodeRefs = panNodeRefsNew;
    1026                 :             }
    1027                 : 
    1028             152 :             pabyDataNewLimit = pabyData + nSize;
    1029             874 :             while (pabyData < pabyDataNewLimit)
    1030                 :             {
    1031                 :                 GIntBig nDeltaRef;
    1032             570 :                 READ_VARSINT64_NOCHECK(pabyData, pabyDataNewLimit, nDeltaRef);
    1033             570 :                 nRefVal += nDeltaRef;
    1034                 : 
    1035             570 :                 psCtxt->panNodeRefs[sWay.nRefs ++] = nRefVal;
    1036                 :             }
    1037                 : 
    1038             152 :             if (pabyData != pabyDataNewLimit)
    1039               0 :                 GOTO_END_ERROR;
    1040                 :         }
    1041                 :         else
    1042                 :         {
    1043               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
    1044                 :         }
    1045                 :     }
    1046                 : 
    1047             152 :     if( pabyData != pabyDataLimit )
    1048               0 :         GOTO_END_ERROR;
    1049                 : 
    1050                 :     /* printf("<ReadWay\n"); */
    1051                 : 
    1052             152 :     if (sWay.nTags)
    1053             133 :         sWay.pasTags = psCtxt->pasTags;
    1054                 :     else
    1055              19 :         sWay.pasTags = NULL;
    1056             152 :     sWay.panNodeRefs = psCtxt->panNodeRefs;
    1057                 : 
    1058             152 :     psCtxt->pfnNotifyWay(&sWay, psCtxt, psCtxt->user_data);
    1059                 : 
    1060             152 :     return TRUE;
    1061                 : 
    1062                 : end_error:
    1063                 :     /* printf("<ReadWay\n"); */
    1064                 : 
    1065               0 :     return FALSE;
    1066                 : }
    1067                 : 
    1068                 : /************************************************************************/
    1069                 : /*                            ReadRelation()                            */
    1070                 : /************************************************************************/
    1071                 : 
    1072                 : #define RELATION_IDX_ID           1
    1073                 : #define RELATION_IDX_KEYS         2
    1074                 : #define RELATION_IDX_VALS         3
    1075                 : #define RELATION_IDX_INFO         4
    1076                 : #define RELATION_IDX_ROLES_SID    8
    1077                 : #define RELATION_IDX_MEMIDS       9
    1078                 : #define RELATION_IDX_TYPES        10
    1079                 : 
    1080                 : static
    1081              95 : int ReadRelation(GByte* pabyData, GByte* pabyDataLimit,
    1082                 :                  OSMContext* psCtxt)
    1083                 : {
    1084                 :     OSMRelation sRelation;
    1085              95 :     sRelation.nID = 0;
    1086              95 :     INIT_INFO(sRelation.sInfo);
    1087              95 :     sRelation.nTags = 0;
    1088              95 :     sRelation.nMembers = 0;
    1089                 : 
    1090                 :     /* printf(">ReadRelation\n"); */
    1091             855 :     while(pabyData < pabyDataLimit)
    1092                 :     {
    1093                 :         int nKey;
    1094             665 :         READ_FIELD_KEY(nKey);
    1095                 : 
    1096             665 :         if (nKey == MAKE_KEY(RELATION_IDX_ID, WT_VARINT))
    1097                 :         {
    1098              95 :             READ_VARINT64(pabyData, pabyDataLimit, sRelation.nID);
    1099                 :         }
    1100             570 :         else if (nKey == MAKE_KEY(RELATION_IDX_KEYS, WT_DATA))
    1101                 :         {
    1102                 :             unsigned int nSize;
    1103                 :             GByte* pabyDataNewLimit;
    1104              95 :             if (sRelation.nTags != 0)
    1105               0 :                 GOTO_END_ERROR;
    1106              95 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1107                 : 
    1108              95 :             if (nSize > psCtxt->nTagsAllocated)
    1109                 :             {
    1110                 :                 OSMTag* pasTagsNew;
    1111                 : 
    1112                 :                 psCtxt->nTagsAllocated = MAX(
    1113               0 :                     psCtxt->nTagsAllocated * 2, nSize);
    1114                 :                 pasTagsNew = (OSMTag*) VSIRealloc(
    1115                 :                     psCtxt->pasTags,
    1116               0 :                     psCtxt->nTagsAllocated * sizeof(OSMTag));
    1117               0 :                 if( pasTagsNew == NULL )
    1118               0 :                     GOTO_END_ERROR;
    1119               0 :                 psCtxt->pasTags = pasTagsNew;
    1120                 :             }
    1121                 : 
    1122              95 :             pabyDataNewLimit = pabyData + nSize;
    1123             304 :             while (pabyData < pabyDataNewLimit)
    1124                 :             {
    1125                 :                 unsigned int nKey;
    1126             114 :                 READ_VARUINT32(pabyData, pabyDataNewLimit, nKey);
    1127                 : 
    1128             114 :                 if (nKey >= psCtxt->nStrCount)
    1129               0 :                     GOTO_END_ERROR;
    1130                 : 
    1131             114 :                 psCtxt->pasTags[sRelation.nTags].pszK = psCtxt->pszStrBuf +
    1132             114 :                                                         psCtxt->panStrOff[nKey];
    1133             114 :                 psCtxt->pasTags[sRelation.nTags].pszV = NULL;
    1134             114 :                 sRelation.nTags ++;
    1135                 :             }
    1136              95 :             if (pabyData != pabyDataNewLimit)
    1137               0 :                 GOTO_END_ERROR;
    1138                 :         }
    1139             475 :         else if (nKey == MAKE_KEY(RELATION_IDX_VALS, WT_DATA))
    1140                 :         {
    1141                 :             unsigned int nSize;
    1142              95 :             unsigned int nIter = 0;
    1143              95 :             if (sRelation.nTags == 0)
    1144               0 :                 GOTO_END_ERROR;
    1145              95 :             READ_VARUINT32(pabyData, pabyDataLimit, nSize);
    1146                 : 
    1147             209 :             for(; nIter < sRelation.nTags; nIter ++)
    1148                 :             {
    1149                 :                 unsigned int nVal;
    1150             114 :                 READ_VARUINT32(pabyData, pabyDataLimit, nVal);
    1151                 : 
    1152             114 :                 if (nVal >= psCtxt->nStrCount)
    1153               0 :                     GOTO_END_ERROR;
    1154                 : 
    1155             114 :                 psCtxt->pasTags[nIter].pszV = psCtxt->pszStrBuf +
    1156             114 :                                               psCtxt->panStrOff[nVal];
    1157                 :             }
    1158                 :         }
    1159             380 :         else if (nKey == MAKE_KEY(RELATION_IDX_INFO, WT_DATA))
    1160                 :         {
    1161                 :             unsigned int nSize;
    1162              95 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1163                 : 
    1164              95 :             if (!ReadOSMInfo(pabyData, pabyData + nSize, &sRelation.sInfo, psCtxt))
    1165               0 :                 GOTO_END_ERROR;
    1166                 : 
    1167              95 :             pabyData += nSize;
    1168                 :         }
    1169             285 :         else if (nKey == MAKE_KEY(RELATION_IDX_ROLES_SID, WT_DATA))
    1170                 :         {
    1171                 :             unsigned int nSize;
    1172                 :             GByte* pabyDataNewLimit;
    1173              95 :             if (sRelation.nMembers != 0)
    1174               0 :                 GOTO_END_ERROR;
    1175              95 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1176                 : 
    1177              95 :             if (nSize > psCtxt->nMembersAllocated)
    1178                 :             {
    1179                 :                 OSMMember* pasMembersNew;
    1180                 :                 psCtxt->nMembersAllocated =
    1181               9 :                     MAX(psCtxt->nMembersAllocated * 2, nSize);
    1182                 :                 pasMembersNew = (OSMMember*) VSIRealloc(
    1183                 :                         psCtxt->pasMembers,
    1184               9 :                         psCtxt->nMembersAllocated * sizeof(OSMMember));
    1185               9 :                 if( pasMembersNew == NULL )
    1186               0 :                     GOTO_END_ERROR;
    1187               9 :                 psCtxt->pasMembers = pasMembersNew;
    1188                 :             }
    1189                 : 
    1190              95 :             pabyDataNewLimit = pabyData + nSize;
    1191             361 :             while (pabyData < pabyDataNewLimit)
    1192                 :             {
    1193                 :                 unsigned int nRoleSID;
    1194             171 :                 READ_VARUINT32(pabyData, pabyDataNewLimit, nRoleSID);
    1195             171 :                 if (nRoleSID >= psCtxt->nStrCount)
    1196               0 :                     GOTO_END_ERROR;
    1197                 : 
    1198             171 :                 psCtxt->pasMembers[sRelation.nMembers].pszRole =
    1199             171 :                     psCtxt->pszStrBuf + psCtxt->panStrOff[nRoleSID];
    1200             171 :                 psCtxt->pasMembers[sRelation.nMembers].nID = 0;
    1201             171 :                 psCtxt->pasMembers[sRelation.nMembers].eType = MEMBER_NODE;
    1202             171 :                 sRelation.nMembers ++;
    1203                 :             }
    1204                 : 
    1205              95 :             if (pabyData != pabyDataNewLimit)
    1206               0 :                 GOTO_END_ERROR;
    1207                 :         }
    1208             190 :         else if (nKey == MAKE_KEY(RELATION_IDX_MEMIDS, WT_DATA))
    1209                 :         {
    1210              95 :             unsigned int nIter = 0;
    1211              95 :             GIntBig nMemID = 0;
    1212                 :             unsigned int nSize;
    1213              95 :             if (sRelation.nMembers == 0)
    1214               0 :                 GOTO_END_ERROR;
    1215              95 :             READ_VARUINT32(pabyData, pabyDataLimit, nSize);
    1216                 : 
    1217             266 :             for(; nIter < sRelation.nMembers; nIter++)
    1218                 :             {
    1219                 :                 GIntBig nDeltaMemID;
    1220             171 :                 READ_VARSINT64(pabyData, pabyDataLimit, nDeltaMemID);
    1221             171 :                 nMemID += nDeltaMemID;
    1222                 : 
    1223             171 :                 psCtxt->pasMembers[nIter].nID = nMemID;
    1224                 :             }
    1225                 :         }
    1226              95 :         else if (nKey == MAKE_KEY(RELATION_IDX_TYPES, WT_DATA))
    1227                 :         {
    1228              95 :             unsigned int nIter = 0;
    1229                 :             unsigned int nSize;
    1230              95 :             if (sRelation.nMembers == 0)
    1231               0 :                 GOTO_END_ERROR;
    1232              95 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1233              95 :             if (nSize != sRelation.nMembers)
    1234               0 :                 GOTO_END_ERROR;
    1235                 : 
    1236             266 :             for(; nIter < sRelation.nMembers; nIter++)
    1237                 :             {
    1238             171 :                 unsigned int nType = pabyData[nIter];
    1239             171 :                 if (nType > MEMBER_RELATION)
    1240               0 :                     GOTO_END_ERROR;
    1241                 : 
    1242             171 :                 psCtxt->pasMembers[nIter].eType = (OSMMemberType) nType;
    1243                 :             }
    1244              95 :             pabyData += nSize;
    1245                 :         }
    1246                 :         else
    1247                 :         {
    1248               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
    1249                 :         }
    1250                 :     }
    1251                 :     /* printf("<ReadRelation\n"); */
    1252                 : 
    1253              95 :     if( pabyData != pabyDataLimit )
    1254               0 :         GOTO_END_ERROR;
    1255                 : 
    1256              95 :     if (sRelation.nTags)
    1257              95 :         sRelation.pasTags = psCtxt->pasTags;
    1258                 :     else
    1259               0 :         sRelation.pasTags = NULL;
    1260                 : 
    1261              95 :     sRelation.pasMembers = psCtxt->pasMembers;
    1262                 : 
    1263              95 :     psCtxt->pfnNotifyRelation(&sRelation, psCtxt, psCtxt->user_data);
    1264                 : 
    1265              95 :     return TRUE;
    1266                 : 
    1267                 : end_error:
    1268                 :     /* printf("<ReadRelation\n"); */
    1269                 : 
    1270               0 :     return FALSE;
    1271                 : }
    1272                 : 
    1273                 : /************************************************************************/
    1274                 : /*                          ReadPrimitiveGroup()                        */
    1275                 : /************************************************************************/
    1276                 : 
    1277                 : #define PRIMITIVEGROUP_IDX_NODES      1
    1278                 : #define PRIMITIVEGROUP_IDX_DENSE      2
    1279                 : #define PRIMITIVEGROUP_IDX_WAYS       3
    1280                 : #define PRIMITIVEGROUP_IDX_RELATIONS  4
    1281                 : #define PRIMITIVEGROUP_IDX_CHANGESETS 5
    1282                 : 
    1283                 : typedef int (*PrimitiveFuncType)(GByte* pabyData, GByte* pabyDataLimit,
    1284                 :                                  OSMContext* psCtxt);
    1285                 : 
    1286                 : static const PrimitiveFuncType apfnPrimitives[] =
    1287                 : {
    1288                 :     ReadNode,
    1289                 :     ReadDenseNodes,
    1290                 :     ReadWay,
    1291                 :     ReadRelation
    1292                 : };
    1293                 : 
    1294                 : static
    1295              57 : int ReadPrimitiveGroup(GByte* pabyData, GByte* pabyDataLimit,
    1296                 :                        OSMContext* psCtxt)
    1297                 : {
    1298                 :     /* printf(">ReadPrimitiveGroup\n"); */
    1299             380 :     while(pabyData < pabyDataLimit)
    1300                 :     {
    1301                 :         int nKey;
    1302                 :         int nFieldNumber;
    1303             266 :         READ_FIELD_KEY(nKey);
    1304                 : 
    1305             266 :         nFieldNumber = GET_FIELDNUMBER(nKey) - 1;
    1306             532 :         if( GET_WIRETYPE(nKey) == WT_DATA &&
    1307                 :             nFieldNumber >= PRIMITIVEGROUP_IDX_NODES - 1 &&
    1308                 :             nFieldNumber <= PRIMITIVEGROUP_IDX_RELATIONS - 1 )
    1309                 :         {
    1310                 :             unsigned int nSize;
    1311             266 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1312                 : 
    1313             266 :             if (!apfnPrimitives[nFieldNumber](pabyData, pabyData + nSize, psCtxt))
    1314               0 :                 GOTO_END_ERROR;
    1315                 : 
    1316             266 :             pabyData += nSize;
    1317                 :         }
    1318                 :         else
    1319                 :         {
    1320               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
    1321                 :         }
    1322                 :     }
    1323                 :     /* printf("<ReadPrimitiveGroup\n"); */
    1324                 : 
    1325              57 :     return pabyData == pabyDataLimit;
    1326                 : 
    1327                 : end_error:
    1328                 :     /* printf("<ReadPrimitiveGroup\n"); */
    1329                 : 
    1330               0 :     return FALSE;
    1331                 : }
    1332                 : 
    1333                 : /************************************************************************/
    1334                 : /*                          ReadPrimitiveBlock()                        */
    1335                 : /************************************************************************/
    1336                 : 
    1337                 : #define PRIMITIVEBLOCK_IDX_STRINGTABLE      1
    1338                 : #define PRIMITIVEBLOCK_IDX_PRIMITIVEGROUP   2
    1339                 : #define PRIMITIVEBLOCK_IDX_GRANULARITY      17
    1340                 : #define PRIMITIVEBLOCK_IDX_DATE_GRANULARITY 18
    1341                 : #define PRIMITIVEBLOCK_IDX_LAT_OFFSET       19
    1342                 : #define PRIMITIVEBLOCK_IDX_LON_OFFSET       20
    1343                 : 
    1344                 : static
    1345              19 : int ReadPrimitiveBlock(GByte* pabyData, GByte* pabyDataLimit,
    1346                 :                        OSMContext* psCtxt)
    1347                 : {
    1348              19 :     GByte* pabyDataSave = pabyData;
    1349                 : 
    1350              19 :     psCtxt->pszStrBuf = NULL;
    1351              19 :     psCtxt->nStrCount = 0;
    1352              19 :     psCtxt->nGranularity = 100;
    1353              19 :     psCtxt->nDateGranularity = 1000;
    1354              19 :     psCtxt->nLatOffset = 0;
    1355              19 :     psCtxt->nLonOffset = 0;
    1356                 : 
    1357             152 :     while(pabyData < pabyDataLimit)
    1358                 :     {
    1359                 :         int nKey;
    1360             114 :         READ_FIELD_KEY(nKey);
    1361                 : 
    1362             114 :         if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_GRANULARITY, WT_VARINT))
    1363                 :         {
    1364              19 :             READ_VARINT32(pabyData, pabyDataLimit, psCtxt->nGranularity);
    1365                 :         }
    1366              95 :         else if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_DATE_GRANULARITY, WT_VARINT))
    1367                 :         {
    1368              19 :             READ_VARINT32(pabyData, pabyDataLimit, psCtxt->nDateGranularity);
    1369                 :         }
    1370              76 :         else if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_LAT_OFFSET, WT_VARINT))
    1371                 :         {
    1372               0 :             READ_VARINT64(pabyData, pabyDataLimit, psCtxt->nLatOffset);
    1373                 :         }
    1374              76 :         else if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_LON_OFFSET, WT_VARINT))
    1375                 :         {
    1376               0 :             READ_VARINT64(pabyData, pabyDataLimit, psCtxt->nLonOffset);
    1377                 :         }
    1378                 :         else
    1379                 :         {
    1380              76 :             SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, FALSE);
    1381                 :         }
    1382                 :     }
    1383                 : 
    1384              19 :     if (pabyData != pabyDataLimit)
    1385               0 :         GOTO_END_ERROR;
    1386                 : 
    1387              19 :     pabyData = pabyDataSave;
    1388             133 :     while(pabyData < pabyDataLimit)
    1389                 :     {
    1390                 :         int nKey;
    1391              95 :         READ_FIELD_KEY(nKey);
    1392                 : 
    1393              95 :         if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_STRINGTABLE, WT_DATA))
    1394                 :         {
    1395                 :             GByte bSaveAfterByte;
    1396                 :             GByte* pbSaveAfterByte;
    1397                 :             unsigned int nSize;
    1398              19 :             if (psCtxt->nStrCount != 0)
    1399               0 :                 GOTO_END_ERROR;
    1400              19 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1401                 : 
    1402                 :             /* Dirty little trick */
    1403                 :             /* ReadStringTable() will over-write the byte after the */
    1404                 :             /* StringTable message with a NUL charachter, so we backup */
    1405                 :             /* it to be able to restore it just before issuing the next */
    1406                 :             /* READ_FIELD_KEY. Then we will re-NUL it to have valid */
    1407                 :             /* NUL terminated strings */
    1408                 :             /* This trick enable us to keep the strings where there are */
    1409                 :             /* in RAM */
    1410              19 :             pbSaveAfterByte = pabyData + nSize;
    1411              19 :             bSaveAfterByte = *pbSaveAfterByte;
    1412                 : 
    1413              19 :             if (!ReadStringTable(pabyData, pabyData + nSize,
    1414                 :                                  psCtxt))
    1415               0 :                 GOTO_END_ERROR;
    1416                 : 
    1417              19 :             pabyData += nSize;
    1418                 : 
    1419              19 :             *pbSaveAfterByte = bSaveAfterByte;
    1420              19 :             if (pabyData == pabyDataLimit)
    1421               0 :                 break;
    1422                 : 
    1423              19 :             READ_FIELD_KEY(nKey);
    1424              19 :             *pbSaveAfterByte = 0;
    1425                 : 
    1426              19 :             if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_STRINGTABLE, WT_DATA))
    1427               0 :                 GOTO_END_ERROR;
    1428                 : 
    1429                 :             /* Yes we go on ! */
    1430                 :         }
    1431                 : 
    1432              95 :         if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_PRIMITIVEGROUP, WT_DATA))
    1433                 :         {
    1434                 :             unsigned int nSize;
    1435              57 :             READ_SIZE(pabyData, pabyDataLimit, nSize);
    1436                 : 
    1437              57 :             if (!ReadPrimitiveGroup(pabyData, pabyData + nSize,
    1438                 :                                     psCtxt))
    1439               0 :                 GOTO_END_ERROR;
    1440                 : 
    1441              57 :             pabyData += nSize;
    1442                 :         }
    1443                 :         else
    1444                 :         {
    1445              38 :             SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, FALSE);
    1446                 :         }
    1447                 :     }
    1448                 : 
    1449              19 :     return pabyData == pabyDataLimit;
    1450                 : 
    1451                 : end_error:
    1452                 : 
    1453               0 :     return FALSE;
    1454                 : }
    1455                 : 
    1456                 : /************************************************************************/
    1457                 : /*                              ReadBlob()                              */
    1458                 : /************************************************************************/
    1459                 : 
    1460                 : #define BLOB_IDX_RAW         1
    1461                 : #define BLOB_IDX_RAW_SIZE    2
    1462                 : #define BLOB_IDX_ZLIB_DATA   3
    1463                 : 
    1464                 : static
    1465              38 : int ReadBlob(GByte* pabyData, unsigned int nDataSize, BlobType eType,
    1466                 :              OSMContext* psCtxt)
    1467                 : {
    1468              38 :     unsigned int nUncompressedSize = 0;
    1469              38 :     int bRet = TRUE;
    1470              38 :     GByte* pabyDataLimit = pabyData + nDataSize;
    1471                 : 
    1472             152 :     while(pabyData < pabyDataLimit)
    1473                 :     {
    1474                 :         int nKey;
    1475              76 :         READ_FIELD_KEY(nKey);
    1476                 : 
    1477              76 :         if (nKey == MAKE_KEY(BLOB_IDX_RAW, WT_DATA))
    1478                 :         {
    1479                 :             unsigned int nDataLength;
    1480               0 :             READ_SIZE(pabyData, pabyDataLimit, nDataLength);
    1481               0 :             if (nDataLength > 64 * 1024 * 1024) GOTO_END_ERROR;
    1482                 : 
    1483                 :             /* printf("raw data size = %d\n", nDataLength); */
    1484                 : 
    1485               0 :             if (eType == BLOB_OSMHEADER)
    1486                 :             {
    1487               0 :                 bRet = ReadOSMHeader(pabyData, pabyData + nDataLength, psCtxt);
    1488                 :             }
    1489               0 :             else if (eType == BLOB_OSMDATA)
    1490                 :             {
    1491                 :                 bRet = ReadPrimitiveBlock(pabyData, pabyData + nDataLength,
    1492               0 :                                           psCtxt);
    1493                 :             }
    1494                 : 
    1495               0 :             pabyData += nDataLength;
    1496                 :         }
    1497              76 :         else if (nKey == MAKE_KEY(BLOB_IDX_RAW_SIZE, WT_VARINT))
    1498                 :         {
    1499              38 :             READ_VARUINT32(pabyData, pabyDataLimit, nUncompressedSize);
    1500                 :             /* printf("nUncompressedSize = %d\n", nUncompressedSize); */
    1501                 :         }
    1502              38 :         else if (nKey == MAKE_KEY(BLOB_IDX_ZLIB_DATA, WT_DATA))
    1503                 :         {
    1504                 :             unsigned int nZlibCompressedSize;
    1505              38 :             READ_VARUINT32(pabyData, pabyDataLimit, nZlibCompressedSize);
    1506              38 :             if (CHECK_OOB && nZlibCompressedSize > nDataSize) GOTO_END_ERROR;
    1507                 : 
    1508                 :             /* printf("nZlibCompressedSize = %d\n", nZlibCompressedSize); */
    1509                 : 
    1510              38 :             if (nUncompressedSize != 0)
    1511                 :             {
    1512                 :                 int nStatus;
    1513                 :                 z_stream sStream;
    1514              38 :                 if (nUncompressedSize > psCtxt->nUncompressedAllocated)
    1515                 :                 {
    1516                 :                     GByte* pabyUncompressedNew;
    1517                 :                     psCtxt->nUncompressedAllocated =
    1518              18 :                         MAX(psCtxt->nUncompressedAllocated * 2, nUncompressedSize);
    1519                 :                     pabyUncompressedNew = (GByte*)VSIRealloc(psCtxt->pabyUncompressed,
    1520              18 :                                         psCtxt->nUncompressedAllocated + EXTRA_BYTES);
    1521              18 :                     if( pabyUncompressedNew == NULL )
    1522               0 :                         GOTO_END_ERROR;
    1523              18 :                     psCtxt->pabyUncompressed = pabyUncompressedNew;
    1524                 :                 }
    1525              38 :                 memset(psCtxt->pabyUncompressed + nUncompressedSize, 0, EXTRA_BYTES);
    1526                 : 
    1527                 :                 /* printf("inflate %d -> %d\n", nZlibCompressedSize, nUncompressedSize); */
    1528                 : 
    1529              38 :                 sStream.next_in   = pabyData;
    1530              38 :                 sStream.avail_in  = nZlibCompressedSize;
    1531              38 :                 sStream.zalloc = NULL;
    1532              38 :                 sStream.zfree = NULL;
    1533              38 :                 sStream.opaque = NULL;
    1534              38 :                 if( inflateInit(&sStream) != Z_OK )
    1535               0 :                     GOTO_END_ERROR;
    1536                 : 
    1537              38 :                 sStream.next_out  = psCtxt->pabyUncompressed;
    1538              38 :                 sStream.avail_out = nUncompressedSize;
    1539              38 :                 nStatus = inflate(&sStream, Z_FINISH);
    1540                 : 
    1541              38 :                 inflateEnd(&sStream);
    1542                 : 
    1543              38 :                 if (nStatus != Z_OK && nStatus != Z_STREAM_END)
    1544               0 :                     GOTO_END_ERROR;
    1545                 : 
    1546              38 :                 if (eType == BLOB_OSMHEADER)
    1547                 :                 {
    1548                 :                     bRet = ReadOSMHeader(psCtxt->pabyUncompressed,
    1549                 :                                          psCtxt->pabyUncompressed + nUncompressedSize,
    1550              19 :                                          psCtxt);
    1551                 :                 }
    1552              19 :                 else if (eType == BLOB_OSMDATA)
    1553                 :                 {
    1554                 :                     bRet = ReadPrimitiveBlock(psCtxt->pabyUncompressed,
    1555                 :                                               psCtxt->pabyUncompressed + nUncompressedSize,
    1556              19 :                                               psCtxt);
    1557                 :                 }
    1558                 :             }
    1559                 : 
    1560              38 :             pabyData += nZlibCompressedSize;
    1561                 :         }
    1562                 :         else
    1563                 :         {
    1564               0 :             SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
    1565                 :         }
    1566                 :     }
    1567                 : 
    1568              38 :     return bRet;
    1569                 : 
    1570                 : end_error:
    1571               0 :     return FALSE;
    1572                 : }
    1573                 : 
    1574                 : /************************************************************************/
    1575                 : /*                        EmptyNotifyNodesFunc()                        */
    1576                 : /************************************************************************/
    1577                 : 
    1578               0 : static void EmptyNotifyNodesFunc(unsigned int nNodes, OSMNode* pasNodes,
    1579                 :                                  OSMContext* psCtxt, void* user_data)
    1580                 : {
    1581               0 : }
    1582                 : 
    1583                 : 
    1584                 : /************************************************************************/
    1585                 : /*                         EmptyNotifyWayFunc()                         */
    1586                 : /************************************************************************/
    1587                 : 
    1588               0 : static void EmptyNotifyWayFunc(OSMWay* psWay,
    1589                 :                                OSMContext* psCtxt, void* user_data)
    1590                 : {
    1591               0 : }
    1592                 : 
    1593                 : /************************************************************************/
    1594                 : /*                       EmptyNotifyRelationFunc()                      */
    1595                 : /************************************************************************/
    1596                 : 
    1597               0 : static void EmptyNotifyRelationFunc(OSMRelation* psRelation,
    1598                 :                                     OSMContext* psCtxt, void* user_data)
    1599                 : {
    1600               0 : }
    1601                 : 
    1602                 : /************************************************************************/
    1603                 : /*                         EmptyNotifyBoundsFunc()                      */
    1604                 : /************************************************************************/
    1605                 : 
    1606               0 : static void EmptyNotifyBoundsFunc( double dfXMin, double dfYMin,
    1607                 :                                    double dfXMax, double dfYMax,
    1608                 :                                    OSMContext* psCtxt, void* user_data )
    1609                 : {
    1610               0 : }
    1611                 : 
    1612                 : #ifdef HAVE_EXPAT
    1613                 : 
    1614                 : /************************************************************************/
    1615                 : /*                          OSM_AddString()                             */
    1616                 : /************************************************************************/
    1617                 : 
    1618              85 : static const char* OSM_AddString(OSMContext* psCtxt, const char* pszStr)
    1619                 : {
    1620                 :     char* pszRet;
    1621              85 :     int nLen = (int)strlen(pszStr);
    1622              85 :     if( psCtxt->nStrLength + nLen + 1 > psCtxt->nStrAllocated )
    1623                 :     {
    1624               0 :         CPLError(CE_Failure, CPLE_AppDefined, "String buffer too small");
    1625               0 :         return "";
    1626                 :     }
    1627              85 :     pszRet = psCtxt->pszStrBuf + psCtxt->nStrLength;
    1628              85 :     memcpy(pszRet, pszStr, nLen);
    1629              85 :     pszRet[nLen] = '\0';
    1630              85 :     psCtxt->nStrLength += nLen + 1;
    1631              85 :     return pszRet;
    1632                 : }
    1633                 : 
    1634                 : 
    1635                 : /************************************************************************/
    1636                 : /*                            OSM_Atoi64()                              */
    1637                 : /************************************************************************/
    1638                 : 
    1639              83 : static GIntBig OSM_Atoi64( const char *pszString )
    1640                 : {
    1641                 :     GIntBig    iValue;
    1642                 : 
    1643                 : #if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
    1644                 :     iValue = (GIntBig)_atoi64( pszString );
    1645                 : # elif HAVE_ATOLL
    1646              83 :     iValue = atoll( pszString );
    1647                 : #else
    1648                 :     iValue = atol( pszString );
    1649                 : #endif
    1650                 : 
    1651              83 :     return iValue;
    1652                 : }
    1653                 : 
    1654                 : /************************************************************************/
    1655                 : /*                      OSM_XML_startElementCbk()                       */
    1656                 : /************************************************************************/
    1657                 : 
    1658              79 : static void XMLCALL OSM_XML_startElementCbk(void *pUserData, const char *pszName,
    1659                 :                                             const char **ppszAttr)
    1660                 : {
    1661              79 :     OSMContext* psCtxt = (OSMContext*) pUserData;
    1662              79 :     const char** ppszIter = ppszAttr;
    1663                 : 
    1664              79 :     if (psCtxt->bStopParsing) return;
    1665                 : 
    1666              79 :     psCtxt->nWithoutEventCounter = 0;
    1667                 : 
    1668              79 :     if( psCtxt->bTryToFetchBounds )
    1669                 :     {
    1670               2 :         if( strcmp(pszName, "bounds") == 0 ||
    1671                 :             strcmp(pszName, "bound") == 0 /* osmosis uses bound */ )
    1672                 :         {
    1673               1 :             int nCountCoords = 0;
    1674                 : 
    1675               1 :             psCtxt->bTryToFetchBounds = FALSE;
    1676                 : 
    1677               1 :             if( ppszIter )
    1678                 :             {
    1679               6 :                 while( ppszIter[0] != NULL )
    1680                 :                 {
    1681               4 :                     if( strcmp(ppszIter[0], "minlon") == 0 )
    1682                 :                     {
    1683               1 :                         psCtxt->dfLeft = CPLAtof( ppszIter[1] );
    1684               1 :                         nCountCoords ++;
    1685                 :                     }
    1686               3 :                     else if( strcmp(ppszIter[0], "minlat") == 0 )
    1687                 :                     {
    1688               1 :                         psCtxt->dfBottom = CPLAtof( ppszIter[1] );
    1689               1 :                         nCountCoords ++;
    1690                 :                     }
    1691               2 :                     else if( strcmp(ppszIter[0], "maxlon") == 0 )
    1692                 :                     {
    1693               1 :                         psCtxt->dfRight = CPLAtof( ppszIter[1] );
    1694               1 :                         nCountCoords ++;
    1695                 :                     }
    1696               1 :                     else if( strcmp(ppszIter[0], "maxlat") == 0 )
    1697                 :                     {
    1698               1 :                         psCtxt->dfTop = CPLAtof( ppszIter[1] );
    1699               1 :                         nCountCoords ++;
    1700                 :                     }
    1701               0 :                     else if( strcmp(ppszIter[0], "box") == 0  /* osmosis uses box */ )
    1702                 :                     {
    1703               0 :                         char** papszTokens = CSLTokenizeString2( ppszIter[1], ",", 0 );
    1704               0 :                         if( CSLCount(papszTokens) == 4 )
    1705                 :                         {
    1706               0 :                             psCtxt->dfBottom = CPLAtof( papszTokens[0] );
    1707               0 :                             psCtxt->dfLeft = CPLAtof( papszTokens[1] );
    1708               0 :                             psCtxt->dfTop = CPLAtof( papszTokens[2] );
    1709               0 :                             psCtxt->dfRight = CPLAtof( papszTokens[3] );
    1710               0 :                             nCountCoords = 4;
    1711                 :                         }
    1712               0 :                         CSLDestroy(papszTokens);
    1713                 :                     }
    1714               4 :                     ppszIter += 2;
    1715                 :                 }
    1716                 :             }
    1717                 : 
    1718               1 :             if( nCountCoords == 4 )
    1719                 :             {
    1720                 :                 psCtxt->pfnNotifyBounds(psCtxt->dfLeft, psCtxt->dfBottom,
    1721                 :                                         psCtxt->dfRight, psCtxt->dfTop,
    1722               1 :                                         psCtxt, psCtxt->user_data);
    1723                 :             }
    1724                 :         }
    1725                 :     }
    1726                 : 
    1727              88 :     if( !psCtxt->bInNode && !psCtxt->bInWay && !psCtxt->bInRelation &&
    1728                 :         strcmp(pszName, "node") == 0 )
    1729                 :     {
    1730               9 :         psCtxt->bInNode = TRUE;
    1731               9 :         psCtxt->bTryToFetchBounds = FALSE;
    1732                 : 
    1733               9 :         psCtxt->nStrLength = 0;
    1734               9 :         psCtxt->pszStrBuf[0] = '\0';
    1735               9 :         psCtxt->nTags = 0;
    1736                 : 
    1737               9 :         memset( &(psCtxt->pasNodes[0]), 0, sizeof(OSMNode) );
    1738               9 :         psCtxt->pasNodes[0].sInfo.pszUserSID = "";
    1739                 : 
    1740               9 :         if( ppszIter )
    1741                 :         {
    1742              90 :             while( ppszIter[0] != NULL )
    1743                 :             {
    1744              72 :                 if( strcmp(ppszIter[0], "id") == 0 )
    1745                 :                 {
    1746               9 :                     psCtxt->pasNodes[0].nID = OSM_Atoi64( ppszIter[1] );
    1747                 :                 }
    1748              63 :                 else if( strcmp(ppszIter[0], "lat") == 0 )
    1749                 :                 {
    1750               9 :                     psCtxt->pasNodes[0].dfLat = CPLAtof( ppszIter[1] );
    1751                 :                 }
    1752              54 :                 else if( strcmp(ppszIter[0], "lon") == 0 )
    1753                 :                 {
    1754               9 :                     psCtxt->pasNodes[0].dfLon = CPLAtof( ppszIter[1] );
    1755                 :                 }
    1756              45 :                 else if( strcmp(ppszIter[0], "version") == 0 )
    1757                 :                 {
    1758               9 :                     psCtxt->pasNodes[0].sInfo.nVersion = atoi( ppszIter[1] );
    1759                 :                 }
    1760              36 :                 else if( strcmp(ppszIter[0], "changeset") == 0 )
    1761                 :                 {
    1762               9 :                     psCtxt->pasNodes[0].sInfo.nChangeset = OSM_Atoi64( ppszIter[1] );
    1763                 :                 }
    1764              27 :                 else if( strcmp(ppszIter[0], "user") == 0 )
    1765                 :                 {
    1766               9 :                     psCtxt->pasNodes[0].sInfo.pszUserSID = OSM_AddString(psCtxt, ppszIter[1]);
    1767                 :                 }
    1768              18 :                 else if( strcmp(ppszIter[0], "uid") == 0 )
    1769                 :                 {
    1770               9 :                     psCtxt->pasNodes[0].sInfo.nUID = atoi( ppszIter[1] );
    1771                 :                 }
    1772               9 :                 else if( strcmp(ppszIter[0], "timestamp") == 0 )
    1773                 :                 {
    1774               9 :                     psCtxt->pasNodes[0].sInfo.ts.pszTimeStamp = OSM_AddString(psCtxt, ppszIter[1]);
    1775               9 :                     psCtxt->pasNodes[0].sInfo.bTimeStampIsStr = 1;
    1776                 :                 }
    1777              72 :                 ppszIter += 2;
    1778                 :             }
    1779                 :         }
    1780                 :     }
    1781                 : 
    1782              78 :     else if( !psCtxt->bInNode && !psCtxt->bInWay && !psCtxt->bInRelation &&
    1783                 :              strcmp(pszName, "way") == 0 )
    1784                 :     {
    1785               8 :         psCtxt->bInWay = TRUE;
    1786                 : 
    1787               8 :         psCtxt->nStrLength = 0;
    1788               8 :         psCtxt->pszStrBuf[0] = '\0';
    1789               8 :         psCtxt->nTags = 0;
    1790                 : 
    1791               8 :         memset( &(psCtxt->sWay), 0, sizeof(OSMWay) );
    1792               8 :         psCtxt->sWay.sInfo.pszUserSID = "";
    1793                 : 
    1794               8 :         if( ppszIter )
    1795                 :         {
    1796              64 :             while( ppszIter[0] != NULL )
    1797                 :             {
    1798              48 :                 if( strcmp(ppszIter[0], "id") == 0 )
    1799                 :                 {
    1800               8 :                     psCtxt->sWay.nID = OSM_Atoi64( ppszIter[1] );
    1801                 :                 }
    1802              40 :                 else if( strcmp(ppszIter[0], "version") == 0 )
    1803                 :                 {
    1804               8 :                     psCtxt->sWay.sInfo.nVersion = atoi( ppszIter[1] );
    1805                 :                 }
    1806              32 :                 else if( strcmp(ppszIter[0], "changeset") == 0 )
    1807                 :                 {
    1808               8 :                     psCtxt->sWay.sInfo.nChangeset = OSM_Atoi64( ppszIter[1] );
    1809                 :                 }
    1810              24 :                 else if( strcmp(ppszIter[0], "user") == 0 )
    1811                 :                 {
    1812               8 :                     psCtxt->sWay.sInfo.pszUserSID = OSM_AddString(psCtxt, ppszIter[1]);
    1813                 :                 }
    1814              16 :                 else if( strcmp(ppszIter[0], "uid") == 0 )
    1815                 :                 {
    1816               8 :                     psCtxt->sWay.sInfo.nUID = atoi( ppszIter[1] );
    1817                 :                 }
    1818               8 :                 else if( strcmp(ppszIter[0], "timestamp") == 0 )
    1819                 :                 {
    1820               8 :                     psCtxt->sWay.sInfo.ts.pszTimeStamp = OSM_AddString(psCtxt, ppszIter[1]);
    1821               8 :                     psCtxt->sWay.sInfo.bTimeStampIsStr = 1;
    1822                 :                 }
    1823              48 :                 ppszIter += 2;
    1824                 :             }
    1825                 :         }
    1826                 :     }
    1827                 : 
    1828              67 :     else if( !psCtxt->bInNode && !psCtxt->bInWay && !psCtxt->bInRelation &&
    1829                 :              strcmp(pszName, "relation") == 0 )
    1830                 :     {
    1831               5 :         psCtxt->bInRelation = TRUE;
    1832                 : 
    1833               5 :         psCtxt->nStrLength = 0;
    1834               5 :         psCtxt->pszStrBuf[0] = '\0';
    1835               5 :         psCtxt->nTags = 0;
    1836                 : 
    1837               5 :         memset( &(psCtxt->sRelation), 0, sizeof(OSMRelation) );
    1838               5 :         psCtxt->sRelation.sInfo.pszUserSID = "";
    1839                 : 
    1840               5 :         if( ppszIter )
    1841                 :         {
    1842              40 :             while( ppszIter[0] != NULL )
    1843                 :             {
    1844              30 :                 if( strcmp(ppszIter[0], "id") == 0 )
    1845                 :                 {
    1846               5 :                     psCtxt->sRelation.nID = OSM_Atoi64( ppszIter[1] );
    1847                 :                 }
    1848              25 :                 else if( strcmp(ppszIter[0], "version") == 0 )
    1849                 :                 {
    1850               5 :                     psCtxt->sRelation.sInfo.nVersion = atoi( ppszIter[1] );
    1851                 :                 }
    1852              20 :                 else if( strcmp(ppszIter[0], "changeset") == 0 )
    1853                 :                 {
    1854               5 :                     psCtxt->sRelation.sInfo.nChangeset = OSM_Atoi64( ppszIter[1] );
    1855                 :                 }
    1856              15 :                 else if( strcmp(ppszIter[0], "user") == 0 )
    1857                 :                 {
    1858               5 :                     psCtxt->sRelation.sInfo.pszUserSID = OSM_AddString(psCtxt, ppszIter[1]);
    1859                 :                 }
    1860              10 :                 else if( strcmp(ppszIter[0], "uid") == 0 )
    1861                 :                 {
    1862               5 :                     psCtxt->sRelation.sInfo.nUID = atoi( ppszIter[1] );
    1863                 :                 }
    1864               5 :                 else if( strcmp(ppszIter[0], "timestamp") == 0 )
    1865                 :                 {
    1866               5 :                     psCtxt->sRelation.sInfo.ts.pszTimeStamp = OSM_AddString(psCtxt, ppszIter[1]);
    1867               5 :                     psCtxt->sRelation.sInfo.bTimeStampIsStr = 1;
    1868                 : 
    1869                 :                 }
    1870              30 :                 ppszIter += 2;
    1871                 :             }
    1872                 :         }
    1873                 :     }
    1874                 : 
    1875              87 :     else if( psCtxt->bInWay &&
    1876                 :              strcmp(pszName, "nd") == 0 )
    1877                 :     {
    1878              30 :         if( ppszAttr != NULL && ppszAttr[0] != NULL &&
    1879                 :             strcmp(ppszAttr[0], "ref") == 0 )
    1880                 :         {
    1881              30 :             if( psCtxt->sWay.nRefs < psCtxt->nNodeRefsAllocated )
    1882                 :             {
    1883              30 :                 psCtxt->panNodeRefs[psCtxt->sWay.nRefs] = OSM_Atoi64( ppszAttr[1] );
    1884              30 :                 psCtxt->sWay.nRefs ++;
    1885                 :             }
    1886                 :             else
    1887                 :             {
    1888                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1889                 :                          "Too many nodes referenced in way " CPL_FRMT_GIB,
    1890               0 :                          psCtxt->sWay.nID);
    1891                 :             }
    1892                 :         }
    1893                 :     }
    1894                 : 
    1895              36 :     else if( psCtxt->bInRelation &&
    1896                 :              strcmp(pszName, "member") == 0 )
    1897                 :     {
    1898               9 :         if( psCtxt->sRelation.nMembers < psCtxt->nMembersAllocated )
    1899                 :         {
    1900               9 :             OSMMember* psMember = &(psCtxt->pasMembers[psCtxt->sRelation.nMembers]);
    1901               9 :             psCtxt->sRelation.nMembers ++;
    1902                 : 
    1903               9 :             psMember->nID = 0;
    1904               9 :             psMember->pszRole = "";
    1905               9 :             psMember->eType = MEMBER_NODE;
    1906                 : 
    1907               9 :             if( ppszIter )
    1908                 :             {
    1909              45 :                 while( ppszIter[0] != NULL )
    1910                 :                 {
    1911              27 :                     if( strcmp(ppszIter[0], "ref") == 0 )
    1912                 :                     {
    1913               9 :                         psMember->nID = OSM_Atoi64( ppszIter[1] );
    1914                 :                     }
    1915              18 :                     else if( strcmp(ppszIter[0], "type") == 0 )
    1916                 :                     {
    1917               9 :                         if( strcmp( ppszIter[1], "node") == 0 )
    1918               1 :                             psMember->eType = MEMBER_NODE;
    1919               8 :                         else if( strcmp( ppszIter[1], "way") == 0 )
    1920               8 :                             psMember->eType = MEMBER_WAY;
    1921               0 :                         else if( strcmp( ppszIter[1], "relation") == 0 )
    1922               0 :                             psMember->eType = MEMBER_RELATION;
    1923                 :                     }
    1924               9 :                     else if( strcmp(ppszIter[0], "role") == 0 )
    1925                 :                     {
    1926               9 :                         psMember->pszRole = OSM_AddString(psCtxt, ppszIter[1]);
    1927                 :                     }
    1928              27 :                     ppszIter += 2;
    1929                 :                 }
    1930                 :             }
    1931                 :         }
    1932                 :         else
    1933                 :         {
    1934                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1935                 :                      "Too many members referenced in relation " CPL_FRMT_GIB,
    1936               0 :                      psCtxt->sRelation.nID);
    1937                 :         }
    1938                 :     }
    1939              18 :     else if( (psCtxt->bInNode || psCtxt->bInWay || psCtxt->bInRelation) &&
    1940                 :              strcmp(pszName, "tag") == 0 )
    1941                 :     {
    1942              16 :         if( psCtxt->nTags < psCtxt->nTagsAllocated )
    1943                 :         {
    1944              16 :             OSMTag* psTag = &(psCtxt->pasTags[psCtxt->nTags]);
    1945              16 :             psCtxt->nTags ++;
    1946                 : 
    1947              16 :             psTag->pszK = "";
    1948              16 :             psTag->pszV = "";
    1949                 : 
    1950              16 :             if( ppszIter )
    1951                 :             {
    1952              64 :                 while( ppszIter[0] != NULL )
    1953                 :                 {
    1954              32 :                     if( ppszIter[0][0] == 'k' )
    1955                 :                     {
    1956              16 :                         psTag->pszK = OSM_AddString(psCtxt, ppszIter[1]);
    1957                 :                     }
    1958              16 :                     else if( ppszIter[0][0] == 'v' )
    1959                 :                     {
    1960              16 :                         psTag->pszV = OSM_AddString(psCtxt, ppszIter[1]);
    1961                 :                     }
    1962              32 :                     ppszIter += 2;
    1963                 :                 }
    1964                 :             }
    1965                 :         }
    1966                 :         else
    1967                 :         {
    1968               0 :             if (psCtxt->bInNode)
    1969                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1970                 :                         "Too many tags in node " CPL_FRMT_GIB,
    1971               0 :                          psCtxt->pasNodes[0].nID);
    1972               0 :             else if (psCtxt->bInWay)
    1973                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1974                 :                         "Too many tags in way " CPL_FRMT_GIB,
    1975               0 :                          psCtxt->sWay.nID);
    1976               0 :             else if (psCtxt->bInRelation)
    1977                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1978                 :                         "Too many tags in relation " CPL_FRMT_GIB,
    1979               0 :                          psCtxt->sRelation.nID);
    1980                 :         }
    1981                 :     }
    1982                 : }
    1983                 : 
    1984                 : /************************************************************************/
    1985                 : /*                       OSM_XML_endElementCbk()                        */
    1986                 : /************************************************************************/
    1987                 : 
    1988              79 : static void XMLCALL OSM_XML_endElementCbk(void *pUserData, const char *pszName)
    1989                 : {
    1990              79 :     OSMContext* psCtxt = (OSMContext*) pUserData;
    1991                 : 
    1992              79 :     if (psCtxt->bStopParsing) return;
    1993                 : 
    1994              79 :     psCtxt->nWithoutEventCounter = 0;
    1995                 : 
    1996              88 :     if( psCtxt->bInNode && strcmp(pszName, "node") == 0 )
    1997                 :     {
    1998               9 :         psCtxt->pasNodes[0].nTags = psCtxt->nTags;
    1999               9 :         psCtxt->pasNodes[0].pasTags = psCtxt->pasTags;
    2000                 : 
    2001               9 :         psCtxt->pfnNotifyNodes(1, psCtxt->pasNodes, psCtxt, psCtxt->user_data);
    2002                 : 
    2003               9 :         psCtxt->bHasFoundFeature = TRUE;
    2004                 : 
    2005               9 :         psCtxt->bInNode = FALSE;
    2006                 :     }
    2007                 : 
    2008                 :     else
    2009              78 :     if( psCtxt->bInWay && strcmp(pszName, "way") == 0 )
    2010                 :     {
    2011               8 :         psCtxt->sWay.nTags = psCtxt->nTags;
    2012               8 :         psCtxt->sWay.pasTags = psCtxt->pasTags;
    2013                 : 
    2014               8 :         psCtxt->sWay.panNodeRefs = psCtxt->panNodeRefs;
    2015                 : 
    2016               8 :         psCtxt->pfnNotifyWay(&(psCtxt->sWay), psCtxt, psCtxt->user_data);
    2017                 : 
    2018               8 :         psCtxt->bHasFoundFeature = TRUE;
    2019                 : 
    2020               8 :         psCtxt->bInWay = FALSE;
    2021                 :     }
    2022                 : 
    2023                 :     else
    2024              62 :     if( psCtxt->bInRelation && strcmp(pszName, "relation") == 0 )
    2025                 :     {
    2026               5 :         psCtxt->sRelation.nTags = psCtxt->nTags;
    2027               5 :         psCtxt->sRelation.pasTags = psCtxt->pasTags;
    2028                 : 
    2029               5 :         psCtxt->sRelation.pasMembers = psCtxt->pasMembers;
    2030                 : 
    2031               5 :         psCtxt->pfnNotifyRelation(&(psCtxt->sRelation), psCtxt, psCtxt->user_data);
    2032                 : 
    2033               5 :         psCtxt->bHasFoundFeature = TRUE;
    2034                 : 
    2035               5 :         psCtxt->bInRelation = FALSE;
    2036                 :     }
    2037                 : }
    2038                 : /************************************************************************/
    2039                 : /*                           dataHandlerCbk()                           */
    2040                 : /************************************************************************/
    2041                 : 
    2042             194 : static void XMLCALL OSM_XML_dataHandlerCbk(void *pUserData, const char *data, int nLen)
    2043                 : {
    2044             194 :     OSMContext* psCtxt = (OSMContext*) pUserData;
    2045                 : 
    2046             194 :     if (psCtxt->bStopParsing) return;
    2047                 : 
    2048             194 :     psCtxt->nWithoutEventCounter = 0;
    2049                 : 
    2050             194 :     psCtxt->nDataHandlerCounter ++;
    2051             194 :     if (psCtxt->nDataHandlerCounter >= XML_BUFSIZE)
    2052                 :     {
    2053                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2054               0 :                  "File probably corrupted (million laugh pattern)");
    2055               0 :         XML_StopParser(psCtxt->hXMLParser, XML_FALSE);
    2056               0 :         psCtxt->bStopParsing = TRUE;
    2057               0 :         return;
    2058                 :     }
    2059                 : }
    2060                 : 
    2061                 : /************************************************************************/
    2062                 : /*                          XML_ProcessBlock()                          */
    2063                 : /************************************************************************/
    2064                 : 
    2065               2 : static OSMRetCode XML_ProcessBlock(OSMContext* psCtxt)
    2066                 : {
    2067               2 :     if( psCtxt->bEOF )
    2068               1 :         return OSM_EOF;
    2069               1 :     if( psCtxt->bStopParsing )
    2070               0 :         return OSM_ERROR;
    2071                 : 
    2072               1 :     psCtxt->bHasFoundFeature = FALSE;
    2073               1 :     psCtxt->nWithoutEventCounter = 0;
    2074                 : 
    2075               1 :     do
    2076                 :     {
    2077                 :         int eErr;
    2078                 :         unsigned int nLen;
    2079                 : 
    2080               1 :         psCtxt->nDataHandlerCounter = 0;
    2081                 : 
    2082                 :         nLen = (unsigned int)VSIFReadL( psCtxt->pabyBlob, 1,
    2083               1 :                                         XML_BUFSIZE, psCtxt->fp );
    2084                 : 
    2085               1 :         psCtxt->nBytesRead += nLen;
    2086                 : 
    2087               1 :         psCtxt->bEOF = VSIFEofL(psCtxt->fp);
    2088                 :         eErr = XML_Parse(psCtxt->hXMLParser, (const char*) psCtxt->pabyBlob,
    2089               1 :                          nLen, psCtxt->bEOF );
    2090                 : 
    2091               1 :         if (eErr == XML_STATUS_ERROR)
    2092                 :         {
    2093                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2094                 :                      "XML parsing of OSM file failed : %s "
    2095                 :                      "at line %d, column %d",
    2096                 :                      XML_ErrorString(XML_GetErrorCode(psCtxt->hXMLParser)),
    2097                 :                      (int)XML_GetCurrentLineNumber(psCtxt->hXMLParser),
    2098               0 :                      (int)XML_GetCurrentColumnNumber(psCtxt->hXMLParser));
    2099               0 :             psCtxt->bStopParsing = TRUE;
    2100                 :         }
    2101               1 :         psCtxt->nWithoutEventCounter ++;
    2102                 :     } while (!psCtxt->bEOF && !psCtxt->bStopParsing &&
    2103                 :              psCtxt->bHasFoundFeature == FALSE &&
    2104                 :              psCtxt->nWithoutEventCounter < 10);
    2105                 : 
    2106               1 :     if (psCtxt->nWithoutEventCounter == 10)
    2107                 :     {
    2108                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2109               0 :                  "Too much data inside one element. File probably corrupted");
    2110               0 :         psCtxt->bStopParsing = TRUE;
    2111                 :     }
    2112                 : 
    2113               1 :     return psCtxt->bStopParsing ? OSM_ERROR : psCtxt->bEOF ? OSM_EOF : OSM_OK;
    2114                 : }
    2115                 : 
    2116                 : #endif
    2117                 : 
    2118                 : /************************************************************************/
    2119                 : /*                              OSM_Open()                              */
    2120                 : /************************************************************************/
    2121                 : 
    2122              10 : OSMContext* OSM_Open( const char* pszFilename,
    2123                 :                       NotifyNodesFunc pfnNotifyNodes,
    2124                 :                       NotifyWayFunc pfnNotifyWay,
    2125                 :                       NotifyRelationFunc pfnNotifyRelation,
    2126                 :                       NotifyBoundsFunc pfnNotifyBounds,
    2127                 :                       void* user_data )
    2128                 : {
    2129                 :     OSMContext* psCtxt;
    2130                 :     GByte abyHeader[1024];
    2131                 :     int nRead;
    2132                 :     VSILFILE* fp;
    2133                 :     int i;
    2134              10 :     int bPBF = FALSE;
    2135                 : 
    2136              10 :     fp = VSIFOpenL(pszFilename, "rb");
    2137              10 :     if (fp == NULL)
    2138               0 :         return NULL;
    2139                 : 
    2140              10 :     nRead = (int)VSIFReadL(abyHeader, 1, sizeof(abyHeader)-1, fp);
    2141              10 :     abyHeader[nRead] = '\0';
    2142                 : 
    2143              10 :     if( strstr((const char*)abyHeader, "<osm") != NULL )
    2144                 :     {
    2145                 :         /* OSM XML */
    2146                 : #ifndef HAVE_EXPAT
    2147                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2148                 :                  "OSM XML detected, but Expat parser not available");
    2149                 :         VSIFCloseL(fp);
    2150                 :         return NULL;
    2151                 : #endif
    2152                 :     }
    2153                 :     else
    2154                 :     {
    2155               9 :         int nLimitI = nRead - strlen("OSMHeader");
    2156              63 :         for(i = 0; i < nLimitI; i++)
    2157                 :         {
    2158              63 :             if( memcmp(abyHeader + i, "OSMHeader", strlen("OSMHeader") ) == 0 )
    2159                 :             {
    2160               9 :                 bPBF = TRUE;
    2161               9 :                 break;
    2162                 :             }
    2163                 :         }
    2164               9 :         if( !bPBF )
    2165                 :         {
    2166               0 :             VSIFCloseL(fp);
    2167               0 :             return NULL;
    2168                 :         }
    2169                 :     }
    2170                 : 
    2171              10 :     VSIFSeekL(fp, 0, SEEK_SET);
    2172                 : 
    2173              10 :     psCtxt = (OSMContext*) VSIMalloc(sizeof(OSMContext));
    2174              10 :     if (psCtxt == NULL)
    2175                 :     {
    2176               0 :         VSIFCloseL(fp);
    2177               0 :         return NULL;
    2178                 :     }
    2179              10 :     memset(psCtxt, 0, sizeof(OSMContext));
    2180              10 :     psCtxt->bPBF = bPBF;
    2181              10 :     psCtxt->fp = fp;
    2182              10 :     psCtxt->pfnNotifyNodes = pfnNotifyNodes;
    2183              10 :     if( pfnNotifyNodes == NULL )
    2184               0 :         psCtxt->pfnNotifyNodes = EmptyNotifyNodesFunc;
    2185              10 :     psCtxt->pfnNotifyWay = pfnNotifyWay;
    2186              10 :     if( pfnNotifyWay == NULL )
    2187               0 :         psCtxt->pfnNotifyWay = EmptyNotifyWayFunc;
    2188              10 :     psCtxt->pfnNotifyRelation = pfnNotifyRelation;
    2189              10 :     if( pfnNotifyRelation == NULL )
    2190               0 :         psCtxt->pfnNotifyRelation = EmptyNotifyRelationFunc;
    2191              10 :     psCtxt->pfnNotifyBounds = pfnNotifyBounds;
    2192              10 :     if( pfnNotifyBounds == NULL )
    2193               0 :         psCtxt->pfnNotifyBounds = EmptyNotifyBoundsFunc;
    2194              10 :     psCtxt->user_data = user_data;
    2195                 : 
    2196              10 :     if( bPBF )
    2197                 :     {
    2198               9 :         psCtxt->nBlobSizeAllocated = 64 * 1024 + EXTRA_BYTES;
    2199                 :     }
    2200                 : #ifdef HAVE_EXPAT
    2201                 :     else
    2202                 :     {
    2203               1 :         psCtxt->nBlobSizeAllocated = XML_BUFSIZE;
    2204                 : 
    2205               1 :         psCtxt->nStrAllocated = 65536;
    2206               1 :         psCtxt->pszStrBuf = (char*) VSIMalloc(psCtxt->nStrAllocated);
    2207               1 :         if( psCtxt->pszStrBuf )
    2208               1 :             psCtxt->pszStrBuf[0] = '\0';
    2209                 : 
    2210               1 :         psCtxt->hXMLParser = OGRCreateExpatXMLParser();
    2211               1 :         XML_SetUserData(psCtxt->hXMLParser, psCtxt);
    2212                 :         XML_SetElementHandler(psCtxt->hXMLParser,
    2213                 :                               OSM_XML_startElementCbk,
    2214               1 :                               OSM_XML_endElementCbk);
    2215               1 :         XML_SetCharacterDataHandler(psCtxt->hXMLParser, OSM_XML_dataHandlerCbk);
    2216                 : 
    2217               1 :         psCtxt->bTryToFetchBounds = TRUE;
    2218                 : 
    2219               1 :         psCtxt->nNodesAllocated = 1;
    2220               1 :         psCtxt->pasNodes = (OSMNode*) VSIMalloc(sizeof(OSMNode) * psCtxt->nNodesAllocated);
    2221                 : 
    2222               1 :         psCtxt->nTagsAllocated = 256;
    2223               1 :         psCtxt->pasTags = (OSMTag*) VSIMalloc(sizeof(OSMTag) * psCtxt->nTagsAllocated);
    2224                 : 
    2225               1 :         psCtxt->nMembersAllocated = 2000;
    2226               1 :         psCtxt->pasMembers = (OSMMember*) VSIMalloc(sizeof(OSMMember) * psCtxt->nMembersAllocated);
    2227                 : 
    2228               1 :         psCtxt->nNodeRefsAllocated = 2000;
    2229               1 :         psCtxt->panNodeRefs = (GIntBig*) VSIMalloc(sizeof(GIntBig) * psCtxt->nNodeRefsAllocated);
    2230                 : 
    2231               1 :         if( psCtxt->pszStrBuf == NULL ||
    2232                 :             psCtxt->pasNodes == NULL ||
    2233                 :             psCtxt->pasTags == NULL ||
    2234                 :             psCtxt->pasMembers == NULL ||
    2235                 :             psCtxt->panNodeRefs == NULL )
    2236                 :         {
    2237               0 :             OSM_Close(psCtxt);
    2238               0 :             return NULL;
    2239                 :         }
    2240                 : 
    2241                 :     }
    2242                 : #endif
    2243                 : 
    2244              10 :     psCtxt->pabyBlob = (GByte*)VSIMalloc(psCtxt->nBlobSizeAllocated);
    2245              10 :     if( psCtxt->pabyBlob == NULL )
    2246                 :     {
    2247               0 :         OSM_Close(psCtxt);
    2248               0 :         return NULL;
    2249                 :     }
    2250                 : 
    2251              10 :     return psCtxt;
    2252                 : }
    2253                 : 
    2254                 : /************************************************************************/
    2255                 : /*                              OSM_Close()                             */
    2256                 : /************************************************************************/
    2257                 : 
    2258             134 : void OSM_Close(OSMContext* psCtxt)
    2259                 : {
    2260             134 :     if( psCtxt == NULL )
    2261             124 :         return;
    2262                 : 
    2263                 : #ifdef HAVE_EXPAT
    2264              10 :     if( !psCtxt->bPBF )
    2265                 :     {
    2266               1 :         if (psCtxt->hXMLParser)
    2267               1 :             XML_ParserFree(psCtxt->hXMLParser);
    2268                 : 
    2269               1 :         CPLFree(psCtxt->pszStrBuf); /* only for XML case ! */
    2270                 :     }
    2271                 : #endif
    2272                 : 
    2273              10 :     VSIFree(psCtxt->pabyBlob);
    2274              10 :     VSIFree(psCtxt->pabyUncompressed);
    2275              10 :     VSIFree(psCtxt->panStrOff);
    2276              10 :     VSIFree(psCtxt->pasNodes);
    2277              10 :     VSIFree(psCtxt->pasTags);
    2278              10 :     VSIFree(psCtxt->pasMembers);
    2279              10 :     VSIFree(psCtxt->panNodeRefs);
    2280                 : 
    2281              10 :     VSIFCloseL(psCtxt->fp);
    2282              10 :     VSIFree(psCtxt);
    2283                 : }
    2284                 : /************************************************************************/
    2285                 : /*                          OSM_ResetReading()                          */
    2286                 : /************************************************************************/
    2287                 : 
    2288              23 : void OSM_ResetReading( OSMContext* psCtxt )
    2289                 : {
    2290              23 :     VSIFSeekL(psCtxt->fp, 0, SEEK_SET);
    2291                 : 
    2292              23 :     psCtxt->nBytesRead = 0;
    2293                 : 
    2294                 : #ifdef HAVE_EXPAT
    2295              23 :     if( !psCtxt->bPBF )
    2296                 :     {
    2297               0 :         XML_ParserFree(psCtxt->hXMLParser);
    2298               0 :         psCtxt->hXMLParser = OGRCreateExpatXMLParser();
    2299               0 :         XML_SetUserData(psCtxt->hXMLParser, psCtxt);
    2300                 :         XML_SetElementHandler(psCtxt->hXMLParser,
    2301                 :                               OSM_XML_startElementCbk,
    2302               0 :                               OSM_XML_endElementCbk);
    2303               0 :         XML_SetCharacterDataHandler(psCtxt->hXMLParser, OSM_XML_dataHandlerCbk);
    2304               0 :         psCtxt->bEOF = FALSE;
    2305               0 :         psCtxt->bStopParsing = FALSE;
    2306               0 :         psCtxt->nStrLength = 0;
    2307               0 :         psCtxt->pszStrBuf[0] = '\0';
    2308               0 :         psCtxt->nTags = 0;
    2309                 : 
    2310               0 :         psCtxt->bTryToFetchBounds = TRUE;
    2311               0 :         psCtxt->bInNode = FALSE;
    2312               0 :         psCtxt->bInWay = FALSE;
    2313               0 :         psCtxt->bInRelation = FALSE;
    2314                 :     }
    2315                 : #endif
    2316              23 : }
    2317                 : 
    2318                 : /************************************************************************/
    2319                 : /*                          OSM_ProcessBlock()                          */
    2320                 : /************************************************************************/
    2321                 : 
    2322              48 : static OSMRetCode PBF_ProcessBlock(OSMContext* psCtxt)
    2323                 : {
    2324              48 :     int nRet = FALSE;
    2325                 :     GByte abyHeaderSize[4];
    2326                 :     unsigned int nHeaderSize;
    2327              48 :     unsigned int nBlobSize = 0;
    2328                 :     BlobType eType;
    2329                 : 
    2330              48 :     if (VSIFReadL(abyHeaderSize, 4, 1, psCtxt->fp) != 1)
    2331                 :     {
    2332              10 :         return OSM_EOF;
    2333                 :     }
    2334              76 :     nHeaderSize = (abyHeaderSize[0] << 24) | (abyHeaderSize[1] << 16) |
    2335              76 :                     (abyHeaderSize[2] << 8) | abyHeaderSize[3];
    2336                 : 
    2337              38 :     psCtxt->nBytesRead += 4;
    2338                 : 
    2339                 :     /* printf("nHeaderSize = %d\n", nHeaderSize); */
    2340              38 :     if (nHeaderSize > 64 * 1024)
    2341               0 :         GOTO_END_ERROR;
    2342              38 :     if (VSIFReadL(psCtxt->pabyBlob, 1, nHeaderSize, psCtxt->fp) != nHeaderSize)
    2343               0 :         GOTO_END_ERROR;
    2344                 : 
    2345              38 :     psCtxt->nBytesRead += nHeaderSize;
    2346                 : 
    2347              38 :     memset(psCtxt->pabyBlob + nHeaderSize, 0, EXTRA_BYTES);
    2348              38 :     nRet = ReadBlobHeader(psCtxt->pabyBlob, psCtxt->pabyBlob + nHeaderSize, &nBlobSize, &eType);
    2349              38 :     if (!nRet || eType == BLOB_UNKNOW)
    2350                 :         GOTO_END_ERROR;
    2351                 : 
    2352              38 :     if (nBlobSize > 64*1024*1024)
    2353               0 :         GOTO_END_ERROR;
    2354              38 :     if (nBlobSize > psCtxt->nBlobSizeAllocated)
    2355                 :     {
    2356                 :         GByte* pabyBlobNew;
    2357               0 :         psCtxt->nBlobSizeAllocated = MAX(psCtxt->nBlobSizeAllocated * 2, nBlobSize);
    2358                 :         pabyBlobNew = (GByte*)VSIRealloc(psCtxt->pabyBlob,
    2359               0 :                                         psCtxt->nBlobSizeAllocated + EXTRA_BYTES);
    2360               0 :         if( pabyBlobNew == NULL )
    2361               0 :             GOTO_END_ERROR;
    2362               0 :         psCtxt->pabyBlob = pabyBlobNew;
    2363                 :     }
    2364              38 :     if (VSIFReadL(psCtxt->pabyBlob, 1, nBlobSize, psCtxt->fp) != nBlobSize)
    2365               0 :         GOTO_END_ERROR;
    2366                 : 
    2367              38 :     psCtxt->nBytesRead += nBlobSize;
    2368                 : 
    2369              38 :     memset(psCtxt->pabyBlob + nBlobSize, 0, EXTRA_BYTES);
    2370                 :     nRet = ReadBlob(psCtxt->pabyBlob, nBlobSize, eType,
    2371              38 :                     psCtxt);
    2372              38 :     if (!nRet)
    2373               0 :         GOTO_END_ERROR;
    2374                 : 
    2375              38 :     return OSM_OK;
    2376                 : 
    2377                 : end_error:
    2378                 : 
    2379               0 :     return OSM_ERROR;
    2380                 : }
    2381                 : 
    2382                 : /************************************************************************/
    2383                 : /*                          OSM_ProcessBlock()                          */
    2384                 : /************************************************************************/
    2385                 : 
    2386              50 : OSMRetCode OSM_ProcessBlock(OSMContext* psCtxt)
    2387                 : {
    2388                 : #ifdef HAVE_EXPAT
    2389              50 :     if( psCtxt->bPBF )
    2390              48 :         return PBF_ProcessBlock(psCtxt);
    2391                 :     else
    2392               2 :         return XML_ProcessBlock(psCtxt);
    2393                 : #else
    2394                 :     return PBF_ProcessBlock(psCtxt);
    2395                 : #endif
    2396                 : }
    2397                 : 
    2398                 : /************************************************************************/
    2399                 : /*                          OSM_GetBytesRead()                          */
    2400                 : /************************************************************************/
    2401                 : 
    2402              10 : GUIntBig OSM_GetBytesRead( OSMContext* psCtxt )
    2403                 : {
    2404              10 :     return psCtxt->nBytesRead;
    2405                 : }

Generated by: LCOV version 1.7