diff options
-rw-r--r-- | include/mupdf/fitz/string.h | 13 | ||||
-rw-r--r-- | source/fitz/string.c | 75 |
2 files changed, 88 insertions, 0 deletions
diff --git a/include/mupdf/fitz/string.h b/include/mupdf/fitz/string.h index cbe1ea93..4de882a6 100644 --- a/include/mupdf/fitz/string.h +++ b/include/mupdf/fitz/string.h @@ -53,6 +53,19 @@ int fz_strlcpy(char *dst, const char *src, int n); int fz_strlcat(char *dst, const char *src, int n); /* + fz_dirname: extract the directory component from a path. +*/ +void fz_dirname(char *dir, const char *path, int dirsize); + +/* + fz_cleanname: rewrite path to the shortest string that names the same path. + + Eliminates multiple and trailing slashes, interprets "." and "..". + Overwrites the string in place. +*/ +char *fz_cleanname(char *name); + +/* fz_chartorune: UTF8 decode a single rune from a sequence of chars. rune: Pointer to an int to assign the decoded 'rune' to. diff --git a/source/fitz/string.c b/source/fitz/string.c index cab8387e..224eeff7 100644 --- a/source/fitz/string.c +++ b/source/fitz/string.c @@ -64,6 +64,81 @@ fz_strlcat(char *dst, const char *src, int siz) return dlen + (s - src); /* count does not include NUL */ } +void +fz_dirname(char *dir, const char *path, int n) +{ + int i; + + if (!path || !path[0]) + { + fz_strlcpy(dir, ".", n); + return; + } + + fz_strlcpy(dir, path, n); + + i = strlen(dir); + for(; dir[i] == '/'; --i) if (!i) { fz_strlcpy(dir, "/", n); return; } + for(; dir[i] != '/'; --i) if (!i) { fz_strlcpy(dir, ".", n); return; } + for(; dir[i] == '/'; --i) if (!i) { fz_strlcpy(dir, "/", n); return; } + dir[i+1] = 0; +} + +#define SEP(x) ((x)=='/' || (x) == 0) + +char * +fz_cleanname(char *name) +{ + char *p, *q, *dotdot; + int rooted; + + rooted = name[0] == '/'; + + /* + * invariants: + * p points at beginning of path element we're considering. + * q points just past the last path element we wrote (no slash). + * dotdot points just past the point where .. cannot backtrack + * any further (no slash). + */ + p = q = dotdot = name + rooted; + while (*p) + { + if(p[0] == '/') /* null element */ + p++; + else if (p[0] == '.' && SEP(p[1])) + p += 1; /* don't count the separator in case it is nul */ + else if (p[0] == '.' && p[1] == '.' && SEP(p[2])) + { + p += 2; + if (q > dotdot) /* can backtrack */ + { + while(--q > dotdot && *q != '/') + ; + } + else if (!rooted) /* /.. is / but ./../ is .. */ + { + if (q != name) + *q++ = '/'; + *q++ = '.'; + *q++ = '.'; + dotdot = q; + } + } + else /* real path element */ + { + if (q != name+rooted) + *q++ = '/'; + while ((*q = *p) != '/' && *q != 0) + p++, q++; + } + } + + if (q == name) /* empty string is really "." */ + *q++ = '.'; + *q = '\0'; + return name; +} enum { UTFmax = 4, /* maximum bytes per rune */ |