diff --git a/include/support/raw_istream.h b/include/support/raw_istream.h index 2eb506b5b8..3c440df0b5 100644 --- a/include/support/raw_istream.h +++ b/include/support/raw_istream.h @@ -66,6 +66,23 @@ class raw_mem_istream : public raw_istream { std::size_t m_left; }; +class raw_fd_istream : public raw_istream { + public: + raw_fd_istream(int fd, bool shouldClose, std::size_t bufSize = 4096); + ~raw_fd_istream() override; + void close() override; + + private: + void read_impl(void* data, std::size_t len) override; + + char* m_buf; + char* m_cur; + char* m_end; + std::size_t m_bufSize; + int m_fd; + bool m_shouldClose; +}; + } // namespace wpi #endif // WPIUTIL_SUPPORT_RAW_ISTREAM_H_ diff --git a/src/support/raw_istream.cpp b/src/support/raw_istream.cpp index 24e8f08b83..e5155cac90 100644 --- a/src/support/raw_istream.cpp +++ b/src/support/raw_istream.cpp @@ -7,8 +7,15 @@ #include "support/raw_istream.h" +#include #include +#ifdef _WIN32 +#include +#else +#include +#endif + using namespace wpi; void raw_mem_istream::close() {} @@ -22,3 +29,47 @@ void raw_mem_istream::read_impl(void* data, std::size_t len) { m_cur += len; m_left -= len; } + +raw_fd_istream::raw_fd_istream(int fd, bool shouldClose, std::size_t bufSize) + : m_bufSize(bufSize), m_fd(fd), m_shouldClose(shouldClose) { + m_cur = m_end = m_buf = static_cast(std::malloc(bufSize)); +} + +raw_fd_istream::~raw_fd_istream() { + if (m_shouldClose) close(); + std::free(m_buf); +} + +void raw_fd_istream::close() { + if (m_fd >= 0) { + ::close(m_fd); + m_fd = -1; + } +} + +void raw_fd_istream::read_impl(void* data, std::size_t len) { + std::size_t left = m_end - m_cur; + if (left < len) { + // not enough data + if (m_cur == m_end) { +#ifdef _WIN32 + int count = ::_read(m_fd, m_buf, m_bufSize); +#else + ssize_t count = ::read(m_fd, m_buf, m_bufSize); +#endif + if (count < 0) { + error_detected(); + return; + } + m_cur = m_buf; + m_end = m_buf + count; + return read_impl(data, len); + } + + std::memcpy(data, m_cur, left); + return read_impl(static_cast(data) + left, len - left); + } + + std::memcpy(data, m_cur, len); + m_cur += len; +}