2016-08-02 05:14:09 +08:00
|
|
|
#pragma once
|
|
|
|
|
2016-08-11 02:17:38 +08:00
|
|
|
#include <cassert>
|
2016-08-02 05:14:09 +08:00
|
|
|
#include <cstring>
|
|
|
|
#include <functional>
|
|
|
|
|
2016-08-11 02:17:38 +08:00
|
|
|
#include "logging/default.hpp"
|
2016-08-02 05:14:09 +08:00
|
|
|
#include "utils/exceptions/basic_exception.hpp"
|
|
|
|
#include "utils/likely.hpp"
|
2016-08-11 02:17:38 +08:00
|
|
|
#include "utils/types/byte.hpp"
|
2016-08-02 05:14:09 +08:00
|
|
|
|
|
|
|
namespace bolt
|
|
|
|
{
|
|
|
|
|
|
|
|
template <class Stream>
|
|
|
|
class ChunkedDecoder
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class DecoderError : public BasicException
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
using BasicException::BasicException;
|
|
|
|
};
|
|
|
|
|
|
|
|
ChunkedDecoder(Stream& stream) : stream(stream) {}
|
|
|
|
|
|
|
|
/* Decode chunked data
|
|
|
|
*
|
|
|
|
* Chunk format looks like:
|
|
|
|
*
|
|
|
|
* |Header| Data ||Header| Data || ... || End |
|
|
|
|
* | 2B | size bytes || 2B | size bytes || ... ||00 00|
|
|
|
|
*/
|
2016-08-11 02:17:38 +08:00
|
|
|
bool decode(const byte *&chunk, size_t n)
|
2016-08-02 05:14:09 +08:00
|
|
|
{
|
2016-08-11 02:17:38 +08:00
|
|
|
while (n > 0)
|
2016-08-02 05:14:09 +08:00
|
|
|
{
|
|
|
|
// get size from first two bytes in the chunk
|
|
|
|
auto size = get_size(chunk);
|
|
|
|
|
2016-08-11 02:17:38 +08:00
|
|
|
if (UNLIKELY(size + 2 > n))
|
2016-08-02 05:14:09 +08:00
|
|
|
throw DecoderError("Chunk size larger than available data.");
|
|
|
|
|
|
|
|
// advance chunk to pass those two bytes
|
|
|
|
chunk += 2;
|
|
|
|
n -= 2;
|
|
|
|
|
|
|
|
// if chunk size is 0, we're done!
|
2016-08-11 02:17:38 +08:00
|
|
|
if (size == 0) return true;
|
2016-08-02 05:14:09 +08:00
|
|
|
|
|
|
|
stream.get().write(chunk, size);
|
|
|
|
|
|
|
|
chunk += size;
|
|
|
|
n -= size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-11 02:17:38 +08:00
|
|
|
bool operator()(const byte *&chunk, size_t n) { return decode(chunk, n); }
|
2016-08-02 05:14:09 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::reference_wrapper<Stream> stream;
|
|
|
|
|
2016-08-11 02:17:38 +08:00
|
|
|
size_t get_size(const byte *chunk)
|
2016-08-02 05:14:09 +08:00
|
|
|
{
|
|
|
|
return size_t(chunk[0]) << 8 | chunk[1];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|