hessian2/basic_codec/byte_codec.cc (114 lines of code) (raw):
#include "hessian2/basic_codec/byte_codec.hpp"
namespace Hessian2 {
namespace {
constexpr size_t CHUNK_SIZE = 1024;
}
// # 8-bit binary data split into 64k chunks
// ::= x41(A) b1 b0 <binary-data> binary # non-final chunk
// ::= x42(B) b1 b0 <binary-data> # final chunk
// ::= [x20-x2f] <binary-data> # binary data of length 0-15
// ::= [x34-x37] <binary-data> # binary data of length 0-1023
template <>
std::unique_ptr<std::vector<uint8_t>> Decoder::decode() {
auto out = std::make_unique<std::vector<uint8_t>>();
if (!decodeBytesWithReader(*out.get(), reader_)) {
return nullptr;
}
return out;
}
bool decodeBytesWithReader(std::vector<uint8_t> &output, ReaderPtr &reader) {
uint8_t code = reader->read<uint8_t>().second;
switch (code) {
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
if (!readBytes(output, reader, code - 0x20, true)) {
return false;
}
return true;
case 0x34:
case 0x35:
case 0x36:
case 0x37: {
auto res = reader->read<uint8_t>();
if (!res.first ||
!readBytes(output, reader, ((code - 0x34) << 8) + res.second, true)) {
return false;
}
return true;
}
case 0x42: {
auto res = reader->readBE<uint16_t>();
if (!res.first) {
return false;
}
return readBytes(output, reader, res.second, true);
}
case 0x41: {
auto res = reader->readBE<uint16_t>();
if (!res.first) {
return false;
}
return readBytes(output, reader, res.second, false);
}
}
return false;
}
// # 8-bit binary data split into 64k chunks
// ::= x41('A') b1 b0 <binary-data> binary # non-final chunk
// ::= x42('B') b1 b0 <binary-data> # final chunk
// ::= [x20-x2f] <binary-data> # binary data of length 0-15
// ::= [x34-x37] <binary-data> # binary data of length 0-1023
template <>
bool Encoder::encode(const std::vector<uint8_t> &data) {
size_t size = data.size();
if (size < 16) {
writer_->writeByte(0x20 + size);
writer_->rawWrite(
absl::string_view(std::move(std::string(data.begin(), data.end()))));
return true;
}
if (size < 1024) {
writer_->writeByte(0x34 + (size >> 8));
writer_->writeByte(size);
writer_->rawWrite(
absl::string_view(std::move(std::string(data.begin(), data.end()))));
return true;
}
uint32_t offset = 0;
while (size > CHUNK_SIZE) {
writer_->writeByte(0x41);
writer_->writeBE<uint16_t>(CHUNK_SIZE);
size -= CHUNK_SIZE;
writer_->rawWrite(absl::string_view(std::move(std::string(
data.begin() + offset, data.begin() + offset + CHUNK_SIZE))));
offset += CHUNK_SIZE;
}
if (size > 0) {
writer_->writeByte(0x42);
writer_->writeBE<uint16_t>(size);
writer_->rawWrite(absl::string_view(
std::move(std::string(data.begin() + offset, data.end()))));
}
return true;
}
bool readBytes(std::vector<uint8_t> &output, ReaderPtr &reader, size_t length,
bool is_last_chunk) {
if (length == 0) {
return true;
}
if (length > reader->byteAvailable()) {
return false;
}
auto offset = output.size();
output.resize(offset + length);
reader->readNBytes(&output[offset], length);
if (is_last_chunk) {
return true;
}
return decodeBytesWithReader(output, reader);
}
} // namespace Hessian2