//
// tardy - a tar post-processor
// Copyright (C) 1998, 1999, 2002, 2003, 2008, 2009, 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_FORMAT_H
#define LIBTARDY_TAR_FORMAT_H

#include <libtardy/rcstring.h>

#define TBLOCK 512
#define NAMSIZ 100

//
// The magic field is filled with this if uname and gname are valid.
//
#define TMAGIC          "ustar  \000"          // 8 chars
#define USTAR_MAGIC     "ustar\000\060\060"    // 8 chars

//
// The linkflag defines the type of file
//
#define LF_OLDNORMAL    '\0'            // Normal disk file, Unix compat
#define LF_NORMAL       '0'             // Normal disk file
#define LF_LINK         '1'             // Link to previously dumped file
#define LF_SYMLINK      '2'             // Symbolic link
#define LF_CHR          '3'             // Character special file
#define LF_BLK          '4'             // Block special file
#define LF_DIR          '5'             // Directory
#define LF_FIFO         '6'             // FIFO special file
#define LF_CONTIG       '7'             // Contiguous file
#define LF_LONGNAME     'L'             // File is actually long name
                                        // for next file in the archive.
#define LF_LONGLINK     'K'             // File is actually long link
                                        // for next file in the archive.
#define LF_GZIPPED      'z'             // Flags that the next file in the
                                        // archive is gzipped.
// Further link types may be defined later.


/**
  * The header_ty class is used to represent the set of information that
  * may be found in a tar(1) file header.  This is typically overlayed
  * (type punned, aliased) onto a "unsigned char [TBLOCK]".
  *
  * <b>DO NOT</b> add any virtual method to this class, or it will cease
  * to be useful for overlaying.
  */
class header_ty
{
public:
    char    name[NAMSIZ];
    char    mode[8];
    char    uid[8];
    char    gid[8];
    char    size[12];
    char    mtime[12];
    char    chksum[8];
    char    linkflag;
    char    linkname[NAMSIZ];
    char    magic[8];
    char    uname[32];
    char    gname[32];
    char    devmajor[8];
    char    devminor[8];

    /**
      * The get_name method is used to extract the file name from the
      * header block.
      */
    rcstring name_get(void) const;

    /**
      * The name_set method is use to insert the file name into the
      * header block.
      *
      * @param name
      *     The name to be inserted.  If it is too long, it will be
      *     silently truncated.
      */
    void name_set(const rcstring &name);

    /**
      * The mode_get method is used to extract the file permission
      * modes form the header block.  It will not include file type
      * information (above lower 12 bits).
      */
    long mode_get(void) const;

    /**
      * The mode_set method is used to insert the file permission mlde
      * bits into the header, space padded.
      *
      * @param value
      *     The value to be inserted.  Only the lower 12 bits are used.
      */
    void mode_set(long value);

    /**
      * The mode_set_z method is used to insert the file permission mlde
      * bits into the header, zero padded.
      *
      * @param value
      *     The value to be inserted.  Only the lower 12 bits are used.
      */
    void mode_set_z(long value);

    /**
      * The uid_get method is used to extract the numeric user ID form
      * the header block.
      */
    long uid_get(void) const;

    /**
      * The uid_set method is used to insert the numeric user ID into
      * the header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void uid_set(long value);

    /**
      * The uid_set_z method is used to insert the numeric user ID into
      * the header block, zero padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void uid_set_z(long value);

    /**
      * The gid_get method is used to extract the numeric user ID form
      * the header block.
      */
    long gid_get(void) const;

    /**
      * The gid_set method is used to insert the numeric group ID into
      * the header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void gid_set(long value);

    /**
      * The gid_set_z method is used to insert the numeric group ID into
      * the header block, zero padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void gid_set_z(long value);

    /**
      * The size_get method is used to extract the file size, in bytes,
      * from the header block.
      */
    long size_get(void) const;

    /**
      * The size_set method is used to insert the file size, in bytes,
      * into the header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void size_set(long value);

    /**
      * The size_set_z method is used to insert the file size, in bytes,
      * into the header block, zero padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void size_set_z(long value);

    /**
      * The mtime_get method is used to extract the file's last-modified
      * time, in seconds since 1-Jan-1970, from the header block.
      */
    long mtime_get(void) const;

    /**
      * The mtime_set method is used to insert the file's last-modified
      * time, in seconds since 1-Jan-1970, into the header block, space
      * padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void mtime_set(long value);

    /**
      * The mtime_set_z method is used to insert the file's last-modified
      * time, in seconds since 1-Jan-1970, into the header block, zero
      * padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void mtime_set_z(long value);

    /**
      * The chksum_get method is used to extract the header block's
      * checksum field.
      *
      * @note
      *     This method <b>does not</b> calculate the header block
      *     checksum, see the #calculate_checksum method for that.  This
      *     method only extracts the value of the file header field.
      */
    long chksum_get(void) const;

    /**
      * The chksum_set method is used to insert the checksum into the
      * header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      *
      * @note
      *     This method <b>does not</b> calculate the header block checksum.
      *     It only inserts the value info the file header field.
      */
    void chksum_set(long value);

    /**
      * The chksum_set_z method is used to insert the checksum into the
      * header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      *
      * @note
      *     This method <b>does not</b> calculate the header block checksum.
      *     It only inserts the value info the file header field.
      */
    void chksum_set_z(long value);

    /**
      * The linkflag_get method is used to extract the link flag from
      * the header block.
      */
    int linkflag_get(void) const;

    /**
      * The linkflag_set method is used to insert the file's link flag
      * into the header block.
      *
      * @param value
      *     The value to be inserted.
      */
    void linkflag_set(int value);

    /**
      * The linkname_get method is used to extract the file's link
      * destination from the header block.
      *
      * @note
      *     This is only a valid thing to do if the file's link type is
      *     LF_LINK or LF_SYMLINK.
      */
    rcstring linkname_get(void) const;

    /**
      * The linkname_set method is used to insert the file's link
      * destination into the header block.
      *
      * @param value
      *     The link destination.  If it is too long, it will be
      *     silently truncated.
      */
    void linkname_set(const rcstring &value);

    /**
      * The uname_get method is used to extract the file's user name
      * from the header block.
      *
      * @returns
      *     The user name, or the empty string if it has not been set.
      *
      * @note
      *     This is completely independent of the #uid_get method.
      */
    rcstring uname_get(void) const;

    /**
      * The uname_set method is used to insert file's user name
      * into the header block.
      *
      * @param value
      *     The name to be inserted, or the empty string to clear the field.
      *
      * @note
      *     This is completely independent of the #uid_set method.
      */
    void uname_set(const rcstring &value);

    /**
      * The gname_get method is used to extract the file's group name
      * from the header block.
      *
      * @returns
      *     The group name, or the empty string if it has not been set.
      *
      * @note
      *     This is completely independent of the #gid_get method.
      */
    rcstring gname_get(void) const;

    /**
      * The gname_set method is used to insert file's group name
      * into the header block.
      *
      * @param value
      *     The name to be inserted, or the empty string to clear the field.
      *
      * @note
      *     This is completely independent of the #gid_set method.
      */
    void gname_set(const rcstring &value);

    /**
      * The devmajor_get method is used to extract the file's major
      * device number from the header block.  This is only a valid thing
      * to do if the file's link type is LF_CHR or LF_BLK.
      *
      * @note
      *     This is likely to be particularly system specific, and
      *     unlikely to be portable across differing POSIX-like system,
      *     let alone any other kind of operating system.
      */
    long devmajor_get(void) const;

    /**
      * The devmajor_set method is used to insert the file's majopr
      * device number into the header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void devmajor_set(long value);

    /**
      * The devmajor_set_z method is used to insert the file's majopr
      * device number into the header block, zero padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void devmajor_set_z(long value);

    /**
      * The devminor_get method is used to extract the file's minor
      * device number from the header block.  This is only a valid thing
      * to do if the file's link type is LF_CHR or LF_BLK.
      *
      * @note
      *     This is likely to be particularly system specific, and
      *     unlikely to be portable across differing POSIX-like system,
      *     let alone any other kind of operating system.
      */
    long devminor_get(void) const;

    /**
      * The devminor_set method is used to insert the file's majopr
      * device number into the header block, space padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void devminor_set(long value);

    /**
      * The devminor_set_z method is used to insert the file's majopr
      * device number into the header block, zero padded.
      *
      * @param value
      *     The value to be inserted.
      */
    void devminor_set_z(long value);

    /**
      * The calculate_checksum method may be used to calculate the
      * header block's checksum.
      *
      * @note
      *     This method does not insert the checksum into the header
      *     block, see the #chksum_set method for that.
      */
    long calculate_checksum(void) const;

    /**
      * The dump method is used to dump a representation of the header block
      * onto the standard output.  This is principally of use when debugging.
      */
    void dump(void) const;
};

#endif // LIBTARDY_TAR_FORMAT_H
