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