//
// 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/tar/output/cpio/binary.h>


tar_output_cpio_binary::~tar_output_cpio_binary()
{
}


tar_output_cpio_binary::tar_output_cpio_binary(
    const file_output::pointer &a_ofp,
    endian_t a_endian
) :
    tar_output_cpio(a_ofp, 2),
    endian(a_endian)
{
}


tar_output_cpio_binary::pointer
tar_output_cpio_binary::create(const file_output::pointer &a_ofp,
    endian_t a_endian)
{
    return pointer(new tar_output_cpio_binary(a_ofp, a_endian));
}


tar_output_cpio_binary::pointer
tar_output_cpio_binary::create_le(const file_output::pointer &a_ofp)
{
    return create(a_ofp, endian_little);
}


tar_output_cpio_binary::pointer
tar_output_cpio_binary::create_be(const file_output::pointer &a_ofp)
{
    return create(a_ofp, endian_big);
}


tar_output_cpio_binary::pointer
tar_output_cpio_binary::create_native_endian(const file_output::pointer &a_ofp)
{
    return create(a_ofp, endian_native());
}


void
tar_output_cpio_binary::write_header(const tar_header &hdr)
{
    char buffer[26];
    set2(buffer, 070707);
    unsigned dev = (hdr.device_major << 8) | hdr.device_minor;
    set2(buffer + 2, dev);
    set2(buffer + 4, hdr.inode_number);
    set2(buffer + 6, calculate_mode(hdr));
    set2(buffer + 8, hdr.user_id);
    set2(buffer + 10, hdr.group_id);
    set2(buffer + 12, hdr.link_count);
    unsigned rdev = (hdr.rdevice_major << 8) | hdr.rdevice_minor;
    set2(buffer + 14, rdev);
    set4(buffer + 16, hdr.mtime);
    unsigned name_size = hdr.name.size() + 1;
    set2(buffer + 20, name_size);
    set4(buffer + 22, hdr.size);
    write_deeper(buffer, sizeof(buffer));
    write_deeper(hdr.name.c_str(), hdr.name.size() + 1);
}


void
tar_output_cpio_binary::set2(void *data, unsigned value)
    const
{
    endian_set2(data, value, endian);
}


void
tar_output_cpio_binary::set4(void *data, unsigned long value)
    const
{
    //
    // This is deeply weird.
    //
    // cpio(5) says "The four-byte integer is stored with the
    // most-significant 16 bits first followed by the least-significant
    // 16 bits.  Each of the two 16 bit values are stored in
    // machine-native byte order."
    //
    unsigned char *p = (unsigned char *)data;
    set2(p, value >> 16);
    set2(p + 2, value);
}


const char *
tar_output_cpio_binary::get_format_name(void)
    const
{
    return (endian == endian_little ? "cpio-bin-le" : "cpio-bin-be");
}


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