You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeadmin/kdat/File.cpp

288 lines
6.7 KiB

// 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 ( _children.first() ) {
delete _children.first();
_children.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 children (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 = _children.count();
fwrite( &ival, sizeof( ival ), 1, fptr );
TQPtrListIterator<File> i( _children );
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 _children;
}
const TQPtrList<Range>& File::getRanges()
{
read();
return _ranges.getRanges();
}
void File::addChild( File* file )
{
read();
_children.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() );
}
}
}