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 #include "form_provider_data.h"
17
18 #include <cinttypes>
19 #include <fstream>
20 #include <iostream>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "fms_log_wrapper.h"
25 #include "form_constants.h"
26 #include "message_parcel.h"
27 #include "string_ex.h"
28
29 namespace OHOS {
30 namespace AppExecFwk {
31 const std::string JSON_EMPTY_STRING = "{}";
32 const std::string JSON_IMAGES_STRING = "formImages";
33 constexpr int32_t READ_PARCEL_MAX_IMAGE_DATA_NUM_SIZE = 1000;
34 constexpr int32_t MAX_IMAGE_BYTE_SIZE = 50 * 1024 * 1024;
35 /**
36 * @brief Constructor.
37 */
FormProviderData()38 FormProviderData::FormProviderData()
39 {
40 jsonFormProviderData_.clear();
41 }
42
43 /**
44 * @brief A constructor used to create a {@code FormProviderData} instance with data of
45 * the {@code nlohmann::json} type specified.
46 * @param jsonData Indicates the data to be carried in the new {@code FormProviderData} instance,
47 * in {@code nlohmann::json} format.
48 */
FormProviderData(nlohmann::json & jsonData)49 FormProviderData::FormProviderData(nlohmann::json &jsonData)
50 {
51 jsonFormProviderData_ = jsonData;
52 ParseImagesData();
53 }
54
55 /**
56 * @brief A constructor used to create a {@code FormProviderData} instance with data of the {@code String} type
57 * specified.
58 * @param jsonDataString Indicates the data to be carried in the new {@code FormProviderData} instance,
59 * in JSON string format.
60 */
FormProviderData(std::string jsonDataString)61 FormProviderData::FormProviderData(std::string jsonDataString)
62 {
63 if (jsonDataString.empty()) {
64 jsonDataString = JSON_EMPTY_STRING;
65 }
66 nlohmann::json jsonObject = nlohmann::json::parse(jsonDataString, nullptr, false);
67 if (jsonObject.is_discarded()) {
68 HILOG_ERROR("failed to parse jsonDataString: %{public}s.", jsonDataString.c_str());
69 return;
70 }
71 jsonFormProviderData_ = jsonObject;
72 ParseImagesData();
73 }
74
75 /**
76 * @brief Updates form data in this {@code FormProviderData} object.
77 * @param jsonData Indicates the new data to use, in {@code ZSONObject} format.
78 */
UpdateData(nlohmann::json & jsonData)79 void FormProviderData::UpdateData(nlohmann::json &jsonData)
80 {
81 jsonFormProviderData_ = jsonData;
82 }
83 /**
84 * @brief Obtains the form data stored in this {@code FormProviderData} object.
85 * @return Returns json data
86 */
GetData() const87 nlohmann::json FormProviderData::GetData() const
88 {
89 return jsonFormProviderData_;
90 }
91 /**
92 * @brief Obtains the form data stored in this {@code FormProviderData} object.
93 * @return Returns json string format
94 */
GetDataString() const95 std::string FormProviderData::GetDataString() const
96 {
97 HILOG_INFO("get data string");
98 std::string dataStr = jsonFormProviderData_.empty() ? "" : jsonFormProviderData_.dump();
99 HILOG_DEBUG("%{public}s, data: %{private}s", __func__, dataStr.c_str());
100 return dataStr;
101 }
102
103 /**
104 * @brief Adds an image to this {@code FormProviderData} instance.
105 * @param picName Indicates the name of the image to add.
106 * @param data Indicates the binary data of the image content.
107 */
AddImageData(const std::string & picName,const std::shared_ptr<char> & data,int32_t size)108 void FormProviderData::AddImageData(const std::string &picName, const std::shared_ptr<char> &data, int32_t size)
109 {
110 if ((picName.length() == 0) || (!data)) {
111 HILOG_ERROR("input param is NULL!");
112 return;
113 }
114
115 rawImageBytesMap_[picName] = std::make_pair(data, size);
116
117 imageDataState_ = IMAGE_DATA_STATE_ADDED;
118 }
119
120 /**
121 * @brief Adds an image to this {@code FormProviderData} instance.
122 * @param picName Indicates the name of the image to add.
123 * @param data Indicates the binary data of the image content.
124 */
AddImageData(const std::string & picName,int fd)125 void FormProviderData::AddImageData(const std::string &picName, int fd)
126 {
127 HILOG_INFO("%{public}s called. fd is %{public}d", __func__, fd);
128 if (fd < 0) {
129 HILOG_ERROR("fd is invalid.");
130 return;
131 }
132
133 int32_t size = lseek(fd, 0L, SEEK_END);
134 if (size <= 0) {
135 HILOG_ERROR("Get file size failed, errno is %{public}d", errno);
136 return;
137 }
138 HILOG_INFO("File size is %{public}d", size);
139 if (lseek(fd, 0L, SEEK_SET) == -1) {
140 return;
141 }
142 if (size > MAX_IMAGE_BYTE_SIZE) {
143 HILOG_ERROR("File is too large");
144 return;
145 }
146 char* bytes = new (std::nothrow) char[size];
147 if (bytes == nullptr) {
148 HILOG_ERROR("malloc memory failed", errno);
149 }
150 if (read(fd, bytes, size) < 0) {
151 delete[] bytes;
152 HILOG_ERROR("Read failed, errno is %{public}d", errno);
153 return;
154 }
155 std::shared_ptr<char> data(bytes, DeleteBytes());
156 AddImageData(picName, data, size);
157 HILOG_INFO("%{public}s called end.", __func__);
158 }
159
ParseImagesData()160 void FormProviderData::ParseImagesData()
161 {
162 if (jsonFormProviderData_ == nullptr) {
163 HILOG_ERROR("Form provider json data is nullptr.");
164 return;
165 }
166 if (!jsonFormProviderData_.contains(JSON_IMAGES_STRING)) {
167 return;
168 }
169 nlohmann::json jsonImages = jsonFormProviderData_.at(JSON_IMAGES_STRING);
170 for (auto iter = jsonImages.begin(); iter != jsonImages.end(); iter++) {
171 if (iter->is_number_integer()) {
172 AddImageData(iter.key(), iter.value());
173 } else {
174 HILOG_ERROR("fd is not number integer.");
175 }
176 }
177 }
178
179 /**
180 * @brief Removes data of an image with the specified {@code picName} from this {@code FormProviderData} instance.
181 * @param picName Indicates the name of the image to remove.
182 */
RemoveImageData(std::string picName)183 void FormProviderData::RemoveImageData(std::string picName)
184 {
185 rawImageBytesMap_.erase(picName);
186 }
187
188 /**
189 * @brief Set the form data stored from string string.
190 * @param Returns string string.
191 */
SetDataString(std::string & jsonDataString)192 void FormProviderData::SetDataString(std::string &jsonDataString)
193 {
194 if (jsonDataString.empty()) {
195 jsonDataString = JSON_EMPTY_STRING;
196 }
197 nlohmann::json jsonObject = nlohmann::json::parse(jsonDataString, nullptr, false);
198 if (jsonObject.is_discarded()) {
199 HILOG_ERROR("failed to parse jsonDataString: %{public}s.", jsonDataString.c_str());
200 return;
201 }
202 jsonFormProviderData_ = jsonObject;
203 }
204 /**
205 * @brief Merge new data to FormProviderData.
206 * @param addJsonData data to merge to FormProviderData
207 */
MergeData(nlohmann::json & addJsonData)208 void FormProviderData::MergeData(nlohmann::json &addJsonData)
209 {
210 HILOG_INFO("merge data");
211 if (addJsonData.empty()) {
212 return;
213 }
214
215 if (jsonFormProviderData_.empty()) {
216 jsonFormProviderData_ = addJsonData;
217 return;
218 }
219
220 for (auto && [key, value] : addJsonData.items()) {
221 jsonFormProviderData_[key] = value;
222 }
223 }
224
225 /**
226 * @brief Obtains the imageDataMap stored in this {@code FormProviderData} object.
227 * @return Returns the map that contains shared image data.
228 */
GetImageDataMap() const229 std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> FormProviderData::GetImageDataMap() const
230 {
231 return imageDataMap_;
232 }
233
234 /**
235 * @brief Obtains the add/remove state stored in this {@code FormProviderData} object.
236 * @return Returns the add/remove state of shared image data.
237 */
GetImageDataState() const238 int32_t FormProviderData::GetImageDataState() const
239 {
240 return imageDataState_;
241 }
242
243 /**
244 * @brief Updates imageDataState in this {@code FormProviderData} object.
245 * @param imageDataState Indicates the imageDataState to update.
246 */
SetImageDataState(int32_t imageDataState)247 void FormProviderData::SetImageDataState(int32_t imageDataState)
248 {
249 imageDataState_ = imageDataState;
250 }
251
252 /**
253 * @brief Updates imageDataMap in this {@code FormProviderData} object.
254 * @param imageDataMap Indicates the imageDataMap to update.
255 */
SetImageDataMap(std::map<std::string,std::pair<sptr<FormAshmem>,int32_t>> imageDataMap)256 void FormProviderData::SetImageDataMap(std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> imageDataMap)
257 {
258 imageDataMap_ = imageDataMap;
259 if (!imageDataMap.empty()) {
260 imageDataState_ = IMAGE_DATA_STATE_ADDED;
261 } else {
262 imageDataState_ = IMAGE_DATA_STATE_NO_OPERATION;
263 }
264 }
265
266 /**
267 * Read this {@code FormProviderData} object from a Parcel.
268 * @param parcel the parcel
269 * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise.
270 */
ReadFromParcel(Parcel & parcel)271 bool FormProviderData::ReadFromParcel(Parcel &parcel)
272 {
273 auto jsonDataString = Str16ToStr8(parcel.ReadString16());
274 nlohmann::json jsonObject = nlohmann::json::parse(jsonDataString, nullptr, false);
275 if (jsonObject.is_discarded()) {
276 HILOG_ERROR("failed to parse jsonDataString: %{public}s.", jsonDataString.c_str());
277 return false;
278 }
279 jsonFormProviderData_ = jsonObject;
280
281 imageDataState_ = parcel.ReadInt32();
282 HILOG_INFO("%{public}s imageDateState is %{public}d", __func__, imageDataState_);
283 switch (imageDataState_) {
284 case IMAGE_DATA_STATE_ADDED: {
285 int32_t imageDataNum = parcel.ReadInt32();
286 if (imageDataNum > READ_PARCEL_MAX_IMAGE_DATA_NUM_SIZE) {
287 return false;
288 }
289 HILOG_INFO("%{public}s imageDataNum is %{public}d", __func__, imageDataNum);
290 for (int32_t i = 0; i < imageDataNum; i++) {
291 sptr<FormAshmem> formAshmem = parcel.ReadParcelable<FormAshmem>();
292 if (formAshmem == nullptr) {
293 HILOG_ERROR("%{public}s failed, ashmem is nullptr", __func__);
294 return false;
295 }
296 int32_t len = parcel.ReadInt32();
297 std::pair<sptr<FormAshmem>, int32_t> imageDataRecord = std::make_pair(formAshmem, len);
298 auto picName = Str16ToStr8(parcel.ReadString16());
299 imageDataMap_[picName] = imageDataRecord;
300 }
301 break;
302 }
303 case IMAGE_DATA_STATE_NO_OPERATION:
304 case IMAGE_DATA_STATE_REMOVED:
305 break;
306 default:
307 HILOG_WARN("%{public}s failed, unexpected imageDataState_ %{public}d", __func__, imageDataState_);
308 break;
309 }
310 return true;
311 }
312
313 /**
314 * @brief Marshals this {@code FormProviderData} object into a {@link ohos.utils.Parcel} object.
315 * @param parcel Indicates the {@code Parcel} object for marshalling.
316 * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise.
317 */
Marshalling(Parcel & parcel) const318 bool FormProviderData::Marshalling(Parcel &parcel) const
319 {
320 HILOG_INFO("%{public}s called, jsonFormProviderData_: %{public}s", __func__, jsonFormProviderData_.dump().c_str());
321 if (!parcel.WriteString16(Str8ToStr16(jsonFormProviderData_.empty() ?
322 JSON_EMPTY_STRING : jsonFormProviderData_.dump()))) {
323 return false;
324 }
325
326 parcel.WriteInt32(imageDataState_);
327 HILOG_INFO("%{public}s imageDateState is %{public}d", __func__, imageDataState_);
328 switch (imageDataState_) {
329 case IMAGE_DATA_STATE_ADDED: {
330 parcel.WriteInt32(rawImageBytesMap_.size()); // firstly write the number of shared image to add
331 for (auto &entry : rawImageBytesMap_) {
332 if (!WriteImageDataToParcel(parcel, entry.first, entry.second.first, entry.second.second)) {
333 HILOG_ERROR("%{public}s failed, the picture name is %{public}s", __func__, entry.first.c_str());
334 return false;
335 }
336 parcel.WriteInt32(sizeof(entry.second));
337 parcel.WriteString16(Str8ToStr16(entry.first));
338 }
339 break;
340 }
341 case IMAGE_DATA_STATE_NO_OPERATION:
342 case IMAGE_DATA_STATE_REMOVED:
343 break;
344 default:
345 HILOG_WARN("%{public}s failed, unexpected imageDataState_ %{public}d", __func__, imageDataState_);
346 break;
347 }
348 return true;
349 }
350
351 /**
352 * @brief Unmarshals this {@code FormProviderData} object from a {@link ohos.utils.Parcel} object.
353 * @param parcel Indicates the {@code Parcel} object for unmarshalling.
354 * @return FormProviderData.
355 */
Unmarshalling(Parcel & parcel)356 FormProviderData* FormProviderData::Unmarshalling(Parcel &parcel)
357 {
358 std::unique_ptr<FormProviderData> formProviderData = std::make_unique<FormProviderData>();
359 if (formProviderData && !formProviderData->ReadFromParcel(parcel)) {
360 formProviderData = nullptr;
361 }
362 return formProviderData.release();
363 }
364
365 /**
366 * @brief Clear imageDataMap, rawImageBytesMap_, imageDataState_ and jsonFormProviderData_.
367 */
ClearData()368 void FormProviderData::ClearData()
369 {
370 jsonFormProviderData_.clear();
371 }
372
NeedCache() const373 bool FormProviderData::NeedCache() const
374 {
375 return !jsonFormProviderData_.empty() || !imageDataMap_.empty();
376 }
377
WriteImageDataToParcel(Parcel & parcel,const std::string & picName,const std::shared_ptr<char> & data,int32_t size) const378 bool FormProviderData::WriteImageDataToParcel(Parcel &parcel, const std::string &picName,
379 const std::shared_ptr<char> &data, int32_t size) const
380 {
381 FormAshmem formAshmem;
382 if (!formAshmem.WriteToAshmem(picName, data.get(), size)) {
383 return false;
384 }
385
386 // write formAshmem
387 if (!parcel.WriteParcelable(&formAshmem)) {
388 HILOG_ERROR("write FormAshmem fail, the picture name is %{public}s", picName.c_str());
389 return false;
390 }
391
392 return true;
393 }
394
ConvertRawImageData()395 bool FormProviderData::ConvertRawImageData()
396 {
397 HILOG_INFO("%{public}s called", __func__);
398 for (auto &entry : rawImageBytesMap_) {
399 sptr<FormAshmem> formAshmem = new (std::nothrow) FormAshmem();
400 if (formAshmem == nullptr) {
401 HILOG_ERROR("%{public}s alloc shmem failed", __func__);
402 return false;
403 }
404 if (!formAshmem->WriteToAshmem(entry.first, entry.second.first.get(), entry.second.second)) {
405 HILOG_ERROR("%{public}s write to shmem failed", __func__);
406 return false;
407 }
408 std::pair<sptr<FormAshmem>, int32_t> imageDataRecord = std::make_pair(formAshmem, entry.second.second);
409 imageDataMap_[entry.first] = imageDataRecord;
410 }
411 rawImageBytesMap_.clear();
412 HILOG_INFO("%{public}s end", __func__);
413 return true;
414 }
415 } // namespace AppExecFwk
416 } // namespace OHOS
417