/*
* 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
/* Like the basename() function, but does not modify @path; it just returns a
* pointer to it. This assumes the path separator is the
- * OS_PREFERRED_PATH_SEPARATOR. */
+ * 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 != OS_PREFERRED_PATH_SEPARATOR)
- break;
- p--;
- }
+ const tchar *p = &path[len];
- while ((p != path - 1) && *p != OS_PREFERRED_PATH_SEPARATOR)
- 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;
}
-
-/* Duplicate a path; return empty string for NULL input. */
-tchar *
-canonicalize_fs_path(const tchar *fs_path)
+/* Collapse and translate path separators, and strip trailing slashes. Doesn't
+ * add or delete a leading slash.
+ *
+ * @in may alias @out.
+ */
+void
+do_canonicalize_path(const tchar *in, tchar *out)
{
- if (!fs_path)
- fs_path = T("");
- return TSTRDUP(fs_path);
+ 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++;
+ }
+ }
+
+ /* Remove trailing slash if existent */
+ if (out - orig_out > 1 && *(out - 1) == WIM_PATH_SEPARATOR)
+ --out;
+
+ *out = T('\0');
}
/*
- * canonicalize_wim_path - Given a user-provided path to a file within a WIM
+ * canonicalize_wim_path() - Given a user-provided path to a file within a WIM
* image, translate it into a "canonical" path.
*
- * To do this, we translate all supported path separators
- * (is_any_path_separator()) into the WIM_PATH_SEPARATOR, and strip any leading
- * and trailing slashes. The returned string is allocated. Note that there
- * still may be consecutive path separators within the string. Furthermore, the
- * string may be empty, which indicates the root dentry of the WIM image.
+ * - 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 (is_any_path_separator(*wim_path))
- wim_path++;
- }
- canonical_path = TSTRDUP(wim_path);
- if (canonical_path) {
- for (p = canonical_path; *p; p++)
- if (is_any_path_separator(*p))
- *p = WIM_PATH_SEPARATOR;
- for (p = tstrchr(canonical_path, T('\0')) - 1;
- p >= canonical_path && *p == WIM_PATH_SEPARATOR;
- 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;
}