#include <cstdint>
#include <iostream>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <memory>
class BufferedReader {
public:
explicit BufferedReader(PackageStream* stream) : stream(stream),
buffer(new char[stream->PackageLen() * 2]), d(0) {
}
~BufferedReader() {
delete[] buffer;
}
int32_t Read(char* output_buffer, int32_t buffer_len) {
int32_t pos = 0;
if (d > 0) {
memcpy(output_buffer, buffer, std::min(d, buffer_len));
pos = std::min(d, buffer_len);
d -= pos;
memmove(buffer, buffer + pos, d);
}
if (pos >= buffer_len)
return pos;
int32_t new_len = stream->ReadPackage(buffer);
int32_t cur_len = 0;
while (new_len > 0 && pos < buffer_len) {
cur_len = new_len;
memcpy(output_buffer + pos, buffer,
std::min(buffer_len - pos, cur_len));
d = cur_len - std::min(cur_len, buffer_len - pos);
pos += std::min(buffer_len - pos, cur_len);
if (pos < buffer_len)
new_len = stream->ReadPackage(buffer);
}
if (d > 0) {
memmove(buffer, buffer + (cur_len - d), d);
}
return pos;
}
private:
PackageStream* stream;
char* buffer;
int32_t d;
};