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

Generated by: LCOV version 1.14