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