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

Generated by: LCOV version 1.14