1 /**
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mergeProgram.h"
17
18 #if defined(PANDA_TARGET_WINDOWS)
19 #include <io.h>
20 #else
21 #include <dirent.h>
22 #endif
23
24 namespace panda::proto {
25 #if PANDA_TARGET_WINDOWS
EnumerateFilesWindows(const std::string & protoBinPath,const std::string & protoBinSuffix,std::vector<std::string> & directoryFiles)26 bool MergeProgram::EnumerateFilesWindows(const std::string &protoBinPath, const std::string &protoBinSuffix,
27 std::vector<std::string> &directoryFiles)
28 {
29 int handle = 0;
30 struct _finddata_t fileInfo;
31 std::string path;
32 if ((handle = _findfirst(path.assign(protoBinPath).append("\\*").c_str(), &fileInfo)) == -1) {
33 return false;
34 }
35 do {
36 if (fileInfo.attrib & _A_SUBDIR) {
37 if ((!strncmp(fileInfo.name, ".", 1)) || (!strncmp(fileInfo.name, "..", 2))) {
38 continue;
39 }
40 if (!GetProtoFiles(path.assign(protoBinPath).append("\\").append(fileInfo.name), protoBinSuffix,
41 directoryFiles)) {
42 _findclose(handle);
43 return false;
44 }
45 } else {
46 std::string fileName(fileInfo.name);
47 if (fileName.substr(fileName.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
48 directoryFiles.emplace_back(path.assign(protoBinPath).append("\\").append(fileName));
49 }
50 }
51 } while (_findnext(handle, &fileInfo) == 0);
52 _findclose(handle);
53 return true;
54 }
55
56 #elif PANDA_TARGET_UNIX
57 bool MergeProgram::EnumerateFilesUnix(const std::string &protoBinPath, const std::string &protoBinSuffix,
58 std::vector<std::string> &directoryFiles)
59 {
60 DIR *protoBin = opendir(protoBinPath.c_str());
61 if (protoBin == nullptr) {
62 return false;
63 }
64 dirent *dir = nullptr;
65 std::string pathPrefix = protoBinPath + "/";
66 while ((dir = readdir(protoBin)) != nullptr) {
67 if ((!strncmp(dir->d_name, ".", 1)) || (!strncmp(dir->d_name, "..", 2))) {
68 continue;
69 }
70 if (dir->d_type == DT_DIR) {
71 std::string subDirName = pathPrefix + dir->d_name;
72 if (!GetProtoFiles(subDirName, protoBinSuffix, directoryFiles)) {
73 closedir(protoBin);
74 return false;
75 }
76 } else {
77 std::string fileName = pathPrefix + dir->d_name;
78 if (fileName.substr(fileName.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
79 directoryFiles.emplace_back(fileName);
80 }
81 }
82 }
83 closedir(protoBin);
84 return true;
85 }
86 #endif
87
GetProtoFiles(const std::string & protoBinPath,const std::string & protoBinSuffix,std::vector<std::string> & directoryFiles)88 bool MergeProgram::GetProtoFiles(const std::string &protoBinPath, const std::string &protoBinSuffix,
89 std::vector<std::string> &directoryFiles)
90 {
91 #if PANDA_TARGET_WINDOWS
92 return EnumerateFilesWindows(protoBinPath, protoBinSuffix, directoryFiles);
93 #elif PANDA_TARGET_UNIX
94 return EnumerateFilesUnix(protoBinPath, protoBinSuffix, directoryFiles);
95 #endif
96 }
97
AppendProtoFiles(const std::string & filePath,const std::string & protoBinSuffix,std::vector<std::string> & protoFiles)98 bool MergeProgram::AppendProtoFiles(const std::string &filePath, const std::string &protoBinSuffix,
99 std::vector<std::string> &protoFiles)
100 {
101 auto inputAbs = panda::os::file::File::GetAbsolutePath(filePath);
102 if (!inputAbs) {
103 std::cerr << "Failed to open: " << filePath << std::endl;
104 return false;
105 }
106
107 auto fPath = inputAbs.Value();
108 if (panda::os::file::File::IsRegularFile(fPath)) {
109 if (filePath.substr(filePath.find_last_of(".") + 1).compare(protoBinSuffix) == 0) {
110 protoFiles.emplace_back(fPath);
111 }
112 } else if (panda::os::file::File::IsDirectory(fPath)) {
113 std::vector<std::string> directoryFiles;
114 if (!GetProtoFiles(fPath, protoBinSuffix, directoryFiles)) {
115 return false;
116 }
117 protoFiles.insert(protoFiles.end(), directoryFiles.begin(), directoryFiles.end());
118 } else {
119 std::cerr << "The input path: " << fPath << " must be either a regular file or directory." << std::endl;
120 return false;
121 }
122
123 return true;
124 }
125
CollectProtoFiles(std::string & input,const std::string & protoBinSuffix,std::vector<std::string> & protoFiles)126 bool MergeProgram::CollectProtoFiles(std::string &input, const std::string &protoBinSuffix,
127 std::vector<std::string> &protoFiles)
128 {
129 constexpr const char DOGGY = '@';
130 std::vector<std::string> inputs;
131 bool isList = false;
132
133 if (input[0] == DOGGY) {
134 input.erase(input.begin() + 0);
135 isList = true;
136 }
137
138 auto inputAbs = panda::os::file::File::GetAbsolutePath(input);
139 if (!inputAbs) {
140 std::cerr << "Failed to open: " << input << std::endl;
141 return false;
142 }
143 if (isList) {
144 std::ifstream in(panda::os::file::File::GetExtendedFilePath(inputAbs.Value()));
145 std::string line;
146 constexpr const char CARRIAGE = '\r';
147 while (getline(in, line)) {
148 // erase front spaces
149 line.erase(line.begin(),
150 std::find_if(line.begin(), line.end(), [](unsigned char ch) { return std::isspace(ch) == 0; }));
151 // erase carrige return symbol (Windows workaround)
152 line.erase(std::find_if(line.rbegin(), line.rend(), [](unsigned char ch) { return ch != CARRIAGE; }).base(),
153 line.end());
154 if (!line.empty()) {
155 inputs.push_back(line);
156 }
157 }
158 in.close();
159 } else {
160 inputs.push_back(inputAbs.Value());
161 }
162
163 protoFiles.reserve(inputs.size());
164 for (auto &filePath : inputs) {
165 if (!AppendProtoFiles(filePath, protoBinSuffix, protoFiles)) {
166 return false;
167 }
168 }
169
170 return true;
171 }
172 } // namespace panda::proto
173