summaryrefslogtreecommitdiff
path: root/queue.h
blob: f2d0dc53fb56b2fcfb31c3ad34d00d6ccd949249 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// queue.h - originally written and placed in the public domain by Wei Dai

/// \file
/// \brief Classes for an unlimited queue to store bytes

#ifndef CRYPTOPP_QUEUE_H
#define CRYPTOPP_QUEUE_H

#include "cryptlib.h"
#include "simple.h"

NAMESPACE_BEGIN(CryptoPP)

class ByteQueueNode;

/// \brief Data structure used to store byte strings
/// \details The queue is implemented as a linked list of byte arrays.
///  Each byte array is stored in a ByteQueueNode.
/// \sa <A HREF="https://www.cryptopp.com/wiki/ByteQueue">ByteQueue</A>
///  on the Crypto++ wiki.
/// \since Crypto++ 2.0
class CRYPTOPP_DLL ByteQueue : public Bufferless<BufferedTransformation>
{
public:
	virtual ~ByteQueue();

	/// \brief Construct a ByteQueue
	/// \param nodeSize the initial node size
	/// \details Internally, ByteQueue uses a ByteQueueNode to store bytes,
	///  and <tt>nodeSize</tt> determines the size of the ByteQueueNode. A value
	///  of 0 indicates the ByteQueueNode should be automatically sized,
	///  which means a value of 256 is used.
	ByteQueue(size_t nodeSize=0);

	/// \brief Copy construct a ByteQueue
	/// \param copy the other ByteQueue
	ByteQueue(const ByteQueue &copy);

	// BufferedTransformation
	lword MaxRetrievable() const
		{return CurrentSize();}
	bool AnyRetrievable() const
		{return !IsEmpty();}

	void IsolatedInitialize(const NameValuePairs &parameters);
	byte * CreatePutSpace(size_t &size);
	size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);

	size_t Get(byte &outByte);
	size_t Get(byte *outString, size_t getMax);

	size_t Peek(byte &outByte) const;
	size_t Peek(byte *outString, size_t peekMax) const;

	size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
	size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;

	/// \brief Set node size
	/// \param nodeSize the new node size, in bytes
	/// \details The default node size is 256.
	void SetNodeSize(size_t nodeSize);

	/// \brief Determine data size
	/// \return the data size, in bytes
	lword CurrentSize() const;

	/// \brief Determine data availability
	/// \return true if the ByteQueue has data, false otherwise
	bool IsEmpty() const;

	/// \brief Empty the queue
	void Clear();

	/// \brief Insert data in the queue
	/// \param inByte a byte to insert
	/// \details Unget() inserts a byte at the head of the queue
	void Unget(byte inByte);

	/// \brief Insert data in the queue
	/// \param inString a byte array to insert
	/// \param length the size of the byte array
	/// \details Unget() inserts a byte array at the head of the queue
	void Unget(const byte *inString, size_t length);

	/// \brief Peek data in the queue
	/// \param contiguousSize the size of the data
	/// \details Spy() peeks at data at the head of the queue. Spy() does
	///  not remove data from the queue.
	/// \details The data's size is returned in <tt>contiguousSize</tt>.
	///  Spy() returns the size of the first byte array in the list. The
	///  entire data may be larger since the queue is a linked list of
	///  byte arrays.
	const byte * Spy(size_t &contiguousSize) const;

	/// \brief Insert data in the queue
	/// \param inString a byte array to insert
	/// \param size the length of the byte array
	/// \details LazyPut() inserts a byte array at the tail of the queue.
	///  The data may not be copied at this point. Rather, the pointer
	///  and size to external data are recorded.
	/// \details Another call to Put() or LazyPut() will force the data to
	///  be copied. When lazy puts are used, the data is copied when
	///  FinalizeLazyPut() is called.
	/// \sa LazyPutter
	void LazyPut(const byte *inString, size_t size);

	/// \brief Insert data in the queue
	/// \param inString a byte array to insert
	/// \param size the length of the byte array
	/// \details LazyPut() inserts a byte array at the tail of the queue.
	///  The data may not be copied at this point. Rather, the pointer
	///  and size to external data are recorded.
	/// \details Another call to Put() or LazyPut() will force the data to
	///  be copied. When lazy puts are used, the data is copied when
	///  FinalizeLazyPut() is called.
	/// \sa LazyPutter
	void LazyPutModifiable(byte *inString, size_t size);

	/// \brief Remove data from the queue
	/// \param size the length of the data
	/// \throw InvalidArgument if there is no lazy data in the queue or if
	///  size is larger than the lazy string
	/// \details UndoLazyPut() truncates data inserted using LazyPut() by
	///  modifying size.
	/// \sa LazyPutter
	void UndoLazyPut(size_t size);

	/// \brief Insert data in the queue
	/// \details FinalizeLazyPut() copies external data inserted using
	///  LazyPut() or LazyPutModifiable() into the tail of the queue.
	/// \sa LazyPutter
	void FinalizeLazyPut();

	/// \brief Assign contents from another ByteQueue
	/// \param rhs the other ByteQueue
	/// \return reference to this ByteQueue
	ByteQueue & operator=(const ByteQueue &rhs);

	/// \brief Bitwise compare two ByteQueue
	/// \param rhs the other ByteQueue
	/// \return true if the size and bits are equal, false otherwise
	/// \details operator==() walks each ByteQueue comparing bytes in
	///  each queue. operator==() is not constant time.
	bool operator==(const ByteQueue &rhs) const;

	/// \brief Bitwise compare two ByteQueue
	/// \param rhs the other ByteQueue
	/// \return true if the size and bits are not equal, false otherwise
	/// \details operator!=() is implemented in terms of operator==().
	///  operator==() is not constant time.
	bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);}

	/// \brief Retrieve data from the queue
	/// \param index of byte to retrieve
	/// \return byte at the specified index
	/// \details operator[]() does not perform bounds checking.
	byte operator[](lword index) const;

	/// \brief Swap contents with another ByteQueue
	/// \param rhs the other ByteQueue
	void swap(ByteQueue &rhs);

	/// \brief A ByteQueue iterator
	class Walker : public InputRejecting<BufferedTransformation>
	{
	public:
		/// \brief Construct a ByteQueue Walker
		/// \param queue a ByteQueue
		Walker(const ByteQueue &queue)
			: m_queue(queue), m_node(NULLPTR), m_position(0), m_offset(0), m_lazyString(NULLPTR), m_lazyLength(0)
				{Initialize();}

		lword GetCurrentPosition() {return m_position;}

		lword MaxRetrievable() const
			{return m_queue.CurrentSize() - m_position;}

		void IsolatedInitialize(const NameValuePairs &parameters);

		size_t Get(byte &outByte);
		size_t Get(byte *outString, size_t getMax);

		size_t Peek(byte &outByte) const;
		size_t Peek(byte *outString, size_t peekMax) const;

		size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
		size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;

	private:
		const ByteQueue &m_queue;
		const ByteQueueNode *m_node;
		lword m_position;
		size_t m_offset;
		const byte *m_lazyString;
		size_t m_lazyLength;
	};

	friend class Walker;

protected:
	void CleanupUsedNodes();
	void CopyFrom(const ByteQueue &copy);
	void Destroy();

private:
	ByteQueueNode *m_head, *m_tail;
	byte *m_lazyString;
	size_t m_lazyLength;
	size_t m_nodeSize;
	bool m_lazyStringModifiable;
	bool m_autoNodeSize;
};

/// \brief Helper class to finalize Puts on ByteQueue
/// \details LazyPutter ensures LazyPut is committed to the ByteQueue
///  in event of exception. During destruction, the LazyPutter class
///  calls FinalizeLazyPut.
class CRYPTOPP_DLL LazyPutter
{
public:
	virtual ~LazyPutter() {
		try {m_bq.FinalizeLazyPut();}
		catch(const Exception&) {CRYPTOPP_ASSERT(0);}
	}

	/// \brief Construct a LazyPutter
	/// \param bq the ByteQueue
	/// \param inString a byte array to insert
	/// \param size the length of the byte array
	/// \details LazyPutter ensures LazyPut is committed to the ByteQueue
	///  in event of exception. During destruction, the LazyPutter class
	///  calls FinalizeLazyPut.
	LazyPutter(ByteQueue &bq, const byte *inString, size_t size)
		: m_bq(bq) {bq.LazyPut(inString, size);}

protected:
	LazyPutter(ByteQueue &bq) : m_bq(bq) {}

private:
	ByteQueue &m_bq;
};

/// \brief Helper class to finalize Puts on ByteQueue
/// \details LazyPutterModifiable ensures LazyPut is committed to the
///  ByteQueue in event of exception. During destruction, the
///  LazyPutterModifiable class calls FinalizeLazyPut.
class LazyPutterModifiable : public LazyPutter
{
public:
	/// \brief Construct a LazyPutterModifiable
	/// \param bq the ByteQueue
	/// \param inString a byte array to insert
	/// \param size the length of the byte array
	/// \details LazyPutterModifiable ensures LazyPut is committed to the
	///  ByteQueue in event of exception. During destruction, the
	///  LazyPutterModifiable class calls FinalizeLazyPut.
	LazyPutterModifiable(ByteQueue &bq, byte *inString, size_t size)
		: LazyPutter(bq) {bq.LazyPutModifiable(inString, size);}
};

NAMESPACE_END

#ifndef __BORLANDC__
NAMESPACE_BEGIN(std)
template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b)
{
	a.swap(b);
}
NAMESPACE_END
#endif

#endif