1 /*
2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <memory>
27 #include <algorithm>
28
29 #include "FileUtils.h"
30
31 namespace FileUtils {
32
33 #ifdef _WIN32
34 const tstring::value_type pathSeparator = _T(';');
35 #else
36 const tstring::value_type pathSeparator = _T(':');
37 #endif
38
39 namespace {
40 #ifdef _WIN32
41 const tstring::value_type dirSeparator = _T('\\');
42 const tstring::value_type alianDirSeparator = _T('/');
43 #else
44 const tstring::value_type dirSeparator = _T('/');
45 const tstring::value_type alianDirSeparator = _T('\\');
46 #endif
47 } // namespace
48
49
isDirSeparator(const tstring::value_type c)50 bool isDirSeparator(const tstring::value_type c) {
51 return (c == dirSeparator || c == alianDirSeparator);
52 }
53
54
dirname(const tstring & path)55 tstring dirname(const tstring &path) {
56 tstring::size_type pos;
57 if (tstrings::endsWith(path, _T("/.")) || tstrings::endsWith(path, _T("\\."))) {
58 // this method is really getparent dirname - if the path ends with "/.",
59 // we need to ignore that when looking for the last "/" to find parent
60 pos = (path.substr(0, path.length() - 2)).find_last_of(_T("\\/"));
61 } else {
62 pos = path.find_last_of(_T("\\/"));
63 }
64
65 if (pos != tstring::npos) {
66 pos = path.find_last_not_of(_T("\\/"), pos); // skip trailing slashes
67 }
68 return pos == tstring::npos ? tstring() : path.substr(0, pos + 1);
69 }
70
71
basename(const tstring & path)72 tstring basename(const tstring &path) {
73 const tstring::size_type pos = path.find_last_of(_T("\\/"));
74 if (pos == tstring::npos) {
75 return path;
76 }
77 return path.substr(pos + 1);
78 }
79
80
suffix(const tstring & path)81 tstring suffix(const tstring &path) {
82 const tstring::size_type pos = path.rfind(_T('.'));
83 if (pos == tstring::npos) {
84 return tstring();
85 }
86 const tstring::size_type dirSepPos = path.find_first_of(_T("\\/"),
87 pos + 1);
88 if (dirSepPos != tstring::npos) {
89 return tstring();
90 }
91 // test for '/..' and '..' cases
92 if (pos != 0 && path[pos - 1] == _T('.')
93 && (pos == 1 || isDirSeparator(path[pos - 2]))) {
94 return tstring();
95 }
96 return path.substr(pos);
97 }
98
99
combinePath(const tstring & parent,const tstring & child)100 tstring combinePath(const tstring& parent, const tstring& child) {
101 if (parent.empty()) {
102 return child;
103 }
104 if (child.empty()) {
105 return parent;
106 }
107
108 tstring parentWOSlash = removeTrailingSlash(parent);
109 // also handle the case when child contains starting slash
110 bool childHasSlash = isDirSeparator(*child.begin());
111 tstring childWOSlash = childHasSlash ? child.substr(1) : child;
112
113 return parentWOSlash.append(1, dirSeparator).append(childWOSlash);
114 }
115
116
removeTrailingSlash(const tstring & path)117 tstring removeTrailingSlash(const tstring& path) {
118 if (path.empty()) {
119 return path;
120 }
121 tstring::const_reverse_iterator it = path.rbegin();
122 tstring::const_reverse_iterator end = path.rend();
123
124 while (it != end && isDirSeparator(*it)) {
125 ++it;
126 }
127 return path.substr(0, end - it);
128 }
129
130
normalizePath(tstring v)131 tstring normalizePath(tstring v) {
132 std::replace(v.begin(), v.end(), alianDirSeparator, dirSeparator);
133 #ifdef _WIN32
134 return tstrings::toLower(v);
135 #else
136 return v;
137 #endif
138 }
139
140
replaceSuffix(const tstring & path,const tstring & newSuffix)141 tstring replaceSuffix(const tstring& path, const tstring& newSuffix) {
142 const tstring oldSuffix = suffix(path);
143 if (oldSuffix.empty()) {
144 return tstring().append(path).append(newSuffix);
145 }
146
147 return path.substr(0, path.size() - oldSuffix.size()).append(newSuffix);
148 }
149
150 } // namespace FileUtils
151