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