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

#include <libtardy/tar/output/cpio/crc.h>


tar_output_cpio_crc::~tar_output_cpio_crc()
{
}


tar_output_cpio_crc::tar_output_cpio_crc(const file_output::pointer &a_fp) :
    tar_output_cpio(a_fp, 4),
    running_checksum(0)
{
}


tar_output::pointer
tar_output_cpio_crc::create(const file_output::pointer &a_fp)
{
    return pointer(new tar_output_cpio_crc(a_fp));
}


void
tar_output_cpio_crc::write_header(const tar_header &h)
{
    current_header = h;
    current_data.clear();
    running_checksum = 0;
}


void
tar_output_cpio_crc::write_header_padding(void)
{
}


void
tar_output_cpio_crc::write_data(const void *data, int data_size)
{
    current_data.push_back(data, data_size);
    const unsigned char *p = (const unsigned char *)data;
    for (int j = 0; j < data_size; ++j)
        running_checksum += *p++;
}


void
tar_output_cpio_crc::write_data_padding(void)
{
    char buffer[112];
    snprintf
    (
        buffer,
        sizeof(buffer),
        "%6s%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx",
        "070702",
        current_header.inode_number,
        (long)calculate_mode(current_header),
        current_header.user_id,
        current_header.group_id,
        current_header.link_count,
        current_header.mtime,
        current_header.size,
        current_header.device_major,
        current_header.device_minor,
        current_header.rdevice_major,
        current_header.rdevice_minor,
        (long)current_header.name.size() + 1,

        //
        // From Linux cpio(5):
        // "The check field is set to the sum of all bytes in the file data.
        // This sum is computed treating all bytes as unsigned values and using
        // unsigned arithmetic.  Only the least-significant 32 bits of the sum
        // are stored."
        //
        running_checksum
    );
    write_deeper(buffer, 110);
    write_deeper(current_header.name.c_str(), current_header.name.size() + 1);
    write_padding();
    write_deeper(current_data.get_data(), current_data.size());
    write_padding();

    current_data.clear();
    running_checksum = 0;
}


const char *
tar_output_cpio_crc::get_format_name(void)
    const
{
    return "cpio-crc";
}


size_t
tar_output_cpio_crc::get_maximum_name_length(void)
    const
{
    return 0;
}
