remove getenv
[platform/core/dotnet/launcher.git] / NativeLauncher / util / utils.cc
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
18 #include <dirent.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <limits.h>
22 #include <strings.h>
23
24 #include <cstdlib>
25 #include <cstring>
26 #include <algorithm>
27 #include <unordered_map>
28 #include <vector>
29 #include <iterator>
30 #include <sstream>
31
32 #include "utils.h"
33
34 bool iCompare(const std::string& a, const std::string& b)
35 {
36         return a.length() == b.length() &&
37                 std::equal(b.begin(), b.end(), a.begin(),
38                         [](unsigned char a, unsigned char b)
39                         { return std::tolower(a) == std::tolower(b); });
40 }
41
42 bool iCompare(const std::string& a, int aOffset, const std::string& b, int bOffset, int length)
43 {
44         return static_cast<int>(a.length()) - length >= aOffset &&
45                 static_cast<int>(b.length()) - length >= bOffset &&
46                 std::equal(b.begin() + bOffset, b.begin() + bOffset + length, a.begin() + aOffset,
47                         [](unsigned char a, unsigned char b)
48                         { return std::tolower(a) == std::tolower(b); });
49 }
50
51 bool isManagedAssembly(const std::string& fileName)
52 {
53         return iCompare(fileName, fileName.size()-4, ".dll", 0, 4) ||
54                 iCompare(fileName, fileName.size()-4, ".exe", 0, 4);
55 }
56
57 bool isNativeImage(const std::string& fileName)
58 {
59         return iCompare(fileName, fileName.size()-7, ".ni", 0, 3);
60 }
61
62 std::string readSelfPath()
63 {
64         char buff[PATH_MAX];
65         ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
66         if (len != -1) {
67                 buff[len] = '\0';
68                 return std::string(buff);
69         }
70
71         return "";
72 }
73
74 std::string concatPath(const std::string& path1, const std::string& path2)
75 {
76         std::string path(path1);
77         if (path.back() == PATH_SEPARATOR) {
78                 path.append(path2);
79         } else {
80                 path += PATH_SEPARATOR;
81                 path.append(path2);
82         }
83
84         return path;
85 }
86
87 void appendPath(std::string& path1, const std::string& path2)
88 {
89         if (path1.back() == PATH_SEPARATOR) {
90                 path1.append(path2);
91         } else {
92                 path1 += PATH_SEPARATOR;
93                 path1.append(path2);
94         }
95 }
96
97 std::string absolutePath(const std::string& path)
98 {
99         std::string absPath;
100         char realPath[PATH_MAX];
101         if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0')
102                 absPath.assign(realPath);
103
104         return absPath;
105 }
106
107 std::string baseName(const std::string& path)
108 {
109         auto pos = path.find_last_of(PATH_SEPARATOR);
110         if (pos != std::string::npos)
111                 return path.substr(0, pos);
112         else
113                 return std::string(".");
114         return path;
115 }
116
117 bool endWithIgnoreCase(const std::string& str1, const std::string& str2, std::string& fileName)
118 {
119         std::string::size_type len1 = str1.length();
120         std::string::size_type len2 = str2.length();
121         if (len2 > len1)
122                 return false;
123
124         int i = 0;
125         bool result = std::all_of(str1.cend() - len2, str1.end(),
126                                 [&i, &str2] (char x) {
127                                         return std::tolower(x) == std::tolower(str2[i++]);
128                                 });
129         if (result)
130                 fileName = str1.substr(0, len1 - len2);
131
132         return result;
133 }
134
135 bool fileNotExist(const std::string& path)
136 {
137         struct stat sb;
138         return stat(path.c_str(), &sb) != 0;
139 }
140
141 #ifdef NOT_USE_FUNCTION
142 static bool extCheckAndGetFileNameIfExist(const std::string& dir, const std::string& ext, struct dirent* entry, std::string& fileName)
143 {
144         std::string fName(entry->d_name);
145         if (fName.length() < ext.length() ||
146                         fHame.compare(fName.length() - ext.length(), ext.length(), ext) != 0) {
147                 return false;
148         }
149
150         std::string fullName = concatPath(dir, entry->d_name);
151         switch (entry->d_type) {
152                 case DT_REG: break;
153                 case DT_LNK:
154                 case DT_UNKNOWN:
155                         if (fileNotExist(fullName))
156                                 return false;
157                 default:
158                         return false;
159         }
160
161         fileName = fullName;
162
163         return true;
164 }
165 #endif
166
167 std::string stripNiDLL(const std::string& path)
168 {
169         std::string niPath(path);
170         if (path.size() < 5) return niPath;
171         if (!strncasecmp(path.c_str() + path.size() - 4, ".dll", 4))
172                 niPath = path.substr(0, path.size()-4);
173         else if (!strncasecmp(path.c_str() + path.size() - 4, ".exe", 4))
174                 niPath = path.substr(0, path.size()-4);
175
176         if (!strncasecmp(niPath.c_str() + niPath.size() - 3, ".ni", 3))
177                 return niPath.substr(0, niPath.size()-3);
178
179         return niPath;
180 }
181
182 std::string joinStrings(const std::vector<std::string>& strings, const char* const delimeter)
183 {
184         switch (strings.size()) {
185                 case 0:
186                         return "";
187                 case 1:
188                         return strings[0];
189                 default:
190                         std::ostringstream os;
191                         std::copy(strings.begin(), strings.end()-1, std::ostream_iterator<std::string>(os, delimeter));
192                         os << *strings.rbegin();
193                         return os.str();
194         }
195 }
196
197 struct AssemblyFile {
198         std::string noExt;
199         std::string ext;
200 };
201
202 bool operator == (const AssemblyFile& lhs, const AssemblyFile& rhs)
203 {
204         return lhs.noExt == rhs.noExt && lhs.ext == rhs.ext;
205 }
206
207 namespace std {
208         template<>
209         struct hash<AssemblyFile> {
210                 std::size_t operator () (const AssemblyFile& f) const {
211                         const std::size_t h1 = std::hash<std::string>{}(f.noExt);
212                         const std::size_t h2 = std::hash<std::string>{}(f.ext);
213
214                         return h1 ^ (h2 << 1);
215                 }
216         };
217 }
218
219 void assembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList)
220 {
221         std::map<std::string, std::string> assemblyList;
222         std::map<std::string, std::string> tmpList;
223
224         auto reader = [&assemblyList, &tmpList] (const char* path, const char* name) {
225                 std::string pathStr(path);
226                 if (isManagedAssembly(pathStr)) {
227                         std::string dllName = stripNiDLL(name);
228                         std::pair<std::map<std::string, std::string>::iterator, bool> ret;
229                         ret = tmpList.insert(std::pair<std::string, std::string>(dllName, pathStr));
230                         if (ret.second == false) {
231                                 if (isNativeImage(pathStr))
232                                         tmpList[dllName] = pathStr;
233                         }
234                 }
235         };
236
237         for (auto directory : directories) {
238                 scanFilesInDir(directory.c_str(), reader, 1);
239                 // merge scaned dll list to tpa list.
240                 // if the dll is already exist in the list, that is skipped.
241                 assemblyList.insert(tmpList.begin(), tmpList.end());
242         }
243
244         std::map<std::string, std::string>::iterator it;
245         for (it = assemblyList.begin(); it != assemblyList.end(); it++)
246                 tpaList += it->second + ':';
247
248         if (tpaList.back() == ':')
249                 tpaList.pop_back();
250 }
251
252 void scanFilesInDir(const char* directory, FileReader reader, unsigned int depth)
253 {
254         DIR *dir;
255         struct dirent* entry;
256         bool isDir;
257
258         dir = opendir(directory);
259
260         if (dir == nullptr)
261                 return;
262
263         std::vector<std::string> innerDirectories;
264
265         while ((entry = readdir(dir)) != nullptr) {
266                 isDir = false;
267                 std::string path = concatPath(directory, entry->d_name);
268                 switch (entry->d_type) {
269                         case DT_REG: break;
270                         case DT_DIR:
271                                 isDir = true;
272                                 break;
273                         case DT_LNK:
274                         case DT_UNKNOWN:
275                                 struct stat sb;
276                                 if (stat(path.c_str(), &sb) == -1)
277                                         continue;
278
279                                 if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
280                                         break;
281                         default:
282                                 continue;
283                 }
284                 if (!isDir)
285                         reader(path.c_str(), entry->d_name);
286                 else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
287                         innerDirectories.push_back(path);
288         }
289
290         if (depth != 0)
291                 for (auto& d : innerDirectories)
292                         scanFilesInDir(d.c_str(), reader, depth-1);
293
294         closedir(dir);
295 }