aboutsummaryrefslogtreecommitdiff
path: root/src/open_lib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/open_lib.cpp')
-rw-r--r--src/open_lib.cpp219
1 files changed, 194 insertions, 25 deletions
diff --git a/src/open_lib.cpp b/src/open_lib.cpp
index 24c31033..cde5be7b 100644
--- a/src/open_lib.cpp
+++ b/src/open_lib.cpp
@@ -44,6 +44,7 @@
#include "proj/internal/internal.hpp"
#include "proj_internal.h"
+#include "filemanager.hpp"
static const char * proj_lib_name =
#ifdef PROJ_LIB
@@ -52,6 +53,8 @@ PROJ_LIB;
nullptr;
#endif
+using namespace NS_PROJ::internal;
+
/************************************************************************/
/* pj_set_finder() */
/************************************************************************/
@@ -197,24 +200,39 @@ static const char *get_path_from_win32_projlib(const char *name, std::string& ou
#endif
/************************************************************************/
-/* pj_open_lib_ex() */
+/* pj_open_lib_internal() */
/************************************************************************/
-static PAFile
-pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
- char* out_full_filename, size_t out_full_filename_size) {
- try {
- std::string fname;
- const char *sysname = nullptr;
- PAFile fid = nullptr;
#ifdef WIN32
- static const char dir_chars[] = "/\\";
- const char dirSeparator = ';';
+static const char dir_chars[] = "/\\";
+static const char dirSeparator = ';';
#else
- static const char dir_chars[] = "/";
- const char dirSeparator = ':';
+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 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();
}
@@ -223,7 +241,7 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
out_full_filename[0] = '\0';
/* check if ~/name */
- if (*name == '~' && strchr(dir_chars,name[1]) )
+ if (is_tilde_slash(name))
if ((sysname = getenv("HOME")) != nullptr) {
fname = sysname;
fname += DIR_CHAR;
@@ -232,11 +250,10 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
} else
return nullptr;
- /* or fixed path: /name, ./name or ../name */
- else if (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])) )
+ /* 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 */
@@ -254,7 +271,7 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
fname += DIR_CHAR;
fname += name;
sysname = fname.c_str();
- fid = pj_ctx_fopen(ctx, sysname, mode);
+ fid = open_file(ctx, sysname, mode);
} catch( const std::exception& )
{
}
@@ -270,7 +287,7 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
fname += DIR_CHAR;
fname += name;
sysname = fname.c_str();
- fid = pj_ctx_fopen(ctx, sysname, mode);
+ fid = open_file(ctx, sysname, mode);
if( fid )
break;
}
@@ -290,7 +307,7 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
}
assert(sysname); // to make Coverity Scan happy
- if ( fid != nullptr || (fid = pj_ctx_fopen(ctx, sysname, mode)) != nullptr)
+ if ( fid != nullptr || (fid = open_file(ctx, sysname, mode)) != nullptr)
{
if( out_full_filename != nullptr && out_full_filename_size > 0 )
{
@@ -322,18 +339,79 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode,
}
/************************************************************************/
+/* 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 );
+ }
+ }
+ }
+ }
+ 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 pj_open_lib_ex(ctx, name, mode, nullptr, 0);
+ 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.
*
@@ -348,12 +426,103 @@ pj_open_lib(projCtx ctx, const char *name, const char *mode) {
int pj_find_file(projCtx ctx, const char *short_filename,
char* out_full_filename, size_t out_full_filename_size)
{
- PAFile f = pj_open_lib_ex(ctx, short_filename, "rb", out_full_filename,
- 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 )
{
- pj_ctx_fclose(ctx, f);
+ 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");
+ }
+ }
+ }
+
+ pos = content.find_first_not_of("\r\n", eol);
+ }
+}