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

source code of qtbase/src/network/access/http2/bitstreams_p.h