Skip to content

Commit

Permalink
CPLFormFilename()/CPLGetDirname()/CPLGetPath(): make it work with 'vs…
Browse files Browse the repository at this point in the history
…icurl/http://example.com?foo' type of filename, to fix Zarr driver

Fixes OSGeo#9749 (comment)
  • Loading branch information
rouault committed Jul 24, 2024
1 parent c49fc86 commit 83dc7fc
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 11 deletions.
19 changes: 19 additions & 0 deletions autotest/cpp/test_cpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,25 @@ TEST_F(test_cpl, CPLFormFilename)
EXPECT_TRUE(
EQUAL(CPLFormFilename("\\\\$\\c:", "..", nullptr), "\\\\$\\c:/..") ||
EQUAL(CPLFormFilename("\\\\$\\c:", "..", nullptr), "\\\\$\\c:\\.."));
EXPECT_STREQ(
CPLFormFilename("/vsicurl/http://example.com?foo", "bar", nullptr),
"/vsicurl/http://example.com/bar?foo");
}

TEST_F(test_cpl, CPLGetPath)
{
EXPECT_STREQ(CPLGetPath("/foo/bar/"), "/foo/bar");
EXPECT_STREQ(CPLGetPath("/foo/bar"), "/foo");
EXPECT_STREQ(CPLGetPath("/vsicurl/http://example.com/foo/bar?suffix"),
"/vsicurl/http://example.com/foo?suffix");
}

TEST_F(test_cpl, CPLGetDirname)
{
EXPECT_STREQ(CPLGetDirname("/foo/bar/"), "/foo/bar");
EXPECT_STREQ(CPLGetDirname("/foo/bar"), "/foo");
EXPECT_STREQ(CPLGetDirname("/vsicurl/http://example.com/foo/bar?suffix"),
"/vsicurl/http://example.com/foo?suffix");
}

TEST_F(test_cpl, VSIGetDiskFreeSpace)
Expand Down
11 changes: 11 additions & 0 deletions gcore/gdalmultidim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4243,6 +4243,17 @@ GDALMDArray::GetCacheRootGroup(bool bCanCreate,
}

osCacheFilenameOut = osFilename + ".gmac";
if (STARTS_WITH(osFilename.c_str(), "/vsicurl/http"))
{
const auto nPosQuestionMark = osFilename.find('?');
if (nPosQuestionMark != std::string::npos)
{
osCacheFilenameOut =
osFilename.substr(0, nPosQuestionMark)
.append(".gmac")
.append(osFilename.substr(nPosQuestionMark));
}
}
const char *pszProxy = PamGetProxy(osCacheFilenameOut.c_str());
if (pszProxy != nullptr)
osCacheFilenameOut = pszProxy;
Expand Down
76 changes: 65 additions & 11 deletions port/cpl_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ static char *CPLGetStaticResult()
/* CPLFindFilenameStart() */
/************************************************************************/

static int CPLFindFilenameStart(const char *pszFilename)
static int CPLFindFilenameStart(const char *pszFilename, size_t nStart = 0)

{
size_t iFileStart = strlen(pszFilename);
size_t iFileStart = nStart ? nStart : strlen(pszFilename);

for (; iFileStart > 0 && pszFilename[iFileStart - 1] != '/' &&
pszFilename[iFileStart - 1] != '\\';
Expand Down Expand Up @@ -144,7 +144,15 @@ static int CPLFindFilenameStart(const char *pszFilename)
const char *CPLGetPath(const char *pszFilename)

{
const int iFileStart = CPLFindFilenameStart(pszFilename);
size_t nSuffixPos = 0;
if (STARTS_WITH(pszFilename, "/vsicurl/http"))
{
const char *pszQuestionMark = strchr(pszFilename, '?');
if (pszQuestionMark)
nSuffixPos = static_cast<size_t>(pszQuestionMark - pszFilename);
}

const int iFileStart = CPLFindFilenameStart(pszFilename, nSuffixPos);
char *pszStaticResult = CPLGetStaticResult();

if (pszStaticResult == nullptr || iFileStart >= CPL_PATH_BUF_SIZE)
Expand All @@ -166,6 +174,13 @@ const char *CPLGetPath(const char *pszFilename)
pszStaticResult[iFileStart - 1] == '\\'))
pszStaticResult[iFileStart - 1] = '\0';

if (nSuffixPos)
{
if (CPLStrlcat(pszStaticResult, pszFilename + nSuffixPos,
CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE)
return CPLStaticBufferTooSmall(pszStaticResult);
}

return pszStaticResult;
}

Expand Down Expand Up @@ -198,7 +213,15 @@ const char *CPLGetPath(const char *pszFilename)
const char *CPLGetDirname(const char *pszFilename)

{
const int iFileStart = CPLFindFilenameStart(pszFilename);
size_t nSuffixPos = 0;
if (STARTS_WITH(pszFilename, "/vsicurl/http"))
{
const char *pszQuestionMark = strchr(pszFilename, '?');
if (pszQuestionMark)
nSuffixPos = static_cast<size_t>(pszQuestionMark - pszFilename);
}

const int iFileStart = CPLFindFilenameStart(pszFilename, nSuffixPos);
char *pszStaticResult = CPLGetStaticResult();

if (pszStaticResult == nullptr || iFileStart >= CPL_PATH_BUF_SIZE)
Expand All @@ -220,6 +243,13 @@ const char *CPLGetDirname(const char *pszFilename)
pszStaticResult[iFileStart - 1] == '\\'))
pszStaticResult[iFileStart - 1] = '\0';

if (nSuffixPos)
{
if (CPLStrlcat(pszStaticResult, pszFilename + nSuffixPos,
CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE)
return CPLStaticBufferTooSmall(pszStaticResult);
}

return pszStaticResult;
}

Expand Down Expand Up @@ -535,6 +565,19 @@ const char *CPLFormFilename(const char *pszPath, const char *pszBasename,
if (pszPath == nullptr)
pszPath = "";
size_t nLenPath = strlen(pszPath);

size_t nSuffixPos = 0;
if (STARTS_WITH_CI(pszPath, "/vsicurl/http"))
{
const char *pszQuestionMark = strchr(pszPath, '?');
if (pszQuestionMark)
{
nSuffixPos = static_cast<size_t>(pszQuestionMark - pszPath);
nLenPath = nSuffixPos;
}
pszAddedPathSep = "/";
}

if (!CPLIsFilenameRelative(pszPath) && strcmp(pszBasename, "..") == 0)
{
// /a/b + .. --> /a
Expand All @@ -560,25 +603,29 @@ const char *CPLFormFilename(const char *pszPath, const char *pszBasename,
else
{
nLenPath = nLenPathOri;
pszAddedPathSep = VSIGetDirectorySeparator(pszPath);
if (pszAddedPathSep[0] == 0)
pszAddedPathSep = VSIGetDirectorySeparator(pszPath);
}
}
else if (nLenPath > 0 && pszPath[nLenPath - 1] != '/' &&
pszPath[nLenPath - 1] != '\\')
{
pszAddedPathSep = VSIGetDirectorySeparator(pszPath);
if (pszAddedPathSep[0] == 0)
pszAddedPathSep = VSIGetDirectorySeparator(pszPath);
}

if (pszExtension == nullptr)
pszExtension = "";
else if (pszExtension[0] != '.' && strlen(pszExtension) > 0)
pszAddedExtSep = ".";

if (CPLStrlcpy(
pszStaticResult, pszPath,
std::min(nLenPath + 1, static_cast<size_t>(CPL_PATH_BUF_SIZE))) >=
static_cast<size_t>(CPL_PATH_BUF_SIZE) ||
CPLStrlcat(pszStaticResult, pszAddedPathSep, CPL_PATH_BUF_SIZE) >=
if (nLenPath >= static_cast<size_t>(CPL_PATH_BUF_SIZE))
return CPLStaticBufferTooSmall(pszStaticResult);

memcpy(pszStaticResult, pszPath, nLenPath);
pszStaticResult[nLenPath] = 0;

if (CPLStrlcat(pszStaticResult, pszAddedPathSep, CPL_PATH_BUF_SIZE) >=
static_cast<size_t>(CPL_PATH_BUF_SIZE) ||
CPLStrlcat(pszStaticResult, pszBasename, CPL_PATH_BUF_SIZE) >=
static_cast<size_t>(CPL_PATH_BUF_SIZE) ||
Expand All @@ -590,6 +637,13 @@ const char *CPLFormFilename(const char *pszPath, const char *pszBasename,
return CPLStaticBufferTooSmall(pszStaticResult);
}

if (nSuffixPos &&
CPLStrlcat(pszStaticResult, pszPath + nSuffixPos, CPL_PATH_BUF_SIZE) >=
static_cast<size_t>(CPL_PATH_BUF_SIZE))
{
return CPLStaticBufferTooSmall(pszStaticResult);
}

return pszStaticResult;
}

Expand Down

0 comments on commit 83dc7fc

Please sign in to comment.