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
|
/**
* Buffering Central
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
#include <botan/buf_op.h>
#include <botan/mem_ops.h>
#include <botan/internal/rounding.h>
#include <stdexcept>
#include <stdio.h>
#include <assert.h>
namespace Botan {
namespace {
const size_t BUFFER_MULTIPLE = 2;
//static_assert(BUFFER_MULTIPLE >= 2, "BUFFER_MULTIPLE must be >= 2");
}
Buffered_Operation::Buffered_Operation(callback_fn m_fn,
callback_fn f_fn,
size_t buf_mod,
size_t final_minimum) :
main_fn(m_fn), final_fn(f_fn),
final_minimum(final_minimum), main_block_mod(buf_mod),
buffer(BUFFER_MULTIPLE * buf_mod), buffer_pos(0)
{
if(buf_mod == 0)
throw std::invalid_argument("buf_mod == 0");
if(final_minimum > buf_mod)
throw std::invalid_argument("final_minimum > buf_mod");
}
void Buffered_Operation::reset()
{
clear_mem(&buffer[0], buffer.size());
buffer_pos = 0;
}
void Buffered_Operation::write(const byte input[],
size_t input_size)
{
if(!input_size)
return;
if(buffer_pos + input_size >= main_block_mod + final_minimum)
{
size_t to_copy = std::min(buffer.size() - buffer_pos, input_size);
copy_mem(&buffer[buffer_pos], input, to_copy);
buffer_pos += to_copy;
input += to_copy;
input_size -= to_copy;
if(input_size >= final_minimum)
{
size_t to_proc = round_down(buffer_pos, main_block_mod);
main_fn(&buffer[0], to_proc);
buffer_pos -= to_proc;
copy_mem(&buffer[0], &buffer[to_proc], buffer_pos);
}
}
if(input_size >= final_minimum)
{
size_t full_blocks = (input_size - final_minimum) / buffer.size();
size_t to_copy = full_blocks * buffer.size();
if(to_copy)
{
main_fn(input, to_copy);
input += to_copy;
input_size -= to_copy;
}
}
assert(input_size + buffer_pos <= buffer.size());
copy_mem(&buffer[buffer_pos], input, input_size);
buffer_pos += input_size;
}
void Buffered_Operation::final()
{
assert(buffer_pos >= final_minimum);
if(buffer_pos < final_minimum)
throw std::runtime_error("Buffered_Operation::final - not enough input");
size_t spare_blocks = (buffer_pos - final_minimum) / main_block_mod;
if(spare_blocks)
{
size_t spare_bytes = main_block_mod * spare_blocks;
assert(spare_bytes <= buffer_pos);
main_fn(&buffer[0], spare_bytes);
assert(buffer_pos - spare_bytes >= final_minimum);
final_fn(&buffer[spare_bytes], buffer_pos - spare_bytes);
}
else
{
final_fn(&buffer[0], buffer_pos);
}
}
}
|