1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <androidfw/PathUtils.h>
18 
19 #include <utils/Compat.h>
20 
21 namespace android {
22 
getPathLeaf(const String8 & str)23 String8 getPathLeaf(const String8& str) {
24     const char* cp;
25     const char*const buf = str.c_str();
26 
27     cp = strrchr(buf, OS_PATH_SEPARATOR);
28     if (cp == nullptr)
29         return str;
30     else
31         return String8(cp+1);
32 }
33 
getPathDir(const String8 & str8)34 String8 getPathDir(const String8& str8) {
35     const char* cp;
36     const char*const str = str8.c_str();
37 
38     cp = strrchr(str, OS_PATH_SEPARATOR);
39     if (cp == nullptr)
40         return String8();
41     else
42         return String8(str, cp - str);
43 }
44 
findExtension(const String8 & str8)45 static char* findExtension(const String8& str8) {
46     const char* lastSlash;
47     const char* lastDot;
48     const char* const str = str8.c_str();
49 
50     // only look at the filename
51     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
52     if (lastSlash == nullptr)
53         lastSlash = str;
54     else
55         lastSlash++;
56 
57     // find the last dot
58     lastDot = strrchr(lastSlash, '.');
59     if (lastDot == nullptr)
60         return nullptr;
61 
62     // looks good, ship it
63     return const_cast<char*>(lastDot);
64 }
65 
getPathExtension(const String8 & str)66 String8 getPathExtension(const String8& str) {
67     char* ext;
68 
69     ext = findExtension(str);
70     if (ext != nullptr)
71         return String8(ext);
72     else
73         return String8();
74 }
75 
getBasePath(const String8 & str8)76 String8 getBasePath(const String8& str8) {
77     char* ext;
78     const char* const str = str8.c_str();
79 
80     ext = findExtension(str8);
81     if (ext == nullptr)
82         return str8;
83     else
84         return String8(str, ext - str);
85 }
86 
setPathName(String8 & s,const char * name)87 static void setPathName(String8& s, const char* name) {
88     size_t len = strlen(name);
89     char* buf = s.lockBuffer(len);
90 
91     memcpy(buf, name, len);
92 
93     // remove trailing path separator, if present
94     if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
95     buf[len] = '\0';
96 
97     s.unlockBuffer(len);
98 }
99 
appendPath(String8 & str,const char * name)100 String8& appendPath(String8& str, const char* name) {
101     // TODO: The test below will fail for Win32 paths. Fix later or ignore.
102     if (name[0] != OS_PATH_SEPARATOR) {
103         if (*name == '\0') {
104             // nothing to do
105             return str;
106         }
107 
108         size_t len = str.length();
109         if (len == 0) {
110             // no existing filename, just use the new one
111             setPathName(str, name);
112             return str;
113         }
114 
115         // make room for oldPath + '/' + newPath
116         int newlen = strlen(name);
117 
118         char* buf = str.lockBuffer(len+1+newlen);
119 
120         // insert a '/' if needed
121         if (buf[len-1] != OS_PATH_SEPARATOR)
122             buf[len++] = OS_PATH_SEPARATOR;
123 
124         memcpy(buf+len, name, newlen+1);
125         len += newlen;
126 
127         str.unlockBuffer(len);
128         return str;
129     } else {
130         setPathName(str, name);
131         return str;
132     }
133 }
134 
135 } // namespace android
136