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 3360 : OGRSQLiteLayer::OGRSQLiteLayer(OGRSQLiteDataSource *poDSIn)
59 : : m_poDS(poDSIn),
60 3360 : m_bUseComprGeom(CPLTestBool(CPLGetConfigOption("COMPRESS_GEOM", "FALSE")))
61 : {
62 3360 : }
63 :
64 : /************************************************************************/
65 : /* ~OGRSQLiteLayer() */
66 : /************************************************************************/
67 :
68 3359 : OGRSQLiteLayer::~OGRSQLiteLayer()
69 :
70 : {
71 3359 : Finalize();
72 3359 : }
73 :
74 : /************************************************************************/
75 : /* Finalize() */
76 : /************************************************************************/
77 :
78 3961 : 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 3961 : if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr)
85 : {
86 1372 : CPLDebug("SQLite", CPL_FRMT_GIB " features read on layer '%s'.",
87 1372 : m_nFeaturesRead, m_poFeatureDefn->GetName());
88 : }
89 :
90 3961 : if (m_hStmt != nullptr)
91 : {
92 927 : sqlite3_finalize(m_hStmt);
93 927 : m_hStmt = nullptr;
94 : }
95 :
96 3961 : if (m_poFeatureDefn != nullptr)
97 : {
98 2874 : m_poFeatureDefn->Release();
99 2874 : m_poFeatureDefn = nullptr;
100 : }
101 :
102 3961 : CPLFree(m_pszFIDColumn);
103 3961 : m_pszFIDColumn = nullptr;
104 3961 : CPLFree(m_panFieldOrdinals);
105 3961 : m_panFieldOrdinals = nullptr;
106 :
107 3961 : CSLDestroy(m_papszCompressedColumns);
108 3961 : m_papszCompressedColumns = nullptr;
109 3961 : }
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 387 : static int OGRIsBinaryGeomCol(sqlite3_stmt *hStmt, int iCol,
162 : CPL_UNUSED OGRFieldDefn &oField,
163 : OGRSQLiteGeomFormat &eGeomFormat)
164 : {
165 387 : OGRGeometry *poGeometry = nullptr;
166 387 : const int nBytes = sqlite3_column_bytes(hStmt, iCol);
167 : // coverity[tainted_data_return]
168 : const GByte *pabyBlob =
169 387 : reinterpret_cast<const GByte *>(sqlite3_column_blob(hStmt, iCol));
170 387 : int nBytesConsumed = 0;
171 387 : CPLPushErrorHandler(CPLQuietErrorHandler);
172 : /* Try as spatialite first since createFromWkb() can sometimes */
173 : /* interpret spatialite blobs as WKB for certain SRID values */
174 387 : if (OGRSQLiteLayer::ImportSpatiaLiteGeometry(pabyBlob, nBytes,
175 387 : &poGeometry) == OGRERR_NONE)
176 : {
177 90 : eGeomFormat = OSGF_SpatiaLite;
178 : }
179 297 : else if (OGRGeometryFactory::createFromWkb(pabyBlob, nullptr, &poGeometry,
180 297 : nBytes) == OGRERR_NONE)
181 : {
182 15 : eGeomFormat = OSGF_WKB;
183 : }
184 282 : else if (OGRGeometryFactory::createFromFgf(pabyBlob, nullptr, &poGeometry,
185 : nBytes, &nBytesConsumed) ==
186 282 : OGRERR_NONE &&
187 0 : nBytes == nBytesConsumed)
188 : {
189 0 : eGeomFormat = OSGF_FGF;
190 : }
191 387 : CPLPopErrorHandler();
192 387 : CPLErrorReset();
193 387 : delete poGeometry;
194 387 : if (eGeomFormat != OSGF_None)
195 : {
196 105 : return TRUE;
197 : }
198 282 : 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 2107 : 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 2107 : m_poFeatureDefn = new OGRSQLiteFeatureDefn(pszLayerName);
215 2107 : m_poFeatureDefn->SetGeomType(wkbNone);
216 2107 : m_poFeatureDefn->Reference();
217 :
218 4214 : std::map<std::string, std::string> oMapTableInfo; // name to type
219 2107 : if (!bIsSelect)
220 : {
221 : // oField.GetNameRef() can be better than sqlite3_column_name() on views
222 659 : char *pszSQL = sqlite3_mprintf("PRAGMA table_info('%q')", pszLayerName);
223 1318 : auto oResultTable = SQLQuery(m_poDS->GetDB(), pszSQL);
224 659 : sqlite3_free(pszSQL);
225 659 : if (oResultTable && oResultTable->ColCount() == 6)
226 : {
227 1632 : for (int iRecord = 0; iRecord < oResultTable->RowCount(); iRecord++)
228 : {
229 1269 : const char *pszName = oResultTable->GetValue(1, iRecord);
230 1269 : const char *pszType = oResultTable->GetValue(2, iRecord);
231 1269 : if (pszName && pszType)
232 1269 : oMapTableInfo[pszName] = pszType;
233 : }
234 : }
235 : }
236 :
237 2107 : const int nRawColumns = sqlite3_column_count(hStmtIn);
238 :
239 2107 : m_panFieldOrdinals =
240 2107 : static_cast<int *>(CPLMalloc(sizeof(int) * nRawColumns));
241 :
242 4214 : std::set<std::string> oSetFields;
243 :
244 11269 : for (int iCol = 0; iCol < nRawColumns; iCol++)
245 : {
246 9162 : OGRFieldDefn oField(SQLUnescape(sqlite3_column_name(hStmtIn, iCol)),
247 9162 : OFTString);
248 9162 : 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 9162 : if (cpl::contains(oSetFields, pszFieldName))
254 9 : continue;
255 :
256 9153 : if (EQUAL(pszFieldName, "OGR_NATIVE_DATA"))
257 : {
258 316 : m_iOGRNativeDataCol = iCol;
259 316 : continue;
260 : }
261 :
262 8837 : 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 8521 : if (m_bIsVirtualShape && EQUAL(pszFieldName, "PKUID"))
271 : {
272 3 : CPLFree(m_pszFIDColumn);
273 3 : m_pszFIDColumn = CPLStrdup(pszFieldName);
274 : }
275 :
276 8521 : if (m_pszFIDColumn != nullptr && EQUAL(m_pszFIDColumn, pszFieldName))
277 1238 : continue;
278 :
279 : // oField.SetWidth( std::max(0,poStmt->GetColSize( iCol )) );
280 :
281 7283 : if (aosIgnoredCols.find(CPLString(pszFieldName).tolower()) !=
282 14566 : aosIgnoredCols.end())
283 : {
284 70 : continue;
285 : }
286 8807 : if (paosGeomCols != nullptr &&
287 8807 : paosGeomCols->find(CPLString(pszFieldName).tolower()) !=
288 8807 : paosGeomCols->end())
289 : {
290 249 : m_poFeatureDefn->AddGeomFieldDefn(
291 498 : std::make_unique<OGRSQLiteGeomFieldDefn>(pszFieldName, iCol));
292 249 : continue;
293 : }
294 :
295 6964 : const int nColType = sqlite3_column_type(hStmtIn, iCol);
296 6964 : switch (nColType)
297 : {
298 1129 : case SQLITE_INTEGER:
299 1129 : if (CPLTestBool(CPLGetConfigOption("OGR_PROMOTE_TO_INTEGER64",
300 : "FALSE")))
301 0 : oField.SetType(OFTInteger64);
302 : else
303 : {
304 1129 : GIntBig nVal = sqlite3_column_int64(hStmtIn, iCol);
305 1129 : if (CPL_INT64_FITS_ON_INT32(nVal))
306 1017 : oField.SetType(OFTInteger);
307 : else
308 112 : oField.SetType(OFTInteger64);
309 : }
310 1129 : break;
311 :
312 433 : case SQLITE_FLOAT:
313 433 : oField.SetType(OFTReal);
314 433 : break;
315 :
316 716 : case SQLITE_BLOB:
317 716 : oField.SetType(OFTBinary);
318 716 : break;
319 :
320 6964 : default:
321 : /* leave it as OFTString */;
322 : }
323 :
324 6964 : const char *pszDeclType = sqlite3_column_decltype(hStmtIn, iCol);
325 6964 : if (pszDeclType == nullptr)
326 : {
327 540 : auto iter = oMapTableInfo.find(pszFieldName);
328 540 : if (iter != oMapTableInfo.end())
329 2 : pszDeclType = iter->second.c_str();
330 : }
331 : // CPLDebug("SQLITE", "decltype(%s) = %s",
332 : // pszFieldName, pszDeclType ? pszDeclType : "null");
333 6964 : OGRFieldType eFieldType = OFTString;
334 6964 : if (pszDeclType != nullptr)
335 : {
336 6426 : std::string osDeclType(pszDeclType);
337 : const char *pszBeginDomainName =
338 6426 : strstr(pszDeclType, "_BEGIN_DOMAIN_NAME_");
339 6426 : 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 6426 : pszDeclType = osDeclType.c_str();
364 :
365 6426 : if (EQUAL(pszDeclType, "INTEGER_BOOLEAN") ||
366 6232 : EQUAL(pszDeclType, "BOOLEAN"))
367 : {
368 194 : oField.SetType(OFTInteger);
369 194 : oField.SetSubType(OFSTBoolean);
370 : }
371 6232 : else if (EQUAL(pszDeclType, "INTEGER_INT16"))
372 : {
373 190 : oField.SetType(OFTInteger);
374 190 : oField.SetSubType(OFSTInt16);
375 : }
376 6042 : else if (EQUAL(pszDeclType, "INTEGER_OR_TEXT"))
377 : {
378 : // Used by PROJ proj.db
379 1 : oField.SetType(OFTString);
380 : }
381 6041 : else if (EQUAL(pszDeclType, "JSONINTEGERLIST"))
382 : {
383 193 : oField.SetType(OFTIntegerList);
384 : }
385 5848 : else if (EQUAL(pszDeclType, "JSONINTEGER64LIST"))
386 : {
387 193 : oField.SetType(OFTInteger64List);
388 : }
389 5655 : else if (EQUAL(pszDeclType, "JSONREALLIST"))
390 : {
391 193 : oField.SetType(OFTRealList);
392 : }
393 5462 : else if (EQUAL(pszDeclType, "JSONSTRINGLIST"))
394 : {
395 193 : oField.SetType(OFTStringList);
396 : }
397 5269 : else if (EQUAL(pszDeclType, "BIGINT") ||
398 5014 : EQUAL(pszDeclType, "INT8") ||
399 5014 : EQUAL(pszDeclType, "UNSIGNED BIG INT"))
400 : {
401 255 : oField.SetType(OFTInteger64);
402 : }
403 5014 : else if (STARTS_WITH_CI(pszDeclType, "INTEGER") ||
404 3913 : EQUAL(pszDeclType, "INT") ||
405 3905 : EQUAL(pszDeclType, "TINYINT") ||
406 3905 : EQUAL(pszDeclType, "SMALLINT") ||
407 3905 : EQUAL(pszDeclType, "MEDIUMINT") ||
408 3905 : EQUAL(pszDeclType, "INT2"))
409 : {
410 1109 : oField.SetType(OFTInteger);
411 : }
412 3905 : else if (EQUAL(pszDeclType, "FLOAT_FLOAT32"))
413 : {
414 190 : oField.SetType(OFTReal);
415 190 : oField.SetSubType(OFSTFloat32);
416 : }
417 3715 : else if (EQUAL(pszDeclType, "FLOAT") ||
418 3280 : EQUAL(pszDeclType, "DECIMAL") ||
419 3280 : EQUAL(pszDeclType, "REAL") ||
420 3271 : EQUAL(pszDeclType, "DOUBLE") ||
421 3268 : EQUAL(pszDeclType, "DOUBLE PRECISION") ||
422 3268 : EQUAL(pszDeclType, "NUMERIC"))
423 : {
424 447 : oField.SetType(OFTReal);
425 : }
426 3268 : else if (STARTS_WITH_CI(pszDeclType, "BLOB"))
427 : {
428 787 : oField.SetType(OFTBinary);
429 : /* Parse format like BLOB_POINT_25D_4326 created by */
430 : /* OGRSQLiteExecuteSQL() */
431 787 : 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 2481 : else if (EQUAL(pszDeclType, "TEXT") ||
475 2051 : STARTS_WITH_CI(pszDeclType, "VARCHAR") ||
476 807 : STARTS_WITH_CI(pszDeclType, "CHARACTER") ||
477 807 : STARTS_WITH_CI(pszDeclType, "VARYING CHARACTER") ||
478 807 : STARTS_WITH_CI(pszDeclType, "NCHAR") ||
479 807 : STARTS_WITH_CI(pszDeclType, "NATIVE CHARACTER") ||
480 807 : STARTS_WITH_CI(pszDeclType, "NVARCHAR") ||
481 807 : EQUAL(pszDeclType, "CLOB"))
482 : {
483 1674 : oField.SetType(OFTString);
484 1674 : 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 807 : else if ((EQUAL(pszDeclType, "TIMESTAMP") ||
496 807 : EQUAL(pszDeclType, "DATETIME")) &&
497 124 : (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT ||
498 : nColType == SQLITE_NULL))
499 273 : eFieldType = OFTDateTime;
500 534 : else if (EQUAL(pszDeclType, "DATE") &&
501 82 : (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT ||
502 : nColType == SQLITE_NULL))
503 195 : eFieldType = OFTDate;
504 339 : else if (EQUAL(pszDeclType, "TIME") &&
505 82 : (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT ||
506 : nColType == SQLITE_NULL))
507 195 : eFieldType = OFTTime;
508 : }
509 538 : else if (nColType == SQLITE_TEXT &&
510 116 : (STARTS_WITH_CI(pszFieldName, "MIN(") ||
511 115 : 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 12147 : if (paosGeomCols == nullptr &&
526 5401 : (EQUAL(pszFieldName, "wkt_geometry") ||
527 5400 : EQUAL(pszFieldName, "geometry") ||
528 5335 : STARTS_WITH_CI(pszFieldName, "asbinary(") ||
529 5335 : STARTS_WITH_CI(pszFieldName, "astext(") ||
530 5335 : (STARTS_WITH_CI(pszFieldName, "st_") &&
531 12147 : 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 5315 : else if (paosGeomCols == nullptr && nColType == SQLITE_NULL &&
605 2091 : !STARTS_WITH_CI(pszFieldName, "Gpkg") &&
606 2091 : !STARTS_WITH_CI(pszFieldName, "AsGPB(") &&
607 14066 : !STARTS_WITH_CI(pszFieldName, "CastAutomagic(") &&
608 2091 : 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 6670 : 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 6990 : if (paosGeomCols == nullptr && nColType == SQLITE_BLOB &&
632 320 : (m_bAllowMultipleGeomFields ||
633 0 : m_poFeatureDefn->GetGeomFieldCount() == 0))
634 : {
635 320 : const int nBytes = sqlite3_column_bytes(hStmtIn, iCol);
636 320 : OGRSQLiteGeomFormat eGeomFormat = OSGF_None;
637 640 : if (nBytes > 0 &&
638 320 : 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 6632 : if (EQUAL(pszFieldName, "_rowid_"))
650 0 : continue;
651 :
652 : // The OGC_FID is for internal use, not a real user visible column.
653 6632 : if (EQUAL(pszFieldName, "OGC_FID"))
654 79 : continue;
655 :
656 : /* Config option just in case we would not want that in some cases */
657 6358 : if ((eFieldType == OFTTime || eFieldType == OFTDate ||
658 13381 : eFieldType == OFTDateTime) &&
659 665 : CPLTestBool(
660 : CPLGetConfigOption("OGR_SQLITE_ENABLE_DATETIME", "YES")))
661 : {
662 665 : oField.SetType(eFieldType);
663 : }
664 :
665 6553 : oSetFields.insert(oField.GetNameRef());
666 6553 : m_poFeatureDefn->AddFieldDefn(&oField);
667 6553 : m_panFieldOrdinals[m_poFeatureDefn->GetFieldCount() - 1] = iCol;
668 : }
669 :
670 2107 : if (m_pszFIDColumn != nullptr)
671 : {
672 660 : for (int iCol = 0; iCol < nRawColumns; iCol++)
673 : {
674 660 : if (EQUAL(SQLUnescape(sqlite3_column_name(hStmtIn, iCol)).c_str(),
675 : m_pszFIDColumn))
676 : {
677 657 : m_iFIDCol = iCol;
678 657 : break;
679 : }
680 : }
681 : }
682 2107 : }
683 :
684 : /************************************************************************/
685 : /* GetFIDColumn() */
686 : /************************************************************************/
687 :
688 237 : const char *OGRSQLiteLayer::GetFIDColumn() const
689 :
690 : {
691 237 : GetLayerDefn();
692 237 : if (m_pszFIDColumn != nullptr)
693 215 : return m_pszFIDColumn;
694 : else
695 22 : return "";
696 : }
697 :
698 : /************************************************************************/
699 : /* ResetReading() */
700 : /************************************************************************/
701 :
702 9920 : void OGRSQLiteLayer::ResetReading()
703 :
704 : {
705 9920 : ClearStatement();
706 9920 : m_iNextShapeId = 0;
707 9920 : m_bEOF = false;
708 9920 : }
709 :
710 : /************************************************************************/
711 : /* GetNextFeature() */
712 : /************************************************************************/
713 :
714 6252 : OGRFeature *OGRSQLiteLayer::GetNextFeature()
715 :
716 : {
717 6252 : if (m_bEOF)
718 15 : return nullptr;
719 :
720 : while (true)
721 : {
722 6366 : OGRFeature *poFeature = GetNextRawFeature();
723 6366 : if (poFeature == nullptr)
724 : {
725 623 : m_bEOF = true;
726 623 : return nullptr;
727 : }
728 :
729 11919 : if ((m_poFilterGeom == nullptr ||
730 11359 : FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
731 5616 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
732 5614 : return poFeature;
733 :
734 129 : delete poFeature;
735 129 : }
736 : }
737 :
738 : /************************************************************************/
739 : /* GetNextRawFeature() */
740 : /************************************************************************/
741 :
742 6430 : OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
743 :
744 : {
745 6430 : if (m_hStmt == nullptr)
746 : {
747 897 : ResetStatement();
748 897 : if (m_hStmt == nullptr)
749 1 : return nullptr;
750 : }
751 :
752 : /* -------------------------------------------------------------------- */
753 : /* Fetch a record (unless otherwise instructed) */
754 : /* -------------------------------------------------------------------- */
755 6429 : if (m_bDoStep)
756 : {
757 5467 : const int rc = sqlite3_step(m_hStmt);
758 5467 : if (rc != SQLITE_ROW)
759 : {
760 634 : 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 634 : ClearStatement();
769 :
770 634 : return nullptr;
771 : }
772 : }
773 : else
774 : {
775 962 : m_bDoStep = true;
776 : }
777 :
778 : /* -------------------------------------------------------------------- */
779 : /* Create a feature from the current result. */
780 : /* -------------------------------------------------------------------- */
781 5795 : OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn);
782 :
783 : /* -------------------------------------------------------------------- */
784 : /* Set FID if we have a column to set it from. */
785 : /* -------------------------------------------------------------------- */
786 5795 : if (m_iFIDCol >= 0)
787 2930 : poFeature->SetFID(sqlite3_column_int64(m_hStmt, m_iFIDCol));
788 : else
789 2865 : poFeature->SetFID(m_iNextShapeId);
790 :
791 5795 : m_iNextShapeId++;
792 :
793 5795 : m_nFeaturesRead++;
794 :
795 : /* -------------------------------------------------------------------- */
796 : /* Process Geometry if we have a column. */
797 : /* -------------------------------------------------------------------- */
798 8071 : for (int iField = 0; iField < m_poFeatureDefn->GetGeomFieldCount();
799 : iField++)
800 : {
801 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
802 2276 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
803 2276 : if (!poGeomFieldDefn->IsIgnored())
804 : {
805 2225 : OGRGeometry *poGeometry = nullptr;
806 2225 : 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 2222 : else if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKB)
813 : {
814 : const int nBytes =
815 830 : 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 830 : 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 830 : if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKB)
837 : {
838 : // coverity[tainted_data_return]
839 : const void *pabyBlob =
840 830 : sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol);
841 830 : CPL_IGNORE_RET_VAL(OGRGeometryFactory::createFromWkb(
842 : pabyBlob, nullptr, &poGeometry, nBytes));
843 : }
844 : }
845 1392 : 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 1381 : else if (poGeomFieldDefn->m_eGeomFormat == OSGF_SpatiaLite)
856 : {
857 : const int nBytes =
858 1381 : sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol);
859 : // coverity[tainted_data_return]
860 : const GByte *pabyBlob = reinterpret_cast<const GByte *>(
861 1381 : sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol));
862 1381 : CPL_IGNORE_RET_VAL(
863 1381 : ImportSpatiaLiteGeometry(pabyBlob, nBytes, &poGeometry));
864 : }
865 :
866 2225 : if (poGeometry != nullptr)
867 : {
868 1938 : if (poGeomFieldDefn->GetSpatialRef() != nullptr)
869 1272 : poGeometry->assignSpatialReference(
870 1272 : poGeomFieldDefn->GetSpatialRef());
871 1938 : poFeature->SetGeomFieldDirectly(iField, poGeometry);
872 : }
873 : }
874 : }
875 :
876 : /* -------------------------------------------------------------------- */
877 : /* set the fields. */
878 : /* -------------------------------------------------------------------- */
879 5795 : const int nFieldCount = m_poFeatureDefn->GetFieldCount();
880 28244 : for (int iField = 0; iField < nFieldCount; iField++)
881 : {
882 : const OGRFieldDefn *poFieldDefn =
883 22449 : m_poFeatureDefn->GetFieldDefnUnsafe(iField);
884 22449 : if (poFieldDefn->IsIgnored())
885 52 : continue;
886 :
887 22397 : int iRawField = m_panFieldOrdinals[iField];
888 :
889 22397 : int nSQLite3Type = sqlite3_column_type(m_hStmt, iRawField);
890 22397 : if (nSQLite3Type == SQLITE_NULL)
891 : {
892 4472 : poFeature->SetFieldNull(iField);
893 4472 : continue;
894 : }
895 :
896 17925 : switch (poFieldDefn->GetType())
897 : {
898 4329 : case OFTInteger:
899 : {
900 : /* Possible since SQLite3 has no strong typing */
901 4329 : 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 4327 : sqlite3_column_int64(m_hStmt, iRawField);
909 4327 : if (poFieldDefn->GetSubType() == OFSTBoolean)
910 : {
911 765 : poFeature->SetField(iField, nVal != 0);
912 : }
913 : else
914 : {
915 3562 : if (nVal >= INT_MIN && nVal <= INT_MAX)
916 3562 : poFeature->SetFieldSameTypeUnsafe(
917 : iField, static_cast<int>(nVal));
918 : else
919 0 : poFeature->SetField(iField, nVal);
920 : }
921 : }
922 4329 : break;
923 : }
924 :
925 765 : case OFTInteger64:
926 : {
927 : /* Possible since SQLite3 has no strong typing */
928 765 : 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 765 : poFeature->SetFieldSameTypeUnsafe(
934 : iField, sqlite3_column_int64(m_hStmt, iRawField));
935 765 : break;
936 : }
937 :
938 2252 : case OFTReal:
939 : {
940 : /* Possible since SQLite3 has no strong typing */
941 2252 : 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 2251 : poFeature->SetField(
947 : iField, sqlite3_column_double(m_hStmt, iRawField));
948 2252 : break;
949 : }
950 :
951 689 : case OFTBinary:
952 : {
953 689 : const int nBytes = sqlite3_column_bytes(m_hStmt, iRawField);
954 : // coverity[tainted_data_return]
955 : const GByte *pabyData = reinterpret_cast<const GByte *>(
956 689 : sqlite3_column_blob(m_hStmt, iRawField));
957 689 : poFeature->SetField(iField, nBytes,
958 : const_cast<GByte *>(pabyData));
959 : }
960 689 : break;
961 :
962 9444 : case OFTString:
963 : case OFTIntegerList:
964 : case OFTInteger64List:
965 : case OFTRealList:
966 : case OFTStringList:
967 : {
968 9444 : if (CSLFindString(
969 9444 : m_papszCompressedColumns,
970 18888 : 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 9405 : poFeature->SetField(
997 : iField, reinterpret_cast<const char *>(
998 9405 : sqlite3_column_text(m_hStmt, iRawField)));
999 : }
1000 9444 : 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 5984 : 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 5984 : 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 5795 : 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 1485 : OGRErr OGRSQLiteLayer::createFromSpatialiteInternal(
1087 : const GByte *pabyData, OGRGeometry **ppoReturn, int nBytes,
1088 : OGRwkbByteOrder eByteOrder, int *pnBytesConsumed, int nRecLevel)
1089 : {
1090 1485 : *ppoReturn = nullptr;
1091 :
1092 : /* Arbitrary value, but certainly large enough for reasonable usages ! */
1093 1485 : 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 1485 : if (nBytes < 4)
1103 0 : return OGRERR_NOT_ENOUGH_DATA;
1104 :
1105 : /* -------------------------------------------------------------------- */
1106 : /* Decode the geometry type. */
1107 : /* -------------------------------------------------------------------- */
1108 1485 : GInt32 nGType = 0;
1109 1485 : memcpy(&nGType, pabyData, 4);
1110 1485 : if (NEED_SWAP_SPATIALITE())
1111 0 : CPL_SWAP32PTR(&nGType);
1112 :
1113 1485 : if ((nGType >= OGRSplitePointXY &&
1114 1485 : nGType <= OGRSpliteGeometryCollectionXY) || // XY types
1115 423 : (nGType >= OGRSplitePointXYZ &&
1116 423 : nGType <= OGRSpliteGeometryCollectionXYZ) || // XYZ types
1117 381 : (nGType >= OGRSplitePointXYM &&
1118 381 : nGType <= OGRSpliteGeometryCollectionXYM) || // XYM types
1119 357 : (nGType >= OGRSplitePointXYZM &&
1120 357 : nGType <= OGRSpliteGeometryCollectionXYZM) || // XYZM types
1121 333 : (nGType >= OGRSpliteComprLineStringXY &&
1122 333 : 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 1485 : OGRGeometry *poGeom = nullptr;
1137 1485 : GInt32 compressedSize = 0;
1138 :
1139 1485 : 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 970 : 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 956 : 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 948 : 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 940 : 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 907 : 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 900 : 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 895 : 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 890 : 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 885 : 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 880 : 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 876 : 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 872 : else if (nGType == OGRSplitePolygonXY)
1705 : {
1706 467 : if (nBytes < 8)
1707 0 : return OGRERR_NOT_ENOUGH_DATA;
1708 :
1709 467 : GInt32 nRingCount = 0;
1710 467 : memcpy(&nRingCount, pabyData + 4, 4);
1711 467 : if (NEED_SWAP_SPATIALITE())
1712 0 : CPL_SWAP32PTR(&nRingCount);
1713 :
1714 467 : if (nRingCount < 0 || nRingCount > INT_MAX / 4)
1715 0 : return OGRERR_CORRUPT_DATA;
1716 :
1717 : // Each ring has a minimum of 4 bytes
1718 467 : if (nBytes - 8 < nRingCount * 4)
1719 0 : return OGRERR_NOT_ENOUGH_DATA;
1720 :
1721 467 : int nNextByte = 8;
1722 :
1723 467 : OGRPolygon *poPoly = new OGRPolygon();
1724 467 : poGeom = poPoly;
1725 :
1726 939 : for (int iRing = 0; iRing < nRingCount; iRing++)
1727 : {
1728 472 : if (nBytes - nNextByte < 4)
1729 : {
1730 0 : delete poPoly;
1731 0 : return OGRERR_NOT_ENOUGH_DATA;
1732 : }
1733 :
1734 472 : GInt32 nPointCount = 0;
1735 472 : memcpy(&nPointCount, pabyData + nNextByte, 4);
1736 472 : if (NEED_SWAP_SPATIALITE())
1737 0 : CPL_SWAP32PTR(&nPointCount);
1738 :
1739 472 : if (nPointCount < 0 || nPointCount > INT_MAX / (2 * 8))
1740 : {
1741 0 : delete poPoly;
1742 0 : return OGRERR_CORRUPT_DATA;
1743 : }
1744 :
1745 472 : nNextByte += 4;
1746 :
1747 472 : if (nBytes - nNextByte < 2 * 8 * nPointCount)
1748 : {
1749 0 : delete poPoly;
1750 0 : return OGRERR_NOT_ENOUGH_DATA;
1751 : }
1752 :
1753 472 : OGRLinearRing *poLR = new OGRLinearRing();
1754 472 : if (!NEED_SWAP_SPATIALITE())
1755 : {
1756 472 : poLR->setPoints(
1757 : nPointCount,
1758 472 : reinterpret_cast<const OGRRawPoint *>(pabyData + nNextByte),
1759 : nullptr);
1760 472 : 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 472 : poPoly->addRingDirectly(poLR);
1777 : }
1778 :
1779 467 : if (pnBytesConsumed)
1780 467 : *pnBytesConsumed = nNextByte;
1781 : }
1782 :
1783 : /* -------------------------------------------------------------------- */
1784 : /* Polygon [XYZ] */
1785 : /* -------------------------------------------------------------------- */
1786 405 : 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 398 : 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 395 : 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 392 : else if (nGType == OGRSpliteComprPolygonXY)
2024 : {
2025 305 : if (nBytes < 8)
2026 0 : return OGRERR_NOT_ENOUGH_DATA;
2027 :
2028 305 : GInt32 nRingCount = 0;
2029 305 : memcpy(&nRingCount, pabyData + 4, 4);
2030 305 : if (NEED_SWAP_SPATIALITE())
2031 0 : CPL_SWAP32PTR(&nRingCount);
2032 :
2033 305 : if (nRingCount < 0 || nRingCount > INT_MAX / 4)
2034 0 : return OGRERR_CORRUPT_DATA;
2035 :
2036 : // Each ring has a minimum of 4 bytes
2037 305 : if (nBytes - 8 < nRingCount * 4)
2038 0 : return OGRERR_NOT_ENOUGH_DATA;
2039 :
2040 305 : int nNextByte = 8;
2041 :
2042 305 : OGRPolygon *poPoly = new OGRPolygon();
2043 305 : poGeom = poPoly;
2044 :
2045 611 : for (int iRing = 0; iRing < nRingCount; iRing++)
2046 : {
2047 306 : if (nBytes - nNextByte < 4)
2048 : {
2049 0 : delete poPoly;
2050 0 : return OGRERR_NOT_ENOUGH_DATA;
2051 : }
2052 :
2053 306 : GInt32 nPointCount = 0;
2054 306 : memcpy(&nPointCount, pabyData + nNextByte, 4);
2055 306 : if (NEED_SWAP_SPATIALITE())
2056 0 : CPL_SWAP32PTR(&nPointCount);
2057 :
2058 306 : if (nPointCount < 0 || nPointCount > (INT_MAX - 16 * 2) / 8 + 2)
2059 : {
2060 0 : delete poPoly;
2061 0 : return OGRERR_CORRUPT_DATA;
2062 : }
2063 :
2064 306 : compressedSize = 16 * 2; // first and last Points
2065 306 : compressedSize += 8 * (nPointCount - 2); // intermediate Points
2066 :
2067 306 : nNextByte += 4;
2068 :
2069 306 : if (nBytes - nNextByte < compressedSize)
2070 : {
2071 0 : delete poPoly;
2072 0 : return OGRERR_NOT_ENOUGH_DATA;
2073 : }
2074 :
2075 306 : double adfTupleBase[2] = {0.0, 0.0};
2076 306 : OGRLinearRing *poLR = new OGRLinearRing();
2077 306 : poLR->setNumPoints(nPointCount, FALSE);
2078 :
2079 9213 : for (int iPoint = 0; iPoint < nPointCount; iPoint++)
2080 : {
2081 8907 : double adfTuple[2] = {0.0, 0.0};
2082 8907 : if (iPoint == 0 || iPoint == (nPointCount - 1))
2083 : {
2084 : // first and last Points are uncompressed
2085 612 : memcpy(adfTuple, pabyData + nNextByte, 2 * 8);
2086 612 : nNextByte += 2 * 8;
2087 :
2088 612 : if (NEED_SWAP_SPATIALITE())
2089 : {
2090 0 : CPL_SWAP64PTR(adfTuple);
2091 0 : CPL_SWAP64PTR(adfTuple + 1);
2092 612 : }
2093 : }
2094 : else
2095 : {
2096 : // any other intermediate Point is compressed
2097 8295 : float asfTuple[2] = {0.0f, 0.0f};
2098 8295 : memcpy(asfTuple, pabyData + nNextByte, 2 * 4);
2099 8295 : nNextByte += 2 * 4;
2100 :
2101 8295 : if (NEED_SWAP_SPATIALITE())
2102 : {
2103 0 : CPL_SWAP32PTR(asfTuple);
2104 0 : CPL_SWAP32PTR(asfTuple + 1);
2105 : }
2106 8295 : adfTuple[0] = asfTuple[0] + adfTupleBase[0];
2107 8295 : adfTuple[1] = asfTuple[1] + adfTupleBase[1];
2108 : }
2109 :
2110 8907 : poLR->setPoint(iPoint, adfTuple[0], adfTuple[1]);
2111 8907 : adfTupleBase[0] = adfTuple[0];
2112 8907 : adfTupleBase[1] = adfTuple[1];
2113 : }
2114 :
2115 306 : poPoly->addRingDirectly(poLR);
2116 : }
2117 :
2118 305 : if (pnBytesConsumed)
2119 305 : *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 1484 : *ppoReturn = poGeom;
2584 1484 : 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 1939 : static bool QuickCheckForSpatialiteGeometryValidity(const GByte *pabyData,
2650 : int nBytes)
2651 : {
2652 1624 : return nBytes >= 44 && pabyData[0] == 0 &&
2653 1432 : (pabyData[1] == wkbXDR || pabyData[1] == wkbNDR) &&
2654 3563 : 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 1848 : OGRErr OGRSQLiteLayer::ImportSpatiaLiteGeometry(const GByte *pabyData,
2752 : int nBytes,
2753 : OGRGeometry **ppoGeometry)
2754 :
2755 : {
2756 1848 : return ImportSpatiaLiteGeometry(pabyData, nBytes, ppoGeometry, nullptr);
2757 : }
2758 :
2759 : /************************************************************************/
2760 : /* ImportSpatiaLiteGeometry() */
2761 : /************************************************************************/
2762 :
2763 1927 : OGRErr OGRSQLiteLayer::ImportSpatiaLiteGeometry(const GByte *pabyData,
2764 : int nBytes,
2765 : OGRGeometry **ppoGeometry,
2766 : int *pnSRID)
2767 :
2768 : {
2769 1927 : *ppoGeometry = nullptr;
2770 :
2771 1927 : if (!QuickCheckForSpatialiteGeometryValidity(pabyData, nBytes))
2772 553 : return OGRERR_CORRUPT_DATA;
2773 :
2774 1374 : const OGRwkbByteOrder eByteOrder =
2775 1374 : static_cast<OGRwkbByteOrder>(pabyData[1]);
2776 :
2777 : /* -------------------------------------------------------------------- */
2778 : /* Decode the geometry type. */
2779 : /* -------------------------------------------------------------------- */
2780 1374 : 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 1374 : int nBytesConsumed = 0;
2790 : OGRErr eErr =
2791 1374 : createFromSpatialiteInternal(pabyData + 39, ppoGeometry, nBytes - 39,
2792 : eByteOrder, &nBytesConsumed, 0);
2793 1374 : 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 1373 : 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 1374 : 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 : }
3019 207 : return OGRSplitePointXY;
3020 :
3021 76 : case wkbLineString:
3022 : case wkbLinearRing:
3023 76 : if (bSpatialite2D == true)
3024 0 : return OGRSpliteLineStringXY;
3025 76 : else if (poGeometry->Is3D())
3026 : {
3027 27 : if (poGeometry->IsMeasured())
3028 9 : return (bUseComprGeom) ? OGRSpliteComprLineStringXYZM
3029 9 : : OGRSpliteLineStringXYZM;
3030 : else
3031 18 : return (bUseComprGeom) ? OGRSpliteComprLineStringXYZ
3032 18 : : OGRSpliteLineStringXYZ;
3033 : }
3034 : else
3035 : {
3036 49 : if (poGeometry->IsMeasured())
3037 9 : return (bUseComprGeom) ? OGRSpliteComprLineStringXYM
3038 9 : : OGRSpliteLineStringXYM;
3039 : }
3040 40 : return (bUseComprGeom) ? OGRSpliteComprLineStringXY
3041 40 : : OGRSpliteLineStringXY;
3042 :
3043 144 : case wkbPolygon:
3044 144 : if (bSpatialite2D == true)
3045 0 : return OGRSplitePolygonXY;
3046 144 : else if (poGeometry->Is3D())
3047 : {
3048 23 : if (poGeometry->IsMeasured())
3049 6 : return (bUseComprGeom) ? OGRSpliteComprPolygonXYZM
3050 6 : : OGRSplitePolygonXYZM;
3051 : else
3052 17 : return (bUseComprGeom) ? OGRSpliteComprPolygonXYZ
3053 17 : : OGRSplitePolygonXYZ;
3054 : }
3055 : else
3056 : {
3057 121 : if (poGeometry->IsMeasured())
3058 6 : return (bUseComprGeom) ? OGRSpliteComprPolygonXYM
3059 6 : : OGRSplitePolygonXYM;
3060 : }
3061 115 : return (bUseComprGeom) ? OGRSpliteComprPolygonXY
3062 115 : : OGRSplitePolygonXY;
3063 :
3064 82 : default:
3065 82 : break;
3066 : }
3067 :
3068 82 : if (!bAcceptMultiGeom)
3069 : {
3070 0 : return 0;
3071 : }
3072 :
3073 82 : switch (eType)
3074 : {
3075 16 : case wkbMultiPoint:
3076 16 : if (bSpatialite2D == true)
3077 0 : return OGRSpliteMultiPointXY;
3078 16 : else if (poGeometry->Is3D())
3079 : {
3080 6 : if (poGeometry->IsMeasured())
3081 2 : return OGRSpliteMultiPointXYZM;
3082 : else
3083 4 : return OGRSpliteMultiPointXYZ;
3084 : }
3085 : else
3086 : {
3087 10 : if (poGeometry->IsMeasured())
3088 2 : return OGRSpliteMultiPointXYM;
3089 : }
3090 8 : return OGRSpliteMultiPointXY;
3091 :
3092 17 : case wkbMultiLineString:
3093 17 : if (bSpatialite2D == true)
3094 0 : return OGRSpliteMultiLineStringXY;
3095 17 : else if (poGeometry->Is3D())
3096 : {
3097 6 : if (poGeometry->IsMeasured())
3098 : return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXYZM
3099 : :*/
3100 2 : OGRSpliteMultiLineStringXYZM;
3101 : else
3102 : return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXYZ
3103 : :*/
3104 4 : OGRSpliteMultiLineStringXYZ;
3105 : }
3106 : else
3107 : {
3108 11 : if (poGeometry->IsMeasured())
3109 : return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXYM
3110 : :*/
3111 2 : OGRSpliteMultiLineStringXYM;
3112 : }
3113 : return /*(bUseComprGeom) ? OGRSpliteComprMultiLineStringXY
3114 : :*/
3115 9 : OGRSpliteMultiLineStringXY;
3116 :
3117 19 : case wkbMultiPolygon:
3118 19 : if (bSpatialite2D == true)
3119 0 : return OGRSpliteMultiPolygonXY;
3120 19 : else if (poGeometry->Is3D())
3121 : {
3122 6 : if (poGeometry->IsMeasured())
3123 : return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXYZM
3124 : :*/
3125 2 : OGRSpliteMultiPolygonXYZM;
3126 : else
3127 : return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXYZ :*/
3128 4 : OGRSpliteMultiPolygonXYZ;
3129 : }
3130 : else
3131 : {
3132 13 : if (poGeometry->IsMeasured())
3133 : return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXYM :*/
3134 2 : OGRSpliteMultiPolygonXYM;
3135 : }
3136 : return /*(bUseComprGeom) ? OGRSpliteComprMultiPolygonXY :*/
3137 11 : OGRSpliteMultiPolygonXY;
3138 :
3139 30 : case wkbGeometryCollection:
3140 30 : if (bSpatialite2D == true)
3141 0 : return OGRSpliteGeometryCollectionXY;
3142 30 : else if (poGeometry->Is3D())
3143 : {
3144 12 : if (poGeometry->IsMeasured())
3145 : return /*(bUseComprGeom) ?
3146 : OGRSpliteComprGeometryCollectionXYZM :*/
3147 2 : OGRSpliteGeometryCollectionXYZM;
3148 : else
3149 : return /*(bUseComprGeom) ?
3150 : OGRSpliteComprGeometryCollectionXYZ :*/
3151 10 : OGRSpliteGeometryCollectionXYZ;
3152 : }
3153 : else
3154 : {
3155 18 : if (poGeometry->IsMeasured())
3156 : return /*(bUseComprGeom) ?
3157 : OGRSpliteComprGeometryCollectionXYM :*/
3158 2 : OGRSpliteGeometryCollectionXYM;
3159 : }
3160 : return /*(bUseComprGeom) ?
3161 : OGRSpliteComprGeometryCollectionXY :*/
3162 16 : OGRSpliteGeometryCollectionXY;
3163 :
3164 0 : default:
3165 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected geometry type");
3166 0 : return 0;
3167 : }
3168 : }
3169 :
3170 : /************************************************************************/
3171 : /* ExportSpatiaLiteGeometryInternal() */
3172 : /************************************************************************/
3173 :
3174 689 : int OGRSQLiteLayer::ExportSpatiaLiteGeometryInternal(
3175 : const OGRGeometry *poGeometry, OGRwkbByteOrder eByteOrder,
3176 : bool bSpatialite2D, bool bUseComprGeom, GByte *pabyData)
3177 : {
3178 689 : const auto eFGeomType = wkbFlatten(poGeometry->getGeometryType());
3179 689 : switch (eFGeomType)
3180 : {
3181 241 : case wkbPoint:
3182 : {
3183 241 : const OGRPoint *poPoint = poGeometry->toPoint();
3184 241 : double x = poPoint->getX();
3185 241 : double y = poPoint->getY();
3186 241 : memcpy(pabyData, &x, 8);
3187 241 : memcpy(pabyData + 8, &y, 8);
3188 241 : if (NEED_SWAP_SPATIALITE())
3189 : {
3190 0 : CPL_SWAP64PTR(pabyData);
3191 0 : CPL_SWAP64PTR(pabyData + 8);
3192 : }
3193 241 : if (bSpatialite2D == true)
3194 0 : return 16;
3195 241 : else if (poGeometry->Is3D())
3196 : {
3197 26 : double z = poPoint->getZ();
3198 26 : memcpy(pabyData + 16, &z, 8);
3199 26 : if (NEED_SWAP_SPATIALITE())
3200 0 : CPL_SWAP64PTR(pabyData + 16);
3201 26 : if (poGeometry->IsMeasured())
3202 : {
3203 8 : double m = poPoint->getM();
3204 8 : memcpy(pabyData + 24, &m, 8);
3205 8 : if (NEED_SWAP_SPATIALITE())
3206 0 : CPL_SWAP64PTR(pabyData + 24);
3207 8 : return 32;
3208 : }
3209 : else
3210 18 : return 24;
3211 : }
3212 : else
3213 : {
3214 215 : if (poGeometry->IsMeasured())
3215 : {
3216 8 : double m = poPoint->getM();
3217 8 : memcpy(pabyData + 16, &m, 8);
3218 8 : if (NEED_SWAP_SPATIALITE())
3219 0 : CPL_SWAP64PTR(pabyData + 16);
3220 8 : return 24;
3221 : }
3222 : else
3223 207 : return 16;
3224 : }
3225 : }
3226 :
3227 222 : case wkbLineString:
3228 : case wkbLinearRing:
3229 : {
3230 222 : const OGRLineString *poLineString = poGeometry->toLineString();
3231 222 : int nTotalSize = 4;
3232 222 : int nPointCount = poLineString->getNumPoints();
3233 222 : memcpy(pabyData, &nPointCount, 4);
3234 222 : if (NEED_SWAP_SPATIALITE())
3235 0 : CPL_SWAP32PTR(pabyData);
3236 :
3237 407 : if (!bUseComprGeom && !NEED_SWAP_SPATIALITE() &&
3238 185 : poGeometry->CoordinateDimension() == 2)
3239 : {
3240 143 : poLineString->getPoints(
3241 143 : reinterpret_cast<OGRRawPoint *>(pabyData + 4), nullptr);
3242 143 : nTotalSize += nPointCount * 16;
3243 143 : return nTotalSize;
3244 : }
3245 :
3246 356 : for (int i = 0; i < nPointCount; i++)
3247 : {
3248 277 : double x = poLineString->getX(i);
3249 277 : double y = poLineString->getY(i);
3250 :
3251 277 : if (!bUseComprGeom || i == 0 || i == nPointCount - 1)
3252 : {
3253 216 : memcpy(pabyData + nTotalSize, &x, 8);
3254 216 : memcpy(pabyData + nTotalSize + 8, &y, 8);
3255 216 : if (NEED_SWAP_SPATIALITE())
3256 : {
3257 0 : CPL_SWAP64PTR(pabyData + nTotalSize);
3258 0 : CPL_SWAP64PTR(pabyData + nTotalSize + 8);
3259 : }
3260 216 : if (!bSpatialite2D && poGeometry->Is3D())
3261 : {
3262 149 : double z = poLineString->getZ(i);
3263 149 : memcpy(pabyData + nTotalSize + 16, &z, 8);
3264 149 : if (NEED_SWAP_SPATIALITE())
3265 0 : CPL_SWAP64PTR(pabyData + nTotalSize + 16);
3266 149 : if (poGeometry->IsMeasured())
3267 : {
3268 39 : double m = poLineString->getM(i);
3269 39 : memcpy(pabyData + nTotalSize + 24, &m, 8);
3270 39 : if (NEED_SWAP_SPATIALITE())
3271 0 : CPL_SWAP64PTR(pabyData + nTotalSize + 24);
3272 39 : nTotalSize += 32;
3273 : }
3274 : else
3275 110 : nTotalSize += 24;
3276 : }
3277 : else
3278 : {
3279 67 : if (poGeometry->IsMeasured())
3280 : {
3281 39 : double m = poLineString->getM(i);
3282 39 : memcpy(pabyData + nTotalSize + 16, &m, 8);
3283 39 : if (NEED_SWAP_SPATIALITE())
3284 0 : CPL_SWAP64PTR(pabyData + nTotalSize + 16);
3285 39 : nTotalSize += 24;
3286 : }
3287 : else
3288 28 : nTotalSize += 16;
3289 216 : }
3290 : }
3291 : else /* Compressed intermediate points */
3292 : {
3293 : float deltax =
3294 61 : static_cast<float>(x - poLineString->getX(i - 1));
3295 : float deltay =
3296 61 : static_cast<float>(y - poLineString->getY(i - 1));
3297 61 : memcpy(pabyData + nTotalSize, &deltax, 4);
3298 61 : memcpy(pabyData + nTotalSize + 4, &deltay, 4);
3299 61 : if (NEED_SWAP_SPATIALITE())
3300 : {
3301 0 : CPL_SWAP32PTR(pabyData + nTotalSize);
3302 0 : CPL_SWAP32PTR(pabyData + nTotalSize + 4);
3303 : }
3304 61 : if (poGeometry->Is3D())
3305 : {
3306 23 : double z = poLineString->getZ(i);
3307 : float deltaz =
3308 23 : static_cast<float>(z - poLineString->getZ(i - 1));
3309 23 : memcpy(pabyData + nTotalSize + 8, &deltaz, 4);
3310 23 : if (NEED_SWAP_SPATIALITE())
3311 0 : CPL_SWAP32PTR(pabyData + nTotalSize + 8);
3312 23 : if (poGeometry->IsMeasured())
3313 : {
3314 10 : double m = poLineString->getM(i);
3315 10 : memcpy(pabyData + nTotalSize + 12, &m, 8);
3316 10 : if (NEED_SWAP_SPATIALITE())
3317 0 : CPL_SWAP64PTR(pabyData + nTotalSize + 12);
3318 10 : nTotalSize += 20;
3319 : }
3320 : else
3321 13 : nTotalSize += 12;
3322 : }
3323 : else
3324 : {
3325 38 : if (poGeometry->IsMeasured())
3326 : {
3327 10 : double m = poLineString->getM(i);
3328 10 : memcpy(pabyData + nTotalSize + 8, &m, 8);
3329 10 : if (NEED_SWAP_SPATIALITE())
3330 0 : CPL_SWAP64PTR(pabyData + nTotalSize + 8);
3331 10 : nTotalSize += 16;
3332 : }
3333 : else
3334 28 : nTotalSize += 8;
3335 : }
3336 : }
3337 : }
3338 79 : return nTotalSize;
3339 : }
3340 :
3341 144 : case wkbPolygon:
3342 : {
3343 144 : const OGRPolygon *poPoly = poGeometry->toPolygon();
3344 144 : int nTotalSize = 4;
3345 144 : if (poPoly->getExteriorRing() != nullptr)
3346 : {
3347 141 : int nInteriorRingCount = poPoly->getNumInteriorRings();
3348 141 : const int nParts = 1 + nInteriorRingCount;
3349 141 : memcpy(pabyData, &nParts, 4);
3350 141 : if (NEED_SWAP_SPATIALITE())
3351 0 : CPL_SWAP32PTR(pabyData);
3352 :
3353 423 : nTotalSize += ExportSpatiaLiteGeometryInternal(
3354 141 : poPoly->getExteriorRing(), eByteOrder, bSpatialite2D,
3355 141 : bUseComprGeom, pabyData + nTotalSize);
3356 :
3357 146 : for (int i = 0; i < nInteriorRingCount; i++)
3358 : {
3359 5 : nTotalSize += ExportSpatiaLiteGeometryInternal(
3360 5 : poPoly->getInteriorRing(i), eByteOrder, bSpatialite2D,
3361 5 : bUseComprGeom, pabyData + nTotalSize);
3362 : }
3363 : }
3364 : else
3365 : {
3366 3 : memset(pabyData, 0, 4);
3367 : }
3368 144 : return nTotalSize;
3369 : }
3370 :
3371 82 : case wkbMultiPoint:
3372 : case wkbMultiLineString:
3373 : case wkbMultiPolygon:
3374 : case wkbGeometryCollection:
3375 : {
3376 : const OGRGeometryCollection *poGeomCollection =
3377 82 : poGeometry->toGeometryCollection();
3378 82 : int nTotalSize = 4;
3379 :
3380 164 : std::vector<const OGRGeometry *> simpleGeometries;
3381 82 : collectSimpleGeometries(poGeomCollection, simpleGeometries);
3382 :
3383 82 : int nParts = static_cast<int>(simpleGeometries.size());
3384 82 : memcpy(pabyData, &nParts, 4);
3385 82 : if (NEED_SWAP_SPATIALITE())
3386 0 : CPL_SWAP32PTR(pabyData);
3387 :
3388 204 : for (int i = 0; i < nParts; i++)
3389 : {
3390 122 : pabyData[nTotalSize] = 0x69;
3391 122 : nTotalSize++;
3392 :
3393 122 : const OGRGeometry *poPart = simpleGeometries[i];
3394 122 : int nCode = GetSpatialiteGeometryCode(poPart, bSpatialite2D,
3395 122 : bUseComprGeom, FALSE);
3396 122 : if (nCode == 0)
3397 0 : return 0;
3398 122 : memcpy(pabyData + nTotalSize, &nCode, 4);
3399 122 : if (NEED_SWAP_SPATIALITE())
3400 0 : CPL_SWAP32PTR(pabyData + nTotalSize);
3401 122 : nTotalSize += 4;
3402 122 : nTotalSize += ExportSpatiaLiteGeometryInternal(
3403 : poPart, eByteOrder, bSpatialite2D, bUseComprGeom,
3404 122 : pabyData + nTotalSize);
3405 : }
3406 82 : return nTotalSize;
3407 : }
3408 :
3409 0 : default:
3410 0 : return 0;
3411 : }
3412 : }
3413 :
3414 421 : OGRErr OGRSQLiteLayer::ExportSpatiaLiteGeometry(
3415 : const OGRGeometry *poGeometry, GInt32 nSRID, OGRwkbByteOrder eByteOrder,
3416 : bool bSpatialite2D, bool bUseComprGeom, GByte **ppabyData,
3417 : int *pnDataLength)
3418 :
3419 : {
3420 : /* Spatialite does not support curve geometries */
3421 421 : const OGRGeometry *poWorkGeom = poGeometry->hasCurveGeometry()
3422 421 : ? poGeometry->getLinearGeometry()
3423 421 : : poGeometry;
3424 :
3425 468 : bUseComprGeom = bUseComprGeom && !bSpatialite2D &&
3426 47 : CanBeCompressedSpatialiteGeometry(poWorkGeom);
3427 :
3428 : const int nGeomSize =
3429 421 : ComputeSpatiaLiteGeometrySize(poWorkGeom, bSpatialite2D, bUseComprGeom);
3430 421 : if (nGeomSize == 0)
3431 : {
3432 0 : *ppabyData = nullptr;
3433 0 : *pnDataLength = 0;
3434 0 : return OGRERR_FAILURE;
3435 : }
3436 421 : const int nDataLen = 44 + nGeomSize;
3437 421 : OGREnvelope sEnvelope;
3438 :
3439 421 : *ppabyData = static_cast<GByte *>(CPLMalloc(nDataLen));
3440 :
3441 421 : (*ppabyData)[0] = 0x00;
3442 421 : (*ppabyData)[1] = static_cast<GByte>(eByteOrder);
3443 :
3444 : // Write out SRID
3445 421 : memcpy(*ppabyData + 2, &nSRID, 4);
3446 :
3447 : // Write out the geometry bounding rectangle
3448 421 : poGeometry->getEnvelope(&sEnvelope);
3449 421 : memcpy(*ppabyData + 6, &sEnvelope.MinX, 8);
3450 421 : memcpy(*ppabyData + 14, &sEnvelope.MinY, 8);
3451 421 : memcpy(*ppabyData + 22, &sEnvelope.MaxX, 8);
3452 421 : memcpy(*ppabyData + 30, &sEnvelope.MaxY, 8);
3453 :
3454 421 : (*ppabyData)[38] = 0x7C;
3455 :
3456 421 : int nCode = GetSpatialiteGeometryCode(poWorkGeom, bSpatialite2D,
3457 421 : bUseComprGeom, TRUE);
3458 421 : if (nCode == 0)
3459 : {
3460 0 : CPLFree(*ppabyData);
3461 0 : *ppabyData = nullptr;
3462 0 : *pnDataLength = 0;
3463 0 : if (poWorkGeom != poGeometry)
3464 0 : delete poWorkGeom;
3465 0 : return OGRERR_FAILURE;
3466 : }
3467 421 : memcpy(*ppabyData + 39, &nCode, 4);
3468 :
3469 842 : int nWritten = ExportSpatiaLiteGeometryInternal(
3470 421 : poWorkGeom, eByteOrder, bSpatialite2D, bUseComprGeom, *ppabyData + 43);
3471 421 : if (poWorkGeom != poGeometry)
3472 1 : delete poWorkGeom;
3473 :
3474 421 : if (nWritten == 0)
3475 : {
3476 0 : CPLFree(*ppabyData);
3477 0 : *ppabyData = nullptr;
3478 0 : *pnDataLength = 0;
3479 0 : return OGRERR_FAILURE;
3480 : }
3481 :
3482 421 : (*ppabyData)[nDataLen - 1] = 0xFE;
3483 :
3484 421 : if (NEED_SWAP_SPATIALITE())
3485 : {
3486 0 : CPL_SWAP32PTR(*ppabyData + 2);
3487 0 : CPL_SWAP64PTR(*ppabyData + 6);
3488 0 : CPL_SWAP64PTR(*ppabyData + 14);
3489 0 : CPL_SWAP64PTR(*ppabyData + 22);
3490 0 : CPL_SWAP64PTR(*ppabyData + 30);
3491 0 : CPL_SWAP32PTR(*ppabyData + 39);
3492 : }
3493 :
3494 421 : *pnDataLength = nDataLen;
3495 :
3496 421 : return OGRERR_NONE;
3497 : }
3498 :
3499 : /************************************************************************/
3500 : /* TestCapability() */
3501 : /************************************************************************/
3502 :
3503 78 : int OGRSQLiteLayer::TestCapability(const char *pszCap) const
3504 :
3505 : {
3506 78 : if (EQUAL(pszCap, OLCRandomRead))
3507 0 : return FALSE;
3508 :
3509 78 : else if (EQUAL(pszCap, OLCFastFeatureCount))
3510 0 : return FALSE;
3511 :
3512 78 : else if (EQUAL(pszCap, OLCFastSpatialFilter))
3513 0 : return FALSE;
3514 :
3515 78 : else if (EQUAL(pszCap, OLCIgnoreFields))
3516 6 : return TRUE;
3517 :
3518 72 : else if (EQUAL(pszCap, OLCTransactions))
3519 6 : return TRUE;
3520 :
3521 66 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
3522 10 : return TRUE;
3523 :
3524 : else
3525 56 : return FALSE;
3526 : }
3527 :
3528 : /************************************************************************/
3529 : /* StartTransaction() */
3530 : /************************************************************************/
3531 :
3532 34 : OGRErr OGRSQLiteLayer::StartTransaction()
3533 : {
3534 34 : return m_poDS->StartTransaction();
3535 : }
3536 :
3537 : /************************************************************************/
3538 : /* CommitTransaction() */
3539 : /************************************************************************/
3540 :
3541 26 : OGRErr OGRSQLiteLayer::CommitTransaction()
3542 : {
3543 26 : return m_poDS->CommitTransaction();
3544 : }
3545 :
3546 : /************************************************************************/
3547 : /* RollbackTransaction() */
3548 : /************************************************************************/
3549 :
3550 8 : OGRErr OGRSQLiteLayer::RollbackTransaction()
3551 : {
3552 8 : return m_poDS->RollbackTransaction();
3553 : }
3554 :
3555 : /************************************************************************/
3556 : /* ClearStatement() */
3557 : /************************************************************************/
3558 :
3559 13426 : void OGRSQLiteLayer::ClearStatement()
3560 :
3561 : {
3562 13426 : if (m_hStmt != nullptr)
3563 : {
3564 : #ifdef DEBUG_VERBOSE
3565 : CPLDebug("OGR_SQLITE", "finalize %p", m_hStmt);
3566 : #endif
3567 1183 : sqlite3_finalize(m_hStmt);
3568 1183 : m_hStmt = nullptr;
3569 : }
3570 13426 : }
3571 :
3572 : /************************************************************************/
3573 : /* FormatSpatialFilterFromRTree() */
3574 : /************************************************************************/
3575 :
3576 87 : CPLString OGRSQLiteLayer::FormatSpatialFilterFromRTree(
3577 : OGRGeometry *poFilterGeom, const char *pszRowIDName,
3578 : const char *pszEscapedTable, const char *pszEscapedGeomCol)
3579 : {
3580 174 : CPLString osSpatialWHERE;
3581 87 : OGREnvelope sEnvelope;
3582 :
3583 87 : poFilterGeom->getEnvelope(&sEnvelope);
3584 :
3585 93 : if (std::isinf(sEnvelope.MinX) && sEnvelope.MinX < 0 &&
3586 9 : std::isinf(sEnvelope.MinY) && sEnvelope.MinY < 0 &&
3587 9 : std::isinf(sEnvelope.MaxX) && sEnvelope.MaxX > 0 &&
3588 93 : std::isinf(sEnvelope.MaxY) && sEnvelope.MaxY > 0)
3589 3 : return "";
3590 :
3591 : osSpatialWHERE.Printf(
3592 : "%s IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
3593 : "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f AND ymin <= %.12f)",
3594 : pszRowIDName, pszEscapedTable, pszEscapedGeomCol,
3595 84 : sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11, sEnvelope.MinY - 1e-11,
3596 84 : sEnvelope.MaxY + 1e-11);
3597 :
3598 84 : return osSpatialWHERE;
3599 : }
3600 :
3601 : /************************************************************************/
3602 : /* FormatSpatialFilterFromMBR() */
3603 : /************************************************************************/
3604 :
3605 : CPLString
3606 6 : OGRSQLiteLayer::FormatSpatialFilterFromMBR(OGRGeometry *poFilterGeom,
3607 : const char *pszEscapedGeomColName)
3608 : {
3609 12 : CPLString osSpatialWHERE;
3610 6 : OGREnvelope sEnvelope;
3611 :
3612 6 : poFilterGeom->getEnvelope(&sEnvelope);
3613 :
3614 6 : if (std::isinf(sEnvelope.MinX) && sEnvelope.MinX < 0 &&
3615 0 : std::isinf(sEnvelope.MinY) && sEnvelope.MinY < 0 &&
3616 0 : std::isinf(sEnvelope.MaxX) && sEnvelope.MaxX > 0 &&
3617 6 : std::isinf(sEnvelope.MaxY) && sEnvelope.MaxY > 0)
3618 0 : return "";
3619 :
3620 : /* A bit inefficient but still faster than OGR filtering */
3621 : osSpatialWHERE.Printf(
3622 : "MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f))",
3623 : pszEscapedGeomColName,
3624 : // Insure that only Decimal.Points are used, never local settings such
3625 : // as Decimal.Comma.
3626 6 : sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11, sEnvelope.MaxX + 1e-11,
3627 6 : sEnvelope.MaxY + 1e-11);
3628 :
3629 6 : return osSpatialWHERE;
3630 : }
3631 :
3632 : /************************************************************************/
3633 : /* OGRSQLiteGetSpatialiteGeometryHeader() */
3634 : /************************************************************************/
3635 :
3636 12 : OGRErr OGRSQLiteGetSpatialiteGeometryHeader(const GByte *pabyData, int nBytes,
3637 : int *pnSRID,
3638 : OGRwkbGeometryType *peType,
3639 : bool *pbIsEmpty, double *pdfMinX,
3640 : double *pdfMinY, double *pdfMaxX,
3641 : double *pdfMaxY)
3642 : {
3643 12 : return OGRSQLiteLayer::GetSpatialiteGeometryHeader(
3644 : pabyData, nBytes, pnSRID, peType, pbIsEmpty, pdfMinX, pdfMinY, pdfMaxX,
3645 12 : pdfMaxY);
3646 : }
3647 :
3648 : /************************************************************************/
3649 : /* OGRSQLiteImportSpatiaLiteGeometry() */
3650 : /************************************************************************/
3651 :
3652 56 : OGRErr OGRSQLiteImportSpatiaLiteGeometry(const GByte *pabyData, int nBytes,
3653 : OGRGeometry **ppoGeometry, int *pnSRID)
3654 : {
3655 56 : return OGRSQLiteLayer::ImportSpatiaLiteGeometry(pabyData, nBytes,
3656 56 : ppoGeometry, pnSRID);
3657 : }
3658 :
3659 : /************************************************************************/
3660 : /* OGRSQLiteExportSpatiaLiteGeometry() */
3661 : /************************************************************************/
3662 :
3663 0 : OGRErr OGRSQLiteExportSpatiaLiteGeometry(const OGRGeometry *poGeometry,
3664 : GInt32 nSRID,
3665 : OGRwkbByteOrder eByteOrder,
3666 : bool bSpatialite2D, bool bUseComprGeom,
3667 : GByte **ppabyData, int *pnDataLength)
3668 : {
3669 0 : return OGRSQLiteLayer::ExportSpatiaLiteGeometry(
3670 : poGeometry, nSRID, eByteOrder, bSpatialite2D, bUseComprGeom, ppabyData,
3671 0 : pnDataLength);
3672 : }
3673 :
3674 : /************************************************************************/
3675 : /* GetDataset() */
3676 : /************************************************************************/
3677 :
3678 46 : GDALDataset *OGRSQLiteLayer::GetDataset()
3679 : {
3680 46 : return m_poDS;
3681 : }
|