Botan
1.11.15
|
00001 /* 00002 * Buffered Filter 00003 * (C) 1999-2007 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/buf_filt.h> 00009 #include <botan/mem_ops.h> 00010 #include <botan/internal/rounding.h> 00011 #include <stdexcept> 00012 00013 namespace Botan { 00014 00015 /* 00016 * Buffered_Filter Constructor 00017 */ 00018 Buffered_Filter::Buffered_Filter(size_t b, size_t f) : 00019 main_block_mod(b), final_minimum(f) 00020 { 00021 if(main_block_mod == 0) 00022 throw std::invalid_argument("main_block_mod == 0"); 00023 00024 if(final_minimum > main_block_mod) 00025 throw std::invalid_argument("final_minimum > main_block_mod"); 00026 00027 buffer.resize(2 * main_block_mod); 00028 buffer_pos = 0; 00029 } 00030 00031 /* 00032 * Buffer input into blocks, trying to minimize copying 00033 */ 00034 void Buffered_Filter::write(const byte input[], size_t input_size) 00035 { 00036 if(!input_size) 00037 return; 00038 00039 if(buffer_pos + input_size >= main_block_mod + final_minimum) 00040 { 00041 size_t to_copy = std::min<size_t>(buffer.size() - buffer_pos, input_size); 00042 00043 copy_mem(&buffer[buffer_pos], input, to_copy); 00044 buffer_pos += to_copy; 00045 00046 input += to_copy; 00047 input_size -= to_copy; 00048 00049 size_t total_to_consume = 00050 round_down(std::min(buffer_pos, 00051 buffer_pos + input_size - final_minimum), 00052 main_block_mod); 00053 00054 buffered_block(&buffer[0], total_to_consume); 00055 00056 buffer_pos -= total_to_consume; 00057 00058 copy_mem(&buffer[0], &buffer[0] + total_to_consume, buffer_pos); 00059 } 00060 00061 if(input_size >= final_minimum) 00062 { 00063 size_t full_blocks = (input_size - final_minimum) / main_block_mod; 00064 size_t to_copy = full_blocks * main_block_mod; 00065 00066 if(to_copy) 00067 { 00068 buffered_block(input, to_copy); 00069 00070 input += to_copy; 00071 input_size -= to_copy; 00072 } 00073 } 00074 00075 copy_mem(&buffer[buffer_pos], input, input_size); 00076 buffer_pos += input_size; 00077 } 00078 00079 /* 00080 * Finish/flush operation 00081 */ 00082 void Buffered_Filter::end_msg() 00083 { 00084 if(buffer_pos < final_minimum) 00085 throw std::runtime_error("Buffered filter end_msg without enough input"); 00086 00087 size_t spare_blocks = (buffer_pos - final_minimum) / main_block_mod; 00088 00089 if(spare_blocks) 00090 { 00091 size_t spare_bytes = main_block_mod * spare_blocks; 00092 buffered_block(&buffer[0], spare_bytes); 00093 buffered_final(&buffer[spare_bytes], buffer_pos - spare_bytes); 00094 } 00095 else 00096 { 00097 buffered_final(&buffer[0], buffer_pos); 00098 } 00099 00100 buffer_pos = 0; 00101 } 00102 00103 }