Line | Count | Source (jump to first uncovered line) |
1 | | // queue.cpp - originally written and placed in the public domain by Wei Dai |
2 | | |
3 | | #include "pch.h" |
4 | | |
5 | | #ifndef CRYPTOPP_IMPORTS |
6 | | |
7 | | #include "queue.h" |
8 | | #include "filters.h" |
9 | | #include "misc.h" |
10 | | #include "trap.h" |
11 | | |
12 | | NAMESPACE_BEGIN(CryptoPP) |
13 | | |
14 | | static const unsigned int s_maxAutoNodeSize = 16*1024u; |
15 | | |
16 | | // this class for use by ByteQueue only |
17 | | class ByteQueueNode |
18 | | { |
19 | | public: |
20 | | ByteQueueNode(size_t maxSize) |
21 | | : m_buf(maxSize) |
22 | 137k | { |
23 | | // See GH #962 for the reason for this assert. |
24 | 137k | CRYPTOPP_ASSERT(maxSize != SIZE_MAX); |
25 | | |
26 | 137k | m_head = m_tail = 0; |
27 | 137k | m_next = NULLPTR; |
28 | 137k | } |
29 | | |
30 | 4.91M | inline size_t MaxSize() const {return m_buf.size();} |
31 | | |
32 | | inline size_t CurrentSize() const |
33 | 5.73M | { |
34 | 5.73M | return m_tail-m_head; |
35 | 5.73M | } |
36 | | |
37 | | inline bool UsedUp() const |
38 | 24 | { |
39 | 24 | return (m_head==MaxSize()); |
40 | 24 | } |
41 | | |
42 | | inline void Clear() |
43 | 136k | { |
44 | 136k | m_head = m_tail = 0; |
45 | 136k | } |
46 | | |
47 | | inline size_t Put(const byte *begin, size_t length) |
48 | 5.04M | { |
49 | | // Avoid passing NULL to memcpy |
50 | 5.04M | if (!begin || !length) return length; |
51 | 4.91M | size_t l = STDMIN(length, MaxSize()-m_tail); |
52 | 4.91M | if (m_buf+m_tail != begin) |
53 | 4.91M | std::memcpy(m_buf+m_tail, begin, l); |
54 | 4.91M | m_tail += l; |
55 | 4.91M | return l; |
56 | 5.04M | } |
57 | | |
58 | | inline size_t Peek(byte &outByte) const |
59 | 0 | { |
60 | 0 | if (m_tail==m_head) |
61 | 0 | return 0; |
62 | | |
63 | 0 | outByte=m_buf[m_head]; |
64 | 0 | return 1; |
65 | 0 | } |
66 | | |
67 | | inline size_t Peek(byte *target, size_t copyMax) const |
68 | 0 | { |
69 | 0 | size_t len = STDMIN(copyMax, m_tail-m_head); |
70 | 0 | std::memcpy(target, m_buf+m_head, len); |
71 | 0 | return len; |
72 | 0 | } |
73 | | |
74 | | inline size_t CopyTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const |
75 | 0 | { |
76 | 0 | size_t len = m_tail-m_head; |
77 | 0 | target.ChannelPut(channel, m_buf+m_head, len); |
78 | 0 | return len; |
79 | 0 | } |
80 | | |
81 | | inline size_t CopyTo(BufferedTransformation &target, size_t copyMax, const std::string &channel=DEFAULT_CHANNEL) const |
82 | 0 | { |
83 | 0 | size_t len = STDMIN(copyMax, m_tail-m_head); |
84 | 0 | target.ChannelPut(channel, m_buf+m_head, len); |
85 | 0 | return len; |
86 | 0 | } |
87 | | |
88 | | inline size_t Get(byte &outByte) |
89 | 0 | { |
90 | 0 | size_t len = Peek(outByte); |
91 | 0 | m_head += len; |
92 | 0 | return len; |
93 | 0 | } |
94 | | |
95 | | inline size_t Get(byte *outString, size_t getMax) |
96 | 0 | { |
97 | 0 | size_t len = Peek(outString, getMax); |
98 | 0 | m_head += len; |
99 | 0 | return len; |
100 | 0 | } |
101 | | |
102 | | inline size_t TransferTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) |
103 | 0 | { |
104 | 0 | size_t len = m_tail-m_head; |
105 | 0 | target.ChannelPutModifiable(channel, m_buf+m_head, len); |
106 | 0 | m_head = m_tail; |
107 | 0 | return len; |
108 | 0 | } |
109 | | |
110 | | inline size_t TransferTo(BufferedTransformation &target, lword transferMax, const std::string &channel=DEFAULT_CHANNEL) |
111 | 4.91M | { |
112 | 4.91M | size_t len = UnsignedMin(m_tail-m_head, transferMax); |
113 | 4.91M | target.ChannelPutModifiable(channel, m_buf+m_head, len); |
114 | 4.91M | m_head += len; |
115 | 4.91M | return len; |
116 | 4.91M | } |
117 | | |
118 | | inline size_t Skip(size_t skipMax) |
119 | 0 | { |
120 | 0 | size_t len = STDMIN(skipMax, m_tail-m_head); |
121 | 0 | m_head += len; |
122 | 0 | return len; |
123 | 0 | } |
124 | | |
125 | | inline byte operator[](size_t i) const |
126 | 0 | { |
127 | 0 | return m_buf[m_head+i]; |
128 | 0 | } |
129 | | |
130 | | ByteQueueNode* m_next; |
131 | | |
132 | | SecByteBlock m_buf; |
133 | | size_t m_head, m_tail; |
134 | | }; |
135 | | |
136 | | // ******************************************************** |
137 | | |
138 | | ByteQueue::ByteQueue(size_t nodeSize) |
139 | | : Bufferless<BufferedTransformation>() |
140 | | , m_head(NULLPTR), m_tail(NULLPTR), m_lazyString(NULLPTR), m_lazyLength(0) |
141 | | , m_nodeSize(nodeSize), m_lazyStringModifiable(false), m_autoNodeSize(!nodeSize) |
142 | 137k | { |
143 | | // See GH #962 for the reason for this assert. |
144 | 137k | CRYPTOPP_ASSERT(nodeSize != SIZE_MAX); |
145 | | |
146 | 137k | SetNodeSize(nodeSize); |
147 | 137k | m_head = m_tail = new ByteQueueNode(m_nodeSize); |
148 | 137k | } |
149 | | |
150 | | void ByteQueue::SetNodeSize(size_t nodeSize) |
151 | 137k | { |
152 | 137k | m_autoNodeSize = !nodeSize; |
153 | 137k | m_nodeSize = m_autoNodeSize ? 256 : nodeSize; |
154 | 137k | } |
155 | | |
156 | | ByteQueue::ByteQueue(const ByteQueue ©) |
157 | | : Bufferless<BufferedTransformation>(copy), m_lazyString(NULLPTR), m_lazyLength(0) |
158 | 0 | { |
159 | 0 | CopyFrom(copy); |
160 | 0 | } |
161 | | |
162 | | void ByteQueue::CopyFrom(const ByteQueue ©) |
163 | 0 | { |
164 | 0 | m_lazyLength = 0; |
165 | 0 | m_autoNodeSize = copy.m_autoNodeSize; |
166 | 0 | m_nodeSize = copy.m_nodeSize; |
167 | 0 | m_head = m_tail = new ByteQueueNode(*copy.m_head); |
168 | |
|
169 | 0 | for (ByteQueueNode *current=copy.m_head->m_next; current; current=current->m_next) |
170 | 0 | { |
171 | 0 | m_tail->m_next = new ByteQueueNode(*current); |
172 | 0 | m_tail = m_tail->m_next; |
173 | 0 | } |
174 | |
|
175 | 0 | m_tail->m_next = NULLPTR; |
176 | |
|
177 | 0 | Put(copy.m_lazyString, copy.m_lazyLength); |
178 | 0 | } |
179 | | |
180 | | ByteQueue::~ByteQueue() |
181 | 137k | { |
182 | 137k | Destroy(); |
183 | 137k | } |
184 | | |
185 | | void ByteQueue::Destroy() |
186 | 137k | { |
187 | 275k | for (ByteQueueNode *next, *current=m_head; current; current=next) |
188 | 137k | { |
189 | 137k | next=current->m_next; |
190 | 137k | delete current; |
191 | 137k | } |
192 | 137k | } |
193 | | |
194 | | void ByteQueue::IsolatedInitialize(const NameValuePairs ¶meters) |
195 | 0 | { |
196 | 0 | m_nodeSize = parameters.GetIntValueWithDefault("NodeSize", 256); |
197 | 0 | Clear(); |
198 | 0 | } |
199 | | |
200 | | lword ByteQueue::CurrentSize() const |
201 | 0 | { |
202 | 0 | lword size=0; |
203 | |
|
204 | 0 | for (ByteQueueNode *current=m_head; current; current=current->m_next) |
205 | 0 | size += current->CurrentSize(); |
206 | |
|
207 | 0 | return size + m_lazyLength; |
208 | 0 | } |
209 | | |
210 | | bool ByteQueue::IsEmpty() const |
211 | 0 | { |
212 | 0 | return m_head==m_tail && m_head->CurrentSize()==0 && m_lazyLength==0; |
213 | 0 | } |
214 | | |
215 | | void ByteQueue::Clear() |
216 | 0 | { |
217 | 0 | for (ByteQueueNode *next, *current=m_head->m_next; current; current=next) |
218 | 0 | { |
219 | 0 | next=current->m_next; |
220 | 0 | delete current; |
221 | 0 | } |
222 | |
|
223 | 0 | m_tail = m_head; |
224 | 0 | m_head->Clear(); |
225 | 0 | m_head->m_next = NULLPTR; |
226 | 0 | m_lazyLength = 0; |
227 | 0 | } |
228 | | |
229 | | size_t ByteQueue::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) |
230 | 5.04M | { |
231 | 5.04M | CRYPTOPP_UNUSED(messageEnd), CRYPTOPP_UNUSED(blocking); |
232 | | |
233 | 5.04M | if (m_lazyLength > 0) |
234 | 0 | FinalizeLazyPut(); |
235 | | |
236 | 5.04M | size_t len; |
237 | 5.04M | while ((len=m_tail->Put(inString, length)) < length) |
238 | 191 | { |
239 | 191 | inString = PtrAdd(inString, len); |
240 | 191 | length -= len; |
241 | 191 | if (m_autoNodeSize && m_nodeSize < s_maxAutoNodeSize) |
242 | 0 | { |
243 | 0 | do |
244 | 0 | { |
245 | 0 | m_nodeSize *= 2; |
246 | 0 | } |
247 | 0 | while (m_nodeSize < length && m_nodeSize < s_maxAutoNodeSize); |
248 | 0 | } |
249 | 191 | m_tail->m_next = new ByteQueueNode(STDMAX(m_nodeSize, length)); |
250 | 191 | m_tail = m_tail->m_next; |
251 | 191 | } |
252 | | |
253 | 5.04M | return 0; |
254 | 5.04M | } |
255 | | |
256 | | void ByteQueue::CleanupUsedNodes() |
257 | 4.91M | { |
258 | | // Test for m_head due to Enterprise Analysis finding |
259 | 4.91M | while (m_head && m_head != m_tail && m_head->UsedUp()) |
260 | 24 | { |
261 | 24 | ByteQueueNode *temp=m_head; |
262 | 24 | m_head=m_head->m_next; |
263 | 24 | delete temp; |
264 | 24 | } |
265 | | |
266 | | // Test for m_head due to Enterprise Analysis finding |
267 | 4.91M | if (m_head && m_head->CurrentSize() == 0) |
268 | 136k | m_head->Clear(); |
269 | 4.91M | } |
270 | | |
271 | | void ByteQueue::LazyPut(const byte *inString, size_t size) |
272 | 0 | { |
273 | 0 | if (m_lazyLength > 0) |
274 | 0 | FinalizeLazyPut(); |
275 | |
|
276 | 0 | if (inString == m_tail->m_buf+m_tail->m_tail) |
277 | 0 | Put(inString, size); |
278 | 0 | else |
279 | 0 | { |
280 | 0 | m_lazyString = const_cast<byte *>(inString); |
281 | 0 | m_lazyLength = size; |
282 | 0 | m_lazyStringModifiable = false; |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | void ByteQueue::LazyPutModifiable(byte *inString, size_t size) |
287 | 0 | { |
288 | 0 | if (m_lazyLength > 0) |
289 | 0 | FinalizeLazyPut(); |
290 | 0 | m_lazyString = inString; |
291 | 0 | m_lazyLength = size; |
292 | 0 | m_lazyStringModifiable = true; |
293 | 0 | } |
294 | | |
295 | | void ByteQueue::UndoLazyPut(size_t size) |
296 | 0 | { |
297 | 0 | if (m_lazyLength < size) |
298 | 0 | throw InvalidArgument("ByteQueue: size specified for UndoLazyPut is too large"); |
299 | | |
300 | 0 | m_lazyLength -= size; |
301 | 0 | } |
302 | | |
303 | | void ByteQueue::FinalizeLazyPut() |
304 | 0 | { |
305 | 0 | size_t len = m_lazyLength; |
306 | 0 | m_lazyLength = 0; |
307 | 0 | if (len) |
308 | 0 | Put(m_lazyString, len); |
309 | 0 | } |
310 | | |
311 | | size_t ByteQueue::Get(byte &outByte) |
312 | 0 | { |
313 | 0 | if (m_head->Get(outByte)) |
314 | 0 | { |
315 | 0 | if (m_head->UsedUp()) |
316 | 0 | CleanupUsedNodes(); |
317 | 0 | return 1; |
318 | 0 | } |
319 | 0 | else if (m_lazyLength > 0) |
320 | 0 | { |
321 | 0 | outByte = *m_lazyString++; |
322 | 0 | m_lazyLength--; |
323 | 0 | return 1; |
324 | 0 | } |
325 | 0 | else |
326 | 0 | return 0; |
327 | 0 | } |
328 | | |
329 | | size_t ByteQueue::Get(byte *outString, size_t getMax) |
330 | 0 | { |
331 | 0 | ArraySink sink(outString, getMax); |
332 | 0 | return (size_t)TransferTo(sink, getMax); |
333 | 0 | } |
334 | | |
335 | | size_t ByteQueue::Peek(byte &outByte) const |
336 | 0 | { |
337 | 0 | if (m_head->Peek(outByte)) |
338 | 0 | return 1; |
339 | 0 | else if (m_lazyLength > 0) |
340 | 0 | { |
341 | 0 | outByte = *m_lazyString; |
342 | 0 | return 1; |
343 | 0 | } |
344 | 0 | else |
345 | 0 | return 0; |
346 | 0 | } |
347 | | |
348 | | size_t ByteQueue::Peek(byte *outString, size_t peekMax) const |
349 | 0 | { |
350 | 0 | ArraySink sink(outString, peekMax); |
351 | 0 | return (size_t)CopyTo(sink, peekMax); |
352 | 0 | } |
353 | | |
354 | | size_t ByteQueue::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) |
355 | 4.91M | { |
356 | | // No need for CRYPTOPP_ASSERT on transferBytes here. |
357 | | // TransferTo2 handles LWORD_MAX as expected. |
358 | | |
359 | 4.91M | if (blocking) |
360 | 4.91M | { |
361 | 4.91M | lword bytesLeft = transferBytes; |
362 | 9.82M | for (ByteQueueNode *current=m_head; bytesLeft && current; current=current->m_next) |
363 | 4.91M | bytesLeft -= current->TransferTo(target, bytesLeft, channel); |
364 | 4.91M | CleanupUsedNodes(); |
365 | | |
366 | 4.91M | size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength); |
367 | 4.91M | if (len) |
368 | 0 | { |
369 | 0 | if (m_lazyStringModifiable) |
370 | 0 | target.ChannelPutModifiable(channel, m_lazyString, len); |
371 | 0 | else |
372 | 0 | target.ChannelPut(channel, m_lazyString, len); |
373 | 0 | m_lazyString = PtrAdd(m_lazyString, len); |
374 | 0 | m_lazyLength -= len; |
375 | 0 | bytesLeft -= len; |
376 | 0 | } |
377 | 4.91M | transferBytes -= bytesLeft; |
378 | 4.91M | return 0; |
379 | 4.91M | } |
380 | 0 | else |
381 | 0 | { |
382 | 0 | Walker walker(*this); |
383 | 0 | size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); |
384 | 0 | Skip(transferBytes); |
385 | 0 | return blockedBytes; |
386 | 0 | } |
387 | 4.91M | } |
388 | | |
389 | | size_t ByteQueue::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const |
390 | 412k | { |
391 | 412k | Walker walker(*this); |
392 | 412k | walker.Skip(begin); |
393 | 412k | lword transferBytes = end-begin; |
394 | | |
395 | 412k | size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); |
396 | 412k | begin += transferBytes; |
397 | 412k | return blockedBytes; |
398 | 412k | } |
399 | | |
400 | | void ByteQueue::Unget(byte inByte) |
401 | 0 | { |
402 | 0 | Unget(&inByte, 1); |
403 | 0 | } |
404 | | |
405 | | void ByteQueue::Unget(const byte *inString, size_t length) |
406 | 0 | { |
407 | | // See GH #962 for the reason for this assert. |
408 | 0 | CRYPTOPP_ASSERT(length != SIZE_MAX); |
409 | |
|
410 | 0 | size_t len = STDMIN(length, m_head->m_head); |
411 | 0 | length -= len; |
412 | 0 | m_head->m_head = m_head->m_head - len; |
413 | 0 | std::memcpy(m_head->m_buf + m_head->m_head, inString + length, len); |
414 | |
|
415 | 0 | if (length > 0) |
416 | 0 | { |
417 | 0 | ByteQueueNode *newHead = new ByteQueueNode(length); |
418 | 0 | newHead->m_next = m_head; |
419 | 0 | m_head = newHead; |
420 | 0 | m_head->Put(inString, length); |
421 | 0 | } |
422 | 0 | } |
423 | | |
424 | | const byte * ByteQueue::Spy(size_t &contiguousSize) const |
425 | 0 | { |
426 | 0 | contiguousSize = m_head->m_tail - m_head->m_head; |
427 | 0 | if (contiguousSize == 0 && m_lazyLength > 0) |
428 | 0 | { |
429 | 0 | contiguousSize = m_lazyLength; |
430 | 0 | return m_lazyString; |
431 | 0 | } |
432 | 0 | else |
433 | 0 | return m_head->m_buf + m_head->m_head; |
434 | 0 | } |
435 | | |
436 | | byte * ByteQueue::CreatePutSpace(size_t &size) |
437 | 0 | { |
438 | | // See GH #962 for the reason for this assert. |
439 | 0 | CRYPTOPP_ASSERT(size != SIZE_MAX); |
440 | | // Sanity check for a reasonable size |
441 | 0 | CRYPTOPP_ASSERT(size <= 16U*1024*1024); |
442 | |
|
443 | 0 | if (m_lazyLength > 0) |
444 | 0 | FinalizeLazyPut(); |
445 | |
|
446 | 0 | if (m_tail->m_tail == m_tail->MaxSize()) |
447 | 0 | { |
448 | 0 | m_tail->m_next = new ByteQueueNode(STDMAX(m_nodeSize, size)); |
449 | 0 | m_tail = m_tail->m_next; |
450 | 0 | } |
451 | |
|
452 | 0 | size = m_tail->MaxSize() - m_tail->m_tail; |
453 | 0 | return PtrAdd(m_tail->m_buf.begin(), m_tail->m_tail); |
454 | 0 | } |
455 | | |
456 | | ByteQueue & ByteQueue::operator=(const ByteQueue &rhs) |
457 | 0 | { |
458 | 0 | Destroy(); |
459 | 0 | CopyFrom(rhs); |
460 | 0 | return *this; |
461 | 0 | } |
462 | | |
463 | | bool ByteQueue::operator==(const ByteQueue &rhs) const |
464 | 0 | { |
465 | 0 | const lword currentSize = CurrentSize(); |
466 | |
|
467 | 0 | if (currentSize != rhs.CurrentSize()) |
468 | 0 | return false; |
469 | | |
470 | 0 | Walker walker1(*this), walker2(rhs); |
471 | 0 | byte b1, b2; |
472 | |
|
473 | 0 | while (walker1.Get(b1) && walker2.Get(b2)) |
474 | 0 | if (b1 != b2) |
475 | 0 | return false; |
476 | | |
477 | 0 | return true; |
478 | 0 | } |
479 | | |
480 | | byte ByteQueue::operator[](lword index) const |
481 | 0 | { |
482 | 0 | for (ByteQueueNode *current=m_head; current; current=current->m_next) |
483 | 0 | { |
484 | 0 | if (index < current->CurrentSize()) |
485 | 0 | return (*current)[(size_t)index]; |
486 | | |
487 | 0 | index -= current->CurrentSize(); |
488 | 0 | } |
489 | | |
490 | 0 | CRYPTOPP_ASSERT(index < m_lazyLength); |
491 | 0 | return m_lazyString[index]; |
492 | 0 | } |
493 | | |
494 | | void ByteQueue::swap(ByteQueue &rhs) |
495 | 0 | { |
496 | 0 | std::swap(m_autoNodeSize, rhs.m_autoNodeSize); |
497 | 0 | std::swap(m_nodeSize, rhs.m_nodeSize); |
498 | 0 | std::swap(m_head, rhs.m_head); |
499 | 0 | std::swap(m_tail, rhs.m_tail); |
500 | 0 | std::swap(m_lazyString, rhs.m_lazyString); |
501 | 0 | std::swap(m_lazyLength, rhs.m_lazyLength); |
502 | 0 | std::swap(m_lazyStringModifiable, rhs.m_lazyStringModifiable); |
503 | 0 | } |
504 | | |
505 | | // ******************************************************** |
506 | | |
507 | | void ByteQueue::Walker::IsolatedInitialize(const NameValuePairs ¶meters) |
508 | 412k | { |
509 | 412k | CRYPTOPP_UNUSED(parameters); |
510 | | |
511 | 412k | m_node = m_queue.m_head; |
512 | 412k | m_position = 0; |
513 | 412k | m_offset = 0; |
514 | 412k | m_lazyString = m_queue.m_lazyString; |
515 | 412k | m_lazyLength = m_queue.m_lazyLength; |
516 | 412k | } |
517 | | |
518 | | size_t ByteQueue::Walker::Get(byte &outByte) |
519 | 0 | { |
520 | 0 | ArraySink sink(&outByte, 1); |
521 | 0 | return (size_t)TransferTo(sink, 1); |
522 | 0 | } |
523 | | |
524 | | size_t ByteQueue::Walker::Get(byte *outString, size_t getMax) |
525 | 0 | { |
526 | 0 | ArraySink sink(outString, getMax); |
527 | 0 | return (size_t)TransferTo(sink, getMax); |
528 | 0 | } |
529 | | |
530 | | size_t ByteQueue::Walker::Peek(byte &outByte) const |
531 | 0 | { |
532 | 0 | ArraySink sink(&outByte, 1); |
533 | 0 | return (size_t)CopyTo(sink, 1); |
534 | 0 | } |
535 | | |
536 | | size_t ByteQueue::Walker::Peek(byte *outString, size_t peekMax) const |
537 | 0 | { |
538 | 0 | ArraySink sink(outString, peekMax); |
539 | 0 | return (size_t)CopyTo(sink, peekMax); |
540 | 0 | } |
541 | | |
542 | | size_t ByteQueue::Walker::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) |
543 | 825k | { |
544 | | // No need for CRYPTOPP_ASSERT on transferBytes here. |
545 | | // TransferTo2 handles LWORD_MAX as expected. |
546 | | |
547 | 825k | lword bytesLeft = transferBytes; |
548 | 825k | size_t blockedBytes = 0; |
549 | | |
550 | 825k | while (m_node) |
551 | 825k | { |
552 | 825k | size_t len = (size_t)STDMIN(bytesLeft, (lword)m_node->CurrentSize()-m_offset); |
553 | 825k | blockedBytes = target.ChannelPut2(channel, m_node->m_buf+m_node->m_head+m_offset, len, 0, blocking); |
554 | | |
555 | 825k | if (blockedBytes) |
556 | 0 | goto done; |
557 | | |
558 | 825k | m_position += len; |
559 | 825k | bytesLeft -= len; |
560 | | |
561 | 825k | if (!bytesLeft) |
562 | 825k | { |
563 | 825k | m_offset += len; |
564 | 825k | goto done; |
565 | 825k | } |
566 | | |
567 | 0 | m_node = m_node->m_next; |
568 | 0 | m_offset = 0; |
569 | 0 | } |
570 | | |
571 | 0 | if (bytesLeft && m_lazyLength) |
572 | 0 | { |
573 | 0 | size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength); |
574 | 0 | blockedBytes = target.ChannelPut2(channel, m_lazyString, len, 0, blocking); |
575 | 0 | if (blockedBytes) |
576 | 0 | goto done; |
577 | | |
578 | 0 | m_lazyString = PtrAdd(m_lazyString, len); |
579 | 0 | m_lazyLength -= len; |
580 | 0 | bytesLeft -= len; |
581 | 0 | } |
582 | | |
583 | 825k | done: |
584 | 825k | transferBytes -= bytesLeft; |
585 | 825k | return blockedBytes; |
586 | 0 | } |
587 | | |
588 | | size_t ByteQueue::Walker::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const |
589 | 0 | { |
590 | 0 | Walker walker(*this); |
591 | 0 | walker.Skip(begin); |
592 | 0 | lword transferBytes = end-begin; |
593 | |
|
594 | 0 | size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); |
595 | 0 | begin += transferBytes; |
596 | 0 | return blockedBytes; |
597 | 0 | } |
598 | | |
599 | | NAMESPACE_END |
600 | | |
601 | | #endif |