📄 path.c
字号:
return FALSE;
}
else if (! uri_char_validity[((unsigned char)path[i])])
{
return FALSE;
}
}
return TRUE;
}
/* URI-encode each character c in PATH for which TABLE[c] is 0.
If no encoding was needed, return PATH, else return a new string allocated
in POOL. */
static const char *
uri_escape (const char *path, const int table[], apr_pool_t *pool)
{
svn_stringbuf_t *retstr;
apr_size_t i, copied = 0;
int c;
retstr = svn_stringbuf_create ("", pool);
for (i = 0; path[i]; i++)
{
c = (unsigned char)path[i];
if (table[c])
continue;
/* If we got here, we're looking at a character that isn't
supported by the (or at least, our) URI encoding scheme. We
need to escape this character. */
/* First things first, copy all the good stuff that we haven't
yet copied into our output buffer. */
if (i - copied)
svn_stringbuf_appendbytes (retstr, path + copied,
i - copied);
/* Now, sprintf() in our escaped character, making sure our
buffer is big enough to hold the '%' and two digits. We cast
the C to unsigned char here because the 'X' format character
will be tempted to treat it as an unsigned int...which causes
problem when messing with 0x80-0xFF chars. We also need space
for a null as sprintf will write one. */
svn_stringbuf_ensure (retstr, retstr->len + 4);
sprintf (retstr->data + retstr->len, "%%%02X", (unsigned char)c);
retstr->len += 3;
/* Finally, update our copy counter. */
copied = i + 1;
}
/* If we didn't encode anything, we don't need to duplicate the string. */
if (retstr->len == 0)
return path;
/* Anything left to copy? */
if (i - copied)
svn_stringbuf_appendbytes (retstr, path + copied, i - copied);
/* retstr is null-terminated either by sprintf or the svn_stringbuf
functions. */
return retstr->data;
}
const char *
svn_path_uri_encode (const char *path, apr_pool_t *pool)
{
const char *ret;
ret = uri_escape (path, uri_char_validity, pool);
/* Our interface guarantees a copy. */
if (ret == path)
return apr_pstrdup (pool, path);
else
return ret;
}
static const int iri_escape_chars[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 128 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
const char *
svn_path_uri_from_iri (const char *iri, apr_pool_t *pool)
{
return uri_escape (iri, iri_escape_chars, pool);
}
const int uri_autoescape_chars[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
/* 64 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
/* 128 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 192 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
const char *
svn_path_uri_autoescape (const char *uri, apr_pool_t *pool)
{
return uri_escape (uri, uri_autoescape_chars, pool);
}
const char *
svn_path_uri_decode (const char *path, apr_pool_t *pool)
{
svn_stringbuf_t *retstr;
apr_size_t i;
svn_boolean_t query_start = FALSE;
retstr = svn_stringbuf_create ("", pool);
/* avoid repeated realloc */
svn_stringbuf_ensure (retstr, strlen (path) + 1);
retstr->len = 0;
for (i = 0; path[i]; i++)
{
char c = path[i];
if (c == '?')
{
/* Mark the start of the query string, if it exists. */
query_start = TRUE;
}
else if (c == '+' && query_start)
{
/* Only do this if we are into the query string.
* RFC 2396, section 3.3 */
c = ' ';
}
else if (c == '%' && apr_isxdigit (path[i + 1])
&& apr_isxdigit (path[i+2]))
{
char digitz[3];
digitz[0] = path[++i];
digitz[1] = path[++i];
digitz[2] = '\0';
c = (char)(strtol (digitz, NULL, 16));
}
retstr->data[retstr->len++] = c;
}
/* Null-terminate this bad-boy. */
retstr->data[retstr->len] = 0;
return retstr->data;
}
const char *
svn_path_url_add_component (const char *url,
const char *component,
apr_pool_t *pool)
{
/* URL can have trailing '/' */
url = svn_path_canonicalize (url, pool);
return svn_path_join (url, svn_path_uri_encode (component, pool), pool);
}
svn_error_t *
svn_path_get_absolute(const char **pabsolute,
const char *relative,
apr_pool_t *pool)
{
/* We call svn_path_canonicalize() on the input data, rather
than the output, so that `buffer' can be returned directly
without const vs non-const issues. */
/* ### This comment seems totally wrong, what? --xbc */
char *buffer;
apr_status_t apr_err;
const char *path_apr;
SVN_ERR (svn_path_cstring_from_utf8
(&path_apr, svn_path_canonicalize (relative, pool), pool));
if (svn_path_is_url (path_apr))
{
buffer = apr_pstrdup (pool, path_apr);
}
else
{
apr_err = apr_filepath_merge(&buffer, NULL,
path_apr,
(APR_FILEPATH_NOTRELATIVE
| APR_FILEPATH_TRUENAME),
pool);
if (apr_err)
return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
"Couldn't determine absolute path of '%s'",
relative);
}
SVN_ERR (svn_path_cstring_to_utf8 (pabsolute, buffer, pool));
*pabsolute = svn_path_canonicalize (*pabsolute, pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_path_split_if_file(const char *path,
const char **pdirectory,
const char **pfile,
apr_pool_t *pool)
{
apr_finfo_t finfo;
svn_error_t *err;
/* assert (is_canonical (path, strlen (path))); ### Expensive strlen */
err = svn_io_stat(&finfo, path, APR_FINFO_TYPE, pool);
if (err && ! APR_STATUS_IS_ENOENT(err->apr_err))
return err;
if (err || finfo.filetype == APR_REG)
{
if (err)
svn_error_clear (err);
svn_path_split(path, pdirectory, pfile, pool);
}
else if (finfo.filetype == APR_DIR)
{
*pdirectory = path;
*pfile = SVN_EMPTY_PATH;
}
else
{
return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
"'%s' is neither a file nor a directory name",
path);
}
return SVN_NO_ERROR;
}
const char *
svn_path_canonicalize (const char *path, apr_pool_t *pool)
{
char *canon, *dst;
const char *src;
apr_size_t seglen;
apr_size_t canon_segments = 0;
svn_boolean_t uri;
dst = canon = apr_pcalloc (pool, strlen (path) + 1);
/* Copy over the URI shema if present. */
src = skip_uri_schema (path);
if (src)
{
uri = TRUE;
memcpy (dst, path, src - path);
dst += (src - path);
}
else
{
uri = FALSE;
src = path;
}
/* If this is an absolute path, then just copy over the initial
separator character. */
if (*src == '/')
{
*(dst++) = *(src++);
#if defined(WIN32) || defined(__CYGWIN__)
/* On Windows permit two leading separator characters which means an
* UNC path. However, a double slash in a URI after the scheme is never
* valid. */
if (!uri && *src == '/')
*(dst++) = *(src++);
#endif /* WIN32 or Cygwin */
}
while (*src)
{
/* Parse each segment, find the closing '/' */
const char *next = src;
while (*next && (*next != '/'))
++next;
seglen = next - src;
if (seglen == 0 || (seglen == 1 && src[0] == '.'))
{
/* Noop segment, so do nothing. */
}
else
{
/* An actual segment, append it to the destination path */
if (*next)
seglen++;
memcpy (dst, src, seglen);
dst += seglen;
canon_segments++;
}
/* Skip over trailing slash to the next segment. */
src = next;
if (*src)
src++;
}
/* Remove the trailing slash. */
if ((canon_segments > 0 || uri) && *(dst - 1) == '/')
dst--;
*dst = '\0';
#if defined(WIN32) || defined(__CYGWIN__)
/* Skip leading double slashes when there are less than 2
* canon segments. UNC paths *MUST* have two segments. */
if (canon_segments < 2 && canon[0] == '/' && canon[1] == '/')
return canon + 1;
#endif /* WIN32 or Cygwin */
return canon;
}
/** Get APR's internal path encoding. */
static svn_error_t *
get_path_encoding (svn_boolean_t *path_is_utf8, apr_pool_t *pool)
{
apr_status_t apr_err;
int encoding_style;
apr_err = apr_filepath_encoding (&encoding_style, pool);
if (apr_err)
return svn_error_wrap_apr (apr_err,
"Can't determine the native path encoding");
/* ### What to do about APR_FILEPATH_ENCODING_UNKNOWN?
Well, for now we'll just punt to the svn_utf_ functions;
those will at least do the ASCII-subset check. */
*path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8);
return SVN_NO_ERROR;
}
svn_error_t *
svn_path_cstring_from_utf8 (const char **path_apr,
const char *path_utf8,
apr_pool_t *pool)
{
svn_boolean_t path_is_utf8;
SVN_ERR (get_path_encoding (&path_is_utf8, pool));
if (path_is_utf8)
{
*path_apr = apr_pstrdup (pool, path_utf8);
return SVN_NO_ERROR;
}
else
return svn_utf_cstring_from_utf8 (path_apr, path_utf8, pool);
}
svn_error_t *
svn_path_cstring_to_utf8 (const char **path_utf8,
const char *path_apr,
apr_pool_t *pool)
{
svn_boolean_t path_is_utf8;
SVN_ERR (get_path_encoding (&path_is_utf8, pool));
if (path_is_utf8)
{
*path_utf8 = apr_pstrdup (pool, path_apr);
return SVN_NO_ERROR;
}
else
return svn_utf_cstring_to_utf8 (path_utf8, path_apr, pool);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -