    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_SOCKStREAMBUF_CPp_
    #define DLIB_SOCKStREAMBUF_CPp_

    #include "sockstreambuf.h"
    #include "../assert.h"

    #include <cstring>

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------
        // output functions
    // ----------------------------------------------------------------------------------------

        sockstreambuf::int_type sockstreambuf::
        overflow (
            int_type c
        )
        {
            if (c != EOF)
            {
                *pptr() = c;
                pbump(1);
            }
            if (flush_out_buffer() == EOF)
            {
                // an error occurred
                return EOF;
            }
            return c;
        }

    // ----------------------------------------------------------------------------------------

        std::streamsize sockstreambuf::
        xsputn (
            const char* s,
            std::streamsize num
        )
        {
            // Add a sanity check here
            DLIB_ASSERT(num >= 0,
                "\tstd::streamsize sockstreambuf::xsputn"
                << "\n\tThe number of bytes to write can't be negative"
                << "\n\tnum:  " << num
                << "\n\tthis: " << this
                );

            std::streamsize space_left = static_cast<std::streamsize>(epptr()-pptr());
            if (num <= space_left)
            {
                std::memcpy(pptr(),s,static_cast<size_t>(num));
                pbump(static_cast<int>(num));
                return num;
            }
            else
            {
                std::memcpy(pptr(),s,static_cast<size_t>(space_left));
                s += space_left;
                pbump(space_left);
                std::streamsize num_left = num - space_left;

                if (flush_out_buffer() == EOF)
                {
                    // the write was not successful so return that 0 bytes were written
                    return 0;
                }

                if (num_left < out_buffer_size)
                {
                    std::memcpy(pptr(),s,static_cast<size_t>(num_left));
                    pbump(num_left);
                    return num;
                }
                else
                {
                    if (con.write(s,num_left) != num_left)
                    {
                        // the write was not successful so return that 0 bytes were written
                        return 0;
                    }
                    return num;
                }
            }
        }

    // ----------------------------------------------------------------------------------------
        // input functions
    // ----------------------------------------------------------------------------------------

        sockstreambuf::int_type sockstreambuf::
        underflow(
        )
        {
            if (gptr() < egptr())
            {
                return static_cast<unsigned char>(*gptr());
            }

            int num_put_back = static_cast<int>(gptr() - eback());
            if (num_put_back > max_putback)
            {
                num_put_back = max_putback;
            }

            // copy the putback characters into the putback end of the in_buffer
            std::memmove(in_buffer+(max_putback-num_put_back), gptr()-num_put_back, num_put_back);

            if (flushes_output_on_read())
            {
                if (flush_out_buffer() == EOF)
                {
                    // an error occurred
                    return EOF;
                }
            }

            int num = con.read(in_buffer+max_putback, in_buffer_size-max_putback);
            if (num <= 0)
            {
                // an error occurred or the connection is over which is EOF
                return EOF;
            }

            // reset in_buffer pointers
            setg (in_buffer+(max_putback-num_put_back),
                  in_buffer+max_putback,
                  in_buffer+max_putback+num);

            return static_cast<unsigned char>(*gptr());
        }

    // ----------------------------------------------------------------------------------------

        std::streamsize sockstreambuf::
        xsgetn (
            char_type* s,
            std::streamsize n
        )
        {
            std::streamsize temp = n;
            while (n > 0)
            {
                int num = static_cast<int>(egptr() - gptr());
                if (num >= n)
                {
                    // copy data from our buffer
                    std::memcpy(s, gptr(), static_cast<size_t>(n));
                    gbump(static_cast<int>(n));
                    return temp;
                }

                // read more data into our buffer
                if (num == 0)
                {
                    if (underflow() == EOF)
                        break;
                    continue;
                }

                // copy all the data from our buffer
                std::memcpy(s, gptr(), num);
                n -= num;
                gbump(num);
                s += num;
            }
            return temp-n;
        }

    // ----------------------------------------------------------------------------------------

    }
    #endif // DLIB_SOCKStREAMBUF_CPp_