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

Generated by: LCOV version 1.14