1 /*
2 * Copyright (C) 2021-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 #ifndef OHOS_WIFI_CONFIG_FILE_IMPL_H
17 #define OHOS_WIFI_CONFIG_FILE_IMPL_H
18 #include <fstream>
19 #include <sstream>
20 #include <string>
21 #include <unistd.h>
22 #include <vector>
23 #include "wifi_config_file_spec.h"
24 #include "wifi_log.h"
25
26 namespace OHOS {
27 namespace Wifi {
28 /**
29 * @Description Remove head and tail space
30 *
31 * @param str - String
32 */
TrimString(std::string & str)33 static inline void TrimString(std::string &str)
34 {
35 int i = 0;
36 int j = static_cast<int>(str.length()) - 1;
37 while (i < static_cast<int>(str.length()) && str[i] == ' ') {
38 ++i;
39 }
40 while (j >= 0 && str[j] == ' ') {
41 --j;
42 }
43 str = ((i > j) ? "" : str.substr(i, j - i + 1));
44 }
45
46 /**
47 * @Description Delete comment message begin with ; and #
48 *
49 * @param str - String
50 */
DelComment(std::string & str)51 static inline void DelComment(std::string &str)
52 {
53 std::string::size_type i = 0;
54 for (; i < str.length(); ++i) {
55 if (str[i] == ';' || str[i] == '#') {
56 str = str.substr(0, i);
57 break;
58 }
59 }
60 return;
61 }
62
63 template<typename T>
64 class WifiConfigFileImpl {
65 public:
66 /**
67 * @Description Set the config file path
68 *
69 * @param fileName - file name
70 * @return int - 0 success
71 */
72 int SetConfigFilePath(const std::string &fileName);
73
74 /**
75 * @Description read and parses the network section of ini config file, need call SetConfigFilePath first
76 *
77 * @return int - 0 Success; >0 parse failed
78 */
79 int ReadNetworkSection(T &item, std::ifstream &fs, std::string &line);
80
81 /**
82 * @Description read and parses the networks of ini config file, need call SetConfigFilePath first
83 *
84 * @return int - 0 Success; >0 parse failed
85 */
86 int ReadNetwork(T &item, std::ifstream &fs, std::string &line);
87
88 /**
89 * @Description read and parses the ini config file, need call SetConfigFilePath first
90 *
91 * @return int - 0 Success; -1 file not exist
92 */
93 int LoadConfig();
94
95 /**
96 * @Description Save config to file
97 *
98 * @return int - 0 Success; -1 Failed
99 */
100 int SaveConfig();
101
102 /**
103 * @Description Get config values
104 *
105 * @param results - output config values
106 * @return int - 0 Success, -1 Failed
107 */
108 int GetValue(std::vector<T> &results);
109
110 /**
111 * @Description Get config values
112 *
113 * @return config values
114 */
115 const std::vector<T>& GetValue() const;
116
117 /**
118 * @Description Set the config value
119 *
120 * @param values - input config values
121 * @return int - 0 Success, -1 Failed
122 */
123 int SetValue(const std::vector<T> &values);
124
125 private:
126 std::string mFileName;
127 std::vector<T> mValues;
128 };
129
130 template<typename T>
SetConfigFilePath(const std::string & fileName)131 int WifiConfigFileImpl<T>::SetConfigFilePath(const std::string &fileName)
132 {
133 mFileName = fileName;
134 return 0;
135 }
136
137 template<typename T>
ReadNetworkSection(T & item,std::ifstream & fs,std::string & line)138 int WifiConfigFileImpl<T>::ReadNetworkSection(T &item, std::ifstream &fs, std::string &line)
139 {
140 int sectionError = 0;
141 while (std::getline(fs, line)) {
142 TrimString(line);
143 if (line.empty()) {
144 continue;
145 }
146 if (line[0] == '<' && line[line.length() - 1] == '>') {
147 return sectionError;
148 }
149 std::string::size_type npos = line.find("=");
150 if (npos == std::string::npos) {
151 LOGE("Invalid config line");
152 sectionError++;
153 continue;
154 }
155 std::string key = line.substr(0, npos);
156 std::string value = line.substr(npos + 1);
157 TrimString(key);
158 TrimString(value);
159 /* template function, needing specialization */
160 sectionError += SetTClassKeyValue(item, key, value);
161 }
162 LOGE("Section config not end correctly");
163 sectionError++;
164 return sectionError;
165 }
166
167 template<typename T>
ReadNetwork(T & item,std::ifstream & fs,std::string & line)168 int WifiConfigFileImpl<T>::ReadNetwork(T &item, std::ifstream &fs, std::string &line)
169 {
170 int networkError = 0;
171 while (std::getline(fs, line)) {
172 TrimString(line);
173 if (line.empty()) {
174 continue;
175 }
176 if (line[0] == '<' && line[line.length() - 1] == '>') {
177 networkError += ReadNetworkSection(item, fs, line);
178 } else if (line.compare("}") == 0) {
179 return networkError;
180 } else {
181 LOGE("Invalid config line");
182 networkError++;
183 }
184 }
185 LOGE("Network config not end correctly");
186 networkError++;
187 return networkError;
188 }
189
190 template<typename T>
LoadConfig()191 int WifiConfigFileImpl<T>::LoadConfig()
192 {
193 if (mFileName.empty()) {
194 LOGE("File name is empty.");
195 return -1;
196 }
197 std::ifstream fs(mFileName.c_str());
198 if (!fs.is_open()) {
199 LOGD("Loading config file: %{public}s, fs.is_open() failed!", mFileName.c_str());
200 return -1;
201 }
202 mValues.clear();
203 T item;
204 std::string line;
205 int configError;
206 while (std::getline(fs, line)) {
207 TrimString(line);
208 if (line.empty()) {
209 continue;
210 }
211 if (line[0] == '[' && line[line.length() - 1] == '{') {
212 ClearTClass(item); /* template function, needing specialization */
213 configError = ReadNetwork(item, fs, line);
214 if (configError > 0) {
215 LOGE("Parse network failed.");
216 continue;
217 }
218 mValues.push_back(item);
219 }
220 }
221 fs.close();
222 return 0;
223 }
224
225 template<typename T>
SaveConfig()226 int WifiConfigFileImpl<T>::SaveConfig()
227 {
228 if (mFileName.empty()) {
229 LOGE("File name is empty.");
230 return -1;
231 }
232 FILE* fp = fopen(mFileName.c_str(), "w");
233 if (!fp) {
234 LOGE("Save config file: %{public}s, fopen() failed!", mFileName.c_str());
235 return -1;
236 }
237 std::ostringstream ss;
238 for (std::size_t i = 0; i < mValues.size(); ++i) {
239 T &item = mValues[i];
240 /*
241 * here use template function GetTClassName OutTClassString, needing
242 * specialization.
243 */
244 ss << "[" << GetTClassName<T>() << "_" << (i + 1) << "] {" << std::endl;
245 ss << OutTClassString(item) << std::endl;
246 ss << "}" << std::endl;
247 }
248 std::string content = ss.str();
249 int ret = fwrite(content.c_str(), 1, content.length(), fp);
250 if (ret != (int)content.length()) {
251 LOGE("Save config file: %{public}s, fwrite() failed!", mFileName.c_str());
252 }
253 (void)fflush(fp);
254 (void)fsync(fileno(fp));
255 (void)fclose(fp);
256 mValues.clear(); /* clear values */
257 return 0;
258 }
259
260 template<typename T>
GetValue(std::vector<T> & results)261 int WifiConfigFileImpl<T>::GetValue(std::vector<T> &results)
262 {
263 /*
264 * swap, WifiConfigFileImpl not saved this config when next use, call LoadConfig first
265 */
266 std::swap(results, mValues);
267 return 0;
268 }
269
270 template <typename T>
GetValue()271 const std::vector<T>& WifiConfigFileImpl<T>::GetValue() const
272 {
273 return mValues;
274 }
275
276 template <typename T>
SetValue(const std::vector<T> & results)277 int WifiConfigFileImpl<T>::SetValue(const std::vector<T> &results)
278 {
279 mValues = results;
280 return 0;
281 }
282 } // namespace Wifi
283 } // namespace OHOS
284 #endif