//
// tardy - a tar post-processor
// Copyright (C) 2012 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/file/output/xz.h>


file_output_xz::~file_output_xz()
{
    strm.next_in = NULL;
    strm.avail_in = 0;
    for (;;)
    {
        const size_t OUT_BUF_MAX = (size_t)1 << 14;
        uint8_t out_buf[OUT_BUF_MAX];
        strm.next_out = out_buf;
        strm.avail_out = OUT_BUF_MAX;
        lzma_ret err = lzma_code(&strm, LZMA_FINISH);
        if (err != LZMA_OK && err != LZMA_STREAM_END)
            drop_dead("lzma_code", err);
        size_t out_len = OUT_BUF_MAX - strm.avail_out;
        deeper->write(out_buf, out_len);
        if (strm.avail_out != 0)
            break;
    }
    lzma_end(&strm);
}


static lzma_stream strm_zero = LZMA_STREAM_INIT;

file_output_xz::file_output_xz(const file_output::pointer &a_deeper) :
    deeper(a_deeper),
    strm(strm_zero)
{
    uint32_t preset = 9 | LZMA_PRESET_EXTREME;
    lzma_check check = LZMA_CHECK_CRC64;
    lzma_ret err = lzma_easy_encoder(&strm, preset, check);
    if (err != LZMA_OK)
        drop_dead("lzma_easy_encoder", err);
}


file_output_xz::pointer
file_output_xz::create(const file_output::pointer &a_deeper)
{
    return pointer(new file_output_xz(a_deeper));
}


void
file_output_xz::write(const void *data, size_t data_size)
{
    strm.next_in = (const uint8_t *)data;
    strm.avail_in = data_size;
    for (;;)
    {
        const size_t OUT_BUF_MAX = (size_t)1 << 14;
        uint8_t out_buf[OUT_BUF_MAX];
        strm.next_out = out_buf;
        strm.avail_out = OUT_BUF_MAX;
        lzma_ret err = lzma_code(&strm, LZMA_RUN);
        if (err != LZMA_OK)
            drop_dead("lzma_code", err);
        size_t out_len = OUT_BUF_MAX - strm.avail_out;
        deeper->write(out_buf, out_len);
        if (strm.avail_out != 0)
            break;
    }
}


void
file_output_xz::drop_dead(const char *caption, lzma_ret err)
{
    fatal("%s: %s", caption, lzma_strerror(err));
}


// vim: set ts=8 sw=4 et :
