//
// 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/ac/string.h>

#include <libtardy/tar/output/ar/bsd.h>
#include <libtardy/tar/output/filter/ar_long_names.h>
#include <libtardy/tar/output/filter/ar_long_names2.h>
#include <libtardy/tar/output/filter/basename.h>


tar_output_ar_bsd::~tar_output_ar_bsd()
{
}


tar_output_ar_bsd::tar_output_ar_bsd(const file_output::pointer &a_ofp) :
    tar_output_ar(a_ofp, 2)
{
}


tar_output::pointer
tar_output_ar_bsd::create(const file_output::pointer &a_ofp)
{
    pointer p(new tar_output_ar_bsd(a_ofp));
    p = tar_output_filter_ar_long_names::create(p);
    return tar_output_filter_basename::create(p);
}


tar_output::pointer
tar_output_ar_bsd::create_l2(const file_output::pointer &a_ofp)
{
    pointer p(new tar_output_ar_bsd(a_ofp));
    p = tar_output_filter_ar_long_names2::create(p);
    return tar_output_filter_basename::create(p);
}


const char *
tar_output_ar_bsd::get_format_name(void)
    const
{
    return "ar-bsd";
}


void
tar_output_ar_bsd::write_archive_begin(void)
{
    write_deeper("!<arch>\n", 8);
}


void
tar_output_ar_bsd::write_header(const tar_header &hdr)
{
    switch (hdr.type)
    {
    case tar_header::type_device_block:
    case tar_header::type_device_character:
    case tar_header::type_fifo:
    case tar_header::type_link_hard:
    case tar_header::type_link_symbolic:
    case tar_header::type_socket:
        fatal("%s: file type not supported", hdr.name.c_str());
        break;

    case tar_header::type_normal_gzipped:
        assert(!"not implemented yet");
        break;

    case tar_header::type_directory:
        // Quietly ignore
        break;

    case tar_header::type_normal:
    case tar_header::type_normal_contiguous:
        //
        // Name Offset Size
        // ---- ------ ----
        // name      0   16
        // date     16   12
        // uid      28    6
        // gid      34    6
        // mode     40    8
        // size     48   10
        // fmag     58    2
        // ----------- ----
        // Total:        60
        //
        char buffer[60];
        size_t name_size = hdr.name.size();
        if (name_size > 16)
            name_size = 16;
        memcpy(buffer, hdr.name.c_str(), name_size);
        if (name_size < 16 && !memchr(hdr.name.c_str(), '/', name_size))
            buffer[name_size++] = '/';
        while (name_size < 16)
            buffer[name_size++] = ' ';
        dec(buffer + 16, hdr.mtime, 12);
        dec(buffer + 28, hdr.user_id, 6);
        dec(buffer + 34, hdr.group_id, 6);
        oct(buffer + 40, calculate_mode(hdr), 8);
        if (hdr.size > 999999999)
            fatal("file size too large");
        dec(buffer + 48, hdr.size, 10);
        buffer[58] = '`';
        buffer[59] = '\n';
        write_deeper(buffer, 60);
        break;
    }
}


size_t
tar_output_ar_bsd::get_maximum_name_length(void)
    const
{
    return 16;
}
