Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 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 : #pragma once
19 :
20 : #include <climits>
21 : #include <stdint.h>
22 : #include <string.h>
23 :
24 : #include <lib/support/Span.h>
25 :
26 : namespace chip {
27 : namespace Encoding {
28 :
29 : class BufferWriter
30 : {
31 : public:
32 390212 : BufferWriter(uint8_t * buf, size_t len) : mBuf(buf), mSize(len), mNeeded(0)
33 : {
34 390212 : if (buf == nullptr)
35 : {
36 123 : mSize = 0;
37 : }
38 390212 : }
39 224 : BufferWriter(MutableByteSpan buf) : BufferWriter(buf.data(), buf.size()) {}
40 : BufferWriter(const BufferWriter & other) = default;
41 : BufferWriter & operator=(const BufferWriter & other) = default;
42 :
43 : /// Append a null terminated string, exclude the null terminator
44 : BufferWriter & Put(const char * s);
45 :
46 : /// Raw append a buffer, regardless of endianess.
47 : /// This is memmove-safe: if `buf` points to the underlying buffer, where output
48 : /// will be written, and the overlap is legal for a memmove to have worked properly,
49 : /// then this method will properly copy data.
50 : BufferWriter & Put(const void * buf, size_t len);
51 :
52 : /// Append a single byte
53 : BufferWriter & Put(uint8_t c);
54 :
55 1871 : BufferWriter & Skip(size_t len)
56 : {
57 1871 : mNeeded += len;
58 1871 : return *this;
59 : }
60 :
61 : /// Number of bytes required to satisfy all calls to Put() so far
62 10274 : inline size_t Needed() const { return mNeeded; }
63 :
64 : /// Alias to Needed() for code clarity: current writing position for the buffer.
65 7726 : inline size_t WritePos() const { return Needed(); }
66 :
67 : /// Number of bytes still available for writing
68 11250 : size_t Available() const { return mSize < mNeeded ? 0 : mSize - mNeeded; }
69 :
70 : /// Whether the input fit in the buffer
71 27259 : bool Fit() const
72 : {
73 : size_t _;
74 27259 : return Fit(_);
75 : }
76 :
77 : /// Returns whether the input fit in the buffer, outputs what was actually written
78 395155 : bool Fit(size_t & actuallyWritten) const
79 : {
80 395155 : actuallyWritten = mSize >= mNeeded ? mNeeded : mSize;
81 395155 : return mSize >= mNeeded;
82 : }
83 :
84 : /// Size of the output buffer
85 26 : size_t Size() const { return mSize; }
86 :
87 23654 : uint8_t * Buffer() { return mBuf; }
88 704 : const uint8_t * Buffer() const { return mBuf; }
89 :
90 341 : void Reset() { mNeeded = 0; }
91 :
92 : protected:
93 : uint8_t * mBuf;
94 : size_t mSize;
95 : size_t mNeeded;
96 : };
97 :
98 : template <class Derived>
99 : class EndianBufferWriterBase : public BufferWriter
100 : {
101 : public:
102 : // typed BufferWriter forwards
103 :
104 737 : Derived & Put(const char * s) { return static_cast<Derived &>(BufferWriter::Put(s)); }
105 507 : Derived & Put(const void * buf, size_t len) { return static_cast<Derived &>(BufferWriter::Put(buf, len)); }
106 1099250 : Derived & Put(uint8_t c) { return static_cast<Derived &>(BufferWriter::Put(c)); }
107 104 : Derived & Skip(size_t len) { return static_cast<Derived &>(BufferWriter::Skip(len)); }
108 :
109 : // write an integer into a buffer, in an endian-specific way
110 :
111 579619 : Derived & Put8(uint8_t c) { return static_cast<Derived *>(this)->Put(c); }
112 8865 : Derived & Put16(uint16_t x) { return static_cast<Derived *>(this)->EndianPut(x, sizeof(x)); }
113 21909 : Derived & Put32(uint32_t x) { return static_cast<Derived *>(this)->EndianPut(x, sizeof(x)); }
114 19421 : Derived & Put64(uint64_t x) { return static_cast<Derived *>(this)->EndianPut(x, sizeof(x)); }
115 :
116 : Derived & PutSigned8(int8_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
117 : Derived & PutSigned16(int16_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
118 : Derived & PutSigned32(int32_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
119 : Derived & PutSigned64(int64_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
120 :
121 : protected:
122 387343 : EndianBufferWriterBase(uint8_t * buf, size_t len) : BufferWriter(buf, len) {}
123 66 : EndianBufferWriterBase(MutableByteSpan buf) : BufferWriter(buf.data(), buf.size()) {}
124 : EndianBufferWriterBase(const EndianBufferWriterBase & other) = default;
125 : EndianBufferWriterBase & operator=(const EndianBufferWriterBase & other) = default;
126 : };
127 :
128 : namespace LittleEndian {
129 :
130 : class BufferWriter : public EndianBufferWriterBase<BufferWriter>
131 : {
132 : public:
133 387271 : BufferWriter(uint8_t * buf, size_t len) : EndianBufferWriterBase<BufferWriter>(buf, len)
134 : {
135 : static_assert((-1 & 3) == 3, "LittleEndian::BufferWriter only works with 2's complement architectures.");
136 387271 : }
137 66 : BufferWriter(MutableByteSpan buf) : EndianBufferWriterBase<BufferWriter>(buf) {}
138 : BufferWriter(const BufferWriter & other) = default;
139 : BufferWriter & operator=(const BufferWriter & other) = default;
140 : BufferWriter & EndianPut(uint64_t x, size_t size);
141 : BufferWriter & EndianPutSigned(int64_t x, size_t size);
142 : };
143 :
144 : } // namespace LittleEndian
145 :
146 : namespace BigEndian {
147 :
148 : class BufferWriter : public EndianBufferWriterBase<BufferWriter>
149 : {
150 : public:
151 72 : BufferWriter(uint8_t * buf, size_t len) : EndianBufferWriterBase<BufferWriter>(buf, len)
152 : {
153 : static_assert((-1 & 3) == 3, "BigEndian::BufferWriter only works with 2's complement architectures.");
154 72 : }
155 : BufferWriter(MutableByteSpan buf) : EndianBufferWriterBase<BufferWriter>(buf) {}
156 : BufferWriter(const BufferWriter & other) = default;
157 : BufferWriter & operator=(const BufferWriter & other) = default;
158 : BufferWriter & EndianPut(uint64_t x, size_t size);
159 : BufferWriter & EndianPutSigned(int64_t x, size_t size);
160 : };
161 :
162 : } // namespace BigEndian
163 :
164 : } // namespace Encoding
165 : } // namespace chip
|