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 <regex>
17 #include "file_uri.h"
18 #include "pasteboard_web_controller.h"
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 ()__anone07300040111::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 MiscServices {
39
40 // static
GetInstance()41 PasteboardWebController& PasteboardWebController::GetInstance()
42 {
43 static PasteboardWebController instance;
44 return instance;
45 }
46
SplitHtml(std::shared_ptr<std::string> html)47 std::shared_ptr<PasteData> PasteboardWebController::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<PasteData> pasteData = BuildPasteData(html, imgSrcMap);
52 return pasteData;
53 }
54
RebuildHtml(std::shared_ptr<PasteData> pasteData)55 std::shared_ptr<std::string> PasteboardWebController::RebuildHtml(
56 std::shared_ptr<PasteData> pasteData) noexcept
57 {
58 std::vector<std::shared_ptr<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 std::string oriPath = replaceUri.second.first;
87 AppFileService::ModuleFileUri::FileUri fileUri(oriPath);
88 std::string path = PasteData::FILE_SCHEME_PREFIX + fileUri.GetRealPath();
89 htmlData->replace(replaceUri.first, replaceUri.second.second.size(), path);
90 }
91 pasteData->AddHtmlRecord(*htmlData);
92 return htmlData;
93 }
94
SplitHtmlWithImgLabel(const std::shared_ptr<std::string> html)95 std::vector<std::pair<std::string, uint32_t>> PasteboardWebController::SplitHtmlWithImgLabel(
96 const std::shared_ptr<std::string> html) noexcept
97 {
98 std::smatch results;
99 std::string pattern(IMG_TAG_PATTERN);
100 std::regex r(pattern);
101 std::string::const_iterator iterStart = html->begin();
102 std::string::const_iterator iterEnd = html->end();
103 std::vector<std::pair<std::string, uint32_t>> matchVec;
104
105 while (std::regex_search(iterStart, iterEnd, results, r)) {
106 std::string tmp = results[0];
107 iterStart = results[0].second;
108 uint32_t offset = static_cast<uint32_t>(results[0].first - html->begin());
109
110 matchVec.emplace_back(std::make_pair(tmp, offset));
111 }
112
113 return matchVec;
114 }
115
SplitHtmlWithImgSrcLabel(const std::vector<std::pair<std::string,uint32_t>> & matchVec)116 std::map<std::string, std::vector<uint8_t>> PasteboardWebController::SplitHtmlWithImgSrcLabel(
117 const std::vector<std::pair<std::string, uint32_t>>& matchVec) noexcept
118 {
119 std::map<std::string, std::vector<uint8_t>> res;
120 std::smatch match;
121 std::regex re(IMG_TAG_SRC_PATTERN);
122 for (auto& node : matchVec) {
123 std::string::const_iterator iterStart = node.first.begin();
124 std::string::const_iterator iterEnd = node.first.end();
125
126 while (std::regex_search(iterStart, iterEnd, match, re)) {
127 std::string tmp = match[0];
128 iterStart = match[0].second;
129 uint32_t offset = static_cast<uint32_t>(match[0].first - node.first.begin());
130 tmp = tmp.substr(IMG_TAG_SRC_HEAD.size());
131 tmp.pop_back();
132 if (!IsLocalURI(tmp)) {
133 continue;
134 }
135 offset += IMG_TAG_SRC_HEAD.size() + node.second;
136 for (uint32_t i = 0; i < FOUR_BYTES; i++) {
137 res[tmp].emplace_back((offset >> (EIGHT_BIT * i)) & 0xff);
138 }
139 }
140 }
141 return res;
142 }
143
BuildPasteData(std::shared_ptr<std::string> html,const std::map<std::string,std::vector<uint8_t>> & imgSrcMap)144 std::shared_ptr<PasteData> PasteboardWebController::BuildPasteData(
145 std::shared_ptr<std::string> html, const std::map<std::string, std::vector<uint8_t>>& imgSrcMap) noexcept
146 {
147 std::shared_ptr<PasteData> pasteData = std::make_shared<PasteData>();
148 pasteData->AddHtmlRecord(*html);
149 for (auto& item : imgSrcMap) {
150 PasteDataRecord::Builder builder(MiscServices::MIMETYPE_TEXT_URI);
151 auto uri = std::make_shared<OHOS::Uri>(item.first);
152 builder.SetUri(uri);
153 auto customData = std::make_shared<MiscServices::MineCustomData>();
154
155 customData->AddItemData(item.first, item.second);
156 builder.SetCustomData(customData);
157 auto record = builder.Build();
158 pasteData->AddRecord(record);
159 }
160 return pasteData;
161 }
162
RemoveAllRecord(std::shared_ptr<PasteData> pasteData)163 void PasteboardWebController::RemoveAllRecord(std::shared_ptr<PasteData> pasteData) noexcept
164 {
165 std::size_t recordCount = pasteData->GetRecordCount();
166 for (uint32_t i = 0; i < recordCount; i++) {
167 pasteData->RemoveRecordAt(i);
168 }
169 }
170
IsLocalURI(std::string & uri)171 bool PasteboardWebController::IsLocalURI(std::string& uri) noexcept
172 {
173 return uri.substr(0, IMG_LOCAL_URI.size()) == IMG_LOCAL_URI || uri.find(IMG_LOCAL_PATH) == std::string::npos;
174 }
175 } // namespace MiscServices
176 } // namespace OHOS
177