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