Add installer plugin and tool for create a NI
[platform/core/dotnet/launcher.git] / NativeLauncher / util / utils.cc
1
2 #include <dirent.h>
3 #include <sys/stat.h>
4 #include <unistd.h>
5 #include <limits.h>
6 #include <strings.h>
7
8 #include <cstdlib>
9 #include <cstring>
10 #include <algorithm>
11 #include <unordered_map>
12 #include <vector>
13 #include <iterator>
14 #include <sstream>
15
16 #include "utils.h"
17
18 bool ICompare(const std::string& a, const std::string& b)
19 {
20   return a.length() == b.length() &&
21     std::equal(b.begin(), b.end(), a.begin(),
22         [](unsigned char a, unsigned char b)
23         { return std::tolower(a) == std::tolower(b); });
24 }
25
26 bool ICompare(const std::string& a, int a_offset, const std::string& b, int b_offset, int length)
27 {
28   return static_cast<int>(a.length()) - length >= a_offset &&
29     static_cast<int>(b.length()) - length >= b_offset &&
30     std::equal(b.begin() + b_offset, b.begin() + b_offset + length, a.begin() + a_offset,
31         [](unsigned char a, unsigned char b)
32         { return std::tolower(a) == std::tolower(b); });
33 }
34
35 bool IsManagedAssembly(const std::string& filename)
36 {
37   return ICompare(filename, filename.size()-4, ".dll", 0, 4) ||
38     ICompare(filename, filename.size()-4, ".exe", 0, 4);
39 }
40
41 bool IsNativeImage(const std::string& filename)
42 {
43   return ICompare(filename, filename.size()-7, ".ni", 0, 3);
44 }
45
46 std::string ReadSelfPath()
47 {
48   char buff[PATH_MAX];
49   ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
50   if (len != -1) {
51     buff[len] = '\0';
52     return std::string(buff);
53   }
54
55   return "";
56 }
57
58 std::string ConcatPath(const std::string& path1, const std::string& path2)
59 {
60   std::string path(path1);
61   if (path.back() == PATH_SEPARATOR)
62   {
63     path.append(path2);
64   }
65   else
66   {
67     path += PATH_SEPARATOR;
68     path.append(path2);
69   }
70
71   return path;
72 }
73
74 void AppendPath(std::string& path1, const std::string& path2)
75 {
76   if (path1.back() == PATH_SEPARATOR)
77   {
78     path1.append(path2);
79   }
80   else
81   {
82     path1 += PATH_SEPARATOR;
83     path1.append(path2);
84   }
85 }
86
87 std::string AbsolutePath(const std::string& path)
88 {
89   std::string absPath;
90
91   char realPath[PATH_MAX];
92   if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0')
93   {
94     absPath.assign(realPath);
95   }
96
97   return absPath;
98 }
99
100 std::string Basename(const std::string& path)
101 {
102   auto pos = path.find_last_of(PATH_SEPARATOR);
103   if (pos != std::string::npos)
104   {
105     return path.substr(0, pos);
106   }
107   else
108   {
109     return std::string(".");
110   }
111   return path;
112 }
113
114 bool EndWithIgnoreCase(const std::string& str1, const std::string& str2, std::string& filename)
115 {
116   std::string::size_type len1 = str1.length();
117   std::string::size_type len2 = str2.length();
118   if (len2 > len1) return false;
119
120   int i = 0;
121   bool result = std::all_of(str1.cend() - len2, str1.end(),
122         [&i, &str2] (char x) {
123           return std::tolower(x) == std::tolower(str2[i++]);
124         });
125   if (result)
126   {
127     filename = str1.substr(0, len1 - len2);
128   }
129   return result;
130 }
131
132 bool FileNotExist(const std::string& path)
133 {
134   struct stat sb;
135   return stat(path.c_str(), &sb) != 0;
136 }
137
138 static bool ExtCheckAndGetFileNameIfExist(const std::string&  dir, const std::string& ext, struct dirent* entry, std::string& filename)
139 {
140   std::string fname(entry->d_name);
141   if (fname.length() < ext.length() ||
142       fname.compare(fname.length() - ext.length(), ext.length(), ext) != 0)
143   {
144     return false;
145   }
146   std::string fullname = ConcatPath(dir, entry->d_name);
147   switch (entry->d_type)
148   {
149     case DT_REG: break;
150     case DT_LNK:
151     case DT_UNKNOWN:
152       if (FileNotExist(fullname))
153       {
154         return false;
155       }
156     default:
157       return false;
158   }
159
160   filename = fullname;
161
162   return true;
163 }
164
165 std::string StripNIDLL(const std::string& path)
166 {
167   std::string npath(path);
168   if (path.size() < 5) return npath;
169   if (strncasecmp(path.c_str() + path.size() - 4, ".dll", 4))
170   {
171     npath = path.substr(0, path.size()-4);
172   }else if (strncasecmp(path.c_str() + path.size() - 4, ".exe", 4))
173   {
174     npath = path.substr(0, path.size()-4);
175   }
176   if (strncasecmp(npath.c_str() + npath.size() - 3, ".ni", 3))
177   {
178     return npath.substr(0, npath.size()-3);
179   }
180   return npath;
181 }
182
183 std::string JoinStrings(const std::vector<std::string>& strings, const char* const delimeter)
184 {
185   switch (strings.size())
186   {
187     case 0:
188       return "";
189     case 1:
190       return strings[0];
191     default:
192       std::ostringstream os; 
193       std::copy(strings.begin(), strings.end()-1, std::ostream_iterator<std::string>(os, delimeter));
194       os << *strings.rbegin();
195       return os.str();
196   }
197 }
198
199 struct AssemblyFile
200 {
201   std::string noext;
202   std::string ext;
203 };
204
205 bool operator == (const AssemblyFile& lhs, const AssemblyFile& rhs)
206 {
207   return lhs.noext == rhs.noext && lhs.ext == rhs.ext;
208 }
209
210 namespace std
211 {
212   template<>
213   struct hash<AssemblyFile>
214   {
215     std::size_t operator () (const AssemblyFile& f) const
216     {
217       const std::size_t h1 = std::hash<std::string>{}(f.noext);
218       const std::size_t h2 = std::hash<std::string>{}(f.ext);
219
220       return h1 ^ (h2 << 1);
221     }
222   };
223 }
224
225 void AssembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList)
226 {
227   std::unordered_map<AssemblyFile, bool> addedAssemblies;
228
229   auto reader = [&addedAssemblies] (const char* path)
230   {
231     std::string _path(path);
232
233     std::string::size_type dotp = _path.rfind('.');
234     std::string ext = dotp != std::string::npos ? _path.substr(dotp) : "";
235     std::string noext;
236     bool ni = false;
237
238     if (IsManagedAssembly(_path))
239     {
240       if (IsNativeImage(_path))
241       {
242         noext = _path.substr(0, _path.size()-7);
243         ni = true;
244       }
245       else
246       {
247         noext = _path.substr(0, _path.size()-4);
248       }
249
250       AssemblyFile f = {noext, ext};
251       addedAssemblies[f] = ni;
252     }
253   };
254
255   for (auto directory : directories)
256   {
257     ScanFilesInDir(directory.c_str(), reader, 1);
258   }
259
260   for (auto kv : addedAssemblies)
261   {
262     tpaList += kv.first.noext + (kv.second ? ".ni" : "") +  kv.first.ext + ':';
263   }
264
265   if (tpaList.back() == ':')
266     tpaList.pop_back();
267 }
268
269 void ScanFilesInDir(const char* directory, FileReader reader, unsigned int depth)
270 {
271   DIR *dir;
272   struct dirent* entry;
273   bool isDir;
274
275   dir = opendir(directory);
276
277   if (dir == nullptr)
278   {
279     //_ERR("Can not open directory : %s", directory);
280     return;
281   }
282
283   std::vector<std::string> innerDirectories;
284
285   while ((entry = readdir(dir)) != nullptr)
286   {
287     isDir = false;
288     std::string path = ConcatPath(directory, entry->d_name);
289     switch (entry->d_type)
290     {
291       case DT_REG: break;
292       case DT_DIR:
293         isDir = true;
294         break;
295       case DT_LNK:
296       case DT_UNKNOWN:
297         struct stat sb;
298         if (stat(path.c_str(), &sb) == -1)
299         {
300           continue;
301         }
302
303         if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
304         {
305           break;
306         }
307       default:
308         continue;
309     }
310     if (!isDir)
311     {
312       reader(path.c_str()); 
313     }
314     else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
315     {
316       innerDirectories.push_back(path);
317     }
318   }
319
320   if (depth != 0)
321   {
322     for (auto& d : innerDirectories)
323     {
324       ScanFilesInDir(d.c_str(), reader, depth-1);
325     }
326   }
327
328   closedir(dir);
329 }