diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-01-10 21:54:34 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2020-01-11 00:27:49 +0100 |
| commit | f6c424165264eec06af2504800ebfdd5d701efae (patch) | |
| tree | 5512b667a9bd7c751c96990ec32082b8564c916b /src/open_lib.cpp | |
| parent | 90b6685a990b8c4931aafb508853401a89163e78 (diff) | |
| download | PROJ-f6c424165264eec06af2504800ebfdd5d701efae.tar.gz PROJ-f6c424165264eec06af2504800ebfdd5d701efae.zip | |
Use Win32 Unicode APIs and expect all strings to be UTF-8 (fixes #1765)
For backward compatibility, if PROJ_LIB content is found to be not UTF-8 or
pointing to a non existing directory, then an attempt at interpretating it
in the ANSI page encoding is done.
proj_context_set_search_paths() now assumes strings to be in UTF-8, and
functions returning paths will also return values in UTF-8.
Diffstat (limited to 'src/open_lib.cpp')
| -rw-r--r-- | src/open_lib.cpp | 576 |
1 files changed, 0 insertions, 576 deletions
diff --git a/src/open_lib.cpp b/src/open_lib.cpp deleted file mode 100644 index ae387281..00000000 --- a/src/open_lib.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of pj_open_lib(), and pj_set_finder(). These - * provide a standard interface for opening projections support - * data files. - * Author: Gerald Evenden, Frank Warmerdam <warmerdam@pobox.com> - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#define PJ_LIB__ - -#ifndef FROM_PROJ_CPP -#define FROM_PROJ_CPP -#endif - -#include <assert.h> -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "proj/internal/internal.hpp" - -#include "proj_internal.h" -#include "filemanager.hpp" - -static const char * proj_lib_name = -#ifdef PROJ_LIB -PROJ_LIB; -#else -nullptr; -#endif - -using namespace NS_PROJ::internal; - -/************************************************************************/ -/* pj_set_finder() */ -/************************************************************************/ - -void pj_set_finder( const char *(*new_finder)(const char *) ) - -{ - auto ctx = pj_get_default_ctx(); - if( ctx ) { - ctx->file_finder_legacy = new_finder; - } -} - -/************************************************************************/ -/* proj_context_set_file_finder() */ -/************************************************************************/ - -/** \brief Assign a file finder callback to a context. - * - * This callback will be used whenever PROJ must open one of its resource files - * (proj.db database, grids, etc...) - * - * The callback will be called with the context currently in use at the moment - * where it is used (not necessarily the one provided during this call), and - * with the provided user_data (which may be NULL). - * The user_data must remain valid during the whole lifetime of the context. - * - * A finder set on the default context will be inherited by contexts created - * later. - * - * @param ctx PROJ context, or NULL for the default context. - * @param finder Finder callback. May be NULL - * @param user_data User data provided to the finder callback. May be NULL. - * - * @since PROJ 6.0 - */ -void proj_context_set_file_finder(PJ_CONTEXT *ctx, proj_file_finder finder, - void* user_data) -{ - if( !ctx ) - ctx = pj_get_default_ctx(); - if( !ctx ) - return; - ctx->file_finder = finder; - ctx->file_finder_user_data = user_data; -} - -/************************************************************************/ -/* proj_context_set_search_paths() */ -/************************************************************************/ - - -/** \brief Sets search paths. - * - * Those search paths will be used whenever PROJ must open one of its resource files - * (proj.db database, grids, etc...) - * - * If set on the default context, they will be inherited by contexts created - * later. - * - * @param ctx PROJ context, or NULL for the default context. - * @param count_paths Number of paths. 0 if paths == NULL. - * @param paths Paths. May be NULL. - * - * @since PROJ 6.0 - */ -void proj_context_set_search_paths(PJ_CONTEXT *ctx, - int count_paths, - const char* const* paths) -{ - if( !ctx ) - ctx = pj_get_default_ctx(); - if( !ctx ) - return; - try { - std::vector<std::string> vector_of_paths; - for (int i = 0; i < count_paths; i++) - { - vector_of_paths.emplace_back(paths[i]); - } - ctx->set_search_paths(vector_of_paths); - } catch( const std::exception& ) - { - } -} - -/************************************************************************/ -/* pj_set_searchpath() */ -/* */ -/* Path control for callers that can't practically provide */ -/* pj_set_finder() style callbacks. Call with (0,NULL) as args */ -/* to clear the searchpath set. */ -/************************************************************************/ - -void pj_set_searchpath ( int count, const char **path ) -{ - proj_context_set_search_paths( nullptr, count, const_cast<const char* const*>(path) ); -} - -#ifdef _WIN32 -#include <windows.h> -#include <sys/stat.h> -static const char *get_path_from_win32_projlib(const char *name, std::string& out) { - /* Check if proj.db lieves in a share/proj dir parallel to bin/proj.dll */ - /* Based in https://stackoverflow.com/questions/9112893/how-to-get-path-to-executable-in-c-running-on-windows */ - - DWORD path_size = 1024; - - for (;;) { - out.resize(path_size); - memset(&out[0], 0, path_size); - DWORD result = GetModuleFileNameA(nullptr, &out[0], path_size - 1); - DWORD last_error = GetLastError(); - - if (result == 0) { - return nullptr; - } - else if (result == path_size - 1) { - if (ERROR_INSUFFICIENT_BUFFER != last_error) { - return nullptr; - } - path_size = path_size * 2; - } - else { - break; - } - } - // Now remove the program's name. It was (example) "C:\programs\gmt6\bin\gdal_translate.exe" - size_t k = strlen(out.c_str()); - while (k > 0 && out[--k] != '\\') {} - out.resize(k); - - out += "/../share/proj/"; - out += name; - - struct stat fileInfo; - if (stat(out.c_str(), &fileInfo) == 0) // Check if file exists (probably there are simpler ways) - return out.c_str(); - else { - return nullptr; - } -} -#endif - -/************************************************************************/ -/* pj_open_lib_internal() */ -/************************************************************************/ - -#ifdef WIN32 -static const char dir_chars[] = "/\\"; -static const char dirSeparator = ';'; -#else -static const char dir_chars[] = "/"; -static const char dirSeparator = ':'; -#endif - -static bool is_tilde_slash(const char* name) -{ - return *name == '~' && strchr(dir_chars,name[1]); -} - -static bool is_rel_or_absolute_filename(const char *name) -{ - return strchr(dir_chars,*name) - || (*name == '.' && strchr(dir_chars,name[1])) - || (!strncmp(name, "..", 2) && strchr(dir_chars,name[2])) - || (name[0] != '\0' && name[1] == ':' && strchr(dir_chars,name[2])); -} - -static bool ignoreUserWritableDirectory() -{ - // Env var mostly for testing purposes and being independent from - // an existing installation - const char* envVarIgnoreUserWritableDirectory = - getenv("PROJ_IGNORE_USER_WRITABLE_DIRECTORY"); - return envVarIgnoreUserWritableDirectory != nullptr && - envVarIgnoreUserWritableDirectory[0] != '\0'; -} - -static void* -pj_open_lib_internal(projCtx ctx, const char *name, const char *mode, - void* (*open_file)(projCtx, const char*, const char*), - char* out_full_filename, size_t out_full_filename_size) { - try { - std::string fname; - const char *sysname = nullptr; - void* fid = nullptr; - - if( ctx == nullptr ) { - ctx = pj_get_default_ctx(); - } - - if( out_full_filename != nullptr && out_full_filename_size > 0 ) - out_full_filename[0] = '\0'; - - /* check if ~/name */ - if (is_tilde_slash(name)) - if ((sysname = getenv("HOME")) != nullptr) { - fname = sysname; - fname += DIR_CHAR; - fname += name; - sysname = fname.c_str(); - } else - return nullptr; - - /* or fixed path: /name, ./name or ../name or http[s]:// */ - else if (is_rel_or_absolute_filename(name) - || starts_with(name, "http://") - || starts_with(name, "https://")) - sysname = name; - - /* or try to use application provided file finder */ - else if( ctx->file_finder != nullptr && (sysname = ctx->file_finder( ctx, name, ctx->file_finder_user_data )) != nullptr ) - ; - - else if( ctx->file_finder_legacy != nullptr && (sysname = ctx->file_finder_legacy( name )) != nullptr ) - ; - - /* The user has search paths set */ - else if( !ctx->search_paths.empty() ) { - for( const auto& path: ctx->search_paths ) { - try { - fname = path; - fname += DIR_CHAR; - fname += name; - sysname = fname.c_str(); - fid = open_file(ctx, sysname, mode); - } catch( const std::exception& ) - { - } - if( fid ) - break; - } - } - - else if( !ignoreUserWritableDirectory() && - (fid = open_file(ctx, - (pj_context_get_user_writable_directory(ctx, false) + - DIR_CHAR + name).c_str(), mode)) != nullptr ) { - fname = pj_context_get_user_writable_directory(ctx, false); - fname += DIR_CHAR; - fname += name; - sysname = fname.c_str(); - } - - /* if is environment PROJ_LIB defined */ - else if ((sysname = getenv("PROJ_LIB")) != nullptr) { - auto paths = NS_PROJ::internal::split(std::string(sysname), dirSeparator); - for( const auto& path: paths ) { - fname = path; - fname += DIR_CHAR; - fname += name; - sysname = fname.c_str(); - fid = open_file(ctx, sysname, mode); - if( fid ) - break; - } -#ifdef _WIN32 - /* check if it lives in a ../share/proj dir of the proj dll */ - } else if ((sysname = get_path_from_win32_projlib(name, fname)) != nullptr) { -#endif - /* or hardcoded path */ - } else if ((sysname = proj_lib_name) != nullptr) { - fname = sysname; - fname += DIR_CHAR; - fname += name; - sysname = fname.c_str(); - /* just try it bare bones */ - } else { - sysname = name; - } - - assert(sysname); // to make Coverity Scan happy - if ( fid != nullptr || (fid = open_file(ctx, sysname, mode)) != nullptr) - { - if( out_full_filename != nullptr && out_full_filename_size > 0 ) - { - // cppcheck-suppress nullPointer - strncpy(out_full_filename, sysname, out_full_filename_size); - out_full_filename[out_full_filename_size-1] = '\0'; - } - errno = 0; - } - - if( ctx->last_errno == 0 && errno != 0 ) - pj_ctx_set_errno( ctx, errno ); - - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "pj_open_lib(%s): call fopen(%s) - %s", - name, sysname, - fid == nullptr ? "failed" : "succeeded" ); - - return(fid); - } - catch( const std::exception& ) { - - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "pj_open_lib(%s): out of memory", - name ); - - return nullptr; - } -} - -/************************************************************************/ -/* pj_open_file_with_manager() */ -/************************************************************************/ - -static void* pj_open_file_with_manager(projCtx ctx, const char *name, - const char * /* mode */) -{ - return NS_PROJ::FileManager::open(ctx, name).release(); -} - -/************************************************************************/ -/* FileManager::open_resource_file() */ -/************************************************************************/ - -std::unique_ptr<NS_PROJ::File> NS_PROJ::FileManager::open_resource_file( - projCtx ctx, const char *name) -{ - auto file = std::unique_ptr<NS_PROJ::File>( - reinterpret_cast<NS_PROJ::File*>( - pj_open_lib_internal(ctx, name, "rb", - pj_open_file_with_manager, - nullptr, 0))); - if( file == nullptr && - !is_tilde_slash(name) && - !is_rel_or_absolute_filename(name) && - !starts_with(name, "http://") && - !starts_with(name, "https://") && - pj_context_is_network_enabled(ctx) ) { - std::string remote_file(pj_context_get_url_endpoint(ctx)); - if( !remote_file.empty() ) { - if( remote_file.back() != '/' ) { - remote_file += '/'; - } - remote_file += name; - auto pos = remote_file.rfind('.'); - if( pos + 4 == remote_file.size() ) { - remote_file = remote_file.substr(0, pos) + ".tif"; - file = open(ctx, remote_file.c_str()); - if( file ) { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "Using %s", remote_file.c_str() ); - pj_ctx_set_errno( ctx, 0 ); - } - } else { - // For example for resource files like 'alaska' - auto remote_file_tif = remote_file + ".tif"; - file = open(ctx, remote_file_tif.c_str()); - if( file ) { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "Using %s", remote_file_tif.c_str() ); - pj_ctx_set_errno( ctx, 0 ); - } else { - // Init files - file = open(ctx, remote_file.c_str()); - if( file ) { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "Using %s", remote_file.c_str() ); - pj_ctx_set_errno( ctx, 0 ); - } - } - } - } - } - return file; -} - -/************************************************************************/ -/* pj_open_lib() */ -/************************************************************************/ - -#ifndef REMOVE_LEGACY_SUPPORT - -// Used by following legacy function -static void* pj_ctx_fopen_adapter(projCtx ctx, const char *name, const char *mode) -{ - return pj_ctx_fopen(ctx, name, mode); -} - -// Legacy function -PAFile -pj_open_lib(projCtx ctx, const char *name, const char *mode) { - return (PAFile)pj_open_lib_internal(ctx, name, mode, pj_ctx_fopen_adapter, nullptr, 0); -} - -#endif // REMOVE_LEGACY_SUPPORT - -/************************************************************************/ -/* pj_find_file() */ -/************************************************************************/ - - -/** Returns the full filename corresponding to a proj resource file specified - * as a short filename. - * - * @param ctx context. - * @param short_filename short filename (e.g. egm96_15.gtx). Must not be NULL. - * @param out_full_filename output buffer, of size out_full_filename_size, that - * will receive the full filename on success. - * Will be zero-terminated. - * @param out_full_filename_size size of out_full_filename. - * @return 1 if the file was found, 0 otherwise. - */ -int pj_find_file(projCtx ctx, const char *short_filename, - char* out_full_filename, size_t out_full_filename_size) -{ - auto f = reinterpret_cast<NS_PROJ::File*>( - pj_open_lib_internal(ctx, short_filename, "rb", - pj_open_file_with_manager, - out_full_filename, - out_full_filename_size)); - if( f != nullptr ) - { - delete f; - return 1; - } - return 0; -} - -/************************************************************************/ -/* pj_context_get_url_endpoint() */ -/************************************************************************/ - -std::string pj_context_get_url_endpoint(PJ_CONTEXT* ctx) -{ - if( !ctx->endpoint.empty() ) { - return ctx->endpoint; - } - pj_load_ini(ctx); - return ctx->endpoint; -} - -/************************************************************************/ -/* trim() */ -/************************************************************************/ - -static std::string trim(const std::string& s) { - const auto first = s.find_first_not_of(' '); - const auto last = s.find_last_not_of(' '); - if( first == std::string::npos || last == std::string::npos ) { - return std::string(); - } - return s.substr(first, last - first + 1); -} - -/************************************************************************/ -/* pj_load_ini() */ -/************************************************************************/ - -void pj_load_ini(projCtx ctx) -{ - if( ctx->iniFileLoaded ) - return; - - const char* endpoint_from_env = getenv("PROJ_NETWORK_ENDPOINT"); - if( endpoint_from_env && endpoint_from_env[0] != '\0' ) { - ctx->endpoint = endpoint_from_env; - } - - ctx->iniFileLoaded = true; - auto file = std::unique_ptr<NS_PROJ::File>( - reinterpret_cast<NS_PROJ::File*>( - pj_open_lib_internal(ctx, "proj.ini", "rb", - pj_open_file_with_manager, - nullptr, 0))); - if( !file ) - return; - file->seek(0, SEEK_END); - const auto filesize = file->tell(); - if( filesize == 0 || filesize > 100 * 1024U ) - return; - file->seek(0, SEEK_SET); - std::string content; - content.resize(static_cast<size_t>(filesize)); - const auto nread = file->read(&content[0], content.size()); - if( nread != content.size() ) - return; - content += '\n'; - size_t pos = 0; - while( pos != std::string::npos ) { - const auto eol = content.find_first_of("\r\n", pos); - if( eol == std::string::npos ) { - break; - } - - const auto equal = content.find('=', pos); - if( equal < eol ) - { - const auto key = trim(content.substr(pos, equal-pos)); - const auto value = trim(content.substr(equal + 1, - eol - (equal+1))); - if( ctx->endpoint.empty() && key == "cdn_endpoint" ) { - ctx->endpoint = value; - } else if ( key == "network" ) { - const char *enabled = getenv("PROJ_NETWORK"); - if (enabled == nullptr || enabled[0] == '\0') { - ctx->networking.enabled = ci_equal(value, "ON") || - ci_equal(value, "YES") || - ci_equal(value, "TRUE"); - } - } else if ( key == "cache_enabled" ) { - ctx->gridChunkCache.enabled = ci_equal(value, "ON") || - ci_equal(value, "YES") || - ci_equal(value, "TRUE"); - } else if ( key == "cache_size_MB" ) { - const int val = atoi(value.c_str()); - ctx->gridChunkCache.max_size = val > 0 ? - static_cast<long long>(val) * 1024 * 1024 : -1; - } else if ( key == "cache_ttl_sec" ) { - ctx->gridChunkCache.ttl = atoi(value.c_str()); - } - } - - pos = content.find_first_not_of("\r\n", eol); - } -} |
