|
|
|
// 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 <assert.h>
|
|
|
|
#include <values.h>
|
|
|
|
|
|
|
|
#include "File.h"
|
|
|
|
|
|
|
|
File::File( File* parent, int size, int mtime, int startRecord, int endRecord, const TQString & name )
|
|
|
|
: _stubbed( FALSE ),
|
|
|
|
_name( name ),
|
|
|
|
_parent( parent )
|
|
|
|
{
|
|
|
|
assert( endRecord >= startRecord );
|
|
|
|
|
|
|
|
_union._data._size = size;
|
|
|
|
_union._data._mtime = mtime;
|
|
|
|
_union._data._startRecord = startRecord;
|
|
|
|
_union._data._endRecord = endRecord;
|
|
|
|
}
|
|
|
|
|
|
|
|
File::File( File* parent, FILE* fptr, int offset )
|
|
|
|
: _stubbed( TRUE ),
|
|
|
|
_parent( parent )
|
|
|
|
{
|
|
|
|
_union._stub._fptr = fptr;
|
|
|
|
_union._stub._offset = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
File::~File()
|
|
|
|
{
|
|
|
|
while ( _tqchildren.first() ) {
|
|
|
|
delete _tqchildren.first();
|
|
|
|
_tqchildren.removeFirst();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void File::read( int version )
|
|
|
|
{
|
|
|
|
if ( !_stubbed ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_stubbed = FALSE;
|
|
|
|
|
|
|
|
FILE* fptr = _union._stub._fptr;
|
|
|
|
|
|
|
|
fseek( fptr, _union._stub._offset, SEEK_SET );
|
|
|
|
|
|
|
|
// File name (4 bytes + n chars).
|
|
|
|
int ival;
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
char * buf = new char[ival+1];
|
|
|
|
buf[ival] = '\0';
|
|
|
|
fread( buf, sizeof( char ), ival, fptr );
|
|
|
|
_name = buf;
|
|
|
|
|
|
|
|
delete [] buf;
|
|
|
|
|
|
|
|
// File size (4 bytes).
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
_union._data._size = ival;
|
|
|
|
|
|
|
|
// File modification time (4 bytes).
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
_union._data._mtime = ival;
|
|
|
|
|
|
|
|
// Start record number.
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
_union._data._startRecord = ival;
|
|
|
|
|
|
|
|
// End record number.
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
_union._data._endRecord = ival;
|
|
|
|
|
|
|
|
//%%% This is a kludge to cope with some screwed up tape indexes.
|
|
|
|
//%%% Hopefully the file with the zero end record is *always* at
|
|
|
|
//%%% the end of the archive.
|
|
|
|
if ( ( _union._data._endRecord <= 0 ) && ( _union._data._startRecord != _union._data._endRecord ) ) {
|
|
|
|
_union._data._endRecord = MAXINT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( version > 3 ) {
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
int rc = ival;
|
|
|
|
int start = 0;
|
|
|
|
int end = 0;
|
|
|
|
for ( int ii = 0; ii < rc; ii++ ) {
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
start = ival;
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
end = ival;
|
|
|
|
_ranges.addRange( start, end );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===== Read files =====
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
for ( int count = ival; count > 0; count-- ) {
|
|
|
|
fread( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
addChild( new File( this, fptr, ival ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void File::readAll( int version )
|
|
|
|
{
|
|
|
|
read( version );
|
|
|
|
|
|
|
|
TQPtrListIterator<File> i( getChildren() );
|
|
|
|
for ( ; i.current(); ++i ) {
|
|
|
|
i.current()->readAll( version );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void File::write( FILE* fptr )
|
|
|
|
{
|
|
|
|
int zero = 0;
|
|
|
|
|
|
|
|
// File name (4 bytes + n chars).
|
|
|
|
int ival = getName().length();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
fwrite( getName().ascii(), sizeof( char ), ival, fptr );
|
|
|
|
|
|
|
|
// File size (4 bytes).
|
|
|
|
ival = getSize();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
// File modification time (4 bytes).
|
|
|
|
ival = getMTime();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
// Start record number.
|
|
|
|
ival = getStartRecord();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
// End record number.
|
|
|
|
ival = getEndRecord();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
// Child range list.
|
|
|
|
ival = _ranges.getRanges().count();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
TQPtrListIterator<Range> it( _ranges.getRanges() );
|
|
|
|
for ( ; it.current(); ++it ) {
|
|
|
|
ival = it.current()->getStart();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
ival = it.current()->getEnd();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Number of immediate tqchildren (4 bytes).
|
|
|
|
ival = getChildren().count();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
// Fill in file offsets later...
|
|
|
|
int fileTable = ftell( fptr );
|
|
|
|
for ( ; ival > 0; ival-- ) {
|
|
|
|
fwrite( &zero, sizeof( zero ), 1, fptr );
|
|
|
|
}
|
|
|
|
|
|
|
|
//===== Write files =====
|
|
|
|
ival = _tqchildren.count();
|
|
|
|
fwrite( &ival, sizeof( ival ), 1, fptr );
|
|
|
|
|
|
|
|
TQPtrListIterator<File> i( _tqchildren );
|
|
|
|
int count = 0;
|
|
|
|
for ( ; i.current(); ++i, count++ ) {
|
|
|
|
// Fill in the file offset.
|
|
|
|
int here = ftell( fptr );
|
|
|
|
fseek( fptr, fileTable + 4*count, SEEK_SET );
|
|
|
|
fwrite( &here, sizeof( here ), 1, fptr );
|
|
|
|
fseek( fptr, here, SEEK_SET );
|
|
|
|
|
|
|
|
i.current()->write( fptr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool File::isDirectory()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _name[ _name.length() - 1 ] == '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
int File::getSize()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _union._data._size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int File::getMTime()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _union._data._mtime;
|
|
|
|
}
|
|
|
|
|
|
|
|
int File::getStartRecord()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _union._data._startRecord;
|
|
|
|
}
|
|
|
|
|
|
|
|
int File::getEndRecord()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _union._data._endRecord;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString File::getName()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _name;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString File::getFullPathName()
|
|
|
|
{
|
|
|
|
TQString tmp = _name.copy();
|
|
|
|
for ( File* parent = getParent(); parent; parent = parent->getParent() ) {
|
|
|
|
tmp.prepend( parent->getName() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
File* File::getParent()
|
|
|
|
{
|
|
|
|
return _parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQPtrList<File>& File::getChildren()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _tqchildren;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQPtrList<Range>& File::getRanges()
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
return _ranges.getRanges();
|
|
|
|
}
|
|
|
|
|
|
|
|
void File::addChild( File* file )
|
|
|
|
{
|
|
|
|
read();
|
|
|
|
|
|
|
|
_tqchildren.append( file );
|
|
|
|
}
|
|
|
|
|
|
|
|
void File::calcRanges()
|
|
|
|
{
|
|
|
|
assert( !_stubbed );
|
|
|
|
|
|
|
|
_ranges.clear();
|
|
|
|
_ranges.addRange( getStartRecord(), getEndRecord() );
|
|
|
|
|
|
|
|
TQPtrListIterator<File> it( getChildren() );
|
|
|
|
for ( ; it.current(); ++it ) {
|
|
|
|
it.current()->calcRanges();
|
|
|
|
TQPtrListIterator<Range> it2( it.current()->getRanges() );
|
|
|
|
for ( ; it2.current(); ++it2 ) {
|
|
|
|
_ranges.addRange( it2.current()->getStart(), it2.current()->getEnd() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|