1 | // Copyright (C) 2018 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef BITSTREAMS_P_H |
5 | #define BITSTREAMS_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of other Qt classes. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtCore/private/qglobal_p.h> |
19 | #include <QtCore/qdebug.h> |
20 | |
21 | #include <type_traits> |
22 | #include <algorithm> |
23 | #include <vector> |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | class QByteArray; |
28 | |
29 | namespace HPack |
30 | { |
31 | |
32 | // BitOStream works with an external buffer, |
33 | // for example, HEADERS frame. |
34 | class Q_AUTOTEST_EXPORT BitOStream |
35 | { |
36 | public: |
37 | BitOStream(std::vector<uchar> &buffer); |
38 | |
39 | // Write 'bitLength' bits from the least significant |
40 | // bits in 'bits' to bitstream: |
41 | void writeBits(uchar bits, quint8 bitLength); |
42 | // HPACK data format, we support: |
43 | // * 32-bit integers |
44 | // * strings |
45 | void write(quint32 src); |
46 | void write(QByteArrayView src, bool compressed); |
47 | |
48 | quint64 bitLength() const; |
49 | quint64 byteLength() const; |
50 | const uchar *begin() const; |
51 | const uchar *end() const; |
52 | |
53 | void clear(); |
54 | |
55 | private: |
56 | Q_DISABLE_COPY_MOVE(BitOStream); |
57 | |
58 | std::vector<uchar> &buffer; |
59 | quint64 bitsSet; |
60 | }; |
61 | |
62 | class Q_AUTOTEST_EXPORT BitIStream |
63 | { |
64 | public: |
65 | // Error is set by 'read' functions. |
66 | // 'peek' does not set the error, |
67 | // since it just peeks some bits |
68 | // without the notion of wrong/right. |
69 | // 'read' functions only change 'streamOffset' |
70 | // on success. |
71 | enum class Error |
72 | { |
73 | NoError, |
74 | NotEnoughData, |
75 | CompressionError, |
76 | InvalidInteger |
77 | }; |
78 | |
79 | BitIStream(); |
80 | BitIStream(const uchar *f, const uchar *l); |
81 | |
82 | quint64 bitLength() const; |
83 | bool hasMoreBits() const; |
84 | |
85 | // peekBits tries to read 'length' bits from the bitstream into |
86 | // 'dst' ('length' must be <= sizeof(dst) * 8), packing them |
87 | // starting from the most significant bit of the most significant |
88 | // byte. It's a template so that we can use it with different |
89 | // integer types. Returns the number of bits actually read. |
90 | // Does not change stream's offset. |
91 | |
92 | template<class T> |
93 | quint64 peekBits(quint64 from, quint64 length, T *dstPtr) const |
94 | { |
95 | static_assert(std::is_unsigned<T>::value, "peekBits: unsigned integer type expected" ); |
96 | |
97 | Q_ASSERT(dstPtr); |
98 | Q_ASSERT(length <= sizeof(T) * 8); |
99 | |
100 | if (from >= bitLength() || !length) |
101 | return 0; |
102 | |
103 | T &dst = *dstPtr; |
104 | dst = T(); |
105 | length = std::min(a: length, b: bitLength() - from); |
106 | |
107 | const uchar *srcByte = first + from / 8; |
108 | auto bitsToRead = length + from % 8; |
109 | |
110 | while (bitsToRead > 8) { |
111 | dst = (dst << 8) | *srcByte; |
112 | bitsToRead -= 8; |
113 | ++srcByte; |
114 | } |
115 | |
116 | dst <<= bitsToRead; |
117 | dst |= *srcByte >> (8 - bitsToRead); |
118 | dst <<= sizeof(T) * 8 - length; |
119 | |
120 | return length; |
121 | } |
122 | |
123 | quint64 streamOffset() const |
124 | { |
125 | return offset; |
126 | } |
127 | |
128 | bool skipBits(quint64 nBits); |
129 | bool rewindOffset(quint64 nBits); |
130 | |
131 | bool read(quint32 *dstPtr); |
132 | bool read(QByteArray *dstPtr); |
133 | |
134 | Error error() const; |
135 | |
136 | private: |
137 | void setError(Error newState); |
138 | |
139 | const uchar *first; |
140 | const uchar *last; |
141 | quint64 offset; |
142 | Error streamError; |
143 | }; |
144 | |
145 | } // namespace HPack |
146 | |
147 | QT_END_NAMESPACE |
148 | |
149 | #endif |
150 | |