From c029d90d1975e124d237605f1edb2be16bd05b5d Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Tue, 28 Feb 2017 21:50:44 +0100 Subject: Initial commit --- src/chunked.cc | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/chunked.cc (limited to 'src/chunked.cc') diff --git a/src/chunked.cc b/src/chunked.cc new file mode 100644 index 0000000..99aea0d --- /dev/null +++ b/src/chunked.cc @@ -0,0 +1,106 @@ +// -*- mode: c++; c-basic-offset: 2; -*- + +#include "common.hh" + +#include +#include +#include + +#include "chunked.hh" + +namespace { + +enum State { + CHUNK, + IN_CHUNK, + TRAILER, + DONE, +}; + +class ChunkedImpl : public Chunked { +public: + ChunkedImpl() + : state_(CHUNK), good_(true) { + } + + size_t add(void const* data, size_t avail) override { + if (!good_) return 0; + auto const start = reinterpret_cast(data); + auto const end = start + avail; + auto d = start; + while (true) { + if (d == end) return avail; + switch (state_) { + case CHUNK: { + auto p = find_crlf(d, end); + if (!p) return d - start; + char* x = nullptr; + errno = 0; + auto tmp = strtoull(d, &x, 16); + if (errno || (x != p && (!x || *x != ';'))) { + good_ = false; + return d - start; + } + size_ = tmp; + d = p + 2; + if (size_ == 0) { + // Last chunk + state_ = TRAILER; + } else { + state_ = IN_CHUNK; + } + break; + } + case IN_CHUNK: + if (static_cast(end - d) < size_) { + return avail; + } + d += size_; + state_ = CHUNK; + break; + case TRAILER: { + auto p = find_crlf(d, end); + if (!p) return d - start; + if (p == d) { + state_ = DONE; + } + d = p + 2; + break; + } + case DONE: + return d - start; + } + } + } + + bool good() const override { + return good_; + } + + bool eof() const override { + return state_ == DONE; + } + +private: + char const* find_crlf(char const* start, char const* end) { + for (; start != end; ++start) { + if (*start == '\r') { + if (start + 1 == end) break; + if (start[1] == '\n') return start; + } + } + return nullptr; + } + + State state_; + bool good_; + uint64_t size_; +}; + +} // namespace + +// static +Chunked* Chunked::create() { + return new ChunkedImpl(); +} + -- cgit v1.2.3-70-g09d2