1 /******************************************************************************
2  * Project:  PROJ.4
3  * Purpose:  Implementation of the projCtx thread context object.
4  * Author:   Frank Warmerdam, warmerdam@pobox.com
5  *
6  ******************************************************************************
7  * Copyright (c) 2010, Frank Warmerdam
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  *****************************************************************************/
27 #ifndef FROM_PROJ_CPP
28 #define FROM_PROJ_CPP
29 #endif
30 
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <new>
36 
37 #include "proj_experimental.h"
38 #include "proj_internal.h"
39 #include "filemanager.hpp"
40 #include "proj/internal/io_internal.hpp"
41 
42 /************************************************************************/
43 /*                             pj_get_ctx()                             */
44 /************************************************************************/
45 
pj_get_ctx(projPJ pj)46 projCtx pj_get_ctx( projPJ pj )
47 
48 {
49     if (nullptr==pj)
50         return pj_get_default_ctx ();
51     if (nullptr==pj->ctx)
52         return pj_get_default_ctx ();
53     return pj->ctx;
54 }
55 
56 /************************************************************************/
57 /*                             pj_set_ctx()                             */
58 /*                                                                      */
59 /*      Note we do not deallocate the old context!                      */
60 /************************************************************************/
61 
pj_set_ctx(projPJ pj,projCtx ctx)62 void pj_set_ctx( projPJ pj, projCtx ctx )
63 
64 {
65     if (pj==nullptr)
66         return;
67     pj->ctx = ctx;
68     if( pj->reassign_context )
69     {
70         pj->reassign_context(pj, ctx);
71     }
72     for( const auto &alt: pj->alternativeCoordinateOperations )
73     {
74         pj_set_ctx(alt.pj, ctx);
75     }
76 }
77 
78 /************************************************************************/
79 /*                        proj_assign_context()                         */
80 /************************************************************************/
81 
82 /** \brief Re-assign a context to a PJ* object.
83  *
84  * This may be useful if the PJ* has been created with a context that is
85  * thread-specific, and is later used in another thread. In that case,
86  * the user may want to assign another thread-specific context to the
87  * object.
88  */
proj_assign_context(PJ * pj,PJ_CONTEXT * ctx)89 void proj_assign_context( PJ* pj, PJ_CONTEXT* ctx )
90 {
91     pj_set_ctx( pj, ctx );
92 }
93 
94 /************************************************************************/
95 /*                          createDefault()                             */
96 /************************************************************************/
97 
createDefault()98 projCtx_t projCtx_t::createDefault()
99 {
100     projCtx_t ctx;
101     ctx.debug_level = PJ_LOG_NONE;
102     ctx.logger = pj_stderr_logger;
103     ctx.fileapi_legacy = pj_get_default_fileapi();
104     NS_PROJ::FileManager::fillDefaultNetworkInterface(&ctx);
105 
106     if( getenv("PROJ_DEBUG") != nullptr )
107     {
108         if( atoi(getenv("PROJ_DEBUG")) >= -PJ_LOG_DEBUG_MINOR )
109             ctx.debug_level = atoi(getenv("PROJ_DEBUG"));
110         else
111             ctx.debug_level = PJ_LOG_DEBUG_MINOR;
112     }
113     return ctx;
114 }
115 
116 /**************************************************************************/
117 /*                           get_cpp_context()                            */
118 /**************************************************************************/
119 
get_cpp_context()120 projCppContext* projCtx_t::get_cpp_context()
121 {
122     if (cpp_context == nullptr) {
123         cpp_context = new projCppContext(this);
124     }
125     return cpp_context;
126 }
127 
128 
129 /**************************************************************************/
130 /*                           safeAutoCloseDbIfNeeded()                      */
131 /**************************************************************************/
132 
safeAutoCloseDbIfNeeded()133 void projCtx_t::safeAutoCloseDbIfNeeded()
134 {
135     if (cpp_context) {
136         cpp_context->autoCloseDbIfNeeded();
137     }
138 }
139 
140 /************************************************************************/
141 /*                           set_search_paths()                         */
142 /************************************************************************/
143 
set_search_paths(const std::vector<std::string> & search_paths_in)144 void projCtx_t::set_search_paths(const std::vector<std::string>& search_paths_in )
145 {
146     search_paths = search_paths_in;
147     delete[] c_compat_paths;
148     c_compat_paths = nullptr;
149     if( !search_paths.empty() ) {
150         c_compat_paths = new const char*[search_paths.size()];
151         for( size_t i = 0; i < search_paths.size(); ++i ) {
152             c_compat_paths[i] = search_paths[i].c_str();
153         }
154     }
155 }
156 
157 /**************************************************************************/
158 /*                           set_ca_bundle_path()                         */
159 /**************************************************************************/
160 
set_ca_bundle_path(const std::string & ca_bundle_path_in)161 void projCtx_t::set_ca_bundle_path(const std::string& ca_bundle_path_in)
162 {
163     ca_bundle_path = ca_bundle_path_in;
164 }
165 
166 /************************************************************************/
167 /*                  projCtx_t(const projCtx_t& other)                   */
168 /************************************************************************/
169 
projCtx_t(const projCtx_t & other)170 projCtx_t::projCtx_t(const projCtx_t& other) :
171     debug_level(other.debug_level),
172     logger(other.logger),
173     logger_app_data(other.logger_app_data),
174     fileapi_legacy(other.fileapi_legacy),
175     cpp_context(other.cpp_context ? other.cpp_context->clone(this) : nullptr),
176     use_proj4_init_rules(other.use_proj4_init_rules),
177     epsg_file_exists(other.epsg_file_exists),
178     ca_bundle_path(other.ca_bundle_path),
179     env_var_proj_lib(other.env_var_proj_lib),
180     file_finder_legacy(other.file_finder_legacy),
181     file_finder(other.file_finder),
182     file_finder_user_data(other.file_finder_user_data),
183     custom_sqlite3_vfs_name(other.custom_sqlite3_vfs_name),
184     user_writable_directory(other.user_writable_directory),
185     // BEGIN ini file settings
186     iniFileLoaded(other.iniFileLoaded),
187     endpoint(other.endpoint),
188     networking(other.networking),
189     gridChunkCache(other.gridChunkCache),
190     defaultTmercAlgo(other.defaultTmercAlgo)
191     // END ini file settings
192 {
193     set_search_paths(other.search_paths);
194 }
195 
196 /************************************************************************/
197 /*                         pj_get_default_ctx()                         */
198 /************************************************************************/
199 
pj_get_default_ctx()200 projCtx pj_get_default_ctx()
201 
202 {
203     // C++11 rules guarantee a thread-safe instantiation.
204     static projCtx_t default_context(projCtx_t::createDefault());
205     return &default_context;
206 }
207 
208 /************************************************************************/
209 /*                            ~projCtx_t()                              */
210 /************************************************************************/
211 
~projCtx_t()212 projCtx_t::~projCtx_t()
213 {
214     delete[] c_compat_paths;
215     proj_context_delete_cpp_context(cpp_context);
216 }
217 
218 /************************************************************************/
219 /*                            pj_ctx_alloc()                            */
220 /************************************************************************/
221 
pj_ctx_alloc()222 projCtx pj_ctx_alloc()
223 
224 {
225     return new (std::nothrow) projCtx_t(*pj_get_default_ctx());
226 }
227 
228 /************************************************************************/
229 /*                            proj_context_clone()                      */
230 /*           Create a new context based on a custom context             */
231 /************************************************************************/
232 
proj_context_clone(PJ_CONTEXT * ctx)233 PJ_CONTEXT *proj_context_clone (PJ_CONTEXT *ctx)
234 {
235     if (nullptr==ctx)
236         return pj_ctx_alloc ();
237 
238     return new (std::nothrow) projCtx_t(*ctx);
239 }
240 
241 /************************************************************************/
242 /*                            pj_ctx_free()                             */
243 /************************************************************************/
244 
pj_ctx_free(projCtx ctx)245 void pj_ctx_free( projCtx ctx )
246 
247 {
248     delete ctx;
249 }
250 
251 /************************************************************************/
252 /*                          pj_ctx_get_errno()                          */
253 /************************************************************************/
254 
pj_ctx_get_errno(projCtx ctx)255 int pj_ctx_get_errno( projCtx ctx )
256 
257 {
258     if (nullptr==ctx)
259         return pj_get_default_ctx ()->last_errno;
260     return ctx->last_errno;
261 }
262 
263 /************************************************************************/
264 /*                          pj_ctx_set_errno()                          */
265 /*                                                                      */
266 /*                      Also sets the global errno                      */
267 /************************************************************************/
268 
pj_ctx_set_errno(projCtx ctx,int new_errno)269 void pj_ctx_set_errno( projCtx ctx, int new_errno )
270 
271 {
272     ctx->last_errno = new_errno;
273     if( new_errno == 0 )
274         return;
275     errno = new_errno;
276     pj_errno = new_errno;
277 }
278 
279 /************************************************************************/
280 /*                          pj_ctx_set_debug()                          */
281 /************************************************************************/
282 
pj_ctx_set_debug(projCtx ctx,int new_debug)283 void pj_ctx_set_debug( projCtx ctx, int new_debug )
284 
285 {
286     if (nullptr==ctx)
287         return;
288     ctx->debug_level = new_debug;
289 }
290 
291 /************************************************************************/
292 /*                         pj_ctx_set_logger()                          */
293 /************************************************************************/
294 
pj_ctx_set_logger(projCtx ctx,void (* new_logger)(void *,int,const char *))295 void pj_ctx_set_logger( projCtx ctx, void (*new_logger)(void*,int,const char*) )
296 
297 {
298     if (nullptr==ctx)
299         return;
300     ctx->logger = new_logger;
301 }
302 
303 /************************************************************************/
304 /*                        pj_ctx_set_app_data()                         */
305 /************************************************************************/
306 
pj_ctx_set_app_data(projCtx ctx,void * new_app_data)307 void pj_ctx_set_app_data( projCtx ctx, void *new_app_data )
308 
309 {
310     if (nullptr==ctx)
311         return;
312     ctx->logger_app_data = new_app_data;
313 }
314 
315 /************************************************************************/
316 /*                        pj_ctx_get_app_data()                         */
317 /************************************************************************/
318 
pj_ctx_get_app_data(projCtx ctx)319 void *pj_ctx_get_app_data( projCtx ctx )
320 
321 {
322     if (nullptr==ctx)
323         return nullptr;
324     return ctx->logger_app_data;
325 }
326