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