Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GeoPackage Translator
4 : * Purpose: Utility functions for OGR GeoPackage driver.
5 : * Author: Paul Ramsey, pramsey@boundlessgeo.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2013, Paul Ramsey <pramsey@boundlessgeo.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogrgeopackageutility.h"
14 : #include "ogr_p.h"
15 : #include "ogr_wkb.h"
16 : #include "sqlite/ogrsqlitebase.h"
17 : #include <limits>
18 :
19 : /* Requirement 20: A GeoPackage SHALL store feature table geometries */
20 : /* with the basic simple feature geometry types (Geometry, Point, */
21 : /* LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, */
22 : /* GeomCollection) */
23 : /* http://opengis.github.io/geopackage/#geometry_types */
24 2857 : OGRwkbGeometryType GPkgGeometryTypeToWKB(const char *pszGpkgType, bool bHasZ,
25 : bool bHasM)
26 : {
27 : OGRwkbGeometryType oType;
28 :
29 2857 : if (EQUAL("Geometry", pszGpkgType))
30 1858 : oType = wkbUnknown;
31 : /* The 1.0 spec is not completely clear on what should be used... */
32 999 : else if (EQUAL("GeomCollection", pszGpkgType) ||
33 999 : EQUAL("GeometryCollection", pszGpkgType))
34 2 : oType = wkbGeometryCollection;
35 : else
36 : {
37 997 : oType = OGRFromOGCGeomType(pszGpkgType);
38 997 : if (oType == wkbUnknown)
39 3 : oType = wkbNone;
40 : }
41 :
42 2857 : if ((oType != wkbNone) && bHasZ)
43 : {
44 60 : oType = wkbSetZ(oType);
45 : }
46 2857 : if ((oType != wkbNone) && bHasM)
47 : {
48 13 : oType = wkbSetM(oType);
49 : }
50 :
51 2857 : return oType;
52 : }
53 :
54 : /* Requirement 5: The columns of tables in a GeoPackage SHALL only be */
55 : /* declared using one of the data types specified in table GeoPackage */
56 : /* Data Types. */
57 : /* http://opengis.github.io/geopackage/#table_column_data_types */
58 : // return a OGRFieldType value or OFTMaxType + 1
59 3842 : int GPkgFieldToOGR(const char *pszGpkgType, OGRFieldSubType &eSubType,
60 : int &nMaxWidth)
61 : {
62 3842 : eSubType = OFSTNone;
63 3842 : nMaxWidth = 0;
64 :
65 : /* Integer types */
66 3842 : if (STRNCASECMP("INT", pszGpkgType, 3) == 0)
67 : {
68 1131 : if (!EQUAL("INT", pszGpkgType) && !EQUAL("INTEGER", pszGpkgType))
69 : {
70 0 : CPLError(CE_Warning, CPLE_AppDefined,
71 : "Field format '%s' not supported. "
72 : "Interpreted as INT",
73 : pszGpkgType);
74 : }
75 1131 : return OFTInteger64;
76 : }
77 2711 : else if (EQUAL("MEDIUMINT", pszGpkgType))
78 100 : return OFTInteger;
79 2611 : else if (EQUAL("SMALLINT", pszGpkgType))
80 : {
81 16 : eSubType = OFSTInt16;
82 16 : return OFTInteger;
83 : }
84 2595 : else if (EQUAL("TINYINT", pszGpkgType))
85 9 : return OFTInteger; // [-128, 127]
86 2586 : else if (EQUAL("BOOLEAN", pszGpkgType))
87 : {
88 20 : eSubType = OFSTBoolean;
89 20 : return OFTInteger;
90 : }
91 :
92 : /* Real types */
93 2566 : else if (EQUAL("FLOAT", pszGpkgType))
94 : {
95 16 : eSubType = OFSTFloat32;
96 16 : return OFTReal;
97 : }
98 2550 : else if (EQUAL("DOUBLE", pszGpkgType))
99 53 : return OFTReal;
100 2497 : else if (EQUAL("REAL", pszGpkgType))
101 501 : return OFTReal;
102 :
103 : // Only used normally in gpkg_data_column_constraints table, and we
104 : // need this only is reading it through ExecuteSQL()
105 1996 : else if (EQUAL("NUMERIC", pszGpkgType))
106 2 : return OFTReal;
107 :
108 : /* String/binary types */
109 1994 : else if (STRNCASECMP("TEXT", pszGpkgType, 4) == 0)
110 : {
111 1162 : if (pszGpkgType[4] == '(')
112 80 : nMaxWidth = atoi(pszGpkgType + 5);
113 1082 : else if (pszGpkgType[4] != '\0')
114 : {
115 0 : CPLError(CE_Warning, CPLE_AppDefined,
116 : "Field format '%s' not supported. "
117 : "Interpreted as TEXT",
118 : pszGpkgType);
119 : }
120 1162 : return OFTString;
121 : }
122 :
123 832 : else if (STRNCASECMP("BLOB", pszGpkgType, 4) == 0)
124 : {
125 40 : if (pszGpkgType[4] != '(' && pszGpkgType[4] != '\0')
126 : {
127 0 : CPLError(CE_Warning, CPLE_AppDefined,
128 : "Field format '%s' not supported. "
129 : "Interpreted as BLOB",
130 : pszGpkgType);
131 : }
132 40 : return OFTBinary;
133 : }
134 :
135 : /* Date types */
136 792 : else if (EQUAL("DATE", pszGpkgType))
137 53 : return OFTDate;
138 739 : else if (EQUAL("DATETIME", pszGpkgType))
139 64 : return OFTDateTime;
140 :
141 : /* Illegal! */
142 : else
143 : {
144 675 : if (GPkgGeometryTypeToWKB(pszGpkgType, false, false) == wkbNone)
145 : {
146 3 : CPLError(CE_Warning, CPLE_AppDefined,
147 : "Field format '%s' not supported", pszGpkgType);
148 : }
149 675 : return OFTMaxType + 1;
150 : }
151 : }
152 :
153 : /* Requirement 5: The columns of tables in a GeoPackage SHALL only be */
154 : /* declared using one of the data types specified in table GeoPackage */
155 : /* Data Types. */
156 : /* http://opengis.github.io/geopackage/#table_column_data_types */
157 3726 : const char *GPkgFieldFromOGR(OGRFieldType eType, OGRFieldSubType eSubType,
158 : int nMaxWidth)
159 : {
160 3726 : switch (eType)
161 : {
162 876 : case OFTInteger:
163 : {
164 876 : if (eSubType == OFSTBoolean)
165 8 : return "BOOLEAN";
166 868 : else if (eSubType == OFSTInt16)
167 7 : return "SMALLINT";
168 : else
169 861 : return "MEDIUMINT";
170 : }
171 66 : case OFTInteger64:
172 66 : return "INTEGER";
173 119 : case OFTReal:
174 : {
175 119 : if (eSubType == OFSTFloat32)
176 12 : return "FLOAT";
177 : else
178 107 : return "REAL";
179 : }
180 2555 : case OFTString:
181 : {
182 2555 : if (nMaxWidth > 0)
183 49 : return CPLSPrintf("TEXT(%d)", nMaxWidth);
184 : else
185 2506 : return "TEXT";
186 : }
187 14 : case OFTBinary:
188 14 : return "BLOB";
189 38 : case OFTDate:
190 38 : return "DATE";
191 53 : case OFTDateTime:
192 53 : return "DATETIME";
193 5 : default:
194 5 : return "TEXT";
195 : }
196 : }
197 :
198 : /* Requirement 19: A GeoPackage SHALL store feature table geometries
199 : * with or without optional elevation (Z) and/or measure (M) values in SQL
200 : * BLOBs using the Standard GeoPackageBinary format specified in table
201 : * GeoPackage SQL Geometry Binary Format and clause Geometry Encoding.
202 : *
203 : * http://opengis.github.io/geopackage/#gpb_format
204 : *
205 : * GeoPackageBinaryHeader {
206 : * byte[2] magic = 0x4750;
207 : * byte version;
208 : * byte flags;
209 : * int32 srs_id;
210 : * double[] envelope;
211 : * }
212 : *
213 : * StandardGeoPackageBinary {
214 : * GeoPackageBinaryHeader header;
215 : * WKBGeometry geometry;
216 : * }
217 : *
218 : * Flags byte contents:
219 : * Bit 7: Reserved for future
220 : * Bit 6: Reserved for future
221 : * Bit 5: Using Extended GPKG Binary?
222 : * Bit 4: Geometry is Empty?
223 : * Bit 3,2,1: Envelope contents (0 none, 1=X/Y, 2=X/Y/Z, 3=X/Y/M, 4=X/Y/Z/M)
224 : * Bit 0: Byte order of header (0=big/XDR, 1=little/NDR)
225 : *
226 : */
227 :
228 251690 : GByte *GPkgGeometryFromOGR(const OGRGeometry *poGeometry, int iSrsId,
229 : const OGRGeomCoordinateBinaryPrecision *psPrecision,
230 : size_t *pnWkbLen)
231 : {
232 251690 : CPLAssert(poGeometry != nullptr);
233 :
234 251690 : GByte byFlags = 0;
235 251690 : GByte byEnv = 1;
236 251690 : OGRwkbExportOptions wkbExportOptions;
237 251690 : if (psPrecision)
238 251688 : wkbExportOptions.sPrecision = *psPrecision;
239 251690 : wkbExportOptions.eByteOrder = static_cast<OGRwkbByteOrder>(CPL_IS_LSB);
240 : OGRErr err;
241 251690 : OGRBoolean bPoint = (wkbFlatten(poGeometry->getGeometryType()) == wkbPoint);
242 251690 : OGRBoolean bEmpty = poGeometry->IsEmpty();
243 : /* We voluntarily use getCoordinateDimension() so as to get only 2 for
244 : * XY/XYM */
245 : /* and 3 for XYZ/XYZM as we currently don't write envelopes with M extent.
246 : */
247 251690 : int iDims = poGeometry->getCoordinateDimension();
248 :
249 : /* Header has 8 bytes for sure, and optional extra space for bounds */
250 251690 : size_t nHeaderLen = 2 + 1 + 1 + 4;
251 251690 : if (!bPoint && !bEmpty)
252 : {
253 3220 : nHeaderLen += 8 * 2 * iDims;
254 : }
255 :
256 : /* Total BLOB size is header + WKB size */
257 251690 : size_t nWkbLen = nHeaderLen + poGeometry->WkbSize();
258 251690 : if (nWkbLen > static_cast<size_t>(std::numeric_limits<int>::max()))
259 : {
260 0 : CPLError(CE_Failure, CPLE_NotSupported, "too big geometry blob");
261 0 : return nullptr;
262 : }
263 251690 : GByte *pabyWkb = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nWkbLen));
264 251690 : if (!pabyWkb)
265 0 : return nullptr;
266 251690 : if (pnWkbLen)
267 251690 : *pnWkbLen = nWkbLen;
268 :
269 : /* Header Magic */
270 251690 : pabyWkb[0] = 0x47;
271 251690 : pabyWkb[1] = 0x50;
272 :
273 : /* GPKG BLOB Version */
274 251690 : pabyWkb[2] = 0;
275 :
276 : /* Extended? No. */
277 :
278 : /* Envelope dimensionality? */
279 :
280 : /* Don't write envelope for point type */
281 251690 : if (bPoint)
282 248453 : byEnv = 0;
283 : else
284 : /* 3D envelope for 3D data */
285 3237 : if (iDims == 3)
286 29 : byEnv = 2;
287 : /* 2D envelope otherwise */
288 : else
289 3208 : byEnv = 1;
290 :
291 : /* Empty? No envelope then. */
292 251690 : if (bEmpty)
293 : {
294 1027 : byEnv = 0;
295 : /* Set empty flag */
296 1027 : byFlags |= (1 << 4);
297 : }
298 :
299 : /* Set envelope flags */
300 251690 : byFlags |= (byEnv << 1);
301 :
302 : /* Byte order of header? */
303 : /* Use native endianness */
304 251690 : byFlags |= wkbExportOptions.eByteOrder;
305 :
306 : /* Write flags byte */
307 251690 : pabyWkb[3] = byFlags;
308 :
309 : /* Write srs_id */
310 251690 : memcpy(pabyWkb + 4, &iSrsId, 4);
311 :
312 : /* Write envelope */
313 251690 : if (!bEmpty && !bPoint)
314 : {
315 3220 : double *padPtr = reinterpret_cast<double *>(pabyWkb + 8);
316 3220 : if (iDims == 3)
317 : {
318 29 : OGREnvelope3D oEnv3d;
319 29 : poGeometry->getEnvelope(&oEnv3d);
320 29 : padPtr[0] = oEnv3d.MinX;
321 29 : padPtr[1] = oEnv3d.MaxX;
322 29 : padPtr[2] = oEnv3d.MinY;
323 29 : padPtr[3] = oEnv3d.MaxY;
324 29 : padPtr[4] = oEnv3d.MinZ;
325 29 : padPtr[5] = oEnv3d.MaxZ;
326 : }
327 : else
328 : {
329 3191 : OGREnvelope oEnv;
330 3191 : poGeometry->getEnvelope(&oEnv);
331 3191 : padPtr[0] = oEnv.MinX;
332 3191 : padPtr[1] = oEnv.MaxX;
333 3191 : padPtr[2] = oEnv.MinY;
334 3191 : padPtr[3] = oEnv.MaxY;
335 : }
336 : }
337 :
338 251690 : GByte *pabyPtr = pabyWkb + nHeaderLen;
339 :
340 : /* Use the wkbVariantIso for ISO SQL/MM output (differs for 3d geometry) */
341 251690 : wkbExportOptions.eWkbVariant = wkbVariantIso;
342 251690 : err = poGeometry->exportToWkb(pabyPtr, &wkbExportOptions);
343 251690 : if (err != OGRERR_NONE)
344 : {
345 0 : CPLFree(pabyWkb);
346 0 : return nullptr;
347 : }
348 :
349 251690 : return pabyWkb;
350 : }
351 :
352 1314850 : OGRErr GPkgHeaderFromWKB(const GByte *pabyGpkg, size_t nGpkgLen,
353 : GPkgHeader *poHeader)
354 : {
355 1314850 : CPLAssert(pabyGpkg != nullptr);
356 1314850 : CPLAssert(poHeader != nullptr);
357 :
358 : /* Magic (match required) */
359 1314850 : if (nGpkgLen < 8 || pabyGpkg[0] != 0x47 || pabyGpkg[1] != 0x50 ||
360 1314780 : pabyGpkg[2] != 0) /* Version (only 0 supported at this time)*/
361 : {
362 67 : memset(poHeader, 0, sizeof(*poHeader));
363 67 : return OGRERR_FAILURE;
364 : }
365 :
366 : /* Flags */
367 1314780 : GByte byFlags = pabyGpkg[3];
368 1314780 : poHeader->bEmpty = (byFlags & (0x01 << 4)) >> 4;
369 1314780 : poHeader->bExtended = (byFlags & (0x01 << 5)) >> 5;
370 1314780 : poHeader->eByteOrder = static_cast<OGRwkbByteOrder>(byFlags & 0x01);
371 1314780 : poHeader->bExtentHasXY = false;
372 1314780 : poHeader->bExtentHasZ = false;
373 : #ifdef notdef
374 : poHeader->bExtentHasM = false;
375 : #endif
376 1314780 : OGRBoolean bSwap = OGR_SWAP(poHeader->eByteOrder);
377 :
378 : /* Envelope */
379 1314780 : int iEnvelope = (byFlags & (0x07 << 1)) >> 1;
380 1314780 : int nEnvelopeDim = 0;
381 1314780 : if (iEnvelope)
382 : {
383 19104 : poHeader->bExtentHasXY = true;
384 19104 : if (iEnvelope == 1)
385 : {
386 18925 : nEnvelopeDim = 2; /* 2D envelope */
387 : }
388 179 : else if (iEnvelope == 2)
389 : {
390 165 : poHeader->bExtentHasZ = true;
391 165 : nEnvelopeDim = 3; /* 2D+Z envelope */
392 : }
393 14 : else if (iEnvelope == 3)
394 : {
395 : #ifdef notdef
396 : poHeader->bExtentHasM = true;
397 : #endif
398 7 : nEnvelopeDim = 3; /* 2D+M envelope */
399 : }
400 7 : else if (iEnvelope == 4)
401 : {
402 7 : poHeader->bExtentHasZ = true;
403 : #ifdef notdef
404 : poHeader->bExtentHasM = true;
405 : #endif
406 7 : nEnvelopeDim = 4; /* 2D+ZM envelope */
407 : }
408 : else
409 : {
410 0 : return OGRERR_FAILURE;
411 : }
412 : }
413 :
414 : /* SrsId */
415 1314780 : int iSrsId = 0;
416 1314780 : memcpy(&iSrsId, pabyGpkg + 4, 4);
417 1314780 : if (bSwap)
418 : {
419 0 : iSrsId = CPL_SWAP32(iSrsId);
420 : }
421 1314780 : poHeader->iSrsId = iSrsId;
422 :
423 1314780 : if (nGpkgLen < static_cast<size_t>(8 + 8 * 2 * nEnvelopeDim))
424 : {
425 : // Not enough bytes
426 0 : return OGRERR_FAILURE;
427 : }
428 :
429 : /* Envelope */
430 1314780 : const double *padPtr = reinterpret_cast<const double *>(pabyGpkg + 8);
431 1314780 : if (poHeader->bExtentHasXY)
432 : {
433 19104 : poHeader->MinX = padPtr[0];
434 19104 : poHeader->MaxX = padPtr[1];
435 19104 : poHeader->MinY = padPtr[2];
436 19104 : poHeader->MaxY = padPtr[3];
437 19104 : if (bSwap)
438 : {
439 0 : CPL_SWAPDOUBLE(&(poHeader->MinX));
440 0 : CPL_SWAPDOUBLE(&(poHeader->MaxX));
441 0 : CPL_SWAPDOUBLE(&(poHeader->MinY));
442 0 : CPL_SWAPDOUBLE(&(poHeader->MaxY));
443 : }
444 : }
445 1314780 : if (poHeader->bExtentHasZ)
446 : {
447 172 : poHeader->MinZ = padPtr[4];
448 172 : poHeader->MaxZ = padPtr[5];
449 172 : if (bSwap)
450 : {
451 0 : CPL_SWAPDOUBLE(&(poHeader->MinZ));
452 0 : CPL_SWAPDOUBLE(&(poHeader->MaxZ));
453 : }
454 : }
455 : #ifdef notdef
456 : if (poHeader->bExtentHasM)
457 : {
458 : poHeader->MinM = padPtr[(poHeader->bExtentHasZ) ? 6 : 4];
459 : poHeader->MaxM = padPtr[(poHeader->bExtentHasZ) ? 7 : 5];
460 : if (bSwap)
461 : {
462 : CPL_SWAPDOUBLE(&(poHeader->MinM));
463 : CPL_SWAPDOUBLE(&(poHeader->MaxM));
464 : }
465 : }
466 : #endif
467 :
468 : /* Header size in byte stream */
469 1314780 : poHeader->nHeaderLen = 8 + 8 * 2 * nEnvelopeDim;
470 :
471 1314780 : return OGRERR_NONE;
472 : }
473 :
474 26 : bool GPkgUpdateHeader(GByte *pabyGpkg, size_t nGpkgLen, int nSrsId, double MinX,
475 : double MaxX, double MinY, double MaxY, double MinZ,
476 : double MaxZ)
477 : {
478 26 : CPLAssert(nGpkgLen >= 8);
479 :
480 : /* Flags */
481 26 : const GByte byFlags = pabyGpkg[3];
482 26 : const auto eByteOrder = static_cast<OGRwkbByteOrder>(byFlags & 0x01);
483 26 : const OGRBoolean bSwap = OGR_SWAP(eByteOrder);
484 :
485 : /* SrsId */
486 26 : if (bSwap)
487 : {
488 0 : nSrsId = CPL_SWAP32(nSrsId);
489 : }
490 26 : memcpy(pabyGpkg + 4, &nSrsId, 4);
491 :
492 : /* Envelope */
493 26 : const int iEnvelope = (byFlags & (0x07 << 1)) >> 1;
494 26 : int nEnvelopeDim = 0;
495 26 : if (iEnvelope)
496 : {
497 23 : if (iEnvelope == 1)
498 : {
499 23 : nEnvelopeDim = 2; /* 2D envelope */
500 : }
501 0 : else if (iEnvelope == 2)
502 : {
503 0 : nEnvelopeDim = 3; /* 2D+Z envelope */
504 : }
505 0 : else if (iEnvelope == 3)
506 : {
507 0 : nEnvelopeDim = 3; /* 2D+M envelope */
508 : }
509 0 : else if (iEnvelope == 4)
510 : {
511 0 : nEnvelopeDim = 4; /* 2D+ZM envelope */
512 : }
513 : else
514 : {
515 0 : return false;
516 : }
517 : }
518 : else
519 : {
520 3 : return true;
521 : }
522 :
523 23 : if (nGpkgLen < static_cast<size_t>(8 + 8 * 2 * nEnvelopeDim))
524 : {
525 : // Not enough bytes
526 0 : return false;
527 : }
528 :
529 : /* Envelope */
530 23 : if (bSwap)
531 : {
532 0 : CPL_SWAPDOUBLE(&(MinX));
533 0 : CPL_SWAPDOUBLE(&(MaxX));
534 0 : CPL_SWAPDOUBLE(&(MinY));
535 0 : CPL_SWAPDOUBLE(&(MaxY));
536 0 : CPL_SWAPDOUBLE(&(MinZ));
537 0 : CPL_SWAPDOUBLE(&(MaxZ));
538 : }
539 :
540 23 : double *padPtr = reinterpret_cast<double *>(pabyGpkg + 8);
541 23 : memcpy(&padPtr[0], &MinX, sizeof(double));
542 23 : memcpy(&padPtr[1], &MaxX, sizeof(double));
543 23 : memcpy(&padPtr[2], &MinY, sizeof(double));
544 23 : memcpy(&padPtr[3], &MaxY, sizeof(double));
545 :
546 23 : if (iEnvelope == 2 || iEnvelope == 4)
547 : {
548 0 : memcpy(&padPtr[4], &MinZ, sizeof(double));
549 0 : memcpy(&padPtr[5], &MaxZ, sizeof(double));
550 : }
551 :
552 23 : return true;
553 : }
554 :
555 11984 : OGRGeometry *GPkgGeometryToOGR(const GByte *pabyGpkg, size_t nGpkgLen,
556 : OGRSpatialReference *poSrs)
557 : {
558 11984 : CPLAssert(pabyGpkg != nullptr);
559 :
560 : GPkgHeader oHeader;
561 :
562 : /* Read header */
563 11984 : OGRErr err = GPkgHeaderFromWKB(pabyGpkg, nGpkgLen, &oHeader);
564 11984 : if (err != OGRERR_NONE)
565 3 : return nullptr;
566 :
567 : /* WKB pointer */
568 11981 : const GByte *pabyWkb = pabyGpkg + oHeader.nHeaderLen;
569 11981 : size_t nWkbLen = nGpkgLen - oHeader.nHeaderLen;
570 :
571 : /* Parse WKB */
572 11981 : OGRGeometry *poGeom = nullptr;
573 11981 : err = OGRGeometryFactory::createFromWkb(pabyWkb, poSrs, &poGeom,
574 : static_cast<int>(nWkbLen));
575 11981 : if (err != OGRERR_NONE)
576 0 : return nullptr;
577 :
578 11981 : return poGeom;
579 : }
580 :
581 : /************************************************************************/
582 : /* OGRGeoPackageGetHeader() */
583 : /************************************************************************/
584 :
585 1237010 : bool OGRGeoPackageGetHeader(sqlite3_context * /*pContext*/, int /*argc*/,
586 : sqlite3_value **argv, GPkgHeader *psHeader,
587 : bool bNeedExtent, bool bNeedExtent3D, int iGeomIdx)
588 : {
589 :
590 : // Extent3D implies extent
591 1237010 : const bool bNeedAnyExtent{bNeedExtent || bNeedExtent3D};
592 :
593 1237010 : if (sqlite3_value_type(argv[iGeomIdx]) != SQLITE_BLOB)
594 : {
595 8 : memset(psHeader, 0, sizeof(*psHeader));
596 8 : return false;
597 : }
598 1237000 : const int nBLOBLen = sqlite3_value_bytes(argv[iGeomIdx]);
599 : const GByte *pabyBLOB =
600 1237000 : reinterpret_cast<const GByte *>(sqlite3_value_blob(argv[iGeomIdx]));
601 :
602 1237000 : if (nBLOBLen < 8)
603 : {
604 6 : memset(psHeader, 0, sizeof(*psHeader));
605 6 : return false;
606 : }
607 1236990 : else if (GPkgHeaderFromWKB(pabyBLOB, nBLOBLen, psHeader) != OGRERR_NONE)
608 : {
609 10 : bool bEmpty = false;
610 10 : memset(psHeader, 0, sizeof(*psHeader));
611 10 : if (OGRSQLiteGetSpatialiteGeometryHeader(
612 : pabyBLOB, nBLOBLen, &(psHeader->iSrsId), nullptr, &bEmpty,
613 : &(psHeader->MinX), &(psHeader->MinY), &(psHeader->MaxX),
614 10 : &(psHeader->MaxY)) == OGRERR_NONE)
615 : {
616 9 : psHeader->bEmpty = bEmpty;
617 9 : psHeader->bExtentHasXY = !bEmpty;
618 9 : if (!bNeedExtent3D && !(bEmpty && bNeedAnyExtent))
619 9 : return true;
620 : }
621 :
622 1 : return false;
623 : }
624 :
625 1236980 : if (psHeader->bEmpty && bNeedAnyExtent)
626 : {
627 1 : return false;
628 : }
629 1236980 : else if (!psHeader->bExtentHasXY && bNeedExtent && !bNeedExtent3D)
630 : {
631 957689 : OGREnvelope sEnvelope;
632 957689 : if (OGRWKBGetBoundingBox(pabyBLOB + psHeader->nHeaderLen,
633 957689 : static_cast<size_t>(nBLOBLen) -
634 957689 : psHeader->nHeaderLen,
635 : sEnvelope))
636 : {
637 957689 : psHeader->MinX = sEnvelope.MinX;
638 957689 : psHeader->MaxX = sEnvelope.MaxX;
639 957689 : psHeader->MinY = sEnvelope.MinY;
640 957689 : psHeader->MaxY = sEnvelope.MaxY;
641 957689 : return true;
642 : }
643 0 : return false;
644 : }
645 279294 : else if (!psHeader->bExtentHasZ && bNeedExtent3D)
646 : {
647 17 : OGREnvelope3D sEnvelope3D;
648 17 : if (OGRWKBGetBoundingBox(pabyBLOB + psHeader->nHeaderLen,
649 17 : static_cast<size_t>(nBLOBLen) -
650 17 : psHeader->nHeaderLen,
651 : sEnvelope3D))
652 : {
653 17 : psHeader->MinX = sEnvelope3D.MinX;
654 17 : psHeader->MaxX = sEnvelope3D.MaxX;
655 17 : psHeader->MinY = sEnvelope3D.MinY;
656 17 : psHeader->MaxY = sEnvelope3D.MaxY;
657 17 : psHeader->MinZ = sEnvelope3D.MinZ;
658 17 : psHeader->MaxZ = sEnvelope3D.MaxZ;
659 17 : return true;
660 : }
661 0 : return false;
662 : }
663 279277 : return true;
664 : }
|