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 "udmf_impl.h"
17
18#include <unordered_map>
19#include <variant>
20
21#include "html.h"
22#include "image.h"
23#include "link.h"
24#include "summary_napi.h"
25#include "system_defined_form.h"
26#include "system_defined_pixelmap.h"
27#include "text.h"
28#include "plain_text.h"
29#include "udmf_client.h"
30#include "application_defined_record.h"
31#include "unified_data.h"
32#include "unified_data_napi.h"
33#include "unified_types.h"
34#include "video.h"
35#include "native_engine/native_engine.h"
36#include "frameworks/bridge/common/utils/engine_helper.h"
37#include "frameworks/bridge/common/utils/utils.h"
38#include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
39#include "js_native_api_types.h"
40
41#include "base/image/file_uri_helper.h"
42#include "base/utils/utils.h"
43#include "core/common/udmf/unified_data.h"
44#include "ndk_data_conversion.h"
45namespace OHOS::Ace {
46UdmfClient* UdmfClient::GetInstance()
47{
48    static UdmfClientImpl instance;
49    return &instance;
50}
51
52RefPtr<UnifiedData> UdmfClientImpl::CreateUnifiedData()
53{
54    return AceType::DynamicCast<UnifiedData>(AceType::MakeRefPtr<UnifiedDataImpl>());
55}
56
57RefPtr<UnifiedData> UdmfClientImpl::TransformUnifiedData(napi_value napiValue)
58{
59    auto engine = EngineHelper::GetCurrentEngine();
60    CHECK_NULL_RETURN(engine, nullptr);
61    NativeEngine* nativeEngine = engine->GetNativeEngine();
62    napi_env env = reinterpret_cast<napi_env>(nativeEngine);
63    void* native = nullptr;
64    napi_unwrap(env, napiValue, &native);
65    auto* unifiedData = reinterpret_cast<UDMF::UnifiedDataNapi*>(native);
66    CHECK_NULL_RETURN(unifiedData, nullptr);
67    CHECK_NULL_RETURN(unifiedData->value_, nullptr);
68    auto udData = AceType::MakeRefPtr<UnifiedDataImpl>();
69    udData->SetUnifiedData(unifiedData->value_);
70    return udData;
71}
72
73napi_value UdmfClientImpl::TransformUdmfUnifiedData(RefPtr<UnifiedData>& UnifiedData)
74{
75    auto engine = EngineHelper::GetCurrentEngine();
76    CHECK_NULL_RETURN(engine, nullptr);
77    NativeEngine* nativeEngine = engine->GetNativeEngine();
78    napi_env env = reinterpret_cast<napi_env>(nativeEngine);
79    auto unifiedData = AceType::DynamicCast<UnifiedDataImpl>(UnifiedData)->GetUnifiedData();
80    CHECK_NULL_RETURN(unifiedData, nullptr);
81    napi_value dataVal = nullptr;
82    UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, dataVal);
83    CHECK_NULL_RETURN(dataVal, nullptr);
84    return dataVal;
85}
86
87void* UdmfClientImpl::TransformUnifiedDataPtr(RefPtr<UnifiedData>& unifiedDataImpl)
88{
89    CHECK_NULL_RETURN(unifiedDataImpl, nullptr);
90    std::shared_ptr<UDMF::UnifiedData> unifiedData =
91        AceType::DynamicCast<UnifiedDataImpl>(unifiedDataImpl)->GetUnifiedData();
92    CHECK_NULL_RETURN(unifiedData, nullptr);
93    return unifiedData.get();
94}
95
96RefPtr<UnifiedData> UdmfClientImpl::TransformUnifiedDataForNative(void* rawData)
97{
98    CHECK_NULL_RETURN(rawData, nullptr);
99    auto udData = AceType::MakeRefPtr<UnifiedDataImpl>();
100    auto udmfData = static_cast<OH_UdmfData*>(rawData);
101    CHECK_NULL_RETURN(udmfData, nullptr);
102    auto unifiedData = std::make_shared<UDMF::UnifiedData>();
103    auto status = OHOS::UDMF::NdkDataConversion::GetNativeUnifiedData(udmfData, unifiedData);
104    if (status) {
105        return nullptr;
106    }
107
108    udData->SetUnifiedData(unifiedData);
109    return udData;
110}
111
112napi_value UdmfClientImpl::TransformSummary(std::map<std::string, int64_t>& summary)
113{
114    auto engine = EngineHelper::GetCurrentEngine();
115    CHECK_NULL_RETURN(engine, nullptr);
116    NativeEngine* nativeEngine = engine->GetNativeEngine();
117    napi_env env = reinterpret_cast<napi_env>(nativeEngine);
118    std::shared_ptr<UDMF::Summary> udmfSummary = std::make_shared<UDMF::Summary>();
119    CHECK_NULL_RETURN(udmfSummary, nullptr);
120    udmfSummary->totalSize = 0;
121    for (auto element : summary) {
122        udmfSummary->totalSize += element.second;
123    }
124    udmfSummary->summary = std::move(summary);
125    napi_value dataVal = nullptr;
126    UDMF::SummaryNapi::NewInstance(env, udmfSummary, dataVal);
127    CHECK_NULL_RETURN(dataVal, nullptr);
128    return dataVal;
129}
130
131int32_t UdmfClientImpl::SetData(const RefPtr<UnifiedData>& unifiedData, std::string& key)
132{
133    auto& client = UDMF::UdmfClient::GetInstance();
134    UDMF::CustomOption udCustomOption;
135    udCustomOption.intention = UDMF::Intention::UD_INTENTION_DRAG;
136    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
137    CHECK_NULL_RETURN(udData, UDMF::E_ERROR);
138    int32_t ret = client.SetData(udCustomOption, *udData->GetUnifiedData(), key);
139    return ret;
140}
141
142int32_t UdmfClientImpl::GetData(const RefPtr<UnifiedData>& unifiedData, const std::string& key)
143{
144    auto& client = UDMF::UdmfClient::GetInstance();
145    UDMF::QueryOption queryOption;
146    queryOption.key = key;
147    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
148    CHECK_NULL_RETURN(udData, UDMF::E_ERROR);
149    int ret = client.GetData(queryOption, *udData->GetUnifiedData());
150    return ret;
151}
152
153int32_t UdmfClientImpl::GetSummary(std::string& key, std::map<std::string, int64_t>& summaryMap)
154{
155    auto& client = UDMF::UdmfClient::GetInstance();
156    UDMF::Summary summary;
157    UDMF::QueryOption queryOption;
158    queryOption.key = key;
159    int32_t ret = client.GetSummary(queryOption, summary);
160    summaryMap = summary.summary;
161    return ret;
162}
163
164bool UdmfClientImpl::GetRemoteStatus(std::string& key)
165{
166    auto& client = UDMF::UdmfClient::GetInstance();
167    bool isRemoteData = false;
168    UDMF::QueryOption queryOption;
169    queryOption.key = key;
170    int32_t ret = client.IsRemoteData(queryOption, isRemoteData);
171    if (ret != 0) {
172        // if ret is not 0, udmf client has not been sync, so return true to use remote getData.
173        return true;
174    }
175    return isRemoteData;
176}
177
178int64_t UnifiedDataImpl::GetSize()
179{
180    CHECK_NULL_RETURN(unifiedData_, 0);
181    return unifiedData_->GetRecords().size();
182}
183
184std::shared_ptr<UDMF::UnifiedData> UnifiedDataImpl::GetUnifiedData()
185{
186    if (unifiedData_ == nullptr) {
187        unifiedData_ = std::make_shared<UDMF::UnifiedData>();
188    }
189    return unifiedData_;
190}
191
192void UnifiedDataImpl::SetUnifiedData(std::shared_ptr<UDMF::UnifiedData> unifiedData)
193{
194    unifiedData_ = unifiedData;
195}
196
197void UdmfClientImpl::AddFormRecord(
198    const RefPtr<UnifiedData>& unifiedData, int32_t formId, const RequestFormInfo& cardInfo)
199{
200    auto formRecord = std::make_shared<UDMF::SystemDefinedForm>();
201    formRecord->SetFormId(formId);
202    formRecord->SetFormName(cardInfo.cardName);
203    formRecord->SetBundleName(cardInfo.bundleName);
204    formRecord->SetAbilityName(cardInfo.abilityName);
205    formRecord->SetModule(cardInfo.moduleName);
206    formRecord->SetType(UDMF::UDType::SYSTEM_DEFINED_FORM);
207
208    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
209    CHECK_NULL_VOID(udData);
210    CHECK_NULL_VOID(udData->GetUnifiedData());
211    udData->GetUnifiedData()->AddRecord(formRecord);
212}
213
214void UdmfClientImpl::AddLinkRecord(
215    const RefPtr<UnifiedData>& unifiedData, const std::string& url, const std::string& description)
216{
217    auto record = std::make_shared<UDMF::Link>(url, description);
218
219    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
220    CHECK_NULL_VOID(udData);
221    CHECK_NULL_VOID(udData->GetUnifiedData());
222    udData->GetUnifiedData()->AddRecord(record);
223}
224
225void UdmfClientImpl::GetLinkRecord(
226    const RefPtr<UnifiedData>& unifiedData, std::string& url, std::string& description)
227{
228    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
229    CHECK_NULL_VOID(udData);
230    CHECK_NULL_VOID(udData->GetUnifiedData());
231    auto records = udData->GetUnifiedData()->GetRecords();
232    for (auto record : records) {
233        UDMF::UDType type = record->GetType();
234        if (type == UDMF::UDType::HYPERLINK) {
235            UDMF::Link* link = reinterpret_cast<UDMF::Link*>(record.get());
236            url = link->GetUrl();
237            description = link->GetDescription();
238            return;
239        }
240    }
241}
242
243void UdmfClientImpl::AddHtmlRecord(
244    const RefPtr<UnifiedData>& unifiedData, const std::string& htmlContent, const std::string& plainContent)
245{
246    auto htmlRecord = std::make_shared<UDMF::Html>(htmlContent, plainContent);
247
248    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
249    CHECK_NULL_VOID(udData);
250    CHECK_NULL_VOID(udData->GetUnifiedData());
251    if (!plainContent.empty() || !htmlContent.empty()) {
252        udData->GetUnifiedData()->AddRecord(htmlRecord);
253    }
254}
255
256void UdmfClientImpl::GetHtmlRecord(
257    const RefPtr<UnifiedData>& unifiedData, std::string& htmlContent, std::string& plainContent)
258{
259    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
260    CHECK_NULL_VOID(udData);
261    CHECK_NULL_VOID(udData->GetUnifiedData());
262    auto records = udData->GetUnifiedData()->GetRecords();
263    for (auto record : records) {
264        UDMF::UDType type = record->GetType();
265        if (type == UDMF::UDType::HTML) {
266            UDMF::Html* html = reinterpret_cast<UDMF::Html*>(record.get());
267            plainContent = html->GetPlainContent();
268            htmlContent = html->GetHtmlContent();
269            return;
270        }
271    }
272}
273
274void UdmfClientImpl::AddPixelMapRecord(const RefPtr<UnifiedData>& unifiedData, std::vector<uint8_t>& data,
275    PixelMapRecordDetails& details)
276{
277    auto record = std::make_shared<UDMF::SystemDefinedPixelMap>(data);
278    UDMF::UDDetails uDetails = {
279        { "width", details.width },
280        { "height", details.height },
281        { "pixel-format", static_cast<int32_t>(details.pixelFormat) },
282        { "alpha-type", static_cast<int32_t>(details.alphaType) } };
283    record->SetDetails(uDetails);
284    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
285    CHECK_NULL_VOID(udData);
286    CHECK_NULL_VOID(udData->GetUnifiedData());
287    udData->GetUnifiedData()->AddRecord(record);
288}
289
290void UdmfClientImpl::AddImageRecord(const RefPtr<UnifiedData>& unifiedData, const std::string& uri)
291{
292    auto record = std::make_shared<UDMF::Image>(uri);
293
294    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
295    CHECK_NULL_VOID(udData);
296    CHECK_NULL_VOID(udData->GetUnifiedData());
297    udData->GetUnifiedData()->AddRecord(record);
298}
299
300void UdmfClientImpl::AddPlainTextRecord(const RefPtr<UnifiedData>& unifiedData, const std::string& selectedStr)
301{
302    auto record = std::make_shared<UDMF::PlainText>(selectedStr, "");
303
304    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
305    CHECK_NULL_VOID(udData);
306    CHECK_NULL_VOID(udData->GetUnifiedData());
307    udData->GetUnifiedData()->AddRecord(record);
308}
309
310std::string UdmfClientImpl::GetSinglePlainTextRecord(const RefPtr<UnifiedData>& unifiedData)
311{
312    std::string str = "";
313    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
314    CHECK_NULL_RETURN(udData, str);
315    CHECK_NULL_RETURN(udData->GetUnifiedData(), str);
316    auto records = udData->GetUnifiedData()->GetRecords();
317    if (records.size() >= 1 && records[0]->GetType() == UDMF::UDType::PLAIN_TEXT) {
318        UDMF::PlainText* plainText = reinterpret_cast<UDMF::PlainText*>(records[0].get());
319        str = plainText->GetContent();
320    }
321    return str;
322}
323
324bool UdmfClientImpl::AddFileUriRecord(const RefPtr<UnifiedData>& unifiedData, std::vector<std::string>& uri)
325{
326    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
327    CHECK_NULL_RETURN(udData, false);
328    CHECK_NULL_RETURN(udData->GetUnifiedData(), false);
329
330    for (std::string u : uri) {
331        LOGI("DragDrop event AddFileUriRecord, uri:%{public}s", u.c_str());
332        auto record = std::make_shared<UDMF::Image>(u);
333        udData->GetUnifiedData()->AddRecord(record);
334    }
335
336    return true;
337}
338
339bool UdmfClientImpl::GetFileUriRecord(const RefPtr<UnifiedData>& unifiedData, std::vector<std::string>& uri)
340{
341    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
342    CHECK_NULL_RETURN(udData, false);
343    CHECK_NULL_RETURN(udData->GetUnifiedData(), false);
344    auto records = udData->GetUnifiedData()->GetRecords();
345
346    for (auto record : records) {
347        UDMF::UDType type = record->GetType();
348        if (type == UDMF::UDType::IMAGE || type == UDMF::UDType::AUDIO ||
349            type == UDMF::UDType::VIDEO || type == UDMF::UDType::FILE) {
350            UDMF::File* file = reinterpret_cast<UDMF::File*>(record.get());
351            if (file) {
352                uri.emplace_back(file->GetUri());
353                LOGI("DragDrop event GetFileUri, uri:%{public}s", file->GetUri().c_str());
354            } else {
355                LOGE("DragDrop event GetFileUri file is null");
356            }
357        }
358    }
359    return true;
360}
361
362std::vector<std::string> UdmfClientImpl::GetPlainTextRecords(const RefPtr<UnifiedData>& unifiedData)
363{
364    std::vector<std::string> textRecords;
365    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
366    CHECK_NULL_RETURN(udData, textRecords);
367    CHECK_NULL_RETURN(udData->GetUnifiedData(), textRecords);
368    auto records = udData->GetUnifiedData()->GetRecords();
369    for (const auto& record : records) {
370        UDMF::UDType type = record->GetType();
371        if (type == UDMF::UDType::PLAIN_TEXT) {
372            UDMF::PlainText* plainText = reinterpret_cast<UDMF::PlainText*>(record.get());
373            std::string str = plainText->GetContent();
374            textRecords.emplace_back(str);
375        }
376    }
377    return textRecords;
378}
379
380int32_t UdmfClientImpl::GetVideoRecordUri(const RefPtr<UnifiedData>& unifiedData, std::string& uri)
381{
382    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
383    CHECK_NULL_RETURN(udData, UDMF::E_ERROR);
384    CHECK_NULL_RETURN(udData->GetUnifiedData(), UDMF::E_ERROR);
385    auto records = udData->GetUnifiedData()->GetRecords();
386    if (records.size() == 0) {
387        return UDMF::E_ERROR;
388    }
389    auto video = static_cast<UDMF::Video*>(records[0].get());
390    uri = video->GetUri();
391    return 0;
392}
393
394std::pair<int32_t, std::string> UdmfClientImpl::GetErrorInfo(int32_t errorCode)
395{
396    switch (errorCode) {
397        case UDMF::E_NOT_FOUND:
398            return { ERROR_CODE_DRAG_DATA_NOT_FOUND, "GetData failed, data not found." };
399        default:
400            return { ERROR_CODE_DRAG_DATA_ERROR, "GetData failed, data error." };
401    }
402}
403
404void UdmfClientImpl::AddSpanStringRecord(
405    const RefPtr<UnifiedData>& unifiedData, std::vector<uint8_t>& data)
406{
407    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
408    CHECK_NULL_VOID(udData);
409    CHECK_NULL_VOID(udData->GetUnifiedData());
410    auto record = std::make_shared<UDMF::ApplicationDefinedRecord>("OPENHARMONY_STYLED_STRING_UDMF", data);
411    udData->GetUnifiedData()->AddRecord(record);
412}
413
414std::vector<uint8_t> UdmfClientImpl::GetSpanStringRecord(const RefPtr<UnifiedData>& unifiedData)
415{
416    std::vector<uint8_t> arr;
417    auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
418    CHECK_NULL_RETURN(udData, arr);
419    CHECK_NULL_RETURN(udData->GetUnifiedData(), arr);
420    auto records = udData->GetUnifiedData()->GetRecords();
421    for (auto record: records) {
422        UDMF::UDType type = record->GetType();
423        if (type == UDMF::UDType::APPLICATION_DEFINED_RECORD) {
424            UDMF::ApplicationDefinedRecord* app = reinterpret_cast<UDMF::ApplicationDefinedRecord*>(record.get());
425            if (app->GetApplicationDefinedType() == "OPENHARMONY_STYLED_STRING_UDMF") {
426                arr = app->GetRawData();
427                return arr;
428            }
429        }
430    }
431    return arr;
432}
433} // namespace OHOS::Ace
434