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

Generated by: LCOV version 1.14