X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fpaths.c;h=4b9db67f87ebed18b7404c5864cf676f4fb6c5a4;hp=b4576cc1026863d1bf9f178edb6bfba266b00041;hb=088dff37aa334c218e1cac96cc847f5dd14f7124;hpb=e8c3ca2d1d0cac3d64985b45a9f654d2029a7518 diff --git a/src/paths.c b/src/paths.c index b4576cc1..4b9db67f 100644 --- a/src/paths.c +++ b/src/paths.c @@ -5,127 +5,147 @@ /* * Copyright (C) 2012, 2013 Eric Biggers * - * This file is part of wimlib, a library for working with WIM files. + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * - * You should have received a copy of the GNU General Public License - * along with wimlib; if not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include + +#include "wimlib.h" #include "wimlib/paths.h" #include "wimlib/util.h" -#include - /* Like the basename() function, but does not modify @path; it just returns a - * pointer to it. */ + * pointer to it. This assumes the path separator is the + * OS_PREFERRED_PATH_SEPARATOR. */ const tchar * path_basename(const tchar *path) { return path_basename_with_len(path, tstrlen(path)); } -/* Like path_basename(), but take an explicit string length. */ +/* Like path_basename(), but take an explicit string length. */ const tchar * path_basename_with_len(const tchar *path, size_t len) { - const tchar *p = &path[len] - 1; - - /* Trailing slashes. */ - while (1) { - if (p == path - 1) - return T(""); - if (*p != T('/')) - break; - p--; - } + const tchar *p = &path[len]; - while ((p != path - 1) && *p != T('/')) - p--; + do { + if (p == path) + return &path[len]; + } while (*--p == OS_PREFERRED_PATH_SEPARATOR); - return p + 1; + do { + if (p == path) + return &path[0]; + } while (*--p != OS_PREFERRED_PATH_SEPARATOR); + + return ++p; } -/* - * Returns a pointer to the part of @path following the first colon in the last - * path component, or NULL if the last path component does not contain a colon. - */ +/* Returns a pointer to the part of @path following the first colon in the last + * path component, or NULL if the last path component does not contain a colon + * or has no characters following the first colon. */ const tchar * path_stream_name(const tchar *path) { const tchar *base = path_basename(path); const tchar *stream_name = tstrchr(base, T(':')); - if (!stream_name) + if (stream_name == NULL || *(stream_name + 1) == T('\0')) return NULL; else return stream_name + 1; } - -/* Translate backslashes to forward slashes in-place. */ +/* Collapse and translate path separators, and strip trailing slashes. Doesn't + * add or delete a leading slash. + * + * @in may alias @out. + */ void -zap_backslashes(tchar *s) +do_canonicalize_path(const tchar *in, tchar *out) { - if (s) { - while (*s != T('\0')) { - if (*s == T('\\')) - *s = T('/'); - s++; + tchar *orig_out = out; + + while (*in) { + if (is_any_path_separator(*in)) { + /* Collapse multiple path separators into one */ + *out++ = WIM_PATH_SEPARATOR; + do { + in++; + } while (is_any_path_separator(*in)); + } else { + /* Copy non-path-separator character */ + *out++ = *in++; } } -} -/* Duplicate a path, with backslashes translated into forward slashes; return - * empty string for NULL input. */ -tchar * -canonicalize_fs_path(const tchar *fs_path) -{ - tchar *canonical_path; + /* Remove trailing slash if existent */ + if (out - orig_out > 1 && *(out - 1) == WIM_PATH_SEPARATOR) + --out; - if (!fs_path) - fs_path = T(""); - canonical_path = TSTRDUP(fs_path); - zap_backslashes(canonical_path); - return canonical_path; + *out = T('\0'); } -/* Duplicate a path, with backslashes translated into forward slashes; return - * empty string for NULL input; also strip leading and trailing slashes. */ +/* + * canonicalize_wim_path() - Given a user-provided path to a file within a WIM + * image, translate it into a "canonical" path. + * + * - Translate both types of slash into a consistent type (WIM_PATH_SEPARATOR). + * - Collapse path separators. + * - Add leading slash if missing. + * - Strip trailing slashes. + * + * Examples (with WIM_PATH_SEPARATOR == '/'): + * + * => / [ either NULL or empty string ] + * / => / + * \ => / + * hello => /hello + * \hello => /hello + * \hello => /hello + * /hello/ => /hello + * \hello/ => /hello + * /hello//1 => /hello/1 + * \\hello\\1\\ => /hello/1 + */ tchar * canonicalize_wim_path(const tchar *wim_path) { - tchar *p; - tchar *canonical_path; - - if (wim_path == NULL) { - wim_path = T(""); - } else { - while (*wim_path == T('/') || *wim_path == T('\\')) - wim_path++; - } - canonical_path = TSTRDUP(wim_path); - if (canonical_path) { - zap_backslashes(canonical_path); - for (p = tstrchr(canonical_path, T('\0')) - 1; - p >= canonical_path && *p == T('/'); - p--) - { - *p = T('\0'); - } - } - return canonical_path; + const tchar *in; + tchar *out; + tchar *result; + + in = wim_path; + if (!in) + in = T(""); + + result = MALLOC((1 + tstrlen(in) + 1) * sizeof(result[0])); + if (!result) + return NULL; + + out = result; + + /* Add leading slash if missing */ + if (!is_any_path_separator(*in)) + *out++ = WIM_PATH_SEPARATOR; + + do_canonicalize_path(in, out); + + return result; }