1/*
2**
3** Copyright 2017, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <android/hardware/confirmationui/support/cbor.h>
19
20namespace android {
21namespace hardware {
22namespace confirmationui {
23namespace support {
24namespace {
25
26inline uint8_t getByte(const uint64_t& v, const uint8_t index) {
27    return v >> (index * 8);
28}
29
30WriteState writeBytes(WriteState state, uint64_t value, uint8_t size) {
31    auto pos = state.data_;
32    if (!(state += size)) return state;
33    switch (size) {
34        case 8:
35            *pos++ = getByte(value, 7);
36            *pos++ = getByte(value, 6);
37            *pos++ = getByte(value, 5);
38            *pos++ = getByte(value, 4);
39        case 4:
40            *pos++ = getByte(value, 3);
41            *pos++ = getByte(value, 2);
42        case 2:
43            *pos++ = getByte(value, 1);
44        case 1:
45            *pos++ = value;
46            break;
47        default:
48            state.error_ = Error::MALFORMED;
49    }
50    return state;
51}
52
53}  // anonymous namespace
54
55WriteState writeHeader(WriteState wState, Type type, const uint64_t value) {
56    if (!wState) return wState;
57    uint8_t& header = *wState.data_;
58    if (!++wState) return wState;
59    header = static_cast<uint8_t>(type) << 5;
60    if (value < 24) {
61        header |= static_cast<uint8_t>(value);
62    } else if (value < 0x100) {
63        header |= 24;
64        wState = writeBytes(wState, value, 1);
65    } else if (value < 0x10000) {
66        header |= 25;
67        wState = writeBytes(wState, value, 2);
68    } else if (value < 0x100000000) {
69        header |= 26;
70        wState = writeBytes(wState, value, 4);
71    } else {
72        header |= 27;
73        wState = writeBytes(wState, value, 8);
74    }
75    return wState;
76}
77
78bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out) {
79    uint32_t multi_byte_length = 0;
80    while (begin != end) {
81        if (multi_byte_length) {
82            // parsing multi byte character - must start with 10xxxxxx
83            --multi_byte_length;
84            if ((*begin & 0xc0) != 0x80) return false;
85        } else if (!((*begin) & 0x80)) {
86            // 7bit character -> nothing to be done
87        } else {
88            // msb is set and we were not parsing a multi byte character
89            // so this must be a header byte
90            char c = *begin << 1;
91            while (c & 0x80) {
92                ++multi_byte_length;
93                c <<= 1;
94            }
95            // headers of the form 10xxxxxx are not allowed
96            if (multi_byte_length < 1) return false;
97            // chars longer than 4 bytes are not allowed (multi_byte_length does not count the
98            // header thus > 3
99            if (multi_byte_length > 3) return false;
100        }
101        if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
102    }
103    // if the string ends in the middle of a multi byte char it is invalid
104    if (multi_byte_length) return false;
105    return true;
106}
107
108}  // namespace support
109}  // namespace confirmationui
110}  // namespace hardware
111}  // namespace android
112