1 /*
2 
3     GeoPackage extensions for SpatiaLite / SQLite
4 
5 Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 
7 The contents of this file are subject to the Mozilla Public License Version
8 1.1 (the "License"); you may not use this file except in compliance with
9 the License. You may obtain a copy of the License at
10 http://www.mozilla.org/MPL/
11 
12 Software distributed under the License is distributed on an "AS IS" basis,
13 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 for the specific language governing rights and limitations under the
15 License.
16 
17 The Original Code is GeoPackage Extensions
18 
19 The Initial Developer of the Original Code is Brad Hards (bradh@frogmouth.net)
20 
21 Portions created by the Initial Developer are Copyright (C) 2012-2015
22 the Initial Developer. All Rights Reserved.
23 
24 Contributor(s):
25 
26 Alternatively, the contents of this file may be used under the terms of
27 either the GNU General Public License Version 2 or later (the "GPL"), or
28 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 in which case the provisions of the GPL or the LGPL are applicable instead
30 of those above. If you wish to allow use of your version of this file only
31 under the terms of either the GPL or the LGPL, and not to allow others to
32 use your version of this file under the terms of the MPL, indicate your
33 decision by deleting the provisions above and replace them with the notice
34 and other provisions required by the GPL or the LGPL. If you do not delete
35 the provisions above, a recipient may use your version of this file under
36 the terms of any one of the MPL, the GPL or the LGPL.
37 
38 */
39 
40 #include "spatialite/geopackage.h"
41 #include "geopackage_internal.h"
42 
43 #if defined(_WIN32) && !defined(__MINGW32__)
44 #include "config-msvc.h"
45 #else
46 #include "config.h"
47 #endif
48 
49 #ifdef ENABLE_GEOPACKAGE
50 GEOPACKAGE_PRIVATE void
fnct_gpkgGetNormalRow(sqlite3_context * context,int argc,sqlite3_value ** argv)51 fnct_gpkgGetNormalRow (sqlite3_context * context, int argc,
52 		       sqlite3_value ** argv)
53 {
54 /* SQL function:
55 / gpkgGetNormalRow(tile_table_name, normal_zoom_level, inverted_row_number)
56 /
57 / Gets the normal integer row number for the specified table, normal zoom level
58 / and inverted row number. Raises a SQL exception if no zoom level row record in
59 / tile_matrix_metadata
60 /
61 / Note that this function can also be used to convert from a normal row number
62 / to an inverted row number - this conversion is symmetric.
63 */
64     const unsigned char *table;
65     int zoom_level;
66     int inverted_row_number;
67     int matrix_height;
68     int normal_row_number;
69     char *sql_stmt = NULL;
70     sqlite3 *sqlite = NULL;
71     char *errMsg = NULL;
72     char **results;
73     char *endptr = 0;
74     int rows = 0;
75     int columns = 0;
76     int ret = 0;
77 
78     if (argc == 0)
79 	argc = 0;		/* suppressing stupid compiler warnings */
80 
81     if (sqlite3_value_type (argv[0]) != SQLITE_TEXT)
82       {
83 	  sqlite3_result_error (context,
84 				"gpkgGetNormalRow() error: argument 1 [tile_table_name] is not of the String type",
85 				-1);
86 	  return;
87       }
88     table = sqlite3_value_text (argv[0]);
89 
90     if (sqlite3_value_type (argv[1]) != SQLITE_INTEGER)
91       {
92 	  sqlite3_result_error (context,
93 				"gpkgGetNormalRow() error: argument 2 [normal zoom level] is not of the integer type",
94 				-1);
95 	  return;
96       }
97     zoom_level = sqlite3_value_int (argv[1]);
98 
99     if (sqlite3_value_type (argv[2]) != SQLITE_INTEGER)
100       {
101 	  sqlite3_result_error (context,
102 				"gpkgGetNormalRow() error: argument 3 [inverted_row_number] is not of the integer type",
103 				-1);
104 	  return;
105       }
106     inverted_row_number = sqlite3_value_int (argv[2]);
107 
108     sql_stmt =
109 	sqlite3_mprintf
110 	("SELECT matrix_height FROM gpkg_tile_matrix WHERE table_name = %Q AND zoom_level=%i",
111 	 table, zoom_level);
112 
113     sqlite = sqlite3_context_db_handle (context);
114     ret = sqlite3_get_table (sqlite,
115 			     sql_stmt, &results, &rows, &columns, &errMsg);
116     sqlite3_free (sql_stmt);
117     if (ret != SQLITE_OK)
118       {
119 	  sqlite3_result_error (context, errMsg, -1);
120 	  sqlite3_free (errMsg);
121 	  return;
122       }
123     if (rows != 1)
124       {
125 	  sqlite3_result_error (context,
126 				"gpkgGetNormalRow: tile table or zoom level not found",
127 				-1);
128 	  sqlite3_free_table (results);
129 	  sqlite3_free (errMsg);
130 	  return;
131       }
132     errno = 0;
133     matrix_height = strtol (results[1 * columns + 0], &endptr, 10);
134     if ((endptr == results[1 * columns + 0])
135 	|| (matrix_height < 0)
136 	|| (errno == ERANGE
137 	    && matrix_height == INT_MAX) || (errno != 0 && matrix_height == 0))
138       {
139 	  sqlite3_free_table (results);
140 	  sqlite3_result_error (context,
141 				"gpkgGetNormalRow: could not parse result (corrupt GeoPackage?)",
142 				-1);
143 	  return;
144       }
145     sqlite3_free_table (results);
146     if ((inverted_row_number >= matrix_height) || (inverted_row_number < 0))
147       {
148 	  sqlite3_result_error (context,
149 				"gpkgGetNormalRow: row number outside of matrix height range",
150 				-1);
151 	  return;
152       }
153 
154     normal_row_number = matrix_height - inverted_row_number - 1;
155     sqlite3_result_int (context, normal_row_number);
156 }
157 #endif
158