LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1492 1856 80.4 %
Date: 2025-01-18 12:42:00 Functions: 32 34 94.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRSQLiteLayer class, code shared between
       5             :  *           the direct table access, and the generic SQL results.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  *
      10             :  * Contributor: Alessandro Furieri, a.furieri@lqt.it
      11             :  * Portions of this module supporting SpatiaLite's own 3D geometries
      12             :  * [XY, XYM, XYZ and XYZM] available since v.2.4.0
      13             :  * Developed for Faunalia ( http://www.faunalia.it) with funding from
      14             :  * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
      15             :  *
      16             :  ******************************************************************************
      17             :  * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
      18             :  * Copyright (c) 2009-2021, Even Rouault <even dot rouault at spatialys.com>
      19             :  *
      20             :  * SPDX-License-Identifier: MIT
      21             :  ****************************************************************************/
      22             : 
      23             : #include "cpl_port.h"
      24             : #include "ogr_sqlite.h"
      25             : #include "ogrsqliteutility.h"
      26             : 
      27             : #include <algorithm>
      28             : #include <cassert>
      29             : #include <climits>
      30             : #include <cmath>
      31             : #include <cstddef>
      32             : #include <cstdio>
      33             : #include <cstdlib>
      34             : #include <cstring>
      35             : #include <map>
      36             : #include <set>
      37             : 
      38             : #include "cpl_conv.h"
      39             : #include "cpl_error.h"
      40             : #include "cpl_string.h"
      41             : #include "ogr_core.h"
      42             : #include "ogr_feature.h"
      43             : #include "ogr_geometry.h"
      44             : #include "ogr_spatialref.h"
      45             : #include "ogrsf_frmts.h"
      46             : #include "sqlite3.h"
      47             : 
      48             : /************************************************************************/
      49             : /*                           OGRSQLiteLayer()                           */
      50             : /************************************************************************/
      51             : 
      52        3984 : OGRSQLiteLayer::OGRSQLiteLayer(OGRSQLiteDataSource *poDSIn)
      53             :     : m_poDS(poDSIn),
      54        3984 :       m_bUseComprGeom(CPLTestBool(CPLGetConfigOption("COMPRESS_GEOM", "FALSE")))
      55             : {
      56        3984 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                          ~OGRSQLiteLayer()                           */
      60             : /************************************************************************/
      61             : 
      62        3982 : OGRSQLiteLayer::~OGRSQLiteLayer()
      63             : 
      64             : {
      65        3982 :     Finalize();
      66        3982 : }
      67             : 
      68             : /************************************************************************/
      69             : /*                               Finalize()                             */
      70             : /************************************************************************/
      71             : 
      72        4577 : void OGRSQLiteLayer::Finalize()
      73             : {
      74             :     /* Caution: this function can be called several times (see */
      75             :     /* OGRSQLiteExecuteSQLLayer::~OGRSQLiteExecuteSQLLayer()), so it must */
      76             :     /* be a no-op on second call */
      77             : 
      78        4577 :     if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
      79             :     {
      80        1520 :         CPLDebug("SQLite", CPL_FRMT_GIB " features read on layer '%s'.",
      81        1520 :                  m_nFeaturesRead, m_poFeatureDefn->GetName());
      82             :     }
      83             : 
      84        4577 :     if (m_hStmt != nullptr)
      85             :     {
      86         996 :         sqlite3_finalize(m_hStmt);
      87         996 :         m_hStmt = nullptr;
      88             :     }
      89             : 
      90        4577 :     if (m_poFeatureDefn != nullptr)
      91             :     {
      92        3126 :         m_poFeatureDefn->Release();
      93        3126 :         m_poFeatureDefn = nullptr;
      94             :     }
      95             : 
      96        4577 :     CPLFree(m_pszFIDColumn);
      97        4577 :     m_pszFIDColumn = nullptr;
      98        4577 :     CPLFree(m_panFieldOrdinals);
      99        4577 :     m_panFieldOrdinals = nullptr;
     100             : 
     101        4577 :     CSLDestroy(m_papszCompressedColumns);
     102        4577 :     m_papszCompressedColumns = nullptr;
     103        4577 : }
     104             : 
     105             : /************************************************************************/
     106             : /*                      OGRGetDateTimeFieldType()                       */
     107             : /************************************************************************/
     108             : 
     109           2 : static bool OGRGetDateTimeFieldType(const char *pszValue,
     110             :                                     OGRFieldType *pFieldType)
     111             : {
     112           2 :     bool bSuccess = false;
     113           2 :     size_t nValueLength = CPLStrnlen(pszValue, 16);
     114             : 
     115           2 :     if (nValueLength >= 5)
     116             :     {
     117             :         unsigned int nYear;
     118             :         unsigned int nMonth;
     119             :         unsigned int nDay;
     120             :         unsigned int nHour;
     121             :         unsigned int nMinute;
     122             : 
     123           2 :         if (nValueLength >= 10)
     124             :         {
     125             :             int nItemsMatched =
     126           2 :                 sscanf(pszValue, "%04u-%02u-%02u", &nYear, &nMonth, &nDay);
     127           2 :             if (nItemsMatched == 1)
     128             :                 nItemsMatched =
     129           0 :                     sscanf(pszValue, "%04u/%02u/%02u", &nYear, &nMonth, &nDay);
     130             : 
     131           2 :             if ((nItemsMatched == 3) && (nValueLength >= 16))
     132           2 :                 nItemsMatched +=
     133           2 :                     sscanf(&pszValue[11], "%02u:%02u", &nHour, &nMinute);
     134             : 
     135           2 :             if (nItemsMatched >= 3)
     136             :             {
     137           2 :                 *pFieldType = (nItemsMatched == 5) ? OFTDateTime : OFTDate;
     138           2 :                 bSuccess = true;
     139             :             }
     140             :         }
     141           0 :         else if (sscanf(pszValue, "%02u:%02u", &nHour, &nMinute) == 2)
     142             :         {
     143           0 :             *pFieldType = OFTTime;
     144           0 :             bSuccess = true;
     145             :         }
     146             :     }
     147             : 
     148           2 :     return bSuccess;
     149             : }
     150             : 
     151             : /************************************************************************/
     152             : /*                          OGRIsBinaryGeomCol()                        */
     153             : /************************************************************************/
     154             : 
     155         515 : static int OGRIsBinaryGeomCol(sqlite3_stmt *hStmt, int iCol,
     156             :                               CPL_UNUSED OGRFieldDefn &oField,
     157             :                               OGRSQLiteGeomFormat &eGeomFormat)
     158             : {
     159         515 :     OGRGeometry *poGeometry = nullptr;
     160         515 :     const int nBytes = sqlite3_column_bytes(hStmt, iCol);
     161             :     // coverity[tainted_data_return]
     162             :     const GByte *pabyBlob =
     163         515 :         reinterpret_cast<const GByte *>(sqlite3_column_blob(hStmt, iCol));
     164         515 :     int nBytesConsumed = 0;
     165         515 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     166             :     /* Try as spatialite first since createFromWkb() can sometimes */
     167             :     /* interpret spatialite blobs as WKB for certain SRID values */
     168         515 :     if (OGRSQLiteLayer::ImportSpatiaLiteGeometry(pabyBlob, nBytes,
     169         515 :                                                  &poGeometry) == OGRERR_NONE)
     170             :     {
     171         154 :         eGeomFormat = OSGF_SpatiaLite;
     172             :     }
     173         361 :     else if (OGRGeometryFactory::createFromWkb(pabyBlob, nullptr, &poGeometry,
     174         361 :                                                nBytes) == OGRERR_NONE)
     175             :     {
     176          15 :         eGeomFormat = OSGF_WKB;
     177             :     }
     178         346 :     else if (OGRGeometryFactory::createFromFgf(pabyBlob, nullptr, &poGeometry,
     179             :                                                nBytes, &nBytesConsumed) ==
     180         346 :                  OGRERR_NONE &&
     181           0 :              nBytes == nBytesConsumed)
     182             :     {
     183           0 :         eGeomFormat = OSGF_FGF;
     184             :     }
     185         515 :     CPLPopErrorHandler();
     186         515 :     CPLErrorReset();
     187         515 :     delete poGeometry;
     188         515 :     if (eGeomFormat != OSGF_None)
     189             :     {
     190         169 :         return TRUE;
     191             :     }
     192         346 :     return FALSE;
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                          BuildFeatureDefn()                          */
     197             : /*                                                                      */
     198             : /*      Build feature definition from a set of column definitions       */
     199             : /*      set on a statement.  Sift out geometry and FID fields.          */
     200             : /************************************************************************/
     201             : 
     202        2340 : void OGRSQLiteLayer::BuildFeatureDefn(const char *pszLayerName, bool bIsSelect,
     203             :                                       sqlite3_stmt *hStmtIn,
     204             :                                       const std::set<CPLString> *paosGeomCols,
     205             :                                       const std::set<CPLString> &aosIgnoredCols)
     206             : 
     207             : {
     208        2340 :     m_poFeatureDefn = new OGRSQLiteFeatureDefn(pszLayerName);
     209        2340 :     m_poFeatureDefn->SetGeomType(wkbNone);
     210        2340 :     m_poFeatureDefn->Reference();
     211             : 
     212        4680 :     std::map<std::string, std::string> oMapTableInfo;  // name to type
     213        2340 :     if (!bIsSelect)
     214             :     {
     215             :         // oField.GetNameRef() can be better than sqlite3_column_name() on views
     216         761 :         char *pszSQL = sqlite3_mprintf("PRAGMA table_info('%q')", pszLayerName);
     217        1522 :         auto oResultTable = SQLQuery(m_poDS->GetDB(), pszSQL);
     218         761 :         sqlite3_free(pszSQL);
     219         761 :         if (oResultTable && oResultTable->ColCount() == 6)
     220             :         {
     221        2250 :             for (int iRecord = 0; iRecord < oResultTable->RowCount(); iRecord++)
     222             :             {
     223        1785 :                 const char *pszName = oResultTable->GetValue(1, iRecord);
     224        1785 :                 const char *pszType = oResultTable->GetValue(2, iRecord);
     225        1785 :                 if (pszName && pszType)
     226        1785 :                     oMapTableInfo[pszName] = pszType;
     227             :             }
     228             :         }
     229             :     }
     230             : 
     231        2340 :     const int nRawColumns = sqlite3_column_count(hStmtIn);
     232             : 
     233        2340 :     m_panFieldOrdinals =
     234        2340 :         static_cast<int *>(CPLMalloc(sizeof(int) * nRawColumns));
     235             : 
     236        4680 :     std::set<std::string> oSetFields;
     237             : 
     238       12447 :     for (int iCol = 0; iCol < nRawColumns; iCol++)
     239             :     {
     240       10107 :         OGRFieldDefn oField(SQLUnescape(sqlite3_column_name(hStmtIn, iCol)),
     241       10107 :                             OFTString);
     242       10107 :         const char *pszFieldName = oField.GetNameRef();
     243             : 
     244             :         // In some cases, particularly when there is a real name for
     245             :         // the primary key/_rowid_ column we will end up getting the
     246             :         // primary key column appearing twice.  Ignore any repeated names.
     247       10107 :         if (cpl::contains(oSetFields, pszFieldName))
     248           9 :             continue;
     249             : 
     250       10098 :         if (EQUAL(pszFieldName, "OGR_NATIVE_DATA"))
     251             :         {
     252         308 :             m_iOGRNativeDataCol = iCol;
     253         308 :             continue;
     254             :         }
     255             : 
     256        9790 :         if (EQUAL(pszFieldName, "OGR_NATIVE_MEDIA_TYPE"))
     257             :         {
     258         308 :             m_iOGRNativeMediaTypeCol = iCol;
     259         308 :             continue;
     260             :         }
     261             : 
     262             :         /* In the case of Spatialite VirtualShape, the PKUID */
     263             :         /* should be considered as a primary key */
     264        9482 :         if (m_bIsVirtualShape && EQUAL(pszFieldName, "PKUID"))
     265             :         {
     266           3 :             CPLFree(m_pszFIDColumn);
     267           3 :             m_pszFIDColumn = CPLStrdup(pszFieldName);
     268             :         }
     269             : 
     270        9482 :         if (m_pszFIDColumn != nullptr && EQUAL(m_pszFIDColumn, pszFieldName))
     271        1436 :             continue;
     272             : 
     273             :         // oField.SetWidth( std::max(0,poStmt->GetColSize( iCol )) );
     274             : 
     275        8046 :         if (aosIgnoredCols.find(CPLString(pszFieldName).tolower()) !=
     276       16092 :             aosIgnoredCols.end())
     277             :         {
     278          70 :             continue;
     279             :         }
     280        9996 :         if (paosGeomCols != nullptr &&
     281        9996 :             paosGeomCols->find(CPLString(pszFieldName).tolower()) !=
     282        9996 :                 paosGeomCols->end())
     283             :         {
     284         256 :             m_poFeatureDefn->AddGeomFieldDefn(
     285         512 :                 std::make_unique<OGRSQLiteGeomFieldDefn>(pszFieldName, iCol));
     286         256 :             continue;
     287             :         }
     288             : 
     289        7720 :         const int nColType = sqlite3_column_type(hStmtIn, iCol);
     290        7720 :         switch (nColType)
     291             :         {
     292        1380 :             case SQLITE_INTEGER:
     293        1380 :                 if (CPLTestBool(CPLGetConfigOption("OGR_PROMOTE_TO_INTEGER64",
     294             :                                                    "FALSE")))
     295           0 :                     oField.SetType(OFTInteger64);
     296             :                 else
     297             :                 {
     298        1380 :                     GIntBig nVal = sqlite3_column_int64(hStmtIn, iCol);
     299        1380 :                     if (CPL_INT64_FITS_ON_INT32(nVal))
     300        1270 :                         oField.SetType(OFTInteger);
     301             :                     else
     302         110 :                         oField.SetType(OFTInteger64);
     303             :                 }
     304        1380 :                 break;
     305             : 
     306         626 :             case SQLITE_FLOAT:
     307         626 :                 oField.SetType(OFTReal);
     308         626 :                 break;
     309             : 
     310         873 :             case SQLITE_BLOB:
     311         873 :                 oField.SetType(OFTBinary);
     312         873 :                 break;
     313             : 
     314        7720 :             default:
     315             :                 /* leave it as OFTString */;
     316             :         }
     317             : 
     318        7720 :         const char *pszDeclType = sqlite3_column_decltype(hStmtIn, iCol);
     319        7720 :         if (pszDeclType == nullptr)
     320             :         {
     321         577 :             auto iter = oMapTableInfo.find(pszFieldName);
     322         577 :             if (iter != oMapTableInfo.end())
     323          14 :                 pszDeclType = iter->second.c_str();
     324             :         }
     325             :         // CPLDebug("SQLITE", "decltype(%s) = %s",
     326             :         //          pszFieldName, pszDeclType ? pszDeclType : "null");
     327        7720 :         OGRFieldType eFieldType = OFTString;
     328        7720 :         if (pszDeclType != nullptr)
     329             :         {
     330        7157 :             std::string osDeclType(pszDeclType);
     331             :             const char *pszBeginDomainName =
     332        7157 :                 strstr(pszDeclType, "_BEGIN_DOMAIN_NAME_");
     333        7157 :             if (pszBeginDomainName)
     334             :             {
     335           2 :                 const char *pszBeginDomainNameOri = pszBeginDomainName;
     336           2 :                 pszBeginDomainName += strlen("_BEGIN_DOMAIN_NAME_");
     337             :                 const char *pszEndDomainName =
     338           2 :                     strstr(pszBeginDomainName, "_END_DOMAIN_NAME");
     339           2 :                 if (pszEndDomainName)
     340             :                 {
     341             :                     std::string osHEXDomainName(pszBeginDomainName,
     342           2 :                                                 pszEndDomainName -
     343           2 :                                                     pszBeginDomainName);
     344           2 :                     int nBytes = 0;
     345             :                     GByte *pabyDecoded =
     346           2 :                         CPLHexToBinary(osHEXDomainName.c_str(), &nBytes);
     347           2 :                     oField.SetDomainName(std::string(
     348             :                         reinterpret_cast<const char *>(pabyDecoded), nBytes));
     349           2 :                     CPLFree(pabyDecoded);
     350             :                     osDeclType =
     351           4 :                         std::string(pszDeclType,
     352           4 :                                     pszBeginDomainNameOri - pszDeclType) +
     353           4 :                         std::string(pszEndDomainName +
     354           4 :                                     strlen(pszEndDomainName));
     355             :                 }
     356             :             }
     357        7157 :             pszDeclType = osDeclType.c_str();
     358             : 
     359        7157 :             if (EQUAL(pszDeclType, "INTEGER_BOOLEAN") ||
     360        6963 :                 EQUAL(pszDeclType, "BOOLEAN"))
     361             :             {
     362         194 :                 oField.SetType(OFTInteger);
     363         194 :                 oField.SetSubType(OFSTBoolean);
     364             :             }
     365        6963 :             else if (EQUAL(pszDeclType, "INTEGER_INT16"))
     366             :             {
     367         190 :                 oField.SetType(OFTInteger);
     368         190 :                 oField.SetSubType(OFSTInt16);
     369             :             }
     370        6773 :             else if (EQUAL(pszDeclType, "INTEGER_OR_TEXT"))
     371             :             {
     372             :                 // Used by PROJ proj.db
     373           1 :                 oField.SetType(OFTString);
     374             :             }
     375        6772 :             else if (EQUAL(pszDeclType, "JSONINTEGERLIST"))
     376             :             {
     377         191 :                 oField.SetType(OFTIntegerList);
     378             :             }
     379        6581 :             else if (EQUAL(pszDeclType, "JSONINTEGER64LIST"))
     380             :             {
     381         191 :                 oField.SetType(OFTInteger64List);
     382             :             }
     383        6390 :             else if (EQUAL(pszDeclType, "JSONREALLIST"))
     384             :             {
     385         191 :                 oField.SetType(OFTRealList);
     386             :             }
     387        6199 :             else if (EQUAL(pszDeclType, "JSONSTRINGLIST"))
     388             :             {
     389         191 :                 oField.SetType(OFTStringList);
     390             :             }
     391        6008 :             else if (EQUAL(pszDeclType, "BIGINT") ||
     392        5756 :                      EQUAL(pszDeclType, "INT8") ||
     393        5756 :                      EQUAL(pszDeclType, "UNSIGNED BIG INT"))
     394             :             {
     395         252 :                 oField.SetType(OFTInteger64);
     396             :             }
     397        5756 :             else if (STARTS_WITH_CI(pszDeclType, "INTEGER") ||
     398        4347 :                      EQUAL(pszDeclType, "INT") ||
     399        4338 :                      EQUAL(pszDeclType, "TINYINT") ||
     400        4338 :                      EQUAL(pszDeclType, "SMALLINT") ||
     401        4338 :                      EQUAL(pszDeclType, "MEDIUMINT") ||
     402        4338 :                      EQUAL(pszDeclType, "INT2"))
     403             :             {
     404        1418 :                 oField.SetType(OFTInteger);
     405             :             }
     406        4338 :             else if (EQUAL(pszDeclType, "FLOAT_FLOAT32"))
     407             :             {
     408         190 :                 oField.SetType(OFTReal);
     409         190 :                 oField.SetSubType(OFSTFloat32);
     410             :             }
     411        4148 :             else if (EQUAL(pszDeclType, "FLOAT") ||
     412        3716 :                      EQUAL(pszDeclType, "DECIMAL") ||
     413        3716 :                      EQUAL(pszDeclType, "REAL") ||
     414        3703 :                      EQUAL(pszDeclType, "DOUBLE") ||
     415        3450 :                      EQUAL(pszDeclType, "DOUBLE PRECISION") ||
     416        3450 :                      EQUAL(pszDeclType, "NUMERIC"))
     417             :             {
     418         698 :                 oField.SetType(OFTReal);
     419             :             }
     420        3450 :             else if (STARTS_WITH_CI(pszDeclType, "BLOB"))
     421             :             {
     422         898 :                 oField.SetType(OFTBinary);
     423             :                 /* Parse format like BLOB_POINT_25D_4326 created by */
     424             :                 /* OGRSQLiteExecuteSQL() */
     425         898 :                 if (pszDeclType[4] == '_')
     426             :                 {
     427         211 :                     char *pszDeclTypeDup = CPLStrdup(pszDeclType);
     428         211 :                     char *pszNextUnderscore = strchr(pszDeclTypeDup + 5, '_');
     429         211 :                     const char *pszGeomType = pszDeclTypeDup + 5;
     430         211 :                     if (pszNextUnderscore != nullptr)
     431             :                     {
     432         211 :                         *pszNextUnderscore = '\0';
     433         211 :                         pszNextUnderscore++;
     434         211 :                         int nSRID = -1;
     435         211 :                         const char *pszCoordDimension = pszNextUnderscore;
     436         211 :                         pszNextUnderscore = strchr(pszNextUnderscore, '_');
     437         211 :                         if (pszNextUnderscore != nullptr)
     438             :                         {
     439         163 :                             *pszNextUnderscore = '\0';
     440         163 :                             pszNextUnderscore++;
     441         163 :                             const char *pszSRID = pszNextUnderscore;
     442         163 :                             nSRID = atoi(pszSRID);
     443             :                         }
     444             : 
     445             :                         OGRwkbGeometryType eGeomType =
     446         211 :                             OGRFromOGCGeomType(pszGeomType);
     447         211 :                         if (EQUAL(pszCoordDimension, "XYZ"))
     448           3 :                             eGeomType = wkbSetZ(eGeomType);
     449         208 :                         else if (EQUAL(pszCoordDimension, "XYM"))
     450           2 :                             eGeomType = wkbSetM(eGeomType);
     451         206 :                         else if (EQUAL(pszCoordDimension, "XYZM"))
     452           1 :                             eGeomType = wkbSetM(wkbSetZ(eGeomType));
     453         211 :                         OGRSpatialReference *poSRS = m_poDS->FetchSRS(nSRID);
     454             :                         auto poGeomFieldDefn =
     455             :                             std::make_unique<OGRSQLiteGeomFieldDefn>(
     456         422 :                                 pszFieldName, iCol);
     457         211 :                         poGeomFieldDefn->m_eGeomFormat = OSGF_SpatiaLite;
     458         211 :                         poGeomFieldDefn->SetSpatialRef(poSRS);
     459         211 :                         poGeomFieldDefn->SetType(eGeomType);
     460         211 :                         m_poFeatureDefn->AddGeomFieldDefn(
     461         211 :                             std::move(poGeomFieldDefn));
     462         211 :                         CPLFree(pszDeclTypeDup);
     463         211 :                         continue;
     464             :                     }
     465           0 :                     CPLFree(pszDeclTypeDup);
     466             :                 }
     467             :             }
     468        2552 :             else if (EQUAL(pszDeclType, "TEXT") ||
     469        2037 :                      STARTS_WITH_CI(pszDeclType, "VARCHAR") ||
     470         879 :                      STARTS_WITH_CI(pszDeclType, "CHARACTER") ||
     471         879 :                      STARTS_WITH_CI(pszDeclType, "VARYING CHARACTER") ||
     472         879 :                      STARTS_WITH_CI(pszDeclType, "NCHAR") ||
     473         879 :                      STARTS_WITH_CI(pszDeclType, "NATIVE CHARACTER") ||
     474         879 :                      STARTS_WITH_CI(pszDeclType, "NVARCHAR") ||
     475         879 :                      EQUAL(pszDeclType, "CLOB"))
     476             :             {
     477        1673 :                 oField.SetType(OFTString);
     478        1673 :                 if (strstr(pszDeclType, "_deflate") != nullptr)
     479             :                 {
     480          48 :                     if (CSLFindString(m_papszCompressedColumns, pszFieldName) <
     481             :                         0)
     482             :                     {
     483          48 :                         m_papszCompressedColumns = CSLAddString(
     484             :                             m_papszCompressedColumns, pszFieldName);
     485          48 :                         CPLDebug("SQLITE", "%s is compressed", pszFieldName);
     486             :                     }
     487             :                 }
     488             :             }
     489         879 :             else if ((EQUAL(pszDeclType, "TIMESTAMP") ||
     490         879 :                       EQUAL(pszDeclType, "DATETIME")) &&
     491         124 :                      (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT ||
     492             :                       nColType == SQLITE_NULL))
     493         271 :                 eFieldType = OFTDateTime;
     494         608 :             else if (EQUAL(pszDeclType, "DATE") &&
     495          82 :                      (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT ||
     496             :                       nColType == SQLITE_NULL))
     497         193 :                 eFieldType = OFTDate;
     498         415 :             else if (EQUAL(pszDeclType, "TIME") &&
     499          82 :                      (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT ||
     500             :                       nColType == SQLITE_NULL))
     501         193 :                 eFieldType = OFTTime;
     502             :         }
     503         563 :         else if (nColType == SQLITE_TEXT &&
     504         112 :                  (STARTS_WITH_CI(pszFieldName, "MIN(") ||
     505         111 :                   STARTS_WITH_CI(pszFieldName, "MAX(")))
     506             :         {
     507             :             const char *pszText = reinterpret_cast<const char *>(
     508           2 :                 sqlite3_column_text(hStmtIn, iCol));
     509           2 :             if (pszText != nullptr)
     510             :             {
     511             :                 OGRField oScratchField;
     512             : 
     513           2 :                 if (OGRParseDate(pszText, &oScratchField, 0))
     514           2 :                     OGRGetDateTimeFieldType(pszText, &eFieldType);
     515             :             }
     516             :         }
     517             : 
     518             :         // Recognise some common geometry column names.
     519       13254 :         if (paosGeomCols == nullptr &&
     520        5745 :             (EQUAL(pszFieldName, "wkt_geometry") ||
     521        5744 :              EQUAL(pszFieldName, "geometry") ||
     522        5613 :              STARTS_WITH_CI(pszFieldName, "asbinary(") ||
     523        5613 :              STARTS_WITH_CI(pszFieldName, "astext(") ||
     524        5613 :              (STARTS_WITH_CI(pszFieldName, "st_") &&
     525       13254 :               nColType == SQLITE_BLOB)) &&
     526         152 :             (m_bAllowMultipleGeomFields ||
     527           3 :              m_poFeatureDefn->GetGeomFieldCount() == 0))
     528             :         {
     529         152 :             if (nColType == SQLITE_BLOB)
     530             :             {
     531         133 :                 const int nBytes = sqlite3_column_bytes(hStmtIn, iCol);
     532         133 :                 if (nBytes > 0)
     533             :                 {
     534         133 :                     OGRSQLiteGeomFormat eGeomFormat = OSGF_None;
     535         133 :                     if (OGRIsBinaryGeomCol(hStmtIn, iCol, oField, eGeomFormat))
     536             :                     {
     537             :                         auto poGeomFieldDefn =
     538             :                             std::make_unique<OGRSQLiteGeomFieldDefn>(
     539         266 :                                 pszFieldName, iCol);
     540         133 :                         poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
     541         133 :                         m_poFeatureDefn->AddGeomFieldDefn(
     542         133 :                             std::move(poGeomFieldDefn));
     543         133 :                         continue;
     544             :                     }
     545             :                 }
     546             :                 else
     547             :                 {
     548             :                     /* This could also be a SpatialLite geometry, so */
     549             :                     /* we'll also try to decode as SpatialLite if */
     550             :                     /* bTriedAsSpatiaLite is not FALSE */
     551             :                     auto poGeomFieldDefn =
     552             :                         std::make_unique<OGRSQLiteGeomFieldDefn>(pszFieldName,
     553           0 :                                                                  iCol);
     554           0 :                     poGeomFieldDefn->m_eGeomFormat = OSGF_WKB;
     555           0 :                     m_poFeatureDefn->AddGeomFieldDefn(
     556           0 :                         std::move(poGeomFieldDefn));
     557           0 :                     continue;
     558             :                 }
     559             :             }
     560          19 :             else if (nColType == SQLITE_TEXT)
     561             :             {
     562             :                 const char *pszText = reinterpret_cast<const char *>(
     563           2 :                     sqlite3_column_text(hStmtIn, iCol));
     564           2 :                 if (pszText != nullptr)
     565             :                 {
     566           2 :                     OGRSQLiteGeomFormat eGeomFormat = OSGF_None;
     567           2 :                     CPLPushErrorHandler(CPLQuietErrorHandler);
     568           2 :                     OGRGeometry *poGeometry = nullptr;
     569           2 :                     if (OGRGeometryFactory::createFromWkt(
     570           2 :                             pszText, nullptr, &poGeometry) == OGRERR_NONE)
     571             :                     {
     572           1 :                         eGeomFormat = OSGF_WKT;
     573             :                         auto poGeomFieldDefn =
     574             :                             std::make_unique<OGRSQLiteGeomFieldDefn>(
     575           1 :                                 pszFieldName, iCol);
     576           1 :                         poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
     577           1 :                         m_poFeatureDefn->AddGeomFieldDefn(
     578           1 :                             std::move(poGeomFieldDefn));
     579             :                     }
     580           2 :                     CPLPopErrorHandler();
     581           2 :                     CPLErrorReset();
     582           2 :                     delete poGeometry;
     583           2 :                     if (eGeomFormat != OSGF_None)
     584           1 :                         continue;
     585             :                 }
     586             :                 else
     587             :                 {
     588             :                     auto poGeomFieldDefn =
     589             :                         std::make_unique<OGRSQLiteGeomFieldDefn>(pszFieldName,
     590           0 :                                                                  iCol);
     591           0 :                     poGeomFieldDefn->m_eGeomFormat = OSGF_WKT;
     592           0 :                     m_poFeatureDefn->AddGeomFieldDefn(
     593           0 :                         std::move(poGeomFieldDefn));
     594           0 :                     continue;
     595             :                 }
     596             :             }
     597             :         }
     598        5593 :         else if (paosGeomCols == nullptr && nColType == SQLITE_NULL &&
     599        2097 :                  !STARTS_WITH_CI(pszFieldName, "Gpkg") &&
     600        2097 :                  !STARTS_WITH_CI(pszFieldName, "AsGPB(") &&
     601       15047 :                  !STARTS_WITH_CI(pszFieldName, "CastAutomagic(") &&
     602        2097 :                  OGRSQLiteIsSpatialFunctionReturningGeometry(pszFieldName))
     603             :         {
     604             :             auto poGeomFieldDefn =
     605          16 :                 std::make_unique<OGRSQLiteGeomFieldDefn>(pszFieldName, iCol);
     606           8 :             poGeomFieldDefn->m_eGeomFormat = OSGF_SpatiaLite;
     607           8 :             m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
     608           8 :             continue;
     609             :         }
     610             : 
     611             :         // SpatialLite / Gaia
     612        7367 :         if (paosGeomCols == nullptr && EQUAL(pszFieldName, "GaiaGeometry") &&
     613           0 :             (m_bAllowMultipleGeomFields ||
     614           0 :              m_poFeatureDefn->GetGeomFieldCount() == 0))
     615             :         {
     616             :             auto poGeomFieldDefn =
     617           0 :                 std::make_unique<OGRSQLiteGeomFieldDefn>(pszFieldName, iCol);
     618           0 :             poGeomFieldDefn->m_eGeomFormat = OSGF_SpatiaLite;
     619           0 :             m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
     620           0 :             continue;
     621             :         }
     622             : 
     623             :         // Recognize a geometry column from trying to build the geometry
     624             :         // Useful for OGRSQLiteSelectLayer
     625        7749 :         if (paosGeomCols == nullptr && nColType == SQLITE_BLOB &&
     626         382 :             (m_bAllowMultipleGeomFields ||
     627           0 :              m_poFeatureDefn->GetGeomFieldCount() == 0))
     628             :         {
     629         382 :             const int nBytes = sqlite3_column_bytes(hStmtIn, iCol);
     630         382 :             OGRSQLiteGeomFormat eGeomFormat = OSGF_None;
     631         764 :             if (nBytes > 0 &&
     632         382 :                 OGRIsBinaryGeomCol(hStmtIn, iCol, oField, eGeomFormat))
     633             :             {
     634             :                 auto poGeomFieldDefn = std::make_unique<OGRSQLiteGeomFieldDefn>(
     635          72 :                     pszFieldName, iCol);
     636          36 :                 poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
     637          36 :                 m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
     638          36 :                 continue;
     639             :             }
     640             :         }
     641             : 
     642             :         // The rowid is for internal use, not a real column.
     643        7331 :         if (EQUAL(pszFieldName, "_rowid_"))
     644           0 :             continue;
     645             : 
     646             :         // The OGC_FID is for internal use, not a real user visible column.
     647        7331 :         if (EQUAL(pszFieldName, "OGC_FID"))
     648          79 :             continue;
     649             : 
     650             :         /* Config option just in case we would not want that in some cases */
     651        7059 :         if ((eFieldType == OFTTime || eFieldType == OFTDate ||
     652       14777 :              eFieldType == OFTDateTime) &&
     653         659 :             CPLTestBool(
     654             :                 CPLGetConfigOption("OGR_SQLITE_ENABLE_DATETIME", "YES")))
     655             :         {
     656         659 :             oField.SetType(eFieldType);
     657             :         }
     658             : 
     659        7252 :         oSetFields.insert(oField.GetNameRef());
     660        7252 :         m_poFeatureDefn->AddFieldDefn(&oField);
     661        7252 :         m_panFieldOrdinals[m_poFeatureDefn->GetFieldCount() - 1] = iCol;
     662             :     }
     663             : 
     664        2340 :     if (m_pszFIDColumn != nullptr)
     665             :     {
     666         762 :         for (int iCol = 0; iCol < nRawColumns; iCol++)
     667             :         {
     668         762 :             if (EQUAL(SQLUnescape(sqlite3_column_name(hStmtIn, iCol)).c_str(),
     669             :                       m_pszFIDColumn))
     670             :             {
     671         759 :                 m_iFIDCol = iCol;
     672         759 :                 break;
     673             :             }
     674             :         }
     675             :     }
     676        2340 : }
     677             : 
     678             : /************************************************************************/
     679             : /*                            GetFIDColumn()                            */
     680             : /************************************************************************/
     681             : 
     682         230 : const char *OGRSQLiteLayer::GetFIDColumn()
     683             : 
     684             : {
     685         230 :     GetLayerDefn();
     686         230 :     if (m_pszFIDColumn != nullptr)
     687         212 :         return m_pszFIDColumn;
     688             :     else
     689          18 :         return "";
     690             : }
     691             : 
     692             : /************************************************************************/
     693             : /*                            ResetReading()                            */
     694             : /************************************************************************/
     695             : 
     696        5125 : void OGRSQLiteLayer::ResetReading()
     697             : 
     698             : {
     699        5125 :     ClearStatement();
     700        5125 :     m_iNextShapeId = 0;
     701        5125 :     m_bEOF = false;
     702        5125 : }
     703             : 
     704             : /************************************************************************/
     705             : /*                           GetNextFeature()                           */
     706             : /************************************************************************/
     707             : 
     708        6462 : OGRFeature *OGRSQLiteLayer::GetNextFeature()
     709             : 
     710             : {
     711        6462 :     if (m_bEOF)
     712           5 :         return nullptr;
     713             : 
     714             :     while (true)
     715             :     {
     716        6586 :         OGRFeature *poFeature = GetNextRawFeature();
     717        6586 :         if (poFeature == nullptr)
     718             :         {
     719         710 :             m_bEOF = true;
     720         710 :             return nullptr;
     721             :         }
     722             : 
     723       12185 :         if ((m_poFilterGeom == nullptr ||
     724       11625 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
     725        5749 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     726        5747 :             return poFeature;
     727             : 
     728         129 :         delete poFeature;
     729         129 :     }
     730             : }
     731             : 
     732             : /************************************************************************/
     733             : /*                         GetNextRawFeature()                          */
     734             : /************************************************************************/
     735             : 
     736        6650 : OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
     737             : 
     738             : {
     739        6650 :     if (m_hStmt == nullptr)
     740             :     {
     741        1003 :         ResetStatement();
     742        1003 :         if (m_hStmt == nullptr)
     743           1 :             return nullptr;
     744             :     }
     745             : 
     746             :     /* -------------------------------------------------------------------- */
     747             :     /*      Fetch a record (unless otherwise instructed)                    */
     748             :     /* -------------------------------------------------------------------- */
     749        6649 :     if (m_bDoStep)
     750             :     {
     751        5652 :         const int rc = sqlite3_step(m_hStmt);
     752        5652 :         if (rc != SQLITE_ROW)
     753             :         {
     754         721 :             if (rc != SQLITE_DONE)
     755             :             {
     756           0 :                 sqlite3_reset(m_hStmt);
     757           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     758             :                          "In GetNextRawFeature(): sqlite3_step() : %s",
     759           0 :                          sqlite3_errmsg(m_poDS->GetDB()));
     760             :             }
     761             : 
     762         721 :             ClearStatement();
     763             : 
     764         721 :             return nullptr;
     765             :         }
     766             :     }
     767             :     else
     768             :     {
     769         997 :         m_bDoStep = true;
     770             :     }
     771             : 
     772             :     /* -------------------------------------------------------------------- */
     773             :     /*      Create a feature from the current result.                       */
     774             :     /* -------------------------------------------------------------------- */
     775        5928 :     OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn);
     776             : 
     777             :     /* -------------------------------------------------------------------- */
     778             :     /*      Set FID if we have a column to set it from.                     */
     779             :     /* -------------------------------------------------------------------- */
     780        5928 :     if (m_iFIDCol >= 0)
     781        2992 :         poFeature->SetFID(sqlite3_column_int64(m_hStmt, m_iFIDCol));
     782             :     else
     783        2936 :         poFeature->SetFID(m_iNextShapeId);
     784             : 
     785        5928 :     m_iNextShapeId++;
     786             : 
     787        5928 :     m_nFeaturesRead++;
     788             : 
     789             :     /* -------------------------------------------------------------------- */
     790             :     /*      Process Geometry if we have a column.                           */
     791             :     /* -------------------------------------------------------------------- */
     792        8207 :     for (int iField = 0; iField < m_poFeatureDefn->GetGeomFieldCount();
     793             :          iField++)
     794             :     {
     795             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
     796        2279 :             m_poFeatureDefn->myGetGeomFieldDefn(iField);
     797        2279 :         if (!poGeomFieldDefn->IsIgnored())
     798             :         {
     799        2228 :             OGRGeometry *poGeometry = nullptr;
     800        2228 :             if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
     801             :             {
     802             :                 const char *pszWKT = reinterpret_cast<const char *>(
     803           3 :                     sqlite3_column_text(m_hStmt, poGeomFieldDefn->m_iCol));
     804           3 :                 OGRGeometryFactory::createFromWkt(pszWKT, nullptr, &poGeometry);
     805             :             }
     806        2225 :             else if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKB)
     807             :             {
     808             :                 const int nBytes =
     809         810 :                     sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol);
     810             : 
     811             :                 /* Try as spatialite first since createFromWkb() can sometimes
     812             :                  */
     813             :                 /* interpret spatialite blobs as WKB for certain SRID values */
     814         810 :                 if (!poGeomFieldDefn->m_bTriedAsSpatiaLite)
     815             :                 {
     816             :                     /* If the layer is the result of a sql select, we cannot be
     817             :                      * sure if it is */
     818             :                     /* WKB or SpatialLite format */
     819             :                     // coverity[tainted_data_return]
     820             :                     const GByte *pabyBlob = reinterpret_cast<const GByte *>(
     821          75 :                         sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol));
     822          75 :                     if (ImportSpatiaLiteGeometry(pabyBlob, nBytes,
     823          75 :                                                  &poGeometry) == OGRERR_NONE)
     824             :                     {
     825           0 :                         poGeomFieldDefn->m_eGeomFormat = OSGF_SpatiaLite;
     826             :                     }
     827          75 :                     poGeomFieldDefn->m_bTriedAsSpatiaLite = true;
     828             :                 }
     829             : 
     830         810 :                 if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKB)
     831             :                 {
     832             :                     // coverity[tainted_data_return]
     833             :                     const void *pabyBlob =
     834         810 :                         sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol);
     835         810 :                     CPL_IGNORE_RET_VAL(OGRGeometryFactory::createFromWkb(
     836             :                         pabyBlob, nullptr, &poGeometry, nBytes));
     837             :                 }
     838             :             }
     839        1415 :             else if (poGeomFieldDefn->m_eGeomFormat == OSGF_FGF)
     840             :             {
     841             :                 const int nBytes =
     842          11 :                     sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol);
     843             :                 // coverity[tainted_data_return]
     844             :                 const void *pabyBlob =
     845          11 :                     sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol);
     846          11 :                 OGRGeometryFactory::createFromFgf(pabyBlob, nullptr,
     847             :                                                   &poGeometry, nBytes, nullptr);
     848             :             }
     849        1404 :             else if (poGeomFieldDefn->m_eGeomFormat == OSGF_SpatiaLite)
     850             :             {
     851             :                 const int nBytes =
     852        1404 :                     sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol);
     853             :                 // coverity[tainted_data_return]
     854             :                 const GByte *pabyBlob = reinterpret_cast<const GByte *>(
     855        1404 :                     sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol));
     856        1404 :                 CPL_IGNORE_RET_VAL(
     857        1404 :                     ImportSpatiaLiteGeometry(pabyBlob, nBytes, &poGeometry));
     858             :             }
     859             : 
     860        2228 :             if (poGeometry != nullptr)
     861             :             {
     862        1936 :                 if (poGeomFieldDefn->GetSpatialRef() != nullptr)
     863        1272 :                     poGeometry->assignSpatialReference(
     864        1272 :                         poGeomFieldDefn->GetSpatialRef());
     865        1936 :                 poFeature->SetGeomFieldDirectly(iField, poGeometry);
     866             :             }
     867             :         }
     868             :     }
     869             : 
     870             :     /* -------------------------------------------------------------------- */
     871             :     /*      set the fields.                                                 */
     872             :     /* -------------------------------------------------------------------- */
     873        5928 :     const int nFieldCount = m_poFeatureDefn->GetFieldCount();
     874       28737 :     for (int iField = 0; iField < nFieldCount; iField++)
     875             :     {
     876             :         const OGRFieldDefn *poFieldDefn =
     877       22809 :             m_poFeatureDefn->GetFieldDefnUnsafe(iField);
     878       22809 :         if (poFieldDefn->IsIgnored())
     879          52 :             continue;
     880             : 
     881       22757 :         int iRawField = m_panFieldOrdinals[iField];
     882             : 
     883       22757 :         int nSQLite3Type = sqlite3_column_type(m_hStmt, iRawField);
     884       22757 :         if (nSQLite3Type == SQLITE_NULL)
     885             :         {
     886        4470 :             poFeature->SetFieldNull(iField);
     887        4470 :             continue;
     888             :         }
     889             : 
     890       18287 :         switch (poFieldDefn->GetType())
     891             :         {
     892        4537 :             case OFTInteger:
     893             :             {
     894             :                 /* Possible since SQLite3 has no strong typing */
     895        4537 :                 if (nSQLite3Type == SQLITE_TEXT)
     896           2 :                     poFeature->SetField(
     897             :                         iField, reinterpret_cast<const char *>(
     898           2 :                                     sqlite3_column_text(m_hStmt, iRawField)));
     899             :                 else
     900             :                 {
     901             :                     const GIntBig nVal =
     902        4535 :                         sqlite3_column_int64(m_hStmt, iRawField);
     903        4535 :                     if (poFieldDefn->GetSubType() == OFSTBoolean)
     904             :                     {
     905         765 :                         poFeature->SetField(iField, nVal != 0);
     906             :                     }
     907             :                     else
     908             :                     {
     909        3770 :                         if (nVal >= INT_MIN && nVal <= INT_MAX)
     910        3770 :                             poFeature->SetFieldSameTypeUnsafe(
     911             :                                 iField, static_cast<int>(nVal));
     912             :                         else
     913           0 :                             poFeature->SetField(iField, nVal);
     914             :                     }
     915             :                 }
     916        4537 :                 break;
     917             :             }
     918             : 
     919         742 :             case OFTInteger64:
     920             :             {
     921             :                 /* Possible since SQLite3 has no strong typing */
     922         742 :                 if (nSQLite3Type == SQLITE_TEXT)
     923           0 :                     poFeature->SetField(
     924             :                         iField, reinterpret_cast<const char *>(
     925           0 :                                     sqlite3_column_text(m_hStmt, iRawField)));
     926             :                 else
     927         742 :                     poFeature->SetFieldSameTypeUnsafe(
     928             :                         iField, sqlite3_column_int64(m_hStmt, iRawField));
     929         742 :                 break;
     930             :             }
     931             : 
     932        2383 :             case OFTReal:
     933             :             {
     934             :                 /* Possible since SQLite3 has no strong typing */
     935        2383 :                 if (nSQLite3Type == SQLITE_TEXT)
     936           1 :                     poFeature->SetField(
     937             :                         iField, reinterpret_cast<const char *>(
     938           1 :                                     sqlite3_column_text(m_hStmt, iRawField)));
     939             :                 else
     940        2382 :                     poFeature->SetField(
     941             :                         iField, sqlite3_column_double(m_hStmt, iRawField));
     942        2383 :                 break;
     943             :             }
     944             : 
     945         750 :             case OFTBinary:
     946             :             {
     947         750 :                 const int nBytes = sqlite3_column_bytes(m_hStmt, iRawField);
     948             :                 // coverity[tainted_data_return]
     949             :                 const GByte *pabyData = reinterpret_cast<const GByte *>(
     950         750 :                     sqlite3_column_blob(m_hStmt, iRawField));
     951         750 :                 poFeature->SetField(iField, nBytes,
     952             :                                     const_cast<GByte *>(pabyData));
     953             :             }
     954         750 :             break;
     955             : 
     956        9429 :             case OFTString:
     957             :             case OFTIntegerList:
     958             :             case OFTInteger64List:
     959             :             case OFTRealList:
     960             :             case OFTStringList:
     961             :             {
     962        9429 :                 if (CSLFindString(
     963        9429 :                         m_papszCompressedColumns,
     964       18858 :                         m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef()) >=
     965             :                     0)
     966             :                 {
     967          39 :                     const int nBytes = sqlite3_column_bytes(m_hStmt, iRawField);
     968             :                     // coverity[tainted_data_return]
     969             :                     const GByte *pabyBlob = reinterpret_cast<const GByte *>(
     970          39 :                         sqlite3_column_blob(m_hStmt, iRawField));
     971             : 
     972             :                     void *pOut =
     973          39 :                         CPLZLibInflate(pabyBlob, nBytes, nullptr, 0, nullptr);
     974          39 :                     if (pOut != nullptr)
     975             :                     {
     976          39 :                         poFeature->SetField(iField,
     977             :                                             static_cast<const char *>(pOut));
     978          39 :                         CPLFree(pOut);
     979             :                     }
     980             :                     else
     981             :                     {
     982           0 :                         poFeature->SetField(
     983             :                             iField,
     984             :                             reinterpret_cast<const char *>(
     985           0 :                                 sqlite3_column_text(m_hStmt, iRawField)));
     986             :                     }
     987             :                 }
     988             :                 else
     989             :                 {
     990        9390 :                     poFeature->SetField(
     991             :                         iField, reinterpret_cast<const char *>(
     992        9390 :                                     sqlite3_column_text(m_hStmt, iRawField)));
     993             :                 }
     994        9429 :                 break;
     995             :             }
     996             : 
     997         446 :             case OFTDate:
     998             :             case OFTTime:
     999             :             case OFTDateTime:
    1000             :             {
    1001         446 :                 if (sqlite3_column_type(m_hStmt, iRawField) == SQLITE_TEXT)
    1002             :                 {
    1003             :                     const char *pszValue = reinterpret_cast<const char *>(
    1004         445 :                         sqlite3_column_text(m_hStmt, iRawField));
    1005         445 :                     if (!OGRParseDate(pszValue,
    1006             :                                       poFeature->GetRawFieldRef(iField), 0))
    1007           0 :                         poFeature->UnsetField(iField);
    1008             :                 }
    1009           1 :                 else if (sqlite3_column_type(m_hStmt, iRawField) ==
    1010             :                          SQLITE_FLOAT)
    1011             :                 {
    1012             :                     // Try converting from Julian day
    1013           1 :                     char **papszResult = nullptr;
    1014           2 :                     sqlite3_get_table(
    1015           1 :                         m_poDS->GetDB(),
    1016             :                         CPLSPrintf(
    1017             :                             "SELECT strftime('%%Y-%%m-%%d %%H:%%M:%%S', %.16g)",
    1018             :                             sqlite3_column_double(m_hStmt, iRawField)),
    1019             :                         &papszResult, nullptr, nullptr, nullptr);
    1020           1 :                     if (papszResult && papszResult[0] && papszResult[1])
    1021             :                     {
    1022           1 :                         if (!OGRParseDate(papszResult[1],
    1023             :                                           poFeature->GetRawFieldRef(iField), 0))
    1024           0 :                             poFeature->UnsetField(iField);
    1025             :                     }
    1026           1 :                     sqlite3_free_table(papszResult);
    1027             :                 }
    1028         446 :                 break;
    1029             :             }
    1030             : 
    1031           0 :             default:
    1032           0 :                 break;
    1033             :         }
    1034             :     }
    1035             : 
    1036             :     /* -------------------------------------------------------------------- */
    1037             :     /*      Set native data if found                                        */
    1038             :     /* -------------------------------------------------------------------- */
    1039        6112 :     if (m_iOGRNativeDataCol >= 0 &&
    1040         184 :         sqlite3_column_type(m_hStmt, m_iOGRNativeDataCol) == SQLITE_TEXT)
    1041             :     {
    1042           1 :         poFeature->SetNativeData(reinterpret_cast<const char *>(
    1043           1 :             sqlite3_column_text(m_hStmt, m_iOGRNativeDataCol)));
    1044             :     }
    1045        6112 :     if (m_iOGRNativeMediaTypeCol >= 0 &&
    1046         184 :         sqlite3_column_type(m_hStmt, m_iOGRNativeMediaTypeCol) == SQLITE_TEXT)
    1047             :     {
    1048           1 :         poFeature->SetNativeMediaType(reinterpret_cast<const char *>(
    1049           1 :             sqlite3_column_text(m_hStmt, m_iOGRNativeMediaTypeCol)));
    1050             :     }
    1051             : 
    1052        5928 :     return poFeature;
    1053             : }
    1054             : 
    1055             : /************************************************************************/
    1056             : /*                             GetFeature()                             */
    1057             : /************************************************************************/
    1058             : 
    1059          19 : OGRFeature *OGRSQLiteLayer::GetFeature(GIntBig nFeatureId)
    1060             : 
    1061             : {
    1062          19 :     return OGRLayer::GetFeature(nFeatureId);
    1063             : }
    1064             : 
    1065             : /************************************************************************/
    1066             : /*                     createFromSpatialiteInternal()                   */
    1067             : /************************************************************************/
    1068             : 
    1069             : /* See http://www.gaia-gis.it/spatialite/spatialite-manual-2.3.0.html#t3.3 */
    1070             : /* for the specification of the spatialite BLOB geometry format */
    1071             : /* Derived from WKB, but unfortunately it is not practical to reuse existing */
    1072             : /* WKB encoding/decoding code */
    1073             : 
    1074             : #ifdef CPL_LSB
    1075             : #define NEED_SWAP_SPATIALITE() (eByteOrder != wkbNDR)
    1076             : #else
    1077             : #define NEED_SWAP_SPATIALITE() (eByteOrder == wkbNDR)
    1078             : #endif
    1079             : 
    1080        1569 : OGRErr OGRSQLiteLayer::createFromSpatialiteInternal(
    1081             :     const GByte *pabyData, OGRGeometry **ppoReturn, int nBytes,
    1082             :     OGRwkbByteOrder eByteOrder, int *pnBytesConsumed, int nRecLevel)
    1083             : {
    1084        1569 :     *ppoReturn = nullptr;
    1085             : 
    1086             :     /* Arbitrary value, but certainly large enough for reasonable usages ! */
    1087        1569 :     if (nRecLevel == 32)
    1088             :     {
    1089           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1090             :                  "Too many recursion levels (%d) while parsing "
    1091             :                  "Spatialite geometry.",
    1092             :                  nRecLevel);
    1093           0 :         return OGRERR_CORRUPT_DATA;
    1094             :     }
    1095             : 
    1096        1569 :     if (nBytes < 4)
    1097           0 :         return OGRERR_NOT_ENOUGH_DATA;
    1098             : 
    1099             :     /* -------------------------------------------------------------------- */
    1100             :     /*      Decode the geometry type.                                       */
    1101             :     /* -------------------------------------------------------------------- */
    1102        1569 :     GInt32 nGType = 0;
    1103        1569 :     memcpy(&nGType, pabyData, 4);
    1104        1569 :     if (NEED_SWAP_SPATIALITE())
    1105           0 :         CPL_SWAP32PTR(&nGType);
    1106             : 
    1107        1569 :     if ((nGType >= OGRSplitePointXY &&
    1108        1569 :          nGType <= OGRSpliteGeometryCollectionXY) ||  // XY types
    1109         408 :         (nGType >= OGRSplitePointXYZ &&
    1110         408 :          nGType <= OGRSpliteGeometryCollectionXYZ) ||  // XYZ types
    1111         367 :         (nGType >= OGRSplitePointXYM &&
    1112         367 :          nGType <= OGRSpliteGeometryCollectionXYM) ||  // XYM types
    1113         343 :         (nGType >= OGRSplitePointXYZM &&
    1114         343 :          nGType <= OGRSpliteGeometryCollectionXYZM) ||  // XYZM types
    1115         319 :         (nGType >= OGRSpliteComprLineStringXY &&
    1116         319 :          nGType <= OGRSpliteComprGeometryCollectionXY) ||  // XY compressed
    1117          23 :         (nGType >= OGRSpliteComprLineStringXYZ &&
    1118          23 :          nGType <= OGRSpliteComprGeometryCollectionXYZ) ||  // XYZ compressed
    1119          14 :         (nGType >= OGRSpliteComprLineStringXYM &&
    1120          14 :          nGType <= OGRSpliteComprGeometryCollectionXYM) ||  // XYM compressed
    1121           7 :         (nGType >= OGRSpliteComprLineStringXYZM &&
    1122           7 :          nGType <= OGRSpliteComprGeometryCollectionXYZM))  // XYZM compressed
    1123             :         ;
    1124             :     else
    1125           0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1126             : 
    1127             :     /* -------------------------------------------------------------------- */
    1128             :     /*      Point [XY]                                                      */
    1129             :     /* -------------------------------------------------------------------- */
    1130        1569 :     OGRGeometry *poGeom = nullptr;
    1131        1569 :     GInt32 compressedSize = 0;
    1132             : 
    1133        1569 :     if (nGType == OGRSplitePointXY)
    1134             :     {
    1135         513 :         if (nBytes < 4 + 2 * 8)
    1136           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1137             : 
    1138         513 :         double adfTuple[2] = {0.0, 0.0};
    1139             : 
    1140         513 :         memcpy(adfTuple, pabyData + 4, 2 * 8);
    1141         513 :         if (NEED_SWAP_SPATIALITE())
    1142             :         {
    1143           0 :             CPL_SWAP64PTR(adfTuple);
    1144           0 :             CPL_SWAP64PTR(adfTuple + 1);
    1145             :         }
    1146             : 
    1147         513 :         poGeom = new OGRPoint(adfTuple[0], adfTuple[1]);
    1148             : 
    1149         513 :         if (pnBytesConsumed)
    1150         513 :             *pnBytesConsumed = 4 + 2 * 8;
    1151             :     }
    1152             :     /* -------------------------------------------------------------------- */
    1153             :     /*      Point [XYZ]                                                     */
    1154             :     /* -------------------------------------------------------------------- */
    1155        1056 :     else if (nGType == OGRSplitePointXYZ)
    1156             :     {
    1157          14 :         if (nBytes < 4 + 3 * 8)
    1158           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1159             : 
    1160          14 :         double adfTuple[3] = {0.0, 0.0, 0.0};
    1161             : 
    1162          14 :         memcpy(adfTuple, pabyData + 4, 3 * 8);
    1163          14 :         if (NEED_SWAP_SPATIALITE())
    1164             :         {
    1165           0 :             CPL_SWAP64PTR(adfTuple);
    1166           0 :             CPL_SWAP64PTR(adfTuple + 1);
    1167           0 :             CPL_SWAP64PTR(adfTuple + 2);
    1168             :         }
    1169             : 
    1170          14 :         poGeom = new OGRPoint(adfTuple[0], adfTuple[1], adfTuple[2]);
    1171             : 
    1172          14 :         if (pnBytesConsumed)
    1173          14 :             *pnBytesConsumed = 4 + 3 * 8;
    1174             :     }
    1175             : 
    1176             :     /* -------------------------------------------------------------------- */
    1177             :     /*      Point [XYM]                                                     */
    1178             :     /* -------------------------------------------------------------------- */
    1179        1042 :     else if (nGType == OGRSplitePointXYM)
    1180             :     {
    1181           8 :         if (nBytes < 4 + 3 * 8)
    1182           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1183             : 
    1184           8 :         double adfTuple[3] = {0.0, 0.0, 0.0};
    1185           8 :         memcpy(adfTuple, pabyData + 4, 3 * 8);
    1186           8 :         if (NEED_SWAP_SPATIALITE())
    1187             :         {
    1188           0 :             CPL_SWAP64PTR(adfTuple);
    1189           0 :             CPL_SWAP64PTR(adfTuple + 1);
    1190           0 :             CPL_SWAP64PTR(adfTuple + 2);
    1191             :         }
    1192             : 
    1193           8 :         OGRPoint *poPoint = new OGRPoint(adfTuple[0], adfTuple[1]);
    1194           8 :         poPoint->setM(adfTuple[2]);
    1195           8 :         poGeom = poPoint;
    1196             : 
    1197           8 :         if (pnBytesConsumed)
    1198           8 :             *pnBytesConsumed = 4 + 3 * 8;
    1199             :     }
    1200             : 
    1201             :     /* -------------------------------------------------------------------- */
    1202             :     /*      Point [XYZM]                                                    */
    1203             :     /* -------------------------------------------------------------------- */
    1204        1034 :     else if (nGType == OGRSplitePointXYZM)
    1205             :     {
    1206           8 :         if (nBytes < 4 + 4 * 8)
    1207           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1208             : 
    1209             :         double adfTuple[4];
    1210           8 :         memcpy(adfTuple, pabyData + 4, 4 * 8);
    1211           8 :         if (NEED_SWAP_SPATIALITE())
    1212             :         {
    1213           0 :             CPL_SWAP64PTR(adfTuple);
    1214           0 :             CPL_SWAP64PTR(adfTuple + 1);
    1215           0 :             CPL_SWAP64PTR(adfTuple + 2);
    1216           0 :             CPL_SWAP64PTR(adfTuple + 3);
    1217             :         }
    1218             : 
    1219           8 :         poGeom =
    1220           8 :             new OGRPoint(adfTuple[0], adfTuple[1], adfTuple[2], adfTuple[3]);
    1221             : 
    1222           8 :         if (pnBytesConsumed)
    1223           8 :             *pnBytesConsumed = 4 + 4 * 8;
    1224             :     }
    1225             : 
    1226             :     /* -------------------------------------------------------------------- */
    1227             :     /*      LineString [XY]                                                 */
    1228             :     /* -------------------------------------------------------------------- */
    1229        1026 :     else if (nGType == OGRSpliteLineStringXY)
    1230             :     {
    1231          31 :         if (nBytes < 8)
    1232           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1233             : 
    1234          31 :         GInt32 nPointCount = 0;
    1235          31 :         memcpy(&nPointCount, pabyData + 4, 4);
    1236          31 :         if (NEED_SWAP_SPATIALITE())
    1237           0 :             CPL_SWAP32PTR(&nPointCount);
    1238             : 
    1239          31 :         if (nPointCount < 0 || nPointCount > INT_MAX / (2 * 8))
    1240           0 :             return OGRERR_CORRUPT_DATA;
    1241             : 
    1242          31 :         if (nBytes - 8 < 2 * 8 * nPointCount)
    1243           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1244             : 
    1245          31 :         OGRLineString *poLS = new OGRLineString();
    1246          31 :         poGeom = poLS;
    1247          31 :         if (!NEED_SWAP_SPATIALITE())
    1248             :         {
    1249          31 :             poLS->setPoints(nPointCount,
    1250          31 :                             reinterpret_cast<const OGRRawPoint *>(pabyData + 8),
    1251             :                             nullptr);
    1252             :         }
    1253             :         else
    1254             :         {
    1255           0 :             poLS->setNumPoints(nPointCount, FALSE);
    1256           0 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1257             :             {
    1258           0 :                 double adfTuple[2] = {0.0, 0.0};
    1259           0 :                 memcpy(adfTuple, pabyData + 8 + 2 * 8 * iPoint, 2 * 8);
    1260           0 :                 CPL_SWAP64PTR(adfTuple);
    1261           0 :                 CPL_SWAP64PTR(adfTuple + 1);
    1262           0 :                 poLS->setPoint(iPoint, adfTuple[0], adfTuple[1]);
    1263             :             }
    1264             :         }
    1265             : 
    1266          31 :         if (pnBytesConsumed)
    1267          31 :             *pnBytesConsumed = 8 + 2 * 8 * nPointCount;
    1268             :     }
    1269             : 
    1270             :     /* -------------------------------------------------------------------- */
    1271             :     /*      LineString [XYZ]                                                */
    1272             :     /* -------------------------------------------------------------------- */
    1273         995 :     else if (nGType == OGRSpliteLineStringXYZ)
    1274             :     {
    1275           7 :         if (nBytes < 8)
    1276           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1277             : 
    1278           7 :         GInt32 nPointCount = 0;
    1279           7 :         memcpy(&nPointCount, pabyData + 4, 4);
    1280           7 :         if (NEED_SWAP_SPATIALITE())
    1281           0 :             CPL_SWAP32PTR(&nPointCount);
    1282             : 
    1283           7 :         if (nPointCount < 0 || nPointCount > INT_MAX / (3 * 8))
    1284           0 :             return OGRERR_CORRUPT_DATA;
    1285             : 
    1286           7 :         if (nBytes - 8 < 3 * 8 * nPointCount)
    1287           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1288             : 
    1289           7 :         OGRLineString *poLS = new OGRLineString();
    1290           7 :         poGeom = poLS;
    1291           7 :         poLS->setNumPoints(nPointCount);
    1292             : 
    1293          22 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1294             :         {
    1295          15 :             double adfTuple[3] = {0.0, 0.0, 0.0};
    1296          15 :             memcpy(adfTuple, pabyData + 8 + 3 * 8 * iPoint, 3 * 8);
    1297          15 :             if (NEED_SWAP_SPATIALITE())
    1298             :             {
    1299           0 :                 CPL_SWAP64PTR(adfTuple);
    1300           0 :                 CPL_SWAP64PTR(adfTuple + 1);
    1301           0 :                 CPL_SWAP64PTR(adfTuple + 2);
    1302             :             }
    1303             : 
    1304          15 :             poLS->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    1305             :         }
    1306             : 
    1307           7 :         if (pnBytesConsumed)
    1308           7 :             *pnBytesConsumed = 8 + 3 * 8 * nPointCount;
    1309             :     }
    1310             : 
    1311             :     /* -------------------------------------------------------------------- */
    1312             :     /*      LineString [XYM]                                                */
    1313             :     /* -------------------------------------------------------------------- */
    1314         988 :     else if (nGType == OGRSpliteLineStringXYM)
    1315             :     {
    1316             : 
    1317           5 :         if (nBytes < 8)
    1318           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1319             : 
    1320           5 :         GInt32 nPointCount = 0;
    1321           5 :         memcpy(&nPointCount, pabyData + 4, 4);
    1322           5 :         if (NEED_SWAP_SPATIALITE())
    1323           0 :             CPL_SWAP32PTR(&nPointCount);
    1324             : 
    1325           5 :         if (nPointCount < 0 || nPointCount > INT_MAX / (3 * 8))
    1326           0 :             return OGRERR_CORRUPT_DATA;
    1327             : 
    1328           5 :         if (nBytes - 8 < 3 * 8 * nPointCount)
    1329           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1330             : 
    1331           5 :         OGRLineString *poLS = new OGRLineString();
    1332           5 :         poGeom = poLS;
    1333           5 :         poLS->setNumPoints(nPointCount);
    1334             : 
    1335          15 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1336             :         {
    1337          10 :             double adfTuple[3] = {0.0, 0.0, 0.0};
    1338          10 :             memcpy(adfTuple, pabyData + 8 + 3 * 8 * iPoint, 3 * 8);
    1339          10 :             if (NEED_SWAP_SPATIALITE())
    1340             :             {
    1341           0 :                 CPL_SWAP64PTR(adfTuple);
    1342           0 :                 CPL_SWAP64PTR(adfTuple + 1);
    1343           0 :                 CPL_SWAP64PTR(adfTuple + 2);
    1344             :             }
    1345             : 
    1346          10 :             poLS->setPointM(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    1347             :         }
    1348             : 
    1349           5 :         if (pnBytesConsumed)
    1350           5 :             *pnBytesConsumed = 8 + 3 * 8 * nPointCount;
    1351             :     }
    1352             : 
    1353             :     /* -------------------------------------------------------------------- */
    1354             :     /*      LineString [XYZM]                                               */
    1355             :     /* -------------------------------------------------------------------- */
    1356         983 :     else if (nGType == OGRSpliteLineStringXYZM)
    1357             :     {
    1358           5 :         if (nBytes < 8)
    1359           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1360             : 
    1361           5 :         GInt32 nPointCount = 0;
    1362           5 :         memcpy(&nPointCount, pabyData + 4, 4);
    1363           5 :         if (NEED_SWAP_SPATIALITE())
    1364           0 :             CPL_SWAP32PTR(&nPointCount);
    1365             : 
    1366           5 :         if (nPointCount < 0 || nPointCount > INT_MAX / (4 * 8))
    1367           0 :             return OGRERR_CORRUPT_DATA;
    1368             : 
    1369           5 :         if (nBytes - 8 < 4 * 8 * nPointCount)
    1370           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1371             : 
    1372           5 :         OGRLineString *poLS = new OGRLineString();
    1373           5 :         poGeom = poLS;
    1374           5 :         poLS->setNumPoints(nPointCount);
    1375             : 
    1376          15 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1377             :         {
    1378          10 :             double adfTuple[4] = {0.0, 0.0, 0.0, 0.0};
    1379          10 :             memcpy(adfTuple, pabyData + 8 + 4 * 8 * iPoint, 4 * 8);
    1380          10 :             if (NEED_SWAP_SPATIALITE())
    1381             :             {
    1382           0 :                 CPL_SWAP64PTR(adfTuple);
    1383           0 :                 CPL_SWAP64PTR(adfTuple + 1);
    1384           0 :                 CPL_SWAP64PTR(adfTuple + 2);
    1385           0 :                 CPL_SWAP64PTR(adfTuple + 3);
    1386             :             }
    1387             : 
    1388          10 :             poLS->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2],
    1389             :                            adfTuple[3]);
    1390             :         }
    1391             : 
    1392           5 :         if (pnBytesConsumed)
    1393           5 :             *pnBytesConsumed = 8 + 4 * 8 * nPointCount;
    1394             :     }
    1395             : 
    1396             :     /* -------------------------------------------------------------------- */
    1397             :     /*      LineString [XY] Compressed                                      */
    1398             :     /* -------------------------------------------------------------------- */
    1399         978 :     else if (nGType == OGRSpliteComprLineStringXY)
    1400             :     {
    1401           5 :         if (nBytes < 8)
    1402           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1403             : 
    1404           5 :         GInt32 nPointCount = 0;
    1405           5 :         memcpy(&nPointCount, pabyData + 4, 4);
    1406           5 :         if (NEED_SWAP_SPATIALITE())
    1407           0 :             CPL_SWAP32PTR(&nPointCount);
    1408             : 
    1409           5 :         if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 16 * 2) / 8)
    1410           0 :             return OGRERR_CORRUPT_DATA;
    1411             : 
    1412           5 :         compressedSize = 16 * 2;                  // first and last Points
    1413           5 :         compressedSize += 8 * (nPointCount - 2);  // intermediate Points
    1414             : 
    1415           5 :         if (nBytes - 8 < compressedSize)
    1416           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1417             : 
    1418           5 :         OGRLineString *poLS = new OGRLineString();
    1419           5 :         poGeom = poLS;
    1420           5 :         poLS->setNumPoints(nPointCount);
    1421             : 
    1422           5 :         int nNextByte = 8;
    1423           5 :         double adfTupleBase[2] = {0.0, 0.0};
    1424             : 
    1425          16 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1426             :         {
    1427          11 :             double adfTuple[2] = {0.0, 0.0};
    1428             : 
    1429          11 :             if (iPoint == 0 || iPoint == (nPointCount - 1))
    1430             :             {
    1431             :                 // first and last Points are uncompressed
    1432          10 :                 memcpy(adfTuple, pabyData + nNextByte, 2 * 8);
    1433          10 :                 nNextByte += 2 * 8;
    1434             : 
    1435          10 :                 if (NEED_SWAP_SPATIALITE())
    1436             :                 {
    1437           0 :                     CPL_SWAP64PTR(adfTuple);
    1438           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1439          10 :                 }
    1440             :             }
    1441             :             else
    1442             :             {
    1443             :                 // any other intermediate Point is compressed
    1444           1 :                 float asfTuple[2] = {0.0f, 0.0f};
    1445           1 :                 memcpy(asfTuple, pabyData + nNextByte, 2 * 4);
    1446           1 :                 nNextByte += 2 * 4;
    1447             : 
    1448           1 :                 if (NEED_SWAP_SPATIALITE())
    1449             :                 {
    1450           0 :                     CPL_SWAP32PTR(asfTuple);
    1451           0 :                     CPL_SWAP32PTR(asfTuple + 1);
    1452             :                 }
    1453           1 :                 adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    1454           1 :                 adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    1455             :             }
    1456             : 
    1457          11 :             poLS->setPoint(iPoint, adfTuple[0], adfTuple[1]);
    1458          11 :             adfTupleBase[0] = adfTuple[0];
    1459          11 :             adfTupleBase[1] = adfTuple[1];
    1460             :         }
    1461             : 
    1462           5 :         if (pnBytesConsumed)
    1463           5 :             *pnBytesConsumed = nNextByte;
    1464             :     }
    1465             : 
    1466             :     /* -------------------------------------------------------------------- */
    1467             :     /*      LineString [XYZ] Compressed                                     */
    1468             :     /* -------------------------------------------------------------------- */
    1469         973 :     else if (nGType == OGRSpliteComprLineStringXYZ)
    1470             :     {
    1471           5 :         if (nBytes < 8)
    1472           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1473             : 
    1474           5 :         GInt32 nPointCount = 0;
    1475           5 :         memcpy(&nPointCount, pabyData + 4, 4);
    1476           5 :         if (NEED_SWAP_SPATIALITE())
    1477           0 :             CPL_SWAP32PTR(&nPointCount);
    1478             : 
    1479           5 :         if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 24 * 2) / 12)
    1480           0 :             return OGRERR_CORRUPT_DATA;
    1481             : 
    1482           5 :         compressedSize = 24 * 2;                   // first and last Points
    1483           5 :         compressedSize += 12 * (nPointCount - 2);  // intermediate Points
    1484             : 
    1485           5 :         if (nBytes - 8 < compressedSize)
    1486           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1487             : 
    1488           5 :         OGRLineString *poLS = new OGRLineString();
    1489           5 :         poGeom = poLS;
    1490           5 :         poLS->setNumPoints(nPointCount);
    1491             : 
    1492           5 :         int nNextByte = 8;
    1493           5 :         double adfTupleBase[3] = {0.0, 0.0, 0.0};
    1494             : 
    1495          16 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1496             :         {
    1497          11 :             double adfTuple[3] = {0.0, 0.0, 0.0};
    1498             : 
    1499          11 :             if (iPoint == 0 || iPoint == (nPointCount - 1))
    1500             :             {
    1501             :                 // first and last Points are uncompressed
    1502          10 :                 memcpy(adfTuple, pabyData + nNextByte, 3 * 8);
    1503          10 :                 nNextByte += 3 * 8;
    1504             : 
    1505          10 :                 if (NEED_SWAP_SPATIALITE())
    1506             :                 {
    1507           0 :                     CPL_SWAP64PTR(adfTuple);
    1508           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1509           0 :                     CPL_SWAP64PTR(adfTuple + 2);
    1510          10 :                 }
    1511             :             }
    1512             :             else
    1513             :             {
    1514             :                 // any other intermediate Point is compressed
    1515           1 :                 float asfTuple[3] = {0.0f, 0.0f, 0.0f};
    1516           1 :                 memcpy(asfTuple, pabyData + nNextByte, 3 * 4);
    1517           1 :                 nNextByte += 3 * 4;
    1518             : 
    1519           1 :                 if (NEED_SWAP_SPATIALITE())
    1520             :                 {
    1521           0 :                     CPL_SWAP32PTR(asfTuple);
    1522           0 :                     CPL_SWAP32PTR(asfTuple + 1);
    1523           0 :                     CPL_SWAP32PTR(asfTuple + 2);
    1524             :                 }
    1525           1 :                 adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    1526           1 :                 adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    1527           1 :                 adfTuple[2] = asfTuple[2] + adfTupleBase[2];
    1528             :             }
    1529             : 
    1530          11 :             poLS->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    1531          11 :             adfTupleBase[0] = adfTuple[0];
    1532          11 :             adfTupleBase[1] = adfTuple[1];
    1533          11 :             adfTupleBase[2] = adfTuple[2];
    1534             :         }
    1535             : 
    1536           5 :         if (pnBytesConsumed)
    1537           5 :             *pnBytesConsumed = nNextByte;
    1538             :     }
    1539             : 
    1540             :     /* -------------------------------------------------------------------- */
    1541             :     /*      LineString [XYM] Compressed                                     */
    1542             :     /* -------------------------------------------------------------------- */
    1543         968 :     else if (nGType == OGRSpliteComprLineStringXYM)
    1544             :     {
    1545           4 :         if (nBytes < 8)
    1546           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1547             : 
    1548           4 :         GInt32 nPointCount = 0;
    1549           4 :         memcpy(&nPointCount, pabyData + 4, 4);
    1550           4 :         if (NEED_SWAP_SPATIALITE())
    1551           0 :             CPL_SWAP32PTR(&nPointCount);
    1552             : 
    1553           4 :         if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 24 * 2) / 16)
    1554           0 :             return OGRERR_CORRUPT_DATA;
    1555             : 
    1556           4 :         compressedSize = 24 * 2;                   // first and last Points
    1557           4 :         compressedSize += 16 * (nPointCount - 2);  // intermediate Points
    1558             : 
    1559           4 :         if (nBytes - 8 < compressedSize)
    1560           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1561             : 
    1562           4 :         OGRLineString *poLS = new OGRLineString();
    1563           4 :         poGeom = poLS;
    1564           4 :         poLS->setNumPoints(nPointCount);
    1565             : 
    1566           4 :         int nNextByte = 8;
    1567           4 :         double adfTupleBase[2] = {0.0, 0.0};
    1568             : 
    1569          13 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1570             :         {
    1571           9 :             double adfTuple[3] = {0.0, 0.0, 0.0};
    1572           9 :             if (iPoint == 0 || iPoint == (nPointCount - 1))
    1573             :             {
    1574             :                 // first and last Points are uncompressed
    1575           8 :                 memcpy(adfTuple, pabyData + nNextByte, 3 * 8);
    1576           8 :                 nNextByte += 3 * 8;
    1577             : 
    1578           8 :                 if (NEED_SWAP_SPATIALITE())
    1579             :                 {
    1580           0 :                     CPL_SWAP64PTR(adfTuple);
    1581           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1582           0 :                     CPL_SWAP64PTR(adfTuple + 2);
    1583           8 :                 }
    1584             :             }
    1585             :             else
    1586             :             {
    1587             :                 // any other intermediate Point is compressed
    1588           1 :                 float asfTuple[2] = {0.0f, 0.0f};
    1589           1 :                 memcpy(asfTuple, pabyData + nNextByte, 2 * 4);
    1590           1 :                 memcpy(adfTuple + 2, pabyData + nNextByte + 2 * 4, 8);
    1591           1 :                 nNextByte += 2 * 4 + 8;
    1592             : 
    1593           1 :                 if (NEED_SWAP_SPATIALITE())
    1594             :                 {
    1595           0 :                     CPL_SWAP32PTR(asfTuple);
    1596           0 :                     CPL_SWAP32PTR(asfTuple + 1);
    1597           0 :                     CPL_SWAP64PTR(
    1598             :                         adfTuple +
    1599             :                         2); /* adfTuple and not asfTuple is intended */
    1600             :                 }
    1601           1 :                 adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    1602           1 :                 adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    1603             :             }
    1604             : 
    1605           9 :             poLS->setPointM(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    1606           9 :             adfTupleBase[0] = adfTuple[0];
    1607           9 :             adfTupleBase[1] = adfTuple[1];
    1608             :         }
    1609             : 
    1610           4 :         if (pnBytesConsumed)
    1611           4 :             *pnBytesConsumed = nNextByte;
    1612             :     }
    1613             : 
    1614             :     /* -------------------------------------------------------------------- */
    1615             :     /*      LineString [XYZM] Compressed                                    */
    1616             :     /* -------------------------------------------------------------------- */
    1617         964 :     else if (nGType == OGRSpliteComprLineStringXYZM)
    1618             :     {
    1619           4 :         if (nBytes < 8)
    1620           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1621             : 
    1622           4 :         GInt32 nPointCount = 0;
    1623           4 :         memcpy(&nPointCount, pabyData + 4, 4);
    1624           4 :         if (NEED_SWAP_SPATIALITE())
    1625           0 :             CPL_SWAP32PTR(&nPointCount);
    1626             : 
    1627           4 :         if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 32 * 2) / 20)
    1628           0 :             return OGRERR_CORRUPT_DATA;
    1629             : 
    1630           4 :         compressedSize = 32 * 2;  // first and last Points
    1631             :         /* Note 20 is not an error : x,y,z are float and the m is a double */
    1632           4 :         compressedSize += 20 * (nPointCount - 2);  // intermediate Points
    1633             : 
    1634           4 :         if (nBytes - 8 < compressedSize)
    1635           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1636             : 
    1637           4 :         OGRLineString *poLS = new OGRLineString();
    1638           4 :         poGeom = poLS;
    1639           4 :         poLS->setNumPoints(nPointCount);
    1640             : 
    1641           4 :         int nNextByte = 8;
    1642           4 :         double adfTupleBase[3] = {0.0, 0.0, 0.0};
    1643             : 
    1644          13 :         for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1645             :         {
    1646           9 :             double adfTuple[4] = {0.0, 0.0, 0.0, 0.0};
    1647             : 
    1648           9 :             if (iPoint == 0 || iPoint == (nPointCount - 1))
    1649             :             {
    1650             :                 // first and last Points are uncompressed
    1651           8 :                 memcpy(adfTuple, pabyData + nNextByte, 4 * 8);
    1652           8 :                 nNextByte += 4 * 8;
    1653             : 
    1654           8 :                 if (NEED_SWAP_SPATIALITE())
    1655             :                 {
    1656           0 :                     CPL_SWAP64PTR(adfTuple);
    1657           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1658           0 :                     CPL_SWAP64PTR(adfTuple + 2);
    1659           0 :                     CPL_SWAP64PTR(adfTuple + 3);
    1660           8 :                 }
    1661             :             }
    1662             :             else
    1663             :             {
    1664             :                 // any other intermediate Point is compressed
    1665           1 :                 float asfTuple[3] = {0.0f, 0.0f, 0.0f};
    1666           1 :                 memcpy(asfTuple, pabyData + nNextByte, 3 * 4);
    1667           1 :                 memcpy(adfTuple + 3, pabyData + nNextByte + 3 * 4, 8);
    1668           1 :                 nNextByte += 3 * 4 + 8;
    1669             : 
    1670           1 :                 if (NEED_SWAP_SPATIALITE())
    1671             :                 {
    1672           0 :                     CPL_SWAP32PTR(asfTuple);
    1673           0 :                     CPL_SWAP32PTR(asfTuple + 1);
    1674           0 :                     CPL_SWAP32PTR(asfTuple + 2);
    1675           0 :                     CPL_SWAP64PTR(
    1676             :                         adfTuple +
    1677             :                         3); /* adfTuple and not asfTuple is intended */
    1678             :                 }
    1679           1 :                 adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    1680           1 :                 adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    1681           1 :                 adfTuple[2] = asfTuple[2] + adfTupleBase[2];
    1682             :             }
    1683             : 
    1684           9 :             poLS->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2],
    1685             :                            adfTuple[3]);
    1686           9 :             adfTupleBase[0] = adfTuple[0];
    1687           9 :             adfTupleBase[1] = adfTuple[1];
    1688           9 :             adfTupleBase[2] = adfTuple[2];
    1689             :         }
    1690             : 
    1691           4 :         if (pnBytesConsumed)
    1692           4 :             *pnBytesConsumed = nNextByte;
    1693             :     }
    1694             : 
    1695             :     /* -------------------------------------------------------------------- */
    1696             :     /*      Polygon [XY]                                                    */
    1697             :     /* -------------------------------------------------------------------- */
    1698         960 :     else if (nGType == OGRSplitePolygonXY)
    1699             :     {
    1700         570 :         if (nBytes < 8)
    1701           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1702             : 
    1703         570 :         GInt32 nRingCount = 0;
    1704         570 :         memcpy(&nRingCount, pabyData + 4, 4);
    1705         570 :         if (NEED_SWAP_SPATIALITE())
    1706           0 :             CPL_SWAP32PTR(&nRingCount);
    1707             : 
    1708         570 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    1709           0 :             return OGRERR_CORRUPT_DATA;
    1710             : 
    1711             :         // Each ring has a minimum of 4 bytes
    1712         570 :         if (nBytes - 8 < nRingCount * 4)
    1713           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1714             : 
    1715         570 :         int nNextByte = 8;
    1716             : 
    1717         570 :         OGRPolygon *poPoly = new OGRPolygon();
    1718         570 :         poGeom = poPoly;
    1719             : 
    1720        1145 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    1721             :         {
    1722         575 :             if (nBytes - nNextByte < 4)
    1723             :             {
    1724           0 :                 delete poPoly;
    1725           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1726             :             }
    1727             : 
    1728         575 :             GInt32 nPointCount = 0;
    1729         575 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    1730         575 :             if (NEED_SWAP_SPATIALITE())
    1731           0 :                 CPL_SWAP32PTR(&nPointCount);
    1732             : 
    1733         575 :             if (nPointCount < 0 || nPointCount > INT_MAX / (2 * 8))
    1734             :             {
    1735           0 :                 delete poPoly;
    1736           0 :                 return OGRERR_CORRUPT_DATA;
    1737             :             }
    1738             : 
    1739         575 :             nNextByte += 4;
    1740             : 
    1741         575 :             if (nBytes - nNextByte < 2 * 8 * nPointCount)
    1742             :             {
    1743           0 :                 delete poPoly;
    1744           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1745             :             }
    1746             : 
    1747         575 :             OGRLinearRing *poLR = new OGRLinearRing();
    1748         575 :             if (!NEED_SWAP_SPATIALITE())
    1749             :             {
    1750         575 :                 poLR->setPoints(
    1751             :                     nPointCount,
    1752         575 :                     reinterpret_cast<const OGRRawPoint *>(pabyData + nNextByte),
    1753             :                     nullptr);
    1754         575 :                 nNextByte += 2 * 8 * nPointCount;
    1755             :             }
    1756             :             else
    1757             :             {
    1758           0 :                 poLR->setNumPoints(nPointCount, FALSE);
    1759           0 :                 for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1760             :                 {
    1761           0 :                     double adfTuple[2] = {0.0, 0.0};
    1762           0 :                     memcpy(adfTuple, pabyData + nNextByte, 2 * 8);
    1763           0 :                     nNextByte += 2 * 8;
    1764           0 :                     CPL_SWAP64PTR(adfTuple);
    1765           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1766           0 :                     poLR->setPoint(iPoint, adfTuple[0], adfTuple[1]);
    1767             :                 }
    1768             :             }
    1769             : 
    1770         575 :             poPoly->addRingDirectly(poLR);
    1771             :         }
    1772             : 
    1773         570 :         if (pnBytesConsumed)
    1774         570 :             *pnBytesConsumed = nNextByte;
    1775             :     }
    1776             : 
    1777             :     /* -------------------------------------------------------------------- */
    1778             :     /*      Polygon [XYZ]                                                   */
    1779             :     /* -------------------------------------------------------------------- */
    1780         390 :     else if (nGType == OGRSplitePolygonXYZ)
    1781             :     {
    1782           6 :         if (nBytes < 8)
    1783           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1784             : 
    1785           6 :         GInt32 nRingCount = 0;
    1786           6 :         memcpy(&nRingCount, pabyData + 4, 4);
    1787           6 :         if (NEED_SWAP_SPATIALITE())
    1788           0 :             CPL_SWAP32PTR(&nRingCount);
    1789             : 
    1790           6 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    1791           0 :             return OGRERR_CORRUPT_DATA;
    1792             : 
    1793             :         // Each ring has a minimum of 4 bytes
    1794           6 :         if (nBytes - 8 < nRingCount * 4)
    1795           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1796             : 
    1797           6 :         int nNextByte = 8;
    1798             : 
    1799           6 :         OGRPolygon *poPoly = new OGRPolygon();
    1800           6 :         poGeom = poPoly;
    1801             : 
    1802          12 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    1803             :         {
    1804           6 :             if (nBytes - nNextByte < 4)
    1805             :             {
    1806           0 :                 delete poPoly;
    1807           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1808             :             }
    1809             : 
    1810           6 :             GInt32 nPointCount = 0;
    1811           6 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    1812           6 :             if (NEED_SWAP_SPATIALITE())
    1813           0 :                 CPL_SWAP32PTR(&nPointCount);
    1814             : 
    1815           6 :             if (nPointCount < 0 || nPointCount > INT_MAX / (3 * 8))
    1816             :             {
    1817           0 :                 delete poPoly;
    1818           0 :                 return OGRERR_CORRUPT_DATA;
    1819             :             }
    1820             : 
    1821           6 :             nNextByte += 4;
    1822             : 
    1823           6 :             if (nBytes - nNextByte < 3 * 8 * nPointCount)
    1824             :             {
    1825           0 :                 delete poPoly;
    1826           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1827             :             }
    1828             : 
    1829           6 :             OGRLinearRing *poLR = new OGRLinearRing();
    1830           6 :             poLR->setNumPoints(nPointCount, FALSE);
    1831             : 
    1832          36 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1833             :             {
    1834          30 :                 double adfTuple[3] = {0.0, 0.0, 0.0};
    1835          30 :                 memcpy(adfTuple, pabyData + nNextByte, 3 * 8);
    1836          30 :                 nNextByte += 3 * 8;
    1837             : 
    1838          30 :                 if (NEED_SWAP_SPATIALITE())
    1839             :                 {
    1840           0 :                     CPL_SWAP64PTR(adfTuple);
    1841           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1842           0 :                     CPL_SWAP64PTR(adfTuple + 2);
    1843             :                 }
    1844             : 
    1845          30 :                 poLR->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    1846             :             }
    1847             : 
    1848           6 :             poPoly->addRingDirectly(poLR);
    1849             :         }
    1850             : 
    1851           6 :         if (pnBytesConsumed)
    1852           6 :             *pnBytesConsumed = nNextByte;
    1853             :     }
    1854             : 
    1855             :     /* -------------------------------------------------------------------- */
    1856             :     /*      Polygon [XYM]                                                   */
    1857             :     /* -------------------------------------------------------------------- */
    1858         384 :     else if (nGType == OGRSplitePolygonXYM)
    1859             :     {
    1860           3 :         if (nBytes < 8)
    1861           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1862             : 
    1863           3 :         GInt32 nRingCount = 0;
    1864           3 :         memcpy(&nRingCount, pabyData + 4, 4);
    1865           3 :         if (NEED_SWAP_SPATIALITE())
    1866           0 :             CPL_SWAP32PTR(&nRingCount);
    1867             : 
    1868           3 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    1869           0 :             return OGRERR_CORRUPT_DATA;
    1870             : 
    1871             :         // Each ring has a minimum of 4 bytes
    1872           3 :         if (nBytes - 8 < nRingCount * 4)
    1873           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1874             : 
    1875           3 :         int nNextByte = 8;
    1876             : 
    1877           3 :         OGRPolygon *poPoly = new OGRPolygon();
    1878           3 :         poGeom = poPoly;
    1879             : 
    1880           6 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    1881             :         {
    1882           3 :             if (nBytes - nNextByte < 4)
    1883             :             {
    1884           0 :                 delete poPoly;
    1885           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1886             :             }
    1887             : 
    1888           3 :             GInt32 nPointCount = 0;
    1889           3 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    1890           3 :             if (NEED_SWAP_SPATIALITE())
    1891           0 :                 CPL_SWAP32PTR(&nPointCount);
    1892             : 
    1893           3 :             if (nPointCount < 0 || nPointCount > INT_MAX / (3 * 8))
    1894             :             {
    1895           0 :                 delete poPoly;
    1896           0 :                 return OGRERR_CORRUPT_DATA;
    1897             :             }
    1898             : 
    1899           3 :             nNextByte += 4;
    1900             : 
    1901           3 :             if (nBytes - nNextByte < 3 * 8 * nPointCount)
    1902             :             {
    1903           0 :                 delete poPoly;
    1904           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1905             :             }
    1906             : 
    1907           3 :             OGRLinearRing *poLR = new OGRLinearRing();
    1908           3 :             poLR->setNumPoints(nPointCount, FALSE);
    1909             : 
    1910          18 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1911             :             {
    1912          15 :                 double adfTuple[3] = {0.0, 0.0, 0.0};
    1913          15 :                 memcpy(adfTuple, pabyData + nNextByte, 3 * 8);
    1914          15 :                 nNextByte += 3 * 8;
    1915             : 
    1916          15 :                 if (NEED_SWAP_SPATIALITE())
    1917             :                 {
    1918           0 :                     CPL_SWAP64PTR(adfTuple);
    1919           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1920           0 :                     CPL_SWAP64PTR(adfTuple + 2);
    1921             :                 }
    1922             : 
    1923          15 :                 poLR->setPointM(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    1924             :             }
    1925             : 
    1926           3 :             poPoly->addRingDirectly(poLR);
    1927             :         }
    1928             : 
    1929           3 :         if (pnBytesConsumed)
    1930           3 :             *pnBytesConsumed = nNextByte;
    1931             :     }
    1932             : 
    1933             :     /* -------------------------------------------------------------------- */
    1934             :     /*      Polygon [XYZM]                                                  */
    1935             :     /* -------------------------------------------------------------------- */
    1936         381 :     else if (nGType == OGRSplitePolygonXYZM)
    1937             :     {
    1938           3 :         if (nBytes < 8)
    1939           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1940             : 
    1941           3 :         GInt32 nRingCount = 0;
    1942           3 :         memcpy(&nRingCount, pabyData + 4, 4);
    1943           3 :         if (NEED_SWAP_SPATIALITE())
    1944           0 :             CPL_SWAP32PTR(&nRingCount);
    1945             : 
    1946           3 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    1947           0 :             return OGRERR_CORRUPT_DATA;
    1948             : 
    1949             :         // Each ring has a minimum of 4 bytes
    1950           3 :         if (nBytes - 8 < nRingCount * 4)
    1951           0 :             return OGRERR_NOT_ENOUGH_DATA;
    1952             : 
    1953           3 :         int nNextByte = 8;
    1954             : 
    1955           3 :         OGRPolygon *poPoly = new OGRPolygon();
    1956           3 :         poGeom = poPoly;
    1957             : 
    1958           6 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    1959             :         {
    1960           3 :             if (nBytes - nNextByte < 4)
    1961             :             {
    1962           0 :                 delete poPoly;
    1963           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1964             :             }
    1965             : 
    1966           3 :             GInt32 nPointCount = 0;
    1967           3 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    1968           3 :             if (NEED_SWAP_SPATIALITE())
    1969           0 :                 CPL_SWAP32PTR(&nPointCount);
    1970             : 
    1971           3 :             if (nPointCount < 0 || nPointCount > INT_MAX / (4 * 8))
    1972             :             {
    1973           0 :                 delete poPoly;
    1974           0 :                 return OGRERR_CORRUPT_DATA;
    1975             :             }
    1976             : 
    1977           3 :             nNextByte += 4;
    1978             : 
    1979           3 :             if (nBytes - nNextByte < 4 * 8 * nPointCount)
    1980             :             {
    1981           0 :                 delete poPoly;
    1982           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1983             :             }
    1984             : 
    1985           3 :             OGRLinearRing *poLR = new OGRLinearRing();
    1986           3 :             poLR->setNumPoints(nPointCount, FALSE);
    1987             : 
    1988          18 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    1989             :             {
    1990          15 :                 double adfTuple[4] = {0.0, 0.0, 0.0, 0.0};
    1991             : 
    1992          15 :                 memcpy(adfTuple, pabyData + nNextByte, 4 * 8);
    1993          15 :                 nNextByte += 4 * 8;
    1994             : 
    1995          15 :                 if (NEED_SWAP_SPATIALITE())
    1996             :                 {
    1997           0 :                     CPL_SWAP64PTR(adfTuple);
    1998           0 :                     CPL_SWAP64PTR(adfTuple + 1);
    1999           0 :                     CPL_SWAP64PTR(adfTuple + 2);
    2000           0 :                     CPL_SWAP64PTR(adfTuple + 3);
    2001             :                 }
    2002             : 
    2003          15 :                 poLR->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2],
    2004             :                                adfTuple[3]);
    2005             :             }
    2006             : 
    2007           3 :             poPoly->addRingDirectly(poLR);
    2008             :         }
    2009             : 
    2010           3 :         if (pnBytesConsumed)
    2011           3 :             *pnBytesConsumed = nNextByte;
    2012             :     }
    2013             : 
    2014             :     /* -------------------------------------------------------------------- */
    2015             :     /*      Polygon [XY] Compressed                                         */
    2016             :     /* -------------------------------------------------------------------- */
    2017         378 :     else if (nGType == OGRSpliteComprPolygonXY)
    2018             :     {
    2019         291 :         if (nBytes < 8)
    2020           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2021             : 
    2022         291 :         GInt32 nRingCount = 0;
    2023         291 :         memcpy(&nRingCount, pabyData + 4, 4);
    2024         291 :         if (NEED_SWAP_SPATIALITE())
    2025           0 :             CPL_SWAP32PTR(&nRingCount);
    2026             : 
    2027         291 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    2028           0 :             return OGRERR_CORRUPT_DATA;
    2029             : 
    2030             :         // Each ring has a minimum of 4 bytes
    2031         291 :         if (nBytes - 8 < nRingCount * 4)
    2032           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2033             : 
    2034         291 :         int nNextByte = 8;
    2035             : 
    2036         291 :         OGRPolygon *poPoly = new OGRPolygon();
    2037         291 :         poGeom = poPoly;
    2038             : 
    2039         583 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    2040             :         {
    2041         292 :             if (nBytes - nNextByte < 4)
    2042             :             {
    2043           0 :                 delete poPoly;
    2044           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2045             :             }
    2046             : 
    2047         292 :             GInt32 nPointCount = 0;
    2048         292 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    2049         292 :             if (NEED_SWAP_SPATIALITE())
    2050           0 :                 CPL_SWAP32PTR(&nPointCount);
    2051             : 
    2052         292 :             if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 16 * 2) / 8)
    2053             :             {
    2054           0 :                 delete poPoly;
    2055           0 :                 return OGRERR_CORRUPT_DATA;
    2056             :             }
    2057             : 
    2058         292 :             compressedSize = 16 * 2;                  // first and last Points
    2059         292 :             compressedSize += 8 * (nPointCount - 2);  // intermediate Points
    2060             : 
    2061         292 :             nNextByte += 4;
    2062             : 
    2063         292 :             if (nBytes - nNextByte < compressedSize)
    2064             :             {
    2065           0 :                 delete poPoly;
    2066           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2067             :             }
    2068             : 
    2069         292 :             double adfTupleBase[2] = {0.0, 0.0};
    2070         292 :             OGRLinearRing *poLR = new OGRLinearRing();
    2071         292 :             poLR->setNumPoints(nPointCount, FALSE);
    2072             : 
    2073        8771 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    2074             :             {
    2075        8479 :                 double adfTuple[2] = {0.0, 0.0};
    2076        8479 :                 if (iPoint == 0 || iPoint == (nPointCount - 1))
    2077             :                 {
    2078             :                     // first and last Points are uncompressed
    2079         584 :                     memcpy(adfTuple, pabyData + nNextByte, 2 * 8);
    2080         584 :                     nNextByte += 2 * 8;
    2081             : 
    2082         584 :                     if (NEED_SWAP_SPATIALITE())
    2083             :                     {
    2084           0 :                         CPL_SWAP64PTR(adfTuple);
    2085           0 :                         CPL_SWAP64PTR(adfTuple + 1);
    2086         584 :                     }
    2087             :                 }
    2088             :                 else
    2089             :                 {
    2090             :                     // any other intermediate Point is compressed
    2091        7895 :                     float asfTuple[2] = {0.0f, 0.0f};
    2092        7895 :                     memcpy(asfTuple, pabyData + nNextByte, 2 * 4);
    2093        7895 :                     nNextByte += 2 * 4;
    2094             : 
    2095        7895 :                     if (NEED_SWAP_SPATIALITE())
    2096             :                     {
    2097           0 :                         CPL_SWAP32PTR(asfTuple);
    2098           0 :                         CPL_SWAP32PTR(asfTuple + 1);
    2099             :                     }
    2100        7895 :                     adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    2101        7895 :                     adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    2102             :                 }
    2103             : 
    2104        8479 :                 poLR->setPoint(iPoint, adfTuple[0], adfTuple[1]);
    2105        8479 :                 adfTupleBase[0] = adfTuple[0];
    2106        8479 :                 adfTupleBase[1] = adfTuple[1];
    2107             :             }
    2108             : 
    2109         292 :             poPoly->addRingDirectly(poLR);
    2110             :         }
    2111             : 
    2112         291 :         if (pnBytesConsumed)
    2113         291 :             *pnBytesConsumed = nNextByte;
    2114             :     }
    2115             : 
    2116             :     /* -------------------------------------------------------------------- */
    2117             :     /*      Polygon [XYZ] Compressed                                        */
    2118             :     /* -------------------------------------------------------------------- */
    2119          87 :     else if (nGType == OGRSpliteComprPolygonXYZ)
    2120             :     {
    2121           4 :         if (nBytes < 8)
    2122           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2123             : 
    2124           4 :         GInt32 nRingCount = 0;
    2125           4 :         memcpy(&nRingCount, pabyData + 4, 4);
    2126           4 :         if (NEED_SWAP_SPATIALITE())
    2127           0 :             CPL_SWAP32PTR(&nRingCount);
    2128             : 
    2129           4 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    2130           0 :             return OGRERR_CORRUPT_DATA;
    2131             : 
    2132             :         // Each ring has a minimum of 4 bytes
    2133           4 :         if (nBytes - 8 < nRingCount * 4)
    2134           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2135             : 
    2136           4 :         int nNextByte = 8;
    2137             : 
    2138           4 :         OGRPolygon *poPoly = new OGRPolygon();
    2139           4 :         poGeom = poPoly;
    2140             : 
    2141           8 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    2142             :         {
    2143           4 :             if (nBytes - nNextByte < 4)
    2144             :             {
    2145           0 :                 delete poPoly;
    2146           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2147             :             }
    2148             : 
    2149           4 :             GInt32 nPointCount = 0;
    2150           4 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    2151           4 :             if (NEED_SWAP_SPATIALITE())
    2152           0 :                 CPL_SWAP32PTR(&nPointCount);
    2153             : 
    2154           4 :             if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 24 * 2) / 12)
    2155             :             {
    2156           0 :                 delete poPoly;
    2157           0 :                 return OGRERR_CORRUPT_DATA;
    2158             :             }
    2159             : 
    2160           4 :             compressedSize = 24 * 2;                   // first and last Points
    2161           4 :             compressedSize += 12 * (nPointCount - 2);  // intermediate Points
    2162             : 
    2163           4 :             nNextByte += 4;
    2164             : 
    2165           4 :             if (nBytes - nNextByte < compressedSize)
    2166             :             {
    2167           0 :                 delete poPoly;
    2168           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2169             :             }
    2170             : 
    2171           4 :             double adfTupleBase[3] = {0.0, 0.0, 0.0};
    2172           4 :             OGRLinearRing *poLR = new OGRLinearRing();
    2173           4 :             poLR->setNumPoints(nPointCount, FALSE);
    2174             : 
    2175          24 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    2176             :             {
    2177          20 :                 double adfTuple[3] = {0.0, 0.0, 0.0};
    2178          20 :                 if (iPoint == 0 || iPoint == (nPointCount - 1))
    2179             :                 {
    2180             :                     // first and last Points are uncompressed
    2181           8 :                     memcpy(adfTuple, pabyData + nNextByte, 3 * 8);
    2182           8 :                     nNextByte += 3 * 8;
    2183             : 
    2184           8 :                     if (NEED_SWAP_SPATIALITE())
    2185             :                     {
    2186           0 :                         CPL_SWAP64PTR(adfTuple);
    2187           0 :                         CPL_SWAP64PTR(adfTuple + 1);
    2188           0 :                         CPL_SWAP64PTR(adfTuple + 2);
    2189           8 :                     }
    2190             :                 }
    2191             :                 else
    2192             :                 {
    2193             :                     // any other intermediate Point is compressed
    2194          12 :                     float asfTuple[3] = {0.0, 0.0, 0.0};
    2195          12 :                     memcpy(asfTuple, pabyData + nNextByte, 3 * 4);
    2196          12 :                     nNextByte += 3 * 4;
    2197             : 
    2198          12 :                     if (NEED_SWAP_SPATIALITE())
    2199             :                     {
    2200           0 :                         CPL_SWAP32PTR(asfTuple);
    2201           0 :                         CPL_SWAP32PTR(asfTuple + 1);
    2202           0 :                         CPL_SWAP32PTR(asfTuple + 2);
    2203             :                     }
    2204          12 :                     adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    2205          12 :                     adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    2206          12 :                     adfTuple[2] = asfTuple[2] + adfTupleBase[2];
    2207             :                 }
    2208             : 
    2209          20 :                 poLR->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    2210          20 :                 adfTupleBase[0] = adfTuple[0];
    2211          20 :                 adfTupleBase[1] = adfTuple[1];
    2212          20 :                 adfTupleBase[2] = adfTuple[2];
    2213             :             }
    2214             : 
    2215           4 :             poPoly->addRingDirectly(poLR);
    2216             :         }
    2217             : 
    2218           4 :         if (pnBytesConsumed)
    2219           4 :             *pnBytesConsumed = nNextByte;
    2220             :     }
    2221             : 
    2222             :     /* -------------------------------------------------------------------- */
    2223             :     /*      Polygon [XYM] Compressed                                        */
    2224             :     /* -------------------------------------------------------------------- */
    2225          83 :     else if (nGType == OGRSpliteComprPolygonXYM)
    2226             :     {
    2227           3 :         if (nBytes < 8)
    2228           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2229             : 
    2230           3 :         GInt32 nRingCount = 0;
    2231           3 :         memcpy(&nRingCount, pabyData + 4, 4);
    2232           3 :         if (NEED_SWAP_SPATIALITE())
    2233           0 :             CPL_SWAP32PTR(&nRingCount);
    2234             : 
    2235           3 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    2236           0 :             return OGRERR_CORRUPT_DATA;
    2237             : 
    2238             :         // Each ring has a minimum of 4 bytes
    2239           3 :         if (nBytes - 8 < nRingCount * 4)
    2240           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2241             : 
    2242           3 :         int nNextByte = 8;
    2243             : 
    2244           3 :         OGRPolygon *poPoly = new OGRPolygon();
    2245           3 :         poGeom = poPoly;
    2246             : 
    2247           6 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    2248             :         {
    2249           3 :             if (nBytes - nNextByte < 4)
    2250             :             {
    2251           0 :                 delete poPoly;
    2252           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2253             :             }
    2254             : 
    2255           3 :             GInt32 nPointCount = 0;
    2256           3 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    2257           3 :             if (NEED_SWAP_SPATIALITE())
    2258           0 :                 CPL_SWAP32PTR(&nPointCount);
    2259             : 
    2260           3 :             if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 24 * 2) / 16)
    2261             :             {
    2262           0 :                 delete poPoly;
    2263           0 :                 return OGRERR_CORRUPT_DATA;
    2264             :             }
    2265             : 
    2266           3 :             compressedSize = 24 * 2;                   // first and last Points
    2267           3 :             compressedSize += 16 * (nPointCount - 2);  // intermediate Points
    2268             : 
    2269           3 :             nNextByte += 4;
    2270             : 
    2271           3 :             if (nBytes - nNextByte < compressedSize)
    2272             :             {
    2273           0 :                 delete poPoly;
    2274           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2275             :             }
    2276             : 
    2277           3 :             double adfTupleBase[2] = {0.0, 0.0};
    2278           3 :             OGRLinearRing *poLR = new OGRLinearRing();
    2279           3 :             poLR->setNumPoints(nPointCount, FALSE);
    2280             : 
    2281          18 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    2282             :             {
    2283          15 :                 double adfTuple[3] = {0.0, 0.0, 0.0};
    2284          15 :                 if (iPoint == 0 || iPoint == (nPointCount - 1))
    2285             :                 {
    2286             :                     // first and last Points are uncompressed
    2287           6 :                     memcpy(adfTuple, pabyData + nNextByte, 3 * 8);
    2288           6 :                     nNextByte += 3 * 8;
    2289             : 
    2290           6 :                     if (NEED_SWAP_SPATIALITE())
    2291             :                     {
    2292           0 :                         CPL_SWAP64PTR(adfTuple);
    2293           0 :                         CPL_SWAP64PTR(adfTuple + 1);
    2294           0 :                         CPL_SWAP64PTR(adfTuple + 2);
    2295           6 :                     }
    2296             :                 }
    2297             :                 else
    2298             :                 {
    2299             :                     // any other intermediate Point is compressed
    2300           9 :                     float asfTuple[2] = {0.0f, 0.0f};
    2301           9 :                     memcpy(asfTuple, pabyData + nNextByte, 2 * 4);
    2302           9 :                     memcpy(adfTuple + 2, pabyData + nNextByte + 2 * 4, 8);
    2303           9 :                     nNextByte += 2 * 4 + 8;
    2304             : 
    2305           9 :                     if (NEED_SWAP_SPATIALITE())
    2306             :                     {
    2307           0 :                         CPL_SWAP32PTR(asfTuple);
    2308           0 :                         CPL_SWAP32PTR(asfTuple + 1);
    2309           0 :                         CPL_SWAP64PTR(
    2310             :                             adfTuple +
    2311             :                             2); /* adfTuple and not asfTuple is intended */
    2312             :                     }
    2313           9 :                     adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    2314           9 :                     adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    2315             :                 }
    2316             : 
    2317          15 :                 poLR->setPointM(iPoint, adfTuple[0], adfTuple[1], adfTuple[2]);
    2318          15 :                 adfTupleBase[0] = adfTuple[0];
    2319          15 :                 adfTupleBase[1] = adfTuple[1];
    2320             :             }
    2321             : 
    2322           3 :             poPoly->addRingDirectly(poLR);
    2323             :         }
    2324             : 
    2325           3 :         if (pnBytesConsumed)
    2326           3 :             *pnBytesConsumed = nNextByte;
    2327             :     }
    2328             : 
    2329             :     /* -------------------------------------------------------------------- */
    2330             :     /*      Polygon [XYZM] Compressed                                       */
    2331             :     /* -------------------------------------------------------------------- */
    2332          80 :     else if (nGType == OGRSpliteComprPolygonXYZM)
    2333             :     {
    2334           3 :         if (nBytes < 8)
    2335           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2336             : 
    2337           3 :         GInt32 nRingCount = 0;
    2338           3 :         memcpy(&nRingCount, pabyData + 4, 4);
    2339           3 :         if (NEED_SWAP_SPATIALITE())
    2340           0 :             CPL_SWAP32PTR(&nRingCount);
    2341             : 
    2342           3 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    2343           0 :             return OGRERR_CORRUPT_DATA;
    2344             : 
    2345             :         // Each ring has a minimum of 4 bytes
    2346           3 :         if (nBytes - 8 < nRingCount * 4)
    2347           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2348             : 
    2349           3 :         int nNextByte = 8;
    2350             : 
    2351           3 :         OGRPolygon *poPoly = new OGRPolygon();
    2352           3 :         poGeom = poPoly;
    2353             : 
    2354           6 :         for (int iRing = 0; iRing < nRingCount; iRing++)
    2355             :         {
    2356           3 :             if (nBytes - nNextByte < 4)
    2357             :             {
    2358           0 :                 delete poPoly;
    2359           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2360             :             }
    2361             : 
    2362           3 :             GInt32 nPointCount = 0;
    2363           3 :             memcpy(&nPointCount, pabyData + nNextByte, 4);
    2364           3 :             if (NEED_SWAP_SPATIALITE())
    2365           0 :                 CPL_SWAP32PTR(&nPointCount);
    2366             : 
    2367           3 :             if (nPointCount < 0 || nPointCount - 2 > (INT_MAX - 32 * 2) / 20)
    2368             :             {
    2369           0 :                 delete poPoly;
    2370           0 :                 return OGRERR_CORRUPT_DATA;
    2371             :             }
    2372             : 
    2373           3 :             compressedSize = 32 * 2;  // first and last Points
    2374             :             /* Note 20 is not an error : x,y,z are float and the m is a double
    2375             :              */
    2376           3 :             compressedSize += 20 * (nPointCount - 2);  // intermediate Points
    2377             : 
    2378           3 :             nNextByte += 4;
    2379             : 
    2380           3 :             if (nBytes - nNextByte < compressedSize)
    2381             :             {
    2382           0 :                 delete poPoly;
    2383           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2384             :             }
    2385             : 
    2386           3 :             double adfTupleBase[3] = {0.0, 0.0, 0.0};
    2387           3 :             OGRLinearRing *poLR = new OGRLinearRing();
    2388           3 :             poLR->setNumPoints(nPointCount, FALSE);
    2389             : 
    2390          18 :             for (int iPoint = 0; iPoint < nPointCount; iPoint++)
    2391             :             {
    2392          15 :                 double adfTuple[4] = {0.0, 0.0, 0.0, 0.0};
    2393          15 :                 if (iPoint == 0 || iPoint == (nPointCount - 1))
    2394             :                 {
    2395             :                     // first and last Points are uncompressed
    2396           6 :                     memcpy(adfTuple, pabyData + nNextByte, 4 * 8);
    2397           6 :                     nNextByte += 4 * 8;
    2398             : 
    2399           6 :                     if (NEED_SWAP_SPATIALITE())
    2400             :                     {
    2401           0 :                         CPL_SWAP64PTR(adfTuple);
    2402           0 :                         CPL_SWAP64PTR(adfTuple + 1);
    2403           0 :                         CPL_SWAP64PTR(adfTuple + 2);
    2404           0 :                         CPL_SWAP64PTR(adfTuple + 3);
    2405           6 :                     }
    2406             :                 }
    2407             :                 else
    2408             :                 {
    2409             :                     // any other intermediate Point is compressed
    2410           9 :                     float asfTuple[3] = {0.0f, 0.0f, 0.0f};
    2411           9 :                     memcpy(asfTuple, pabyData + nNextByte, 3 * 4);
    2412           9 :                     memcpy(adfTuple + 3, pabyData + nNextByte + 3 * 4, 8);
    2413           9 :                     nNextByte += 3 * 4 + 8;
    2414             : 
    2415           9 :                     if (NEED_SWAP_SPATIALITE())
    2416             :                     {
    2417           0 :                         CPL_SWAP32PTR(asfTuple);
    2418           0 :                         CPL_SWAP32PTR(asfTuple + 1);
    2419           0 :                         CPL_SWAP32PTR(asfTuple + 2);
    2420           0 :                         CPL_SWAP64PTR(
    2421             :                             adfTuple +
    2422             :                             3); /* adfTuple and not asfTuple is intended */
    2423             :                     }
    2424           9 :                     adfTuple[0] = asfTuple[0] + adfTupleBase[0];
    2425           9 :                     adfTuple[1] = asfTuple[1] + adfTupleBase[1];
    2426           9 :                     adfTuple[2] = asfTuple[2] + adfTupleBase[2];
    2427             :                 }
    2428             : 
    2429          15 :                 poLR->setPoint(iPoint, adfTuple[0], adfTuple[1], adfTuple[2],
    2430             :                                adfTuple[3]);
    2431          15 :                 adfTupleBase[0] = adfTuple[0];
    2432          15 :                 adfTupleBase[1] = adfTuple[1];
    2433          15 :                 adfTupleBase[2] = adfTuple[2];
    2434             :             }
    2435             : 
    2436           3 :             poPoly->addRingDirectly(poLR);
    2437             :         }
    2438             : 
    2439           3 :         if (pnBytesConsumed)
    2440           3 :             *pnBytesConsumed = nNextByte;
    2441             :     }
    2442             : 
    2443             :     /* -------------------------------------------------------------------- */
    2444             :     /*      GeometryCollections of various kinds.                           */
    2445             :     /* -------------------------------------------------------------------- */
    2446          77 :     else if ((nGType >= OGRSpliteMultiPointXY &&
    2447          77 :               nGType <= OGRSpliteGeometryCollectionXY) ||  // XY types
    2448          30 :              (nGType >= OGRSpliteMultiPointXYZ &&
    2449          30 :               nGType <= OGRSpliteGeometryCollectionXYZ) ||  // XYZ types
    2450          16 :              (nGType >= OGRSpliteMultiPointXYM &&
    2451          16 :               nGType <= OGRSpliteGeometryCollectionXYM) ||  // XYM types
    2452           8 :              (nGType >= OGRSpliteMultiPointXYZM &&
    2453           8 :               nGType <= OGRSpliteGeometryCollectionXYZM) ||  // XYZM types
    2454           0 :              (nGType >= OGRSpliteComprMultiLineStringXY &&
    2455           0 :               nGType <= OGRSpliteComprGeometryCollectionXY) ||  // XY compressed
    2456           0 :              (nGType >= OGRSpliteComprMultiLineStringXYZ &&
    2457           0 :               nGType <=
    2458           0 :                   OGRSpliteComprGeometryCollectionXYZ) ||  // XYZ compressed
    2459           0 :              (nGType >= OGRSpliteComprMultiLineStringXYM &&
    2460           0 :               nGType <=
    2461           0 :                   OGRSpliteComprGeometryCollectionXYM) ||  // XYM compressed
    2462           0 :              (nGType >= OGRSpliteComprMultiLineStringXYZM &&
    2463           0 :               nGType <=
    2464             :                   OGRSpliteComprGeometryCollectionXYZM))  // XYZM compressed
    2465             :     {
    2466          77 :         if (nBytes < 8)
    2467           1 :             return OGRERR_NOT_ENOUGH_DATA;
    2468             : 
    2469          77 :         GInt32 nGeomCount = 0;
    2470          77 :         memcpy(&nGeomCount, pabyData + 4, 4);
    2471          77 :         if (NEED_SWAP_SPATIALITE())
    2472           0 :             CPL_SWAP32PTR(&nGeomCount);
    2473             : 
    2474          77 :         if (nGeomCount < 0 || nGeomCount > INT_MAX / 9)
    2475           1 :             return OGRERR_CORRUPT_DATA;
    2476             : 
    2477             :         // Each sub geometry takes at least 9 bytes
    2478          76 :         if (nBytes - 8 < nGeomCount * 9)
    2479           0 :             return OGRERR_NOT_ENOUGH_DATA;
    2480             : 
    2481          76 :         int nBytesUsed = 8;
    2482          76 :         OGRGeometryCollection *poGC = nullptr;
    2483             : 
    2484          76 :         switch (nGType)
    2485             :         {
    2486          12 :             case OGRSpliteMultiPointXY:
    2487             :             case OGRSpliteMultiPointXYZ:
    2488             :             case OGRSpliteMultiPointXYM:
    2489             :             case OGRSpliteMultiPointXYZM:
    2490          12 :                 poGC = new OGRMultiPoint();
    2491          12 :                 break;
    2492          13 :             case OGRSpliteMultiLineStringXY:
    2493             :             case OGRSpliteMultiLineStringXYZ:
    2494             :             case OGRSpliteMultiLineStringXYM:
    2495             :             case OGRSpliteMultiLineStringXYZM:
    2496             :             case OGRSpliteComprMultiLineStringXY:
    2497             :             case OGRSpliteComprMultiLineStringXYZ:
    2498             :             case OGRSpliteComprMultiLineStringXYM:
    2499             :             case OGRSpliteComprMultiLineStringXYZM:
    2500          13 :                 poGC = new OGRMultiLineString();
    2501          13 :                 break;
    2502          25 :             case OGRSpliteMultiPolygonXY:
    2503             :             case OGRSpliteMultiPolygonXYZ:
    2504             :             case OGRSpliteMultiPolygonXYM:
    2505             :             case OGRSpliteMultiPolygonXYZM:
    2506             :             case OGRSpliteComprMultiPolygonXY:
    2507             :             case OGRSpliteComprMultiPolygonXYZ:
    2508             :             case OGRSpliteComprMultiPolygonXYM:
    2509             :             case OGRSpliteComprMultiPolygonXYZM:
    2510          25 :                 poGC = new OGRMultiPolygon();
    2511          25 :                 break;
    2512          26 :             case OGRSpliteGeometryCollectionXY:
    2513             :             case OGRSpliteGeometryCollectionXYZ:
    2514             :             case OGRSpliteGeometryCollectionXYM:
    2515             :             case OGRSpliteGeometryCollectionXYZM:
    2516             :             case OGRSpliteComprGeometryCollectionXY:
    2517             :             case OGRSpliteComprGeometryCollectionXYZ:
    2518             :             case OGRSpliteComprGeometryCollectionXYM:
    2519             :             case OGRSpliteComprGeometryCollectionXYZM:
    2520          26 :                 poGC = new OGRGeometryCollection();
    2521          26 :                 break;
    2522             :         }
    2523             : 
    2524          76 :         assert(nullptr != poGC);
    2525             : 
    2526         187 :         for (int iGeom = 0; iGeom < nGeomCount; iGeom++)
    2527             :         {
    2528         111 :             OGRGeometry *poThisGeom = nullptr;
    2529             : 
    2530         111 :             if (nBytes - nBytesUsed < 5)
    2531             :             {
    2532           0 :                 delete poGC;
    2533           0 :                 return OGRERR_NOT_ENOUGH_DATA;
    2534             :             }
    2535             : 
    2536         111 :             if (pabyData[nBytesUsed] != 0x69)
    2537             :             {
    2538           0 :                 delete poGC;
    2539           0 :                 return OGRERR_CORRUPT_DATA;
    2540             :             }
    2541             : 
    2542         111 :             nBytesUsed++;
    2543             : 
    2544         111 :             int nThisGeomSize = 0;
    2545         222 :             OGRErr eErr = createFromSpatialiteInternal(
    2546         111 :                 pabyData + nBytesUsed, &poThisGeom, nBytes - nBytesUsed,
    2547             :                 eByteOrder, &nThisGeomSize, nRecLevel + 1);
    2548         111 :             if (eErr != OGRERR_NONE)
    2549             :             {
    2550           0 :                 delete poGC;
    2551           0 :                 return eErr;
    2552             :             }
    2553             : 
    2554         111 :             nBytesUsed += nThisGeomSize;
    2555         111 :             eErr = poGC->addGeometryDirectly(poThisGeom);
    2556         111 :             if (eErr != OGRERR_NONE)
    2557             :             {
    2558           0 :                 delete poThisGeom;
    2559           0 :                 delete poGC;
    2560           0 :                 return eErr;
    2561             :             }
    2562             :         }
    2563             : 
    2564          76 :         poGeom = poGC;
    2565          76 :         if (pnBytesConsumed)
    2566          76 :             *pnBytesConsumed = nBytesUsed;
    2567             :     }
    2568             : 
    2569             :     /* -------------------------------------------------------------------- */
    2570             :     /*      Currently unsupported geometry.                                 */
    2571             :     /* -------------------------------------------------------------------- */
    2572             :     else
    2573             :     {
    2574           0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    2575             :     }
    2576             : 
    2577        1568 :     *ppoReturn = poGeom;
    2578        1568 :     return OGRERR_NONE;
    2579             : }
    2580             : 
    2581             : /************************************************************************/
    2582             : /*                     GetSpatialiteGeometryHeader()                    */
    2583             : /************************************************************************/
    2584             : typedef struct
    2585             : {
    2586             :     int nSpatialiteType;
    2587             :     OGRwkbGeometryType eGType;
    2588             : } SpatialiteOGRGeometryTypeTuple;
    2589             : 
    2590             : static const SpatialiteOGRGeometryTypeTuple anTypesMap[] = {
    2591             :     {OGRSplitePointXY, wkbPoint},
    2592             :     {OGRSplitePointXYZ, wkbPoint25D},
    2593             :     {OGRSplitePointXYM, wkbPointM},
    2594             :     {OGRSplitePointXYZM, wkbPointZM},
    2595             :     {OGRSpliteLineStringXY, wkbLineString},
    2596             :     {OGRSpliteLineStringXYZ, wkbLineString25D},
    2597             :     {OGRSpliteLineStringXYM, wkbLineStringM},
    2598             :     {OGRSpliteLineStringXYZM, wkbLineStringZM},
    2599             :     {OGRSpliteComprLineStringXY, wkbLineString},
    2600             :     {OGRSpliteComprLineStringXYZ, wkbLineString25D},
    2601             :     {OGRSpliteComprLineStringXYM, wkbLineStringM},
    2602             :     {OGRSpliteComprLineStringXYZM, wkbLineStringZM},
    2603             :     {OGRSplitePolygonXY, wkbPolygon},
    2604             :     {OGRSplitePolygonXYZ, wkbPolygon25D},
    2605             :     {OGRSplitePolygonXYM, wkbPolygonM},
    2606             :     {OGRSplitePolygonXYZM, wkbPolygonZM},
    2607             :     {OGRSpliteComprPolygonXY, wkbPolygon},
    2608             :     {OGRSpliteComprPolygonXYZ, wkbPolygon25D},
    2609             :     {OGRSpliteComprPolygonXYM, wkbPolygonM},
    2610             :     {OGRSpliteComprPolygonXYZM, wkbPolygonZM},
    2611             : 
    2612             :     {OGRSpliteMultiPointXY, wkbMultiPoint},
    2613             :     {OGRSpliteMultiPointXYZ, wkbMultiPoint25D},
    2614             :     {OGRSpliteMultiPointXYM, wkbMultiPointM},
    2615             :     {OGRSpliteMultiPointXYZM, wkbMultiPointZM},
    2616             :     {OGRSpliteMultiLineStringXY, wkbMultiLineString},
    2617             :     {OGRSpliteMultiLineStringXYZ, wkbMultiLineString25D},
    2618             :     {OGRSpliteMultiLineStringXYM, wkbMultiLineStringM},
    2619             :     {OGRSpliteMultiLineStringXYZM, wkbMultiLineStringZM},
    2620             :     {OGRSpliteComprMultiLineStringXY, wkbMultiLineString},
    2621             :     {OGRSpliteComprMultiLineStringXYZ, wkbMultiLineString25D},
    2622             :     {OGRSpliteComprMultiLineStringXYM, wkbMultiLineStringM},
    2623             :     {OGRSpliteComprMultiLineStringXYZM, wkbMultiLineStringZM},
    2624             :     {OGRSpliteMultiPolygonXY, wkbMultiPolygon},
    2625             :     {OGRSpliteMultiPolygonXYZ, wkbMultiPolygon25D},
    2626             :     {OGRSpliteMultiPolygonXYM, wkbMultiPolygonM},
    2627             :     {OGRSpliteMultiPolygonXYZM, wkbMultiPolygonZM},
    2628             :     {OGRSpliteComprMultiPolygonXY, wkbMultiPolygon},
    2629             :     {OGRSpliteComprMultiPolygonXYZ, wkbMultiPolygon25D},
    2630             :     {OGRSpliteComprMultiPolygonXYM, wkbMultiPolygonM},
    2631             :     {OGRSpliteComprMultiPolygonXYZM, wkbMultiPolygonZM},
    2632             : 
    2633             :     {OGRSpliteGeometryCollectionXY, wkbGeometryCollection},
    2634             :     {OGRSpliteGeometryCollectionXYZ, wkbGeometryCollection25D},
    2635             :     {OGRSpliteGeometryCollectionXYM, wkbGeometryCollectionM},
    2636             :     {OGRSpliteGeometryCollectionXYZM, wkbGeometryCollectionZM},
    2637             :     {OGRSpliteComprGeometryCollectionXY, wkbGeometryCollection},
    2638             :     {OGRSpliteComprGeometryCollectionXYZ, wkbGeometryCollection25D},
    2639             :     {OGRSpliteComprGeometryCollectionXYM, wkbGeometryCollectionM},
    2640             :     {OGRSpliteComprGeometryCollectionXYZM, wkbGeometryCollectionZM},
    2641             : };
    2642             : 
    2643        2091 : static bool QuickCheckForSpatialiteGeometryValidity(const GByte *pabyData,
    2644             :                                                     int nBytes)
    2645             : {
    2646        1771 :     return nBytes >= 44 && pabyData[0] == 0 &&
    2647        1516 :            (pabyData[1] == wkbXDR || pabyData[1] == wkbNDR) &&
    2648        3862 :            pabyData[38] == 0x7C && pabyData[nBytes - 1] == 0xFE;
    2649             : }
    2650             : 
    2651          12 : OGRErr OGRSQLiteLayer::GetSpatialiteGeometryHeader(
    2652             :     const GByte *pabyData, int nBytes, int *pnSRID, OGRwkbGeometryType *peType,
    2653             :     bool *pbIsEmpty, double *pdfMinX, double *pdfMinY, double *pdfMaxX,
    2654             :     double *pdfMaxY)
    2655             : {
    2656          12 :     if (!QuickCheckForSpatialiteGeometryValidity(pabyData, nBytes))
    2657           2 :         return OGRERR_CORRUPT_DATA;
    2658             : 
    2659          10 :     const OGRwkbByteOrder eByteOrder =
    2660          10 :         static_cast<OGRwkbByteOrder>(pabyData[1]);
    2661             : 
    2662          10 :     if (pnSRID != nullptr)
    2663             :     {
    2664           9 :         int nSRID = 0;
    2665           9 :         memcpy(&nSRID, pabyData + 2, 4);
    2666           9 :         if (NEED_SWAP_SPATIALITE())
    2667           0 :             CPL_SWAP32PTR(&nSRID);
    2668           9 :         *pnSRID = nSRID;
    2669             :     }
    2670             : 
    2671          10 :     if (peType != nullptr || pbIsEmpty != nullptr)
    2672             :     {
    2673          10 :         OGRwkbGeometryType eGType = wkbUnknown;
    2674          10 :         int nSpatialiteType = 0;
    2675          10 :         memcpy(&nSpatialiteType, pabyData + 39, 4);
    2676          10 :         if (NEED_SWAP_SPATIALITE())
    2677           0 :             CPL_SWAP32PTR(&nSpatialiteType);
    2678         170 :         for (size_t i = 0; i < CPL_ARRAYSIZE(anTypesMap); ++i)
    2679             :         {
    2680         170 :             if (anTypesMap[i].nSpatialiteType == nSpatialiteType)
    2681             :             {
    2682          10 :                 eGType = anTypesMap[i].eGType;
    2683          10 :                 break;
    2684             :             }
    2685             :         }
    2686          10 :         if (peType != nullptr)
    2687           1 :             *peType = eGType;
    2688          10 :         if (pbIsEmpty != nullptr)
    2689             :         {
    2690           9 :             *pbIsEmpty = false;
    2691           9 :             if (wkbFlatten(eGType) != wkbPoint && nBytes >= 44 + 4)
    2692             :             {
    2693           8 :                 int nCount = 0;
    2694           8 :                 memcpy(&nCount, pabyData + 43, 4);
    2695           8 :                 if (NEED_SWAP_SPATIALITE())
    2696           0 :                     CPL_SWAP32PTR(&nCount);
    2697           8 :                 *pbIsEmpty = (nCount == 0);
    2698             :             }
    2699             :         }
    2700             :     }
    2701             : 
    2702          10 :     if (pdfMinX != nullptr)
    2703             :     {
    2704           9 :         double dfMinX = 0.0;
    2705           9 :         memcpy(&dfMinX, pabyData + 6, 8);
    2706           9 :         if (NEED_SWAP_SPATIALITE())
    2707           0 :             CPL_SWAP64PTR(&dfMinX);
    2708           9 :         *pdfMinX = dfMinX;
    2709             :     }
    2710             : 
    2711          10 :     if (pdfMinY != nullptr)
    2712             :     {
    2713           9 :         double dfMinY = 0.0;
    2714           9 :         memcpy(&dfMinY, pabyData + 14, 8);
    2715           9 :         if (NEED_SWAP_SPATIALITE())
    2716           0 :             CPL_SWAP64PTR(&dfMinY);
    2717           9 :         *pdfMinY = dfMinY;
    2718             :     }
    2719             : 
    2720          10 :     if (pdfMaxX != nullptr)
    2721             :     {
    2722           9 :         double dfMaxX = 0.0;
    2723           9 :         memcpy(&dfMaxX, pabyData + 22, 8);
    2724           9 :         if (NEED_SWAP_SPATIALITE())
    2725           0 :             CPL_SWAP64PTR(&dfMaxX);
    2726           9 :         *pdfMaxX = dfMaxX;
    2727             :     }
    2728             : 
    2729          10 :     if (pdfMaxY != nullptr)
    2730             :     {
    2731           9 :         double dfMaxY = 0.0;
    2732           9 :         memcpy(&dfMaxY, pabyData + 30, 8);
    2733           9 :         if (NEED_SWAP_SPATIALITE())
    2734           0 :             CPL_SWAP64PTR(&dfMaxY);
    2735           9 :         *pdfMaxY = dfMaxY;
    2736             :     }
    2737             : 
    2738          10 :     return OGRERR_NONE;
    2739             : }
    2740             : 
    2741             : /************************************************************************/
    2742             : /*                      ImportSpatiaLiteGeometry()                      */
    2743             : /************************************************************************/
    2744             : 
    2745        2000 : OGRErr OGRSQLiteLayer::ImportSpatiaLiteGeometry(const GByte *pabyData,
    2746             :                                                 int nBytes,
    2747             :                                                 OGRGeometry **ppoGeometry)
    2748             : 
    2749             : {
    2750        2000 :     return ImportSpatiaLiteGeometry(pabyData, nBytes, ppoGeometry, nullptr);
    2751             : }
    2752             : 
    2753             : /************************************************************************/
    2754             : /*                      ImportSpatiaLiteGeometry()                      */
    2755             : /************************************************************************/
    2756             : 
    2757        2079 : OGRErr OGRSQLiteLayer::ImportSpatiaLiteGeometry(const GByte *pabyData,
    2758             :                                                 int nBytes,
    2759             :                                                 OGRGeometry **ppoGeometry,
    2760             :                                                 int *pnSRID)
    2761             : 
    2762             : {
    2763        2079 :     *ppoGeometry = nullptr;
    2764             : 
    2765        2079 :     if (!QuickCheckForSpatialiteGeometryValidity(pabyData, nBytes))
    2766         621 :         return OGRERR_CORRUPT_DATA;
    2767             : 
    2768        1458 :     const OGRwkbByteOrder eByteOrder =
    2769        1458 :         static_cast<OGRwkbByteOrder>(pabyData[1]);
    2770             : 
    2771             :     /* -------------------------------------------------------------------- */
    2772             :     /*      Decode the geometry type.                                       */
    2773             :     /* -------------------------------------------------------------------- */
    2774        1458 :     if (pnSRID != nullptr)
    2775             :     {
    2776           9 :         int nSRID = 0;
    2777           9 :         memcpy(&nSRID, pabyData + 2, 4);
    2778           9 :         if (NEED_SWAP_SPATIALITE())
    2779           0 :             CPL_SWAP32PTR(&nSRID);
    2780           9 :         *pnSRID = nSRID;
    2781             :     }
    2782             : 
    2783        1458 :     int nBytesConsumed = 0;
    2784             :     OGRErr eErr =
    2785        1458 :         createFromSpatialiteInternal(pabyData + 39, ppoGeometry, nBytes - 39,
    2786             :                                      eByteOrder, &nBytesConsumed, 0);
    2787        1458 :     if (eErr == OGRERR_NONE)
    2788             :     {
    2789             :         /* This is a hack: in OGR2SQLITE_ExportGeometry(), we may have added */
    2790             :         /* the original curve geometry after the spatialite blob, so in case */
    2791             :         /* we detect that there's still binary */
    2792             :         /* content after the spatialite blob, this may be our original geometry
    2793             :          */
    2794        1457 :         if (39 + nBytesConsumed + 1 < nBytes &&
    2795           1 :             pabyData[39 + nBytesConsumed] == 0xFE)
    2796             :         {
    2797           1 :             OGRGeometry *poOriginalGeometry = nullptr;
    2798           2 :             eErr = OGRGeometryFactory::createFromWkb(
    2799           1 :                 pabyData + 39 + nBytesConsumed + 1, nullptr,
    2800           1 :                 &poOriginalGeometry, nBytes - (39 + nBytesConsumed + 1 + 1));
    2801           1 :             delete *ppoGeometry;
    2802           1 :             if (eErr == OGRERR_NONE)
    2803             :             {
    2804           1 :                 *ppoGeometry = poOriginalGeometry;
    2805             :             }
    2806             :             else
    2807             :             {
    2808           0 :                 *ppoGeometry = nullptr;
    2809             :             }
    2810             :         }
    2811             :     }
    2812        1458 :     return eErr;
    2813             : }
    2814             : 
    2815             : /************************************************************************/
    2816             : /*                CanBeCompressedSpatialiteGeometry()                   */
    2817             : /************************************************************************/
    2818             : 
    2819         135 : int OGRSQLiteLayer::CanBeCompressedSpatialiteGeometry(
    2820             :     const OGRGeometry *poGeometry)
    2821             : {
    2822         135 :     switch (wkbFlatten(poGeometry->getGeometryType()))
    2823             :     {
    2824          58 :         case wkbLineString:
    2825             :         case wkbLinearRing:
    2826             :         {
    2827          58 :             int nPoints = poGeometry->toLineString()->getNumPoints();
    2828          58 :             return nPoints >= 2;
    2829             :         }
    2830             : 
    2831          36 :         case wkbPolygon:
    2832             :         {
    2833          36 :             const OGRPolygon *poPoly = poGeometry->toPolygon();
    2834          36 :             if (poPoly->getExteriorRing() != nullptr)
    2835             :             {
    2836          34 :                 if (!CanBeCompressedSpatialiteGeometry(
    2837          34 :                         poPoly->getExteriorRing()))
    2838           0 :                     return FALSE;
    2839             : 
    2840          34 :                 int nInteriorRingCount = poPoly->getNumInteriorRings();
    2841          38 :                 for (int i = 0; i < nInteriorRingCount; i++)
    2842             :                 {
    2843           4 :                     if (!CanBeCompressedSpatialiteGeometry(
    2844           4 :                             poPoly->getInteriorRing(i)))
    2845           0 :                         return FALSE;
    2846             :                 }
    2847             :             }
    2848          36 :             return TRUE;
    2849             :         }
    2850             : 
    2851          27 :         case wkbMultiPoint:
    2852             :         case wkbMultiLineString:
    2853             :         case wkbMultiPolygon:
    2854             :         case wkbGeometryCollection:
    2855             :         {
    2856             :             const OGRGeometryCollection *poGeomCollection =
    2857          27 :                 poGeometry->toGeometryCollection();
    2858          27 :             int nParts = poGeomCollection->getNumGeometries();
    2859          49 :             for (int i = 0; i < nParts; i++)
    2860             :             {
    2861          32 :                 if (!CanBeCompressedSpatialiteGeometry(
    2862             :                         poGeomCollection->getGeometryRef(i)))
    2863          10 :                     return FALSE;
    2864             :             }
    2865          17 :             return TRUE;
    2866             :         }
    2867             : 
    2868          14 :         default:
    2869          14 :             return FALSE;
    2870             :     }
    2871             : }
    2872             : 
    2873             : /************************************************************************/
    2874             : /*                        collectSimpleGeometries()                     */
    2875             : /************************************************************************/
    2876             : 
    2877             : static void
    2878         168 : collectSimpleGeometries(const OGRGeometryCollection *poGeomCollection,
    2879             :                         std::vector<const OGRGeometry *> &simpleGeometries)
    2880             : {
    2881         168 :     const int nParts = poGeomCollection->getNumGeometries();
    2882         168 :     simpleGeometries.reserve(simpleGeometries.size() + nParts);
    2883         416 :     for (int i = 0; i < nParts; i++)
    2884             :     {
    2885         248 :         const OGRGeometry *poSubGeom = poGeomCollection->getGeometryRef(i);
    2886             :         const OGRGeometryCollection *poSubGeomColl =
    2887         248 :             dynamic_cast<const OGRGeometryCollection *>(poSubGeom);
    2888         248 :         if (poSubGeomColl)
    2889           4 :             collectSimpleGeometries(poSubGeomColl, simpleGeometries);
    2890             :         else
    2891         244 :             simpleGeometries.push_back(poSubGeom);
    2892             :     }
    2893         168 : }
    2894             : 
    2895             : /************************************************************************/
    2896             : /*                  ComputeSpatiaLiteGeometrySize()                     */
    2897             : /************************************************************************/
    2898             : 
    2899         728 : int OGRSQLiteLayer::ComputeSpatiaLiteGeometrySize(const OGRGeometry *poGeometry,
    2900             :                                                   bool bSpatialite2D,
    2901             :                                                   bool bUseComprGeom)
    2902             : {
    2903         728 :     switch (wkbFlatten(poGeometry->getGeometryType()))
    2904             :     {
    2905         241 :         case wkbPoint:
    2906         241 :             if (bSpatialite2D == true)
    2907           0 :                 return 16;
    2908         241 :             return 8 * poGeometry->CoordinateDimension();
    2909             : 
    2910         241 :         case wkbLineString:
    2911             :         case wkbLinearRing:
    2912             :         {
    2913         241 :             int nPoints = poGeometry->toLineString()->getNumPoints();
    2914         241 :             int nDimension = 2;
    2915         241 :             int nPointsDouble = nPoints;
    2916         241 :             int nPointsFloat = 0;
    2917         241 :             bool bHasM = CPL_TO_BOOL(poGeometry->IsMeasured());
    2918         241 :             if (bSpatialite2D == true)
    2919             :             {
    2920             :                 // nDimension = 2;
    2921           0 :                 bHasM = false;
    2922             :             }
    2923             :             else
    2924             :             {
    2925         241 :                 if (bUseComprGeom && nPoints >= 2)
    2926             :                 {
    2927          37 :                     nPointsDouble = 2;
    2928          37 :                     nPointsFloat = nPoints - 2;
    2929             :                 }
    2930         241 :                 nDimension = poGeometry->Is3D() ? 3 : 2;
    2931             :             }
    2932         241 :             return 4 + nDimension * (8 * nPointsDouble + 4 * nPointsFloat) +
    2933         241 :                    (bHasM ? nPoints * 8 : 0);
    2934             :         }
    2935             : 
    2936         164 :         case wkbPolygon:
    2937             :         {
    2938         164 :             int nSize = 4;
    2939         164 :             const OGRPolygon *poPoly = poGeometry->toPolygon();
    2940         182 :             bUseComprGeom = bUseComprGeom && !bSpatialite2D &&
    2941          18 :                             CanBeCompressedSpatialiteGeometry(poGeometry);
    2942         164 :             if (poPoly->getExteriorRing() != nullptr)
    2943             :             {
    2944         483 :                 nSize += ComputeSpatiaLiteGeometrySize(
    2945         161 :                     poPoly->getExteriorRing(), bSpatialite2D, bUseComprGeom);
    2946             : 
    2947         161 :                 int nInteriorRingCount = poPoly->getNumInteriorRings();
    2948         166 :                 for (int i = 0; i < nInteriorRingCount; i++)
    2949           5 :                     nSize += ComputeSpatiaLiteGeometrySize(
    2950           5 :                         poPoly->getInteriorRing(i), bSpatialite2D,
    2951             :                         bUseComprGeom);
    2952             :             }
    2953         164 :             return nSize;
    2954             :         }
    2955             : 
    2956          82 :         case wkbMultiPoint:
    2957             :         case wkbMultiLineString:
    2958             :         case wkbMultiPolygon:
    2959             :         case wkbGeometryCollection:
    2960             :         {
    2961          82 :             int nSize = 4;
    2962             :             const OGRGeometryCollection *poGeomCollection =
    2963          82 :                 poGeometry->toGeometryCollection();
    2964             : 
    2965          82 :             std::vector<const OGRGeometry *> simpleGeometries;
    2966          82 :             collectSimpleGeometries(poGeomCollection, simpleGeometries);
    2967             : 
    2968          82 :             int nParts = static_cast<int>(simpleGeometries.size());
    2969         204 :             for (int i = 0; i < nParts; i++)
    2970         122 :                 nSize += 5 + ComputeSpatiaLiteGeometrySize(simpleGeometries[i],
    2971             :                                                            bSpatialite2D,
    2972             :                                                            bUseComprGeom);
    2973          82 :             return nSize;
    2974             :         }
    2975             : 
    2976           0 :         default:
    2977             :         {
    2978           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2979             :                      "Unexpected geometry type: %s",
    2980           0 :                      OGRToOGCGeomType(poGeometry->getGeometryType()));
    2981           0 :             return 0;
    2982             :         }
    2983             :     }
    2984             : }
    2985             : 
    2986             : /************************************************************************/
    2987             : /*                    GetSpatialiteGeometryCode()                       */
    2988             : /************************************************************************/
    2989             : 
    2990         562 : int OGRSQLiteLayer::GetSpatialiteGeometryCode(const OGRGeometry *poGeometry,
    2991             :                                               bool bSpatialite2D,
    2992             :                                               bool bUseComprGeom,
    2993             :                                               bool bAcceptMultiGeom)
    2994             : {
    2995         562 :     OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
    2996         562 :     switch (eType)
    2997             :     {
    2998         241 :         case wkbPoint:
    2999         241 :             if (bSpatialite2D == true)
    3000           0 :                 return OGRSplitePointXY;
    3001         241 :             else if (poGeometry->Is3D())
    3002             :             {
    3003          26 :                 if (poGeometry->IsMeasured())
    3004           8 :                     return OGRSplitePointXYZM;
    3005             :                 else
    3006          18 :                     return OGRSplitePointXYZ;
    3007             :             }
    3008             :             else
    3009             :             {
    3010         215 :                 if (poGeometry->IsMeasured())
    3011           8 :                     return OGRSplitePointXYM;
    3012             :                 else
    3013         207 :                     return OGRSplitePointXY;
    3014             :             }
    3015             :             break;
    3016             : 
    3017          75 :         case wkbLineString:
    3018             :         case wkbLinearRing:
    3019          75 :             if (bSpatialite2D == true)
    3020           0 :                 return OGRSpliteLineStringXY;
    3021          75 :             else if (poGeometry->Is3D())
    3022             :             {
    3023          27 :                 if (poGeometry->IsMeasured())
    3024           9 :                     return (bUseComprGeom) ? OGRSpliteComprLineStringXYZM
    3025           9 :                                            : OGRSpliteLineStringXYZM;
    3026             :                 else
    3027          18 :                     return (bUseComprGeom) ? OGRSpliteComprLineStringXYZ
    3028          18 :                                            : OGRSpliteLineStringXYZ;
    3029             :             }
    3030             :             else
    3031             :             {
    3032          48 :                 if (poGeometry->IsMeasured())
    3033           9 :                     return (bUseComprGeom) ? OGRSpliteComprLineStringXYM
    3034           9 :                                            : OGRSpliteLineStringXYM;
    3035             :                 else
    3036          39 :                     return (bUseComprGeom) ? OGRSpliteComprLineStringXY
    3037          39 :                                            : OGRSpliteLineStringXY;
    3038             :             }
    3039             :             break;
    3040             : 
    3041         164 :         case wkbPolygon:
    3042         164 :             if (bSpatialite2D == true)
    3043           0 :                 return OGRSplitePolygonXY;
    3044         164 :             else if (poGeometry->Is3D())
    3045             :             {
    3046          22 :                 if (poGeometry->IsMeasured())
    3047           6 :                     return (bUseComprGeom) ? OGRSpliteComprPolygonXYZM
    3048           6 :                                            : OGRSplitePolygonXYZM;
    3049             :                 else
    3050          16 :                     return (bUseComprGeom) ? OGRSpliteComprPolygonXYZ
    3051          16 :                                            : OGRSplitePolygonXYZ;
    3052             :             }
    3053             :             else
    3054             :             {
    3055         142 :                 if (poGeometry->IsMeasured())
    3056           6 :                     return (bUseComprGeom) ? OGRSpliteComprPolygonXYM
    3057           6 :                                            : OGRSplitePolygonXYM;
    3058             :                 else
    3059         136 :                     return (bUseComprGeom) ? OGRSpliteComprPolygonXY
    3060         136 :                                            : OGRSplitePolygonXY;
    3061             :             }
    3062             :             break;
    3063             : 
    3064          82 :         default:
    3065          82 :             break;
    3066             :     }
    3067             : 
    3068          82 :     if (!bAcceptMultiGeom)
    3069             :     {
    3070           0 :         return 0;
    3071             :     }
    3072             : 
    3073          82 :     switch (eType)
    3074             :     {
    3075          16 :         case wkbMultiPoint:
    3076          16 :             if (bSpatialite2D == true)
    3077           0 :                 return OGRSpliteMultiPointXY;
    3078          16 :             else if (poGeometry->Is3D())
    3079             :             {
    3080           6 :                 if (poGeometry->IsMeasured())
    3081           2 :                     return OGRSpliteMultiPointXYZM;
    3082             :                 else
    3083           4 :                     return OGRSpliteMultiPointXYZ;
    3084             :             }
    3085             :             else
    3086             :             {
    3087          10 :                 if (poGeometry->IsMeasured())
    3088           2 :                     return OGRSpliteMultiPointXYM;
    3089             :                 else
    3090           8 :                     return OGRSpliteMultiPointXY;
    3091             :             }
    3092             :             break;
    3093             : 
    3094          17 :         case wkbMultiLineString:
    3095          17 :             if (bSpatialite2D == true)
    3096           0 :                 return OGRSpliteMultiLineStringXY;
    3097          17 :             else if (poGeometry->Is3D())
    3098             :             {
    3099           6 :                 if (poGeometry->IsMeasured())
    3100             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXYZM
    3101             :                               :*/
    3102           2 :                         OGRSpliteMultiLineStringXYZM;
    3103             :                 else
    3104             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXYZ
    3105             :                               :*/
    3106           4 :                         OGRSpliteMultiLineStringXYZ;
    3107             :             }
    3108             :             else
    3109             :             {
    3110          11 :                 if (poGeometry->IsMeasured())
    3111             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXYM
    3112             :                               :*/
    3113           2 :                         OGRSpliteMultiLineStringXYM;
    3114             :                 else
    3115             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXY
    3116             :                               :*/
    3117           9 :                         OGRSpliteMultiLineStringXY;
    3118             :             }
    3119             :             break;
    3120             : 
    3121          19 :         case wkbMultiPolygon:
    3122          19 :             if (bSpatialite2D == true)
    3123           0 :                 return OGRSpliteMultiPolygonXY;
    3124          19 :             else if (poGeometry->Is3D())
    3125             :             {
    3126           6 :                 if (poGeometry->IsMeasured())
    3127             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXYZM
    3128             :                               :*/
    3129           2 :                         OGRSpliteMultiPolygonXYZM;
    3130             :                 else
    3131             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXYZ :*/
    3132           4 :                         OGRSpliteMultiPolygonXYZ;
    3133             :             }
    3134             :             else
    3135             :             {
    3136          13 :                 if (poGeometry->IsMeasured())
    3137             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXYM :*/
    3138           2 :                         OGRSpliteMultiPolygonXYM;
    3139             :                 else
    3140             :                     return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXY :*/
    3141          11 :                         OGRSpliteMultiPolygonXY;
    3142             :             }
    3143             :             break;
    3144             : 
    3145          30 :         case wkbGeometryCollection:
    3146          30 :             if (bSpatialite2D == true)
    3147           0 :                 return OGRSpliteGeometryCollectionXY;
    3148          30 :             else if (poGeometry->Is3D())
    3149             :             {
    3150          12 :                 if (poGeometry->IsMeasured())
    3151             :                     return /*(bUseComprGeom) ?
    3152             :                               OGRSpliteComprGeometryCollectionXYZM :*/
    3153           2 :                         OGRSpliteGeometryCollectionXYZM;
    3154             :                 else
    3155             :                     return /*(bUseComprGeom) ?
    3156             :                               OGRSpliteComprGeometryCollectionXYZ :*/
    3157          10 :                         OGRSpliteGeometryCollectionXYZ;
    3158             :             }
    3159             :             else
    3160             :             {
    3161          18 :                 if (poGeometry->IsMeasured())
    3162             :                     return /*(bUseComprGeom) ?
    3163             :                               OGRSpliteComprGeometryCollectionXYM :*/
    3164           2 :                         OGRSpliteGeometryCollectionXYM;
    3165             :                 else
    3166             :                     return /*(bUseComprGeom) ?
    3167             :                               OGRSpliteComprGeometryCollectionXY :*/
    3168          16 :                         OGRSpliteGeometryCollectionXY;
    3169             :             }
    3170             :             break;
    3171             : 
    3172           0 :         default:
    3173           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Unexpected geometry type");
    3174           0 :             return 0;
    3175             :     }
    3176             : }
    3177             : 
    3178             : /************************************************************************/
    3179             : /*                    ExportSpatiaLiteGeometryInternal()                */
    3180             : /************************************************************************/
    3181             : 
    3182         728 : int OGRSQLiteLayer::ExportSpatiaLiteGeometryInternal(
    3183             :     const OGRGeometry *poGeometry, OGRwkbByteOrder eByteOrder,
    3184             :     bool bSpatialite2D, bool bUseComprGeom, GByte *pabyData)
    3185             : {
    3186         728 :     const auto eFGeomType = wkbFlatten(poGeometry->getGeometryType());
    3187         728 :     switch (eFGeomType)
    3188             :     {
    3189         241 :         case wkbPoint:
    3190             :         {
    3191         241 :             const OGRPoint *poPoint = poGeometry->toPoint();
    3192         241 :             double x = poPoint->getX();
    3193         241 :             double y = poPoint->getY();
    3194         241 :             memcpy(pabyData, &x, 8);
    3195         241 :             memcpy(pabyData + 8, &y, 8);
    3196         241 :             if (NEED_SWAP_SPATIALITE())
    3197             :             {
    3198           0 :                 CPL_SWAP64PTR(pabyData);
    3199           0 :                 CPL_SWAP64PTR(pabyData + 8);
    3200             :             }
    3201         241 :             if (bSpatialite2D == true)
    3202           0 :                 return 16;
    3203         241 :             else if (poGeometry->Is3D())
    3204             :             {
    3205          26 :                 double z = poPoint->getZ();
    3206          26 :                 memcpy(pabyData + 16, &z, 8);
    3207          26 :                 if (NEED_SWAP_SPATIALITE())
    3208           0 :                     CPL_SWAP64PTR(pabyData + 16);
    3209          26 :                 if (poGeometry->IsMeasured())
    3210             :                 {
    3211           8 :                     double m = poPoint->getM();
    3212           8 :                     memcpy(pabyData + 24, &m, 8);
    3213           8 :                     if (NEED_SWAP_SPATIALITE())
    3214           0 :                         CPL_SWAP64PTR(pabyData + 24);
    3215           8 :                     return 32;
    3216             :                 }
    3217             :                 else
    3218          18 :                     return 24;
    3219             :             }
    3220             :             else
    3221             :             {
    3222         215 :                 if (poGeometry->IsMeasured())
    3223             :                 {
    3224           8 :                     double m = poPoint->getM();
    3225           8 :                     memcpy(pabyData + 16, &m, 8);
    3226           8 :                     if (NEED_SWAP_SPATIALITE())
    3227           0 :                         CPL_SWAP64PTR(pabyData + 16);
    3228           8 :                     return 24;
    3229             :                 }
    3230             :                 else
    3231         207 :                     return 16;
    3232             :             }
    3233             :         }
    3234             : 
    3235         241 :         case wkbLineString:
    3236             :         case wkbLinearRing:
    3237             :         {
    3238         241 :             const OGRLineString *poLineString = poGeometry->toLineString();
    3239         241 :             int nTotalSize = 4;
    3240         241 :             int nPointCount = poLineString->getNumPoints();
    3241         241 :             memcpy(pabyData, &nPointCount, 4);
    3242         241 :             if (NEED_SWAP_SPATIALITE())
    3243           0 :                 CPL_SWAP32PTR(pabyData);
    3244             : 
    3245         445 :             if (!bUseComprGeom && !NEED_SWAP_SPATIALITE() &&
    3246         204 :                 poGeometry->CoordinateDimension() == 2)
    3247             :             {
    3248         163 :                 poLineString->getPoints(
    3249         163 :                     reinterpret_cast<OGRRawPoint *>(pabyData + 4), nullptr);
    3250         163 :                 nTotalSize += nPointCount * 16;
    3251         163 :                 return nTotalSize;
    3252             :             }
    3253             : 
    3254         350 :             for (int i = 0; i < nPointCount; i++)
    3255             :             {
    3256         272 :                 double x = poLineString->getX(i);
    3257         272 :                 double y = poLineString->getY(i);
    3258             : 
    3259         272 :                 if (!bUseComprGeom || i == 0 || i == nPointCount - 1)
    3260             :                 {
    3261         211 :                     memcpy(pabyData + nTotalSize, &x, 8);
    3262         211 :                     memcpy(pabyData + nTotalSize + 8, &y, 8);
    3263         211 :                     if (NEED_SWAP_SPATIALITE())
    3264             :                     {
    3265           0 :                         CPL_SWAP64PTR(pabyData + nTotalSize);
    3266           0 :                         CPL_SWAP64PTR(pabyData + nTotalSize + 8);
    3267             :                     }
    3268         211 :                     if (!bSpatialite2D && poGeometry->Is3D())
    3269             :                     {
    3270         144 :                         double z = poLineString->getZ(i);
    3271         144 :                         memcpy(pabyData + nTotalSize + 16, &z, 8);
    3272         144 :                         if (NEED_SWAP_SPATIALITE())
    3273           0 :                             CPL_SWAP64PTR(pabyData + nTotalSize + 16);
    3274         144 :                         if (poGeometry->IsMeasured())
    3275             :                         {
    3276          39 :                             double m = poLineString->getM(i);
    3277          39 :                             memcpy(pabyData + nTotalSize + 24, &m, 8);
    3278          39 :                             if (NEED_SWAP_SPATIALITE())
    3279           0 :                                 CPL_SWAP64PTR(pabyData + nTotalSize + 24);
    3280          39 :                             nTotalSize += 32;
    3281             :                         }
    3282             :                         else
    3283         105 :                             nTotalSize += 24;
    3284             :                     }
    3285             :                     else
    3286             :                     {
    3287          67 :                         if (poGeometry->IsMeasured())
    3288             :                         {
    3289          39 :                             double m = poLineString->getM(i);
    3290          39 :                             memcpy(pabyData + nTotalSize + 16, &m, 8);
    3291          39 :                             if (NEED_SWAP_SPATIALITE())
    3292           0 :                                 CPL_SWAP64PTR(pabyData + nTotalSize + 16);
    3293          39 :                             nTotalSize += 24;
    3294             :                         }
    3295             :                         else
    3296          28 :                             nTotalSize += 16;
    3297         211 :                     }
    3298             :                 }
    3299             :                 else /* Compressed intermediate points */
    3300             :                 {
    3301             :                     float deltax =
    3302          61 :                         static_cast<float>(x - poLineString->getX(i - 1));
    3303             :                     float deltay =
    3304          61 :                         static_cast<float>(y - poLineString->getY(i - 1));
    3305          61 :                     memcpy(pabyData + nTotalSize, &deltax, 4);
    3306          61 :                     memcpy(pabyData + nTotalSize + 4, &deltay, 4);
    3307          61 :                     if (NEED_SWAP_SPATIALITE())
    3308             :                     {
    3309           0 :                         CPL_SWAP32PTR(pabyData + nTotalSize);
    3310           0 :                         CPL_SWAP32PTR(pabyData + nTotalSize + 4);
    3311             :                     }
    3312          61 :                     if (poGeometry->Is3D())
    3313             :                     {
    3314          23 :                         double z = poLineString->getZ(i);
    3315             :                         float deltaz =
    3316          23 :                             static_cast<float>(z - poLineString->getZ(i - 1));
    3317          23 :                         memcpy(pabyData + nTotalSize + 8, &deltaz, 4);
    3318          23 :                         if (NEED_SWAP_SPATIALITE())
    3319           0 :                             CPL_SWAP32PTR(pabyData + nTotalSize + 8);
    3320          23 :                         if (poGeometry->IsMeasured())
    3321             :                         {
    3322          10 :                             double m = poLineString->getM(i);
    3323          10 :                             memcpy(pabyData + nTotalSize + 12, &m, 8);
    3324          10 :                             if (NEED_SWAP_SPATIALITE())
    3325           0 :                                 CPL_SWAP64PTR(pabyData + nTotalSize + 12);
    3326          10 :                             nTotalSize += 20;
    3327             :                         }
    3328             :                         else
    3329          13 :                             nTotalSize += 12;
    3330             :                     }
    3331             :                     else
    3332             :                     {
    3333          38 :                         if (poGeometry->IsMeasured())
    3334             :                         {
    3335          10 :                             double m = poLineString->getM(i);
    3336          10 :                             memcpy(pabyData + nTotalSize + 8, &m, 8);
    3337          10 :                             if (NEED_SWAP_SPATIALITE())
    3338           0 :                                 CPL_SWAP64PTR(pabyData + nTotalSize + 8);
    3339          10 :                             nTotalSize += 16;
    3340             :                         }
    3341             :                         else
    3342          28 :                             nTotalSize += 8;
    3343             :                     }
    3344             :                 }
    3345             :             }
    3346          78 :             return nTotalSize;
    3347             :         }
    3348             : 
    3349         164 :         case wkbPolygon:
    3350             :         {
    3351         164 :             const OGRPolygon *poPoly = poGeometry->toPolygon();
    3352         164 :             int nTotalSize = 4;
    3353         164 :             if (poPoly->getExteriorRing() != nullptr)
    3354             :             {
    3355         161 :                 int nInteriorRingCount = poPoly->getNumInteriorRings();
    3356         161 :                 const int nParts = 1 + nInteriorRingCount;
    3357         161 :                 memcpy(pabyData, &nParts, 4);
    3358         161 :                 if (NEED_SWAP_SPATIALITE())
    3359           0 :                     CPL_SWAP32PTR(pabyData);
    3360             : 
    3361         483 :                 nTotalSize += ExportSpatiaLiteGeometryInternal(
    3362         161 :                     poPoly->getExteriorRing(), eByteOrder, bSpatialite2D,
    3363         161 :                     bUseComprGeom, pabyData + nTotalSize);
    3364             : 
    3365         166 :                 for (int i = 0; i < nInteriorRingCount; i++)
    3366             :                 {
    3367           5 :                     nTotalSize += ExportSpatiaLiteGeometryInternal(
    3368           5 :                         poPoly->getInteriorRing(i), eByteOrder, bSpatialite2D,
    3369           5 :                         bUseComprGeom, pabyData + nTotalSize);
    3370             :                 }
    3371             :             }
    3372             :             else
    3373             :             {
    3374           3 :                 memset(pabyData, 0, 4);
    3375             :             }
    3376         164 :             return nTotalSize;
    3377             :         }
    3378             : 
    3379          82 :         case wkbMultiPoint:
    3380             :         case wkbMultiLineString:
    3381             :         case wkbMultiPolygon:
    3382             :         case wkbGeometryCollection:
    3383             :         {
    3384             :             const OGRGeometryCollection *poGeomCollection =
    3385          82 :                 poGeometry->toGeometryCollection();
    3386          82 :             int nTotalSize = 4;
    3387             : 
    3388         164 :             std::vector<const OGRGeometry *> simpleGeometries;
    3389          82 :             collectSimpleGeometries(poGeomCollection, simpleGeometries);
    3390             : 
    3391          82 :             int nParts = static_cast<int>(simpleGeometries.size());
    3392          82 :             memcpy(pabyData, &nParts, 4);
    3393          82 :             if (NEED_SWAP_SPATIALITE())
    3394           0 :                 CPL_SWAP32PTR(pabyData);
    3395             : 
    3396         204 :             for (int i = 0; i < nParts; i++)
    3397             :             {
    3398         122 :                 pabyData[nTotalSize] = 0x69;
    3399         122 :                 nTotalSize++;
    3400             : 
    3401         122 :                 const OGRGeometry *poPart = simpleGeometries[i];
    3402         122 :                 int nCode = GetSpatialiteGeometryCode(poPart, bSpatialite2D,
    3403         122 :                                                       bUseComprGeom, FALSE);
    3404         122 :                 if (nCode == 0)
    3405           0 :                     return 0;
    3406         122 :                 memcpy(pabyData + nTotalSize, &nCode, 4);
    3407         122 :                 if (NEED_SWAP_SPATIALITE())
    3408           0 :                     CPL_SWAP32PTR(pabyData + nTotalSize);
    3409         122 :                 nTotalSize += 4;
    3410         122 :                 nTotalSize += ExportSpatiaLiteGeometryInternal(
    3411             :                     poPart, eByteOrder, bSpatialite2D, bUseComprGeom,
    3412         122 :                     pabyData + nTotalSize);
    3413             :             }
    3414          82 :             return nTotalSize;
    3415             :         }
    3416             : 
    3417           0 :         default:
    3418           0 :             return 0;
    3419             :     }
    3420             : }
    3421             : 
    3422         440 : OGRErr OGRSQLiteLayer::ExportSpatiaLiteGeometry(
    3423             :     const OGRGeometry *poGeometry, GInt32 nSRID, OGRwkbByteOrder eByteOrder,
    3424             :     bool bSpatialite2D, bool bUseComprGeom, GByte **ppabyData,
    3425             :     int *pnDataLength)
    3426             : 
    3427             : {
    3428             :     /* Spatialite does not support curve geometries */
    3429         440 :     const OGRGeometry *poWorkGeom = poGeometry->hasCurveGeometry()
    3430         440 :                                         ? poGeometry->getLinearGeometry()
    3431         440 :                                         : poGeometry;
    3432             : 
    3433         487 :     bUseComprGeom = bUseComprGeom && !bSpatialite2D &&
    3434          47 :                     CanBeCompressedSpatialiteGeometry(poWorkGeom);
    3435             : 
    3436             :     const int nGeomSize =
    3437         440 :         ComputeSpatiaLiteGeometrySize(poWorkGeom, bSpatialite2D, bUseComprGeom);
    3438         440 :     if (nGeomSize == 0)
    3439             :     {
    3440           0 :         *ppabyData = nullptr;
    3441           0 :         *pnDataLength = 0;
    3442           0 :         return OGRERR_FAILURE;
    3443             :     }
    3444         440 :     const int nDataLen = 44 + nGeomSize;
    3445         440 :     OGREnvelope sEnvelope;
    3446             : 
    3447         440 :     *ppabyData = static_cast<GByte *>(CPLMalloc(nDataLen));
    3448             : 
    3449         440 :     (*ppabyData)[0] = 0x00;
    3450         440 :     (*ppabyData)[1] = static_cast<GByte>(eByteOrder);
    3451             : 
    3452             :     // Write out SRID
    3453         440 :     memcpy(*ppabyData + 2, &nSRID, 4);
    3454             : 
    3455             :     // Write out the geometry bounding rectangle
    3456         440 :     poGeometry->getEnvelope(&sEnvelope);
    3457         440 :     memcpy(*ppabyData + 6, &sEnvelope.MinX, 8);
    3458         440 :     memcpy(*ppabyData + 14, &sEnvelope.MinY, 8);
    3459         440 :     memcpy(*ppabyData + 22, &sEnvelope.MaxX, 8);
    3460         440 :     memcpy(*ppabyData + 30, &sEnvelope.MaxY, 8);
    3461             : 
    3462         440 :     (*ppabyData)[38] = 0x7C;
    3463             : 
    3464         440 :     int nCode = GetSpatialiteGeometryCode(poWorkGeom, bSpatialite2D,
    3465         440 :                                           bUseComprGeom, TRUE);
    3466         440 :     if (nCode == 0)
    3467             :     {
    3468           0 :         CPLFree(*ppabyData);
    3469           0 :         *ppabyData = nullptr;
    3470           0 :         *pnDataLength = 0;
    3471           0 :         if (poWorkGeom != poGeometry)
    3472           0 :             delete poWorkGeom;
    3473           0 :         return OGRERR_FAILURE;
    3474             :     }
    3475         440 :     memcpy(*ppabyData + 39, &nCode, 4);
    3476             : 
    3477         880 :     int nWritten = ExportSpatiaLiteGeometryInternal(
    3478         440 :         poWorkGeom, eByteOrder, bSpatialite2D, bUseComprGeom, *ppabyData + 43);
    3479         440 :     if (poWorkGeom != poGeometry)
    3480           1 :         delete poWorkGeom;
    3481             : 
    3482         440 :     if (nWritten == 0)
    3483             :     {
    3484           0 :         CPLFree(*ppabyData);
    3485           0 :         *ppabyData = nullptr;
    3486           0 :         *pnDataLength = 0;
    3487           0 :         return OGRERR_FAILURE;
    3488             :     }
    3489             : 
    3490         440 :     (*ppabyData)[nDataLen - 1] = 0xFE;
    3491             : 
    3492         440 :     if (NEED_SWAP_SPATIALITE())
    3493             :     {
    3494           0 :         CPL_SWAP32PTR(*ppabyData + 2);
    3495           0 :         CPL_SWAP64PTR(*ppabyData + 6);
    3496           0 :         CPL_SWAP64PTR(*ppabyData + 14);
    3497           0 :         CPL_SWAP64PTR(*ppabyData + 22);
    3498           0 :         CPL_SWAP64PTR(*ppabyData + 30);
    3499           0 :         CPL_SWAP32PTR(*ppabyData + 39);
    3500             :     }
    3501             : 
    3502         440 :     *pnDataLength = nDataLen;
    3503             : 
    3504         440 :     return OGRERR_NONE;
    3505             : }
    3506             : 
    3507             : /************************************************************************/
    3508             : /*                           TestCapability()                           */
    3509             : /************************************************************************/
    3510             : 
    3511          70 : int OGRSQLiteLayer::TestCapability(const char *pszCap)
    3512             : 
    3513             : {
    3514          70 :     if (EQUAL(pszCap, OLCRandomRead))
    3515           0 :         return FALSE;
    3516             : 
    3517          70 :     else if (EQUAL(pszCap, OLCFastFeatureCount))
    3518           0 :         return FALSE;
    3519             : 
    3520          70 :     else if (EQUAL(pszCap, OLCFastSpatialFilter))
    3521           0 :         return FALSE;
    3522             : 
    3523          70 :     else if (EQUAL(pszCap, OLCIgnoreFields))
    3524           6 :         return TRUE;
    3525             : 
    3526          64 :     else if (EQUAL(pszCap, OLCTransactions))
    3527           6 :         return TRUE;
    3528             : 
    3529             :     else
    3530          58 :         return FALSE;
    3531             : }
    3532             : 
    3533             : /************************************************************************/
    3534             : /*                          StartTransaction()                          */
    3535             : /************************************************************************/
    3536             : 
    3537          34 : OGRErr OGRSQLiteLayer::StartTransaction()
    3538             : {
    3539          34 :     return m_poDS->StartTransaction();
    3540             : }
    3541             : 
    3542             : /************************************************************************/
    3543             : /*                         CommitTransaction()                          */
    3544             : /************************************************************************/
    3545             : 
    3546          26 : OGRErr OGRSQLiteLayer::CommitTransaction()
    3547             : {
    3548          26 :     return m_poDS->CommitTransaction();
    3549             : }
    3550             : 
    3551             : /************************************************************************/
    3552             : /*                        RollbackTransaction()                         */
    3553             : /************************************************************************/
    3554             : 
    3555           8 : OGRErr OGRSQLiteLayer::RollbackTransaction()
    3556             : {
    3557           8 :     return m_poDS->RollbackTransaction();
    3558             : }
    3559             : 
    3560             : /************************************************************************/
    3561             : /*                           ClearStatement()                           */
    3562             : /************************************************************************/
    3563             : 
    3564        9317 : void OGRSQLiteLayer::ClearStatement()
    3565             : 
    3566             : {
    3567        9317 :     if (m_hStmt != nullptr)
    3568             :     {
    3569             : #ifdef DEBUG_VERBOSE
    3570             :         CPLDebug("OGR_SQLITE", "finalize %p", m_hStmt);
    3571             : #endif
    3572        1303 :         sqlite3_finalize(m_hStmt);
    3573        1303 :         m_hStmt = nullptr;
    3574             :     }
    3575        9317 : }
    3576             : 
    3577             : /************************************************************************/
    3578             : /*                     FormatSpatialFilterFromRTree()                   */
    3579             : /************************************************************************/
    3580             : 
    3581          87 : CPLString OGRSQLiteLayer::FormatSpatialFilterFromRTree(
    3582             :     OGRGeometry *poFilterGeom, const char *pszRowIDName,
    3583             :     const char *pszEscapedTable, const char *pszEscapedGeomCol)
    3584             : {
    3585         174 :     CPLString osSpatialWHERE;
    3586          87 :     OGREnvelope sEnvelope;
    3587             : 
    3588          87 :     poFilterGeom->getEnvelope(&sEnvelope);
    3589             : 
    3590          93 :     if (std::isinf(sEnvelope.MinX) && sEnvelope.MinX < 0 &&
    3591           9 :         std::isinf(sEnvelope.MinY) && sEnvelope.MinY < 0 &&
    3592           9 :         std::isinf(sEnvelope.MaxX) && sEnvelope.MaxX > 0 &&
    3593          93 :         std::isinf(sEnvelope.MaxY) && sEnvelope.MaxY > 0)
    3594           3 :         return "";
    3595             : 
    3596             :     osSpatialWHERE.Printf(
    3597             :         "%s IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
    3598             :         "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f AND ymin <= %.12f)",
    3599             :         pszRowIDName, pszEscapedTable, pszEscapedGeomCol,
    3600          84 :         sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11, sEnvelope.MinY - 1e-11,
    3601          84 :         sEnvelope.MaxY + 1e-11);
    3602             : 
    3603          84 :     return osSpatialWHERE;
    3604             : }
    3605             : 
    3606             : /************************************************************************/
    3607             : /*                     FormatSpatialFilterFromMBR()                     */
    3608             : /************************************************************************/
    3609             : 
    3610             : CPLString
    3611           6 : OGRSQLiteLayer::FormatSpatialFilterFromMBR(OGRGeometry *poFilterGeom,
    3612             :                                            const char *pszEscapedGeomColName)
    3613             : {
    3614          12 :     CPLString osSpatialWHERE;
    3615           6 :     OGREnvelope sEnvelope;
    3616             : 
    3617           6 :     poFilterGeom->getEnvelope(&sEnvelope);
    3618             : 
    3619           6 :     if (std::isinf(sEnvelope.MinX) && sEnvelope.MinX < 0 &&
    3620           0 :         std::isinf(sEnvelope.MinY) && sEnvelope.MinY < 0 &&
    3621           0 :         std::isinf(sEnvelope.MaxX) && sEnvelope.MaxX > 0 &&
    3622           6 :         std::isinf(sEnvelope.MaxY) && sEnvelope.MaxY > 0)
    3623           0 :         return "";
    3624             : 
    3625             :     /* A bit inefficient but still faster than OGR filtering */
    3626             :     osSpatialWHERE.Printf(
    3627             :         "MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f))",
    3628             :         pszEscapedGeomColName,
    3629             :         // Insure that only Decimal.Points are used, never local settings such
    3630             :         // as Decimal.Comma.
    3631           6 :         sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11, sEnvelope.MaxX + 1e-11,
    3632           6 :         sEnvelope.MaxY + 1e-11);
    3633             : 
    3634           6 :     return osSpatialWHERE;
    3635             : }
    3636             : 
    3637             : /************************************************************************/
    3638             : /*                 OGRSQLiteGetSpatialiteGeometryHeader()               */
    3639             : /************************************************************************/
    3640             : 
    3641          12 : OGRErr OGRSQLiteGetSpatialiteGeometryHeader(const GByte *pabyData, int nBytes,
    3642             :                                             int *pnSRID,
    3643             :                                             OGRwkbGeometryType *peType,
    3644             :                                             bool *pbIsEmpty, double *pdfMinX,
    3645             :                                             double *pdfMinY, double *pdfMaxX,
    3646             :                                             double *pdfMaxY)
    3647             : {
    3648          12 :     return OGRSQLiteLayer::GetSpatialiteGeometryHeader(
    3649             :         pabyData, nBytes, pnSRID, peType, pbIsEmpty, pdfMinX, pdfMinY, pdfMaxX,
    3650          12 :         pdfMaxY);
    3651             : }
    3652             : 
    3653             : /************************************************************************/
    3654             : /*                   OGRSQLiteImportSpatiaLiteGeometry()                */
    3655             : /************************************************************************/
    3656             : 
    3657          56 : OGRErr OGRSQLiteImportSpatiaLiteGeometry(const GByte *pabyData, int nBytes,
    3658             :                                          OGRGeometry **ppoGeometry, int *pnSRID)
    3659             : {
    3660          56 :     return OGRSQLiteLayer::ImportSpatiaLiteGeometry(pabyData, nBytes,
    3661          56 :                                                     ppoGeometry, pnSRID);
    3662             : }
    3663             : 
    3664             : /************************************************************************/
    3665             : /*                   OGRSQLiteExportSpatiaLiteGeometry()                */
    3666             : /************************************************************************/
    3667             : 
    3668           0 : OGRErr OGRSQLiteExportSpatiaLiteGeometry(const OGRGeometry *poGeometry,
    3669             :                                          GInt32 nSRID,
    3670             :                                          OGRwkbByteOrder eByteOrder,
    3671             :                                          bool bSpatialite2D, bool bUseComprGeom,
    3672             :                                          GByte **ppabyData, int *pnDataLength)
    3673             : {
    3674           0 :     return OGRSQLiteLayer::ExportSpatiaLiteGeometry(
    3675             :         poGeometry, nSRID, eByteOrder, bSpatialite2D, bUseComprGeom, ppabyData,
    3676           0 :         pnDataLength);
    3677             : }
    3678             : 
    3679             : /************************************************************************/
    3680             : /*                             GetDataset()                             */
    3681             : /************************************************************************/
    3682             : 
    3683          46 : GDALDataset *OGRSQLiteLayer::GetDataset()
    3684             : {
    3685          46 :     return m_poDS;
    3686             : }

Generated by: LCOV version 1.14