summaryrefslogtreecommitdiffstats
path: root/kdat/File.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdat/File.cpp')
-rw-r--r--kdat/File.cpp287
1 files changed, 287 insertions, 0 deletions
diff --git a/kdat/File.cpp b/kdat/File.cpp
new file mode 100644
index 0000000..7fc8f97
--- /dev/null
+++ b/kdat/File.cpp
@@ -0,0 +1,287 @@
+// 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 QString & 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 );
+
+ QPtrListIterator<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 );
+ QPtrListIterator<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 );
+
+ QPtrListIterator<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;
+}
+
+QString File::getName()
+{
+ read();
+
+ return _name;
+}
+
+QString File::getFullPathName()
+{
+ QString tmp = _name.copy();
+ for ( File* parent = getParent(); parent; parent = parent->getParent() ) {
+ tmp.prepend( parent->getName() );
+ }
+
+ return tmp;
+}
+
+File* File::getParent()
+{
+ return _parent;
+}
+
+const QPtrList<File>& File::getChildren()
+{
+ read();
+
+ return _children;
+}
+
+const QPtrList<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() );
+
+ QPtrListIterator<File> it( getChildren() );
+ for ( ; it.current(); ++it ) {
+ it.current()->calcRanges();
+ QPtrListIterator<Range> it2( it.current()->getRanges() );
+ for ( ; it2.current(); ++it2 ) {
+ _ranges.addRange( it2.current()->getStart(), it2.current()->getEnd() );
+ }
+ }
+}