LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1486 1854 80.2 %
Date: 2024-11-25 13:07:18 Functions: 32 34 94.1 %

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

Generated by: LCOV version 1.14