OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimGpkgUtil.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 // File: ossimGpkgUtil.cpp
3 //
4 // License: LGPL
5 //
6 // See LICENSE.txt file in the top level directory for more details.
7 //
8 // Description: OSSIM GeoPackage utility class.
9 //----------------------------------------------------------------------------
10 // $Id$
11 
12 #include "ossimGpkgUtil.h"
16 #include "ossimGpkgTileEntry.h"
17 #include "ossimGpkgTileRecord.h"
21 
22 #include <ossim/base/ossimCommon.h>
23 #include <ossim/base/ossimNotify.h>
24 
25 #include <sqlite3.h>
26 #include <fstream>
27 #include <ostream>
28 #include <sstream>
29 
31 {
32  //---
33  // First 15 bytes should be: "SQLite format 3"
34  // Note the spec says 16 bytes but it doesn't add up.
35  // Samples have '.' at end.
36  //---
37  bool result = false;
38  char SIG[15];
39  in.read(SIG, 15);
40  if ( (SIG[0] == 'S') && (SIG[1] == 'Q') && (SIG[2] == 'L') && (SIG[3] == 'i') &&
41  (SIG[4] == 't') && (SIG[5] == 'e') && (SIG[6] == ' ') && (SIG[7] == 'f') &&
42  (SIG[8] == 'o') && (SIG[9] == 'r') && (SIG[10] == 'm') && (SIG[11] == 'a') &&
43  (SIG[12] == 't') && (SIG[13] == ' ') && (SIG[14] == '3') )
44  {
45  result = true;
46  }
47  return result;
48 }
49 
51 {
52  //---
53  // Check the application_id.
54  // From GeoPackage 1.0:
55  // Requirement 2: Every GeoPackage must contain 0x47503130 ("GP10" in ACII)
56  // in the application id field of the SQLite database header to indicate a
57  // GeoPackage version 1.0 file.
58  // From GeoPackage 1.1:
59  // A GeoPackage SHALL contain 0x47503131 ("GP11" in ASCII) in the application
60  // id field of the SQLite database header to indicate a GeoPackage version 1.1 file.
61  //---
62  bool result = false;
63  char APP_ID[4];
64  in.seekg( 68, std::ios_base::beg );
65  in.read(APP_ID, 4);
66  if ( (APP_ID[0] == 'G') && (APP_ID[1] == 'P') && (APP_ID[2] == '1') &&
67  ( (APP_ID[3] == '0') || (APP_ID[3] == '1') ) )
68  {
69  result = true;
70  }
71  return result;
72 }
73 
74 void ossim_gpkg::getTileEntries( sqlite3* db, std::vector<ossimGpkgTileEntry>& entries )
75 {
76  if ( db )
77  {
78  // Get all the tile matrix sets. Each set can be concidered an entry.
79 
80  std::vector<ossimGpkgTileMatrixSetRecord> sets;
83 
84  if ( sets.size() )
85  {
86  // Get all the tile matrix rows.
87  std::vector<ossimGpkgTileMatrixRecord> levels;
90 
91  // Get all the nsg tile matrix extent rows.
92  std::vector<ossimGpkgNsgTileMatrixExtentRecord> extents;
95 
96  // Get all the srs rows.
97  std::vector<ossimGpkgSpatialRefSysRecord> srs;
100 
101  // For each entry captue the tile matrix and srs that belong to entry.
102  std::vector<ossimGpkgTileMatrixSetRecord>::const_iterator setIdx = sets.begin();
103  while ( setIdx != sets.end() )
104  {
105  ossimGpkgTileEntry entry;
106  entry.setTileMatrixSet(*setIdx);
107 
108  // Add tile matrix objects to entry if table_name matches.
109  std::vector<ossimGpkgTileMatrixRecord>::const_iterator mIdx = levels.begin();
110  while ( mIdx != levels.end() )
111  {
112  if ( entry.getTileMatrixSet().m_table_name == (*mIdx).m_table_name )
113  {
114  // table_name matches...
115  entry.addTileMatrix( (*mIdx) );
116  }
117  ++mIdx;
118  }
119 
120  // Add tile matrix extent objects to entry if table_name matches.
121  std::vector<ossimGpkgNsgTileMatrixExtentRecord>::const_iterator extIdx = extents.begin();
122  while ( extIdx != extents.end() )
123  {
124  if ( entry.getTileMatrixSet().m_table_name == (*extIdx).m_table_name )
125  {
126  // table_name matches...
127  entry.addTileMatrixExtent( (*extIdx) );
128  }
129  ++extIdx;
130  }
131 
132  std::vector<ossimGpkgSpatialRefSysRecord>::const_iterator srsIdx = srs.begin();
133  while ( srsIdx != srs.end() )
134  {
135  if (entry.getTileMatrixSet().m_srs_id == (*srsIdx).m_srs_id)
136  {
137  // srs id matches...
138  entry.setSrs( (*srsIdx) );
139  break;
140  }
141  ++srsIdx;
142  }
143 
144  if ( entry.getTileMatrix().size() )
145  {
146  // The sort call puts the tile matrix entries in highest zoom to lowest order.
147  entry.sortTileMatrix();
148  entry.sortTileMatrixExtents();
149 
150  // Add the entry
151  entries.push_back( entry );
152  }
153  else
154  {
156  << "ossim_gpkg::getTileEntries WARNING No levels found for entry!"
157  << std::endl;
158  }
159 
160  ++setIdx; // Next entry.
161  }
162  }
163 
164  } // Matches: if ( sqlite3* db )
165 
166 } // End: ossim_gpkg::getTileEntries( ... )
167 
168 bool ossim_gpkg::getTileEntry( sqlite3* db,
169  const std::string& tileTableName,
170  ossimGpkgTileEntry& entry )
171 {
172  bool status = false;
173 
174  if ( db )
175  {
176  // Get all the tile matrix set for the tile table name.
179  db, set, ossimGpkgTileMatrixSetRecord::getTableName(), tileTableName ) )
180  {
181  entry.setTileMatrixSet( set );
182 
183  // Get all the tile matrix rows. There's one for each level.
184  std::vector<ossimGpkgTileMatrixRecord> levels;
186  db, levels, ossimGpkgTileMatrixRecord::getTableName(), tileTableName );
187 
188  if ( levels.size() )
189  {
190  // Add tile matrix objects to entry if table_name matches.
191  std::vector<ossimGpkgTileMatrixRecord>::const_iterator mIdx = levels.begin();
192  while ( mIdx != levels.end() )
193  {
194  entry.addTileMatrix( (*mIdx) );
195  ++mIdx;
196  }
197 
198  // Get the GpkgSpatialRefSys. Required or we don't go on.
201  db,
202  set.m_srs_id,
203  srs ) )
204  {
205  entry.setSrs( srs );
206 
207  //---
208  // At this point we can set the status to true. The below nsg
209  // tile matrix extent is not required.
210  //---
211  status = true;
212 
213  // Add tile matrix extent objects to entry if table_name matches.
214 
215  // Get all the nsg tile matrix extent rows.
216  std::vector<ossimGpkgNsgTileMatrixExtentRecord> extents;
218  db,
219  extents,
221  tileTableName );
222  std::vector<ossimGpkgNsgTileMatrixExtentRecord>::const_iterator extIdx =
223  extents.begin();
224  while ( extIdx != extents.end() )
225  {
226  if ( entry.getTileMatrixSet().m_table_name == (*extIdx).m_table_name )
227  {
228  // table_name matches...
229  entry.addTileMatrixExtent( (*extIdx) );
230  }
231  ++extIdx;
232  }
233 
234  if ( entry.getTileMatrix().size() )
235  {
236  // The sort call puts the tile matrix entries in highest zoom to lowest order.
237  entry.sortTileMatrix();
238  }
239  if ( entry.getTileMatrixExtent().size() )
240  {
241  // The sort call puts the tile matrix entries in highest zoom to lowest order.
242  entry.sortTileMatrixExtents();
243 
244  // If we have extents, the size should match the tile matrix size.
245  if ( entry.getTileMatrixExtent().size() != entry.getTileMatrix().size() )
246  {
248  << "ossim_gpkg::getTileEntry WARNING size mismatch between tile matrix"
249  << " and tile matrix extents!\n";
250  }
251  }
252  }
253  else
254  {
256  << "ossim_gpkg::getTileEntry WARNING No gpkg_spatial_ref_sys record found for"
257  << " entry!\n";
258  }
259  }
260  else
261  {
263  << "ossim_gpkg::getTileEntry WARNING No gpkg_tile_matrix records found for entry!"
264  << std::endl;
265  }
266  }
267 
268  } // Matches: if ( sqlite3* db )
269 
270  return status;
271 
272 } // End: ossim_gpkg::getTileEntry( ... )
273 
274 template <class T> void ossim_gpkg::getGpkgRecords( sqlite3* db,
275  std::vector<T>& result,
276  const std::string& dbTableName )
277 {
278  if ( db && dbTableName.size() )
279  {
280  const char *zLeftover; /* Tail of unprocessed SQL */
281  sqlite3_stmt *pStmt = 0; /* The current SQL statement */
282  std::string sql = "SELECT * from ";
283  sql += dbTableName;
284 
285  int rc = sqlite3_prepare_v2(db, // Database handle
286  sql.c_str(), // SQL statement, UTF-8 encoded
287  -1, // Maximum length of zSql in bytes.
288  &pStmt, // OUT: Statement handle
289  &zLeftover); // OUT: Pointer to unused portion of zSql
290  if ( rc == SQLITE_OK )
291  {
292  while( 1 )
293  {
294  // Read the row:
295  rc = sqlite3_step(pStmt);
296  if ( rc == SQLITE_ROW )
297  {
298  T record;
299  ossimGpkgDatabaseRecordBase* gpkgRecPtr =
300  dynamic_cast<ossimGpkgDatabaseRecordBase*>( &record );
301  if ( gpkgRecPtr )
302  {
303  if ( gpkgRecPtr->init( pStmt ) )
304  {
305  result.push_back(record);
306  }
307  else
308  {
310  << "ossim_gpkg::getGpkgRecords init failed!"
311  << std::endl;
312  break;
313  }
314  }
315  else
316  {
317  break;
318  }
319  }
320  else
321  {
322  break;
323  }
324  }
325  }
326  sqlite3_finalize(pStmt);
327  }
328 
329 } // End: ossim_gpkg::getGpkgRecords( db, result, dbTableName )
330 
331 template <class T> void ossim_gpkg::getGpkgRecords( sqlite3* db,
332  std::vector<T>& result,
333  const std::string& dbTableName,
334  const std::string& table_name )
335 {
336  if ( db && dbTableName.size() && table_name.size() )
337  {
338  const char *zLeftover; /* Tail of unprocessed SQL */
339  sqlite3_stmt *pStmt = 0; /* The current SQL statement */
340  std::ostringstream sql;
341  sql << "SELECT * from " << dbTableName
342  << " WHERE table_name == '" << table_name << "'";
343 
344  int rc = sqlite3_prepare_v2(db, // Database handle
345  sql.str().c_str(), // SQL statement, UTF-8 encoded
346  -1, // Maximum length of zSql in bytes.
347  &pStmt, // OUT: Statement handle
348  &zLeftover); // OUT: Pointer to unused portion of zSql
349  if ( rc == SQLITE_OK )
350  {
351  while( 1 )
352  {
353  // Read the row:
354  rc = sqlite3_step(pStmt);
355  if ( rc == SQLITE_ROW )
356  {
357  T record;
358  ossimGpkgDatabaseRecordBase* gpkgRecPtr =
359  dynamic_cast<ossimGpkgDatabaseRecordBase*>( &record );
360  if ( gpkgRecPtr )
361  {
362  if ( gpkgRecPtr->init( pStmt ) )
363  {
364  result.push_back(record);
365  }
366  else
367  {
369  << "ossim_gpkg::getGpkgRecords init failed!"
370  << std::endl;
371  break;
372  }
373  }
374  else
375  {
376  break;
377  }
378  }
379  else
380  {
381  break;
382  }
383  }
384  }
385  sqlite3_finalize(pStmt);
386  }
387 
388 } // End: ossim_gpkg::getGpkgRecords( db, result, dbTableName, table_name )
389 
390 template <class T> bool ossim_gpkg::getGpkgRecord( sqlite3* db,
391  T& result,
392  const std::string& dbTableName,
393  const std::string& table_name )
394 {
395  bool status = false;
396 
397  if ( db && dbTableName.size() && table_name.size() )
398  {
399  const char *zLeftover; /* Tail of unprocessed SQL */
400  sqlite3_stmt *pStmt = 0; /* The current SQL statement */
401  std::ostringstream sql;
402  sql << "SELECT * from " << dbTableName
403  << " WHERE table_name == '" << table_name << "'";
404 
405  int rc = sqlite3_prepare_v2(db, // Database handle
406  sql.str().c_str(), // SQL statement, UTF-8 encoded
407  -1, // Maximum length of zSql in bytes.
408  &pStmt, // OUT: Statement handle
409  &zLeftover); // OUT: Pointer to unused portion of zSql
410  if ( rc == SQLITE_OK )
411  {
412  // Read the row:
413  rc = sqlite3_step(pStmt);
414 
415  if ( rc == SQLITE_ROW )
416  {
417  ossimGpkgDatabaseRecordBase* gpkgRecPtr =
418  dynamic_cast<ossimGpkgDatabaseRecordBase*>( &result );
419  if ( gpkgRecPtr )
420  {
421  status = gpkgRecPtr->init( pStmt );
422  if ( !status )
423  {
425  << "ossim_gpkg::getGpkgRecord init failed!"
426  << std::endl;
427  }
428  }
429  }
430  }
431  sqlite3_finalize(pStmt);
432  }
433 
434  return status;
435 
436 } // End: ossim_gpkg::getGpkgRecord( ... )
437 
438 
439 bool ossim_gpkg::getSrsRecord( sqlite3* db,
440  ossim_int32 srs_id,
442 {
443  bool status = false;
444 
445  if ( db )
446  {
447  const char *zLeftover; /* Tail of unprocessed SQL */
448  sqlite3_stmt *pStmt = 0; /* The current SQL statement */
449  std::ostringstream sql;
450  sql << "SELECT * from " << srs.getTableName()
451  << " WHERE srs_id == " << srs_id;
452 
453  int rc = sqlite3_prepare_v2(db, // Database handle
454  sql.str().c_str(), // SQL statement, UTF-8 encoded
455  -1, // Maximum length of zSql in bytes.
456  &pStmt, // OUT: Statement handle
457  &zLeftover); // OUT: Pointer to unused portion of zSql
458  if ( rc == SQLITE_OK )
459  {
460  // Read the row:
461  rc = sqlite3_step(pStmt);
462  if ( rc == SQLITE_ROW )
463  {
464  ossimGpkgDatabaseRecordBase* gpkgRecPtr =
465  dynamic_cast<ossimGpkgDatabaseRecordBase*>( &srs );
466  if ( gpkgRecPtr )
467  {
468  status = gpkgRecPtr->init( pStmt );
469  if ( !status )
470  {
472  << "ossim_gpkg::getSrsRecord init failed!"
473  << std::endl;
474  }
475  }
476  }
477  }
478  sqlite3_finalize(pStmt);
479  }
480 
481  return status;
482 
483 } // End: ossim_gpkg::getSrsRecord( ... )
484 
486  sqlite3* db,
487  const std::string& tableName,
488  std::vector< ossimRefPtr<ossimGpkgDatabaseRecordBase> >& result )
489 {
490  static const char M[] = "ossim_gpkg::getTableRows";
491 
492  bool status = false;
493 
494  if ( db && tableName.size() )
495  {
496  const char *zLeftover; /* Tail of unprocessed SQL */
497  sqlite3_stmt *pStmt = 0; /* The current SQL statement */
498  std::string sql = "SELECT * from ";
499  sql += tableName;
500 
501  int rc = sqlite3_prepare_v2(db, // Database handle
502  sql.c_str(), // SQL statement, UTF-8 encoded
503  -1, // Maximum length of zSql in bytes.
504  &pStmt, // OUT: Statement handle
505  &zLeftover); // OUT: Pointer to unused portion of zSql
506  if ( rc == SQLITE_OK )
507  {
508  bool initStatus = true;
509 
510  int nCol = sqlite3_column_count( pStmt );
511  if ( nCol )
512  {
513  while( 1 )
514  {
515  // Read the row:
516  rc = sqlite3_step(pStmt);
517  if ( rc == SQLITE_ROW )
518  {
520  if ( row.valid() )
521  {
522  if ( row->init( pStmt ) )
523  {
524  result.push_back(row);
525  }
526  else
527  {
529  << M << " init failed!" << std::endl;
530  initStatus = false;
531  break;
532  }
533  }
534  else
535  {
537  << M << " could not make object for table name: " << tableName
538  << std::endl;
539  initStatus = false;
540  break;
541  }
542  }
543  else
544  {
545  break;
546  }
547  }
548  }
549  if ( initStatus && result.size() )
550  {
551  status = true;
552  }
553  }
554  sqlite3_finalize(pStmt);
555  }
556 
557  return status;
558 
559 } // End: ossim_gpks::getTableRows(...)
560 
562  const std::string& tableName )
563 {
565  if ( tableName == ossimGpkgTileMatrixRecord::getTableName() )
566  {
567  result = new ossimGpkgTileMatrixRecord();
568  }
569  else if ( tableName == ossimGpkgTileMatrixSetRecord::getTableName() )
570  {
571  result = new ossimGpkgTileMatrixSetRecord();
572  }
573  else if ( tableName == ossimGpkgSpatialRefSysRecord::getTableName() )
574  {
575  result = new ossimGpkgSpatialRefSysRecord();
576  }
577  else if ( tableName == ossimGpkgContentsRecord::getTableName() )
578  {
579  result = new ossimGpkgContentsRecord();
580  }
581  else if ( tableName == ossimGpkgNsgTileMatrixExtentRecord::getTableName() )
582  {
583  result = new ossimGpkgNsgTileMatrixExtentRecord();
584  }
585 
586  return result;
587 }
588 
589 std::ostream& ossim_gpkg::printTiles(sqlite3* db, const std::string& tileTableName, std::ostream& out)
590 {
591  if ( db )
592  {
593  const char *zLeftover; /* Tail of unprocessed SQL */
594  sqlite3_stmt *pStmt = 0; /* The current SQL statement */
595  std::string sql = "SELECT * from ";
596  sql += tileTableName;
597 
598  int rc = sqlite3_prepare_v2(db, // Database handle
599  sql.c_str(), // SQL statement, UTF-8 encoded
600  -1, // Maximum length of zSql in bytes.
601  &pStmt, // OUT: Statement handle
602  &zLeftover); // OUT: Pointer to unused portion of zSql
603  if ( rc == SQLITE_OK )
604  {
605  int nCol = sqlite3_column_count( pStmt );
606  if ( nCol )
607  {
608  ossimGpkgTileRecord tile;
609  tile.setCopyTileFlag(false);
610  while( 1 )
611  {
612  // Read the row:
613  rc = sqlite3_step(pStmt);
614  if ( rc == SQLITE_ROW )
615  {
616  if (tile.init( pStmt ) )
617  {
618  out << tile << std::endl;
619  }
620  }
621  else
622  {
623  break;
624  }
625  }
626  }
627  }
628  sqlite3_finalize(pStmt);
629  }
630  return out;
631 }
void addTileMatrixExtent(const ossimGpkgNsgTileMatrixExtentRecord &record)
Adds a tile matrix extent level to array.
static const std::string & getTableName()
Get the table name "gpkg_spatial_ref_sys".
void getTileEntries(sqlite3 *db, std::vector< ossimGpkgTileEntry > &entries)
Gets all the tile entries.
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
bool getSrsRecord(sqlite3 *db, ossim_int32 srs_id, ossimGpkgSpatialRefSysRecord &srs)
Get gpkg_spatial_ref_sys record for srs_it.
bool checkApplicationId(std::istream &in)
Check application_id.
bool valid() const
Definition: ossimRefPtr.h:75
const ossimGpkgTileMatrixSetRecord & getTileMatrixSet() const
static const std::string & getTableName()
Get the table name "gpkg_tile_matrix_set".
static const std::string & getTableName()
Get the table name "gpkg_tile_matrix".
bool init(sqlite3_stmt *pStmt)
Initialize from database.
void setTileMatrixSet(const ossimGpkgTileMatrixSetRecord &set)
Sets the tile matrix set.
bool getTileEntry(sqlite3 *db, const std::string &tileTableName, ossimGpkgTileEntry &entry)
Gets tile entry whos table_name field matches tileTableName.
bool getTableRows(sqlite3 *db, const std::string &tableName, std::vector< ossimRefPtr< ossimGpkgDatabaseRecordBase > > &result)
Parse table rows.
void getGpkgRecords(sqlite3 *db, std::vector< T > &result, const std::string &dbTableName)
Get gpkg records.
bool checkSignature(std::istream &in)
Check signature method.
std::ostream & printTiles(sqlite3 *db, const std::string &tileTableName, std::ostream &out)
void sortTileMatrix()
Sorts the m_tileMatrix by zoom levels with the highest zoom level being at the lowest array index...
void addTileMatrix(const ossimGpkgTileMatrixRecord &level)
Adds a tile matrix level to array.
void sortTileMatrixExtents()
Sorts the m_tileMatrixExtents by zoom levels with the highest zoom level being at the lowest array in...
return status
void setSrs(const ossimGpkgSpatialRefSysRecord &srs)
Sets the spatial ref sys.
std::basic_istream< char > istream
Base class for char input streams.
Definition: ossimIosFwd.h:20
const std::vector< ossimGpkgTileMatrixRecord > & getTileMatrix() const
static const std::string & getTableName()
Get the table name "nsg_tile_matrix_extent".
virtual bool init(sqlite3_stmt *pStmt)=0
Initialize from database.
ossimRefPtr< ossimGpkgDatabaseRecordBase > getNewTableRecord(const std::string &tableName)
Parse gpkg_spatial_ref_sys tables.
bool getGpkgRecord(sqlite3 *db, T &result, const std::string &dbTableName, const std::string &table_name)
Get gpkg record.
void setCopyTileFlag(bool flag)
static const std::string & getTableName()
Get the table name "gpkg_contents".
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
int ossim_int32
const std::vector< ossimGpkgNsgTileMatrixExtentRecord > & getTileMatrixExtent() const