1/*
2 * Copyright (c) 2021 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 "buffer_extra_data_impl.h"
17#include <message_parcel.h>
18#include "buffer_log.h"
19
20namespace OHOS {
21namespace {
22constexpr int32_t BUFFER_EXTRA_DATA_MAGIC = 0x4567;
23} // namespace
24
25GSError BufferExtraDataImpl::ReadFromParcel(MessageParcel &parcel)
26{
27    int32_t magic = 0;
28    if (parcel.ReadInt32(magic) == false || magic != BUFFER_EXTRA_DATA_MAGIC) {
29        BLOGW("read failed, magic: %{public}d", magic);
30        return GSERROR_INTERNAL;
31    }
32
33    int32_t size = parcel.ReadInt32();
34    if (size > SURFACE_MAX_USER_DATA_COUNT) {
35        BLOGE("ReadFromParcel size: %{public}d", size);
36        return GSERROR_INTERNAL;
37    }
38
39    GSError ret = GSERROR_OK;
40    for (int32_t i = 0; i < size; i++) {
41        auto key = parcel.ReadString();
42        auto type = static_cast<ExtraDataType>(parcel.ReadInt32());
43        switch (type) {
44            case ExtraDataType::i32: {
45                ret = ExtraSet(key, type, parcel.ReadInt32());
46                break;
47            }
48            case ExtraDataType::i64: {
49                ret = ExtraSet(key, type, parcel.ReadInt64());
50                break;
51            }
52            case ExtraDataType::f64: {
53                ret = ExtraSet(key, type, parcel.ReadDouble());
54                break;
55            }
56            case ExtraDataType::string: {
57                ret = ExtraSet(key, type, parcel.ReadString());
58                break;
59            }
60            default: break;
61        }
62
63        if (ret != GSERROR_OK) {
64            BLOGE("ExtraSet failed, ret %{public}d", ret);
65            break;
66        }
67    }
68    return ret;
69}
70
71GSError BufferExtraDataImpl::WriteToParcel(MessageParcel &parcel)
72{
73    std::lock_guard<std::mutex> lockGuard(mtx_);
74    if (!parcel.WriteInt32(BUFFER_EXTRA_DATA_MAGIC) || !parcel.WriteInt32(datas_.size())) {
75        return GSERROR_BINDER;
76    }
77    bool ipcRet = true;
78    for (const auto &[key, data] : datas_) {
79        if (!parcel.WriteString(key) || !parcel.WriteInt32(static_cast<int32_t>(data.type))) {
80            return GSERROR_BINDER;
81        }
82        switch (data.type) {
83            case ExtraDataType::i32: {
84                int32_t i32 = -1;
85                auto pVal = std::any_cast<int32_t>(&data.val);
86                if (pVal != nullptr) {
87                    i32 = *pVal;
88                }
89                ipcRet = parcel.WriteInt32(i32);
90                break;
91            }
92            case ExtraDataType::i64: {
93                int64_t i64 = -1;
94                auto pVal = std::any_cast<int64_t>(&data.val);
95                if (pVal != nullptr) {
96                    i64 = *pVal;
97                }
98                ipcRet = parcel.WriteInt64(i64);
99                break;
100            }
101            case ExtraDataType::f64: {
102                double f64 = -1;
103                auto pVal = std::any_cast<double>(&data.val);
104                if (pVal != nullptr) {
105                    f64 = *pVal;
106                }
107                ipcRet = parcel.WriteDouble(f64);
108                break;
109            }
110            case ExtraDataType::string: {
111                std::string string = "-1";
112                auto pVal = std::any_cast<std::string>(&data.val);
113                if (pVal != nullptr) {
114                    string = *pVal;
115                }
116                ipcRet = parcel.WriteString(string);
117                break;
118            }
119            default:
120                break;
121        }
122    }
123    return ipcRet ? GSERROR_OK : GSERROR_BINDER;
124}
125
126GSError BufferExtraDataImpl::ExtraGet(const std::string &key, int32_t &value) const
127{
128    return ExtraGet<int32_t>(key, ExtraDataType::i32, value);
129}
130
131GSError BufferExtraDataImpl::ExtraGet(const std::string &key, int64_t &value) const
132{
133    return ExtraGet<int64_t>(key, ExtraDataType::i64, value);
134}
135
136GSError BufferExtraDataImpl::ExtraGet(const std::string &key, double &value) const
137{
138    return ExtraGet<double>(key, ExtraDataType::f64, value);
139}
140
141GSError BufferExtraDataImpl::ExtraGet(const std::string &key, std::string &value) const
142{
143    return ExtraGet<std::string>(key, ExtraDataType::string, value);
144}
145
146GSError BufferExtraDataImpl::ExtraSet(const std::string &key, int32_t value)
147{
148    return ExtraSet(key, ExtraDataType::i32, value);
149}
150
151GSError BufferExtraDataImpl::ExtraSet(const std::string &key, int64_t value)
152{
153    return ExtraSet(key, ExtraDataType::i64, value);
154}
155
156GSError BufferExtraDataImpl::ExtraSet(const std::string &key, double value)
157{
158    return ExtraSet(key, ExtraDataType::f64, value);
159}
160
161GSError BufferExtraDataImpl::ExtraSet(const std::string &key, const std::string& value)
162{
163    return ExtraSet(key, ExtraDataType::string, value);
164}
165
166template<class T>
167GSError BufferExtraDataImpl::ExtraGet(const std::string &key, ExtraDataType type, T &value) const
168{
169    std::lock_guard<std::mutex> lockGuard(mtx_);
170    auto it = datas_.find(key);
171    if (it == datas_.end()) {
172        return GSERROR_NO_ENTRY;
173    }
174    if (it->second.type != type) {
175        return GSERROR_TYPE_ERROR;
176    }
177    auto pVal = std::any_cast<T>(&it->second.val);
178    if (pVal == nullptr) {
179        return GSERROR_TYPE_ERROR;
180    }
181    value = *pVal;
182    return GSERROR_OK;
183}
184
185GSError BufferExtraDataImpl::ExtraSet(const std::string &key, ExtraDataType type, const std::any& val)
186{
187    std::lock_guard<std::mutex> lockGuard(mtx_);
188    auto it = datas_.find(key);
189    if (it == datas_.end() && datas_.size() > SURFACE_MAX_USER_DATA_COUNT) {
190        BLOGW("SurfaceBuffer has too many extra data, cannot save one more!!!");
191        return GSERROR_OUT_OF_RANGE;
192    }
193    datas_[key].type = type;
194    datas_[key].val = val;
195    return GSERROR_OK;
196}
197} // namespace OHOS
198