// KDat - a tar-based DAT archiver
// Copyright (C) 1998-2000  Sean Vyain, svyain@mail.tds.net
// Copyright (C) 2001-2002  Lawrence Widman, kdat@cardiothink.com
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>

#include <QFile>
//Added by qt3to4:
#include <QByteArray>
#include <Q3PtrList>

#include <kmessagebox.h>
#include <klocale.h>
#include <kstandarddirs.h>

#include "IndexDlg.h"
#include "KDatMainWindow.h"
#include "Options.h"
#include "Tape.h"
#include "TapeDrive.h"
#include "TapeManager.h"
#include "kdat.h"

Tape::Tape()
        : _stubbed( FALSE ),
          _name( i18n( "New Tape" ) ),
          _size( Options::instance()->getDefaultTapeSize() ),
          _fptr( 0 )
{
    char buffer[1024];
    gethostname( buffer, 1024 );
    time_t tm = time( NULL );
    _ctime = tm;
    _mtime = tm;
    _id.sprintf("%s:%d", buffer, tm);

    write();
}

Tape::Tape( const char * id )
        : _stubbed( TRUE ),
          _id( id ),
          _ctime( -1 ),
          _mtime( -1 ),
          _name( "<unknown>" ),
          _size( -1 ),
          _fptr( 0 )
{
}

Tape::~Tape()
{
    clear();
}

void Tape::format()
{
    // Rewind tape.
    if ( !TapeDrive::instance()->rewind() ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Rewinding tape failed." ), i18n("Format Failed"));
        return;
    }

    // Set block size for tape.
    if ( !TapeDrive::instance()->setBlockSize( Options::instance()->getTapeBlockSize() ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Cannot set tape block size." ), i18n("Format Failed"));
        return;
    }

    // TAPE HEADER
    int iv;

    // KDat magic string.
    if ( TapeDrive::instance()->write( KDAT_MAGIC, KDAT_MAGIC_LENGTH ) < KDAT_MAGIC_LENGTH ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing magic string failed." ), i18n("Format Failed"));
        return;
    }

    // Tape header version number.
    iv = KDAT_TAPE_HEADER_VERSION;
    if ( TapeDrive::instance()->write( (const char*)&iv, 4 ) < 4 ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing version number failed." ), i18n("Format Failed") );
        return;
    }

    // Write tape ID.  Tape ID is machine name + current time.
    iv = _id.length() + 1;
    if ( TapeDrive::instance()->write( (const char*)&iv, 4 ) < 4 ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing tape ID length failed." ), i18n("Format Failed") );
        return;
    }
 {
#ifdef __GNUC__
#warning "Port Qt4: test if toUtf8 is correct"    
#endif
    if ( TapeDrive::instance()->write( _id.toUtf8(), iv ) < iv ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing tape ID failed." ), i18n("Format Failed") );
        return;
    }

    // Write end of file marker.
    TapeDrive::instance()->close();
    TapeDrive::instance()->open();

    // Write new tape index.
    write();
}

void Tape::read()
{
    if ( !_stubbed ) {
      /* 2002-01-28 LEW */
      // printf("Can't read tape data because tape isn't stubbed\n" );
      /* 2002-01-28 LEW */
      return;
    }

    _stubbed = FALSE;

    /* 2002-01-28 LEW */
    // printf("Preparing to read tape data\n" );
    // QString filename1 = locateLocal( "appdata", _id);
    // printf("The tape data are in \"%s\"\n", filename1.ascii() );
    /* 2002-01-28 LEW */

    if ( !_fptr ) {
        QString filename = locateLocal( "appdata", _id);
        _fptr = fopen( QFile::encodeName(filename), "r" );

	/* 2002-01-28 LEW */
#ifdef DEBUG
	//	printf("Opened tape archive file \"%s\". %s %d\n", 
	//	       filename.ascii(), __FILE__, __LINE__ );
#endif /* DEBUG */
	/* 2002-01-28 LEW */

    }

    if ( !_fptr ) {
        // No tape index file was found.
        int result = KMessageBox::warningContinueCancel( KDatMainWindow::getInstance(), 
                 i18n( "No index file was found for this tape.\n"
                       "Recreate the index from tape?" ), 
                 i18n("Tape Index"), 
                 i18n("Recreate"));
        if (result == KMessageBox::Continue ) {
            write();

            IndexDlg dlg( this, KDatMainWindow::getInstance() );
            dlg.exec();
            TapeManager::instance()->addTape( this );
            return;
        } else {
            return;
        }
    }

    char buf[4096];

    fseek( _fptr, 0, SEEK_SET );

    // Read index file version number.
    if ( !fgets( buf, 4096, _fptr ) ) {
        fclose( _fptr );
        KMessageBox::error( KDatMainWindow::getInstance(), 
                              i18n( "Reading version number failed." ), 
                              i18n("Index File Error") );
        return;
    }
    int version = atoi( buf );

    switch ( version ) {
        case 1:
            readVersion1Index( _fptr );
            readAll( version );
            calcRanges();
            fclose( _fptr );
            _fptr = NULL;
            write();
            break;

        case 2:
            readVersion2Index( _fptr );
            readAll( version );
            calcRanges();
            fclose( _fptr );
            _fptr = NULL;
            write();
            break;

        case 3:
            readVersion3Index( _fptr );
            readAll( version );
            calcRanges();
            fclose( _fptr );
            _fptr = NULL;
            write();
            break;

        case 4:
            readVersion4Index( _fptr );
            break;

        default:
        {
            KMessageBox::sorry( KDatMainWindow::getInstance(), 
                i18n( "The tape index file format is version %1. The index cannot be read by this version of KDat. Perhaps the tape index file was created by a newer version of KDat?" , version ),
                i18n("Tape Index") );
        }
    }
}

void Tape::readAll( int version )
{
    read();

    Q3PtrListIterator<Archive> i( _children );
    for ( ; i.current(); ++i ) {
        i.current()->readAll( version );
    }
}

void Tape::write()
{
    QString filename = locateLocal( "appdata", _id);

    /* 2002-01-28 LEW */
#ifdef DEBUG
    //    printf("Preparing to write the archive data to \"%s\". %s %d\n", 
    //            filename.ascii(), __FILE__, __LINE__ );
#endif /* DEBUG */
    /* 2002-01-28 LEW */

    if ( !_fptr ) {
        _fptr = fopen( QFile::encodeName(filename), "w" );

    /* 2002-01-31 LEW */
#ifdef DEBUG
	//  printf("Opened new archive file \"%s\". %s %d\n", 
	//  filename.ascii(), __FILE__, __LINE__ );
#endif /* DEBUG */
    /* 2002-01-31 LEW */

        if ( !_fptr ) {
            // Suck!
            printf( "Tape::write() -- cannot open '%s' for writing!\n", filename.ascii() );
            return;
        }
    } else {
        freopen( QFile::encodeName(filename), "w", _fptr );
    /* 2002-01-31 LEW */
#ifdef DEBUG
	//	printf("Reopened new archive file \"%s\". %s %d\n", 
	//	       filename.ascii(), __FILE__, __LINE__ );
#endif /* DEBUG */
    /* 2002-01-31 LEW */
    }

    int zero = 0;

    //===== Write the tape data =====

    fprintf( _fptr, "%d\n", KDAT_INDEX_FILE_VERSION );
    fprintf( _fptr, "%s\n", _id.data() );

    fwrite( &_ctime, sizeof( _ctime ), 1, _fptr );
    fwrite( &_mtime, sizeof( _mtime ), 1, _fptr );
    fwrite( &_size , sizeof( _size  ), 1, _fptr );
    char buf[4096];
    memset( buf, 0, 4096 );
    memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
    fwrite( buf, sizeof( char ), 4096, _fptr );
    int ival = _children.count();
    fwrite( &ival, sizeof( ival ), 1, _fptr );

    // Fill in the archive offsets later...
    int archiveTable = ftell( _fptr );
    for ( uint i = 0; i < MAX_NUM_ARCHIVES; i++ ) {
        fwrite( &zero, sizeof( zero ), 1, _fptr );
    }

    //===== Write archives =====
    Q3PtrListIterator<Archive> i( _children );
    int count = 0;
    for ( ; i.current(); ++i, count++ ) {
        // Fill in the file offset.
        int here = ftell( _fptr );
        fseek( _fptr, archiveTable + 4*count, SEEK_SET );
        fwrite( &here, sizeof( here ), 1, _fptr );
        fseek( _fptr, here, SEEK_SET );

        i.current()->write( _fptr );
    }

    freopen( QFile::encodeName(filename), "r+", _fptr );
}

QString Tape::getID()
{
    read();

    return _id;
}

QString Tape::getName()
{
    read();

    return _name;
}

int Tape::getCTime()
{
    read();

    return _ctime;
}

int Tape::getMTime()
{
    read();

    return _mtime;
}

int Tape::getSize()
{
    read();

    return _size;
}

const Q3PtrList<Archive>& Tape::getChildren()
{
    read();

    return _children;
}

void Tape::setName( const QString & name )
{
    /* 2002-01-31 LEW */
    int i;
    /* 2002-01-31 LEW */

    read();

    if ( !_fptr ) {
        // Create a new empty index file.
        write();
    }

    // change file to read-write so we can update it   2002-01-31 LEW
    QString filename = locateLocal( "appdata", _id);
    freopen( QFile::encodeName(filename), "r+", _fptr );

    _name = name;

    char buf[4096];
    if( fseek( _fptr, 0, SEEK_SET ) < 0 )
      {
	clearerr( _fptr );
#ifdef DEBUG
        QString msg = i18n("Error during fseek #1 while accessing archive: \"%1\": %2").arg( getID() ).arg( i18n(strerror( errno )) );
	printf("%s\n", msg.toLatin1());      
	KMessageBox::error(NULL, msg, i18n("File Access Error"));
#endif /* DEBUG */
	return;      
      }
    if( fgets( buf, 4096, _fptr ) == NULL )
      {
	clearerr( _fptr );
#ifdef DEBUG
	QString msg = i18n("Error while accessing string #1 in archive: \"%1\": %2").arg( getID() ).arg(i18n(strerror( errno )));
	printf("%s\n", msg.toLatin1());      
	KMessageBox::error(NULL, msg, i18n("File Access Error"));
#endif /* DEBUG */
	return;      
      }
    if( fgets( buf, 4096, _fptr ) == NULL )
      {
	clearerr( _fptr );
#ifdef DEBUG
	QString msg = i18n("Error while accessing string #2 in archive: \"%1\": %2").arg( getID() ).arg(i18n(strerror( errno )));
	printf("%s\n", msg.toLatin1());      
	KMessageBox::error(NULL, msg, i18n("File Access Error"));
#endif /* DEBUG */
	return;      
      }
    if( fseek( _fptr, 12, SEEK_CUR ) < 0 )
      {
	clearerr( _fptr );
#ifdef DEBUG
	QString msg = i18n("Error during fseek #2 while accessing archive: \"%1\": %2").arg( getID() ).arg(i18n(strerror( errno )));
	printf("%s\n", msg.toLatin1());      
	KMessageBox::error(NULL, msg, i18n("File Access Error"));
#endif /* DEBUG */
	return;      
      }
    memset( buf, 0, 4096 );
    memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
    i = fwrite( buf, sizeof( char ), 4096, _fptr );
    if( ( i < 4096 ) || ( ferror( _fptr ) != 0 )){
      clearerr( _fptr );
      QString msg = i18n("Error while updating archive name: ");
      msg.append( i18n(strerror( errno )) );
      printf("%s\n", msg.latin1());      
      KMessageBox::error(NULL, msg, i18n("File Access Error"));
      // return;      
    /* 2002-01-31 LEW */
    }
    fflush( _fptr );

    /* 2002-01-31 LEW */
#ifdef DEBUG
    //    printf("Tape::setName. wrote \"%s\" (%d bytes) into archive ID %s. %s %d\n", 
    //	   _name.ascii(), _name.length(), getID().toLatin1(), __FILE__, __LINE__);
    //    printf("  The buffer size is 4096.  %d bytes were written\n", i);
#endif /* DEBUG */
    /* 2002-01-31 LEW */

    // change back to read-only   2002-01-31 LEW
    freopen( QFile::encodeName(filename), "r", _fptr );

    TapeManager::instance()->tapeModified( this );
}

void Tape::setMTime( int mtime )
{
    read();

    if ( !_fptr ) {
        // Create a new empty index file.
        write();
    }

    // change file to read-write so we can update it   2002-01-31 LEW
    QString filename = locateLocal( "appdata", _id);
    freopen( QFile::encodeName(filename), "r+", _fptr );

    _mtime = mtime;

    char buf[4096];
    fseek( _fptr, 0, SEEK_SET );
    fgets( buf, 4096, _fptr );
    fgets( buf, 4096, _fptr );
    fseek( _fptr, 4, SEEK_CUR );
    fwrite( &_mtime, sizeof( _mtime ), 1, _fptr );
    fflush( _fptr );

    // change back to read-only   2002-01-31 LEW
    freopen( QFile::encodeName(filename), "r", _fptr );

    TapeManager::instance()->tapeModified( this );
}

void Tape::setSize( int size )
{
    read();

    if ( !_fptr ) {
        // Create a new empty index file.
        write();
    }

    _size = size;

    // change file to read-write so we can update it   2002-01-31 LEW
    QString filename = locateLocal( "appdata", _id);
    freopen( QFile::encodeName(filename), "r+", _fptr );

    char buf[4096];
    fseek( _fptr, 0, SEEK_SET );
    fgets( buf, 4096, _fptr );
    fgets( buf, 4096, _fptr );
    fseek( _fptr, 8, SEEK_CUR );
    fwrite( &_size, sizeof( _size ), 1, _fptr );
    fflush( _fptr );

    // change back to read-only   2002-01-31 LEW
    freopen( QFile::encodeName(filename), "r", _fptr );

    TapeManager::instance()->tapeModified( this );
}

void Tape::addChild( Archive* archive )
{
    /* 2002-01-28 LEW */
    // printf("Preparing to add archive to tape file\n" );
    /* 2002-01-28 LEW */

    read();

    // change file to read-write so we can update it   2002-01-31 LEW
    QString filename = locateLocal( "appdata", _id);
    freopen( QFile::encodeName(filename), "r+", _fptr );

    archive->calcRanges();

    _children.append( archive );

    char buf[4096];
    fseek( _fptr, 0, SEEK_END );
    int here = ftell( _fptr );
    fseek( _fptr, 0, SEEK_SET );
    fgets( buf, 4096, _fptr );
    fgets( buf, 4096, _fptr );
    fseek( _fptr, 12 + 4096, SEEK_CUR );
    int ival = _children.count();
    fwrite( &ival, sizeof( ival ), 1, _fptr );
    fseek( _fptr, ( _children.count() - 1 ) * 4, SEEK_CUR );
    fwrite( &here, sizeof( here ), 1, _fptr );
    fseek( _fptr, here, SEEK_SET );
    archive->write( _fptr );
    fflush( _fptr );

    setMTime( time( NULL ) );

    // change back to read-only   2002-01-31 LEW
    freopen( QFile::encodeName(filename), "r", _fptr );

    /* 2002-01-28 LEW */
    // printf("Done adding archive to tape file\n" );
    /* 2002-01-28 LEW */
}

void Tape::removeChild( Archive* archive )
{
    read();

    while ( _children.last() != archive ) {
        _children.removeLast();
    }
    _children.removeLast();

    char buf[4096];
    fseek( _fptr, 0, SEEK_SET );
    fgets( buf, 4096, _fptr );
    fgets( buf, 4096, _fptr );
    fseek( _fptr, 12 + 4096, SEEK_CUR );
    int ival = _children.count();
    fwrite( &ival, sizeof( ival ), 1, _fptr );
    int here;
    if ( ival > 0 ) {
        fseek( _fptr, _children.count() * 4, SEEK_CUR );
        fread( &here, sizeof( here ), 1, _fptr );
    } else {
        fseek( _fptr, MAX_NUM_ARCHIVES * 4, SEEK_CUR );
        here = ftell( _fptr );
    }

    QString filename = locateLocal( "appdata", _id);
    truncate( QFile::encodeName(filename), here );
    freopen( QFile::encodeName(filename), "r+", _fptr );
    fflush( _fptr );

    // change back to read-only   2002-01-31 LEW
    freopen( QFile::encodeName(filename), "r", _fptr );

    setMTime( time( NULL ) );
}

void Tape::clear()
{
    if ( _children.count() < 1 ) {
        return;
    }

    while ( _children.first() ) {
        delete _children.first();
        _children.removeFirst();
    }

    char buf[4096];
    fseek( _fptr, 0, SEEK_SET );
    fgets( buf, 4096, _fptr );
    fgets( buf, 4096, _fptr );
    fseek( _fptr, 12 + 4096, SEEK_CUR );
    int ival = _children.count();
    fwrite( &ival, sizeof( ival ), 1, _fptr );
    fseek( _fptr, MAX_NUM_ARCHIVES * 4, SEEK_CUR );
    int here = ftell( _fptr );

    QString filename = locateLocal( "appdata", _id);
    truncate( QFile::encodeName(filename), here );
    freopen( QFile::encodeName(filename), "r+", _fptr );
    fflush( _fptr );

    // change back to read-only   2002-01-31 LEW
    freopen( QFile::encodeName(filename), "r", _fptr );

    setMTime( time( NULL ) );
}

void Tape::readVersion1Index( FILE* fptr )
{
    fseek( fptr, 0, SEEK_CUR );

    char buf[4096];

    // Read the tapeID.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
        return;
    }
    QByteArray tapeID = buf;
    tapeID.truncate( tapeID.length() - 1 );
    if ( tapeID !=_id ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
        return;
    }

    // Read creation time.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading creation time failed." ), i18n("Index File Error") );
        return;
    }
    _ctime = atoi( buf );

    // Read modification time.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading modification time failed." ), i18n("Index File Error") );
        return;
    }
    _mtime = atoi( buf );

    // Read tape name.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape name failed." ), i18n("Index File Error") );
        return;
    }
    _name = buf;
    _name.truncate( _name.length() - 1 );

    // Read tape size.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape size failed." ), i18n("Index File Error") );
        return;
    }
    _size = atoi( buf );

    // Read number of archives.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive count failed." ), i18n("Index File Error") );
        return;
    }
    int numArchives = atoi( buf );

    for ( ; numArchives; numArchives-- ) {
        // Read archive name.
        if ( !fgets( buf, 4096, fptr ) ) {
            KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive name failed." ), i18n("Index File Error") );
            return;
        }
        QString archiveName = buf;
        archiveName.truncate( archiveName.length() - 1 );

        // Read archive time stamp.
        if ( !fgets( buf, 4096, fptr ) ) {
            KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive time stamp failed." ), i18n("Index File Error") );
            return;
        }
        int archiveTimeStamp = atoi( buf );

        // Read archive start block.
        if ( !fgets( buf, 4096, fptr ) ) {
            KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive start block failed." ), i18n("Index File Error") );
            return;
        }
        int archiveStartBlock = atoi( buf );

        // Read archive end block.
        if ( !fgets( buf, 4096, fptr ) ) {
            KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive end block failed." ), i18n("Index File Error") );
            return;
        }
        int archiveEndBlock = atoi( buf );

        // Create the archive.
        Archive* archive = new Archive( this, archiveTimeStamp, archiveName );
        archive->setEndBlock( archiveEndBlock - archiveStartBlock );

        _children.append( archive );

        // Read the number of files.
        if ( !fgets( buf, 4096, fptr ) ) {
            KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive file count failed." ), i18n("Index File Error") );
            return;
        }
        int archiveNumFiles = atoi( buf );

        QString tmpFileName;
        int tmpFileSize = -1;
        int tmpFileMTime = -1;
        int tmpFileStartRecord = -1;
        for ( ; archiveNumFiles; archiveNumFiles-- ) {
            // Read file name.
            if ( !fgets( buf, 4096, fptr ) ) {
                KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file name failed." ), i18n("Index File Error") );
                return;
            }
            QString fileName = buf;
            fileName.truncate( fileName.length() - 1 );

            // Read file size.
            if ( !fgets( buf, 4096, fptr ) ) {
                KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file size failed." ), i18n("Index File Error") );
                return;
            }
            int fileSize = atoi( buf );

            // Read file modification time.
            if ( !fgets( buf, 4096, fptr ) ) {
                KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file modification time failed." ), i18n("Index File Error") );
                return;
            }
            int fileModTime = atoi( buf );

            // Read file record number.
            if ( !fgets( buf, 4096, fptr ) ) {
                KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file record number failed." ), i18n("Index File Error") );
                return;
            }
            int fileRecord = atoi( buf );

            if ( tmpFileName.length() > 0 ) {
                archive->addFile( tmpFileSize, tmpFileMTime, tmpFileStartRecord, fileRecord, tmpFileName );
            }

            tmpFileName = fileName.copy();
            tmpFileSize = fileSize;
            tmpFileMTime = fileModTime;
            tmpFileStartRecord = fileRecord;
        }

        if ( tmpFileName.length() > 0 ) {
            archive->addFile( tmpFileSize, tmpFileMTime, tmpFileStartRecord, archive->getEndBlock() * ( Options::instance()->getTapeBlockSize() / 512 ), tmpFileName );
        }
    }
}

void Tape::readVersion2Index( FILE* fptr )
{
    fseek( fptr, 0, SEEK_CUR );

    char buf[4096];

    // Read the tapeID.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
        return;
    }
    QByteArray tapeID = buf;
    tapeID.truncate( tapeID.length() - 1 );
    if ( tapeID != _id ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
        return;
    }

    // Read creation time.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading creation time failed." ), i18n("Index File Error") );
        return;
    }
    _ctime = atoi( buf );

    // Read modification time.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading modification time failed." ), i18n("Index File Error") );
        return;
    }
    _mtime = atoi( buf );

    // Read tape name.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape name failed." ), i18n("Index File Error") );
        return;
    }
    _name = buf;
    _name.truncate( _name.length() - 1 );

    // Read tape size.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape size failed." ), i18n("Index File Error") );
        return;
    }
    _size = atoi( buf );

    // Read number of archives.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive count failed." ), i18n("Index File Error") );
        return;
    }
    int numArchives = atoi( buf );

    int ival;
    for ( ; numArchives; numArchives-- ) {
        fread( &ival, sizeof( ival ), 1, fptr );
        _children.append( new Archive( this, fptr, ival ) );
    }
}

void Tape::readVersion3Index( FILE* fptr )
{
    fseek( fptr, 0, SEEK_CUR );

    char buf[4097];
    buf[4096] = '\0';

    // Read the tapeID.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
        return;
    }
    QByteArray tapeID = buf;
    tapeID.truncate( tapeID.length() - 1 );
    if ( tapeID != _id ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
        return;
    }

    // Read creation time.
    fread( &_ctime, sizeof( _ctime ), 1, fptr );

    // Read modification time.
    fread( &_mtime, sizeof( _mtime ), 1, fptr );

    // Read tape size.
    fread( &_size, sizeof( _size ), 1, fptr );

    // Read tape name.
    fread( buf, sizeof( char ), 4096, fptr );
    _name = buf;

    // Read number of archives.
    int numArchives;
    fread( &numArchives, sizeof( numArchives ), 1, fptr );

    int ival;
    for ( ; numArchives; numArchives-- ) {
        fread( &ival, sizeof( ival ), 1, fptr );
        _children.append( new Archive( this, fptr, ival ) );
    }
}

void Tape::readVersion4Index( FILE* fptr )
{
    fseek( fptr, 0, SEEK_CUR );

    char buf[4097];
    buf[4096] = '\0';

    // Read the tapeID.
    if ( !fgets( buf, 4096, fptr ) ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
        return;
    }
    QByteArray tapeID = buf;
    tapeID.truncate( tapeID.length() - 1 );
    if ( tapeID != _id ) {
        KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
        return;
    }

    // Read creation time.
    fread( &_ctime, sizeof( _ctime ), 1, fptr );

    // Read modification time.
    fread( &_mtime, sizeof( _mtime ), 1, fptr );

    // Read tape size.
    fread( &_size, sizeof( _size ), 1, fptr );

    // Read tape name.
    fread( buf, sizeof( char ), 4096, fptr );
    _name = buf;

    // Read number of archives.
    int numArchives;
    fread( &numArchives, sizeof( numArchives ), 1, fptr );

    int ival;
    for ( ; numArchives; numArchives-- ) {
        fread( &ival, sizeof( ival ), 1, fptr );
        _children.append( new Archive( this, fptr, ival ) );
    }

    /* 2002-01-31 LEW */
#ifdef DEBUG
    printf("Read contents of archive file \"%s\". %s %d\n", 
	   _name.toLatin1(), __FILE__, __LINE__ );
#endif /* DEBUG */
    /* 2002-01-31 LEW */
}

void Tape::calcRanges()
{
    Q3PtrListIterator<Archive> it( getChildren() );
    for ( ; it.current(); ++it ) {
        it.current()->calcRanges();
    }
}
