//
//      tardy - a tar post-processor
//      Copyright (C) 2003, 2008, 2009, 2011 Peter Miller
//
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 3 of the License, or
//      (at your option) any later version.
//
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//
//      You should have received a copy of the GNU General Public License
//      along with this program. If not, see
//      <http://www.gnu.org/licenses/>.
//

#include <libtardy/ac/string.h>

#include <libtardy/file/output/buffer.h>


file_output_buffer::~file_output_buffer()
{
    if (pos > 0)
    {
        deeper->write(buffer, pos);
        pos = 0;
    }
    delete buffer;
    buffer = 0;
}


file_output_buffer::file_output_buffer(
    const file_output::pointer &a_deeper,
    int a_blocksize
) :
    deeper(a_deeper),
    blocksize(a_blocksize > 0 ? a_blocksize : 512),
    buffer(0),
    pos(0)
{
    assert(deeper);
    assert((blocksize % 512) == 0);
}


file_output::pointer
file_output_buffer::create(const file_output::pointer &a_deeper,
    int a_blocksize)
{
    return pointer(new file_output_buffer(a_deeper, a_blocksize));
}


rcstring
file_output_buffer::filename(void)
    const
{
    return deeper->filename();
}


void
file_output_buffer::write(const void *data, int data_size)
{
    while (data_size > 0)
    {
        //
        // Don't double handle the data if we can avoid it.
        // (But only write `blocksize' bytes at a time.)
        //
        if (pos == 0 && data_size >= blocksize)
        {
            deeper->write(data, blocksize);
            data = (char *)data + blocksize;
            data_size -= blocksize;
            continue;
        }

        //
        // Add the data to the end of the buffer.
        //
        int len = blocksize - pos;
        if (len > data_size)
            len = data_size;
        if (!buffer)
            buffer = new char[blocksize];
        memcpy(buffer + pos, data, len);
        pos += len;
        if (pos >= blocksize)
        {
            //
            // If the buffer is full,
            // write it out and start again.
            //
            deeper->write(buffer, pos);
            pos = 0;
        }
        data = (char *)data + len;
        data_size -= len;
    }
}
