diff --git a/src/ctx.cpp b/src/ctx.cpp index 4364030578..bc1b6f8a4c 100644 --- a/src/ctx.cpp +++ b/src/ctx.cpp @@ -129,6 +129,7 @@ projCppContext *pj_ctx::get_cpp_context() { /************************************************************************/ void pj_ctx::set_search_paths(const std::vector &search_paths_in) { + lookupedFiles.clear(); search_paths = search_paths_in; delete[] c_compat_paths; c_compat_paths = nullptr; diff --git a/src/filemanager.cpp b/src/filemanager.cpp index 3c6bcef61d..2e3f3d8a26 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -1779,6 +1779,16 @@ NS_PROJ::FileManager::open_resource_file(PJ_CONTEXT *ctx, const char *name, */ int pj_find_file(PJ_CONTEXT *ctx, const char *short_filename, char *out_full_filename, size_t out_full_filename_size) { + const auto iter = ctx->lookupedFiles.find(short_filename); + if (iter != ctx->lookupedFiles.end()) { + if (iter->second.empty()) { + out_full_filename[0] = 0; + return 0; + } + snprintf(out_full_filename, out_full_filename_size, "%s", + iter->second.c_str()); + return 1; + } const bool old_network_enabled = proj_context_is_network_enabled(ctx) != FALSE; if (old_network_enabled) @@ -1787,6 +1797,11 @@ int pj_find_file(PJ_CONTEXT *ctx, const char *short_filename, ctx, short_filename, out_full_filename, out_full_filename_size); if (old_network_enabled) proj_context_set_enable_network(ctx, true); + if (file) { + ctx->lookupedFiles[short_filename] = out_full_filename; + } else { + ctx->lookupedFiles[short_filename] = std::string(); + } return file != nullptr; } diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 1417d00d6f..c83ff3a344 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -12244,25 +12244,35 @@ PROJStringParser::createFromPROJString(const std::string &projString) { if (d->steps_.size() == 1 && d->steps_[0].isInit && !d->steps_[0].inverted) { + auto ctx = d->ctx_ ? d->ctx_ : proj_context_create(); + if (!ctx) { + throw ParsingException("out of memory"); + } + PJContextHolder contextHolder(ctx, ctx != d->ctx_); + // Those used to come from a text init file // We only support them in compatibility mode const std::string &stepName = d->steps_[0].name; if (ci_starts_with(stepName, "epsg:") || ci_starts_with(stepName, "IGNF:")) { - /* We create a new context so as to avoid messing up with the */ - /* errorno of the main context, when trying to find the likely */ - /* missing epsg file */ - auto ctx = proj_context_create(); - if (!ctx) { - throw ParsingException("out of memory"); - } - PJContextHolder contextHolder(ctx, true); - if (d->ctx_) { - ctx->set_search_paths(d->ctx_->search_paths); - ctx->file_finder = d->ctx_->file_finder; - ctx->file_finder_user_data = d->ctx_->file_finder_user_data; - } + struct BackupContextErrno { + PJ_CONTEXT *m_ctxt = nullptr; + int m_last_errno = 0; + + explicit BackupContextErrno(PJ_CONTEXT *ctxtIn) + : m_ctxt(ctxtIn), m_last_errno(m_ctxt->last_errno) { + m_ctxt->debug_level = PJ_LOG_ERROR; + } + + ~BackupContextErrno() { m_ctxt->last_errno = m_last_errno; } + + BackupContextErrno(const BackupContextErrno &) = delete; + BackupContextErrno & + operator=(const BackupContextErrno &) = delete; + }; + + BackupContextErrno backupContextErrno(ctx); bool usePROJ4InitRules = d->usePROJ4InitRules_; if (!usePROJ4InitRules) { @@ -12369,12 +12379,6 @@ PROJStringParser::createFromPROJString(const std::string &projString) { } } - auto ctx = d->ctx_ ? d->ctx_ : proj_context_create(); - if (!ctx) { - throw ParsingException("out of memory"); - } - PJContextHolder contextHolder(ctx, ctx != d->ctx_); - paralist *init = pj_mkparam(("init=" + d->steps_[0].name).c_str()); if (!init) { throw ParsingException("out of memory"); diff --git a/src/proj_internal.h b/src/proj_internal.h index f51337296b..a32eb1d162 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -806,6 +806,9 @@ struct pj_ctx { void *user_data) = nullptr; void *file_finder_user_data = nullptr; + // Cache result of pj_find_file() + std::map lookupedFiles{}; + bool defer_grid_opening = false; // set transiently by pj_obj_create() projFileApiCallbackAndData fileApi{};