1 /*
2 * Copyright (C) 2021-2023 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 #include "paste_data_record.h"
16
17 #include <sys/stat.h>
18 #include <unistd.h>
19
20 #include "copy_uri_handler.h"
21 #include "parcel_util.h"
22 #include "paste_uri_handler.h"
23 #include "pasteboard_error.h"
24 #include "pasteboard_hilog.h"
25 #include "pixel_map_parcel.h"
26
27 using namespace OHOS::Media;
28
29 namespace OHOS {
30 namespace MiscServices {
31 namespace {
32 constexpr int MAX_TEXT_LEN = 20 * 1024 * 1024;
33 }
34
SetMimeType(std::string mimeType)35 PasteDataRecord::Builder &PasteDataRecord::Builder::SetMimeType(std::string mimeType)
36 {
37 record_->mimeType_ = std::move(mimeType);
38 return *this;
39 }
40 enum TAG_PASTEBOARD_RECORD : uint16_t {
41 TAG_MIMETYPE = TAG_BUFF + 1,
42 TAG_HTMLTEXT,
43 TAG_WANT,
44 TAG_PLAINTEXT,
45 TAG_URI,
46 TAG_PIXELMAP,
47 TAG_CUSTOM_DATA,
48 TAG_CONVERT_URI,
49 TAG_URI_PERMISSION,
50 };
51
52 enum TAG_CUSTOMDATA : uint16_t {
53 TAG_ITEM_DATA = TAG_BUFF + 1,
54 };
55
SetHtmlText(std::shared_ptr<std::string> htmlText)56 PasteDataRecord::Builder &PasteDataRecord::Builder::SetHtmlText(std::shared_ptr<std::string> htmlText)
57 {
58 record_->htmlText_ = std::move(htmlText);
59 return *this;
60 }
SetWant(std::shared_ptr<OHOS::AAFwk::Want> want)61 PasteDataRecord::Builder &PasteDataRecord::Builder::SetWant(std::shared_ptr<OHOS::AAFwk::Want> want)
62 {
63 record_->want_ = std::move(want);
64 return *this;
65 }
SetPlainText(std::shared_ptr<std::string> plainText)66 PasteDataRecord::Builder &PasteDataRecord::Builder::SetPlainText(std::shared_ptr<std::string> plainText)
67 {
68 record_->plainText_ = std::move(plainText);
69 return *this;
70 }
SetUri(std::shared_ptr<OHOS::Uri> uri)71 PasteDataRecord::Builder &PasteDataRecord::Builder::SetUri(std::shared_ptr<OHOS::Uri> uri)
72 {
73 record_->uri_ = std::move(uri);
74 return *this;
75 }
SetPixelMap(std::shared_ptr<OHOS::Media::PixelMap> pixelMap)76 PasteDataRecord::Builder &PasteDataRecord::Builder::SetPixelMap(std::shared_ptr<OHOS::Media::PixelMap> pixelMap)
77 {
78 record_->pixelMap_ = std::move(pixelMap);
79 return *this;
80 }
81
SetCustomData(std::shared_ptr<MineCustomData> customData)82 PasteDataRecord::Builder &PasteDataRecord::Builder::SetCustomData(std::shared_ptr<MineCustomData> customData)
83 {
84 record_->customData_ = std::move(customData);
85 return *this;
86 }
87
Build()88 std::shared_ptr<PasteDataRecord> PasteDataRecord::Builder::Build()
89 {
90 return record_;
91 }
Builder(const std::string & mimeType)92 PasteDataRecord::Builder::Builder(const std::string &mimeType)
93 {
94 record_ = std::make_shared<PasteDataRecord>();
95 if (record_ != nullptr) {
96 record_->mimeType_ = mimeType;
97 record_->htmlText_ = nullptr;
98 record_->want_ = nullptr;
99 record_->plainText_ = nullptr;
100 record_->uri_ = nullptr;
101 record_->convertUri_ = "";
102 record_->pixelMap_ = nullptr;
103 record_->customData_ = nullptr;
104 }
105 }
106
NewHtmlRecord(const std::string & htmlText)107 std::shared_ptr<PasteDataRecord> PasteDataRecord::NewHtmlRecord(const std::string &htmlText)
108 {
109 if (htmlText.length() >= MAX_TEXT_LEN) {
110 return nullptr;
111 }
112 return Builder(MIMETYPE_TEXT_HTML).SetHtmlText(std::make_shared<std::string>(htmlText)).Build();
113 }
114
NewWantRecord(std::shared_ptr<OHOS::AAFwk::Want> want)115 std::shared_ptr<PasteDataRecord> PasteDataRecord::NewWantRecord(std::shared_ptr<OHOS::AAFwk::Want> want)
116 {
117 return Builder(MIMETYPE_TEXT_WANT).SetWant(std::move(want)).Build();
118 }
119
NewPlaintTextRecord(const std::string & text)120 std::shared_ptr<PasteDataRecord> PasteDataRecord::NewPlaintTextRecord(const std::string &text)
121 {
122 if (text.length() >= MAX_TEXT_LEN) {
123 return nullptr;
124 }
125 return Builder(MIMETYPE_TEXT_PLAIN).SetPlainText(std::make_shared<std::string>(text)).Build();
126 }
127
NewPixelMapRecord(std::shared_ptr<PixelMap> pixelMap)128 std::shared_ptr<PasteDataRecord> PasteDataRecord::NewPixelMapRecord(std::shared_ptr<PixelMap> pixelMap)
129 {
130 return Builder(MIMETYPE_PIXELMAP).SetPixelMap(std::move(pixelMap)).Build();
131 }
132
NewUriRecord(const OHOS::Uri & uri)133 std::shared_ptr<PasteDataRecord> PasteDataRecord::NewUriRecord(const OHOS::Uri &uri)
134 {
135 return Builder(MIMETYPE_TEXT_URI).SetUri(std::make_shared<OHOS::Uri>(uri)).Build();
136 }
137
NewKvRecord(const std::string & mimeType,const std::vector<uint8_t> & arrayBuffer)138 std::shared_ptr<PasteDataRecord> PasteDataRecord::NewKvRecord(
139 const std::string &mimeType, const std::vector<uint8_t> &arrayBuffer)
140 {
141 std::shared_ptr<MineCustomData> customData = std::make_shared<MineCustomData>();
142 customData->AddItemData(mimeType, arrayBuffer);
143 return Builder(mimeType).SetCustomData(std::move(customData)).Build();
144 }
145
PasteDataRecord(std::string mimeType,std::shared_ptr<std::string> htmlText,std::shared_ptr<OHOS::AAFwk::Want> want,std::shared_ptr<std::string> plainText,std::shared_ptr<OHOS::Uri> uri)146 PasteDataRecord::PasteDataRecord(std::string mimeType, std::shared_ptr<std::string> htmlText,
147 std::shared_ptr<OHOS::AAFwk::Want> want, std::shared_ptr<std::string> plainText, std::shared_ptr<OHOS::Uri> uri)
148 : mimeType_{ std::move(mimeType) }, htmlText_{ std::move(htmlText) }, want_{ std::move(want) },
149 plainText_{ std::move(plainText) }, uri_{ std::move(uri) }
150 {
151 }
152
PasteDataRecord()153 PasteDataRecord::PasteDataRecord()
154 {
155 fd_ = std::make_shared<FileDescriptor>();
156 InitDecodeMap();
157 }
158
PasteDataRecord(const PasteDataRecord & record)159 PasteDataRecord::PasteDataRecord(const PasteDataRecord &record) : mimeType_(record.mimeType_),
160 htmlText_(record.htmlText_), want_(record.want_), plainText_(record.plainText_), uri_(record.uri_),
161 convertUri_(record.convertUri_), pixelMap_(record.pixelMap_), customData_(record.customData_),
162 hasGrantUriPermission_(record.hasGrantUriPermission_), fd_(record.fd_)
163 {
164 InitDecodeMap();
165 }
166
InitDecodeMap()167 void PasteDataRecord::InitDecodeMap()
168 {
169 decodeMap = {
170 {TAG_MIMETYPE, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
171 ret = ret && ReadValue(buffer, mimeType_, head);
172 }
173 },
174 {TAG_HTMLTEXT, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
175 ret = ret && ReadValue(buffer, htmlText_, head);
176 }
177 },
178 {TAG_WANT, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
179 RawMem rawMem{};
180 ret = ret && ReadValue(buffer, rawMem, head);
181 want_ = ParcelUtil::Raw2Parcelable<AAFwk::Want>(rawMem);
182 }
183 },
184 {TAG_PLAINTEXT, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
185 ret = ret && ReadValue(buffer, plainText_, head);
186 }
187 },
188 {TAG_URI, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
189 RawMem rawMem{};
190 ret = ret && ReadValue(buffer, rawMem, head);
191 uri_ = ParcelUtil::Raw2Parcelable<OHOS::Uri>(rawMem);
192 }
193 },
194 {TAG_CONVERT_URI, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
195 ret = ret && ReadValue(buffer, convertUri_, head);
196 }
197 },
198 {TAG_PIXELMAP, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
199 std::vector<std::uint8_t> value;
200 ret = ret && ReadValue(buffer, value, head);
201 pixelMap_ = Vector2PixelMap(value);
202 }
203 },
204 {TAG_CUSTOM_DATA, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
205 ret = ret && ReadValue(buffer, customData_, head);
206 }
207 },
208 {TAG_URI_PERMISSION, [&](bool &ret, const std::vector<std::uint8_t> &buffer, TLVHead &head) -> void {
209 ret = ret && ReadValue(buffer, hasGrantUriPermission_, head);
210 }
211 },
212 };
213 }
214
GetHtmlText() const215 std::shared_ptr<std::string> PasteDataRecord::GetHtmlText() const
216 {
217 return this->htmlText_;
218 }
219
GetMimeType() const220 std::string PasteDataRecord::GetMimeType() const
221 {
222 return this->mimeType_;
223 }
224
GetPlainText() const225 std::shared_ptr<std::string> PasteDataRecord::GetPlainText() const
226 {
227 return this->plainText_;
228 }
229
GetPixelMap() const230 std::shared_ptr<PixelMap> PasteDataRecord::GetPixelMap() const
231 {
232 return this->pixelMap_;
233 }
234
GetUri() const235 std::shared_ptr<OHOS::Uri> PasteDataRecord::GetUri() const
236 {
237 if (convertUri_.empty()) {
238 return uri_;
239 }
240 return std::make_shared<OHOS::Uri>(convertUri_);
241 }
242
SetUri(std::shared_ptr<OHOS::Uri> uri)243 void PasteDataRecord::SetUri(std::shared_ptr<OHOS::Uri> uri)
244 {
245 uri_ = std::move(uri);
246 }
247
GetOrginUri() const248 std::shared_ptr<OHOS::Uri> PasteDataRecord::GetOrginUri() const
249 {
250 return uri_;
251 }
252
GetWant() const253 std::shared_ptr<OHOS::AAFwk::Want> PasteDataRecord::GetWant() const
254 {
255 return this->want_;
256 }
257
GetCustomData() const258 std::shared_ptr<MineCustomData> PasteDataRecord::GetCustomData() const
259 {
260 return this->customData_;
261 }
262
GetItemData()263 std::map<std::string, std::vector<uint8_t>> MineCustomData::GetItemData()
264 {
265 return this->itemData_;
266 }
267
AddItemData(const std::string & mimeType,const std::vector<uint8_t> & arrayBuffer)268 void MineCustomData::AddItemData(const std::string &mimeType, const std::vector<uint8_t> &arrayBuffer)
269 {
270 itemData_.insert(std::make_pair(mimeType, arrayBuffer));
271 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "itemData_.size = %{public}zu", itemData_.size());
272 }
273
ConvertToText() const274 std::string PasteDataRecord::ConvertToText() const
275 {
276 if (this->htmlText_) {
277 return *this->htmlText_;
278 } else if (this->plainText_) {
279 return *this->plainText_;
280 } else if (this->uri_) {
281 return this->uri_->ToString();
282 } else {
283 return "";
284 }
285 }
286
Encode(std::vector<std::uint8_t> & buffer)287 bool MineCustomData::Encode(std::vector<std::uint8_t> &buffer)
288 {
289 return TLVObject::Write(buffer, TAG_ITEM_DATA, itemData_);
290 }
291
Decode(const std::vector<std::uint8_t> & buffer)292 bool MineCustomData::Decode(const std::vector<std::uint8_t> &buffer)
293 {
294 for (; IsEnough();) {
295 TLVHead head{};
296 bool ret = ReadHead(buffer, head);
297 switch (head.tag) {
298 case TAG_ITEM_DATA:
299 ret = ret && ReadValue(buffer, itemData_, head);
300 break;
301 default:
302 ret = ret && Skip(head.len, buffer.size());
303 break;
304 }
305 if (!ret) {
306 return false;
307 }
308 }
309 return true;
310 }
311
Count()312 size_t MineCustomData::Count()
313 {
314 return TLVObject::Count(itemData_);
315 }
316
Encode(std::vector<std::uint8_t> & buffer)317 bool PasteDataRecord::Encode(std::vector<std::uint8_t> &buffer)
318 {
319 bool ret = Write(buffer, TAG_MIMETYPE, mimeType_);
320 ret = Write(buffer, TAG_HTMLTEXT, htmlText_) && ret;
321 ret = Write(buffer, TAG_WANT, ParcelUtil::Parcelable2Raw(want_.get())) && ret;
322 ret = Write(buffer, TAG_PLAINTEXT, plainText_) && ret;
323 ret = Write(buffer, TAG_URI, ParcelUtil::Parcelable2Raw(uri_.get())) && ret;
324 ret = Write(buffer, TAG_CONVERT_URI, convertUri_) && ret;
325 auto pixelVector = PixelMap2Vector(pixelMap_);
326 ret = Write(buffer, TAG_PIXELMAP, pixelVector) && ret;
327 ret = Write(buffer, TAG_CUSTOM_DATA, customData_) && ret;
328 ret = Write(buffer, TAG_URI_PERMISSION, hasGrantUriPermission_) && ret;
329 return ret;
330 }
331
Decode(const std::vector<std::uint8_t> & buffer)332 bool PasteDataRecord::Decode(const std::vector<std::uint8_t> &buffer)
333 {
334 for (; IsEnough();) {
335 TLVHead head{};
336 bool ret = ReadHead(buffer, head);
337 auto it = decodeMap.find(head.tag);
338 if (it == decodeMap.end()) {
339 ret = ret && Skip(head.len, buffer.size());
340 } else {
341 auto func = it->second;
342 func(ret, buffer, head);
343 }
344 if (!ret) {
345 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "read value,tag:%{public}u, len:%{public}u",
346 head.tag, head.len);
347 return false;
348 }
349 }
350 return true;
351 }
Count()352 size_t PasteDataRecord::Count()
353 {
354 size_t expectedSize = 0;
355 expectedSize += TLVObject::Count(mimeType_);
356 expectedSize += TLVObject::Count(htmlText_);
357 expectedSize += TLVObject::Count(ParcelUtil::Parcelable2Raw(want_.get()));
358 expectedSize += TLVObject::Count(plainText_);
359 expectedSize += TLVObject::Count(ParcelUtil::Parcelable2Raw(uri_.get()));
360 expectedSize += TLVObject::Count(convertUri_);
361 auto pixelVector = PixelMap2Vector(pixelMap_);
362 expectedSize += TLVObject::Count(pixelVector);
363 expectedSize += TLVObject::Count(customData_);
364 expectedSize += TLVObject::Count(hasGrantUriPermission_);
365 return expectedSize;
366 }
367
Vector2PixelMap(std::vector<std::uint8_t> & value)368 std::shared_ptr<PixelMap> PasteDataRecord::Vector2PixelMap(std::vector<std::uint8_t> &value)
369 {
370 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "Vector2PixelMap, size is %{public}zu", value.size());
371 if (value.size() == 0) {
372 return nullptr;
373 }
374 return std::shared_ptr<PixelMap> (PixelMap::DecodeTlv(value));
375 }
376
PixelMap2Vector(std::shared_ptr<PixelMap> & pixelMap)377 std::vector<std::uint8_t> PasteDataRecord::PixelMap2Vector(std::shared_ptr<PixelMap> &pixelMap)
378 {
379 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "PixelMap2Vector");
380 if (pixelMap == nullptr) {
381 return {};
382 }
383 std::vector<std::uint8_t> value;
384 if (!pixelMap->EncodeTlv(value)) {
385 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "pixelMap encode failed");
386 return {};
387 }
388 return value;
389 }
390
WriteFd(MessageParcel & parcel,UriHandler & uriHandler,bool isClient)391 bool PasteDataRecord::WriteFd(MessageParcel &parcel, UriHandler &uriHandler, bool isClient)
392 {
393 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "isClient: %{public}d", isClient);
394 if (fd_->GetFd() >= 0) {
395 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "write fd_, fd_ is %{public}d", fd_->GetFd());
396 return parcel.WriteFileDescriptor(fd_->GetFd());
397 }
398 std::string tempUri = GetPassUri();
399 if (tempUri.empty()) {
400 return false;
401 }
402 int32_t fd = uriHandler.ToFd(tempUri, isClient);
403 bool ret = parcel.WriteFileDescriptor(fd);
404 uriHandler.ReleaseFd(fd);
405
406 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "ret is %{public}d", ret);
407 return ret;
408 }
ReadFd(MessageParcel & parcel,UriHandler & uriHandler)409 bool PasteDataRecord::ReadFd(MessageParcel &parcel, UriHandler &uriHandler)
410 {
411 int32_t fd = parcel.ReadFileDescriptor();
412 if (fd >= 0) {
413 convertUri_ = uriHandler.ToUri(fd);
414 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "convertUri_:%{public}s", convertUri_.c_str());
415 }
416 if (!uriHandler.IsPaste()) {
417 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "Set fd, fd is %{public}d", fd);
418 fd_->SetFd(fd);
419 }
420 return true;
421 }
NeedFd(const UriHandler & uriHandler)422 bool PasteDataRecord::NeedFd(const UriHandler &uriHandler)
423 {
424 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "start");
425 std::string tempUri = GetPassUri();
426 if (tempUri.empty()) {
427 return false;
428 }
429 if (!uriHandler.IsFile(tempUri) && fd_->GetFd() < 0) {
430 PASTEBOARD_HILOGW(PASTEBOARD_MODULE_CLIENT, "invalid file uri, fd:%{public}d", fd_->GetFd());
431 return false;
432 }
433 return true;
434 }
GetPassUri()435 std::string PasteDataRecord::GetPassUri()
436 {
437 std::string tempUri;
438 if (uri_ != nullptr) {
439 tempUri = uri_->ToString();
440 }
441 if (!convertUri_.empty()) {
442 tempUri = convertUri_;
443 }
444 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "tempUri:%{public}s", tempUri.c_str());
445 return tempUri;
446 }
ReplaceShareUri(int32_t userId)447 void PasteDataRecord::ReplaceShareUri(int32_t userId)
448 {
449 if (convertUri_.empty()) {
450 return;
451 }
452
453 // convert uri format: /mnt/hmdfs/100/account/merge_view/services/psteboard_service/.share/xxx.txt
454 constexpr const char *SHARE_PATH_PREFIX = "/mnt/hmdfs/";
455 auto frontPos = convertUri_.find(SHARE_PATH_PREFIX);
456 auto rearPos = convertUri_.find("/account/");
457 if (frontPos == 0 && rearPos != std::string::npos) {
458 convertUri_ = SHARE_PATH_PREFIX + std::to_string(userId) + convertUri_.substr(rearPos);
459 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "replace uri:%{public}s", convertUri_.c_str());
460 }
461 }
SetConvertUri(const std::string & value)462 void PasteDataRecord::SetConvertUri(const std::string &value)
463 {
464 convertUri_ = value;
465 }
GetConvertUri() const466 std::string PasteDataRecord::GetConvertUri() const
467 {
468 return convertUri_;
469 }
SetGrantUriPermission(bool hasPermission)470 void PasteDataRecord::SetGrantUriPermission(bool hasPermission)
471 {
472 hasGrantUriPermission_ = hasPermission;
473 }
HasGrantUriPermission()474 bool PasteDataRecord::HasGrantUriPermission()
475 {
476 return hasGrantUriPermission_;
477 }
~FileDescriptor()478 FileDescriptor::~FileDescriptor()
479 {
480 if (fd_ >= 0) {
481 close(fd_);
482 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "close fd_: %{public}d", fd_);
483 }
484 }
SetFd(int32_t fd)485 void FileDescriptor::SetFd(int32_t fd)
486 {
487 fd_ = fd;
488 }
GetFd() const489 int32_t FileDescriptor::GetFd() const
490 {
491 return fd_;
492 }
493 } // namespace MiscServices
494 } // namespace OHOS