1 /*
2 * Copyright (C) 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
16 #include "web_clipboard_controller.h"
17
18 #include <regex>
19
20 namespace {
21 const std::string IMG_TAG_PATTERN = "<img.*?data-ohos=.*?>";
22 const std::string IMG_TAG_SRC_PATTERN = "src=\"([^\"]*)\"";
23 const std::string IMG_TAG_SRC_HEAD = "src=\"";
24 const std::string IMG_LOCAL_URI = "file:///";
25 const std::string IMG_LOCAL_PATH = "://";
26 constexpr uint32_t FOUR_BYTES = 4;
27 constexpr uint32_t EIGHT_BIT = 8;
28
29 struct Cmp {
operator ()__anon995640570111::Cmp30 bool operator()(const uint32_t& lhs, const uint32_t& rhs) const
31 {
32 return lhs > rhs;
33 }
34 };
35 } // namespace
36
37 namespace OHOS {
38 namespace NWeb {
39
40 // static
GetInstance()41 WebClipboardController& WebClipboardController::GetInstance()
42 {
43 static WebClipboardController instance;
44 return instance;
45 }
46
SplitHtml(std::shared_ptr<std::string> html)47 std::shared_ptr<MiscServices::PasteData> WebClipboardController::SplitHtml(std::shared_ptr<std::string> html) noexcept
48 {
49 std::vector<std::pair<std::string, uint32_t>> matchVec = SplitHtmlWithImgLabel(html);
50 std::map<std::string, std::vector<uint8_t>> imgSrcMap = SplitHtmlWithImgSrcLabel(matchVec);
51 std::shared_ptr<MiscServices::PasteData> pasteData = BuildPasteData(html, imgSrcMap);
52 return pasteData;
53 }
54
RebuildHtml(std::shared_ptr<MiscServices::PasteData> pasteData)55 std::shared_ptr<std::string> WebClipboardController::RebuildHtml(
56 std::shared_ptr<MiscServices::PasteData> pasteData) noexcept
57 {
58 std::vector<std::shared_ptr<MiscServices::PasteDataRecord>> pasteDataRecords = pasteData->AllRecords();
59 std::shared_ptr<std::string> htmlData;
60 std::map<uint32_t, std::pair<std::string, std::string>, Cmp> replaceUris;
61
62 for (auto& item : pasteDataRecords) {
63 std::shared_ptr<std::string> html = item->GetHtmlText();
64 if (html) {
65 htmlData = html;
66 }
67 std::shared_ptr<OHOS::Uri> uri = item->GetUri();
68 std::shared_ptr<MiscServices::MineCustomData> customData = item->GetCustomData();
69 if (!uri || !customData) {
70 continue;
71 }
72 std::map<std::string, std::vector<uint8_t>> customItemData = customData->GetItemData();
73 for (auto& itemData : customItemData) {
74 for (uint32_t i = 0; i < itemData.second.size(); i += FOUR_BYTES) {
75 uint32_t offset = static_cast<uint32_t>(itemData.second[i]) |
76 static_cast<uint32_t>(itemData.second[i + 1] << 8) |
77 static_cast<uint32_t>(itemData.second[i + 2] << 16) |
78 static_cast<uint32_t>(itemData.second[i + 3] << 24);
79 replaceUris[offset] = std::make_pair(uri->ToString(), itemData.first);
80 }
81 }
82 }
83
84 RemoveAllRecord(pasteData);
85 for (auto& replaceUri : replaceUris) {
86 htmlData->replace(replaceUri.first, replaceUri.second.second.size(), replaceUri.second.first);
87 }
88 pasteData->AddHtmlRecord(*htmlData);
89 return htmlData;
90 }
91
SplitHtmlWithImgLabel(const std::shared_ptr<std::string> html)92 std::vector<std::pair<std::string, uint32_t>> WebClipboardController::SplitHtmlWithImgLabel(
93 const std::shared_ptr<std::string> html) noexcept
94 {
95 std::smatch results;
96 std::string pattern(IMG_TAG_PATTERN);
97 std::regex r(pattern);
98 std::string::const_iterator iterStart = html->begin();
99 std::string::const_iterator iterEnd = html->end();
100 std::vector<std::pair<std::string, uint32_t>> matchVec;
101
102 while (std::regex_search(iterStart, iterEnd, results, r)) {
103 std::string tmp = results[0];
104 iterStart = results[0].second;
105 uint32_t offset = static_cast<uint32_t>(results[0].first - html->begin());
106
107 matchVec.emplace_back(std::make_pair(tmp, offset));
108 }
109
110 return matchVec;
111 }
112
SplitHtmlWithImgSrcLabel(const std::vector<std::pair<std::string,uint32_t>> & matchVec)113 std::map<std::string, std::vector<uint8_t>> WebClipboardController::SplitHtmlWithImgSrcLabel(
114 const std::vector<std::pair<std::string, uint32_t>>& matchVec) noexcept
115 {
116 std::map<std::string, std::vector<uint8_t>> res;
117 std::smatch match;
118 std::regex re(IMG_TAG_SRC_PATTERN);
119 for (auto& node : matchVec) {
120 std::string::const_iterator iterStart = node.first.begin();
121 std::string::const_iterator iterEnd = node.first.end();
122
123 while (std::regex_search(iterStart, iterEnd, match, re)) {
124 std::string tmp = match[0];
125 iterStart = match[0].second;
126 uint32_t offset = static_cast<uint32_t>(match[0].first - node.first.begin());
127 tmp = tmp.substr(IMG_TAG_SRC_HEAD.size());
128 tmp.pop_back();
129 if (!IsLocalURI(tmp)) {
130 continue;
131 }
132 offset += IMG_TAG_SRC_HEAD.size() + node.second;
133 for (uint32_t i = 0; i < FOUR_BYTES; i++) {
134 res[tmp].emplace_back((offset >> (EIGHT_BIT * i)) & 0xff);
135 }
136 }
137 }
138 return res;
139 }
140
BuildPasteData(std::shared_ptr<std::string> html,const std::map<std::string,std::vector<uint8_t>> & imgSrcMap)141 std::shared_ptr<MiscServices::PasteData> WebClipboardController::BuildPasteData(
142 std::shared_ptr<std::string> html, const std::map<std::string, std::vector<uint8_t>>& imgSrcMap) noexcept
143 {
144 std::shared_ptr<MiscServices::PasteData> pasteData = std::make_shared<MiscServices::PasteData>();
145 pasteData->AddHtmlRecord(*html);
146 for (auto& item : imgSrcMap) {
147 MiscServices::PasteDataRecord::Builder builder(MiscServices::MIMETYPE_TEXT_URI);
148 auto uri = std::make_shared<OHOS::Uri>(item.first);
149 builder.SetUri(uri);
150 auto customData = std::make_shared<MiscServices::MineCustomData>();
151
152 customData->AddItemData(item.first, item.second);
153 builder.SetCustomData(customData);
154 auto record = builder.Build();
155 pasteData->AddRecord(record);
156 }
157 return pasteData;
158 }
159
RemoveAllRecord(std::shared_ptr<MiscServices::PasteData> pasteData)160 void WebClipboardController::RemoveAllRecord(std::shared_ptr<MiscServices::PasteData> pasteData) noexcept
161 {
162 std::size_t recordCount = pasteData->GetRecordCount();
163 for (uint32_t i = 0; i < recordCount; i++) {
164 pasteData->RemoveRecordAt(i);
165 }
166 }
167
IsLocalURI(std::string & uri)168 bool WebClipboardController::IsLocalURI(std::string& uri) noexcept
169 {
170 return uri.substr(0, IMG_LOCAL_URI.size()) == IMG_LOCAL_URI || uri.find(IMG_LOCAL_PATH) == std::string::npos;
171 }
172 } // namespace NWeb
173 } // namespace OHOS
174