Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
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 "BufferReader.h"
19 :
20 : #include <lib/core/CHIPEncoding.h>
21 : #include <lib/core/CHIPError.h>
22 :
23 : #include <cstdint>
24 : #include <string.h>
25 : #include <type_traits>
26 :
27 : namespace chip {
28 : namespace Encoding {
29 :
30 4947 : BufferReader & BufferReader::ReadBytes(uint8_t * dest, size_t size)
31 : {
32 : static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing");
33 :
34 4947 : if (EnsureAvailable(size))
35 : {
36 4944 : memcpy(dest, mReadPtr, size);
37 4944 : mReadPtr += size;
38 4944 : mAvailable -= size;
39 : }
40 :
41 4947 : return *this;
42 : }
43 :
44 : namespace LittleEndian {
45 :
46 : namespace {
47 :
48 : // This helper methods return void and put the value being read into an
49 : // outparam because that allows us to easily overload on the type of the
50 : // thing being read.
51 6 : void ReadHelper(const uint8_t * p, bool * dest)
52 : {
53 6 : *dest = (*p != 0);
54 6 : }
55 :
56 : template <typename T>
57 188971 : void ReadHelper(const uint8_t * p, T * dest)
58 : {
59 : std::make_unsigned_t<T> result;
60 188971 : memcpy(&result, p, sizeof(result));
61 188971 : result = chip::Encoding::LittleEndian::HostSwap(result);
62 :
63 188971 : *dest = static_cast<T>(result);
64 188971 : }
65 :
66 : } // anonymous namespace
67 :
68 : template <typename T>
69 189288 : void Reader::RawReadLowLevelBeCareful(T * retval)
70 : {
71 : static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing");
72 : static_assert((-1 & 3) == 3, "LittleEndian::BufferReader only works with 2's complement architectures.");
73 :
74 189288 : VerifyOrReturn(IsSuccess());
75 :
76 189282 : constexpr size_t data_size = sizeof(T);
77 :
78 189282 : if (EnsureAvailable(data_size))
79 : {
80 188977 : ReadHelper(mReadPtr, retval);
81 188977 : mReadPtr += data_size;
82 188977 : mAvailable -= data_size;
83 : }
84 : }
85 :
86 : // Explicit Read instantiations for the data types we want to support.
87 : template void Reader::RawReadLowLevelBeCareful(char *);
88 : template void Reader::RawReadLowLevelBeCareful(bool *);
89 : template void Reader::RawReadLowLevelBeCareful(int8_t *);
90 : template void Reader::RawReadLowLevelBeCareful(int16_t *);
91 : template void Reader::RawReadLowLevelBeCareful(int32_t *);
92 : template void Reader::RawReadLowLevelBeCareful(int64_t *);
93 : template void Reader::RawReadLowLevelBeCareful(uint8_t *);
94 : template void Reader::RawReadLowLevelBeCareful(uint16_t *);
95 : template void Reader::RawReadLowLevelBeCareful(uint32_t *);
96 : template void Reader::RawReadLowLevelBeCareful(uint64_t *);
97 :
98 : } // namespace LittleEndian
99 :
100 : namespace BigEndian {
101 :
102 1 : Reader & Reader::Read16(uint16_t * dest)
103 : {
104 1 : if (!EnsureAvailable(sizeof(uint16_t)))
105 : {
106 0 : return *this;
107 : }
108 :
109 : static_assert(sizeof(*dest) == 2);
110 :
111 1 : *dest = static_cast<uint16_t>((mReadPtr[0] << 8) + mReadPtr[1]);
112 1 : mReadPtr += 2;
113 1 : mAvailable -= 2;
114 1 : return *this;
115 : }
116 :
117 2 : Reader & Reader::Read32(uint32_t * dest)
118 : {
119 2 : if (!EnsureAvailable(sizeof(uint32_t)))
120 : {
121 1 : return *this;
122 : }
123 :
124 : static_assert(sizeof(*dest) == 4);
125 :
126 1 : *dest = 0;
127 5 : for (unsigned i = 0; i < sizeof(uint32_t); i++)
128 : {
129 4 : *dest <<= 8;
130 4 : *dest += mReadPtr[i];
131 : }
132 :
133 1 : mReadPtr += sizeof(uint32_t);
134 1 : mAvailable -= sizeof(uint32_t);
135 1 : return *this;
136 : }
137 :
138 : } // namespace BigEndian
139 :
140 : } // namespace Encoding
141 : } // namespace chip
|