Add License file and comments to sources
[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 a_offset, const std::string& b, int b_offset, int length)
43 {
44   return static_cast<int>(a.length()) - length >= a_offset &&
45     static_cast<int>(b.length()) - length >= b_offset &&
46     std::equal(b.begin() + b_offset, b.begin() + b_offset + length, a.begin() + a_offset,
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   {
79     path.append(path2);
80   }
81   else
82   {
83     path += PATH_SEPARATOR;
84     path.append(path2);
85   }
86
87   return path;
88 }
89
90 void AppendPath(std::string& path1, const std::string& path2)
91 {
92   if (path1.back() == PATH_SEPARATOR)
93   {
94     path1.append(path2);
95   }
96   else
97   {
98     path1 += PATH_SEPARATOR;
99     path1.append(path2);
100   }
101 }
102
103 std::string AbsolutePath(const std::string& path)
104 {
105   std::string absPath;
106
107   char realPath[PATH_MAX];
108   if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0')
109   {
110     absPath.assign(realPath);
111   }
112
113   return absPath;
114 }
115
116 std::string Basename(const std::string& path)
117 {
118   auto pos = path.find_last_of(PATH_SEPARATOR);
119   if (pos != std::string::npos)
120   {
121     return path.substr(0, pos);
122   }
123   else
124   {
125     return std::string(".");
126   }
127   return path;
128 }
129
130 bool EndWithIgnoreCase(const std::string& str1, const std::string& str2, std::string& filename)
131 {
132   std::string::size_type len1 = str1.length();
133   std::string::size_type len2 = str2.length();
134   if (len2 > len1) return false;
135
136   int i = 0;
137   bool result = std::all_of(str1.cend() - len2, str1.end(),
138         [&i, &str2] (char x) {
139           return std::tolower(x) == std::tolower(str2[i++]);
140         });
141   if (result)
142   {
143     filename = str1.substr(0, len1 - len2);
144   }
145   return result;
146 }
147
148 bool FileNotExist(const std::string& path)
149 {
150   struct stat sb;
151   return stat(path.c_str(), &sb) != 0;
152 }
153
154 static bool ExtCheckAndGetFileNameIfExist(const std::string&  dir, const std::string& ext, struct dirent* entry, std::string& filename)
155 {
156   std::string fname(entry->d_name);
157   if (fname.length() < ext.length() ||
158       fname.compare(fname.length() - ext.length(), ext.length(), ext) != 0)
159   {
160     return false;
161   }
162   std::string fullname = ConcatPath(dir, entry->d_name);
163   switch (entry->d_type)
164   {
165     case DT_REG: break;
166     case DT_LNK:
167     case DT_UNKNOWN:
168       if (FileNotExist(fullname))
169       {
170         return false;
171       }
172     default:
173       return false;
174   }
175
176   filename = fullname;
177
178   return true;
179 }
180
181 std::string StripNIDLL(const std::string& path)
182 {
183   std::string npath(path);
184   if (path.size() < 5) return npath;
185   if (strncasecmp(path.c_str() + path.size() - 4, ".dll", 4))
186   {
187     npath = path.substr(0, path.size()-4);
188   }else if (strncasecmp(path.c_str() + path.size() - 4, ".exe", 4))
189   {
190     npath = path.substr(0, path.size()-4);
191   }
192   if (strncasecmp(npath.c_str() + npath.size() - 3, ".ni", 3))
193   {
194     return npath.substr(0, npath.size()-3);
195   }
196   return npath;
197 }
198
199 std::string JoinStrings(const std::vector<std::string>& strings, const char* const delimeter)
200 {
201   switch (strings.size())
202   {
203     case 0:
204       return "";
205     case 1:
206       return strings[0];
207     default:
208       std::ostringstream os; 
209       std::copy(strings.begin(), strings.end()-1, std::ostream_iterator<std::string>(os, delimeter));
210       os << *strings.rbegin();
211       return os.str();
212   }
213 }
214
215 struct AssemblyFile
216 {
217   std::string noext;
218   std::string ext;
219 };
220
221 bool operator == (const AssemblyFile& lhs, const AssemblyFile& rhs)
222 {
223   return lhs.noext == rhs.noext && lhs.ext == rhs.ext;
224 }
225
226 namespace std
227 {
228   template<>
229   struct hash<AssemblyFile>
230   {
231     std::size_t operator () (const AssemblyFile& f) const
232     {
233       const std::size_t h1 = std::hash<std::string>{}(f.noext);
234       const std::size_t h2 = std::hash<std::string>{}(f.ext);
235
236       return h1 ^ (h2 << 1);
237     }
238   };
239 }
240
241 void AssembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList)
242 {
243   std::unordered_map<AssemblyFile, bool> addedAssemblies;
244
245   auto reader = [&addedAssemblies] (const char* path)
246   {
247     std::string _path(path);
248
249     std::string::size_type dotp = _path.rfind('.');
250     std::string ext = dotp != std::string::npos ? _path.substr(dotp) : "";
251     std::string noext;
252     bool ni = false;
253
254     if (IsManagedAssembly(_path))
255     {
256       if (IsNativeImage(_path))
257       {
258         noext = _path.substr(0, _path.size()-7);
259         ni = true;
260       }
261       else
262       {
263         noext = _path.substr(0, _path.size()-4);
264       }
265
266       AssemblyFile f = {noext, ext};
267       if (addedAssemblies.find(f) == addedAssemblies.end())
268       {
269         addedAssemblies[f] = ni;
270       }
271       else
272       {
273         addedAssemblies[f] |= ni;
274       }
275     }
276   };
277
278   for (auto directory : directories)
279   {
280     ScanFilesInDir(directory.c_str(), reader, 1);
281   }
282
283   for (auto kv : addedAssemblies)
284   {
285     tpaList += kv.first.noext + (kv.second ? ".ni" : "") +  kv.first.ext + ':';
286   }
287
288   if (tpaList.back() == ':')
289     tpaList.pop_back();
290 }
291
292 void ScanFilesInDir(const char* directory, FileReader reader, unsigned int depth)
293 {
294   DIR *dir;
295   struct dirent* entry;
296   bool isDir;
297
298   dir = opendir(directory);
299
300   if (dir == nullptr)
301   {
302     //_ERR("Can not open directory : %s", directory);
303     return;
304   }
305
306   std::vector<std::string> innerDirectories;
307
308   while ((entry = readdir(dir)) != nullptr)
309   {
310     isDir = false;
311     std::string path = ConcatPath(directory, entry->d_name);
312     switch (entry->d_type)
313     {
314       case DT_REG: break;
315       case DT_DIR:
316         isDir = true;
317         break;
318       case DT_LNK:
319       case DT_UNKNOWN:
320         struct stat sb;
321         if (stat(path.c_str(), &sb) == -1)
322         {
323           continue;
324         }
325
326         if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
327         {
328           break;
329         }
330       default:
331         continue;
332     }
333     if (!isDir)
334     {
335       reader(path.c_str()); 
336     }
337     else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
338     {
339       innerDirectories.push_back(path);
340     }
341   }
342
343   if (depth != 0)
344   {
345     for (auto& d : innerDirectories)
346     {
347       ScanFilesInDir(d.c_str(), reader, depth-1);
348     }
349   }
350
351   closedir(dir);
352 }