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

#include <libtardy/tar/output/filter/ar_long_names2.h>


tar_output_filter_ar_long_names2::~tar_output_filter_ar_long_names2()
{
}


tar_output_filter_ar_long_names2::tar_output_filter_ar_long_names2(
    const pointer &a_deeper
) :
    tar_output_filter(a_deeper),
    name_is_long(false)
{
}


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


static bool
name_is_oops(const rcstring &name, size_t max)
{
    return
        (
            name.empty()
        ||
            name.size() > max
        ||
            memchr(name.c_str(), '/', name.size())
        ||
            memchr(name.c_str(), ' ', name.size())
        );
}


void
tar_output_filter_ar_long_names2::write_header(const tar_header &hdr)
{
    name_cache.clear();
    name_is_long = false;
    switch (hdr.type)
    {
    case tar_header::type_directory:
        // silently ignore
        break;

    case tar_header::type_normal:
    case tar_header::type_normal_contiguous:
        break;

    default:
        fatal("file %s type not supported", hdr.name.quote_c().c_str());
        break;
    }
    size_t maxnamlen = tar_output_filter::get_maximum_name_length();
    name_is_long = name_is_oops(hdr.name, maxnamlen);
    if (name_is_long)
    {
        //
        // "If any file name is more than 16 characters in length or contains
        // an embedded space, the string "#1/" followed by the ASCII length of
        // the name is written in the name field.  The file size (stored in the
        // archive header) is incremented by the length of the name.  The name
        // is then written immediately following the archive header."
        //
        name_cache = hdr.name;
        tar_header h2 = hdr;
        h2.name = rcstring::printf("#1/%lu", hdr.name.size());
        h2.size += hdr.name.size();
        tar_output_filter::write_header(h2);
    }
    else
    {
        tar_output_filter::write_header(hdr);
    }
}


void
tar_output_filter_ar_long_names2::write_header_padding(void)
{
    tar_output_filter::write_header_padding();

    if (name_is_long)
    {
        //
        // "The name is then written immediately following the archive header."
        //
        tar_output_filter::write_data(name_cache.c_str(), name_cache.size());
        name_is_long = false;
        name_cache.clear();
    }
}


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