/*****************************************************************************/
/* File name: Block.java                                                     */
/* Purpose: to contain a block of tar data                                   */
/* Last modified: 16.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*                                                                           */
/* 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.                                          */
/*                                                                           */
/* This software is distributed under the terms                              */
/* of the GNU General Public License as published                            */
/* by the Free Software Foundation; either version 2, or (at your option)    */
/* any later version.                                                        */
/* See file COPYING for your rights (GNU GPL)                                */
/*****************************************************************************/

package jtar;

import java.lang.reflect.*;
import java.io.*;
import util.*;
import general.*;

final

class

Block

     implements jtar.Constants, general.Constants

{

  private final static java.lang.String RCSID =
"$Header: /d/NFS/jtar/RCS/Block.java,v 1.2 1999/07/19 14:10:22 vklimov Exp $";


/* `tar' Header Block, from POSIX 1003.1-1990 */
                                               /* POSIX header posixHeader */
                                /* byte offset */
  byte[] name;                  /*   0 */
  byte[] mode;                  /* 100 */
  byte[] uid;                   /* 108 */
  byte[] gid;                   /* 116 */
  byte[] size;                  /* 124 */
  byte[] mtime;                 /* 136 */
  byte[] chksum;                /* 148 */
  byte typeflag;                /* 156 */
  byte[] linkname;              /* 157 */
  byte[] magic;                 /* 257 */
  byte[] version;               /* 263 */
  byte[] uname;                 /* 265 */
  byte[] gname;                 /* 297 */
  byte[] devmajor;              /* 329 */
  byte[] devminor;              /* 337 */
  byte[] prefix;                /* 345 */

/* The old GNU format header conflicts with POSIX format in such a way that
                                  /* POSIX archives may fool old GNU tar's, */
                                  /* and POSIX tar's might well be fooled   */
                                  /* by old GNU tar archives. An old GNU    */
                                  /* format header uses the space used      */
                                  /* by the prefix field in a POSIX header, */
                                  /* and cumulates information normally     */
                                  /* found in a GNU extra header.           */
                                  /* With an old GNU tar header, we never   */
                                  /* see any POSIX header nor GNU extra     */
                                  /* header.  Supplementary sparse headers  */
                                  /* are allowed, however.                  */

  /* oldgnuHeader */
                                /* byte offset */
/*byte  unusedPad1[345]; */      /*   0 */

  byte[] atime;                   /* 345 */
  byte[] ctime;                   /* 357 */
  byte[] offset;                  /* 369 */
  byte[] longnames;               /* 381 */
  byte   unusedPad2;             /* 385 */
  Sparse[] sp;
                                  /* 386 */
  byte   isextended;              /* 482 */
  byte[] realsize;                /* 483 */
                                  /* 495 */
                                  /* 500 */




  byte[] buffer;

  
  Block( )
/*****************************************************************************/
/* Function name: Block                                                      */
/* File name: Block.java                                                     */
/* Purpose: constructor for the object Block, i.e. `tar' Header Block        */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 11.12.98                                                   */
/* Author: Victor Klimov, 1998                                               */
/*****************************************************************************/
    {
      int i;
                                                            /* Block */
/*---------------------------------------------------------------------------*/

                                                          /* byte offset */
      name = new byte[ HEADER_FIELD_LENGTH_NAME ];            /*   0 */
      mode = new byte[ HEADER_FIELD_LENGTH_MODE ];            /* 100 */
      uid = new byte[ HEADER_FIELD_LENGTH_UID ];              /* 108 */
      gid = new byte[ HEADER_FIELD_LENGTH_GID ];              /* 116 */
      size = new byte[ HEADER_FIELD_LENGTH_SIZE ];            /* 124 */
      mtime = new byte[ HEADER_FIELD_LENGTH_MTIME ];          /* 136 */
      chksum = new byte[ HEADER_FIELD_LENGTH_CHKSUM ];        /* 148 */
   /* byte typeflag                */                         /* 156 */
      linkname = new byte[ HEADER_FIELD_LENGTH_LINKNAME ];    /* 157 */
      magic = new byte[ HEADER_FIELD_LENGTH_MAGIC ];          /* 257 */
      version = new byte[ HEADER_FIELD_LENGTH_VERSION ];      /* 263 */
      uname = new byte[ HEADER_FIELD_LENGTH_UNAME ];          /* 265 */
      gname = new byte[ HEADER_FIELD_LENGTH_GNAME ];          /* 297 */
      devmajor = new byte[ HEADER_FIELD_LENGTH_DEVMAJOR ];    /* 329 */
      devminor = new byte[ HEADER_FIELD_LENGTH_DEVMINOR ];    /* 337 */
      prefix = new byte[ HEADER_FIELD_LENGTH_PREFIX ];        /* 345 */

                              /* oldgnuHeader fields */

      atime = new byte[ OLDGNU_HEADER_FIELD_LENGTH_ATIME ];   /* 345 */
      ctime = new byte[ OLDGNU_HEADER_FIELD_LENGTH_CTIME ];   /* 357 */
      offset = new byte[ OLDGNU_HEADER_FIELD_LENGTH_OFFSET ]; /* 369 */
      longnames = new                                         /* 381 */
        byte[ OLDGNU_HEADER_FIELD_LENGTH_LONGNAMES ];
   /* byte   unusedPad2;         */                          /* 385 */
      sp = new Sparse[ SPARSES_IN_OLDGNU_HEADER ];            /* 386 */
      for (i=0; i<SPARSES_IN_OLDGNU_HEADER; i++)
        sp[i] = new Sparse();
    /*end of for-loop*/

   /* byte   isextended;          */                          /* 482 */
      realsize = new                                          /* 483 */
        byte[ OLDGNU_HEADER_FIELD_LENGTH_REALSIZE ];


                                                              /* 500 */
      buffer = new byte[ BLOCKSIZE ];

                                             /* fill up with nulls */

      util.Array.bytefill( name, general.Constants.NULL_BYTE );
      util.Array.bytefill( mode, general.Constants.NULL_BYTE );
      util.Array.bytefill( uid, general.Constants.NULL_BYTE );
      util.Array.bytefill( gid, general.Constants.NULL_BYTE );
      util.Array.bytefill( size, general.Constants.NULL_BYTE );
      util.Array.bytefill( mtime, general.Constants.NULL_BYTE );
      util.Array.bytefill( chksum, general.Constants.NULL_BYTE );
      typeflag = general.Constants.NULL_BYTE;
      util.Array.bytefill( linkname, general.Constants.NULL_BYTE );
      util.Array.bytefill( magic, general.Constants.NULL_BYTE );
      util.Array.bytefill( version, general.Constants.NULL_BYTE );
      util.Array.bytefill( uname, general.Constants.NULL_BYTE );
      util.Array.bytefill( gname, general.Constants.NULL_BYTE );
      util.Array.bytefill( devmajor, general.Constants.NULL_BYTE );
      util.Array.bytefill( devminor, general.Constants.NULL_BYTE );
      util.Array.bytefill( prefix, general.Constants.NULL_BYTE );
                              /* oldgnuHeader fields */
      util.Array.bytefill( atime, general.Constants.NULL_BYTE );
      util.Array.bytefill( ctime, general.Constants.NULL_BYTE );
      util.Array.bytefill( offset, general.Constants.NULL_BYTE );
      util.Array.bytefill( longnames, general.Constants.NULL_BYTE );
      isextended = general.Constants.NULL_BYTE;
      util.Array.bytefill( realsize, general.Constants.NULL_BYTE );
      util.Array.bytefill( buffer, general.Constants.NULL_BYTE );

    }
/*end of Block*/


  void
  fillUpBufferOther()
/*****************************************************************************/
/* Function name: fillUpBufferOther                                          */
/* File name: Block.java                                                     */
/* Purpose: to copy all the non-posix fields of the Block byte by byte       */
/*          into the buffer field - this is actually a repository            */
/*          of building blocks to create working methods to write            */
/*          extraHeader, oldgnuHeader, sparseHeader                          */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 16.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      io.ByteFixedArrayOutputStream byteArrayStream;
                                                       /* fillUpBufferOther */
/*---------------------------------------------------------------------------*/

      byteArrayStream = new
        io.ByteFixedArrayOutputStream( BLOCKSIZE );

      try
        {
          byteArrayStream.writeF(
             name, 0,
             HEADER_FIELD_LENGTH_NAME );
          byteArrayStream.writeF(
             mode, 0,
             HEADER_FIELD_LENGTH_MODE );
          byteArrayStream.writeF(
             uid, 0,
             HEADER_FIELD_LENGTH_UID );
          byteArrayStream.writeF(
             gid, 0,
             HEADER_FIELD_LENGTH_GID );
          byteArrayStream.writeF(
             size, 0,
             HEADER_FIELD_LENGTH_SIZE );
          byteArrayStream.writeF(
             mtime, 0,
             HEADER_FIELD_LENGTH_MTIME );
          byteArrayStream.writeF(
             chksum, 0,
             HEADER_FIELD_LENGTH_CHKSUM );
          byteArrayStream.writeF(
            (int) typeflag       );
          byteArrayStream.writeF(
             linkname, 0,
             HEADER_FIELD_LENGTH_LINKNAME );
          byteArrayStream.writeF(
             magic, 0,
             HEADER_FIELD_LENGTH_MAGIC );
          byteArrayStream.writeF(
             version, 0,
             HEADER_FIELD_LENGTH_VERSION );
          byteArrayStream.writeF(
             uname, 0,
             HEADER_FIELD_LENGTH_UNAME );
          byteArrayStream.writeF(
             gname, 0,
             HEADER_FIELD_LENGTH_GNAME );
          byteArrayStream.writeF(
             devmajor, 0,
             HEADER_FIELD_LENGTH_DEVMAJOR );
          byteArrayStream.writeF(
             devminor, 0,
             HEADER_FIELD_LENGTH_DEVMINOR );
          byteArrayStream.writeF(
             prefix, 0,
             HEADER_FIELD_LENGTH_PREFIX );
                                                     /* oldgnuHeader fields */
          byteArrayStream.writeF(
             atime, 0,
             OLDGNU_HEADER_FIELD_LENGTH_ATIME );
          byteArrayStream.writeF(
             ctime, 0,
             OLDGNU_HEADER_FIELD_LENGTH_CTIME );
          byteArrayStream.writeF(
             offset, 0,
             OLDGNU_HEADER_FIELD_LENGTH_OFFSET );
          byteArrayStream.writeF(
             longnames, 0,
             OLDGNU_HEADER_FIELD_LENGTH_LONGNAMES );
          byteArrayStream.writeF(
             (int) unusedPad2   );

          for( i=0; i<SPARSES_IN_OLDGNU_HEADER; i++ )
            {
              sp[i].write( byteArrayStream );
            }
        /*end of for-loop*/

          byteArrayStream.writeF(
            (int) isextended     );
          byteArrayStream.writeF(
             realsize, 0,
             OLDGNU_HEADER_FIELD_LENGTH_REALSIZE );
        }
      catch( io.BufferFullException e )
        {
          System.out.println(
            e.getMessage()    );
          return;                                      /* return ! */
        }
    /*end of try-catch*/


      buffer = byteArrayStream.toByteArray();

    }
/*end of fillUpBufferOther*/


  void
  fillUpBufferPosix()
/*****************************************************************************/
/* Function name: fillUpBufferPosix                                          */
/* File name: Block.java                                                     */
/* Purpose: to copy all posix fields of the Block byte by byte               */
/*          into the buffer field                                            */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 16.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      io.ByteFixedArrayOutputStream byteArrayStream;
                                                       /* fillUpBufferPosix */
/*---------------------------------------------------------------------------*/

      byteArrayStream = new
        io.ByteFixedArrayOutputStream( BLOCKSIZE );

      try
        {
          byteArrayStream.writeF(
             name, 0,
             HEADER_FIELD_LENGTH_NAME );
          byteArrayStream.writeF(
             mode, 0,
             HEADER_FIELD_LENGTH_MODE );
          byteArrayStream.writeF(
             uid, 0,
             HEADER_FIELD_LENGTH_UID );
          byteArrayStream.writeF(
             gid, 0,
             HEADER_FIELD_LENGTH_GID );
          byteArrayStream.writeF(
             size, 0,
             HEADER_FIELD_LENGTH_SIZE );
          byteArrayStream.writeF(
             mtime, 0,
             HEADER_FIELD_LENGTH_MTIME );
          byteArrayStream.writeF(
             chksum, 0,
             HEADER_FIELD_LENGTH_CHKSUM );
          byteArrayStream.writeF(
            (int) typeflag       );
          byteArrayStream.writeF(
             linkname, 0,
             HEADER_FIELD_LENGTH_LINKNAME );
          byteArrayStream.writeF(
             magic, 0,
             HEADER_FIELD_LENGTH_MAGIC );
          byteArrayStream.writeF(
             version, 0,
             HEADER_FIELD_LENGTH_VERSION );
          byteArrayStream.writeF(
             uname, 0,
             HEADER_FIELD_LENGTH_UNAME );
          byteArrayStream.writeF(
             gname, 0,
             HEADER_FIELD_LENGTH_GNAME );
          byteArrayStream.writeF(
             devmajor, 0,
             HEADER_FIELD_LENGTH_DEVMAJOR );
          byteArrayStream.writeF(
             devminor, 0,
             HEADER_FIELD_LENGTH_DEVMINOR );
          byteArrayStream.writeF(
             prefix, 0,
             HEADER_FIELD_LENGTH_PREFIX );
          for (i=0; i<
               POSIX_HEADER_FIELD_LENGTH_UNUSED_AT_THE_END;
               i++)
            byteArrayStream.writeF( (int)
              general.Constants.NULL_BYTE );
        /*end of for-loop*/
        }
      catch( io.BufferFullException e )
        {
          System.out.println(
            e.getMessage()    );
          return;                                      /* return ! */
        }
    /*end of try-catch*/


      buffer = byteArrayStream.toByteArray();

    }
/*end of fillUpBufferPosix*/


  public
  java.lang.String
  toString()
/*****************************************************************************/
/* Function name: Block                                                      */
/* File name: Block.java                                                     */
/* Purpose: to present the contents of the Block as a String                 */
/* Parameters:                                                               */
/* Returns: the String                                                       */
/* Last modified: 16.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Class  thisClass = null;
      StringBuffer resultBuffer = new StringBuffer( "" );
      Field[] thisAllFieldsArray = null;
      java.lang.String nameFieldString;

      int i;
      int indexNull;
                                                            /* toString */
/*---------------------------------------------------------------------------*/

      thisClass = this.getClass();
      try
        {
          thisAllFieldsArray = thisClass.getDeclaredFields();
          resultBuffer.append( thisClass.toString() +
                               general.Constants.
                                 TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "name=" +
            util.Array.
              byteArrayToStringOfHex( name ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "mode=" +
            util.Array.
              byteArrayToStringOfHex( mode ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "uid=" +
            util.Array.
              byteArrayToStringOfHex( uid ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "gid=" +
            util.Array.
              byteArrayToStringOfHex( gid ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "size=" +
            util.Array.
              byteArrayToStringOfHex( size ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "mtime=" +
            util.Array.
              byteArrayToStringOfHex( mtime ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "chksum=" +
            util.Array.
              byteArrayToStringOfHex( chksum ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "typeflag=" + typeflag +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "linkname=" +
            util.Array.
              byteArrayToStringOfHex( linkname ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "magic=" +
            util.Array.
              byteArrayToStringOfHex( magic ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "version=" +
            util.Array.
              byteArrayToStringOfHex( version ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "uname=" +
            util.Array.
              byteArrayToStringOfHex( uname ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "gname=" +
            util.Array.
              byteArrayToStringOfHex( gname ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "devmajor=" +
            util.Array.
              byteArrayToStringOfHex( devmajor ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "devminor=" +
            util.Array.
              byteArrayToStringOfHex( devminor ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "prefix=" +
            util.Array.
              byteArrayToStringOfHex( prefix ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "atime=" +
            util.Array.
              byteArrayToStringOfHex( atime ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "ctime=" +
            util.Array.
              byteArrayToStringOfHex( ctime ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "offset=" +
            util.Array.
              byteArrayToStringOfHex( offset ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "longnames=" +
            util.Array.
              byteArrayToStringOfHex( longnames ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          for (i=0; i<SPARSES_IN_OLDGNU_HEADER; i++)
            {
              resultBuffer.append(
                "sp[" + i + "].offset=" +
                util.Array.
                  byteArrayToStringOfHex( sp[i].offset ) +
                general.Constants.
                  TO_STRING_FIELD_SEPARATOR_STRING );

              resultBuffer.append(
                "sp[" + i + "].numbytes=" +
                util.Array.
                  byteArrayToStringOfHex( sp[i].numbytes ) +
                general.Constants.
                  TO_STRING_FIELD_SEPARATOR_STRING );
            }
        /*end of for-loop*/

          resultBuffer.append(
            "isextended=" + isextended +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

          resultBuffer.append(
            "realsize=" +
            util.Array.
              byteArrayToStringOfHex( realsize ) +
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

            

          resultBuffer.append(
            general.Constants.
              TO_STRING_FIELD_SEPARATOR_STRING );

        }
      catch( SecurityException e )
        {
          System.out.println(
            "SecurityException! " +
                      e.toString() );
        }
    /*end of try on SecurityException*/

      nameFieldString = new java.lang.String( this.name );
      nameFieldString =
        c.String.truncateNull( nameFieldString );

      resultBuffer.append( "name= \'" + 
                           nameFieldString + "\'" +
                           general.Constants.
                             TO_STRING_FIELD_SEPARATOR_STRING );

      resultBuffer.append( util.Array.
                             byteArrayToStringOfHex(
                               this.buffer           ) );

      return resultBuffer.toString();

    }
/*end of toString*/


} /*end of Block */

/*****************************************************************************/
/* End of file: Block.java                                                   */
/*****************************************************************************/

