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#define LOG_TAG "TlvObject"
17#include "tlv_object.h"
18#include "logger.h"
19
20namespace OHOS {
21namespace UDMF {
22TLVObject::TLVObject(std::vector<std::uint8_t> &buffer)
23{
24    total_ += buffer.size();
25    buffer_ = &buffer;
26    cursor_ = 0;
27    file_ = nullptr;
28}
29
30void TLVObject::SetFile(std::FILE *file)
31{
32    file_ = file;
33    if (fseek(file_, 0, SEEK_END) != 0) {
34        LOG_ERROR(UDMF_SERVICE, "fseek to end error!");
35    }
36
37    auto total = ftell(file_);
38    if (total < 0) {
39        LOG_ERROR(UDMF_SERVICE, "Values are out of range, total:%{public}ld", total);
40        return;
41    }
42    total_ = static_cast<size_t>(total);
43    ResetCursor();
44}
45
46void TLVObject::UpdateSize()
47{
48    if (file_ != nullptr) {
49        return;
50    }
51    buffer_->resize(total_);
52}
53
54std::vector<std::uint8_t> TLVObject::GetBuffer()
55{
56    return *buffer_;
57}
58
59size_t TLVObject::GetTotal()
60{
61    return total_;
62}
63
64size_t TLVObject::GetCursor()
65{
66    return cursor_;
67}
68
69size_t TLVObject::OffsetHead()
70{
71    if (file_ != nullptr) {
72        if (fseek(file_, sizeof(TLVHead), SEEK_CUR) != 0) {
73            LOG_ERROR(UDMF_SERVICE, "OffsetHead file error!");
74            return 0;
75        }
76    }
77    cursor_ += sizeof(TLVHead);
78    return cursor_;
79}
80
81void TLVObject::ResetCursor()
82{
83    cursor_ = 0;
84    if (file_ != nullptr) {
85        if (fseek(file_, 0, SEEK_SET) != 0) {
86            LOG_ERROR(UDMF_SERVICE, "ResetCursor file error!");
87        }
88    }
89}
90
91size_t TLVObject::Count(const std::string &value)
92{
93    auto size = sizeof(TLVHead) + value.size();
94    total_ += size;
95    return size;
96}
97
98size_t TLVObject::Count(const std::vector<uint8_t> &value)
99{
100    auto size = sizeof(TLVHead) + value.size();
101    total_ += size;
102    return size;
103}
104
105size_t TLVObject::Count(const OHOS::AAFwk::Want &value)
106{
107    Parcel parcel;
108    if (!value.Marshalling(parcel)) {
109        LOG_ERROR(UDMF_FRAMEWORK, "Marshalling want error when Count");
110        return 0;
111    }
112    auto size = sizeof(TLVHead) + parcel.GetDataSize();
113    total_ += size;
114    return size;
115}
116
117size_t TLVObject::Count(const std::monostate &value)
118{
119    auto size = sizeof(TLVHead);
120    total_ += size;
121    return size;
122}
123
124size_t TLVObject::Count(const void *value)
125{
126    auto size = sizeof(TLVHead);
127    total_ += size;
128    return size;
129}
130
131bool TLVObject::Write(TAG tag, const std::string &value)
132{
133    if (!HasExpectBuffer(sizeof(TLVHead) + value.size())) {
134        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write. tag=%{public}hu, value=%{public}s", tag,
135            value.c_str());
136        return false;
137    }
138    auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
139    tlvHead->tag = HostToNet(static_cast<uint16_t>(tag));
140    tlvHead->len = HostToNet((uint32_t)value.size());
141    if (!value.empty()) {
142        auto err = memcpy_s(tlvHead->value, value.size(), value.c_str(), value.size());
143        if (err != EOK) {
144            LOG_ERROR(UDMF_FRAMEWORK, "memcpy error in tlv write. tag=%{public}hu, value=%{public}s", tag,
145                value.c_str());
146            return false;
147        }
148    }
149    cursor_ += sizeof(TLVHead) + value.size();
150    return SaveBufferToFile();
151}
152
153bool TLVObject::Read(std::string &value, const TLVHead &head)
154{
155    if (!HasExpectBuffer(head.len)) {
156        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read string. tag=%{public}hu", head.tag);
157        return false;
158    }
159    if (!LoadBufferFormFile(head.len)) {
160        LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read string. tag=%{public}hu", head.tag);
161        return false;
162    }
163    auto startCursor = GetStartCursor();
164    value.append(reinterpret_cast<const char *>(startCursor), head.len);
165    cursor_ += head.len;
166    return true;
167}
168
169bool TLVObject::Write(TAG tag, const std::vector<uint8_t> &value)
170{
171    if (!HasExpectBuffer(sizeof(TLVHead) + value.size())) {
172        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write u8 vector. tag=%{public}hu", tag);
173        return false;
174    }
175    auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
176    tlvHead->tag = HostToNet(static_cast<uint16_t>(tag));
177    tlvHead->len = HostToNet(static_cast<uint32_t>(value.size()));
178    if (!value.empty()) {
179        auto err = memcpy_s(tlvHead->value, value.size(), value.data(), value.size());
180        if (err != EOK) {
181            LOG_ERROR(UDMF_FRAMEWORK, "memcpy error in tlv write u8 vector. tag=%{public}hu", tag);
182            return false;
183        }
184    }
185    cursor_ += sizeof(TLVHead) + value.size();
186    return SaveBufferToFile();
187}
188
189
190bool TLVObject::Read(std::vector<uint8_t> &value, const TLVHead &head)
191{
192    if (!HasExpectBuffer(head.len)) {
193        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read u8 vector. tag=%{public}hu", head.tag);
194        return false;
195    }
196    if (!LoadBufferFormFile(head.len)) {
197        LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read u8 vector. tag=%{public}hu", head.tag);
198        return false;
199    }
200    auto startCursor = GetStartCursor();
201    std::vector<uint8_t> buff(startCursor, startCursor + head.len);
202    value = std::move(buff);
203    cursor_ += head.len;
204    return true;
205}
206
207bool TLVObject::Write(TAG tag, const OHOS::AAFwk::Want &value)
208{
209    Parcel parcel;
210    if (!value.Marshalling(parcel)) {
211        LOG_ERROR(UDMF_FRAMEWORK, "Marshalling want error in tlv write. tag=%{public}hu", tag);
212        return false;
213    }
214    auto size = parcel.GetDataSize();
215    auto buffer = parcel.GetData();
216
217    if (!HasExpectBuffer(sizeof(TLVHead) + size)) {
218        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write want. tag=%{public}hu", tag);
219        return false;
220    }
221    auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
222    tlvHead->tag = HostToNet(static_cast<uint16_t>(tag));
223    tlvHead->len = HostToNet(static_cast<uint32_t>(size));
224    if (size != 0) {
225        auto err = memcpy_s(tlvHead->value, size, reinterpret_cast<const void *>(buffer), size);
226        if (err != EOK) {
227            LOG_ERROR(UDMF_FRAMEWORK, "memcpy error in tlv write want. tag=%{public}hu", tag);
228            return false;
229        }
230    }
231    cursor_ += sizeof(TLVHead) + size;
232    return SaveBufferToFile();
233}
234
235bool TLVObject::Read(OHOS::AAFwk::Want &value, const TLVHead &head)
236{
237    if (!HasExpectBuffer(head.len)) {
238        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read want. tag=%{public}hu", head.tag);
239        return false;
240    }
241    if (!LoadBufferFormFile(head.len)) {
242        LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read want. tag=%{public}hu", head.tag);
243        return false;
244    }
245    auto startCursor = GetStartCursor();
246    std::vector<uint8_t> buff(startCursor, startCursor + head.len);
247
248    auto buffer = (uintptr_t)(buff.data() + cursor_);
249    cursor_ += head.len;
250
251    Parcel parcel;
252    if (!parcel.ParseFrom(buffer, head.len)) {
253        LOG_ERROR(UDMF_FRAMEWORK, "ParseFrom error in tlv read want. tag=%{public}hu", head.tag);
254        return false;
255    }
256    auto want = AAFwk::Want::Unmarshalling(parcel);
257    if (want == nullptr) {
258        LOG_ERROR(UDMF_FRAMEWORK, "Unmarshalling want error in tlv read. tag=%{public}hu", head.tag);
259        return false;
260    }
261    value = *want;
262    return true;
263}
264
265bool TLVObject::Write(TAG tag, const std::monostate &value)
266{
267    return WriteHead(static_cast<uint16_t>(tag), (uint32_t)0);
268}
269
270bool TLVObject::Read(std::monostate &value, const TLVHead &head)
271{
272    return true;
273}
274
275bool TLVObject::Write(TAG tag, const void *value)
276{
277    return WriteHead(static_cast<uint16_t>(tag), (uint32_t)0);
278}
279
280
281bool TLVObject::Read(void *value, const TLVHead &head)
282{
283    value = nullptr;
284    return true;
285}
286
287size_t TLVObject::CountHead()
288{
289    total_ += sizeof(TLVHead);
290    return sizeof(TLVHead);
291}
292
293bool TLVObject::WriteHead(uint16_t tag, uint32_t len)
294{
295    if (!HasExpectBuffer(sizeof(TLVHead))) {
296        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv write head. tag=%{public}hu", tag);
297        return false;
298    }
299    PrepareBufferForFile(sizeof(TLVHead));
300    auto tlvHead = reinterpret_cast<TLVHead *>(GetStartCursor());
301    tlvHead->tag = HostToNet(tag);
302    tlvHead->len = HostToNet(len);
303    cursor_ += sizeof(TLVHead);
304    return SaveBufferToFile();
305}
306
307bool TLVObject::WriteBackHead(uint16_t tag, size_t tagCursor, uint32_t len)
308{
309    auto startCursor = buffer_->data();
310    if (file_ == nullptr) {
311        startCursor += tagCursor;
312    }
313    auto tlvHead = reinterpret_cast<TLVHead *>(startCursor);
314    tlvHead->tag = HostToNet(tag);
315    tlvHead->len = HostToNet(len);
316    return SaveBufferToFileFront(tagCursor, sizeof(TLVHead));
317}
318
319bool TLVObject::ReadHead(TLVHead &head)
320{
321    if (!HasExpectBuffer(sizeof(TLVHead))) {
322        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read head. tag=%{public}hu", head.tag);
323        return false;
324    }
325    if (!LoadBufferFormFile(sizeof(TLVHead))) {
326        LOG_ERROR(UDMF_FRAMEWORK, "LoadBufferFormFile error in tlv read head. tag=%{public}hu", head.tag);
327        return false;
328    }
329    auto startCursor = GetStartCursor();
330    const auto *pHead = reinterpret_cast<const TLVHead *>(startCursor);
331    auto len = NetToHost(pHead->len);
332    if (file_ == nullptr) {
333        if (!HasExpectBuffer(len + sizeof(TLVHead))) {
334            LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv read head and len. tag=%{public}hu", head.tag);
335            return false;
336        }
337    }
338
339    head.tag = NetToHost(pHead->tag);
340    head.len = len;
341    cursor_ += sizeof(TLVHead);
342    return true;
343}
344
345bool TLVObject::Skip(TLVHead &head)
346{
347    if (file_ != nullptr) {
348        cursor_ += head.len;
349        return fseek(file_, head.len * sizeof(uint8_t), SEEK_CUR) == 0;
350    }
351    if (total_ < head.len || total_ - head.len < cursor_) {
352        LOG_ERROR(UDMF_FRAMEWORK, "Has no enough buffer in tlv skip. tag=%{public}hu", head.tag);
353        return false;
354    }
355    cursor_ += head.len;
356    return true;
357}
358
359bool TLVObject::HasExpectBuffer(const uint32_t expectLen) const
360{
361    if (buffer_ == nullptr) {
362        return false;
363    }
364    if (file_ != nullptr) {
365        buffer_->resize(expectLen);
366        return true;
367    }
368    return buffer_->size() >= cursor_ && buffer_->size() - cursor_ >= expectLen;
369}
370
371void TLVObject::PrepareBufferForFile(size_t size)
372{
373    if (file_ == nullptr) {
374        return;
375    }
376    buffer_->resize(size);
377}
378
379std::uint8_t *TLVObject::GetStartCursor()
380{
381    auto startCursor = buffer_->data();
382    if (file_ == nullptr) {
383        startCursor += cursor_;
384    }
385    return startCursor;
386}
387
388bool TLVObject::SaveBufferToFile()
389{
390    if (file_ == nullptr) {
391        return true;
392    }
393    auto count = fwrite(buffer_->data(), sizeof(uint8_t), buffer_->size(), file_);
394    if (count != buffer_->size()) {
395        LOG_ERROR(UDMF_FRAMEWORK, "fwrite error!");
396        return false;
397    }
398    return true;
399}
400
401bool TLVObject::SaveBufferToFileFront(size_t tagCursor, uint32_t len)
402{
403    if (file_ == nullptr) {
404        return true;
405    }
406    int32_t leftOffset =
407        -((static_cast<int32_t>(cursor_) - static_cast<int32_t>(tagCursor))) * static_cast<int32_t>(sizeof(uint8_t));
408    if (fseek(file_, leftOffset * sizeof(uint8_t), SEEK_CUR) != 0) {
409        LOG_ERROR(UDMF_FRAMEWORK, "file fseek left error!");
410        return false;
411    }
412    auto count = fwrite(buffer_->data(), sizeof(uint8_t), sizeof(TLVHead), file_);
413    if (count != sizeof(TLVHead)) {
414        LOG_ERROR(UDMF_FRAMEWORK, "file write error!");
415        return false;
416    }
417    int32_t rightOffset =
418        static_cast<int32_t>(cursor_) - static_cast<int32_t>(tagCursor) - static_cast<int32_t>(sizeof(TLVHead));
419    if (fseek(file_, rightOffset * sizeof(uint8_t), SEEK_CUR) != 0) {
420        LOG_ERROR(UDMF_FRAMEWORK, "file fseek right error!");
421        return false;
422    }
423    return true;
424}
425
426bool TLVObject::LoadBufferFormFile(size_t size)
427{
428    if (file_ == nullptr) {
429        return true;
430    }
431    auto count = fread(buffer_->data(), sizeof(uint8_t), buffer_->size(), file_);
432    if (count != buffer_->size()) {
433        return false;
434    }
435    return true;
436}
437} // namespace UDMF
438} // namespace OHOS
439