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