• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License for more details.
11 
12 #include "android/base/files/PathUtils.h"
13 
14 #include <string.h>
15 
16 namespace android {
17 namespace base {
18 
19 // static
isDirSeparator(int ch,HostType hostType)20 bool PathUtils::isDirSeparator(int ch, HostType hostType) {
21     return (ch == '/') || (hostType == HOST_WIN32 && ch == '\\');
22 }
23 
24 
25 // static
isPathSeparator(int ch,HostType hostType)26 bool PathUtils::isPathSeparator(int ch, HostType hostType) {
27     return (hostType == HOST_POSIX && ch == ':') ||
28             (hostType == HOST_WIN32 && ch == ';');
29 }
30 
31 // static
rootPrefixSize(const char * path,HostType hostType)32 size_t PathUtils::rootPrefixSize(const char* path, HostType hostType) {
33     if (!path || !path[0])
34         return 0;
35 
36     if (hostType != HOST_WIN32)
37         return (path[0] == '/') ? 1U : 0U;
38 
39     size_t result = 0;
40     if (path[1] == ':') {
41         int ch = path[0];
42         if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
43             result = 2U;
44     } else if (!strncmp(path, "\\\\.\\", 4) ||
45             !strncmp(path, "\\\\?\\", 4)) {
46         // UNC prefixes.
47         return 4U;
48     } else if (isDirSeparator(path[0], hostType)) {
49         result = 1;
50         if (isDirSeparator(path[1], hostType)) {
51             result = 2;
52             while (path[result] && !isDirSeparator(path[result], HOST_WIN32))
53                 result++;
54         }
55     }
56     if (result && path[result] && isDirSeparator(path[result], HOST_WIN32))
57         result++;
58 
59     return result;
60 }
61 
62 // static
isAbsolute(const char * path,HostType hostType)63 bool PathUtils::isAbsolute(const char* path, HostType hostType) {
64     size_t prefixSize = rootPrefixSize(path, hostType);
65     if (!prefixSize) {
66         return false;
67     }
68     if (hostType != HOST_WIN32) {
69         return true;
70     }
71     return isDirSeparator(path[prefixSize - 1], HOST_WIN32);
72 }
73 
74 // static
decompose(const char * path,HostType hostType)75 StringVector PathUtils::decompose(const char* path, HostType hostType) {
76     StringVector result;
77     if (!path || !path[0])
78         return result;
79 
80     size_t prefixLen = rootPrefixSize(path, hostType);
81     if (prefixLen) {
82         result.push_back(String(path, prefixLen));
83         path += prefixLen;
84     }
85     for (;;) {
86         const char* p = path;
87         while (*p && !isDirSeparator(*p, hostType))
88             p++;
89         if (p > path) {
90             result.push_back(String(path, p - path));
91         }
92         if (!*p) {
93             break;
94         }
95         path = p + 1;
96     }
97     return result;
98 }
99 
100 // static
recompose(const StringVector & components,HostType hostType)101 String PathUtils::recompose(const StringVector& components,
102                             HostType hostType) {
103     const char dirSeparator = (hostType == HOST_WIN32) ? '\\' : '/';
104     String result;
105     size_t capacity = 0;
106     // To reduce memory allocations, compute capacity before doing the
107     // real append.
108     for (size_t n = 0; n < components.size(); ++n) {
109         if (n)
110             capacity++;
111         capacity += components[n].size();
112     }
113 
114     result.reserve(capacity);
115 
116     bool addSeparator = false;
117     for (size_t n = 0; n < components.size(); ++n) {
118         const String& component = components[n];
119         if (addSeparator)
120             result += dirSeparator;
121         addSeparator = true;
122         if (n == 0) {
123             size_t prefixLen = rootPrefixSize(component.c_str(), hostType);
124             if (prefixLen > 0) {
125                 addSeparator = false;
126             }
127         }
128         result += components[n];
129     }
130     return result;
131 }
132 
133 // static
simplifyComponents(StringVector * components)134 void PathUtils::simplifyComponents(StringVector* components) {
135     StringVector stack;
136     for (StringVector::const_iterator it = components->begin();
137             it != components->end();
138             ++it) {
139         if (*it == ".") {
140             // Ignore any instance of '.' from the list.
141             continue;
142         }
143         if (*it == "..") {
144             // Handling of '..' is specific: if there is a item on the
145             // stack that is not '..', then remove it, otherwise push
146             // the '..'.
147             if (!stack.empty() && stack[stack.size() -1U] != "..") {
148                 stack.resize(stack.size() - 1U);
149             } else {
150                 stack.push_back(*it);
151             }
152             continue;
153         }
154         // If not a '..', just push on the stack.
155         stack.push_back(*it);
156     }
157     if (stack.empty())
158         stack.push_back(".");
159 
160     components->swap(&stack);
161 }
162 
163 }  // namespace base
164 }  // namespace android
165