LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/osm - osm_parser.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 971 736 75.8 %
Date: 2013-03-30 Functions: 28 23 82.1 %

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

Generated by: LCOV version 1.7