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 ini config file, need call SetConfigFilePath first
76 *
77 * @return int - 0 Success; -1 file not exist
78 */
79 int LoadConfig();
80
81 /**
82 * @Description Save config to file
83 *
84 * @return int - 0 Success; -1 Failed
85 */
86 int SaveConfig();
87
88 /**
89 * @Description Get config values
90 *
91 * @param results - output config values
92 * @return int - 0 Success, -1 Failed
93 */
94 int GetValue(std::vector<T> &results);
95
96 /**
97 * @Description Get config values
98 *
99 * @return config values
100 */
101 const std::vector<T>& GetValue() const;
102
103 /**
104 * @Description Set the config value
105 *
106 * @param values - input config values
107 * @return int - 0 Success, -1 Failed
108 */
109 int SetValue(const std::vector<T> &values);
110
111 private:
112 std::string mFileName;
113 std::vector<T> mValues;
114 };
115
116 template<typename T>
SetConfigFilePath(const std::string & fileName)117 int WifiConfigFileImpl<T>::SetConfigFilePath(const std::string &fileName)
118 {
119 mFileName = fileName;
120 return 0;
121 }
122
123 template<typename T>
LoadConfig()124 int WifiConfigFileImpl<T>::LoadConfig()
125 {
126 if (mFileName.empty()) {
127 LOGE("File name is empty.");
128 return -1;
129 }
130 std::ifstream fs(mFileName.c_str());
131 if (!fs.is_open()) {
132 LOGE("Loading config file: %{public}s, fs.is_open() failed!", mFileName.c_str());
133 return -1;
134 }
135 mValues.clear();
136 bool bSection = false;
137 T item;
138 std::string line;
139 while (std::getline(fs, line)) {
140 TrimString(line);
141 if (line.empty()) {
142 continue;
143 }
144 if (line[0] == '[' && line[line.length() - 1] == ']') {
145 if (bSection) {
146 mValues.push_back(item);
147 }
148 bSection = true;
149 ClearTClass(item); /* template function, needing specialization */
150 continue;
151 }
152 std::string::size_type npos = line.find("=");
153 if (npos == std::string::npos) {
154 continue;
155 }
156 std::string key = line.substr(0, npos);
157 std::string value = line.substr(npos + 1);
158 TrimString(key);
159 TrimString(value);
160 /* template function, needing specialization */
161 SetTClassKeyValue(item, key, value);
162 }
163 if (bSection) {
164 mValues.push_back(item);
165 }
166 fs.close();
167 return 0;
168 }
169
170 template<typename T>
SaveConfig()171 int WifiConfigFileImpl<T>::SaveConfig()
172 {
173 if (mFileName.empty()) {
174 LOGE("File name is empty.");
175 return -1;
176 }
177 FILE* fp = fopen(mFileName.c_str(), "w");
178 if (!fp) {
179 LOGE("Save config file: %{public}s, fopen() failed!", mFileName.c_str());
180 return -1;
181 }
182 std::ostringstream ss;
183 for (std::size_t i = 0; i < mValues.size(); ++i) {
184 T &item = mValues[i];
185 /*
186 * here use template function GetTClassName OutTClassString, needing
187 * specialization.
188 */
189 ss << "[" << GetTClassName<T>() << "_" << (i + 1) << "]" << std::endl;
190 ss << OutTClassString(item) << std::endl;
191 }
192 std::string content = ss.str();
193 int ret = fwrite(content.c_str(), 1, content.length(), fp);
194 if (ret != (int)content.length()) {
195 LOGE("Save config file: %{public}s, fwrite() failed!", mFileName.c_str());
196 }
197 (void)fflush(fp);
198 (void)fsync(fileno(fp));
199 (void)fclose(fp);
200 mValues.clear(); /* clear values */
201 return 0;
202 }
203
204 template<typename T>
GetValue(std::vector<T> & results)205 int WifiConfigFileImpl<T>::GetValue(std::vector<T> &results)
206 {
207 /*
208 * swap, WifiConfigFileImpl not saved this config when next use, call LoadConfig first
209 */
210 std::swap(results, mValues);
211 return 0;
212 }
213
214 template <typename T>
GetValue()215 const std::vector<T>& WifiConfigFileImpl<T>::GetValue() const
216 {
217 return mValues;
218 }
219
220 template <typename T>
SetValue(const std::vector<T> & results)221 int WifiConfigFileImpl<T>::SetValue(const std::vector<T> &results)
222 {
223 mValues = results;
224 return 0;
225 }
226 } // namespace Wifi
227 } // namespace OHOS
228 #endif