1/*
2 * Copyright (c) 2022 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 "imsclient_fuzzer.h"
17
18#include <cstddef>
19#include <cstdint>
20#define private public
21#include "addcellularcalltoken_fuzzer.h"
22#include "cellular_call_service.h"
23#include "ims_call_client.h"
24#include "ims_call_proxy.h"
25#include "securec.h"
26#include "surface_utils.h"
27#include "system_ability_definition.h"
28
29using namespace OHOS::Telephony;
30namespace OHOS {
31static bool g_isInited = false;
32constexpr int32_t SERVICE_STATE_RUNNING = 1;
33constexpr int32_t IMS_CONFIG_ITEM_NUM = 2;
34enum {
35    NUM_ONE = 1,
36    NUM_TWO,
37    NUM_THREE,
38    NUM_FOUR,
39    NUM_FIVE,
40    NUM_SIX,
41    NUM_SEVEN,
42    NUM_EIGHT,
43};
44
45bool IsServiceInited()
46{
47    auto service = DelayedSingleton<CellularCallService>::GetInstance();
48    if (service == nullptr) {
49        return g_isInited;
50    }
51    if (service->GetServiceRunningState() != SERVICE_STATE_RUNNING) {
52        service->OnStart();
53    }
54    if (!g_isInited && service->GetServiceRunningState() == SERVICE_STATE_RUNNING) {
55        g_isInited = true;
56    }
57    return g_isInited;
58}
59
60void TestImsCallClientWithCallInfo(
61    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
62{
63    ImsCallInfo callInfo;
64    if (memset_s(&callInfo, sizeof(struct ImsCallInfo), 0x00, sizeof(struct ImsCallInfo)) != EOK) {
65        return;
66    }
67    size_t length = std::min(static_cast<size_t>(sizeof(callInfo.phoneNum) - 1), size);
68    std::string number(reinterpret_cast<const char *>(data), length);
69    int32_t mode = static_cast<int32_t>(size % NUM_TWO);
70    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
71    int32_t videoState = static_cast<int32_t>(size % NUM_THREE);
72    int32_t index = static_cast<int32_t>(size % NUM_THREE);
73    const char *cDtmfCode = number.c_str();
74    if (strcpy_s(callInfo.phoneNum, sizeof(callInfo.phoneNum), number.c_str()) != EOK) {
75        return;
76    }
77    callInfo.slotId = slotId;
78    callInfo.videoState = videoState;
79    callInfo.index = index;
80    std::vector<std::string> numberList;
81    numberList.push_back(number);
82    imsCallClient->Dial(callInfo, static_cast<CLIRMode>(mode));
83    imsCallClient->HangUp(callInfo);
84    imsCallClient->Answer(callInfo);
85    imsCallClient->Reject(callInfo);
86    imsCallClient->RejectWithReason(callInfo, ImsRejectReason::USER_DECLINE);
87    imsCallClient->InviteToConference(slotId, numberList);
88    imsCallClient->KickOutFromConference(slotId, index);
89    imsCallClient->StartDtmf(slotId, *cDtmfCode, index);
90    imsCallClient->SendDtmf(slotId, *cDtmfCode, index);
91    imsCallClient->StopDtmf(slotId, index);
92    imsCallClient->StartRtt(slotId, number);
93    imsCallClient->StopRtt(slotId);
94    imsCallClient->SetDomainPreferenceMode(slotId, mode);
95    imsCallClient->GetDomainPreferenceMode(slotId);
96    imsCallClient->SetImsSwitchStatus(slotId, mode);
97    imsCallClient->GetImsSwitchStatus(slotId);
98    imsCallClient->SetMute(slotId, mode);
99    imsCallClient->GetMute(slotId);
100}
101
102void TestImsCallClientWithSlotAndType(
103    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
104{
105    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
106    int32_t index = static_cast<int32_t>(size % NUM_EIGHT);
107    int32_t callType = static_cast<int32_t>(size % NUM_TWO);
108    std::string info(reinterpret_cast<const char *>(data), size);
109    int32_t mode = static_cast<int32_t>(size % NUM_SIX);
110    imsCallClient->HoldCall(slotId, callType);
111    imsCallClient->UnHoldCall(slotId, callType);
112    imsCallClient->SwitchCall(slotId, callType);
113    imsCallClient->CombineConference(slotId);
114    imsCallClient->GetImsCallsDataRequest(slotId, callType);
115    imsCallClient->GetLastCallFailReason(slotId);
116    imsCallClient->ControlCamera(slotId, index, info);
117    imsCallClient->SetPausePicture(slotId, index, info);
118    int len = static_cast<int>(info.length());
119    std::string subSurfaceId = info;
120    if (len >= 1) {
121        subSurfaceId = info.substr(0, 1);
122    }
123    if (subSurfaceId.empty() || subSurfaceId[0] < '0' || subSurfaceId[0] > '9') {
124        subSurfaceId = "";
125        imsCallClient->SetPreviewWindow(slotId, index, subSurfaceId, nullptr);
126        imsCallClient->SetDisplayWindow(slotId, index, subSurfaceId, nullptr);
127    } else {
128        uint64_t tmpSurfaceId = std::stoull(subSurfaceId);
129        auto surface = SurfaceUtils::GetInstance()->GetSurface(tmpSurfaceId);
130        imsCallClient->SetPreviewWindow(slotId, index, subSurfaceId, surface);
131        imsCallClient->SetDisplayWindow(slotId, index, subSurfaceId, surface);
132    }
133    imsCallClient->SetDeviceDirection(slotId, index, mode);
134    imsCallClient->SetCameraZoom(mode);
135    ImsCapabilityList imsCapabilityList;
136    ImsCapability capbility;
137    capbility.enable = mode;
138    capbility.imsCapabilityType = static_cast<ImsCapabilityType>(callType);
139    capbility.imsRadioTech = static_cast<ImsRegTech>(callType);
140    imsCapabilityList.imsCapabilities.push_back(capbility);
141    imsCallClient->UpdateImsCapabilities(slotId, imsCapabilityList);
142}
143
144void TestImsCallClientWithSettingFunction(
145    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
146{
147    CallTransferInfo transferInfo;
148    if (memset_s(&transferInfo, sizeof(struct CallTransferInfo), 0x00, sizeof(struct CallTransferInfo)) != EOK) {
149        return;
150    }
151    size_t length = std::min(static_cast<size_t>(sizeof(transferInfo.transferNum) - 1), size);
152    std::string number(reinterpret_cast<const char *>(data), length);
153    int32_t mode = static_cast<int32_t>(size % NUM_TWO);
154    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
155    int32_t index = static_cast<int32_t>(size % NUM_THREE);
156    int32_t item = static_cast<int32_t>(size % IMS_CONFIG_ITEM_NUM);
157    int32_t value = static_cast<int32_t>(size % NUM_FOUR);
158    int32_t type = static_cast<int32_t>(size % NUM_FOUR);
159    imsCallClient->SetImsConfig(static_cast<ImsConfigItem>(item), number);
160    imsCallClient->SetImsConfig(static_cast<ImsConfigItem>(item), value);
161    imsCallClient->GetImsConfig(static_cast<ImsConfigItem>(item));
162    imsCallClient->SetImsFeatureValue(static_cast<FeatureType>(type), value);
163    imsCallClient->GetImsFeatureValue(static_cast<FeatureType>(type), value);
164    imsCallClient->SetClip(slotId, mode, index);
165    imsCallClient->GetClip(slotId, index);
166    imsCallClient->SetClir(slotId, mode, index);
167    imsCallClient->GetClir(slotId, index);
168    imsCallClient->SetCallWaiting(slotId, mode, type, index);
169    imsCallClient->GetCallWaiting(slotId, index);
170    imsCallClient->SetColr(slotId, mode, index);
171    imsCallClient->GetColr(slotId, index);
172    imsCallClient->SetColp(slotId, mode, index);
173    imsCallClient->GetColp(slotId, index);
174    if (strcpy_s(transferInfo.transferNum, sizeof(transferInfo.transferNum), number.c_str()) != EOK) {
175        return;
176    }
177    transferInfo.settingType = static_cast<CallTransferSettingType>(type);
178    transferInfo.type = static_cast<CallTransferType>(type);
179    imsCallClient->SetCallTransfer(slotId, transferInfo, type, index);
180    imsCallClient->GetCallTransfer(slotId, type, index);
181    imsCallClient->SetCallRestriction(slotId, number, mode, number, index);
182    imsCallClient->GetCallRestriction(slotId, number, index);
183}
184
185void TestImsCallClientWithCallMediaModeRequest(
186    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
187{
188    ImsCallInfo callInfo;
189    if (memset_s(&callInfo, sizeof(struct ImsCallInfo), 0x00, sizeof(struct ImsCallInfo)) != EOK) {
190        return;
191    }
192    size_t length = std::min(static_cast<size_t>(sizeof(callInfo.phoneNum) - 1), size);
193    std::string number(reinterpret_cast<const char *>(data), length);
194    callInfo.slotId = static_cast<int32_t>(size % NUM_TWO);
195    callInfo.videoState = static_cast<int32_t>(size % NUM_TWO);
196    callInfo.index = static_cast<int32_t>(size % NUM_EIGHT);
197    if (strcpy_s(callInfo.phoneNum, sizeof(callInfo.phoneNum), number.c_str()) != EOK) {
198        return;
199    }
200    ImsCallType callMode = static_cast<ImsCallType>(static_cast<int32_t>(size % NUM_SIX));
201    imsCallClient->SendUpdateCallMediaModeRequest(callInfo, callMode);
202}
203
204void TestImsCallClientWithCallMediaModeResponse(
205    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
206{
207    ImsCallInfo callInfo;
208    if (memset_s(&callInfo, sizeof(struct ImsCallInfo), 0x00, sizeof(struct ImsCallInfo)) != EOK) {
209        return;
210    }
211    size_t length = std::min(static_cast<size_t>(sizeof(callInfo.phoneNum) - 1), size);
212    std::string number(reinterpret_cast<const char *>(data), length);
213    callInfo.slotId = static_cast<int32_t>(size % NUM_TWO);
214    callInfo.videoState = static_cast<int32_t>(size % NUM_TWO);
215    callInfo.index = static_cast<int32_t>(size % NUM_EIGHT);
216    if (strcpy_s(callInfo.phoneNum, sizeof(callInfo.phoneNum), number.c_str()) != EOK) {
217        return;
218    }
219    ImsCallType callMode = static_cast<ImsCallType>(static_cast<int32_t>(size % NUM_SIX));
220    imsCallClient->SendUpdateCallMediaModeResponse(callInfo, callMode);
221}
222
223void TestImsCallClientWithCancelCallUpgrade(
224    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
225{
226    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
227    int32_t index = static_cast<int32_t>(size % NUM_EIGHT);
228    imsCallClient->CancelCallUpgrade(slotId, index);
229}
230
231void TestImsCallClientWithRequestCameraCapabilities(
232    const uint8_t *data, size_t size, const std::shared_ptr<ImsCallClient> &imsCallClient)
233{
234    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
235    int32_t index = static_cast<int32_t>(size % NUM_EIGHT);
236    imsCallClient->RequestCameraCapabilities(slotId, index);
237}
238
239void TestImsCallProxyWithCallInfo(const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
240{
241    ImsCallInfo callInfo;
242    if (memset_s(&callInfo, sizeof(struct ImsCallInfo), 0x00, sizeof(struct ImsCallInfo)) != EOK) {
243        return;
244    }
245    size_t length = std::min(static_cast<size_t>(sizeof(callInfo.phoneNum) - 1), size);
246    std::string number(reinterpret_cast<const char *>(data), length);
247    int32_t mode = static_cast<int32_t>(size % NUM_TWO);
248    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
249    int32_t videoState = static_cast<int32_t>(size % NUM_THREE);
250    int32_t index = static_cast<int32_t>(size % NUM_THREE);
251    const char *cDtmfCode = number.c_str();
252    if (strcpy_s(callInfo.phoneNum, sizeof(callInfo.phoneNum), number.c_str()) != EOK) {
253        return;
254    }
255    callInfo.slotId = slotId;
256    callInfo.videoState = videoState;
257    callInfo.index = index;
258    std::vector<std::string> numberList;
259    numberList.push_back(number);
260    proxy->Dial(callInfo, static_cast<CLIRMode>(mode));
261    proxy->HangUp(callInfo);
262    proxy->Answer(callInfo);
263    proxy->RejectWithReason(callInfo, ImsRejectReason::USER_DECLINE);
264    proxy->InviteToConference(slotId, numberList);
265    proxy->KickOutFromConference(slotId, index);
266    proxy->StartDtmf(slotId, *cDtmfCode, index);
267    proxy->SendDtmf(slotId, *cDtmfCode, index);
268    proxy->StopDtmf(slotId, index);
269    proxy->StartRtt(slotId, number);
270    proxy->StopRtt(slotId);
271    proxy->SetDomainPreferenceMode(slotId, mode);
272    proxy->GetDomainPreferenceMode(slotId);
273    proxy->SetImsSwitchStatus(slotId, mode);
274    proxy->GetImsSwitchStatus(slotId);
275    proxy->SetMute(slotId, mode);
276    proxy->GetMute(slotId);
277}
278
279void TestImsCallProxyWithSlotAndType(const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
280{
281    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
282    int32_t index = static_cast<int32_t>(size % NUM_EIGHT);
283    int32_t callType = static_cast<int32_t>(size % NUM_TWO);
284    std::string info(reinterpret_cast<const char *>(data), size);
285    int32_t mode = static_cast<int32_t>(size % NUM_SIX);
286    proxy->HoldCall(slotId, callType);
287    proxy->UnHoldCall(slotId, callType);
288    proxy->SwitchCall(slotId, callType);
289    proxy->CombineConference(slotId);
290    proxy->GetImsCallsDataRequest(slotId, callType);
291    proxy->GetLastCallFailReason(slotId);
292    proxy->ControlCamera(slotId, index, info);
293    proxy->SetPausePicture(slotId, index, info);
294    int len = static_cast<int>(info.length());
295    std::string subSurfaceId = info;
296    if (len >= 1) {
297        subSurfaceId = info.substr(0, 1);
298    }
299    if (subSurfaceId.empty() || subSurfaceId[0] < '0' || subSurfaceId[0] > '9') {
300        subSurfaceId = "";
301        proxy->SetPreviewWindow(slotId, index, subSurfaceId, nullptr);
302        proxy->SetDisplayWindow(slotId, index, subSurfaceId, nullptr);
303    } else {
304        uint64_t tmpSurfaceId = std::stoull(subSurfaceId);
305        auto surface = SurfaceUtils::GetInstance()->GetSurface(tmpSurfaceId);
306        proxy->SetPreviewWindow(slotId, index, subSurfaceId, surface);
307        proxy->SetDisplayWindow(slotId, index, subSurfaceId, surface);
308    }
309    proxy->SetDeviceDirection(slotId, index, mode);
310    proxy->SetCameraZoom(mode);
311    ImsCapabilityList imsCapabilityList;
312    ImsCapability capbility;
313    capbility.enable = mode;
314    capbility.imsCapabilityType = static_cast<ImsCapabilityType>(callType);
315    capbility.imsRadioTech = static_cast<ImsRegTech>(callType);
316    imsCapabilityList.imsCapabilities.push_back(capbility);
317    proxy->UpdateImsCapabilities(slotId, imsCapabilityList);
318}
319
320void TestImsCallProxyWithSettingFunction(const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
321{
322    CallTransferInfo transferInfo;
323    if (memset_s(&transferInfo, sizeof(struct CallTransferInfo), 0x00, sizeof(struct CallTransferInfo)) != EOK) {
324        return;
325    }
326    size_t length = std::min(static_cast<size_t>(sizeof(transferInfo.transferNum) - 1), size);
327    std::string number(reinterpret_cast<const char *>(data), length);
328    int32_t mode = static_cast<int32_t>(size % NUM_TWO);
329    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
330    int32_t index = static_cast<int32_t>(size % NUM_THREE);
331    int32_t item = static_cast<int32_t>(size % IMS_CONFIG_ITEM_NUM);
332    int32_t value = static_cast<int32_t>(size % NUM_FOUR);
333    int32_t type = static_cast<int32_t>(size % NUM_FOUR);
334    proxy->SetImsConfig(static_cast<ImsConfigItem>(item), number);
335    proxy->SetImsConfig(static_cast<ImsConfigItem>(item), value);
336    proxy->GetImsConfig(static_cast<ImsConfigItem>(item));
337    proxy->SetImsFeatureValue(static_cast<FeatureType>(type), value);
338    proxy->GetImsFeatureValue(static_cast<FeatureType>(type), value);
339    proxy->SetClip(slotId, mode, index);
340    proxy->GetClip(slotId, index);
341    proxy->SetClir(slotId, mode, index);
342    proxy->GetClir(slotId, index);
343    proxy->SetCallWaiting(slotId, mode, type, index);
344    proxy->GetCallWaiting(slotId, index);
345    proxy->SetColr(slotId, mode, index);
346    proxy->GetColr(slotId, index);
347    proxy->SetColp(slotId, mode, index);
348    proxy->GetColp(slotId, index);
349    if (strcpy_s(transferInfo.transferNum, sizeof(transferInfo.transferNum), number.c_str()) != EOK) {
350        return;
351    }
352    transferInfo.settingType = static_cast<CallTransferSettingType>(type);
353    transferInfo.type = static_cast<CallTransferType>(type);
354    proxy->SetCallTransfer(slotId, transferInfo, type, index);
355    proxy->GetCallTransfer(slotId, type, index);
356    proxy->SetCallRestriction(slotId, number, mode, number, index);
357    proxy->GetCallRestriction(slotId, number, index);
358}
359
360void TestImsCallProxyWithCallMediaModeRequest(const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
361{
362    ImsCallInfo callInfo;
363    if (memset_s(&callInfo, sizeof(struct ImsCallInfo), 0x00, sizeof(struct ImsCallInfo)) != EOK) {
364        return;
365    }
366    size_t length = std::min(static_cast<size_t>(sizeof(callInfo.phoneNum) - 1), size);
367    std::string number(reinterpret_cast<const char *>(data), length);
368    callInfo.slotId = static_cast<int32_t>(size % NUM_TWO);
369    callInfo.videoState = static_cast<int32_t>(size % NUM_TWO);
370    callInfo.index = static_cast<int32_t>(size % NUM_EIGHT);
371    if (strcpy_s(callInfo.phoneNum, sizeof(callInfo.phoneNum), number.c_str()) != EOK) {
372        return;
373    }
374    ImsCallType callType = static_cast<ImsCallType>(static_cast<int32_t>(size % NUM_SIX));
375    proxy->SendUpdateCallMediaModeRequest(callInfo, callType);
376}
377
378void TestImsCallProxyWithCallMediaModeResponse(const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
379{
380    ImsCallInfo callInfo;
381    if (memset_s(&callInfo, sizeof(struct ImsCallInfo), 0x00, sizeof(struct ImsCallInfo)) != EOK) {
382        return;
383    }
384    size_t length = std::min(static_cast<size_t>(sizeof(callInfo.phoneNum) - 1), size);
385    std::string number(reinterpret_cast<const char *>(data), length);
386    callInfo.slotId = static_cast<int32_t>(size % NUM_TWO);
387    callInfo.videoState = static_cast<int32_t>(size % NUM_TWO);
388    callInfo.index = static_cast<int32_t>(size % NUM_EIGHT);
389    if (strcpy_s(callInfo.phoneNum, sizeof(callInfo.phoneNum), number.c_str()) != EOK) {
390        return;
391    }
392    ImsCallType callType = static_cast<ImsCallType>(static_cast<int32_t>(size % NUM_SIX));
393    proxy->SendUpdateCallMediaModeResponse(callInfo, callType);
394}
395
396void TestImsCallProxyWithCancelCallUpgrade(const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
397{
398    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
399    int32_t index = static_cast<int32_t>(size % NUM_EIGHT);
400    proxy->CancelCallUpgrade(slotId, index);
401}
402
403void TestImsCallProxyWithRequestCameraCapabilities(
404    const uint8_t *data, size_t size, const sptr<ImsCallInterface> &proxy)
405{
406    int32_t slotId = static_cast<int32_t>(size % NUM_TWO);
407    int32_t index = static_cast<int32_t>(size % NUM_EIGHT);
408    proxy->RequestCameraCapabilities(slotId, index);
409}
410
411void DoSomethingInterestingWithMyAPI(const uint8_t *data, size_t size)
412{
413    if (data == nullptr || size == 0) {
414        return;
415    }
416    auto imsCallClient = DelayedSingleton<ImsCallClient>::GetInstance();
417    if (imsCallClient == nullptr) {
418        return;
419    }
420    if (!IsServiceInited()) {
421        return;
422    }
423    TestImsCallClientWithCallInfo(data, size, imsCallClient);
424    TestImsCallClientWithSlotAndType(data, size, imsCallClient);
425    TestImsCallClientWithSettingFunction(data, size, imsCallClient);
426    TestImsCallClientWithCallMediaModeRequest(data, size, imsCallClient);
427    TestImsCallClientWithCallMediaModeResponse(data, size, imsCallClient);
428    TestImsCallClientWithCancelCallUpgrade(data, size, imsCallClient);
429    TestImsCallClientWithRequestCameraCapabilities(data, size, imsCallClient);
430
431    auto managerPtr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
432    if (managerPtr == nullptr) {
433        return;
434    }
435    auto remoteObjectPtr = managerPtr->CheckSystemAbility(TELEPHONY_IMS_SYS_ABILITY_ID);
436    if (remoteObjectPtr == nullptr) {
437        return;
438    }
439    sptr<ImsCallInterface> proxy = iface_cast<ImsCallInterface>(remoteObjectPtr);
440    if (proxy == nullptr) {
441        return;
442    }
443    TestImsCallProxyWithCallInfo(data, size, proxy);
444    TestImsCallProxyWithSlotAndType(data, size, proxy);
445    TestImsCallProxyWithSettingFunction(data, size, proxy);
446    TestImsCallProxyWithCallMediaModeRequest(data, size, proxy);
447    TestImsCallProxyWithCallMediaModeResponse(data, size, proxy);
448    TestImsCallProxyWithCancelCallUpgrade(data, size, proxy);
449    TestImsCallProxyWithRequestCameraCapabilities(data, size, proxy);
450    proxy.clear();
451    proxy = nullptr;
452}
453} // namespace OHOS
454
455/* Fuzzer entry point */
456extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
457{
458    OHOS::AddCellularCallTokenFuzzer token;
459    /* Run your code on data */
460    OHOS::DoSomethingInterestingWithMyAPI(data, size);
461    return 0;
462}
463