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