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

#ifndef LIBTARDY_TAR_INPUT_CPIO_H
#define LIBTARDY_TAR_INPUT_CPIO_H

#include <libtardy/file/input.h>
#include <libtardy/tar/input.h>

/**
  * The tar_input_cpio class is used to represent the process of parsing
  * an input file, in one of the cpio(1) formats, into a series of
  * archive members.
  */
class tar_input_cpio:
    public tar_input
{
public:
    /**
      * The destructor.
      */
    virtual ~tar_input_cpio();

    /**
      * The factory class method is used to create new dynamically
      * allocated instances of this class.
      *
      * The file provided is non-destructively examined to determine
      * which cpio format is actually present, and then the appropriate
      * class' create method is called.
      *
      * @param ifp
      *     The file to be read and parsed.
      */
    static tar_input::pointer factory(const file_input::pointer &ifp);

    /**
      * The candidate class method is used to sniff at an input file
      * (without moving the file position) to see if it looks like a
      * CPIO archive.
      *
      * @param ifp
      *     The file to be examined.
      * @returns
      *     true if the #factory class method could open it, false otherwise.
      */
    static bool candidate(const file_input::pointer &ifp);

protected:
    /**
      * The constructor.
      * For use by derived classes only.
      *
      * @param ifp
      *     The input file to read and parse into archive members.
      * @param padding
      *     The padding multiple to be used.
      */
    tar_input_cpio(const file_input::pointer &ifp, int padding);

    // See base class for documentation.
    void read_header_padding(void);

    // See base class for documentation.
    int read_data(void *data, int data_size);

    // See base class for documentation.
    void read_data_padding(void);

    // See base class for documentation.
    rcstring filename(void) const;

    // See base class for documentation.
    format_family_t get_format_family(void) const;

    /**
      * The read_name method is used to read the name from the archive data,
      * checking various aspects as it goes.
      *
      * @param name_size
      *     The size of the name field, including the terminating NUL character.
      */
    rcstring read_name(unsigned name_size);

    /**
      * The is_end class method is used to determine whether or not the
      * given header represents the end of a cpio(5) archive.
      *
      * @param hdr
      *     The header data to test.
      */
    static bool is_end(const tar_header &hdr);

    /**
      * The read_deeper method is used by derived classes to read
      * underlying file contents.  The file position is tracked, for
      * alignment purposes.
      *
      * @param data
      *     Pointer to the base of an array of char in which to place
      *     the data.
      * @param data_size
      *     The number of bytes of data to read, maximum size of the
      *     data array.
      * @returns
      *     the number of bytes read
      * @note
      *     If there is an error, this function will not return, but
      *     will exit with a fatal error message.
      */
    size_t read_deeper(void *data, size_t data_size);

private:
    /**
      * The ifp instance variable is used to remember where to get the
      * binary archive data from.
      */
    file_input::pointer ifp;

    /**
      * The padding instance variable is used to remember the padding
      * multiple to be used, in bytes.
      */
    unsigned padding;

    /**
      * The read_padding method is used to advance the file position to
      * the next padding boundary.  The actual contents of the bytes are
      * ignored (although they should all be NUL characters).
      */
    void read_padding(void);

    /**
      * The default constructor.  Do not use.
      */
    tar_input_cpio();

    /**
      * The copy constructor.  Do not use.
      *
      * @param rhs
      *     The right hand side of the initialisation.
      */
    tar_input_cpio(const tar_input_cpio &rhs);

    /**
      * The assignment operator.  Do not use.
      *
      * @param rhs
      *     The right hand side of the initialisation.
      */
    tar_input_cpio &operator=(const tar_input_cpio &rhs);
};

#endif // LIBTARDY_TAR_INPUT_CPIO_H
