Skip to content

Commit

Permalink
Add capability to read resource files from the user writable directory
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Jan 8, 2020
1 parent da93fe3 commit 9263e1d
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 102 deletions.
8 changes: 4 additions & 4 deletions cmake/ProjTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ function(proj_add_test_script_sh SH_NAME BIN_USE)
)
if(MSVC)
set_tests_properties( ${testname}
PROPERTIES ENVIRONMENT "PROJ_LIB=${PROJECT_BINARY_DIR}/data\\;${PROJECT_SOURCE_DIR}/data")
PROPERTIES ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data\\;${PROJECT_SOURCE_DIR}/data")
else()
set_tests_properties( ${testname}
PROPERTIES ENVIRONMENT "PROJ_LIB=${PROJECT_BINARY_DIR}/data:${PROJECT_SOURCE_DIR}/data")
PROPERTIES ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data:${PROJECT_SOURCE_DIR}/data")
endif()
endif()

Expand All @@ -51,10 +51,10 @@ function(proj_add_gie_test TESTNAME TESTCASE)

if(MSVC)
set_tests_properties( ${TESTNAME}
PROPERTIES ENVIRONMENT "PROJ_LIB=${PROJECT_BINARY_DIR}/data\\;${PROJECT_SOURCE_DIR}/data")
PROPERTIES ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data\\;${PROJECT_SOURCE_DIR}/data")
else()
set_tests_properties( ${TESTNAME}
PROPERTIES ENVIRONMENT "PROJ_LIB=${PROJECT_BINARY_DIR}/data:${PROJECT_SOURCE_DIR}/data")
PROPERTIES ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data:${PROJECT_SOURCE_DIR}/data")
endif()


Expand Down
13 changes: 13 additions & 0 deletions docs/source/resource_files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,34 @@ The following paths are checked in order:

- For transformation grids that have an explict relative or absolute path,
the directory specified in the grid filename.

- Path resolved by the callback function set with
the :c:func:`proj_context_set_file_finder`. If it is set, the next tests
will not be run.

- Path(s) set with the :c:func:`proj_context_set_search_paths`. If set, the
next tests will not be run.

- The PROJ user writable directory, which is :

* on Windows, ${LOCALAPPDATA}/proj
* on MacOSX, ${HOME}/Library/Logs/proj
* on other platforms (Linux), ${XDG_DATA_HOME}/proj if :envvar:`XDG_DATA_HOME`
is defined. Else ${HOME}/.local/share/proj

- Path(s) set with by the environment variable :envvar:`PROJ_LIB`.
On Linux/MacOSX/Unix, use ``:`` to separate paths. On Windows, ``;``

- On Windows, the *..\\share\\proj\\* and its contents are found automatically
at run-time if the installation respects the build structure. That is, the
binaries and proj.dll are installed under *..\\bin\\*, and resource files
are in *..\\share\\proj\\*.

- A path built into PROJ as its resource installation directory (whose value is
$(pkgdatadir)), for builds using the Makefile build system. Note, however,
that since this is a hard-wired path setting, it only works if the whole
PROJ installation is not moved somewhere else.

- The current directory

When networking capabilities are enabled, either by API with the
Expand Down
1 change: 1 addition & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ pj_cleanup_lock
pj_clear_initcache
pj_compare_datums
pj_context_get_grid_cache_filename(projCtx_t*)
pj_context_get_user_writable_directory(projCtx_t*, bool)
pj_context_is_network_enabled(projCtx_t*)
pj_ctx_alloc
pj_ctx_fclose
Expand Down
11 changes: 11 additions & 0 deletions src/4D_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <math.h>
#include "geodesic.h"
#include "grids.hpp"
#include "filemanager.hpp"

#include "proj/common.hpp"
#include "proj/coordinateoperation.hpp"
Expand Down Expand Up @@ -1450,6 +1451,16 @@ PJ_INFO proj_info (void) {
/* build search path string */
auto ctx = pj_get_default_ctx();
if (!ctx || ctx->search_paths.empty()) {
// Env var mostly for testing purposes and being independent from
// an existing installation
const char* ignoreUserWritableDirectory =
getenv("PROJ_IGNORE_USER_WRITABLE_DIRECTORY");
if( ignoreUserWritableDirectory == nullptr ||
ignoreUserWritableDirectory[0] == '\0' ) {
buf = path_append(buf,
pj_context_get_user_writable_directory(ctx, false).c_str(),
&buf_size);
}
const char *envPROJ_LIB = getenv("PROJ_LIB");
buf = path_append(buf, envPROJ_LIB, &buf_size);
#ifdef PROJ_LIB
Expand Down
77 changes: 45 additions & 32 deletions src/filemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2294,48 +2294,61 @@ static void CreateDirectory(const std::string &path) {

// ---------------------------------------------------------------------------

std::string pj_context_get_grid_cache_filename(PJ_CONTEXT *ctx) {
pj_load_ini(ctx);
if (!ctx->gridChunkCache.filename.empty()) {
return ctx->gridChunkCache.filename;
}
std::string path;
std::string pj_context_get_user_writable_directory(PJ_CONTEXT *ctx,
bool create) {
if (ctx->user_writable_directory.empty()) {
std::string path;
#ifdef _WIN32
std::wstring wPath;
wPath.resize(MAX_PATH);
if (SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, &wPath[0]) ==
S_OK) {
wPath.resize(wcslen(wPath.data()));
path = WStringToUTF8(wPath);
} else {
const char *local_app_data = getenv("LOCALAPPDATA");
if (!local_app_data) {
local_app_data = getenv("TEMP");
std::wstring wPath;
wPath.resize(MAX_PATH);
if (SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0,
&wPath[0]) == S_OK) {
wPath.resize(wcslen(wPath.data()));
path = WStringToUTF8(wPath);
} else {
const char *local_app_data = getenv("LOCALAPPDATA");
if (!local_app_data) {
local_app_data = "c:/users";
local_app_data = getenv("TEMP");
if (!local_app_data) {
local_app_data = "c:/users";
}
}
path = local_app_data;
}
path = local_app_data;
}
#else
const char *xdg_data_home = getenv("XDG_DATA_HOME");
if (xdg_data_home != nullptr) {
path = xdg_data_home;
} else {
const char *home = getenv("HOME");
if (home) {
const char *xdg_data_home = getenv("XDG_DATA_HOME");
if (xdg_data_home != nullptr) {
path = xdg_data_home;
} else {
const char *home = getenv("HOME");
if (home) {
#if defined(__MACH__) && defined(__APPLE__)
path = std::string(home) + "/Library/Logs";
path = std::string(home) + "/Library/Logs";
#else
path = std::string(home) + "/.local/share";
path = std::string(home) + "/.local/share";
#endif
} else {
path = "/tmp";
} else {
path = "/tmp";
}
}
}
#endif
path += "/proj";
CreateDirectory(path);
path += "/proj";
ctx->user_writable_directory = path;
}
if (create) {
CreateDirectory(ctx->user_writable_directory);
}
return ctx->user_writable_directory;
}

// ---------------------------------------------------------------------------

std::string pj_context_get_grid_cache_filename(PJ_CONTEXT *ctx) {
pj_load_ini(ctx);
if (!ctx->gridChunkCache.filename.empty()) {
return ctx->gridChunkCache.filename;
}
const std::string path(pj_context_get_user_writable_directory(ctx, true));
ctx->gridChunkCache.filename = path + "/cache.db";
return ctx->gridChunkCache.filename;
}
Expand Down
8 changes: 4 additions & 4 deletions src/filemanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
#include "proj.h"
#include "proj/util.hpp"

NS_PROJ_START

//! @cond Doxygen_Suppress

NS_PROJ_START

class File;

class FileManager {
Expand Down Expand Up @@ -74,8 +74,8 @@ class File {
const std::string &name() const { return name_; }
};

//! @endcond Doxygen_Suppress

NS_PROJ_END

//! @endcond Doxygen_Suppress

#endif // FILEMANAGER_HPP_INCLUDED
21 changes: 21 additions & 0 deletions src/open_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,16 @@ static bool is_rel_or_absolute_filename(const char *name)
|| (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*),
Expand Down Expand Up @@ -279,6 +289,17 @@ pj_open_lib_internal(projCtx ctx, const char *name, const char *mode,
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);
Expand Down
4 changes: 3 additions & 1 deletion src/proj_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ struct projCtx_t {
bool iniFileLoaded = false;
std::string endpoint{};

std::string user_writable_directory{};
projGridChunkCache gridChunkCache{};

int projStringParserCreateFromPROJStringRecursionCounter = 0; // to avoid potential infinite recursion in PROJStringParser::createFromPROJString()
Expand Down Expand Up @@ -844,8 +845,9 @@ std::string pj_context_get_url_endpoint(PJ_CONTEXT* ctx);

void pj_load_ini(PJ_CONTEXT* ctx);

// For testing purposes
// Exported for testing purposes only
std::string PROJ_DLL pj_context_get_grid_cache_filename(PJ_CONTEXT *ctx);
std::string PROJ_DLL pj_context_get_user_writable_directory(PJ_CONTEXT *ctx, bool create);

/* classic public API */
#include "proj_api.h"
Expand Down
12 changes: 6 additions & 6 deletions test/cli/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ EXTRA_DIST = pj_out27.dist pj_out83.dist td_out.dist \
CMakeLists.txt

testprojinfo-check:
PROJ_LIB=$(PROJ_LIB) $(TESTPROJINFO) $(PROJINFOEXE)
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(TESTPROJINFO) $(PROJINFOEXE)

test27-check:
$(TEST27) $(PROJEXE)
Expand All @@ -36,24 +36,24 @@ test83-check:
$(TEST83) $(PROJEXE)

testvarious-check:
PROJ_LIB=$(PROJ_LIB) $(TESTVARIOUS) $(CS2CSEXE)
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(TESTVARIOUS) $(CS2CSEXE)

testdatumfile-check:
@if [ -f $(PROJ_LIB)/conus -a -f $(PROJ_LIB)/ntv1_can.dat -a -f $(PROJ_LIB)/MD -a -f $(PROJ_LIB)/ntf_r93.gsb -a -f $(PROJ_LIB)/egm96_15.gtx ]; then \
PROJ_LIB=$(PROJ_LIB) $(TESTDATUMFILE) $(CS2CSEXE) ; \
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(TESTDATUMFILE) $(CS2CSEXE) ; \
fi

testign-check:
@if [ -f $(PROJ_LIB)/ntf_r93.gsb ] ; then \
PROJ_LIB=$(PROJ_LIB) $(TESTIGN) $(CS2CSEXE) ; \
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(TESTIGN) $(CS2CSEXE) ; \
fi

testntv2-check:
@if [ -f $(PROJ_LIB)/ntv2_0.gsb -a -f $(PROJ_LIB)/conus -a -f $(PROJ_LIB)/ntv1_can.dat ] ; then \
PROJ_LIB=$(PROJ_LIB) $(TESTNTV2) $(CS2CSEXE) ; \
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(TESTNTV2) $(CS2CSEXE) ; \
fi

testcct-check:
PROJ_LIB=$(PROJ_LIB) $(TESTCCT) $(CCTEXE)
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(TESTCCT) $(CCTEXE)

check-local: testprojinfo-check test27-check test83-check testvarious-check testdatumfile-check testign-check testntv2-check testcct-check
20 changes: 10 additions & 10 deletions test/gie/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,33 @@ EXTRA_DIST = 4D-API_cs2cs-style.gie \
PROJ_LIB ?= ../../data

4D-API-cs2cs-style: 4D-API_cs2cs-style.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

GDA: GDA.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

axisswap: axisswap.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

builtins: builtins.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

deformation: deformation.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

ellipsoid: ellipsoid.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

more_builtins: more_builtins.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

unitconvert: unitconvert.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

DHDN_ETRS89: DHDN_ETRS89.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

geotiff_grids: geotiff_grids.gie
PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<
PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES PROJ_LIB=$(PROJ_LIB) $(GIEEXE) $<

check-local: 4D-API-cs2cs-style GDA axisswap builtins deformation ellipsoid more_builtins unitconvert DHDN_ETRS89 geotiff_grids
Loading

0 comments on commit 9263e1d

Please sign in to comment.