c69b00b10ca2eb2e5c595b168b73e5ebc1c908cb
[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 #include <dirent.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <limits.h>
22 #include <strings.h>
23 #include <pkgmgr-info.h>
24 #include <pkgmgr_installer_info.h>
25 #include <sys/smack.h>
26 #include <json/json.h>
27
28 #include <cstdlib>
29 #include <cstring>
30 #include <algorithm>
31 #include <unordered_map>
32 #include <vector>
33 #include <iterator>
34 #include <fstream>
35 #include <sstream>
36 #include <map>
37
38 #include "log.h"
39 #include "utils.h"
40 #include "path_manager.h"
41
42 static 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                         !isNativeImage(fileName);
56 }
57
58 bool isNativeImage(const std::string& fileName)
59 {
60         return iCompare(fileName, fileName.size()-7, ".ni", 0, 3);
61 }
62
63 bool cmdOptionExists(char** begin, char** end, const std::string& option)
64 {
65         return std::find(begin, end, option) != end;
66 }
67
68 std::string readSelfPath()
69 {
70         char buff[PATH_MAX];
71         ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
72         if (len != -1) {
73                 buff[len] = '\0';
74                 return std::string(buff);
75         }
76
77         return "";
78 }
79
80 std::string concatPath(const std::string& path1, const std::string& path2)
81 {
82         std::string path(path1);
83         if (path.back() == PATH_SEPARATOR) {
84                 path.append(path2);
85         } else {
86                 path += PATH_SEPARATOR;
87                 path.append(path2);
88         }
89
90         return path;
91 }
92
93 void splitPath(const std::string& path, std::vector<std::string>& out)
94 {
95         std::istringstream ss(path);
96         std::string token;
97
98         while (std::getline(ss, token, ':')) {
99                 out.push_back(token);
100         }
101 }
102
103 std::string absolutePath(const std::string& path)
104 {
105         std::string absPath;
106         char realPath[PATH_MAX];
107         if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0')
108                 absPath.assign(realPath);
109
110         return absPath;
111 }
112
113 int getRootPath(std::string pkgId, std::string& rootPath)
114 {
115         int ret = 0;
116         char *path = 0;
117         uid_t uid = 0;
118
119         if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
120                 _ERR("Failed to get UID");
121                 return -1;
122         }
123
124         pkgmgrinfo_pkginfo_h handle;
125         if (uid == 0) {
126                 ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
127                 if (ret != PMINFO_R_OK) {
128                         return -1;
129                 }
130         } else {
131                 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
132                 if (ret != PMINFO_R_OK) {
133                         return -1;
134                 }
135         }
136
137         ret = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
138         if (ret != PMINFO_R_OK) {
139                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
140                 return -1;
141         }
142         rootPath = path;
143         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
144         return 0;
145 }
146
147 int getExecName(std::string pkgId, std::string& execName)
148 {
149         char *exec = NULL;
150         char *appId = 0;
151
152         pkgmgrinfo_pkginfo_h pkg_handle;
153         int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &pkg_handle);
154         if (ret != PMINFO_R_OK) {
155                 return -1;
156         }
157         ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId);
158         if (ret != PMINFO_R_OK) {
159                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
160                 return -1;
161         }
162
163         pkgmgrinfo_appinfo_h app_handle;
164         ret = pkgmgrinfo_appinfo_get_appinfo(appId, &app_handle);
165         if (ret != PMINFO_R_OK) {
166                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
167                 return -1;
168         }
169         ret = pkgmgrinfo_appinfo_get_exec(app_handle, &exec);
170         if (ret != PMINFO_R_OK) {
171                 pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
172                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
173                 return -1;
174         }
175         execName = std::string(exec).substr(std::string(exec).rfind('/') + 1);
176
177         pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
178         pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
179         return 0;
180 }
181
182 int getMetadataValue(std::string pkgId, std::string metadataKey, std::string& metadataValue)
183 {
184         char *value = NULL;
185         char *appId = 0;
186
187         pkgmgrinfo_pkginfo_h pkg_handle;
188         int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &pkg_handle);
189         if (ret != PMINFO_R_OK) {
190                 return -1;
191         }
192         ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId);
193         if (ret != PMINFO_R_OK) {
194                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
195                 return -1;
196         }
197
198         pkgmgrinfo_appinfo_h app_handle;
199         ret = pkgmgrinfo_appinfo_get_appinfo(appId, &app_handle);
200         if (ret != PMINFO_R_OK) {
201                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
202                 return -1;
203         }
204         ret = pkgmgrinfo_appinfo_get_metadata_value(app_handle, metadataKey.c_str(), &value);
205         if (ret != PMINFO_R_OK) {
206                 pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
207                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
208                 //Does not return error because the metadata key may not exist.
209                 return 0;
210         }
211         metadataValue = std::string(value);
212
213         pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
214         pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
215         return 0;
216 }
217
218 std::string baseName(const std::string& path)
219 {
220         auto pos = path.find_last_of(PATH_SEPARATOR);
221         if (pos != std::string::npos)
222                 return path.substr(0, pos);
223         else
224                 return std::string(".");
225         return path;
226 }
227
228 std::string replaceAll(const std::string &str, const std::string &pattern, const std::string &replace)
229 {
230         std::string result = str;
231         std::string::size_type pos = 0;
232         std::string::size_type offset = 0;
233
234         while ((pos = result.find(pattern, offset)) != std::string::npos) {
235                 result.replace(result.begin() + pos, result.begin() + pos + pattern.size(), replace);
236                 offset = pos + replace.size();
237         }
238
239         return result;
240 }
241
242 bool isFileExist(const std::string& path)
243 {
244         struct stat sb;
245         return stat(path.c_str(), &sb) == 0;
246 }
247
248 uintptr_t getFileSize(const std::string& path)
249 {
250         struct stat sb;
251
252         if (stat(path.c_str(), &sb) == 0) {
253                 return sb.st_size;
254         }
255
256         return 0;
257 }
258
259 std::string stripNiDLL(const std::string& path)
260 {
261         std::string niPath(path);
262         if (path.size() < 5) return niPath;
263         if (!strncasecmp(path.c_str() + path.size() - 4, ".dll", 4))
264                 niPath = path.substr(0, path.size()-4);
265         else if (!strncasecmp(path.c_str() + path.size() - 4, ".exe", 4))
266                 niPath = path.substr(0, path.size()-4);
267
268         if (!strncasecmp(niPath.c_str() + niPath.size() - 3, ".ni", 3))
269                 return niPath.substr(0, niPath.size()-3);
270
271         return niPath;
272 }
273
274 void assembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList)
275 {
276         std::map<std::string, std::string> assemblyList;
277         std::map<std::string, std::string> tmpList;
278
279         auto reader = [&assemblyList, &tmpList] (const std::string& path, const char* name) {
280                 if (isManagedAssembly(path) || isNativeImage(path)) {
281                         std::string dllName = stripNiDLL(name);
282                         std::pair<std::map<std::string, std::string>::iterator, bool> ret;
283                         ret = tmpList.insert(std::pair<std::string, std::string>(dllName, path));
284                         if (ret.second == false) {
285                                 if (isNativeImage(path))
286                                         tmpList[dllName] = path;
287                         }
288                 }
289         };
290
291         for (auto directory : directories) {
292                 scanFilesInDir(directory.c_str(), reader, 1);
293                 // merge scaned dll list to tpa list.
294                 // if the dll is already exist in the list, that is skipped.
295                 assemblyList.insert(tmpList.begin(), tmpList.end());
296         }
297
298         std::map<std::string, std::string>::iterator it;
299         for (it = assemblyList.begin(); it != assemblyList.end(); it++)
300                 tpaList += it->second + ':';
301
302         if (tpaList.back() == ':')
303                 tpaList.pop_back();
304 }
305
306 void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth)
307 {
308         DIR *dir;
309         struct dirent* entry;
310         bool isDir;
311
312         if (strstr(directory.c_str(), TAC_SYMLINK_SUB_DIR) != NULL)
313                 return;
314
315         dir = opendir(directory.c_str());
316
317         if (dir == nullptr)
318                 return;
319
320         std::vector<std::string> innerDirectories;
321
322         while ((entry = readdir(dir)) != nullptr) {
323                 isDir = false;
324                 std::string path = concatPath(directory, entry->d_name);
325                 switch (entry->d_type) {
326                         case DT_REG: break;
327                         case DT_DIR:
328                                 isDir = true;
329                                 break;
330                         case DT_LNK:
331                         case DT_UNKNOWN:
332                                 struct stat sb;
333                                 if (stat(path.c_str(), &sb) == -1)
334                                         continue;
335
336                                 if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
337                                         break;
338                         default:
339                                 continue;
340                 }
341                 if (!isDir)
342                         reader(path, entry->d_name);
343                 else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
344                         innerDirectories.push_back(path);
345         }
346
347         if (depth != 0)
348                 for (auto& d : innerDirectories)
349                         scanFilesInDir(d.c_str(), reader, depth - 1);
350
351         closedir(dir);
352 }
353
354 void updateAssemblyInfo(const std::string& getPath, const std::string& setPath, bool isSymlink)
355 {
356         char* label = NULL;
357         struct stat info;
358
359         if (isSymlink) {
360                 // change smack label for symbolic link.
361                 if (smack_lgetlabel(getPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
362                         if (smack_lsetlabel(setPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
363                                 fprintf(stderr, "Fail to set smack label\n");
364                         }
365                         free(label);
366                 }
367
368                 // change owner and groups for symbolic link.
369                 if (!stat(getPath.c_str(), &info)) {
370                         if (lchown(setPath.c_str(), info.st_uid, info.st_gid) == -1)
371                                 fprintf(stderr, "Failed to change owner and group name\n");
372                 }
373         } else {
374                 // change smack label
375                 if (smack_getlabel(getPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
376                         if (smack_setlabel(setPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
377                                 fprintf(stderr, "Fail to set smack label\n");
378                         }
379                         free(label);
380                 }
381
382                 // change owner and groups for generated ni file.
383                 if (!stat(getPath.c_str(), &info)) {
384                         if (chown(setPath.c_str(), info.st_uid, info.st_gid) == -1)
385                                 fprintf(stderr, "Failed to change owner and group name\n");
386                 }
387         }
388 }
389
390 static bool setOwnership(const bf::path& path, uid_t uid, gid_t gid) {
391         int fd = open(path.c_str(), O_RDONLY);
392         if (fd < 0) {
393                 _ERR("Can't open directory: %s", path.c_str());
394                 return false;
395         }
396         int ret = fchown(fd, uid, gid);
397         close(fd);
398         if (ret != 0) {
399                 _ERR("Failed to change owner of: %s", path.c_str());
400                 return false;
401         }
402         return true;
403 }
404
405 static bool setDirPermissions(const bf::path& path, bf::perms permissions) {
406         bs::error_code error;
407         bf::permissions(path, permissions, error);
408         if (error) {
409                 _ERR("Failed to set permissions for directory: %s, %s", path.c_str(), error.message().c_str());
410                 return false;
411         }
412         return true;
413 }
414
415 static bool setDirOwnershipAndPermissions(const bf::path& path, bf::perms permissions, uid_t uid, gid_t gid) {
416         if (!setOwnership(path, uid, gid)) {
417                 _ERR("Failed to change owner: %s, (uid: %d, gid: %d)", path.c_str(), uid, gid);
418                 return false;
419         }
420         if (!setDirPermissions(path, permissions)) {
421                 _ERR("Failed to change permission: %s, (%d)", path.c_str(), permissions);
422                 return false;
423         }
424         return true;
425 }
426
427 static bool copyOwnershipAndPermissions(const bf::path& path, const bf::path& path2) {
428         if (!bf::exists(path)) {
429                 _ERR("Failed to copy ownership and permissions from %s to %s", path.c_str(), path2.c_str());
430                 return false;
431         }
432         bf::perms permissions = bf::status(path).permissions();
433         struct stat stats;
434         if (stat(path.c_str(), &stats) != 0) {
435                 return false;
436         }
437         if (!setDirOwnershipAndPermissions(path2, permissions, stats.st_uid, stats.st_gid)) {
438                 _ERR("Failed to copy ownership and permissions from %s to %s", path.c_str(), path2.c_str());
439                 return false;
440         }
441         return true;
442 }
443
444 bool createDir(const bf::path& path) {
445         if (bf::exists(path)) {
446                 return true;
447         }
448         bs::error_code error;
449         bf::create_directories(path, error);
450         if (error) {
451                 _ERR("Failed to create directory: %s", error.message().c_str());
452                 return false;
453         }
454         return true;
455 }
456
457 bool copyDir(const bf::path& path1, const bf::path& path2, FSFlag flags) {
458         try {
459                 // Check whether the function call is valid
460                 if (!bf::exists(path1) || !bf::is_directory(path1)) {
461                         _ERR("Source directory %s does not exist or is not a directory", path1.c_str());
462                         return false;
463                 }
464                 if (!bf::exists(path2)) {
465                         // Create the destination directory
466                         if (!createDir(path2)) {
467                                 _ERR("Unable to create destination directory %s", path2.c_str());
468                                 return false;
469                         }
470                         if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS) {
471                                 copyOwnershipAndPermissions(path1, path2);
472                         }
473                 } else {
474                         if (!(flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE))) {
475                                 _ERR("Destination directory %s already exists", path2.c_str());
476                                 return false;
477                         }
478                         if (flags & (FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)) {
479                                 copyOwnershipAndPermissions(path1, path2);
480                         }
481                 }
482         } catch (const bf::filesystem_error& error) {
483                 _ERR("Failed to copy directory: %s", error.what());
484                 return false;
485         }
486
487         // Iterate through the source directory
488         for (bf::directory_iterator file(path1); file != bf::directory_iterator(); ++file) {
489                 try {
490                         bf::path current(file->path());
491                         bf::path target = path2 / current.filename();
492                         if (bf::is_symlink(symlink_status(current))) {
493                                 if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) && bf::exists(target)) {
494                                         continue;
495                                 }
496                                 bs::error_code error;
497                                 bf::copy_symlink(current, target, error);
498                                 if (error) {
499                                         _ERR("Failed to copy symlink: %s, %s", current.c_str(), error.message().c_str());
500                                         return false;
501                                 }
502                         } else if (bf::is_directory(current)) {
503                                 // Found directory: Recursion
504                                 if (!copyDir(current, target, flags)) {
505                                         return false;
506                                 }
507                         } else {
508                                 if ((flags & FS_MERGE_SKIP) && bf::exists(target)) {
509                                         continue;
510                                 }
511                                 bf::path destination = target;
512                                 if (flags & FS_COMMIT_COPY_FILE) {
513                                         destination = bf::unique_path(target.parent_path() / "%%%%-%%%%-%%%%-%%%%");
514                                 }
515                                 if (flags & FS_MERGE_OVERWRITE) {
516                                         bf::copy_file(current, destination, bf::copy_option::overwrite_if_exists);
517                                 } else {
518                                         bf::copy_file(current, destination);
519                                 }
520                                 if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS) {
521                                         copyOwnershipAndPermissions(current, destination);
522                                 }
523                                 if (flags & FS_COMMIT_COPY_FILE) {
524                                         if (flags & FS_MERGE_OVERWRITE) {
525                                                 bf::remove(target);
526                                         }
527                                         bf::rename(destination, target);
528                                 }
529                         }
530                 } catch (const bf::filesystem_error& error) {
531                         _ERR("Failed to copy directory: %s", error.what());
532                         return false;
533                 }
534         }
535         return true;
536 }
537
538 bool copyFile(const bf::path& path1, const bf::path& path2) {
539         bs::error_code error;
540         if (!bf::exists(path1)) {
541                 return false;
542         }
543         bf::copy_file(path1, path2, bf::copy_option::overwrite_if_exists, error);
544         if (error) {
545                 _ERR("copy file %s due to error [%s]", path1.c_str(), error.message().c_str());
546                 return false;
547         }
548         return true;
549 }
550
551 bool moveFile(const bf::path& path1, const bf::path& path2) {
552         if (!bf::exists(path1) || bf::exists(path2)) {
553                 return false;
554         }
555         bs::error_code error;
556         bf::rename(path1, path2, error);
557         if (error) {
558                 _ERR("Cannot move file: %s. Will copy/remove... with error [%s]", path1.c_str(), error.message().c_str());
559                 bf::copy_file(path1, path2, bf::copy_option::overwrite_if_exists, error);
560                 if (error) {
561                         _ERR("Cannot copy file %s due to error [%s]", path1.c_str(), error.message().c_str());
562                         return false;
563                 }
564                 bf::remove_all(path1, error);
565                 if (error) {
566                         _ERR("Cannot remove old file when coping: %s with error [%s]", path1.c_str(), error.message().c_str());
567                         return false;
568                 }
569         }
570         return true;
571 }
572
573 bool removeFile(const bf::path& path) {
574         if (!bf::exists(path)) {
575                 return true;
576         }
577         bs::error_code error;
578         bf::remove(path, error);
579         if (error) {
580                 _ERR("Cannot remove: %s, %s", path.c_str(), error.message().c_str());
581                 return false;
582         }
583         return true;
584 }
585
586 bool removeAll(const bf::path& path) {
587         if (!exists(path)) {
588                 return true;
589         }
590         bs::error_code error;
591         bf::remove_all(path, error);
592         if (error) {
593                 _ERR("Cannot remove: %s, %s", path.c_str(), error.message().c_str());
594                 return false;
595         }
596         return true;
597 }
598
599 //Parser the .deps.json file to get nuget information.
600 std::vector<std::string> depsJsonParser(std::string rootPath, std::string execName, std::string tpaList)
601 {
602         std::vector<std::string> tpaAssemblies;
603         splitPath(tpaList, tpaAssemblies);
604
605         std::vector<std::string> parserData;
606         std::string depsJsonName = execName.substr(0, execName.rfind(".dll")) + ".deps.json";
607         std::string depsJsonPath = concatPath(rootPath, depsJsonName);
608         if (bf::exists(depsJsonPath)) {
609                 std::ifstream ifs(depsJsonPath);
610                 Json::CharReaderBuilder reader;
611                 Json::Value root;
612                 std::string error;
613                 if (ifs.is_open()) {
614                         if (!Json::parseFromStream(reader, ifs, &root, &error)) {
615                                 _ERR("Failed to parse of deps.json");
616                                 ifs.close();
617                                 tpaAssemblies.clear();
618                                 return parserData;
619                         }
620                         const Json::Value runtimeTargetName = root["runtimeTarget"]["name"];
621                         const Json::Value nugetPackages = root["targets"][runtimeTargetName.asString().c_str()];
622                         std::vector<std::string> appDependencies;
623                         for (auto& nuget : nugetPackages.getMemberNames()) {
624                                 if (strstr(nuget.c_str(), (execName.substr(0, execName.find(".Tizen."))).c_str()) != NULL ||
625                                         strstr(nuget.c_str(), (execName.substr(0, execName.find(".dll"))).c_str()) != NULL) {
626                                         const Json::Value assemblies = nugetPackages[nuget.c_str()]["runtime"];
627                                         if (assemblies != Json::nullValue) {
628                                                 const Json::Value dependencies = nugetPackages[nuget.c_str()]["dependencies"];
629                                                 for (auto& dependency : dependencies.getMemberNames()) {
630                                                         appDependencies.push_back(dependency);
631                                                 }
632                                         }
633                                 }
634                         }
635                         for (auto& nuget : nugetPackages.getMemberNames()) {
636                                 //Skip the nuget package related to Tizen
637                                 if (strstr(nuget.c_str(), TIZEN_DOTNET_NUGET) == NULL &&
638                                         strstr(nuget.c_str(), TIZEN_DOTNET_SDK_NUGET) == NULL &&
639                                         strstr(nuget.c_str(), (execName.substr(0, execName.find(".Tizen."))).c_str()) == NULL &&
640                                         strstr(nuget.c_str(), (execName.substr(0, execName.find(".dll"))).c_str()) == NULL) {
641                                         const Json::Value assemblies = nugetPackages[nuget.c_str()]["runtime"];
642                                         if (assemblies != Json::nullValue) {
643                                                 const Json::Value dependencies = nugetPackages[nuget.c_str()]["dependencies"];
644                                                 bool hasDependency = false;
645                                                 for (auto& dependency : dependencies.getMemberNames()) {
646                                                         //Skip the nugget package that is dependent on another nuget package
647                                                         if (strstr(dependency.c_str(), TIZEN_DOTNET_NUGET) == NULL &&
648                                                                 strstr(dependency.c_str(), NET_STANDARD_LIBRARY_NUGET) == NULL) {
649                                                                 hasDependency = true;
650                                                                 for (auto& ad : appDependencies) {
651                                                                         if (!strcmp(ad.c_str(), dependency.c_str())) {
652                                                                                 hasDependency = true;
653                                                                                 break;
654                                                                         } else {
655                                                                                 hasDependency = false;
656                                                                         }
657                                                                 }
658                                                                 if (hasDependency) break;
659                                                         }
660                                                 }
661                                                 if (!hasDependency) {
662                                                         bool isExistTpaAssembly = false;
663                                                         for (auto& assembly : assemblies.getMemberNames()) {
664                                                                 std::string assemblyName = assembly.substr(assembly.rfind('/') + 1);
665                                                                 //Skip the assembly present in the TPA list
666                                                                 for (auto& tpa : tpaAssemblies) {
667                                                                         if (!strcmp(replaceAll(tpa, ".ni.dll", ".dll").c_str(), assembly.c_str())) {
668                                                                                 isExistTpaAssembly = true;
669                                                                                 break;
670                                                                         }
671                                                                 }
672                                                                 if (isExistTpaAssembly) break;
673                                                         }
674                                                         if (!isExistTpaAssembly) {
675                                                                 for (auto& assembly : assemblies.getMemberNames()) {
676                                                                         std::string assemblyName = assembly.substr(assembly.rfind('/') + 1);
677                                                                         parserData.push_back(nuget + ":" + assemblyName);
678                                                                         _INFO("Nuget : [%s] / Assembly : [%s]", nuget.c_str(), assemblyName.c_str());
679                                                                 }
680                                                         }
681                                                 }
682                                         }
683                                 }
684                         }
685                         appDependencies.clear();
686                         ifs.close();
687                 }
688         }
689         tpaAssemblies.clear();
690         return parserData;
691 }