1/*
2 * Copyright (c) 2024 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 <set>
16#include <map>
17#include <cstring>
18#include <string>
19#include <thread>
20#include "securec.h"
21#include "refbase.h"
22#include "scan_callback.h"
23#include "scan_manager_client.h"
24#include "scan_constant.h"
25#include "scan_log.h"
26#include "scanner_info.h"
27#include "scan_option_value.h"
28#include "ohscan.h"
29
30using namespace OHOS::Scan;
31
32struct ValueMap {
33    uint32_t valueType;
34    int32_t optionIndex;
35    std::set<std::string> numList;
36    std::set<std::string> strList;
37};
38
39struct ScanParaTable {
40    std::vector<std::string> titBuff;
41    std::vector<std::string> desBuff;
42    std::vector<std::string> rangesBuff;
43    int32_t lengthBuff;
44};
45
46static constexpr int32_t SCAN_INT_TYPE = 1;
47static constexpr int32_t SCAN_STRING_TYPE = 3;
48static constexpr int32_t SCAN_NUM_LIST = 2;
49static constexpr int32_t SCAN_STRING_LIST = 3;
50static std::map<std::string, std::map<int, ValueMap>> g_valueMap;
51static std::map<std::string, Scan_ScannerOptions* > g_scanParaTables;
52static bool g_isListening = false;
53static const char* GET_SCANNER_DEVICE_LIST = "GET_SCANNER_DEVICE_LIST";
54static Scan_ScannerDiscoveryCallback g_discoverCallback = nullptr;
55
56
57static inline void FreeDeviceListMemory(Scan_ScannerDevice** devices, int32_t deviceCount)
58{
59    for (int32_t i = 0; i < deviceCount; i++) {
60        DELETE_AND_NULLIFY(devices[i])
61    }
62    DELETE_ARRAY_AND_NULLIFY(devices)
63}
64
65auto callbackFunction = [](std::vector<ScanDeviceInfo> &infos) {
66    int32_t deviceCount = infos.size();
67    SCAN_HILOGI("deviceCount : [%{public}d]", deviceCount);
68    if (deviceCount == 0) {
69        SCAN_HILOGE("not found");
70        g_discoverCallback(nullptr, 0);
71        return;
72    }
73    Scan_ScannerDevice** devices = new (std::nothrow) Scan_ScannerDevice* [deviceCount];
74    if (devices == nullptr) {
75        SCAN_HILOGE("devices is a nullptr");
76        g_discoverCallback(nullptr, 0);
77    }
78    int32_t devicesMemSize = deviceCount * sizeof(Scan_ScannerDevice*);
79    if (memset_s(devices, devicesMemSize, 0, devicesMemSize) != 0) {
80        SCAN_HILOGW("memset_s fail");
81        FreeDeviceListMemory(devices, 0);
82        g_discoverCallback(nullptr, 0);
83        return;
84    }
85    for (int i = 0; i < deviceCount; i++) {
86        Scan_ScannerDevice* device = new (std::nothrow) Scan_ScannerDevice();
87        if (device == nullptr) {
88            SCAN_HILOGE("devices is a nullptr");
89            deviceCount = i;
90            break;
91        }
92        if (memset_s(device, sizeof(Scan_ScannerDevice), 0, sizeof(Scan_ScannerDevice)) != 0) {
93            SCAN_HILOGW("memset_s fail");
94            deviceCount = i;
95            break;
96        }
97        device->scannerId = infos[i].GetDeviceId().c_str();
98        device->manufacturer = infos[i].GetManufacturer().c_str();
99        device->model = infos[i].GetModel().c_str();
100        device->serialNumber = infos[i].GetSerialNumber().c_str();
101        device->discoverMode = infos[i].GetDiscoverMode().c_str();
102        devices[i] = device;
103    }
104    g_discoverCallback(devices, deviceCount);
105    FreeDeviceListMemory(devices, deviceCount);
106};
107
108namespace {
109int32_t GetScanParaDesc(const std::string &deviceId, ScanOptionValue &value)
110{
111    auto client = ScanManagerClient::GetInstance();
112    ScanOptionDescriptor desc;
113    int32_t ret = client->GetScanOptionDesc(deviceId, 0, desc);
114    uint32_t optionType = desc.GetOptionType();
115    int32_t optionSize = desc.GetOptionSize();
116    value.SetScanOptionValueType(static_cast<ScanOptionValueType>(optionType));
117    value.SetValueSize(optionSize);
118    int32_t info = 0;
119    ret = client->OpScanOptionValue(deviceId, 0, SCAN_ACTION_GET_VALUE, value, info);
120    return ret;
121}
122
123int32_t GetScanParaValues(const std::string &deviceId, ScanOptionValue &value, ScanParaTable &paraTable)
124{
125    std::set<uint32_t> dataType = {SCAN_INT_TYPE, SCAN_STRING_TYPE};
126    int32_t lengthBuff = 0;
127    for (int i = 1 ; i < value.GetNumValue(); i++) {
128        ScanOptionDescriptor desc;
129        auto client = ScanManagerClient::GetInstance();
130        int32_t ret = client->GetScanOptionDesc(deviceId, i, desc);
131        if (ret != SCAN_ERROR_NONE) {
132            SCAN_HILOGE("Failed to get scanner parameters.");
133            return ret;
134        }
135        if (!dataType.count(desc.GetOptionType())) {
136            continue;
137        }
138        if (desc.GetOptionConstraintType() == SCAN_NUM_LIST) {
139            std::string tmp;
140            std::vector<std::int32_t> optionConstraintNumber;
141            desc.GetOptionConstraintNumber(optionConstraintNumber);
142            for (auto t : optionConstraintNumber) {
143                std::string numStr = std::to_string(t);
144                tmp.append(numStr).append(",");
145                g_valueMap[deviceId][lengthBuff].numList.insert(numStr);
146                g_valueMap[deviceId][lengthBuff].valueType = SCAN_INT_TYPE;
147            }
148            tmp.pop_back();
149            paraTable.rangesBuff.emplace_back(tmp);
150        } else if (desc.GetOptionConstraintType() == SCAN_STRING_LIST) {
151            std::string tmp;
152            std::vector<std::string> optionConstraintString;
153            desc.GetOptionConstraintString(optionConstraintString);
154            for (auto t : optionConstraintString) {
155                tmp.append(t).append(",");
156                g_valueMap[deviceId][lengthBuff].strList.insert(t);
157                g_valueMap[deviceId][lengthBuff].valueType = SCAN_STRING_TYPE;
158            }
159            tmp.pop_back();
160            paraTable.rangesBuff.emplace_back(tmp);
161        } else {
162            continue;
163        }
164        paraTable.titBuff.emplace_back(desc.GetOptionTitle());
165        paraTable.desBuff.emplace_back(desc.GetOptionDesc());
166        g_valueMap[deviceId][lengthBuff].optionIndex = i;
167        lengthBuff++;
168    }
169    paraTable.lengthBuff = lengthBuff;
170    return SCAN_ERROR_NONE;
171}
172
173void FreeScannerOptionsMemory(Scan_ScannerOptions* scannerOptions)
174{
175    if (scannerOptions == nullptr) {
176        SCAN_HILOGW("scannerOptions is a nullptr.");
177        return;
178    }
179
180    for (int i = 0; i < scannerOptions->optionCount; i++) {
181        DELETE_AND_NULLIFY(scannerOptions->titles[i])
182    }
183    DELETE_ARRAY_AND_NULLIFY(scannerOptions->titles)
184
185    for (int i = 0; i < scannerOptions->optionCount; i++) {
186        DELETE_AND_NULLIFY(scannerOptions->descriptions[i])
187    }
188    DELETE_ARRAY_AND_NULLIFY(scannerOptions->descriptions)
189
190    for (int i = 0; i < scannerOptions->optionCount; i++) {
191        DELETE_AND_NULLIFY(scannerOptions->ranges[i])
192    }
193    DELETE_ARRAY_AND_NULLIFY(scannerOptions->ranges)
194    DELETE_AND_NULLIFY(scannerOptions)
195}
196
197Scan_ScannerOptions* CreateScannerOptions(int32_t &optionCount)
198{
199    Scan_ScannerOptions* scannerOptions = new (std::nothrow) Scan_ScannerOptions();
200    if (scannerOptions == nullptr) {
201        SCAN_HILOGE("scannerOptions is a nullptr");
202        return nullptr;
203    }
204    int32_t scannerOptionsMemSize = sizeof(Scan_ScannerOptions);
205    if (memset_s(scannerOptions, scannerOptionsMemSize, 0, scannerOptionsMemSize) != 0) {
206        SCAN_HILOGW("memset_s fail");
207        FreeScannerOptionsMemory(scannerOptions);
208        return nullptr;
209    }
210    scannerOptions->titles = new (std::nothrow) char* [optionCount];
211    scannerOptions->descriptions = new (std::nothrow) char* [optionCount];
212    scannerOptions->ranges = new (std::nothrow) char* [optionCount];
213    scannerOptions->optionCount = optionCount;
214    if (scannerOptions->titles == nullptr || scannerOptions->descriptions == nullptr ||
215        scannerOptions->ranges == nullptr) {
216        FreeScannerOptionsMemory(scannerOptions);
217        return nullptr;
218    }
219    int32_t stringMemSize = optionCount * sizeof(char**);
220    if (memset_s(scannerOptions->titles, stringMemSize, 0, stringMemSize) != 0 ||
221        memset_s(scannerOptions->descriptions, stringMemSize, 0, stringMemSize) != 0 ||
222        memset_s(scannerOptions->ranges, stringMemSize, 0, stringMemSize) != 0) {
223            SCAN_HILOGW("memset_s fail");
224            FreeScannerOptionsMemory(scannerOptions);
225            return nullptr;
226    }
227    return scannerOptions;
228}
229
230bool CopySingleBuf(char* destBuf, const char* srcBuf, size_t bufferSize)
231{
232    if (destBuf == nullptr || srcBuf == nullptr) {
233        SCAN_HILOGW("CopySingleBuf new fail");
234        return false;
235    }
236    if (memset_s(destBuf, bufferSize, 0, bufferSize) != 0) {
237        SCAN_HILOGE("CopySingleBuf memset_s fail");
238        return false;
239    }
240    if (strncpy_s(destBuf, bufferSize, srcBuf, bufferSize) != 0) {
241        SCAN_HILOGE("CopySingleBuf strncpy_s fail");
242        return false;
243    }
244
245    return true;
246}
247
248bool MemSetScannerOptions(Scan_ScannerOptions* scannerOptions, int32_t &optionCount, ScanParaTable &paraTable)
249{
250    for (int i = 0; i < optionCount; i++) {
251        auto bufferSize = paraTable.titBuff[i].length() + 1;
252        char* titBuff = new(std::nothrow) char[bufferSize];
253        if (!CopySingleBuf(titBuff, paraTable.titBuff[i].c_str(), bufferSize)) {
254            if (titBuff != nullptr) {
255                delete[] titBuff;
256            }
257            return false;
258        }
259        scannerOptions->titles[i] = titBuff;
260
261        bufferSize = paraTable.desBuff[i].length() + 1;
262        char* desBuff = new (std::nothrow) char[bufferSize];
263        if (!CopySingleBuf(desBuff, paraTable.desBuff[i].c_str(), bufferSize)) {
264            if (desBuff != nullptr) {
265                delete[] desBuff;
266            }
267            return false;
268        }
269        scannerOptions->descriptions[i] = desBuff;
270
271        bufferSize = paraTable.rangesBuff[i].length() + 1;
272        char* rangesBuff = new (std::nothrow) char[bufferSize];
273        if (!CopySingleBuf(rangesBuff, paraTable.rangesBuff[i].c_str(), bufferSize)) {
274            if (rangesBuff != nullptr) {
275                delete[] rangesBuff;
276            }
277            return false;
278        }
279        scannerOptions->ranges[i] = rangesBuff;
280    }
281    return true;
282}
283
284Scan_ScannerOptions* GetScanParaValue(ScanParaTable &paraTable)
285{
286    int32_t optionCount = paraTable.lengthBuff;
287    if (optionCount <= 0) {
288        SCAN_HILOGE("optionCount <= 0");
289        return nullptr;
290    }
291    Scan_ScannerOptions* scannerOptions = CreateScannerOptions(optionCount);
292    if (scannerOptions == nullptr) {
293        SCAN_HILOGE("scannerOptions is a nullptr");
294        return nullptr;
295    }
296    if (!MemSetScannerOptions(scannerOptions, optionCount, paraTable)) {
297        SCAN_HILOGE("MemSetScannerOptions error");
298        FreeScannerOptionsMemory(scannerOptions);
299        return nullptr;
300    }
301    return scannerOptions;
302}
303}
304
305int32_t OH_Scan_Init()
306{
307    SCAN_HILOGI("Enter OH_Scan_Init");
308    auto client = ScanManagerClient::GetInstance();
309    int32_t scanVersion = 0;
310    int32_t ret = client->InitScan(scanVersion);
311    if (ret != SCAN_ERROR_NONE) {
312        SCAN_HILOGE("InitScan failed, ErrorCode: [%{public}d]", ret);
313        return ret;
314    } else {
315        SCAN_HILOGI("InitScan successfully");
316        return SCAN_ERROR_NONE;
317    }
318}
319
320int32_t OH_Scan_StartScannerDiscovery(Scan_ScannerDiscoveryCallback callback)
321{
322    g_discoverCallback = callback;
323    auto client = ScanManagerClient::GetInstance();
324    int32_t ret = SCAN_ERROR_NONE;
325    if (!g_isListening) {
326        OHOS::sptr<IScanCallback> call = new (std::nothrow) ScanCallback(callbackFunction);
327        if (call == nullptr) {
328            SCAN_HILOGE("call is null");
329            return SCAN_ERROR_GENERIC_FAILURE;
330        }
331        ret = client->On("", std::string(GET_SCANNER_DEVICE_LIST), call);
332        if (ret != SCAN_ERROR_NONE) {
333            SCAN_HILOGE("Failed to register event");
334            return ret;
335        }
336        g_isListening = true;
337    }
338    ret = client->GetScannerList();
339    if (ret != SCAN_ERROR_NONE) {
340        SCAN_HILOGE("Failed to GetScannerList");
341        return ret;
342    }
343    return SCAN_ERROR_NONE;
344}
345
346int32_t OH_Scan_OpenScanner(const char* scannerId)
347{
348    if (scannerId == nullptr) {
349        SCAN_HILOGE("Invalid parameter.");
350        return SCAN_ERROR_INVALID_PARAMETER;
351    }
352    auto client = ScanManagerClient::GetInstance();
353    int32_t ret = client->OpenScanner(std::string(scannerId));
354    if (ret != SCAN_ERROR_NONE) {
355        SCAN_HILOGE("OpenScanner failed, ErrorCode: [%{public}d]", ret);
356        return ret;
357    } else {
358        SCAN_HILOGI("OpenScanner successfully");
359        return SCAN_ERROR_NONE;
360    }
361}
362
363int32_t OH_Scan_CloseScanner(const char* scannerId)
364{
365    if (scannerId == nullptr) {
366        SCAN_HILOGE("Invalid parameter.");
367        return SCAN_ERROR_INVALID_PARAMETER;
368    }
369    auto client = ScanManagerClient::GetInstance();
370    int32_t ret = client->CloseScanner(std::string(scannerId));
371    if (ret != SCAN_ERROR_NONE) {
372        SCAN_HILOGE("CloseScanner failed, ErrorCode: [%{public}d]", ret);
373        return ret;
374    } else {
375        SCAN_HILOGI("CloseScanner successfully");
376        return SCAN_ERROR_NONE;
377    }
378}
379
380Scan_ScannerOptions* OH_Scan_GetScannerParameter(const char* scannerId, int32_t* errorCode)
381{
382    if (scannerId == nullptr || errorCode == nullptr) {
383        SCAN_HILOGE("Invalid parameter.");
384        return nullptr;
385    }
386    std::string deviceId = std::string(scannerId);
387    if (g_scanParaTables.find(deviceId) != g_scanParaTables.end()) {
388        SCAN_HILOGW("Device parameters have been obtained.");
389        *errorCode = SCAN_ERROR_NONE;
390        return g_scanParaTables[deviceId];
391    }
392    int32_t status = SCAN_ERROR_NONE;
393    ScanOptionValue value;
394    status = GetScanParaDesc(deviceId, value);
395    if (status != SCAN_ERROR_NONE) {
396        SCAN_HILOGE("Failed to get scanner ScanOptionValue value.");
397        *errorCode = status;
398        return nullptr;
399    }
400    ScanParaTable paraTable;
401    status = GetScanParaValues(deviceId, value, paraTable);
402    if (status != SCAN_ERROR_NONE) {
403        SCAN_HILOGE("Failed to get scanner ScanParaTable paraTable.");
404        *errorCode = status;
405        return nullptr;
406    }
407
408    Scan_ScannerOptions* scaParaOptions = GetScanParaValue(paraTable);
409    if (scaParaOptions == nullptr) {
410        *errorCode = SCAN_ERROR_GENERIC_FAILURE;
411        return nullptr;
412    }
413    g_scanParaTables[scannerId] = scaParaOptions;
414    *errorCode = SCAN_ERROR_NONE;
415    return scaParaOptions;
416}
417
418int32_t OH_Scan_SetScannerParameter(const char* scannerId, const int32_t option, const char* value)
419{
420    if (scannerId == nullptr || value == nullptr) {
421        SCAN_HILOGE("Invalid parameter.");
422        return SCAN_ERROR_INVALID_PARAMETER;
423    }
424    auto client = ScanManagerClient::GetInstance();
425    if (g_valueMap.find(scannerId) == g_valueMap.end() ||
426        g_valueMap[scannerId].find(option) == g_valueMap[scannerId].end()) {
427        SCAN_HILOGE("not exit this option: [%{public}d]", option);
428        return SCAN_ERROR_INVALID_PARAMETER;
429    }
430    auto t = g_valueMap[scannerId].find(option);
431    uint32_t valueType = g_valueMap[scannerId][option].valueType;
432    std::string strvalue = std::string(value);
433    ScanOptionValue optionValue;
434
435    if (valueType == SCAN_INT_TYPE) {
436        if (!t->second.numList.count(strvalue)) {
437            SCAN_HILOGE("not exit this value: [%{public}s]", strvalue.c_str());
438            return SCAN_ERROR_INVALID_PARAMETER;
439        }
440        optionValue.SetNumValue(std::stoi(strvalue));
441        optionValue.SetScanOptionValueType(SCAN_VALUE_NUM);
442    } else if (valueType == SCAN_STRING_TYPE) {
443        if (!t->second.strList.count(strvalue)) {
444            SCAN_HILOGE("not exit this value: [%{public}s]", strvalue.c_str());
445            return SCAN_ERROR_INVALID_PARAMETER;
446        }
447        optionValue.SetStrValue(strvalue);
448        optionValue.SetScanOptionValueType(SCAN_VALUE_STR);
449    } else {
450        SCAN_HILOGI("not exist this type ");
451        return SCAN_ERROR_GENERIC_FAILURE;
452    }
453
454    int32_t optionIndex = t->second.optionIndex;
455    int32_t info;
456    int32_t ret = client->OpScanOptionValue(std::string(scannerId),
457        optionIndex, SCAN_ACTION_SET_VALUE, optionValue, info);
458    if (ret != SCAN_ERROR_NONE) {
459        SCAN_HILOGE("SetScannerParameter failed, ErxrorCode: [%{public}d]", ret);
460        return ret;
461    } else {
462        SCAN_HILOGI("SetScannerParameter successfully");
463        return SCAN_ERROR_NONE;
464    }
465    return SCAN_ERROR_NONE;
466}
467
468int32_t OH_Scan_StartScan(const char* scannerId, bool batchMode)
469{
470    if (scannerId == nullptr) {
471        SCAN_HILOGE("Invalid parameter.");
472        return SCAN_ERROR_INVALID_PARAMETER;
473    }
474    auto client = ScanManagerClient::GetInstance();
475    int32_t ret = client->StartScan(std::string(scannerId), batchMode);
476    if (ret != SCAN_ERROR_NONE) {
477        SCAN_HILOGE("StartScan failed, ErxrorCode: [%{public}d]", ret);
478        return ret;
479    } else {
480        SCAN_HILOGI("StartScan successfully");
481        return SCAN_ERROR_NONE;
482    }
483}
484
485int32_t OH_Scan_CancelScan(const char* scannerId)
486{
487    if (scannerId == nullptr) {
488        SCAN_HILOGE("Invalid parameter.");
489        return SCAN_ERROR_INVALID_PARAMETER;
490    }
491    auto client = ScanManagerClient::GetInstance();
492    int32_t ret = client->CancelScan(std::string(scannerId));
493    if (ret != SCAN_ERROR_NONE) {
494        SCAN_HILOGE("CancelScan failed, ErxrorCode: [%{public}d]", ret);
495        return ret;
496    } else {
497        SCAN_HILOGI("CancelScan successfully");
498        return SCAN_ERROR_NONE;
499    }
500}
501
502int32_t OH_Scan_GetPictureScanProgress(const char* scannerId, Scan_PictureScanProgress* prog)
503{
504    if (prog == nullptr) {
505        SCAN_HILOGE("Invalid parameter.");
506        return SCAN_ERROR_INVALID_PARAMETER;
507    }
508    ScanProgress scanProg;
509    auto client = ScanManagerClient::GetInstance();
510    int32_t ret = client->GetScanProgress(std::string(scannerId), scanProg);
511    if (ret != SCAN_ERROR_NONE) {
512        SCAN_HILOGE("GetScanProgress failed, ErrorCode: [%{public}d]", ret);
513        return ret;
514    } else {
515        prog->progress = scanProg.GetScanProgress();
516        prog->fd = scanProg.GetScanPictureFd();
517        prog->isFinal = scanProg.GetIsFinal();
518        SCAN_HILOGI("GetScanProgress successfully");
519        return SCAN_ERROR_NONE;
520    }
521}
522
523int32_t OH_Scan_Exit()
524{
525    auto client = ScanManagerClient::GetInstance();
526    int32_t ret = client->ExitScan();
527    if (ret != SCAN_ERROR_NONE) {
528        SCAN_HILOGE("ExitScan failed, ErrorCode: [%{public}d]", ret);
529        return ret;
530    }
531    for (auto table : g_scanParaTables) {
532        FreeScannerOptionsMemory(table.second);
533    }
534    g_scanParaTables.clear();
535    if (g_isListening) {
536        client->Off("", std::string(GET_SCANNER_DEVICE_LIST));
537    }
538    SCAN_HILOGI("ExitScan successfully");
539    return SCAN_ERROR_NONE;
540}