summaryrefslogtreecommitdiffstats
path: root/libk3b/tools
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-03 02:15:56 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-03 02:15:56 +0000
commit50b48aec6ddd451a6d1709c0942477b503457663 (patch)
treea9ece53ec06fd0a2819de7a2a6de997193566626 /libk3b/tools
downloadk3b-50b48aec6ddd451a6d1709c0942477b503457663.tar.gz
k3b-50b48aec6ddd451a6d1709c0942477b503457663.zip
Added abandoned KDE3 version of K3B
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/k3b@1084400 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libk3b/tools')
-rw-r--r--libk3b/tools/Makefile.am44
-rw-r--r--libk3b/tools/k3bactivepipe.cpp255
-rw-r--r--libk3b/tools/k3bactivepipe.h134
-rw-r--r--libk3b/tools/k3bbusywidget.cpp103
-rw-r--r--libk3b/tools/k3bbusywidget.h54
-rw-r--r--libk3b/tools/k3bcdparanoialib.cpp783
-rw-r--r--libk3b/tools/k3bcdparanoialib.h161
-rw-r--r--libk3b/tools/k3bcdtextvalidator.cpp42
-rw-r--r--libk3b/tools/k3bcdtextvalidator.h33
-rw-r--r--libk3b/tools/k3bchecksumpipe.cpp99
-rw-r--r--libk3b/tools/k3bchecksumpipe.h66
-rw-r--r--libk3b/tools/k3bcutcombobox.cpp230
-rw-r--r--libk3b/tools/k3bcutcombobox.h92
-rw-r--r--libk3b/tools/k3bdevicecombobox.cpp174
-rw-r--r--libk3b/tools/k3bdevicecombobox.h67
-rw-r--r--libk3b/tools/k3bdevicehandler.cpp332
-rw-r--r--libk3b/tools/k3bdevicehandler.h237
-rw-r--r--libk3b/tools/k3bdeviceselectiondialog.cpp130
-rw-r--r--libk3b/tools/k3bdeviceselectiondialog.h62
-rw-r--r--libk3b/tools/k3bdirsizejob.cpp184
-rw-r--r--libk3b/tools/k3bdirsizejob.h67
-rw-r--r--libk3b/tools/k3bexceptions.cpp43
-rw-r--r--libk3b/tools/k3bexceptions.h35
-rw-r--r--libk3b/tools/k3bfilesplitter.cpp307
-rw-r--r--libk3b/tools/k3bfilesplitter.h108
-rw-r--r--libk3b/tools/k3bfilesysteminfo.cpp141
-rw-r--r--libk3b/tools/k3bfilesysteminfo.h56
-rw-r--r--libk3b/tools/k3bintmapcombobox.cpp127
-rw-r--r--libk3b/tools/k3bintmapcombobox.h83
-rw-r--r--libk3b/tools/k3bintvalidator.cpp137
-rw-r--r--libk3b/tools/k3bintvalidator.h84
-rw-r--r--libk3b/tools/k3biso9660.cpp899
-rw-r--r--libk3b/tools/k3biso9660.h453
-rw-r--r--libk3b/tools/k3biso9660backend.cpp239
-rw-r--r--libk3b/tools/k3biso9660backend.h95
-rw-r--r--libk3b/tools/k3blibdvdcss.cpp307
-rw-r--r--libk3b/tools/k3blibdvdcss.h84
-rw-r--r--libk3b/tools/k3blistview.cpp1290
-rw-r--r--libk3b/tools/k3blistview.h296
-rw-r--r--libk3b/tools/k3blistviewitemanimator.cpp137
-rw-r--r--libk3b/tools/k3blistviewitemanimator.h78
-rw-r--r--libk3b/tools/k3bmd5job.cpp322
-rw-r--r--libk3b/tools/k3bmd5job.h92
-rw-r--r--libk3b/tools/k3bmsfedit.cpp153
-rw-r--r--libk3b/tools/k3bmsfedit.h70
-rw-r--r--libk3b/tools/k3bmultichoicedialog.cpp191
-rw-r--r--libk3b/tools/k3bmultichoicedialog.h73
-rw-r--r--libk3b/tools/k3bpipe.cpp79
-rw-r--r--libk3b/tools/k3bpipe.h60
-rw-r--r--libk3b/tools/k3bprogressdialog.cpp107
-rw-r--r--libk3b/tools/k3bprogressdialog.h63
-rw-r--r--libk3b/tools/k3bpushbutton.cpp136
-rw-r--r--libk3b/tools/k3bpushbutton.h75
-rw-r--r--libk3b/tools/k3bradioaction.cpp94
-rw-r--r--libk3b/tools/k3bradioaction.h122
-rw-r--r--libk3b/tools/k3brichtextlabel.cpp109
-rw-r--r--libk3b/tools/k3brichtextlabel.h62
-rw-r--r--libk3b/tools/k3bsignalwaiter.cpp62
-rw-r--r--libk3b/tools/k3bsignalwaiter.h51
-rw-r--r--libk3b/tools/k3bstdguiitems.cpp215
-rw-r--r--libk3b/tools/k3bstdguiitems.h45
-rw-r--r--libk3b/tools/k3bstringutils.cpp111
-rw-r--r--libk3b/tools/k3bstringutils.h39
-rw-r--r--libk3b/tools/k3btempfile.cpp51
-rw-r--r--libk3b/tools/k3btempfile.h43
-rw-r--r--libk3b/tools/k3bthreadwidget.cpp142
-rw-r--r--libk3b/tools/k3bthreadwidget.h78
-rw-r--r--libk3b/tools/k3bthroughputestimator.cpp98
-rw-r--r--libk3b/tools/k3bthroughputestimator.h57
-rw-r--r--libk3b/tools/k3btitlelabel.cpp266
-rw-r--r--libk3b/tools/k3btitlelabel.h68
-rw-r--r--libk3b/tools/k3btoolbox.cpp293
-rw-r--r--libk3b/tools/k3btoolbox.h93
-rw-r--r--libk3b/tools/k3btoolbutton.cpp109
-rw-r--r--libk3b/tools/k3btoolbutton.h50
-rw-r--r--libk3b/tools/k3bvalidators.cpp154
-rw-r--r--libk3b/tools/k3bvalidators.h131
-rw-r--r--libk3b/tools/k3bwavefilewriter.cpp186
-rw-r--r--libk3b/tools/k3bwavefilewriter.h78
-rw-r--r--libk3b/tools/kcutlabel.cpp115
-rw-r--r--libk3b/tools/kcutlabel.h68
-rw-r--r--libk3b/tools/libisofs/COPYING280
-rw-r--r--libk3b/tools/libisofs/ChangeLog9
-rw-r--r--libk3b/tools/libisofs/Makefile.am5
-rw-r--r--libk3b/tools/libisofs/README24
-rw-r--r--libk3b/tools/libisofs/bswap.h94
-rw-r--r--libk3b/tools/libisofs/el_torito.h63
-rw-r--r--libk3b/tools/libisofs/iso_fs.h219
-rw-r--r--libk3b/tools/libisofs/isofs.cpp878
-rw-r--r--libk3b/tools/libisofs/isofs.h151
-rw-r--r--libk3b/tools/libisofs/rock.h127
91 files changed, 14609 insertions, 0 deletions
diff --git a/libk3b/tools/Makefile.am b/libk3b/tools/Makefile.am
new file mode 100644
index 0000000..d48a295
--- /dev/null
+++ b/libk3b/tools/Makefile.am
@@ -0,0 +1,44 @@
+AM_CPPFLAGS= -I$(srcdir)/../../src \
+ -I$(srcdir)/../core \
+ -I$(srcdir)/../../libk3bdevice \
+ -I$(srcdir)/.. \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libk3btools.la
+
+libk3btools_la_LIBADD = libisofs/libisofs.la
+
+libk3btools_la_LDFLAGS = $(all_libraries)
+
+libk3btools_la_SOURCES = k3bwavefilewriter.cpp k3bbusywidget.cpp k3bdeviceselectiondialog.cpp \
+ k3bmd5job.cpp k3btitlelabel.cpp k3bcutcombobox.cpp \
+ k3bstringutils.cpp k3bdevicecombobox.cpp kcutlabel.cpp \
+ k3bstdguiitems.cpp k3bvalidators.cpp k3bthroughputestimator.cpp \
+ k3biso9660.cpp k3bmultichoicedialog.cpp k3bdevicehandler.cpp \
+ k3bcdparanoialib.cpp k3blistview.cpp k3bmsfedit.cpp \
+ k3bcdtextvalidator.cpp k3bintvalidator.cpp k3bexceptions.cpp \
+ k3bprogressdialog.cpp k3btoolbox.cpp k3bpushbutton.cpp \
+ k3blistviewitemanimator.cpp k3bthreadwidget.cpp k3bradioaction.cpp \
+ k3bsignalwaiter.cpp k3blibdvdcss.cpp k3biso9660backend.cpp \
+ k3bpipe.cpp k3bchecksumpipe.cpp k3btoolbutton.cpp \
+ k3bintmapcombobox.cpp k3bdirsizejob.cpp k3brichtextlabel.cpp \
+ k3btempfile.cpp k3bactivepipe.cpp k3bfilesplitter.cpp \
+ k3bfilesysteminfo.cpp
+
+include_HEADERS = k3bwavefilewriter.h k3bbusywidget.h k3bdeviceselectiondialog.h \
+ k3bmd5job.h k3bcutcombobox.h k3bstringutils.h \
+ k3bdevicecombobox.h kcutlabel.h k3bstdguiitems.h \
+ k3bvalidators.h k3bthroughputestimator.h k3biso9660.h \
+ k3bmultichoicedialog.h k3bdevicehandler.h k3bcdparanoialib.h \
+ k3blistview.h k3bmsfedit.h k3bcdtextvalidator.h \
+ k3bintvalidator.h k3bexceptions.h k3bprogressdialog.h \
+ k3btoolbox.h k3bpushbutton.h k3blistviewitemanimator.h \
+ k3bthreadwidget.h k3bradioaction.h k3bsignalwaiter.h \
+ k3biso9660backend.h k3bpipe.h k3bdirsizejob.h \
+ k3bchecksumpipe.h k3btoolbutton.h k3bintmapcombobox.h \
+ k3brichtextlabel.h k3btempfile.h k3bactivepipe.h \
+ k3bfilesplitter.h k3bfilesysteminfo.h
+
+METASOURCES = AUTO
+
+SUBDIRS = libisofs
diff --git a/libk3b/tools/k3bactivepipe.cpp b/libk3b/tools/k3bactivepipe.cpp
new file mode 100644
index 0000000..5a1e575
--- /dev/null
+++ b/libk3b/tools/k3bactivepipe.cpp
@@ -0,0 +1,255 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bactivepipe.h"
+
+#include <k3bpipe.h>
+
+#include <kdebug.h>
+
+#include <qthread.h>
+#include <qiodevice.h>
+
+#include <unistd.h>
+
+
+class K3bActivePipe::Private : public QThread
+{
+public:
+ Private( K3bActivePipe* pipe ) :
+ m_pipe( pipe ),
+ fdToReadFrom(-1),
+ fdToWriteTo(-1),
+ sourceIODevice(0),
+ sinkIODevice(0),
+ closeFdToReadFrom(false),
+ closeFdToWriteTo(false) {
+ }
+
+ void run() {
+ kdDebug() << "(K3bActivePipe) started thread." << endl;
+ bytesRead = bytesWritten = 0;
+ buffer.resize( 10*2048 );
+ ssize_t r = 0;
+ while( ( r = m_pipe->read( buffer.data(), buffer.size() ) ) > 0 ) {
+
+ bytesRead += r;
+
+ // write it out
+ ssize_t w = 0;
+ ssize_t ww = 0;
+ while( w < r ) {
+ if( ( ww = m_pipe->write( buffer.data()+w, r-w ) ) > 0 ) {
+ w += ww;
+ bytesWritten += ww;
+ }
+ else {
+ kdDebug() << "(K3bActivePipe) write failed." << endl;
+ close( closeWhenDone );
+ return;
+ }
+ }
+ }
+ // kdDebug() << "(K3bActivePipe) thread done: " << r << " (total bytes read/written: " << bytesRead << "/" << bytesWritten << ")" << endl;
+ close( closeWhenDone );
+ }
+
+ int readFd() const {
+ if( fdToReadFrom == -1 )
+ return pipeIn.out();
+ else
+ return fdToReadFrom;
+ }
+
+ int writeFd() const {
+ if( fdToWriteTo == -1 )
+ return pipeOut.in();
+ else
+ return fdToWriteTo;
+ }
+
+ void close( bool closeAll ) {
+ if( sourceIODevice )
+ sourceIODevice->close();
+ if( sinkIODevice )
+ sinkIODevice->close();
+
+ if( closeAll ) {
+ pipeIn.close();
+ pipeOut.close();
+ if( fdToWriteTo != -1 &&
+ closeFdToWriteTo )
+ ::close( fdToWriteTo );
+
+ if( fdToReadFrom != -1 &&
+ closeFdToReadFrom )
+ ::close( fdToReadFrom );
+ }
+ }
+
+private:
+ K3bActivePipe* m_pipe;
+
+public:
+ int fdToReadFrom;
+ int fdToWriteTo;
+ K3bPipe pipeIn;
+ K3bPipe pipeOut;
+
+ QIODevice* sourceIODevice;
+ QIODevice* sinkIODevice;
+
+ bool closeWhenDone;
+ bool closeFdToReadFrom;
+ bool closeFdToWriteTo;
+
+ QByteArray buffer;
+
+ Q_UINT64 bytesRead;
+ Q_UINT64 bytesWritten;
+};
+
+
+K3bActivePipe::K3bActivePipe()
+{
+ d = new Private( this );
+}
+
+
+K3bActivePipe::~K3bActivePipe()
+{
+ delete d;
+}
+
+
+bool K3bActivePipe::open( bool closeWhenDone )
+{
+ if( d->running() )
+ return false;
+
+ d->closeWhenDone = closeWhenDone;
+
+ if( d->sourceIODevice ) {
+ if( !d->sourceIODevice->open( IO_ReadOnly ) )
+ return false;
+ }
+ else if( d->fdToReadFrom == -1 && !d->pipeIn.open() ) {
+ return false;
+ }
+
+ if( d->sinkIODevice ) {
+ if( !d->sinkIODevice->open( IO_WriteOnly ) )
+ return false;
+ }
+ else if( d->fdToWriteTo == -1 && !d->pipeOut.open() ) {
+ close();
+ return false;
+ }
+
+ kdDebug() << "(K3bActivePipe) successfully opened pipe." << endl;
+
+ d->start();
+ return true;
+}
+
+
+void K3bActivePipe::close()
+{
+ d->pipeIn.closeIn();
+ d->wait();
+ d->close( true );
+}
+
+
+void K3bActivePipe::readFromFd( int fd, bool close )
+{
+ d->fdToReadFrom = fd;
+ d->sourceIODevice = 0;
+ d->closeFdToReadFrom = close;
+}
+
+
+void K3bActivePipe::writeToFd( int fd, bool close )
+{
+ d->fdToWriteTo = fd;
+ d->sinkIODevice = 0;
+ d->closeFdToWriteTo = close;
+}
+
+
+void K3bActivePipe::readFromIODevice( QIODevice* dev )
+{
+ d->fdToReadFrom = -1;
+ d->sourceIODevice = dev;
+}
+
+
+void K3bActivePipe::writeToIODevice( QIODevice* dev )
+{
+ d->fdToWriteTo = -1;
+ d->sinkIODevice = dev;
+}
+
+
+int K3bActivePipe::in() const
+{
+ return d->pipeIn.in();
+}
+
+
+int K3bActivePipe::out() const
+{
+ return d->pipeOut.out();
+}
+
+
+int K3bActivePipe::read( char* data, int max )
+{
+ if( d->sourceIODevice )
+ return d->sourceIODevice->readBlock( data, max );
+ else
+ return ::read( d->readFd(), data, max );
+}
+
+
+int K3bActivePipe::write( char* data, int max )
+{
+ if( d->sinkIODevice )
+ return d->sinkIODevice->writeBlock( data, max );
+ else
+ return ::write( d->writeFd(), data, max );
+}
+
+
+bool K3bActivePipe::pumpSync()
+{
+ if( open( true ) )
+ d->wait();
+ else
+ return false;
+ return true;
+}
+
+
+Q_UINT64 K3bActivePipe::bytesRead() const
+{
+ return d->bytesRead;
+}
+
+
+Q_UINT64 K3bActivePipe::bytesWritten() const
+{
+ return d->bytesWritten;
+}
diff --git a/libk3b/tools/k3bactivepipe.h b/libk3b/tools/k3bactivepipe.h
new file mode 100644
index 0000000..367646d
--- /dev/null
+++ b/libk3b/tools/k3bactivepipe.h
@@ -0,0 +1,134 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_ACTIVE_PIPE_H_
+#define _K3B_ACTIVE_PIPE_H_
+
+#include <qcstring.h>
+
+#include <k3b_export.h>
+
+
+class QIODevice;
+
+
+/**
+ * The active pipe pumps data from a source to a sink using an
+ * additional thread.
+ */
+class LIBK3B_EXPORT K3bActivePipe
+{
+ public:
+ K3bActivePipe();
+ virtual ~K3bActivePipe();
+
+ /**
+ * Opens the pipe and thus starts the
+ * pumping.
+ *
+ * \param closeWhenDone If true the pipes will be closed
+ * once all data has been read.
+ */
+ virtual bool open( bool closeWhenDone = false );
+
+ /**
+ * Opens the pipe syncroneously and blocks until all data has been
+ * pumped through.
+ * The pipe is closed afterwards.
+ */
+ bool pumpSync();
+
+ /**
+ * Close the pipe
+ */
+ virtual void close();
+
+ /**
+ * Set the file descriptor to read from. If this is -1 (the default) then
+ * data has to be piped into the in() file descriptor.
+ *
+ * \param fd The file descriptor to read from.
+ * \param close If true the reading file descriptor will be closed on a call to close()
+ */
+ void readFromFd( int fd, bool close = false );
+
+ /**
+ * Set the file descriptor to write to. If this is -1 (the default) then
+ * data has to read from the out() file descriptor.
+ *
+ * \param fd The file descriptor to write to.
+ * \param close If true the reading file descriptor will be closed on a call to close()
+ */
+ void writeToFd( int fd, bool close = false );
+
+ /**
+ * Read from a QIODevice instead of a file descriptor.
+ * The device will be opened IO_ReadOnly and closed
+ * afterwards.
+ */
+ void readFromIODevice( QIODevice* dev );
+
+ /**
+ * Write to a QIODevice instead of a file descriptor.
+ * The device will be opened IO_WriteOnly and closed
+ * afterwards.
+ */
+ void writeToIODevice( QIODevice* dev );
+
+ /**
+ * The file descriptor to write into
+ * Only valid if no source has been set
+ */
+ int in() const;
+
+ /**
+ * The file descriptor to read from
+ * Only valid if no sink has been set
+ */
+ int out() const;
+
+ /**
+ * The number of bytes that have been read.
+ */
+ Q_UINT64 bytesRead() const;
+
+ /**
+ * The number of bytes that have been written.
+ */
+ Q_UINT64 bytesWritten() const;
+
+ protected:
+ /**
+ * Reads the data from the source.
+ * The default implementation reads from the file desc
+ * set via readFromFd or from in()
+ */
+ virtual int read( char* data, int max );
+
+ /**
+ * Write the data to the sink.
+ * The default implementation writes to the file desc
+ * set via writeToFd or out()
+ *
+ * Can be reimplememented to further process the data.
+ */
+ virtual int write( char* data, int max );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bbusywidget.cpp b/libk3b/tools/k3bbusywidget.cpp
new file mode 100644
index 0000000..d222107
--- /dev/null
+++ b/libk3b/tools/k3bbusywidget.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * $Id: k3bbusywidget.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bbusywidget.h"
+
+#include <qtimer.h>
+#include <qpainter.h>
+
+#include <kglobalsettings.h>
+
+
+K3bBusyWidget::K3bBusyWidget( QWidget* parent, const char* name )
+ : QFrame( parent, name )
+{
+ m_busyTimer = new QTimer( this );
+ m_iBusyPosition = 0;
+
+ connect( m_busyTimer, SIGNAL(timeout()), this, SLOT(animateBusy()) );
+
+ m_bBusy = false;
+}
+
+K3bBusyWidget::~K3bBusyWidget()
+{
+}
+
+
+void K3bBusyWidget::showBusy( bool b )
+{
+ m_bBusy = b;
+
+// if( b ) {
+// m_iBusyCounter++;
+// }
+// else if( m_iBusyCounter > 0 ) {
+// m_iBusyCounter--;
+// }
+
+ if( m_bBusy ) {
+ if( !m_busyTimer->isActive() )
+ m_busyTimer->start( 500 );
+ }
+ else {
+ if( m_busyTimer->isActive() )
+ m_busyTimer->stop();
+ update();
+ m_iBusyPosition = 0;
+ }
+}
+
+
+void K3bBusyWidget::animateBusy()
+{
+ m_iBusyPosition++;
+ update();
+}
+
+
+QSize K3bBusyWidget::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+
+QSize K3bBusyWidget::minimumSizeHint() const
+{
+ return QSize( 2*frameWidth() + 62, 10 );
+}
+
+
+void K3bBusyWidget::drawContents( QPainter* p )
+{
+ QRect rect = contentsRect();
+
+ int squareSize = 8;
+
+ int pos = 2 + m_iBusyPosition * (squareSize + 2);
+
+ // check if the position is in the visible area
+ if( pos + 8 + 2> rect.width() ) {
+ m_iBusyPosition = 0;
+ pos = 2;
+ }
+
+ // p->eraseRect( rect );
+ if( m_bBusy )
+ p->fillRect( pos, (rect.height() - squareSize)/2, squareSize, squareSize, KGlobalSettings::highlightColor() );
+}
+
+
+#include "k3bbusywidget.moc"
diff --git a/libk3b/tools/k3bbusywidget.h b/libk3b/tools/k3bbusywidget.h
new file mode 100644
index 0000000..2a6934c
--- /dev/null
+++ b/libk3b/tools/k3bbusywidget.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * $Id: k3bbusywidget.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef K3B_BUSY_WIDGET_H
+#define K3B_BUSY_WIDGET_H
+
+
+#include <qframe.h>
+#include "k3b_export.h"
+
+class QPainter;
+class QTimer;
+
+
+class LIBK3B_EXPORT K3bBusyWidget : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ K3bBusyWidget( QWidget* parent = 0, const char* name = 0 );
+ ~K3bBusyWidget();
+
+ void showBusy( bool b );
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ protected:
+ void drawContents( QPainter* p );
+
+ private slots:
+ void animateBusy();
+
+ private:
+ bool m_bBusy;
+ int m_iBusyPosition;
+
+ QTimer* m_busyTimer;
+};
+
+
+#endif
diff --git a/libk3b/tools/k3bcdparanoialib.cpp b/libk3b/tools/k3bcdparanoialib.cpp
new file mode 100644
index 0000000..5976941
--- /dev/null
+++ b/libk3b/tools/k3bcdparanoialib.cpp
@@ -0,0 +1,783 @@
+/*
+ *
+ * $Id: k3bcdparanoialib.cpp 621693 2007-01-09 14:38:25Z trueg $
+ * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <config.h>
+
+#include "k3bcdparanoialib.h"
+
+#include <k3bdevice.h>
+#include <k3btoc.h>
+#include <k3bmsf.h>
+
+#include <kdebug.h>
+
+#include <dlfcn.h>
+
+#include <qfile.h>
+#include <qmutex.h>
+
+
+static bool s_haveLibCdio = false;
+
+
+void* K3bCdparanoiaLib::s_libInterface = 0;
+void* K3bCdparanoiaLib::s_libParanoia = 0;
+int K3bCdparanoiaLib::s_counter = 0;
+
+
+#define CDDA_IDENTIFY s_haveLibCdio ? "cdio_cddap_identify" : "cdda_identify"
+#define CDDA_CLOSE s_haveLibCdio ? "cdio_cddap_close" : "cdda_close"
+#define CDDA_OPEN s_haveLibCdio ? "cdio_cddap_open" : "cdda_open"
+#define CDDA_TRACK_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_track_firstsector" : "cdda_track_firstsector"
+#define CDDA_TRACK_LASTSECTOR s_haveLibCdio ? "cdio_cddap_track_lastsector" : "cdda_track_lastsector"
+#define CDDA_VERBOSE_SET s_haveLibCdio ? "cdio_cddap_verbose_set" : "cdda_verbose_set"
+#define CDDA_DISC_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_disc_firstsector" : "cdda_disc_firstsector"
+
+#define PARANOIA_INIT s_haveLibCdio ? "cdio_paranoia_init" : "paranoia_init"
+#define PARANOIA_FREE s_haveLibCdio ? "cdio_paranoia_free" : "paranoia_free"
+#define PARANOIA_MODESET s_haveLibCdio ? "cdio_paranoia_modeset" : "paranoia_modeset"
+#define PARANOIA_SEEK s_haveLibCdio ? "cdio_paranoia_seek" : "paranoia_seek"
+#define PARANOIA_READ_LIMITED s_haveLibCdio ? "cdio_paranoia_read_limited" : "paranoia_read_limited"
+
+
+// from cdda_paranoia.h
+#define PARANOIA_CB_READ 0
+#define PARANOIA_CB_VERIFY 1
+#define PARANOIA_CB_FIXUP_EDGE 2
+#define PARANOIA_CB_FIXUP_ATOM 3
+#define PARANOIA_CB_SCRATCH 4
+#define PARANOIA_CB_REPAIR 5
+#define PARANOIA_CB_SKIP 6
+#define PARANOIA_CB_DRIFT 7
+#define PARANOIA_CB_BACKOFF 8
+#define PARANOIA_CB_OVERLAP 9
+#define PARANOIA_CB_FIXUP_DROPPED 10
+#define PARANOIA_CB_FIXUP_DUPED 11
+#define PARANOIA_CB_READERR 12
+
+
+
+static void paranoiaCallback( long, int status )
+{
+ // do nothing so far....
+ return;
+
+ switch( status ) {
+ case -1:
+ break;
+ case -2:
+ break;
+ case PARANOIA_CB_READ:
+ // no problem
+ // does only this mean that the sector has been read?
+// m_lastReadSector = sector; // this seems to be rather useless
+// m_readSectors++;
+ break;
+ case PARANOIA_CB_VERIFY:
+ break;
+ case PARANOIA_CB_FIXUP_EDGE:
+ break;
+ case PARANOIA_CB_FIXUP_ATOM:
+ break;
+ case PARANOIA_CB_SCRATCH:
+ // scratch detected
+ break;
+ case PARANOIA_CB_REPAIR:
+ break;
+ case PARANOIA_CB_SKIP:
+ // skipped sector
+ break;
+ case PARANOIA_CB_DRIFT:
+ break;
+ case PARANOIA_CB_BACKOFF:
+ break;
+ case PARANOIA_CB_OVERLAP:
+ // sector does not seem to contain the current
+ // sector but the amount of overlapped data
+ // m_overlap = sector;
+ break;
+ case PARANOIA_CB_FIXUP_DROPPED:
+ break;
+ case PARANOIA_CB_FIXUP_DUPED:
+ break;
+ case PARANOIA_CB_READERR:
+ break;
+ }
+}
+
+
+
+extern "C" {
+ struct cdrom_drive;
+ struct cdrom_paranoia;
+
+ // HINT: these pointers must NOT have the same name like the actual methods!
+ // I added "cdda_" as prefix
+ // Before doing that K3b crashed in cdda_open!
+ // Can anyone please explain that to me?
+
+ // cdda_interface
+ cdrom_drive* (*cdda_cdda_identify)(const char*, int, char**);
+ int (*cdda_cdda_open)(cdrom_drive *d);
+ int (*cdda_cdda_close)(cdrom_drive *d);
+ long (*cdda_cdda_track_firstsector)( cdrom_drive*, int );
+ long (*cdda_cdda_track_lastsector)( cdrom_drive*, int );
+ long (*cdda_cdda_disc_firstsector)(cdrom_drive *d);
+ void (*cdda_cdda_verbose_set)(cdrom_drive *d,int err_action, int mes_action);
+
+ // cdda_paranoia
+ cdrom_paranoia* (*cdda_paranoia_init)(cdrom_drive*);
+ void (*cdda_paranoia_free)(cdrom_paranoia *p);
+ void (*cdda_paranoia_modeset)(cdrom_paranoia *p, int mode);
+ int16_t* (*cdda_paranoia_read_limited)(cdrom_paranoia *p, void(*callback)(long,int), int);
+ long (*cdda_paranoia_seek)(cdrom_paranoia *p,long seek,int mode);
+}
+
+// from cdda_paranoia.h
+#define PARANOIA_MODE_FULL 0xff
+#define PARANOIA_MODE_DISABLE 0
+
+#define PARANOIA_MODE_VERIFY 1
+#define PARANOIA_MODE_FRAGMENT 2
+#define PARANOIA_MODE_OVERLAP 4
+#define PARANOIA_MODE_SCRATCH 8
+#define PARANOIA_MODE_REPAIR 16
+#define PARANOIA_MODE_NEVERSKIP 32
+
+
+
+/**
+ * Internal class used by K3bCdparanoiaLib
+ */
+class K3bCdparanoiaLibData
+{
+ public:
+ K3bCdparanoiaLibData( K3bDevice::Device* dev )
+ : m_device(dev),
+ m_drive(0),
+ m_paranoia(0),
+ m_currentSector(0) {
+ s_dataMap.insert( dev, this );
+ }
+
+ ~K3bCdparanoiaLibData() {
+ paranoiaFree();
+
+ s_dataMap.erase( m_device );
+ }
+
+ K3bDevice::Device* device() const { return m_device; }
+ void paranoiaModeSet( int );
+ bool paranoiaInit();
+ void paranoiaFree();
+ int16_t* paranoiaRead( void(*callback)(long,int), int maxRetries );
+ long paranoiaSeek( long, int );
+ long firstSector( int );
+ long lastSector( int );
+ long sector() const { return m_currentSector; }
+
+ static K3bCdparanoiaLibData* data( K3bDevice::Device* dev ) {
+ QMap<K3bDevice::Device*, K3bCdparanoiaLibData*>::const_iterator it = s_dataMap.find( dev );
+ if( it == s_dataMap.constEnd() )
+ return new K3bCdparanoiaLibData( dev );
+ else
+ return *it;
+ }
+
+ static void freeAll() {
+ // clean up all K3bCdparanoiaLibData instances
+ for( QMap<K3bDevice::Device*, K3bCdparanoiaLibData*>::iterator it = s_dataMap.begin();
+ it != s_dataMap.end(); ++it )
+ delete it.data();
+ }
+
+ private:
+ //
+ // We have exactly one instance of K3bCdparanoiaLibData per device
+ //
+ static QMap<K3bDevice::Device*, K3bCdparanoiaLibData*> s_dataMap;
+
+ K3bDevice::Device* m_device;
+
+ cdrom_drive* m_drive;
+ cdrom_paranoia* m_paranoia;
+
+ long m_currentSector;
+
+ QMutex mutex;
+};
+
+
+QMap<K3bDevice::Device*, K3bCdparanoiaLibData*> K3bCdparanoiaLibData::s_dataMap;
+
+bool K3bCdparanoiaLibData::paranoiaInit()
+{
+ mutex.lock();
+
+ if( m_drive )
+ paranoiaFree();
+
+ // since we use cdparanoia to open the device it is important to close
+ // the device here
+ m_device->close();
+
+ m_drive = cdda_cdda_identify( QFile::encodeName(m_device->blockDeviceName()), 0, 0 );
+ if( m_drive == 0 ) {
+ mutex.unlock();
+ return false;
+ }
+
+ // cdda_cdda_verbose_set( m_drive, 1, 1 );
+
+ cdda_cdda_open( m_drive );
+ m_paranoia = cdda_paranoia_init( m_drive );
+ if( m_paranoia == 0 ) {
+ mutex.unlock();
+ paranoiaFree();
+ return false;
+ }
+
+ m_currentSector = 0;
+
+ mutex.unlock();
+
+ return true;
+}
+
+
+void K3bCdparanoiaLibData::paranoiaFree()
+{
+ mutex.lock();
+
+ if( m_paranoia ) {
+ cdda_paranoia_free( m_paranoia );
+ m_paranoia = 0;
+ }
+ if( m_drive ) {
+ cdda_cdda_close( m_drive );
+ m_drive = 0;
+ }
+
+ mutex.unlock();
+}
+
+
+void K3bCdparanoiaLibData::paranoiaModeSet( int mode )
+{
+ mutex.lock();
+ cdda_paranoia_modeset( m_paranoia, mode );
+ mutex.unlock();
+}
+
+
+int16_t* K3bCdparanoiaLibData::paranoiaRead( void(*callback)(long,int), int maxRetries )
+{
+ if( m_paranoia ) {
+ mutex.lock();
+ int16_t* data = cdda_paranoia_read_limited( m_paranoia, callback, maxRetries );
+ if( data )
+ m_currentSector++;
+ mutex.unlock();
+ return data;
+ }
+ else
+ return 0;
+}
+
+
+long K3bCdparanoiaLibData::firstSector( int track )
+{
+ if( m_drive ) {
+ mutex.lock();
+ long sector = cdda_cdda_track_firstsector( m_drive, track );
+ mutex.unlock();
+ return sector;
+ }
+ else
+ return -1;
+}
+
+long K3bCdparanoiaLibData::lastSector( int track )
+{
+ if( m_drive ) {
+ mutex.lock();
+ long sector = cdda_cdda_track_lastsector(m_drive, track );
+ mutex.unlock();
+ return sector;
+ }
+ else
+ return -1;
+}
+
+
+long K3bCdparanoiaLibData::paranoiaSeek( long sector, int mode )
+{
+ if( m_paranoia ) {
+ mutex.lock();
+ m_currentSector = cdda_paranoia_seek( m_paranoia, sector, mode );
+ mutex.unlock();
+ return m_currentSector;
+ }
+ else
+ return -1;
+}
+
+
+
+class K3bCdparanoiaLib::Private
+{
+public:
+ Private()
+ : device(0),
+ currentSector(0),
+ startSector(0),
+ lastSector(0),
+ status(S_OK),
+ paranoiaLevel(0),
+ neverSkip(true),
+ maxRetries(5),
+ data(0) {
+ }
+
+ ~Private() {
+ }
+
+ void updateParanoiaMode() {
+ // from cdrdao 1.1.7
+ int paranoiaMode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
+
+ switch( paranoiaLevel ) {
+ case 0:
+ paranoiaMode = PARANOIA_MODE_DISABLE;
+ break;
+
+ case 1:
+ paranoiaMode |= PARANOIA_MODE_OVERLAP;
+ paranoiaMode &= ~PARANOIA_MODE_VERIFY;
+ break;
+
+ case 2:
+ paranoiaMode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);
+ break;
+ }
+
+ if( neverSkip )
+ paranoiaMode |= PARANOIA_MODE_NEVERSKIP;
+
+ data->paranoiaModeSet( paranoiaMode );
+ }
+
+ // high-level api
+ K3bDevice::Device* device;
+ K3bDevice::Toc toc;
+ long currentSector;
+ long startSector;
+ long lastSector;
+ int status;
+ unsigned int currentTrack;
+ int paranoiaLevel;
+ bool neverSkip;
+ int maxRetries;
+
+ K3bCdparanoiaLibData* data;
+};
+
+
+K3bCdparanoiaLib::K3bCdparanoiaLib()
+{
+ d = new Private();
+ s_counter++;
+}
+
+
+K3bCdparanoiaLib::~K3bCdparanoiaLib()
+{
+ delete d;
+ s_counter--;
+ if( s_counter == 0 ) {
+ K3bCdparanoiaLibData::freeAll();
+
+ // cleanup the dynamically loaded lib
+ dlclose( s_libInterface );
+ dlclose( s_libParanoia );
+ s_libInterface = 0;
+ s_libParanoia = 0;
+ }
+}
+
+
+bool K3bCdparanoiaLib::load()
+{
+ cdda_cdda_identify = (cdrom_drive* (*) (const char*, int, char**))dlsym( s_libInterface, CDDA_IDENTIFY );
+ cdda_cdda_open = (int (*) (cdrom_drive*))dlsym( s_libInterface, CDDA_OPEN );
+ cdda_cdda_close = (int (*) (cdrom_drive*))dlsym( s_libInterface, CDDA_CLOSE );
+ cdda_cdda_track_firstsector = (long (*)(cdrom_drive*, int))dlsym( s_libInterface, CDDA_TRACK_FIRSTSECTOR );
+ cdda_cdda_track_lastsector = (long (*)(cdrom_drive*, int))dlsym( s_libInterface, CDDA_TRACK_LASTSECTOR );
+ cdda_cdda_verbose_set = (void (*)(cdrom_drive *d,int err_action, int mes_action))dlsym( s_libInterface, CDDA_VERBOSE_SET );
+ cdda_cdda_disc_firstsector = (long (*)(cdrom_drive *d))dlsym( s_libInterface, CDDA_DISC_FIRSTSECTOR );
+
+ cdda_paranoia_init = (cdrom_paranoia* (*)(cdrom_drive*))dlsym( s_libParanoia, PARANOIA_INIT );
+ cdda_paranoia_free = (void (*)(cdrom_paranoia *p))dlsym( s_libParanoia, PARANOIA_FREE );
+ cdda_paranoia_modeset = (void (*)(cdrom_paranoia *p, int mode))dlsym( s_libParanoia, PARANOIA_MODESET );
+ cdda_paranoia_read_limited = (int16_t* (*)(cdrom_paranoia *p, void(*callback)(long,int), int))dlsym( s_libParanoia, PARANOIA_READ_LIMITED );
+ cdda_paranoia_seek = (long (*)(cdrom_paranoia *p,long seek,int mode))dlsym( s_libParanoia, PARANOIA_SEEK );
+
+ // check if all symbols could be resoled
+ if( cdda_cdda_identify == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_identify'" << endl;
+ return false;
+ }
+ if( cdda_cdda_open == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_open'" << endl;
+ return false;
+ }
+ if( cdda_cdda_close == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_close'" << endl;
+ return false;
+ }
+ if( cdda_cdda_track_firstsector == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_track_firstsector'" << endl;
+ return false;
+ }
+ if( cdda_cdda_track_lastsector == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_track_lastsector'" << endl;
+ return false;
+ }
+ if( cdda_cdda_disc_firstsector == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_disc_firstsector'" << endl;
+ return false;
+ }
+ if( cdda_cdda_verbose_set == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_verbose_set'" << endl;
+ return false;
+ }
+
+ if( cdda_paranoia_init == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_init'" << endl;
+ return false;
+ }
+ if( cdda_paranoia_free == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_free'" << endl;
+ return false;
+ }
+ if( cdda_paranoia_modeset == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_modeset'" << endl;
+ return false;
+ }
+ if( cdda_paranoia_read_limited == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_read_limited'" << endl;
+ return false;
+ }
+ if( cdda_paranoia_seek == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_seek'" << endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+
+K3bCdparanoiaLib* K3bCdparanoiaLib::create()
+{
+ // check if libcdda_interface is avalilable
+ if( s_libInterface == 0 ) {
+ s_haveLibCdio = false;
+
+ s_libInterface = dlopen( "libcdda_interface.so.0", RTLD_NOW|RTLD_GLOBAL );
+
+ // try the redhat & Co. location
+ if( s_libInterface == 0 )
+ s_libInterface = dlopen( "cdda/libcdda_interface.so.0", RTLD_NOW|RTLD_GLOBAL );
+
+ // try the new cdio lib
+ if( s_libInterface == 0 ) {
+ s_libInterface = dlopen( "libcdio_cdda.so", RTLD_NOW|RTLD_GLOBAL );
+ s_haveLibCdio = true;
+ }
+
+ if( s_libInterface == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error while loading libcdda_interface. " << endl;
+ return 0;
+ }
+
+
+ s_libParanoia = dlopen( "libcdda_paranoia.so.0", RTLD_NOW );
+
+ // try the redhat & Co. location
+ if( s_libParanoia == 0 )
+ s_libParanoia = dlopen( "cdda/libcdda_paranoia.so.0", RTLD_NOW );
+
+ // try the new cdio lib
+ if( s_haveLibCdio && s_libParanoia == 0 )
+ s_libParanoia = dlopen( "libcdio_paranoia.so.0", RTLD_NOW );
+
+ if( s_libParanoia == 0 ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error while loading libcdda_paranoia. " << endl;
+ dlclose( s_libInterface );
+ s_libInterface = 0;
+ return 0;
+ }
+ }
+
+ K3bCdparanoiaLib* lib = new K3bCdparanoiaLib();
+ if( !lib->load() ) {
+ kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve all symbols!" << endl;
+ delete lib;
+ return 0;
+ }
+ return lib;
+}
+
+
+bool K3bCdparanoiaLib::initParanoia( K3bDevice::Device* dev, const K3bDevice::Toc& toc )
+{
+ if( !dev ) {
+ kdError() << "(K3bCdparanoiaLib::initParanoia) dev = 0!" << endl;
+ return false;
+ }
+
+ close();
+
+ d->device = dev;
+ d->toc = toc;
+ if( d->toc.isEmpty() ) {
+ kdDebug() << "(K3bCdparanoiaLib) empty toc." << endl;
+ cleanup();
+ return false;
+ }
+
+ if( d->toc.contentType() == K3bDevice::DATA ) {
+ kdDebug() << "(K3bCdparanoiaLib) No audio tracks found." << endl;
+ cleanup();
+ return false;
+ }
+
+ //
+ // Get the appropriate data instance for this device
+ //
+ d->data = K3bCdparanoiaLibData::data( dev );
+
+ if( d->data->paranoiaInit() ) {
+ d->startSector = d->currentSector = d->lastSector = 0;
+
+ return true;
+ }
+ else {
+ cleanup();
+ return false;
+ }
+}
+
+
+bool K3bCdparanoiaLib::initParanoia( K3bDevice::Device* dev )
+{
+ return initParanoia( dev, dev->readToc() );
+}
+
+
+void K3bCdparanoiaLib::close()
+{
+ cleanup();
+}
+
+
+void K3bCdparanoiaLib::cleanup()
+{
+ if( d->data )
+ d->data->paranoiaFree();
+ d->device = 0;
+ d->currentSector = 0;
+}
+
+
+bool K3bCdparanoiaLib::initReading()
+{
+ if( d->device ) {
+ // find first audio track
+ K3bDevice::Toc::const_iterator trackIt = d->toc.begin();
+ while( (*trackIt).type() != K3bDevice::Track::AUDIO ) {
+ ++trackIt;
+ }
+
+ long start = (*trackIt).firstSector().lba();
+
+ // find last audio track
+ while( trackIt != d->toc.end() && (*trackIt).type() == K3bDevice::Track::AUDIO )
+ ++trackIt;
+ --trackIt;
+
+ long end = (*trackIt).lastSector().lba();
+
+ return initReading( start, end );
+ }
+ else {
+ kdDebug() << "(K3bCdparanoiaLib) initReading without initParanoia." << endl;
+ return false;
+ }
+}
+
+
+bool K3bCdparanoiaLib::initReading( unsigned int track )
+{
+ if( d->device ) {
+ if( track <= d->toc.count() ) {
+ const K3bDevice::Track& k3bTrack = d->toc[track-1];
+ if( k3bTrack.type() == K3bDevice::Track::AUDIO ) {
+ return initReading( k3bTrack.firstSector().lba(), k3bTrack.lastSector().lba() );
+ }
+ else {
+ kdDebug() << "(K3bCdparanoiaLib) Track " << track << " no audio track." << endl;
+ return false;
+ }
+ }
+ else {
+ kdDebug() << "(K3bCdparanoiaLib) Track " << track << " too high." << endl;
+ return false;
+ }
+ }
+ else {
+ kdDebug() << "(K3bCdparanoiaLib) initReading without initParanoia." << endl;
+ return false;
+ }
+}
+
+
+bool K3bCdparanoiaLib::initReading( long start, long end )
+{
+ kdDebug() << "(K3bCdparanoiaLib) initReading( " << start << ", " << end << " )" << endl;
+
+ if( d->device ) {
+ if( d->toc.firstSector().lba() <= start &&
+ d->toc.lastSector().lba() >= end ) {
+ d->startSector = d->currentSector = start;
+ d->lastSector = end;
+
+ // determine track number
+ d->currentTrack = 1;
+ while( d->toc[d->currentTrack-1].lastSector() < start )
+ d->currentTrack++;
+
+ // let the paranoia stuff point to the startSector
+ d->data->paranoiaSeek( start, SEEK_SET );
+ return true;
+ }
+ else {
+ kdDebug() << "(K3bCdparanoiaLib) " << start << " and " << end << " out of range." << endl;
+ return false;
+ }
+ }
+ else {
+ kdDebug() << "(K3bCdparanoiaLib) initReading without initParanoia." << endl;
+ return false;
+ }
+}
+
+
+char* K3bCdparanoiaLib::read( int* statusCode, unsigned int* track, bool littleEndian )
+{
+ if( d->currentSector > d->lastSector ) {
+ kdDebug() << "(K3bCdparanoiaLib) finished ripping. read "
+ << (d->currentSector - d->startSector) << " sectors." << endl
+ << " current sector: " << d->currentSector << endl;
+ d->status = S_OK;
+ if( statusCode )
+ *statusCode = d->status;
+ return 0;
+ }
+
+ if( d->currentSector != d->data->sector() ) {
+ kdDebug() << "(K3bCdparanoiaLib) need to seek before read. Looks as if we are reusing the paranoia instance." << endl;
+ if( !d->data->paranoiaSeek( d->currentSector, SEEK_SET ) )
+ return 0;
+ }
+
+ //
+ // The paranoia data could have been used by someone else before
+ // and setting the paranoia mode is fast
+ //
+ d->updateParanoiaMode();
+
+ Q_INT16* data = d->data->paranoiaRead( paranoiaCallback, d->maxRetries );
+
+ char* charData = reinterpret_cast<char*>(data);
+
+#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN
+ if( littleEndian ) {
+#else
+ if( !littleEndian ) {
+#endif
+ for( int i = 0; i < CD_FRAMESIZE_RAW-1; i+=2 ) {
+ char b = charData[i];
+ charData[i] = charData[i+1];
+ charData[i+1] = b;
+ }
+ }
+
+
+ if( data )
+ d->status = S_OK;
+ else
+ d->status = S_ERROR; // We may skip this sector if we'd like...
+
+ if( statusCode )
+ *statusCode = d->status;
+
+ if( track )
+ *track = d->currentTrack;
+
+ d->currentSector++;
+
+ if( d->toc[d->currentTrack-1].lastSector() < d->currentSector )
+ d->currentTrack++;
+
+ return charData;
+}
+
+
+int K3bCdparanoiaLib::status() const
+{
+ return d->status;
+}
+
+
+const K3bDevice::Toc& K3bCdparanoiaLib::toc() const
+{
+ return d->toc;
+}
+
+
+long K3bCdparanoiaLib::rippedDataLength() const
+{
+ return d->lastSector - d->startSector + 1;
+}
+
+
+void K3bCdparanoiaLib::setParanoiaMode( int m )
+{
+ d->paranoiaLevel = m;
+}
+
+
+void K3bCdparanoiaLib::setNeverSkip( bool b )
+{
+ d->neverSkip = b;
+}
+
+
+void K3bCdparanoiaLib::setMaxRetries( int r )
+{
+ d->maxRetries = r;
+}
diff --git a/libk3b/tools/k3bcdparanoialib.h b/libk3b/tools/k3bcdparanoialib.h
new file mode 100644
index 0000000..70504de
--- /dev/null
+++ b/libk3b/tools/k3bcdparanoialib.h
@@ -0,0 +1,161 @@
+/*
+ *
+ * $Id: k3bcdparanoialib.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef K3B_CDPARANOIA_LIB_H
+#define K3B_CDPARANOIA_LIB_H
+
+// from cdda_interface.h
+#define CD_FRAMESIZE_RAW 2352
+
+
+#include <qstring.h>
+
+#include <sys/types.h>
+#include "k3b_export.h"
+
+namespace K3bDevice {
+ class Device;
+ class Toc;
+}
+
+
+/**
+ * K3bCdparanoiaLib is a convenience wrapper around libcdda_interface
+ * and libcdda_paranoia.
+ *
+ * It uses four paranoia levels 0-3 which can be set via setParanoiaMode
+ * and are used the same way as in cdrdao:
+ * \li 0: No checking, data is copied directly from the drive.
+ * \li 1: Perform overlapped reading to avoid jitter.
+ * \li 2: Like 1 but with additional checks of the read audio data.
+ * \li 3: Like 2 but with additional scratch detection and repair.
+ *
+ * K3bCdparanoiaLib is based on a shared data approach which makes sure
+ * that each device can only be opened once. This is necessary since
+ * libcdda_interface opens the device exclusively on most distributions.
+ *
+ * However, it is perfectly possible to have two instances of K3bCdparanoiaLib
+ * accessing the same device at the same time. K3bCdparanoiaLib will take care
+ * of the syncing and seeking issues automatically.
+ *
+ * K3bCdparanoiaLib is thread-safe.
+ *
+ * Usage:
+ * <pre>
+ * K3bCdparanoiaLib lib;
+ * lib.initParanoia( mydevice );
+ * lib.initReading( tracknumber );
+ * while( char* data = lib.read() )
+ * dosomethingcoolwithdata( data );
+ * </pre>
+ */
+class LIBK3B_EXPORT K3bCdparanoiaLib
+{
+ public:
+ ~K3bCdparanoiaLib();
+
+ /** default: 1 */
+ void setParanoiaMode( int );
+ void setNeverSkip( bool b );
+
+ /** default: 5 */
+ void setMaxRetries( int );
+
+ /**
+ * This will read the Toc and initialize some stuff.
+ * It will also call paranoiaInit( const QString& )
+ */
+ bool initParanoia( K3bDevice::Device* dev );
+
+ /**
+ * Use for faster initialization without reading the toc
+ */
+ bool initParanoia( K3bDevice::Device* dev, const K3bDevice::Toc& );
+
+ void close();
+
+ /**
+ * Call this after initParanoia to set the data to rip.
+ *
+ * Rip all audio tracks.
+ */
+ bool initReading();
+
+ /**
+ * Call this after initParanoia to set the data to rip.
+ */
+ bool initReading( unsigned int track );
+
+ /**
+ * Call this after initParanoia to set the data to rip.
+ */
+ bool initReading( long startSector, long endSector );
+
+ /**
+ * Read data.
+ * \param statusCode If not 0 will be set.
+ * \param track the tracknumer the data belongs to
+ *
+ * This method takes care of swapping the byte-order depending on the
+ * machine type.
+ *
+ * \return The read sector data or 0 if all data within the specified range
+ * has been read or an error has occured.
+ */
+ char* read( int* statusCode = 0, unsigned int* track = 0, bool littleEndian = true );
+
+ /**
+ * This only is valid after a call to read()
+ */
+ int status() const;
+
+ enum Status {
+ S_OK,
+ S_ERROR
+ // to be extended with Jitter and stuff...
+ };
+
+ /**
+ * Only valid after a call to initParanoia()
+ */
+ const K3bDevice::Toc& toc() const;
+
+ long rippedDataLength() const;
+
+ /**
+ * returns 0 if the cdparanoialib could not
+ * be found on the system.
+ * Otherwise you have to take care of
+ * deleting.
+ */
+ static K3bCdparanoiaLib* create();
+
+ private:
+ void cleanup();
+
+ K3bCdparanoiaLib();
+ bool load();
+
+ class Private;
+ Private* d;
+
+ static void* s_libInterface;
+ static void* s_libParanoia;
+ static int s_counter;
+};
+
+
+#endif
diff --git a/libk3b/tools/k3bcdtextvalidator.cpp b/libk3b/tools/k3bcdtextvalidator.cpp
new file mode 100644
index 0000000..8b3c97a
--- /dev/null
+++ b/libk3b/tools/k3bcdtextvalidator.cpp
@@ -0,0 +1,42 @@
+/*
+ *
+ * $Id: k3bcdtextvalidator.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3bcdtextvalidator.h"
+
+K3bCdTextValidator::K3bCdTextValidator(QObject *parent, const char *name)
+ : K3bLatin1Validator(parent, name)
+{
+}
+
+
+K3bCdTextValidator::~K3bCdTextValidator()
+{
+}
+
+
+QValidator::State K3bCdTextValidator::validate( QString& input, int& pos ) const
+{
+ if( input.length() > 160 )
+ return Invalid;
+
+ // forbid some characters that might introduce problems
+ for( unsigned int i = 0; i < input.length(); ++i ) {
+ if( input[i] == '/' || input[i] == '"' || input[i] == '\\' )
+ return Invalid;
+ }
+
+ return K3bLatin1Validator::validate( input, pos );
+}
diff --git a/libk3b/tools/k3bcdtextvalidator.h b/libk3b/tools/k3bcdtextvalidator.h
new file mode 100644
index 0000000..48ada05
--- /dev/null
+++ b/libk3b/tools/k3bcdtextvalidator.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * $Id: k3bcdtextvalidator.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3BCDTEXTVALIDATOR_H_
+#define _K3BCDTEXTVALIDATOR_H_
+
+
+#include <k3bvalidators.h>
+#include "k3b_export.h"
+
+class LIBK3B_EXPORT K3bCdTextValidator : public K3bLatin1Validator
+{
+ public:
+ K3bCdTextValidator(QObject *parent = 0, const char *name = 0);
+ ~K3bCdTextValidator();
+
+ State validate( QString& input, int& pos ) const;
+};
+
+#endif
diff --git a/libk3b/tools/k3bchecksumpipe.cpp b/libk3b/tools/k3bchecksumpipe.cpp
new file mode 100644
index 0000000..21d308a
--- /dev/null
+++ b/libk3b/tools/k3bchecksumpipe.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bchecksumpipe.h"
+
+#include <kmdcodec.h>
+#include <kdebug.h>
+
+#include <unistd.h>
+
+
+class K3bChecksumPipe::Private
+{
+public:
+ Private()
+ : checksumType(MD5) {
+ }
+
+ void update( const char* in, int len ) {
+ switch( checksumType ) {
+ case MD5:
+ md5.update( in, len );
+ break;
+ }
+ }
+
+ void reset() {
+ switch( checksumType ) {
+ case MD5:
+ md5.reset();
+ break;
+ }
+ }
+
+ int checksumType;
+
+ KMD5 md5;
+};
+
+
+K3bChecksumPipe::K3bChecksumPipe()
+ : K3bActivePipe()
+{
+ d = new Private();
+}
+
+
+K3bChecksumPipe::~K3bChecksumPipe()
+{
+ delete d;
+}
+
+
+bool K3bChecksumPipe::open( bool closeWhenDone )
+{
+ return open( MD5, closeWhenDone );
+}
+
+
+bool K3bChecksumPipe::open( Type type, bool closeWhenDone )
+{
+ if( K3bActivePipe::open( closeWhenDone ) ) {
+ d->reset();
+ d->checksumType = type;
+ return true;
+ }
+ else
+ return false;
+}
+
+
+QCString K3bChecksumPipe::checksum() const
+{
+ switch( d->checksumType ) {
+ case MD5:
+ return d->md5.hexDigest();
+ }
+
+ return QCString();
+}
+
+
+int K3bChecksumPipe::write( char* data, int max )
+{
+ d->update( data, max );
+ return K3bActivePipe::write( data, max );
+}
diff --git a/libk3b/tools/k3bchecksumpipe.h b/libk3b/tools/k3bchecksumpipe.h
new file mode 100644
index 0000000..88adc74
--- /dev/null
+++ b/libk3b/tools/k3bchecksumpipe.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_CHECKSUM_PIPE_H_
+#define _K3B_CHECKSUM_PIPE_H_
+
+#include <k3bactivepipe.h>
+
+#include <k3b_export.h>
+
+
+/**
+ * The checksum pipe calculates the checksum of the data
+ * passed through it.
+ */
+class LIBK3B_EXPORT K3bChecksumPipe : public K3bActivePipe
+{
+ public:
+ K3bChecksumPipe();
+ ~K3bChecksumPipe();
+
+ enum Type {
+ MD5
+ };
+
+ /**
+ * \reimplemented
+ * Defaults to MD5 checksum
+ */
+ bool open( bool closeWhenDone = false );
+
+ /**
+ * Opens the pipe and thus starts the
+ * checksum calculation
+ *
+ * \param closeWhenDone If true the pipes will be closed
+ * once all data has been read.
+ */
+ bool open( Type type, bool closeWhenDone = false );
+
+ /**
+ * Get the calculated checksum
+ */
+ QCString checksum() const;
+
+ protected:
+ int write( char* data, int max );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bcutcombobox.cpp b/libk3b/tools/k3bcutcombobox.cpp
new file mode 100644
index 0000000..d4f516b
--- /dev/null
+++ b/libk3b/tools/k3bcutcombobox.cpp
@@ -0,0 +1,230 @@
+/*
+ *
+ * $Id: k3bcutcombobox.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bcutcombobox.h"
+
+#include <k3bstringutils.h>
+
+#include <qfontmetrics.h>
+#include <qevent.h>
+#include <qstringlist.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qsizepolicy.h>
+
+
+class K3bCutComboBox::Private
+{
+public:
+ Private() {
+ method = CUT;
+ }
+
+ QStringList originalItems;
+
+ int method;
+ int width;
+};
+
+
+K3bCutComboBox::K3bCutComboBox( QWidget* parent, const char* name )
+ : KComboBox( parent, name )
+{
+ d = new Private();
+ // setSizePolicy( QSizePolicy::Maximum, sizePolicy().horData(), sizePolicy().hasHeightForWidth() );
+}
+
+
+K3bCutComboBox::K3bCutComboBox( int method, QWidget* parent, const char* name )
+ : KComboBox( parent, name )
+{
+ d = new Private();
+ d->method = method;
+}
+
+
+K3bCutComboBox::~K3bCutComboBox()
+{
+ delete d;
+}
+
+
+void K3bCutComboBox::setMethod( int m )
+{
+ d->method = m;
+ cutText();
+}
+
+
+QSize K3bCutComboBox::sizeHint() const
+{
+// QSize s(KComboBox::sizeHint());
+
+// for( int i = 0; i < count(); i++ ) {
+// int w = fontMetrics().width(d->originalItems[i]) +
+// ( d->pixmaps[i].isNull() ? 0 : d->pixmaps[i].width() + 4);
+// if( w > s.width() )
+// s.setWidth( w );
+// }
+
+ return KComboBox::sizeHint();
+}
+
+QSize K3bCutComboBox::minimumSizeHint() const
+{
+ return KComboBox::minimumSizeHint();
+}
+
+
+void K3bCutComboBox::setCurrentText( const QString& s )
+{
+ int i;
+ for( i = 0; i < count(); i++ )
+ if ( d->originalItems[i] == s )
+ break;
+ if ( i < count() ) {
+ setCurrentItem(i);
+ }
+ else if( !d->originalItems.isEmpty() ) {
+ d->originalItems[currentItem()] = s;
+ cutText();
+ }
+}
+
+
+void K3bCutComboBox::insertStringList( const QStringList&, int )
+{
+ // FIXME
+}
+
+
+void K3bCutComboBox::insertStrList( const QStrList&, int )
+{
+ // FIXME
+}
+
+void K3bCutComboBox::insertStrList( const QStrList*, int )
+{
+ // FIXME
+}
+
+void K3bCutComboBox::insertStrList( const char**, int, int)
+{
+ // FIXME
+}
+
+void K3bCutComboBox::insertItem( const QString& text, int index )
+{
+ insertItem( QPixmap(), text, index );
+}
+
+void K3bCutComboBox::insertItem( const QPixmap& pix, int i )
+{
+ insertItem( pix, "", i );
+}
+
+void K3bCutComboBox::insertItem( const QPixmap& pixmap, const QString& text, int index )
+{
+ if( index != -1 )
+ d->originalItems.insert( d->originalItems.at(index), text );
+ else
+ d->originalItems.append( text );
+
+ if( !pixmap.isNull() )
+ KComboBox::insertItem( pixmap, "xx", index );
+ else
+ KComboBox::insertItem( "xx", index );
+
+ cutText();
+}
+
+void K3bCutComboBox::removeItem( int i )
+{
+ d->originalItems.erase( d->originalItems.at(i) );
+ KComboBox::removeItem( i );
+}
+
+void K3bCutComboBox::changeItem( const QString& s, int i )
+{
+ d->originalItems[i] = s;
+ cutText();
+}
+
+void K3bCutComboBox::changeItem( const QPixmap& pix, const QString& s, int i )
+{
+ KComboBox::changeItem( pix, i );
+ changeItem( s, i );
+}
+
+
+QString K3bCutComboBox::text( int i ) const
+{
+ if( i < (int)d->originalItems.count() )
+ return d->originalItems[i];
+ else
+ return QString::null;
+}
+
+
+QString K3bCutComboBox::currentText() const
+{
+ if( currentItem() < (int)d->originalItems.count() )
+ return d->originalItems[currentItem()];
+ else
+ return QString::null;
+}
+
+
+void K3bCutComboBox::clear()
+{
+ KComboBox::clear();
+ d->originalItems.clear();
+}
+
+void K3bCutComboBox::resizeEvent( QResizeEvent* e )
+{
+ cutText();
+
+ KComboBox::resizeEvent(e);
+}
+
+
+void K3bCutComboBox::cutText()
+{
+ d->width = QStyle::visualRect( style().querySubControlMetrics(QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxEditField), this ).width();
+
+ for( int i = 0; i < (int)d->originalItems.count(); ++i ) {
+ int w = d->width;
+ if ( pixmap(i) && !pixmap(i)->isNull() )
+ w -= ( pixmap(i)->width() + 4 );
+
+ QString text;
+ if( d->method == SQUEEZE )
+ text = K3b::squeezeTextToWidth( fontMetrics(), d->originalItems[i], w );
+ else
+ text = K3b::cutToWidth( fontMetrics(), d->originalItems[i], w );
+
+ // now insert the cut text
+ if( pixmap(i) )
+ KComboBox::changeItem( *pixmap(i), text, i );
+ else
+ KComboBox::changeItem( text, i );
+ }
+}
+
+#include "k3bcutcombobox.moc"
diff --git a/libk3b/tools/k3bcutcombobox.h b/libk3b/tools/k3bcutcombobox.h
new file mode 100644
index 0000000..1c35e78
--- /dev/null
+++ b/libk3b/tools/k3bcutcombobox.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * $Id: k3bcutcombobox.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_CUT_COMBOBOX_H_
+#define _K3B_CUT_COMBOBOX_H_
+
+#include <kcombobox.h>
+#include "k3b_export.h"
+class QResizeEvent;
+
+
+/**
+ * Cuts it's text.
+ * Since it rebuilds the complete list of strings every time
+ * a new string is added or one gets removed it is not a good
+ * idea to use this for dynamic lists.
+ *
+ * Be aware that currently only insertItem works.
+ * none of the insertStrList or insertStringList methods are implemeted
+ * yet and also the removeItem methos does not work.
+ */
+class LIBK3B_EXPORT K3bCutComboBox : public KComboBox
+{
+ Q_OBJECT
+
+ public:
+ K3bCutComboBox( QWidget* parent = 0, const char* name = 0 );
+ K3bCutComboBox( int method, QWidget* parent = 0, const char* name = 0 );
+ virtual ~K3bCutComboBox();
+
+ enum Method {
+ CUT,
+ SQUEEZE
+ };
+
+ /**
+ * The method to shorten the text
+ * defaut: CUT
+ */
+ void setMethod( int );
+
+ /** reimplemeted */
+ QSize sizeHint() const;
+
+ /** reimplemeted */
+ QSize minimumSizeHint() const;
+
+ /** reimplemeted */
+ virtual void setCurrentText( const QString& );
+
+ void insertStringList( const QStringList &, int index=-1 );
+ void insertStrList( const QStrList &, int index=-1 );
+ void insertStrList( const QStrList *, int index=-1 );
+ void insertStrList( const char **, int numStrings=-1, int index=-1);
+
+ void insertItem( const QString &text, int index=-1 );
+ void insertItem( const QPixmap &pixmap, int index=-1 );
+ void insertItem( const QPixmap &pixmap, const QString &text, int index=-1 );
+
+ void removeItem( int index );
+
+ void changeItem( const QString &text, int index );
+ void changeItem( const QPixmap &pixmap, const QString &text, int index );
+
+ QString text( int ) const;
+ QString currentText() const;
+
+ void clear();
+
+ protected:
+ void resizeEvent( QResizeEvent* e );
+ void cutText();
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bdevicecombobox.cpp b/libk3b/tools/k3bdevicecombobox.cpp
new file mode 100644
index 0000000..165b59d
--- /dev/null
+++ b/libk3b/tools/k3bdevicecombobox.cpp
@@ -0,0 +1,174 @@
+/*
+ *
+ * $Id: k3bdevicecombobox.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bdevicecombobox.h"
+#include <k3bdevice.h>
+#include <k3bdevicemanager.h>
+#include <k3bcore.h>
+
+#include <klocale.h>
+
+#include <qmap.h>
+#include <qptrvector.h>
+
+
+class K3bDeviceComboBox::Private
+{
+public:
+ QMap<QString, int> deviceIndexMap;
+ QPtrVector<K3bDevice::Device> devices;
+};
+
+
+K3bDeviceComboBox::K3bDeviceComboBox( QWidget* parent, const char* name )
+ : KComboBox( parent, name )
+{
+ d = new Private();
+ connect( this, SIGNAL(activated(int)),
+ this, SLOT(slotActivated(int)) );
+ connect( k3bcore->deviceManager(), SIGNAL(changed(K3bDevice::DeviceManager*)),
+ this, SLOT(slotDeviceManagerChanged(K3bDevice::DeviceManager*)) );
+}
+
+
+K3bDeviceComboBox::~K3bDeviceComboBox()
+{
+ delete d;
+}
+
+K3bDevice::Device* K3bDeviceComboBox::selectedDevice() const
+{
+ if ( count() > 0 )
+ return d->devices[currentItem()];
+ else
+ return 0;
+}
+
+
+void K3bDeviceComboBox::addDevice( K3bDevice::Device* dev )
+{
+ int devIndex = -2;
+ bool addDevice = false;
+ for( int i = 0; i < count(); ++i ) {
+ if( dev->vendor() == d->devices[i]->vendor() &&
+ dev->description() == d->devices[i]->description() ) {
+ addDevice = true;
+ if( devIndex < -1 ) // when devIndex == -1 we already found two devices.
+ devIndex = i;
+ else
+ devIndex = -1; // when there are already two or more equal devices they have already been updated
+ }
+ }
+
+ // update the existing device item
+ if( devIndex >= 0 ) {
+ changeItem( d->devices[devIndex]->vendor() + " " +
+ d->devices[devIndex]->description() +
+ " (" + d->devices[devIndex]->blockDeviceName() + ")",
+ devIndex );
+ d->deviceIndexMap[d->devices[devIndex]->devicename()] = devIndex;
+ }
+
+ // add the new device item
+ if( addDevice )
+ insertItem( dev->vendor() + " " + dev->description() + " (" + dev->blockDeviceName() + ")" );
+ else
+ insertItem( dev->vendor() + " " + dev->description() );
+
+ d->deviceIndexMap[dev->devicename()] = count()-1;
+ d->devices.resize( count() );
+ d->devices.insert(count()-1, dev);
+}
+
+
+void K3bDeviceComboBox::removeDevice( K3bDevice::Device* dev )
+{
+ if( dev ) {
+ if( d->deviceIndexMap.contains(dev->devicename()) ) {
+ // let's make it easy and recreate the whole list
+ K3bDevice::Device* selDev = selectedDevice();
+ QPtrList<K3bDevice::Device> devices;
+ for( unsigned int i = 0; i < d->devices.size(); ++i )
+ devices.append( d->devices[i] );
+
+ clear();
+
+ devices.removeRef( dev );
+
+ addDevices( devices );
+ setSelectedDevice( selDev );
+ }
+ }
+}
+
+
+void K3bDeviceComboBox::addDevices( const QPtrList<K3bDevice::Device>& list )
+{
+ for( QPtrListIterator<K3bDevice::Device> it( list );
+ it.current(); ++it )
+ addDevice( it.current() );
+}
+
+
+void K3bDeviceComboBox::refreshDevices( const QPtrList<K3bDevice::Device>& list )
+{
+ K3bDevice::Device* selDev = selectedDevice();
+ clear();
+ if( !list.containsRef( selDev ) )
+ selDev = 0;
+ addDevices( list );
+ setSelectedDevice( selDev );
+}
+
+
+void K3bDeviceComboBox::setSelectedDevice( K3bDevice::Device* dev )
+{
+ if( dev ) {
+ if( d->deviceIndexMap.contains(dev->devicename()) ) {
+ setCurrentItem( d->deviceIndexMap[dev->devicename()] );
+ emit selectionChanged( dev );
+ }
+ }
+}
+
+
+void K3bDeviceComboBox::clear()
+{
+ d->deviceIndexMap.clear();
+ d->devices.clear();
+ KComboBox::clear();
+}
+
+
+void K3bDeviceComboBox::slotActivated( int i )
+{
+ emit selectionChanged( d->devices[i] );
+}
+
+
+void K3bDeviceComboBox::slotDeviceManagerChanged( K3bDevice::DeviceManager* dm )
+{
+ unsigned int i = 0;
+ while( i < d->devices.size() ) {
+ if( !dm->allDevices().containsRef( d->devices[i] ) ) {
+ removeDevice( d->devices[i] );
+ i = 0;
+ }
+ else
+ ++i;
+ }
+}
+
+#include "k3bdevicecombobox.moc"
diff --git a/libk3b/tools/k3bdevicecombobox.h b/libk3b/tools/k3bdevicecombobox.h
new file mode 100644
index 0000000..5a9cb85
--- /dev/null
+++ b/libk3b/tools/k3bdevicecombobox.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * $Id: k3bdevicecombobox.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_DEVICE_COMBO_BOX_H_
+#define _K3B_DEVICE_COMBO_BOX_H_
+
+#include <kcombobox.h>
+#include "k3b_export.h"
+
+namespace K3bDevice {
+ class Device;
+ class DeviceManager;
+}
+
+
+/**
+ * A combobox to select a K3b device.
+ *
+ * It automatically removes devices that are removed from the system.
+ */
+class LIBK3B_EXPORT K3bDeviceComboBox : public KComboBox
+{
+ Q_OBJECT
+
+ public:
+ K3bDeviceComboBox( QWidget* parent = 0, const char* name = 0 );
+ ~K3bDeviceComboBox();
+
+ K3bDevice::Device* selectedDevice() const;
+
+ signals:
+ void selectionChanged( K3bDevice::Device* );
+
+ public slots:
+ void addDevice( K3bDevice::Device* );
+ void addDevices( const QPtrList<K3bDevice::Device>& );
+ /**
+ * Clears the device combo and tries to keep the current selection
+ */
+ void refreshDevices( const QPtrList<K3bDevice::Device>& );
+ void removeDevice( K3bDevice::Device* );
+ void setSelectedDevice( K3bDevice::Device* );
+ void clear();
+
+ private slots:
+ void slotActivated( int );
+ void slotDeviceManagerChanged( K3bDevice::DeviceManager* dm );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bdevicehandler.cpp b/libk3b/tools/k3bdevicehandler.cpp
new file mode 100644
index 0000000..c77f1e6
--- /dev/null
+++ b/libk3b/tools/k3bdevicehandler.cpp
@@ -0,0 +1,332 @@
+/*
+ *
+ * $Id: k3bdevicehandler.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3bdevicehandler.h"
+#include <k3bprogressinfoevent.h>
+#include <k3bthread.h>
+#include <k3bdevice.h>
+#include <k3bcdtext.h>
+
+
+
+class K3bDevice::DeviceHandler::DeviceHandlerThread : public K3bThread
+{
+public:
+ DeviceHandlerThread()
+ : K3bThread(),
+ dev(0) {
+ }
+
+
+ void run() {
+ success = false;
+ m_bCanceled = false;
+
+ // clear data
+ toc.clear();
+ ngInfo = DiskInfo();
+ cdText.clear();
+ cdTextRaw.resize(0);
+
+ if( dev ) {
+ success = dev->open();
+ if( !m_bCanceled && command & DISKINFO ) {
+ ngInfo = dev->diskInfo();
+ if( !m_bCanceled && !ngInfo.empty() ) {
+ toc = dev->readToc();
+ if( toc.contentType() == AUDIO ||
+ toc.contentType() == MIXED )
+ cdText = dev->readCdText();
+ }
+ }
+
+ if( !m_bCanceled && command & (NG_DISKINFO|
+ DISKSIZE|
+ REMAININGSIZE|
+ NUMSESSIONS) ) {
+ ngInfo = dev->diskInfo();
+ }
+
+ if( !m_bCanceled && command & (TOC|TOCTYPE) ) {
+ toc = dev->readToc();
+ }
+
+ if( !m_bCanceled && command & CD_TEXT ) {
+ cdText = dev->readCdText();
+ success = (success && !cdText.isEmpty());
+ }
+
+ if( !m_bCanceled && command & CD_TEXT_RAW ) {
+ unsigned char* data = 0;
+ unsigned int dataLen = 0;
+ if( dev->readTocPmaAtip( &data, dataLen, 5, false, 0 ) ) {
+ // we need more than the header and a multiple of 18 bytes to have valid CD-TEXT
+ if( dataLen > 4 && dataLen%18 == 4 ) {
+ cdTextRaw.assign( reinterpret_cast<char*>(data), dataLen );
+ }
+ else {
+ kdDebug() << "(K3bDevice::DeviceHandler) invalid CD-TEXT length: " << dataLen << endl;
+ delete [] data;
+ success = false;
+ }
+ }
+ else
+ success = false;
+ }
+
+ if( !m_bCanceled && command & BLOCK )
+ success = (success && dev->block( true ));
+
+ if( !m_bCanceled && command & UNBLOCK )
+ success = (success && dev->block( false ));
+
+ //
+ // It is important that eject is performed before load
+ // since the RELOAD command is a combination of both
+ //
+
+ if( !m_bCanceled && command & EJECT )
+ success = (success && dev->eject());
+
+ if( !m_bCanceled && command & LOAD )
+ success = (success && dev->load());
+
+ if( !m_bCanceled && command & BUFFER_CAPACITY )
+ success = dev->readBufferCapacity( bufferCapacity, availableBufferCapacity );
+
+ dev->close();
+ }
+
+ //
+ // This thread only gets cancelled if a new request was started.
+ // So we don't emit the finished signal for this (old) request.
+ //
+ if( !m_bCanceled )
+ emitFinished(success);
+ }
+
+ void cancel() {
+ m_bCanceled = true;
+ }
+
+
+ bool success;
+ int errorCode;
+ int command;
+ DiskInfo ngInfo;
+ Toc toc;
+ CdText cdText;
+ QByteArray cdTextRaw;
+ long long bufferCapacity;
+ long long availableBufferCapacity;
+ Device* dev;
+
+private:
+ bool m_bCanceled;
+};
+
+
+K3bDevice::DeviceHandler::DeviceHandler( Device* dev, QObject* parent, const char* name )
+ : K3bThreadJob( 0, parent, name ),
+ m_selfDelete(false)
+{
+ m_thread = new DeviceHandlerThread();
+ m_thread->dev = dev;
+ setThread( m_thread );
+}
+
+
+K3bDevice::DeviceHandler::DeviceHandler( QObject* parent, const char* name )
+ : K3bThreadJob( 0, parent, name ),
+ m_selfDelete(false)
+{
+ m_thread = new DeviceHandlerThread();
+ setThread( m_thread );
+}
+
+
+K3bDevice::DeviceHandler::DeviceHandler( int command, Device* dev, const char* name )
+ : K3bThreadJob( 0, 0, name ),
+ m_selfDelete(true)
+{
+ m_thread = new DeviceHandlerThread();
+ setThread( m_thread );
+ m_thread->dev = dev;
+ sendCommand(command);
+}
+
+K3bDevice::DeviceHandler::~DeviceHandler()
+{
+ delete m_thread;
+}
+
+
+int K3bDevice::DeviceHandler::errorCode() const
+{
+ return m_thread->errorCode;
+}
+
+bool K3bDevice::DeviceHandler::success() const
+{
+ return m_thread->success;
+}
+
+
+const K3bDevice::DiskInfo& K3bDevice::DeviceHandler::diskInfo() const
+{
+ return m_thread->ngInfo;
+}
+
+
+const K3bDevice::Toc& K3bDevice::DeviceHandler::toc() const
+{
+ return m_thread->toc;
+}
+
+const K3bDevice::CdText& K3bDevice::DeviceHandler::cdText() const
+{
+ return m_thread->cdText;
+}
+
+
+const QByteArray& K3bDevice::DeviceHandler::cdTextRaw() const
+{
+ return m_thread->cdTextRaw;
+}
+
+
+K3b::Msf K3bDevice::DeviceHandler::diskSize() const
+{
+ return m_thread->ngInfo.capacity();
+}
+
+K3b::Msf K3bDevice::DeviceHandler::remainingSize() const
+{
+ return m_thread->ngInfo.remainingSize();
+}
+
+int K3bDevice::DeviceHandler::tocType() const
+{
+ return m_thread->toc.contentType();
+}
+
+int K3bDevice::DeviceHandler::numSessions() const
+{
+ return m_thread->ngInfo.numSessions();
+}
+
+long long K3bDevice::DeviceHandler::bufferCapacity() const
+{
+ return m_thread->bufferCapacity;
+}
+
+long long K3bDevice::DeviceHandler::availableBufferCapacity() const
+{
+ return m_thread->availableBufferCapacity;
+}
+
+void K3bDevice::DeviceHandler::setDevice( Device* dev )
+{
+ m_thread->dev = dev;
+}
+
+
+
+void K3bDevice::DeviceHandler::sendCommand( int command )
+{
+ //
+ // We do not want the finished signal emitted in case the devicehandler was cancelled. This is a special case.
+ // That's why we do not use K3bThreadJob::start() becasue otherwise we would be registered twice.
+ //
+ if( m_thread->running() ) {
+ kdDebug() << "(K3bDevice::DeviceHandler) thread already running. canceling thread..." << endl;
+ m_thread->cancel();
+ m_thread->wait();
+ }
+ else
+ jobStarted();
+
+ kdDebug() << "(K3bDevice::DeviceHandler) starting command: " << command << endl;
+
+ m_thread->command = command;
+ m_thread->start();
+}
+
+void K3bDevice::DeviceHandler::getToc()
+{
+ sendCommand(DeviceHandler::TOC);
+}
+
+void K3bDevice::DeviceHandler::getDiskInfo()
+{
+ sendCommand(DeviceHandler::DISKINFO);
+}
+
+void K3bDevice::DeviceHandler::getDiskSize()
+{
+ sendCommand(DeviceHandler::DISKSIZE);
+}
+
+void K3bDevice::DeviceHandler::getRemainingSize()
+{
+ sendCommand(DeviceHandler::REMAININGSIZE);
+}
+
+void K3bDevice::DeviceHandler::getTocType()
+{
+ sendCommand(DeviceHandler::TOCTYPE);
+}
+
+void K3bDevice::DeviceHandler::getNumSessions()
+{
+ sendCommand(DeviceHandler::NUMSESSIONS);
+}
+
+
+void K3bDevice::DeviceHandler::block( bool b )
+{
+ sendCommand(b ? DeviceHandler::BLOCK : DeviceHandler::UNBLOCK);
+}
+
+void K3bDevice::DeviceHandler::eject()
+{
+ sendCommand(DeviceHandler::EJECT);
+}
+
+K3bDevice::DeviceHandler* K3bDevice::sendCommand( int command, Device* dev )
+{
+ return new DeviceHandler( command, dev, "DeviceHandler" );
+}
+
+void K3bDevice::DeviceHandler::customEvent( QCustomEvent* e )
+{
+ K3bThreadJob::customEvent(e);
+
+ if( (int)e->type() == K3bProgressInfoEvent::Finished ) {
+ emit finished( this );
+ if( m_selfDelete ) {
+ kdDebug() << "(K3bDevice::DeviceHandler) thread emitted finished. Waiting for thread actually finishing" << endl;
+ kdDebug() << "(K3bDevice::DeviceHandler) success: " << m_thread->success << endl;
+ // wait for the thread to finish
+ m_thread->wait();
+ kdDebug() << "(K3bDevice::DeviceHandler) deleting thread." << endl;
+ deleteLater();
+ }
+ }
+}
+
+
+#include "k3bdevicehandler.moc"
diff --git a/libk3b/tools/k3bdevicehandler.h b/libk3b/tools/k3bdevicehandler.h
new file mode 100644
index 0000000..d5159a0
--- /dev/null
+++ b/libk3b/tools/k3bdevicehandler.h
@@ -0,0 +1,237 @@
+/*
+ *
+ * $Id: k3bdevicehandler.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_DEVICE_HANDLER_H_
+#define _K3B_DEVICE_HANDLER_H_
+
+#include <k3bthreadjob.h>
+#include "k3bdevice.h"
+#include "k3bdiskinfo.h"
+#include "k3bmsf.h"
+#include "k3bcdtext.h"
+#include "k3b_export.h"
+#include <qcstring.h>
+
+class QCustomEvent;
+
+
+namespace K3bDevice
+{
+ class Device;
+
+
+ /**
+ * The K3bDevice::Devicehandler is a threaded wrapper around K3bDevice::Device.
+ * It allows async access to the time comsuming blocking K3bDevice::Device methods.
+ * Since it's a K3bJob it is very easy to handle. Just use one of the methods and
+ * connect to the finished signal.
+ * Be aware that all methods only return valid values if the corresponding info has
+ * been successfuly requested.
+ *
+ * Be aware that multiple requests in a row (without waiting for the job to finish) will
+ * only result in one finished() signal answering the last request.
+ */
+ class LIBK3B_EXPORT DeviceHandler : public K3bThreadJob
+ {
+ Q_OBJECT
+
+ public:
+ DeviceHandler( Device*, QObject* parent = 0, const char* name = 0 );
+ DeviceHandler( QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * This constructor is used by the global "quick" methods and should not be used
+ * otherwise except for the same usage.
+ */
+ DeviceHandler( int command, Device*, const char* name = 0 );
+
+ ~DeviceHandler();
+
+ const DiskInfo& diskInfo() const;
+ const Toc& toc() const;
+ const CdText& cdText() const;
+ const QByteArray& cdTextRaw() const;
+ K3b::Msf diskSize() const;
+ K3b::Msf remainingSize() const;
+ int tocType() const;
+ int numSessions() const;
+ long long bufferCapacity() const;
+ long long availableBufferCapacity() const;
+
+ bool success() const;
+
+ /**
+ * Use this when the command
+ * returnes some error code.
+ */
+ int errorCode() const;
+
+ enum Command {
+ /**
+ * Always successful, even with an empty or no media at all!
+ */
+ NG_DISKINFO = 1, // TODO: rename this into DISKINFO
+ /**
+ * Always successful, even with an empty or no media at all!
+ */
+ TOC = 2,
+ /**
+ * Successful if the media contains CD-Text.
+ */
+ CD_TEXT = 4,
+ /**
+ * Successful if the media contains CD-Text.
+ */
+ CD_TEXT_RAW = 8,
+ /**
+ * Always successful, even with an empty or no media at all!
+ */
+ DISKSIZE = 16,
+ /**
+ * Always successful, even with an empty or no media at all!
+ */
+ REMAININGSIZE = 32,
+ /**
+ * Always successful, even with an empty or no media at all!
+ */
+ TOCTYPE = 64,
+ /**
+ * Always successful, even with an empty or no media at all!
+ */
+ NUMSESSIONS = 128,
+ /**
+ * Successful if the drive could be blocked.
+ */
+ BLOCK = 256,
+ /**
+ * Successful if the drive could be unblocked.
+ */
+ UNBLOCK = 512,
+ /**
+ * Successful if the media was ejected.
+ */
+ EJECT = 1024,
+ /**
+ * Successful if the media was loaded
+ */
+ LOAD = 2048,
+ RELOAD = EJECT|LOAD,
+ /**
+ * Retrieves NG_DISKINFO, TOC, and CD-Text in case of an audio or mixed
+ * mode cd.
+ * The only difference to NG_DISKINFO|TOC|CD_TEXT is that no CD-Text is not
+ * considered an error.
+ *
+ * Always successful, even with an empty or no media at all!
+ */
+ DISKINFO = 4096, // TODO: rename this in somthing like: DISKINFO_COMPLETE
+ /**
+ * Determine the device buffer state.
+ */
+ BUFFER_CAPACITY = 8192
+ };
+
+ signals:
+ void finished( K3bDevice::DeviceHandler* );
+
+ public slots:
+ void setDevice( Device* );
+ void sendCommand( int command );
+
+ void getToc();
+ void getDiskInfo();
+ void getDiskSize();
+ void getRemainingSize();
+ void getTocType();
+ void getNumSessions();
+ void block( bool );
+ void eject();
+
+ protected:
+ /**
+ * reimplemented from K3bThreadJob for internal reasons
+ */
+ virtual void customEvent( QCustomEvent* );
+
+ private:
+ class DeviceHandlerThread;
+ DeviceHandlerThread* m_thread;
+
+ bool m_selfDelete;
+ };
+
+ /**
+ * Usage:
+ * \code
+ * connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::MOUNT, dev ),
+ * SIGNAL(finished(DeviceHandler*)),
+ * this, SLOT(someSlot(DeviceHandler*)) );
+ *
+ * void someSlot( DeviceHandler* dh ) {
+ * if( dh->success() ) {
+ * \endcode
+ *
+ * Be aware that the DeviceHandler will get destroyed once the signal has been
+ * emited.
+ */
+ LIBK3B_EXPORT DeviceHandler* sendCommand( int command, Device* );
+
+ inline DeviceHandler* diskInfo(Device* dev) {
+ return sendCommand(DeviceHandler::DISKINFO,dev);
+ }
+
+ inline DeviceHandler* toc(Device* dev) {
+ return sendCommand(DeviceHandler::TOC,dev);
+ }
+
+ inline DeviceHandler* diskSize(Device* dev) {
+ return sendCommand(DeviceHandler::DISKSIZE,dev);
+ }
+
+ inline DeviceHandler* remainingSize(Device* dev) {
+ return sendCommand(DeviceHandler::REMAININGSIZE,dev);
+ }
+
+ inline DeviceHandler* tocType(Device* dev) {
+ return sendCommand(DeviceHandler::TOCTYPE,dev);
+ }
+
+ inline DeviceHandler* numSessions(Device* dev) {
+ return sendCommand(DeviceHandler::NUMSESSIONS,dev);
+ }
+
+ inline DeviceHandler* block(Device* dev) {
+ return sendCommand(DeviceHandler::BLOCK,dev);
+ }
+
+ inline DeviceHandler* unblock(Device* dev) {
+ return sendCommand(DeviceHandler::UNBLOCK,dev);
+ }
+
+ inline DeviceHandler* eject(Device* dev) {
+ return sendCommand(DeviceHandler::EJECT,dev);
+ }
+
+ inline DeviceHandler* reload(Device* dev) {
+ return sendCommand(DeviceHandler::RELOAD,dev);
+ }
+
+ inline DeviceHandler* load(Device* dev) {
+ return sendCommand(DeviceHandler::LOAD,dev);
+ }
+}
+
+#endif
diff --git a/libk3b/tools/k3bdeviceselectiondialog.cpp b/libk3b/tools/k3bdeviceselectiondialog.cpp
new file mode 100644
index 0000000..d622457
--- /dev/null
+++ b/libk3b/tools/k3bdeviceselectiondialog.cpp
@@ -0,0 +1,130 @@
+/*
+ *
+ * $Id: k3bdeviceselectiondialog.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+
+#include "k3bdeviceselectiondialog.h"
+#include <k3bdevice.h>
+#include <k3bdevicecombobox.h>
+#include <k3bcore.h>
+#include <k3bdevicemanager.h>
+
+#include <qcombobox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qstring.h>
+#include <qframe.h>
+
+#include <klocale.h>
+
+
+class K3bDeviceSelectionDialog::Private
+{
+public:
+ K3bDeviceComboBox* comboDevices;
+};
+
+
+K3bDeviceSelectionDialog::K3bDeviceSelectionDialog( QWidget* parent,
+ const char* name,
+ const QString& text,
+ bool modal )
+ : KDialogBase( KDialogBase::Plain,
+ i18n("Device Selection"),
+ Ok|Cancel,
+ Ok,
+ parent,
+ name,
+ modal )
+{
+ d = new Private();
+
+ QGridLayout* lay = new QGridLayout( plainPage() );
+
+ QLabel* label = new QLabel( text.isEmpty() ? i18n("Please select a device:") : text, plainPage() );
+ d->comboDevices = new K3bDeviceComboBox( plainPage() );
+
+ // lay->setMargin( marginHint() );
+ lay->setSpacing( spacingHint() );
+ lay->addWidget( label, 0, 0 );
+ lay->addWidget( d->comboDevices, 1, 0 );
+ lay->setRowStretch( 2, 1 );
+}
+
+
+K3bDeviceSelectionDialog::~K3bDeviceSelectionDialog()
+{
+ delete d;
+}
+
+
+void K3bDeviceSelectionDialog::addDevice( K3bDevice::Device* dev )
+{
+ d->comboDevices->addDevice( dev );
+}
+
+
+void K3bDeviceSelectionDialog::addDevices( const QPtrList<K3bDevice::Device>& list )
+{
+ d->comboDevices->addDevices( list );
+}
+
+
+K3bDevice::Device* K3bDeviceSelectionDialog::selectedDevice() const
+{
+ return d->comboDevices->selectedDevice();
+}
+
+
+void K3bDeviceSelectionDialog::setSelectedDevice( K3bDevice::Device* dev )
+{
+ d->comboDevices->setSelectedDevice( dev );
+}
+
+
+K3bDevice::Device* K3bDeviceSelectionDialog::selectDevice( QWidget* parent,
+ const QPtrList<K3bDevice::Device>& devices,
+ const QString& text )
+{
+ if( devices.isEmpty() )
+ return 0;
+ if( devices.count() == 1 )
+ return devices.getFirst();
+
+ K3bDeviceSelectionDialog dlg( parent, 0, text );
+ dlg.addDevices( devices );
+
+ if( dlg.exec() == Accepted )
+ return dlg.selectedDevice();
+ else
+ return 0;
+}
+
+K3bDevice::Device* K3bDeviceSelectionDialog::selectDevice( QWidget* parent,
+ const QString& text )
+{
+ return selectDevice( parent, k3bcore->deviceManager()->allDevices(), text );
+
+
+}
+
+
+K3bDevice::Device* K3bDeviceSelectionDialog::selectWriter( QWidget* parent, const QString& text )
+{
+ return selectDevice( parent, k3bcore->deviceManager()->burningDevices(), text );
+}
+
+
+#include "k3bdeviceselectiondialog.moc"
diff --git a/libk3b/tools/k3bdeviceselectiondialog.h b/libk3b/tools/k3bdeviceselectiondialog.h
new file mode 100644
index 0000000..b61ce1e
--- /dev/null
+++ b/libk3b/tools/k3bdeviceselectiondialog.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * $Id: k3bdeviceselectiondialog.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+
+#ifndef K3B_DEVICE_SELECTION_DIALOG_H
+#define K3B_DEVICE_SELECTION_DIALOG_H
+
+
+#include <kdialogbase.h>
+#include "k3b_export.h"
+#include <qptrlist.h>
+
+namespace K3bDevice {
+ class Device;
+}
+
+
+class LIBK3B_EXPORT K3bDeviceSelectionDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ K3bDeviceSelectionDialog( QWidget* parent = 0,
+ const char* name = 0,
+ const QString& text = QString::null,
+ bool modal = false );
+ ~K3bDeviceSelectionDialog();
+
+ void addDevice( K3bDevice::Device* );
+ void addDevices( const QPtrList<K3bDevice::Device>& );
+
+ void setSelectedDevice( K3bDevice::Device* );
+
+ K3bDevice::Device* selectedDevice() const;
+
+ static K3bDevice::Device* selectWriter( QWidget* parent,
+ const QString& text = QString::null );
+ static K3bDevice::Device* selectDevice( QWidget* parent,
+ const QString& text = QString::null );
+ static K3bDevice::Device* selectDevice( QWidget* parent,
+ const QPtrList<K3bDevice::Device>& devices,
+ const QString& text = QString::null );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bdirsizejob.cpp b/libk3b/tools/k3bdirsizejob.cpp
new file mode 100644
index 0000000..ab9cb8a
--- /dev/null
+++ b/libk3b/tools/k3bdirsizejob.cpp
@@ -0,0 +1,184 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bdirsizejob.h"
+
+#include <k3bthread.h>
+#include <k3bthreadjob.h>
+#include <k3bsimplejobhandler.h>
+#include <k3bglobals.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+
+
+class K3bDirSizeJob::WorkThread : public K3bThread
+{
+public:
+ WorkThread()
+ : K3bThread(),
+ followSymlinks(false),
+ totalSize(0),
+ totalFiles(0),
+ totalDirs(0),
+ totalSymlinks(0) {
+ }
+
+ void init() {
+ m_canceled = false;
+
+ totalSize = 0;
+ totalFiles = 0;
+ totalDirs = 0;
+ totalSymlinks = 0;
+ }
+
+ void run() {
+ emitStarted();
+
+ QStringList l;
+ for( KURL::List::const_iterator it = urls.begin();
+ it != urls.end(); ++it ) {
+ const KURL& url = *it;
+
+ if( !url.isLocalFile() ) {
+ kdDebug() << "(K3bDirSizeJob) no remote support." << endl;
+ emitFinished( false );
+ return;
+ }
+
+ l.append( url.path() );
+ }
+
+ emitFinished( countFiles( l, QString() ) );
+ }
+
+ bool countDir( const QString& dir ) {
+ const QString& dot = KGlobal::staticQString( "." );
+ const QString& dotdot = KGlobal::staticQString( ".." );
+ QStringList l = QDir(dir).entryList( QDir::All|QDir::Hidden|QDir::System );
+ l.remove( dot );
+ l.remove( dotdot );
+
+ return countFiles( l, dir );
+ }
+
+
+ bool countFiles( const QStringList& l, const QString& dir ) {
+ for( QStringList::const_iterator it = l.begin();
+ it != l.end(); ++it ) {
+
+ if( m_canceled )
+ return false;
+
+ k3b_struct_stat s;
+ if( k3b_lstat( QFile::encodeName( dir + *it ), &s ) )
+ return false;
+
+ if( S_ISLNK( s.st_mode ) ) {
+ ++totalSymlinks;
+ if( followSymlinks ) {
+ if( k3b_stat( QFile::encodeName( dir + *it ), &s ) )
+ return false;
+ }
+ }
+
+ if( S_ISDIR( s.st_mode ) ) {
+ ++totalDirs;
+ if( !countDir( dir + *it + '/' ) )
+ return false;
+ }
+ else if( !S_ISLNK( s.st_mode ) ) {
+ ++totalFiles;
+ totalSize += (KIO::filesize_t)s.st_size;
+ }
+ }
+
+ return true;
+ }
+
+ void cancel() {
+ m_canceled = true;
+ emitCanceled();
+ wait();
+ }
+
+ KURL::List urls;
+ bool followSymlinks;
+
+ KIO::filesize_t totalSize;
+ KIO::filesize_t totalFiles;
+ KIO::filesize_t totalDirs;
+ KIO::filesize_t totalSymlinks;
+
+private:
+ bool m_canceled;
+};
+
+
+K3bDirSizeJob::K3bDirSizeJob( QObject* parent )
+ : K3bThreadJob( new K3bSimpleJobHandler(), parent )
+{
+ d = new WorkThread;
+ setThread( d );
+}
+
+
+K3bDirSizeJob::~K3bDirSizeJob()
+{
+ delete d;
+ delete jobHandler();
+}
+
+
+KIO::filesize_t K3bDirSizeJob::totalSize() const
+{
+ return d->totalSize;
+}
+
+
+KIO::filesize_t K3bDirSizeJob::totalFiles() const
+{
+ return d->totalFiles;
+}
+
+
+KIO::filesize_t K3bDirSizeJob::totalDirs() const
+{
+ return d->totalDirs;
+}
+
+
+KIO::filesize_t K3bDirSizeJob::totalSymlinks() const
+{
+ return d->totalSymlinks;
+}
+
+
+void K3bDirSizeJob::setUrls( const KURL::List& urls )
+{
+ d->urls = urls;
+}
+
+
+void K3bDirSizeJob::setFollowSymlinks( bool b )
+{
+ d->followSymlinks = b;
+}
+
+#include "k3bdirsizejob.moc"
diff --git a/libk3b/tools/k3bdirsizejob.h b/libk3b/tools/k3bdirsizejob.h
new file mode 100644
index 0000000..d6a3e5a
--- /dev/null
+++ b/libk3b/tools/k3bdirsizejob.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_DIR_SIZE_JOB_H_
+#define _K3B_DIR_SIZE_JOB_H_
+
+#include <k3bthreadjob.h>
+#include <kio/global.h>
+
+#include <k3b_export.h>
+
+/**
+ * K3bDirSizeJob is a replacement for KDirSize which allows
+ * a much finer grained control over what is counted and how.
+ * Additionally it uses threading for enhanced speed.
+ *
+ * For now K3bDirSizeJob only works on local urls.
+ */
+class LIBK3B_EXPORT K3bDirSizeJob : public K3bThreadJob
+{
+ Q_OBJECT
+
+ public:
+ K3bDirSizeJob( QObject* parent = 0 );
+ ~K3bDirSizeJob();
+
+ KIO::filesize_t totalSize() const;
+
+ /**
+ * Does also include symlinks to files, devices, and fifos
+ */
+ KIO::filesize_t totalFiles() const;
+
+ /**
+ * Total number of counted dirs. This does also
+ * include the first dirs the job was started with.
+ * Does also include symlinks to dirs.
+ */
+ KIO::filesize_t totalDirs() const;
+
+ /**
+ * Includes symlinks to files and folders
+ */
+ KIO::filesize_t totalSymlinks() const;
+
+ public slots:
+ void setUrls( const KURL::List& urls );
+ void setFollowSymlinks( bool );
+
+ private:
+ class WorkThread;
+ WorkThread* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bexceptions.cpp b/libk3b/tools/k3bexceptions.cpp
new file mode 100644
index 0000000..1d8806f
--- /dev/null
+++ b/libk3b/tools/k3bexceptions.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * $Id: k3bexceptions.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bexceptions.h"
+#include <k3bdevice.h>
+
+bool K3bExceptions::brokenDaoAudio( K3bDevice::Device* dev )
+{
+ if( dev->vendor().upper().startsWith("PIONEER") )
+ if( dev->description().upper().startsWith("DVR-106D") ||
+ dev->description().upper().startsWith("DVD-RW DVR-K12D") )
+ return true;
+
+ if( dev->vendor().upper().startsWith("HL-DT-ST") )
+ if( dev->description().upper().startsWith("RW/DVD GCC-4320B") ||
+ dev->description().upper().contains("GCE-8520B") )
+ return true;
+
+ if( dev->vendor().upper().startsWith("PHILIPS") &&
+ dev->description().upper().startsWith("CDRWDVD3210") )
+ return true;
+
+ if( dev->vendor().upper().startsWith("LITE-ON") )
+ if( dev->description().upper().startsWith("LTR-32123S") ||
+ dev->description().upper().startsWith("LTR-40125S") ||
+ dev->description().upper().contains("LTC-48161H") ||
+ dev->description().upper().startsWith("DVDRW LDW-811S") )
+ return true;
+
+ return false;
+}
diff --git a/libk3b/tools/k3bexceptions.h b/libk3b/tools/k3bexceptions.h
new file mode 100644
index 0000000..a078992
--- /dev/null
+++ b/libk3b/tools/k3bexceptions.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * $Id: k3bexceptions.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_EXCEPTIONS_H_
+#define _K3B_EXCEPTIONS_H_
+
+namespace K3bDevice {
+ class Device;
+}
+
+class K3bExceptions
+{
+ public:
+ /**
+ * Returns true if the drive's firmware produces broken
+ * Audio CDs with zero length pregaps.
+ *
+ * It simply uses a compiled in table.
+ */
+ static bool brokenDaoAudio( K3bDevice::Device* );
+};
+
+#endif
diff --git a/libk3b/tools/k3bfilesplitter.cpp b/libk3b/tools/k3bfilesplitter.cpp
new file mode 100644
index 0000000..af5b83f
--- /dev/null
+++ b/libk3b/tools/k3bfilesplitter.cpp
@@ -0,0 +1,307 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bfilesplitter.h"
+#include "k3bfilesysteminfo.h"
+
+#include <kdebug.h>
+
+#include <qfile.h>
+
+
+class K3bFileSplitter::Private
+{
+public:
+ Private( K3bFileSplitter* splitter )
+ : m_splitter( splitter ) {
+ }
+
+ QString filename;
+ QFile file;
+ int counter;
+
+ // QIODevice::Offset is too small on most compilations
+ KIO::filesize_t maxFileSize;
+
+ KIO::filesize_t currentOverallPos;
+ KIO::filesize_t currentFilePos;
+
+ void determineMaxFileSize() {
+ if( maxFileSize == 0 ) {
+ if( K3bFileSystemInfo( filename ).type() == K3bFileSystemInfo::FS_FAT )
+ maxFileSize = 1024ULL*1024ULL*1024ULL; // 1GB
+ else
+ maxFileSize = 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL; // incredibly big, 1024 TB
+ }
+ }
+
+ QString buildFileName( int counter ) {
+ if( counter > 0 )
+ return filename + '.' + QString::number(counter).rightJustify( 3, '0' );
+ else
+ return filename;
+ }
+
+ QString currentFileName() {
+ return buildFileName( counter );
+ }
+
+ bool openPrevFile() {
+ return openFile( --counter );
+ }
+
+ bool openNextFile() {
+ return openFile( ++counter );
+ }
+
+ bool openFile( int counter ) {
+ file.close();
+ file.setName( buildFileName( counter ) );
+ currentFilePos = 0;
+ if( file.open( m_splitter->mode() ) ) {
+ m_splitter->setState( IO_Open );
+ return true;
+ }
+ else {
+ m_splitter->setState( ~IO_Open );
+ return false;
+ }
+ }
+
+private:
+ K3bFileSplitter* m_splitter;
+};
+
+
+K3bFileSplitter::K3bFileSplitter()
+{
+ d = new Private( this );
+}
+
+
+K3bFileSplitter::K3bFileSplitter( const QString& filename )
+{
+ d = new Private( this );
+ setName( filename );
+}
+
+
+K3bFileSplitter::~K3bFileSplitter()
+{
+ delete d;
+}
+
+
+const QString& K3bFileSplitter::name() const
+{
+ return d->filename;
+}
+
+
+void K3bFileSplitter::setName( const QString& filename )
+{
+ close();
+ d->maxFileSize = 0;
+ d->filename = filename;
+}
+
+
+bool K3bFileSplitter::open( int mode )
+{
+ close();
+
+ d->determineMaxFileSize();
+
+ d->counter = 0;
+ d->currentFilePos = 0;
+ d->currentOverallPos = 0;
+ setMode( mode );
+
+ return d->openFile( 0 );
+}
+
+
+void K3bFileSplitter::close()
+{
+ d->file.close();
+ d->counter = 0;
+ d->currentFilePos = 0;
+ d->currentOverallPos = 0;
+}
+
+
+int K3bFileSplitter::handle() const
+{
+ // FIXME: use a K3bPipe to simulate this
+ return -1;
+}
+
+
+
+void K3bFileSplitter::flush()
+{
+ d->file.flush();
+}
+
+
+QIODevice::Offset K3bFileSplitter::size() const
+{
+ // not implemented due to Offset size limitations
+ return 0;
+}
+
+
+QIODevice::Offset K3bFileSplitter::at() const
+{
+ return d->currentOverallPos;
+}
+
+
+bool K3bFileSplitter::at( QIODevice::Offset pos )
+{
+ Q_UNUSED( pos );
+ // not implemented due to Offset size limitations
+ return false;
+}
+
+
+bool K3bFileSplitter::atEnd() const
+{
+ return d->file.atEnd() && !QFile::exists( d->buildFileName( d->counter+1 ) );
+}
+
+
+Q_LONG K3bFileSplitter::readBlock( char *data, Q_ULONG maxlen )
+{
+ Q_LONG r = d->file.readBlock( data, maxlen );
+ if( r == 0 ) {
+ if( atEnd() ) {
+ return r;
+ }
+ else if( d->openNextFile() ) {
+ // recursively call us
+ return readBlock( data, maxlen );
+ }
+ }
+ else if( r > 0 ) {
+ d->currentOverallPos += r;
+ d->currentFilePos += r;
+ }
+
+ return r;
+}
+
+
+Q_LONG K3bFileSplitter::writeBlock( const char *data, Q_ULONG len )
+{
+ // We cannot rely on QFile::at since it uses long on most copmpilations
+ Q_ULONG max = (Q_ULONG)QMIN( (KIO::filesize_t)len, d->maxFileSize - d->currentFilePos );
+
+ Q_LONG r = d->file.writeBlock( data, max );
+
+ if( r < 0 )
+ return r;
+
+ d->currentOverallPos += r;
+ d->currentFilePos += r;
+
+ // recursively call us
+ if( (Q_ULONG)r < len ) {
+ if( d->openNextFile() )
+ return r + writeBlock( data+r, len-r );
+ else
+ return -1;
+ }
+ else
+ return r;
+}
+
+
+int K3bFileSplitter::getch()
+{
+ int r = d->file.getch();
+ if( r == -1 ) {
+ if( !d->file.atEnd() ) {
+ return -1;
+ }
+ else if( !atEnd() ) {
+ if( !d->openNextFile() )
+ return -1;
+ else
+ return getch();
+ }
+ }
+
+ d->currentOverallPos++;
+ d->currentFilePos++;
+
+ return r;
+}
+
+
+int K3bFileSplitter::putch( int c )
+{
+ if( d->currentFilePos < d->maxFileSize ) {
+ d->currentOverallPos++;
+ d->currentFilePos++;
+ return d->file.putch( c );
+ }
+ else if( d->openNextFile() ) {
+ // recursively call us
+ return putch( c );
+ }
+ else
+ return -1;
+}
+
+
+int K3bFileSplitter::ungetch( int c )
+{
+ if( d->currentFilePos > 0 ) {
+ int r = d->file.ungetch( c );
+ if( r != -1 ) {
+ d->currentOverallPos--;
+ d->currentFilePos--;
+ }
+ return r;
+ }
+ else if( d->counter > 0 ) {
+ // open prev file
+ if( d->openPrevFile() ) {
+ // seek to the end
+ d->file.at( d->file.size() );
+ d->currentFilePos = d->file.at();
+ return getch();
+ }
+ else
+ return -1;
+ }
+ else
+ return -1;
+}
+
+
+void K3bFileSplitter::remove()
+{
+ close();
+ while( QFile::exists( d->buildFileName( d->counter ) ) )
+ QFile::remove( d->buildFileName( d->counter++ ) );
+}
+
+
+void K3bFileSplitter::setMaxFileSize( KIO::filesize_t size )
+{
+ d->maxFileSize = size;
+}
diff --git a/libk3b/tools/k3bfilesplitter.h b/libk3b/tools/k3bfilesplitter.h
new file mode 100644
index 0000000..22dcad9
--- /dev/null
+++ b/libk3b/tools/k3bfilesplitter.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_FILE_SPLITTER_H_
+#define _K3B_FILE_SPLITTER_H_
+
+#include <qiodevice.h>
+#include <qstring.h>
+
+#include <kio/global.h>
+
+#include <k3b_export.h>
+
+
+/**
+ * QFile replacement which splits
+ * big files according to the underlying file system's
+ * maximum file size.
+ *
+ * The filename will be changed to include a counter
+ * if the file has to be splitted like so:
+ *
+ * <pre>
+ * filename.iso
+ * filename.iso.001
+ * filename.iso.002
+ * ...
+ * </pre>
+ */
+class LIBK3B_EXPORT K3bFileSplitter : public QIODevice
+{
+ public:
+ K3bFileSplitter();
+ K3bFileSplitter( const QString& filename );
+ ~K3bFileSplitter();
+
+ /**
+ * Set the maximum file size. If this is set to 0
+ * (the default) the max filesize is determined based on
+ * the filesystem type.
+ *
+ * Be aware that setName will reset the max file size.
+ */
+ void setMaxFileSize( KIO::filesize_t size );
+
+ const QString& name() const;
+
+ void setName( const QString& filename );
+
+ virtual bool open( int mode );
+
+ virtual void close();
+
+ /**
+ * File descriptor to read from and write to.
+ * Not implemented yet!
+ */
+ int handle() const;
+
+ virtual void flush();
+
+ /**
+ * Not implemented
+ */
+ virtual Offset size() const;
+
+ /**
+ * Not implemented
+ */
+ virtual Offset at() const;
+
+ /**
+ * Not implemented
+ */
+ virtual bool at( Offset );
+
+ virtual bool atEnd() const;
+ virtual Q_LONG readBlock( char *data, Q_ULONG maxlen );
+ virtual Q_LONG writeBlock( const char *data, Q_ULONG len );
+ virtual int getch();
+ virtual int putch( int );
+ virtual int ungetch( int );
+
+ /**
+ * Deletes all the splitted files.
+ * Caution: Does remove all files that fit the naming scheme without any
+ * additional checks.
+ */
+ void remove();
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bfilesysteminfo.cpp b/libk3b/tools/k3bfilesysteminfo.cpp
new file mode 100644
index 0000000..fe1eaf8
--- /dev/null
+++ b/libk3b/tools/k3bfilesysteminfo.cpp
@@ -0,0 +1,141 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <config.h>
+
+#include "k3bfilesysteminfo.h"
+
+#include <k3bglobals.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#ifdef Q_OS_FREEBSD
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h>
+# if defined(Q_OS_NETBSD)
+# include <sys/param.h>
+# if __NetBSD_Version__ > 299000000
+# define statfs statvfs
+# define f_type f_fsid
+# endif
+# endif
+#endif
+#ifdef HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+
+
+class K3bFileSystemInfo::Private
+{
+public:
+ Private()
+ : type(FS_UNKNOWN),
+ statDone(false) {
+ }
+
+ FileSystemType type;
+ QString path;
+
+ bool statDone;
+
+ void stat() {
+ struct statfs fs;
+ if( !::statfs( QFile::encodeName( QFileInfo(path).dirPath( true ) ), &fs ) ) {
+ switch( fs.f_type ) {
+ case 0x4d44: // MS-DOS
+ type = FS_FAT;
+ default:
+ type = FS_UNKNOWN;
+ }
+
+ statDone = true;
+ }
+ else {
+ kdDebug() << "(K3bFileSystemInfo) statfs failed: " << ::strerror(errno) << endl;
+ }
+ }
+};
+
+
+K3bFileSystemInfo::K3bFileSystemInfo()
+{
+ d = new Private;
+}
+
+
+K3bFileSystemInfo::K3bFileSystemInfo( const QString& path )
+{
+ d = new Private;
+ d->path = path;
+}
+
+
+K3bFileSystemInfo::K3bFileSystemInfo( const K3bFileSystemInfo& other )
+{
+ d = new Private;
+ d->type = other.d->type;
+ d->path = other.d->path;
+ d->statDone = other.d->statDone;
+}
+
+
+K3bFileSystemInfo::~K3bFileSystemInfo()
+{
+ delete d;
+}
+
+
+QString K3bFileSystemInfo::path() const
+{
+ return d->path;
+}
+
+
+void K3bFileSystemInfo::setPath( const QString& path )
+{
+ if( d->path != path ) {
+ d->path = path;
+ d->statDone = false;
+ }
+}
+
+
+K3bFileSystemInfo::FileSystemType K3bFileSystemInfo::type() const
+{
+ if( !d->statDone )
+ d->stat();
+ return d->type;
+}
+
+
+QString K3bFileSystemInfo::fixupPath( const QString& path )
+{
+ QString s = K3b::fixupPath( path );
+ if( type() == K3bFileSystemInfo::FS_FAT )
+ return s.replace( QRegExp("[\"\\?\\*/\\\\[\\]\\|\\=\\:;]"), "_" );
+ else
+ return s;
+}
diff --git a/libk3b/tools/k3bfilesysteminfo.h b/libk3b/tools/k3bfilesysteminfo.h
new file mode 100644
index 0000000..be9995c
--- /dev/null
+++ b/libk3b/tools/k3bfilesysteminfo.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_FILE_SYSTEM_INFO_H_
+#define _K3B_FILE_SYSTEM_INFO_H_
+
+#include <k3b_export.h>
+
+#include <qstring.h>
+
+class LIBK3B_EXPORT K3bFileSystemInfo
+{
+ public:
+ K3bFileSystemInfo();
+ K3bFileSystemInfo( const QString& path );
+ K3bFileSystemInfo( const K3bFileSystemInfo& );
+ ~K3bFileSystemInfo();
+
+ QString path() const;
+ void setPath( const QString& path );
+
+ enum FileSystemType {
+ FS_UNKNOWN,
+ FS_FAT
+ // FIXME: add way more file system types
+ };
+
+ FileSystemType type() const;
+
+ /**
+ * Ensures that the file path does not contain
+ * any invalid chars.
+ *
+ * For now it only replaces characters like * or [
+ * on FAT file systems.
+ */
+ QString fixupPath( const QString& );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bintmapcombobox.cpp b/libk3b/tools/k3bintmapcombobox.cpp
new file mode 100644
index 0000000..19ac649
--- /dev/null
+++ b/libk3b/tools/k3bintmapcombobox.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * $Id: k3bwritingmodewidget.cpp 554512 2006-06-24 07:25:39Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bintmapcombobox.h"
+
+#include <qwhatsthis.h>
+#include <qmap.h>
+#include <qvaluevector.h>
+
+
+class K3bIntMapComboBox::Private
+{
+public:
+ QMap<int, int> valueIndexMap;
+ QMap<int, QPair<int, QString> > indexValueDescriptionMap;
+
+ QString topWhatsThis;
+ QString bottomWhatsThis;
+};
+
+
+K3bIntMapComboBox::K3bIntMapComboBox( QWidget* parent, const char* name )
+ : KComboBox( parent, name )
+{
+ d = new Private;
+ connect( this, SIGNAL(highlighted(int)),
+ this, SLOT(slotItemHighlighted(int)) );
+ connect( this, SIGNAL(activated(int)),
+ this, SLOT(slotItemActivated(int)) );
+}
+
+
+K3bIntMapComboBox::~K3bIntMapComboBox()
+{
+ delete d;
+}
+
+
+int K3bIntMapComboBox::selectedValue() const
+{
+ if( (int)d->indexValueDescriptionMap.count() > KComboBox::currentItem() )
+ return d->indexValueDescriptionMap[KComboBox::currentItem()].first;
+ else
+ return 0;
+}
+
+
+void K3bIntMapComboBox::setSelectedValue( int value )
+{
+ if( d->valueIndexMap.contains( value ) )
+ KComboBox::setCurrentItem( d->valueIndexMap[value] );
+}
+
+
+void K3bIntMapComboBox::clear()
+{
+ d->valueIndexMap.clear();
+ d->indexValueDescriptionMap.clear();
+
+ KComboBox::clear();
+}
+
+
+bool K3bIntMapComboBox::insertItem( int value, const QString& text, const QString& description, int index )
+{
+ if( d->valueIndexMap.contains( value ) )
+ return false;
+
+ // FIXME: allow inserition at any index
+ index = KComboBox::count();
+
+ d->valueIndexMap[value] = index;
+ d->indexValueDescriptionMap[index] = qMakePair<int, QString>( value, description );
+
+ KComboBox::insertItem( text );
+
+ updateWhatsThis();
+
+ return true;
+}
+
+
+void K3bIntMapComboBox::updateWhatsThis()
+{
+ QString ws( d->topWhatsThis );
+ for( unsigned int i = 0; i < d->indexValueDescriptionMap.count(); ++i ) {
+ ws += "<p><b>" + KComboBox::text( i ) + "</b><br>";
+ ws += d->indexValueDescriptionMap[i].second;
+ }
+ ws += "<p>" + d->bottomWhatsThis;
+
+ QWhatsThis::add( this, ws );
+}
+
+
+void K3bIntMapComboBox::slotItemHighlighted( int index )
+{
+ emit valueHighlighted( d->indexValueDescriptionMap[index].first );
+}
+
+
+void K3bIntMapComboBox::slotItemActivated( int index )
+{
+ emit valueChanged( d->indexValueDescriptionMap[index].first );
+}
+
+
+void K3bIntMapComboBox::addGlobalWhatsThisText( const QString& top, const QString& bottom )
+{
+ d->topWhatsThis = top;
+ d->bottomWhatsThis = bottom;
+ updateWhatsThis();
+}
+
+#include "k3bintmapcombobox.moc"
diff --git a/libk3b/tools/k3bintmapcombobox.h b/libk3b/tools/k3bintmapcombobox.h
new file mode 100644
index 0000000..b0ae717
--- /dev/null
+++ b/libk3b/tools/k3bintmapcombobox.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * $Id: k3bwritingmodewidget.cpp 554512 2006-06-24 07:25:39Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_INT_MAP_COMBOBOX_H_
+#define _K3B_INT_MAP_COMBOBOX_H_
+
+#include <kcombobox.h>
+
+#include "k3b_export.h"
+
+/**
+ * The K3bIntMapComboBox allows a simple selection of integer
+ * values.
+ *
+ * The K3bIntMapComboBox will create a WhatsThis help automatically from
+ * the description texts (if all are set). The ToolTip has to be set manually.
+ */
+class LIBK3B_EXPORT K3bIntMapComboBox : public KComboBox
+{
+ Q_OBJECT
+
+ public:
+ K3bIntMapComboBox( QWidget* parent = 0, const char* name = 0 );
+ ~K3bIntMapComboBox();
+
+ int selectedValue() const;
+
+ signals:
+ /**
+ * Emitted if the selected value changes by user interaction.
+ */
+ void valueChanged( int );
+
+ /**
+ * Emitted if the current highlighted value changed by user interaction.
+ */
+ void valueHighlighted( int );
+
+ public slots:
+ /**
+ * If \a v has not been added via insertItem the selection will not be changed
+ */
+ void setSelectedValue( int v );
+
+ void clear();
+
+ /**
+ * Insert a new item
+ * \param value The integer value to insert
+ * \param text The text to be displayed in the combobox
+ * \param description The text to be used to describe the item in the whatsthis help
+ * \param index The position where to inserts the item. The item will be appended if index is negative.
+ *
+ * \return true if the item could be inserted. False if the value had already been inserted.
+ */
+ bool insertItem( int value, const QString& text, const QString& description, int index = -1 );
+
+ void addGlobalWhatsThisText( const QString& top, const QString& bottom );
+
+ private slots:
+ void slotItemActivated( int );
+ void slotItemHighlighted( int );
+
+ private:
+ void updateWhatsThis();
+
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bintvalidator.cpp b/libk3b/tools/k3bintvalidator.cpp
new file mode 100644
index 0000000..dabf719
--- /dev/null
+++ b/libk3b/tools/k3bintvalidator.cpp
@@ -0,0 +1,137 @@
+/*
+ *
+ * $Id: k3bintvalidator.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include <qwidget.h>
+#include <qstring.h>
+
+#include "k3bintvalidator.h"
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+
+
+K3bIntValidator::K3bIntValidator ( QWidget * parent, const char * name )
+ : QValidator(parent, name)
+{
+ m_min = m_max = 0;
+}
+
+
+K3bIntValidator::K3bIntValidator ( int bottom, int top, QWidget * parent, const char * name )
+ : QValidator(parent, name)
+{
+ m_min = bottom;
+ m_max = top;
+}
+
+
+K3bIntValidator::~K3bIntValidator ()
+{
+}
+
+
+QValidator::State K3bIntValidator::validate ( QString &str, int & ) const
+{
+ bool ok;
+ int val = 0;
+ QString newStr;
+
+ newStr = str.stripWhiteSpace();
+ newStr = newStr.upper();
+
+ if( newStr.length() ) {
+ // check for < 0
+ bool minus = newStr.startsWith( "-" );
+ if( minus )
+ newStr.remove( 0, 1 );
+
+ // check for hex
+ bool hex = newStr.startsWith( "0X" );
+
+ if( hex )
+ newStr.remove( 0, 2 );
+
+ // a special case
+ if( newStr.isEmpty() ) {
+ if( minus && m_min && m_min >= 0)
+ ok = false;
+ else
+ return QValidator::Acceptable;
+ }
+
+ val = newStr.toInt( &ok, hex ? 16 : 10 );
+ if( minus )
+ val *= -1;
+ }
+ else {
+ val = 0;
+ ok = true;
+ }
+
+ if( !ok )
+ return QValidator::Invalid;
+
+ if( m_min && val > 0 && val < m_min )
+ return QValidator::Acceptable;
+
+ if( m_max && val < 0 && val > m_max )
+ return QValidator::Acceptable;
+
+ if( (m_max && val > m_max) || (m_min && val < m_min) )
+ return QValidator::Invalid;
+
+ return QValidator::Valid;
+}
+
+
+void K3bIntValidator::fixup ( QString& ) const
+{
+ // TODO: remove preceding zeros
+}
+
+
+void K3bIntValidator::setRange ( int bottom, int top )
+{
+ m_min = bottom;
+ m_max = top;
+
+ if( m_max < m_min )
+ m_max = m_min;
+}
+
+
+int K3bIntValidator::bottom () const
+{
+ return m_min;
+}
+
+
+int K3bIntValidator::top () const
+{
+ return m_max;
+}
+
+
+int K3bIntValidator::toInt( const QString& s, bool* ok )
+{
+ if( s.lower().startsWith( "0x" ) )
+ return s.right( s.length()-2 ).toInt( ok, 16 );
+ else if( s.lower().startsWith( "-0x" ) )
+ return -1 * s.right( s.length()-3 ).toInt( ok, 16 );
+ else
+ return s.toInt( ok, 10 );
+}
diff --git a/libk3b/tools/k3bintvalidator.h b/libk3b/tools/k3bintvalidator.h
new file mode 100644
index 0000000..551d56a
--- /dev/null
+++ b/libk3b/tools/k3bintvalidator.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * $Id: k3bintvalidator.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_INT_VALIDATOR_H_
+#define _K3B_INT_VALIDATOR_H_
+
+#include <qvalidator.h>
+#include "k3b_export.h"
+class QWidget;
+class QString;
+
+/**
+ * QValidator for integers.
+ *
+ * It differs from QIntValidator and KIntValidator in the fact that
+ * it also accepts hex numbers prefixed with 0x.
+ */
+class LIBK3B_EXPORT K3bIntValidator : public QValidator
+{
+ public:
+ /**
+ * Constuctor. Also sets the base value.
+ */
+ K3bIntValidator ( QWidget * parent, const char * name = 0 );
+
+ /**
+ * Constructor. Also sets the minimum, maximum, and numeric base values.
+ */
+ K3bIntValidator ( int bottom, int top, QWidget * parent, const char * name = 0 );
+
+ /**
+ * Destructs the validator.
+ */
+ virtual ~K3bIntValidator ();
+
+ /**
+ * Validates the text, and return the result. Does not modify the parameters.
+ */
+ virtual State validate ( QString &, int & ) const;
+
+ /**
+ * Fixes the text if possible, providing a valid string. The parameter may be modified.
+ */
+ virtual void fixup ( QString & ) const;
+
+ /**
+ * Sets the minimum and maximum values allowed.
+ */
+ virtual void setRange ( int bottom, int top );
+
+ /**
+ * Returns the current minimum value allowed.
+ */
+ virtual int bottom () const;
+
+ /**
+ * Returns the current maximum value allowed.
+ */
+ virtual int top () const;
+
+ /**
+ * If the string starts with 0x it's assumed to be a hex number.
+ */
+ static int toInt( const QString&, bool* ok = 0 );
+
+ private:
+ int m_min;
+ int m_max;
+};
+
+#endif
diff --git a/libk3b/tools/k3biso9660.cpp b/libk3b/tools/k3biso9660.cpp
new file mode 100644
index 0000000..84edc4b
--- /dev/null
+++ b/libk3b/tools/k3biso9660.cpp
@@ -0,0 +1,899 @@
+/*
+ *
+ * $Id: k3biso9660.cpp 690529 2007-07-21 10:51:47Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <config.h>
+#include <k3bglobals.h>
+
+#include "k3biso9660.h"
+#include "k3biso9660backend.h"
+
+#include <k3bdevice.h>
+
+#include "libisofs/isofs.h"
+
+#include <qcstring.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qptrlist.h>
+
+#include <kdebug.h>
+
+
+/* callback function for libisofs */
+int K3bIso9660::read_callback( char* buf, sector_t start, int len, void* udata )
+{
+ K3bIso9660* isoF = static_cast<K3bIso9660*>(udata);
+
+ return isoF->read( start, buf, len );
+}
+
+/* callback function for libisofs */
+int K3bIso9660::isofs_callback( struct iso_directory_record *idr, void *udata )
+{
+ K3bIso9660 *iso = static_cast<K3bIso9660*> (udata);
+ QString path, isoPath,user,group,symlink;
+ int i;
+ int access;
+ int time,cdate,adate;
+ rr_entry rr;
+ bool special=false;
+ K3bIso9660Entry *entry=0;
+ //K3bIso9660Entry *oldentry=0;
+ char z_algo[2],z_params[2];
+ int z_size=0;
+
+ if (isonum_711(idr->name_len)==1) {
+ switch (idr->name[0]) {
+ case 0:
+ path+=(".");
+ special=true;
+ break;
+ case 1:
+ path+=("..");
+ special=true;
+ break;
+ }
+ }
+ //
+ // First extract the raw iso9660 name
+ //
+ if( !special ) {
+ for( i = 0; i < isonum_711( idr->name_len ); i++ ) {
+ if( idr->name[i] )
+ isoPath += idr->name[i];
+ }
+ }
+ else
+ isoPath = path;
+
+ //
+ // Now see if we have RockRidge
+ //
+ if( !iso->plainIso9660() && ParseRR(idr,&rr) > 0 ) {
+ iso->m_rr = true;
+ if (!special)
+ path = QString::fromLocal8Bit( rr.name );
+ symlink=rr.sl;
+ access=rr.mode;
+ time=0;//rr.st_mtime;
+ adate=0;//rr.st_atime;
+ cdate=0;//rr.st_ctime;
+ user.setNum(rr.uid);
+ group.setNum(rr.gid);
+ z_algo[0]=rr.z_algo[0];z_algo[1]=rr.z_algo[1];
+ z_params[0]=rr.z_params[0];z_params[1]=rr.z_params[1];
+ z_size=rr.z_size;
+ }
+ else {
+ access=iso->dirent->permissions() & ~S_IFMT;
+ adate=cdate=time=isodate_915(idr->date,0);
+ user=iso->dirent->user();
+ group=iso->dirent->group();
+ if (idr->flags[0] & 2) access |= S_IFDIR; else access |= S_IFREG;
+ if (!special) {
+ if( !iso->plainIso9660() && iso->jolietLevel() ) {
+ for (i=0;i<(isonum_711(idr->name_len)-1);i+=2) {
+ QChar ch( be2me_16(*((ushort*)&(idr->name[i]))) );
+ if (ch==';') break;
+ path+=ch;
+ }
+ }
+ else {
+ // no RR, no Joliet, just plain iso9660
+ path = isoPath;
+
+ // remove the version field
+ int pos = path.find( ';' );
+ if( pos > 0 )
+ path.truncate( pos );
+ }
+ if (path.endsWith(".")) path.setLength(path.length()-1);
+ }
+ }
+
+ if( !iso->plainIso9660() )
+ FreeRR(&rr);
+
+ if (idr->flags[0] & 2) {
+ entry = new K3bIso9660Directory( iso, isoPath, path, access | S_IFDIR, time, adate, cdate,
+ user, group, symlink,
+ special ? 0 : isonum_733(idr->extent),
+ special ? 0 : isonum_733(idr->size) );
+ }
+ else {
+ entry = new K3bIso9660File( iso, isoPath, path, access, time, adate, cdate,
+ user, group, symlink, isonum_733(idr->extent), isonum_733(idr->size) );
+ if (z_size)
+ (static_cast<K3bIso9660File*>(entry))->setZF( z_algo, z_params, z_size );
+ }
+ iso->dirent->addEntry(entry);
+
+ return 0;
+}
+
+
+
+K3bIso9660Entry::K3bIso9660Entry( K3bIso9660* archive,
+ const QString& isoName,
+ const QString& name,
+ int access,
+ int date,
+ int adate,
+ int cdate,
+ const QString& user,
+ const QString& group,
+ const QString& symlink )
+ : m_adate( adate ),
+ m_cdate( cdate ),
+ m_name( name ),
+ m_isoName( isoName ),
+ m_date( date ),
+ m_access( access ),
+ m_user( user ),
+ m_group( group ),
+ m_symlink( symlink ),
+ m_archive( archive )
+{
+}
+
+
+K3bIso9660Entry::~K3bIso9660Entry()
+{
+}
+
+
+
+
+
+
+K3bIso9660File::K3bIso9660File( K3bIso9660* archive,
+ const QString& isoName,
+ const QString& name,
+ int access,
+ int date,
+ int adate,
+ int cdate,
+ const QString& user,
+ const QString& group,
+ const QString& symlink,
+ unsigned int pos,
+ unsigned int size )
+ : K3bIso9660Entry( archive, isoName, name, access, date, adate, cdate, user, group, symlink ),
+ m_startSector(pos),
+ m_size(size)
+{
+ m_algo[0] = 0;
+ m_algo[1] = 0;
+ m_parms[0] = 0;
+ m_parms[1] = 0;
+ m_realsize = 0;
+}
+
+K3bIso9660File::~K3bIso9660File()
+{
+}
+
+void K3bIso9660File::setZF(char algo[2],char parms[2],int realsize)
+{
+ m_algo[0]=algo[0];m_algo[1]=algo[1];
+ m_parms[0]=parms[0];m_parms[1]=parms[1];
+ m_realsize=realsize;
+}
+
+
+int K3bIso9660File::read( unsigned int pos, char* data, int maxlen ) const
+{
+ if( pos >= size() )
+ return 0;
+
+ unsigned long startSec = m_startSector + pos/2048;
+ int startSecOffset = pos%2048;
+ char* buffer = data;
+ bool buffered = false;
+ unsigned long bufferLen = maxlen+startSecOffset;
+
+ // cut to size
+ if( pos + maxlen > size() )
+ bufferLen = size() - pos + startSecOffset;
+
+ // pad to 2048
+ if( bufferLen%2048 )
+ bufferLen += (2048-(bufferLen%2048));
+
+ // we need to buffer if we changed the startSec or need a bigger buffer
+ if( startSecOffset || bufferLen > (unsigned int)maxlen ) {
+ buffered = true;
+ buffer = new char[bufferLen];
+ }
+
+ int read = archive()->read( startSec, buffer, bufferLen/2048 )*2048;
+
+ if( buffered ) {
+ if( read > 0 ) {
+ // cut to requested data
+ read -= startSecOffset;
+ if( read + pos > size() )
+ read = size() - pos;
+ if( read > maxlen )
+ read = maxlen;
+
+ ::memcpy( data, buffer+startSecOffset, read );
+ }
+ delete [] buffer;
+
+ return read;
+ }
+ else {
+ // cut read data
+ if( read + pos > size() )
+ read = size() - pos;
+
+ return read;
+ }
+}
+
+
+bool K3bIso9660File::copyTo( const QString& url ) const
+{
+ QFile of( url );
+ if( of.open( IO_WriteOnly ) ) {
+ char buffer[2048*10];
+ unsigned int pos = 0;
+ int r = 0;
+ while( ( r = read( pos, buffer, 2048*10 ) ) > 0 ) {
+ of.writeBlock( buffer, r );
+ pos += r;
+ }
+
+ return !r;
+ }
+ else {
+ kdDebug() << "(K3bIso9660File) could not open " << url << " for writing." << endl;
+ return false;
+ }
+}
+
+
+K3bIso9660Directory::K3bIso9660Directory( K3bIso9660* archive,
+ const QString& isoName,
+ const QString& name,
+ int access,
+ int date,
+ int adate,
+ int cdate,
+ const QString& user,
+ const QString& group,
+ const QString& symlink,
+ unsigned int pos,
+ unsigned int size )
+ : K3bIso9660Entry( archive, isoName, name, access, date, adate, cdate, user, group, symlink ),
+ m_bExpanded( size == 0 ), // we can only expand entries that represent an actual directory
+ m_startSector(pos),
+ m_size(size)
+{
+ m_entries.setAutoDelete( true );
+}
+
+K3bIso9660Directory::~K3bIso9660Directory()
+{
+}
+
+
+void K3bIso9660Directory::expand()
+{
+ if( !m_bExpanded ) {
+ archive()->dirent = this;
+ if( ProcessDir( &K3bIso9660::read_callback, m_startSector, m_size, &K3bIso9660::isofs_callback, archive() ) )
+ kdDebug() << "(K3bIso9660) failed to expand dir: " << name() << " with size: " << m_size << endl;
+
+ m_bExpanded = true;
+ }
+}
+
+
+QStringList K3bIso9660Directory::entries() const
+{
+ // create a fake const method to fool the user ;)
+ const_cast<K3bIso9660Directory*>(this)->expand();
+
+ QStringList l;
+
+ QDictIterator<K3bIso9660Entry> it( m_entries );
+ for( ; it.current(); ++it )
+ l.append( it.currentKey() );
+
+ return l;
+}
+
+
+QStringList K3bIso9660Directory::iso9660Entries() const
+{
+ // create a fake const method to fool the user ;)
+ const_cast<K3bIso9660Directory*>(this)->expand();
+
+ QStringList l;
+
+ QDictIterator<K3bIso9660Entry> it( m_iso9660Entries );
+ for( ; it.current(); ++it )
+ l.append( it.currentKey() );
+
+ return l;
+}
+
+
+K3bIso9660Entry* K3bIso9660Directory::entry( const QString& n )
+{
+ if( n.isEmpty() )
+ return 0;
+
+ expand();
+
+ QString name(n);
+
+ // trailing slash ? -> remove
+ if( name.length() > 1 && name[name.length()-1] == '/' ) {
+ name.truncate( name.length()-1 );
+ }
+
+ int pos = name.find( '/' );
+ while( pos == 0 ) {
+ if( name.length() > 1 ) {
+ name = name.mid( 1 ); // remove leading slash
+ pos = name.find( '/' ); // look again
+ }
+ else // "/"
+ return this;
+ }
+
+ if ( pos != -1 ) {
+ QString left = name.left( pos );
+ QString right = name.mid( pos + 1 );
+
+ K3bIso9660Entry* e = m_entries[ left ];
+ if ( !e || !e->isDirectory() )
+ return 0;
+ return static_cast<K3bIso9660Directory*>(e)->entry( right );
+ }
+
+ return m_entries[ name ];
+}
+
+
+K3bIso9660Entry* K3bIso9660Directory::iso9660Entry( const QString& n )
+{
+ if( n.isEmpty() )
+ return 0;
+
+ expand();
+
+ QString name(n);
+
+ // trailing slash ? -> remove
+ if( name.length() > 1 && name[name.length()-1] == '/' ) {
+ name.truncate( name.length()-1 );
+ }
+
+ int pos = name.find( '/' );
+ while( pos == 0 ) {
+ if( name.length() > 1 ) {
+ name = name.mid( 1 ); // remove leading slash
+ pos = name.find( '/' ); // look again
+ }
+ else // "/"
+ return this;
+ }
+
+ if ( pos != -1 ) {
+ QString left = name.left( pos );
+ QString right = name.mid( pos + 1 );
+
+ K3bIso9660Entry* e = m_iso9660Entries[ left ];
+ if ( !e || !e->isDirectory() )
+ return 0;
+ return static_cast<K3bIso9660Directory*>(e)->iso9660Entry( right );
+ }
+
+ return m_iso9660Entries[ name ];
+}
+
+
+const K3bIso9660Entry* K3bIso9660Directory::entry( const QString& name ) const
+{
+ return const_cast<K3bIso9660Directory*>(this)->entry( name );
+}
+
+
+const K3bIso9660Entry* K3bIso9660Directory::iso9660Entry( const QString& name ) const
+{
+ return const_cast<K3bIso9660Directory*>(this)->iso9660Entry( name );
+}
+
+
+void K3bIso9660Directory::addEntry( K3bIso9660Entry* entry )
+{
+ m_entries.insert( entry->name(), entry );
+ m_iso9660Entries.insert( entry->isoName(), entry );
+}
+
+
+
+
+
+class K3bIso9660::Private
+{
+public:
+ Private()
+ : cdDevice(0),
+ fd(-1),
+ isOpen(false),
+ startSector(0),
+ plainIso9660(false),
+ backend(0) {
+ }
+
+ QPtrList<K3bIso9660Directory> elToritoDirs;
+ QPtrList<K3bIso9660Directory> jolietDirs;
+ QPtrList<K3bIso9660Directory> isoDirs;
+ QPtrList<K3bIso9660Directory> rrDirs; // RockRidge
+
+ K3bIso9660SimplePrimaryDescriptor primaryDesc;
+
+ K3bDevice::Device* cdDevice;
+ int fd;
+
+ bool isOpen;
+
+ // only used for direkt K3bDevice::Device access
+ unsigned int startSector;
+
+ bool plainIso9660;
+
+ K3bIso9660Backend* backend;
+};
+
+
+K3bIso9660::K3bIso9660( const QString& filename )
+ : m_filename( filename )
+{
+ d = new Private();
+}
+
+
+K3bIso9660::K3bIso9660( int fd )
+{
+ d = new Private();
+ d->fd = fd;
+}
+
+
+K3bIso9660::K3bIso9660( K3bIso9660Backend* backend )
+{
+ d = new Private();
+ d->backend = backend;
+}
+
+
+K3bIso9660::K3bIso9660( K3bDevice::Device* dev, unsigned int startSector )
+{
+ d = new Private();
+ d->cdDevice = dev;
+ d->startSector = startSector;
+}
+
+
+K3bIso9660::~K3bIso9660()
+{
+ close();
+ delete d->backend;
+ delete d;
+}
+
+
+void K3bIso9660::setStartSector( unsigned int startSector )
+{
+ d->startSector = startSector;
+}
+
+
+void K3bIso9660::setPlainIso9660( bool b )
+{
+ d->plainIso9660 = b;
+}
+
+
+bool K3bIso9660::plainIso9660() const
+{
+ return d->plainIso9660;
+}
+
+
+int K3bIso9660::read( unsigned int sector, char* data, int count )
+{
+ if( count == 0 )
+ return 0;
+ else
+ return d->backend->read( sector, data, count );
+}
+
+
+void K3bIso9660::addBoot(struct el_torito_boot_descriptor* bootdesc)
+{
+ int i,size;
+ boot_head boot;
+ boot_entry *be;
+ QString path;
+ K3bIso9660File *entry;
+
+ entry=new K3bIso9660File( this, "Catalog", "Catalog", dirent->permissions() & ~S_IFDIR,
+ dirent->date(), dirent->adate(), dirent->cdate(),
+ dirent->user(), dirent->group(), QString::null,
+ isonum_731(bootdesc->boot_catalog), 2048 );
+ dirent->addEntry(entry);
+ if (!ReadBootTable(&K3bIso9660::read_callback,isonum_731(bootdesc->boot_catalog),&boot,this)) {
+ i=1;
+ be=boot.defentry;
+ while (be) {
+ size=BootImageSize(&K3bIso9660::read_callback,
+ isonum_711(((struct default_entry*) be->data)->media),
+ isonum_731(((struct default_entry*) be->data)->start),
+ isonum_721(((struct default_entry*) be->data)->seccount),
+ this);
+ path="Default Image";
+ if (i>1) path += " (" + QString::number(i) + ")";
+ entry=new K3bIso9660File( this, path, path, dirent->permissions() & ~S_IFDIR,
+ dirent->date(), dirent->adate(), dirent->cdate(),
+ dirent->user(), dirent->group(), QString::null,
+ isonum_731(((struct default_entry*) be->data)->start), size<<9 );
+ dirent->addEntry(entry);
+ be=be->next;
+ i++;
+ }
+
+ FreeBootTable(&boot);
+ }
+}
+
+
+bool K3bIso9660::open()
+{
+ if( d->isOpen )
+ return true;
+
+ if( !d->backend ) {
+ // create a backend
+
+ if( !m_filename.isEmpty() )
+ d->backend = new K3bIso9660FileBackend( m_filename );
+
+ else if( d->fd > 0 )
+ d->backend = new K3bIso9660FileBackend( d->fd );
+
+ else if( d->cdDevice ) {
+ // now check if we have a scrambled video dvd
+ if( d->cdDevice->copyrightProtectionSystemType() == 1 ) {
+
+ kdDebug() << "(K3bIso9660) found encrypted dvd. using libdvdcss." << endl;
+
+ // open the libdvdcss stuff
+ d->backend = new K3bIso9660LibDvdCssBackend( d->cdDevice );
+ if( !d->backend->open() ) {
+ // fallback to devicebackend
+ delete d->backend;
+ d->backend = new K3bIso9660DeviceBackend( d->cdDevice );
+ }
+ }
+ else
+ d->backend = new K3bIso9660DeviceBackend( d->cdDevice );
+ }
+ }
+
+ d->isOpen = d->backend->open();
+ if( !d->isOpen )
+ return false;
+
+ iso_vol_desc *desc;
+ QString path,tmp,uid,gid;
+ k3b_struct_stat buf;
+ int access,c_i,c_j;
+ struct el_torito_boot_descriptor* bootdesc;
+
+
+ /* We'll use the permission and user/group of the 'host' file except
+ * in Rock Ridge, where the permissions are stored on the file system
+ */
+ if ( k3b_stat( QFile::encodeName(m_filename), &buf ) < 0 ) {
+ /* defaults, if stat fails */
+ memset(&buf,0,sizeof(k3b_struct_stat));
+ buf.st_mode=0777;
+ }
+ uid.setNum(buf.st_uid);
+ gid.setNum(buf.st_gid);
+ access = buf.st_mode & ~S_IFMT;
+
+
+ int c_b=1;
+ c_i=1;c_j=1;
+
+ desc = ReadISO9660( &K3bIso9660::read_callback, d->startSector, this );
+
+ if (!desc) {
+ kdDebug() << "K3bIso9660::openArchive no volume descriptors" << endl;
+ close();
+ return false;
+ }
+
+ while (desc) {
+
+ m_rr = false;
+
+ switch (isonum_711(desc->data.type)) {
+ case ISO_VD_BOOT:
+
+ bootdesc=(struct el_torito_boot_descriptor*) &(desc->data);
+ if( !memcmp( EL_TORITO_ID, bootdesc->system_id, ISODCL(8,39) ) ) {
+ path="El Torito Boot";
+ if( c_b > 1 )
+ path += " (" + QString::number(c_b) + ")";
+
+ dirent = new K3bIso9660Directory( this, path, path, access | S_IFDIR,
+ buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null );
+ d->elToritoDirs.append( dirent );
+
+ addBoot(bootdesc);
+ c_b++;
+ }
+ break;
+
+ case ISO_VD_PRIMARY:
+ createSimplePrimaryDesc( (struct iso_primary_descriptor*)&desc->data );
+ // fall through
+ case ISO_VD_SUPPLEMENTARY:
+ {
+ struct iso_primary_descriptor* primaryDesc = (struct iso_primary_descriptor*)&desc->data;
+ struct iso_directory_record* idr = (struct iso_directory_record*)&primaryDesc->root_directory_record;
+
+ m_joliet = JolietLevel(&desc->data);
+
+ // skip joliet in plain iso mode
+ if( m_joliet && plainIso9660() )
+ break;
+
+ if (m_joliet) {
+ path = "Joliet level " + QString::number(m_joliet);
+ if( c_j > 1 )
+ path += " (" + QString::number(c_j) + ")";
+ }
+ else {
+ path = QString::fromLocal8Bit( primaryDesc->volume_id, 32 );
+ if( c_i > 1 )
+ path += " (" + QString::number(c_i) + ")";
+ }
+
+ dirent = new K3bIso9660Directory( this, path, path, access | S_IFDIR,
+ buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null );
+
+ // expand the root entry
+ ProcessDir( &K3bIso9660::read_callback, isonum_733(idr->extent),isonum_733(idr->size),&K3bIso9660::isofs_callback,this);
+
+ if (m_joliet)
+ c_j++;
+ else
+ c_i++;
+
+ if( m_joliet )
+ d->jolietDirs.append( dirent );
+ else {
+ if( m_rr )
+ d->rrDirs.append( dirent );
+ d->isoDirs.append( dirent );
+ }
+
+ break;
+ }
+ }
+ desc = desc->next;
+ }
+
+ FreeISO9660(desc);
+
+ return true;
+}
+
+
+bool K3bIso9660::isOpen() const
+{
+ return d->isOpen;
+}
+
+
+void K3bIso9660::createSimplePrimaryDesc( struct iso_primary_descriptor* desc )
+{
+ d->primaryDesc.volumeId = QString::fromLocal8Bit( desc->volume_id, 32 ).stripWhiteSpace();
+ d->primaryDesc.systemId = QString::fromLocal8Bit( desc->system_id, 32 ).stripWhiteSpace();
+ d->primaryDesc.volumeSetId = QString::fromLocal8Bit( desc->volume_set_id, 128 ).stripWhiteSpace();
+ d->primaryDesc.publisherId = QString::fromLocal8Bit( desc->publisher_id, 128 ).stripWhiteSpace();
+ d->primaryDesc.preparerId = QString::fromLocal8Bit( desc->preparer_id, 128 ).stripWhiteSpace();
+ d->primaryDesc.applicationId = QString::fromLocal8Bit( desc->application_id, 128 ).stripWhiteSpace();
+ d->primaryDesc.volumeSetSize = isonum_723(desc->volume_set_size);
+ d->primaryDesc.volumeSetNumber = isonum_723(desc->volume_set_size);
+ d->primaryDesc.logicalBlockSize = isonum_723(desc->logical_block_size);
+ d->primaryDesc.volumeSpaceSize = isonum_733(desc->volume_space_size);
+}
+
+
+void K3bIso9660::close()
+{
+ if( d->isOpen ) {
+ d->backend->close();
+
+ // Since the first isoDir is the KArchive
+ // root we must not delete it but all the
+ // others.
+
+ d->elToritoDirs.setAutoDelete(true);
+ d->jolietDirs.setAutoDelete(true);
+ d->isoDirs.setAutoDelete(true);
+ d->elToritoDirs.clear();
+ d->jolietDirs.clear();
+ d->isoDirs.clear();
+
+ d->isOpen = false;
+ }
+}
+
+
+const K3bIso9660Directory* K3bIso9660::firstJolietDirEntry() const
+{
+ return d->jolietDirs.first();
+}
+
+
+const K3bIso9660Directory* K3bIso9660::firstIsoDirEntry() const
+{
+ return d->isoDirs.first();
+}
+
+
+const K3bIso9660Directory* K3bIso9660::firstElToritoEntry() const
+{
+ return d->elToritoDirs.first();
+}
+
+
+const K3bIso9660Directory* K3bIso9660::firstRRDirEntry() const
+{
+ return d->rrDirs.first();
+}
+
+
+const K3bIso9660SimplePrimaryDescriptor& K3bIso9660::primaryDescriptor() const
+{
+ return d->primaryDesc;
+}
+
+
+void K3bIso9660::debug() const
+{
+ if( isOpen() ) {
+ kdDebug() << "System Id: " << primaryDescriptor().systemId << endl;
+ kdDebug() << "Volume Id: " << primaryDescriptor().volumeId << endl;
+ kdDebug() << "Volume Set Id: " << primaryDescriptor().volumeSetId << endl;
+ kdDebug() << "Preparer Id: " << primaryDescriptor().preparerId << endl;
+ kdDebug() << "Publisher Id: " << primaryDescriptor().publisherId << endl;
+ kdDebug() << "Application Id: " << primaryDescriptor().applicationId << endl;
+ kdDebug() << "Volume Set Size: " << primaryDescriptor().volumeSetSize << endl;
+ kdDebug() << "Volume Set Number: " << primaryDescriptor().volumeSetNumber << endl;
+
+ if( firstIsoDirEntry() ) {
+ kdDebug() << "First ISO Dir entry:" << endl;
+ kdDebug() << "----------------------------------------------" << endl;
+ debugEntry( firstIsoDirEntry(), 0 );
+ kdDebug() << "----------------------------------------------" << endl << endl;
+ }
+ if( firstRRDirEntry() ) {
+ kdDebug() << "First RR Dir entry:" << endl;
+ kdDebug() << "----------------------------------------------" << endl;
+ debugEntry( firstRRDirEntry(), 0 );
+ kdDebug() << "----------------------------------------------" << endl << endl;
+ }
+ if( firstJolietDirEntry() ) {
+ kdDebug() << "First Joliet Dir entry:" << endl;
+ kdDebug() << "----------------------------------------------" << endl;
+ debugEntry( firstJolietDirEntry(), 0 );
+ kdDebug() << "----------------------------------------------" << endl << endl;
+ }
+ }
+}
+
+
+void K3bIso9660::debugEntry( const K3bIso9660Entry* entry, int depth ) const
+{
+ if( !entry ) {
+ kdDebug() << "(K3bIso9660::debugEntry) null entry." << endl;
+ return;
+ }
+
+ QString spacer;
+ spacer.fill( ' ', depth*3 );
+ kdDebug() << spacer << "- " << entry->name() << " (" << entry->isoName() << ")" << endl;
+ if( entry->isDirectory() ) {
+ const K3bIso9660Directory* dir = dynamic_cast<const K3bIso9660Directory*>(entry);
+ QStringList entries = dir->entries();
+ for( QStringList::const_iterator it = entries.begin(); it != entries.end(); ++it ) {
+ debugEntry( dir->entry( *it ), depth+1 );
+ }
+ }
+}
+
+
+K3bIso9660SimplePrimaryDescriptor::K3bIso9660SimplePrimaryDescriptor()
+ : volumeSetSize(0),
+ volumeSetNumber(0),
+ logicalBlockSize(0),
+ volumeSpaceSize(0)
+{
+}
+
+
+bool operator==( const K3bIso9660SimplePrimaryDescriptor& d1,
+ const K3bIso9660SimplePrimaryDescriptor& d2 )
+{
+ return( d1.volumeId == d2.volumeId &&
+ d1.systemId == d2.systemId &&
+ d1.volumeSetId == d2.volumeSetId &&
+ d1.publisherId == d2.publisherId &&
+ d1.preparerId == d2.preparerId &&
+ d1.applicationId == d2.applicationId &&
+ d1.volumeSetSize == d2.volumeSetSize &&
+ d1.volumeSetNumber == d2.volumeSetNumber &&
+ d1.logicalBlockSize == d2.logicalBlockSize &&
+ d1.volumeSpaceSize == d2.volumeSpaceSize );
+}
+
+
+bool operator!=( const K3bIso9660SimplePrimaryDescriptor& d1,
+ const K3bIso9660SimplePrimaryDescriptor& d2 )
+{
+ return( d1.volumeId != d2.volumeId ||
+ d1.systemId != d2.systemId ||
+ d1.volumeSetId != d2.volumeSetId ||
+ d1.publisherId != d2.publisherId ||
+ d1.preparerId != d2.preparerId ||
+ d1.applicationId != d2.applicationId ||
+ d1.volumeSetSize != d2.volumeSetSize ||
+ d1.volumeSetNumber != d2.volumeSetNumber ||
+ d1.logicalBlockSize != d2.logicalBlockSize ||
+ d1.volumeSpaceSize != d2.volumeSpaceSize );
+}
diff --git a/libk3b/tools/k3biso9660.h b/libk3b/tools/k3biso9660.h
new file mode 100644
index 0000000..7fc52d9
--- /dev/null
+++ b/libk3b/tools/k3biso9660.h
@@ -0,0 +1,453 @@
+/*
+ *
+ * $Id: k3biso9660.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_ISO9660_H_
+#define _K3B_ISO9660_H_
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdict.h>
+
+#include "k3b_export.h"
+
+
+namespace K3bDevice {
+ class Device;
+}
+
+class K3bIso9660;
+class K3bIso9660Backend;
+struct iso_directory_record;
+struct el_torito_boot_descriptor;
+struct iso_primary_descriptor;
+
+typedef long sector_t;
+
+
+
+/**
+ * Simplyfied primary descriptor which just contains the fields
+ * used by K3b.
+ */
+class LIBK3B_EXPORT K3bIso9660SimplePrimaryDescriptor
+{
+ public:
+ /**
+ * Creates an empty descriptor
+ */
+ K3bIso9660SimplePrimaryDescriptor();
+
+ QString volumeId;
+ QString systemId;
+ QString volumeSetId;
+ QString publisherId;
+ QString preparerId;
+ QString applicationId;
+ int volumeSetSize;
+ int volumeSetNumber;
+ long logicalBlockSize;
+ long long volumeSpaceSize;
+};
+
+
+LIBK3B_EXPORT bool operator==( const K3bIso9660SimplePrimaryDescriptor& d1,
+ const K3bIso9660SimplePrimaryDescriptor& d2 );
+LIBK3B_EXPORT bool operator!=( const K3bIso9660SimplePrimaryDescriptor& d1,
+ const K3bIso9660SimplePrimaryDescriptor& d2 );
+
+
+/**
+ * Base class for all entries in a K3bIso9660 archive. A lot has been copied
+ * from KArchive.
+ */
+class LIBK3B_EXPORT K3bIso9660Entry
+{
+ public:
+ K3bIso9660Entry( K3bIso9660* archive,
+ const QString& isoName,
+ const QString& name,
+ int access,
+ int date,
+ int adate,
+ int cdate,
+ const QString& user,
+ const QString& group,
+ const QString& symlink );
+ virtual ~K3bIso9660Entry();
+
+ int adate() const { return m_adate; }
+ int cdate() const { return m_cdate; }
+
+ /**
+ * Creation date of the file.
+ * @return the creation date
+ */
+ QDateTime datetime() const;
+
+ /**
+ * Creation date of the file.
+ * @return the creation date in seconds since 1970
+ */
+ int date() const { return m_date; }
+
+ /**
+ * Name of the file without path.
+ * @return The file name without path.
+ */
+ const QString& name() const { return m_name; }
+
+ /**
+ * \return The raw name as saved in the ISO9660 tree
+ */
+ const QString& isoName() const { return m_isoName; }
+
+ /**
+ * The permissions and mode flags as returned by the stat() function
+ * in st_mode.
+ * @return the permissions
+ */
+ mode_t permissions() const { return m_access; }
+
+ /**
+ * User who created the file.
+ * @return the owner of the file
+ */
+ const QString& user() const { return m_user; }
+
+ /**
+ * Group of the user who created the file.
+ * @return the group of the file
+ */
+ const QString& group() const { return m_group; }
+
+ /**
+ * Symlink if there is one.
+ * @return the symlink, or QString::null
+ */
+ const QString& symlink() const { return m_symlink; }
+
+ /**
+ * Checks whether the entry is a file.
+ * @return true if this entry is a file
+ */
+ virtual bool isFile() const { return false; }
+
+ /**
+ * Checks whether the entry is a directory.
+ * @return true if this entry is a directory
+ */
+ virtual bool isDirectory() const { return false; }
+
+ K3bIso9660* archive() const { return m_archive; }
+
+ private:
+ int m_adate;
+ int m_cdate;
+ QString m_name;
+ QString m_isoName;
+ int m_date;
+ mode_t m_access;
+ QString m_user;
+ QString m_group;
+ QString m_symlink;
+ K3bIso9660* m_archive;
+};
+
+
+class LIBK3B_EXPORT K3bIso9660Directory : public K3bIso9660Entry
+{
+ public:
+ K3bIso9660Directory( K3bIso9660* archive,
+ const QString& isoName,
+ const QString& name,
+ int access,
+ int date,
+ int adate,
+ int cdate,
+ const QString& user,
+ const QString& group,
+ const QString& symlink,
+ unsigned int pos = 0,
+ unsigned int size = 0 );
+ ~K3bIso9660Directory();
+
+ /**
+ * Returns a list of sub-entries.
+ * @return the names of all entries in this directory (filenames, no path).
+ */
+ QStringList entries() const;
+
+ /**
+ * Returns the entry with the given name.
+ * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+ * @return a pointer to the entry in the directory.
+ */
+ K3bIso9660Entry* entry( const QString& name );
+
+ /**
+ * Returns the entry with the given name.
+ * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+ * @return a pointer to the entry in the directory.
+ */
+ const K3bIso9660Entry* entry( const QString& name ) const;
+
+ /**
+ * Returns a list of sub-entries.
+ * Searches for Iso9660 names.
+ * @return the names of all entries in this directory (filenames, no path).
+ */
+ QStringList iso9660Entries() const;
+
+ /**
+ * Returns the entry with the given name.
+ * Searches for Iso9660 names.
+ * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+ * @return a pointer to the entry in the directory.
+ */
+ K3bIso9660Entry* iso9660Entry( const QString& name );
+
+ /**
+ * Returns the entry with the given name.
+ * Searches for Iso9660 names.
+ * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+ * @return a pointer to the entry in the directory.
+ */
+ const K3bIso9660Entry* iso9660Entry( const QString& name ) const;
+
+ /**
+ * @internal
+ * Adds a new entry to the directory.
+ */
+ void addEntry( K3bIso9660Entry* );
+
+ /**
+ * Checks whether this entry is a directory.
+ * @return true, since this entry is a directory
+ */
+ bool isDirectory() const { return true; }
+
+ private:
+ void expand();
+
+ QDict<K3bIso9660Entry> m_entries;
+ QDict<K3bIso9660Entry> m_iso9660Entries;
+
+ bool m_bExpanded;
+ unsigned int m_startSector;
+ unsigned int m_size;
+};
+
+
+class LIBK3B_EXPORT K3bIso9660File : public K3bIso9660Entry
+{
+ public:
+ /**
+ * @param pos start sector
+ */
+ K3bIso9660File( K3bIso9660* archive,
+ const QString& isoName,
+ const QString& name,
+ int access,
+ int date,
+ int adate,
+ int cdate,
+ const QString& user,
+ const QString& group,
+ const QString& symlink,
+ unsigned int pos,
+ unsigned int size );
+ ~K3bIso9660File();
+
+ bool isFile() const { return true; }
+
+ void setZF( char algo[2], char parms[2], int realsize );
+ int realsize() const { return m_realsize; }
+
+ /**
+ * @return size in bytes.
+ */
+ unsigned int size() const { return m_size; }
+
+ /**
+ * Returnes the startSector of the file.
+ */
+ unsigned int startSector() const { return m_startSector; }
+
+ /**
+ * Returnes the startOffset of the file in bytes.
+ */
+ unsigned long long startPostion() const { return (unsigned long long)m_startSector * 2048; }
+
+ /**
+ * @param pos offset in bytes
+ * @param len max number of bytes to read
+ */
+ int read( unsigned int pos, char* data, int len ) const;
+
+ /**
+ * Copy this file to a url.
+ */
+ bool copyTo( const QString& url ) const;
+
+ private:
+ char m_algo[2];
+ char m_parms[2];
+ int m_realsize;
+
+ unsigned int m_curpos;
+ unsigned int m_startSector;
+ unsigned int m_size;
+};
+
+
+/**
+ * This class is based on the KIso class by
+ * Gy�gy Szombathelyi <gyurco@users.sourceforge.net>.
+ * A lot has been changed and bugfixed.
+ * The API has been improved to be useful.
+ *
+ * Due to the stupid Qt which does not support large files as default
+ * we cannot use QIODevice with DVDs! That's why we have our own
+ * reading code which is not allowed by KArchive (which is limited to int
+ * by the way... who the hell designed this?)
+ * I also removed the KArchive inheritance because of the named reasons.
+ * So this stuff contains a lot KArchive code which has been made usable.
+ *
+ * That does not mean that this class is well designed. No, it's not. :)
+ *
+ * Opening a K3bIso9660 object should be fast since creation of the directory
+ * and file entries is not done until a call to K3bIso9660Directory::entries.
+*/
+class LIBK3B_EXPORT K3bIso9660
+{
+ public:
+ /**
+ * Creates an instance that operates on the given filename.
+ * using the compression filter associated to given mimetype.
+ *
+ * @param filename is a local path (e.g. "/home/weis/myfile.tgz")
+ */
+ K3bIso9660( const QString& filename );
+
+ /**
+ * Special case which always reads the TOC from the specified sector
+ * thus supporting multisession CDs.
+ */
+ K3bIso9660( K3bDevice::Device* dev, unsigned int startSector = 0 );
+
+ /**
+ * @param fd open file descriptor
+ */
+ K3bIso9660( int fd );
+
+ /**
+ * Directly specify the backend to read from.
+ * K3bIso9660 will take ownership of the backend and delete it.
+ */
+ K3bIso9660( K3bIso9660Backend* );
+
+ /**
+ * If the .iso is still opened, then it will be
+ * closed automatically by the destructor.
+ */
+ virtual ~K3bIso9660();
+
+ /**
+ * Set where to start reading in the source.
+ */
+ void setStartSector( unsigned int startSector );
+
+ /**
+ * If set to true before opening K3bIso9660 will ignore RR and joliet extensions
+ * and only create plain iso9660 names.
+ */
+ void setPlainIso9660( bool );
+
+ bool plainIso9660() const;
+
+ /**
+ * Opens the archive for reading.
+ * Parses the directory listing of the archive
+ * and creates the K3bIso9660Directory/K3bIso9660File entries.
+ */
+ bool open();
+
+ bool isOpen() const;
+
+ /**
+ * Closes everything.
+ * This is also called in the destructor
+ */
+ void close();
+
+ /**
+ * @param sector startsector
+ * @param len number of sectors
+ * @return number of sectors read or -1 on error
+ */
+ int read( unsigned int sector, char* data, int len );
+
+ /**
+ * The name of the os file, as passed to the constructor
+ * Null if you did not use the QString constructor.
+ */
+ const QString& fileName() { return m_filename; }
+
+ const K3bIso9660Directory* firstJolietDirEntry() const;
+ const K3bIso9660Directory* firstRRDirEntry() const;
+ const K3bIso9660Directory* firstIsoDirEntry() const;
+ const K3bIso9660Directory* firstElToritoEntry() const;
+
+ /**
+ * @returns 0 if no joliet desc could be found
+ * the joliet level (1-3) otherwise
+ */
+ int jolietLevel() const { return m_joliet; }
+
+ const K3bIso9660SimplePrimaryDescriptor& primaryDescriptor() const;
+
+ void debug() const;
+
+ private:
+ /**
+ * @internal
+ */
+ void addBoot( struct el_torito_boot_descriptor* bootdesc );
+ void createSimplePrimaryDesc( struct iso_primary_descriptor* desc );
+
+ void debugEntry( const K3bIso9660Entry*, int depth ) const;
+
+ int m_joliet;
+
+ // only used for creation
+ static int read_callback( char* buf, sector_t start, int len, void* udata );
+ static int isofs_callback( struct iso_directory_record* idr, void *udata );
+ K3bIso9660Directory *dirent;
+ bool m_rr;
+ friend class K3bIso9660Directory;
+
+ private:
+ QString m_filename;
+
+ class Private;
+ Private * d;
+};
+
+#endif
diff --git a/libk3b/tools/k3biso9660backend.cpp b/libk3b/tools/k3biso9660backend.cpp
new file mode 100644
index 0000000..aacc079
--- /dev/null
+++ b/libk3b/tools/k3biso9660backend.cpp
@@ -0,0 +1,239 @@
+/*
+ *
+ * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3biso9660backend.h"
+#include "k3blibdvdcss.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <qfile.h>
+
+#include <k3bdevice.h>
+
+
+//
+// K3bIso9660DeviceBackend -----------------------------------
+//
+
+K3bIso9660DeviceBackend::K3bIso9660DeviceBackend( K3bDevice::Device* dev )
+ : m_device( dev ),
+ m_isOpen(false)
+{
+}
+
+
+K3bIso9660DeviceBackend::~K3bIso9660DeviceBackend()
+{
+ close();
+}
+
+
+bool K3bIso9660DeviceBackend::open()
+{
+ if( m_isOpen )
+ return true;
+ else if( m_device->open() ) {
+ // set optimal reading speed
+ m_device->setSpeed( 0xffff, 0xffff );
+ m_isOpen = true;
+ return true;
+ }
+ else
+ return false;
+}
+
+
+void K3bIso9660DeviceBackend::close()
+{
+ if( m_isOpen ) {
+ m_isOpen = false;
+ m_device->close();
+ }
+}
+
+
+int K3bIso9660DeviceBackend::read( unsigned int sector, char* data, int len )
+{
+ if( isOpen() ) {
+ //
+ // split the number of sectors to be read
+ // FIXME: use a "real" value, not some arbitrary one
+ //
+ static const int maxReadSectors = 20;
+ int sectorsRead = 0;
+ int retries = 10; // TODO: no fixed value
+ while( retries ) {
+ int read = QMIN(len-sectorsRead, maxReadSectors);
+ if( !m_device->read10( (unsigned char*)(data+sectorsRead*2048),
+ read*2048,
+ sector+sectorsRead,
+ read ) ) {
+ retries--;
+ }
+ else {
+ sectorsRead += read;
+ retries = 10; // new retires for every read part
+ if( sectorsRead == len )
+ return len;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+//
+// K3bIso9660FileBackend -----------------------------------
+//
+
+K3bIso9660FileBackend::K3bIso9660FileBackend( const QString& filename )
+ : m_filename( filename ),
+ m_fd( -1 ),
+ m_closeFd( true )
+{
+}
+
+
+K3bIso9660FileBackend::K3bIso9660FileBackend( int fd )
+ : m_fd( fd ),
+ m_closeFd( false )
+{
+}
+
+
+K3bIso9660FileBackend::~K3bIso9660FileBackend()
+{
+ close();
+}
+
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
+
+bool K3bIso9660FileBackend::open()
+{
+ if( m_fd > 0 )
+ return true;
+ else {
+ m_fd = ::open( QFile::encodeName( m_filename ), O_RDONLY|O_LARGEFILE );
+ return ( m_fd > 0 );
+ }
+}
+
+
+void K3bIso9660FileBackend::close()
+{
+ if( m_closeFd && m_fd > 0 ) {
+ ::close( m_fd );
+ m_fd = -1;
+ }
+}
+
+
+
+bool K3bIso9660FileBackend::isOpen() const
+{
+ return ( m_fd > 0 );
+}
+
+
+int K3bIso9660FileBackend::read( unsigned int sector, char* data, int len )
+{
+ int read = 0;
+ if( ::lseek( m_fd, static_cast<unsigned long long>(sector)*2048, SEEK_SET ) != -1 )
+ if( (read = ::read( m_fd, data, len*2048 )) != -1 )
+ return read / 2048;
+
+ return -1;
+}
+
+
+
+//
+// K3bIso9660LibDvdCssBackend -----------------------------------
+//
+
+K3bIso9660LibDvdCssBackend::K3bIso9660LibDvdCssBackend( K3bDevice::Device* dev )
+ : m_device( dev ),
+ m_libDvdCss( 0 )
+{
+}
+
+
+K3bIso9660LibDvdCssBackend::~K3bIso9660LibDvdCssBackend()
+{
+ close();
+}
+
+
+bool K3bIso9660LibDvdCssBackend::open()
+{
+ if( !m_libDvdCss ) {
+ // open the libdvdcss stuff
+ m_libDvdCss = K3bLibDvdCss::create();
+
+ if( m_libDvdCss ) {
+
+ if( !m_libDvdCss->open( m_device ) ||
+ !m_libDvdCss->crackAllKeys() ) {
+ kdDebug() << "(K3bIso9660LibDvdCssBackend) Failed to retrieve all CSS keys." << endl;
+ close();
+ }
+ }
+ else
+ kdDebug() << "(K3bIso9660LibDvdCssBackend) failed to open libdvdcss." << endl;
+ }
+
+ return ( m_libDvdCss != 0 );
+}
+
+
+void K3bIso9660LibDvdCssBackend::close()
+{
+ delete m_libDvdCss;
+ m_libDvdCss = 0;
+}
+
+
+
+bool K3bIso9660LibDvdCssBackend::isOpen() const
+{
+ return ( m_libDvdCss != 0 );
+}
+
+
+int K3bIso9660LibDvdCssBackend::read( unsigned int sector, char* data, int len )
+{
+ int read = -1;
+
+ if( isOpen() ) {
+ int retries = 10; // TODO: no fixed value
+ while( retries && !m_libDvdCss->readWrapped( reinterpret_cast<void*>(data),
+ sector,
+ len ) )
+ retries--;
+
+ if( retries > 0 )
+ read = len;
+ }
+
+ return read;
+}
+
diff --git a/libk3b/tools/k3biso9660backend.h b/libk3b/tools/k3biso9660backend.h
new file mode 100644
index 0000000..78937e5
--- /dev/null
+++ b/libk3b/tools/k3biso9660backend.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_ISO9660_BACKEND_H_
+#define _K3B_ISO9660_BACKEND_H_
+
+#include <qstring.h>
+
+#include "k3b_export.h"
+
+namespace K3bDevice {
+ class Device;
+}
+
+class K3bLibDvdCss;
+
+
+class K3bIso9660Backend
+{
+ public:
+ K3bIso9660Backend() {}
+ virtual ~K3bIso9660Backend() {}
+
+ virtual bool open() = 0;
+ virtual void close() = 0;
+ virtual bool isOpen() const = 0;
+ virtual int read( unsigned int sector, char* data, int len ) = 0;
+};
+
+
+class K3bIso9660DeviceBackend : public K3bIso9660Backend
+{
+ public:
+ LIBK3B_EXPORT K3bIso9660DeviceBackend( K3bDevice::Device* dev );
+ ~K3bIso9660DeviceBackend();
+
+ bool open();
+ void close();
+ bool isOpen() const { return m_isOpen; }
+ int read( unsigned int sector, char* data, int len );
+
+ private:
+ K3bDevice::Device* m_device;
+ bool m_isOpen;
+};
+
+
+class K3bIso9660FileBackend : public K3bIso9660Backend
+{
+ public:
+ LIBK3B_EXPORT K3bIso9660FileBackend( const QString& filename );
+ K3bIso9660FileBackend( int fd );
+ ~K3bIso9660FileBackend();
+
+ bool open();
+ void close();
+ bool isOpen() const;
+ int read( unsigned int sector, char* data, int len );
+
+ private:
+ QString m_filename;
+ int m_fd;
+ bool m_closeFd;
+};
+
+
+class K3bIso9660LibDvdCssBackend : public K3bIso9660Backend
+{
+ public:
+ LIBK3B_EXPORT K3bIso9660LibDvdCssBackend( K3bDevice::Device* );
+ ~K3bIso9660LibDvdCssBackend();
+
+ bool open();
+ void close();
+ bool isOpen() const;
+ int read( unsigned int sector, char* data, int len );
+
+ private:
+ K3bDevice::Device* m_device;
+ K3bLibDvdCss* m_libDvdCss;
+};
+
+#endif
diff --git a/libk3b/tools/k3blibdvdcss.cpp b/libk3b/tools/k3blibdvdcss.cpp
new file mode 100644
index 0000000..0a8d1f0
--- /dev/null
+++ b/libk3b/tools/k3blibdvdcss.cpp
@@ -0,0 +1,307 @@
+/*
+ *
+ * $Id: k3blibdvdcss.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <config.h>
+
+#include "k3blibdvdcss.h"
+
+#include <k3bdevice.h>
+#include <k3biso9660.h>
+#include <k3biso9660backend.h>
+
+#include <qfile.h>
+#include <qcstring.h>
+#include <qvaluevector.h>
+#include <qpair.h>
+
+#include <dlfcn.h>
+
+
+void* K3bLibDvdCss::s_libDvdCss = 0;
+int K3bLibDvdCss::s_counter = 0;
+
+
+extern "C" {
+ struct dvdcss_s;
+ typedef struct dvdcss_s* dvdcss_t;
+
+ dvdcss_t (*k3b_dvdcss_open)(char*);
+ int (*k3b_dvdcss_close)( dvdcss_t );
+ int (*k3b_dvdcss_seek)( dvdcss_t, int, int );
+ int (*k3b_dvdcss_read)( dvdcss_t, void*, int, int );
+}
+
+
+
+class K3bLibDvdCss::Private
+{
+public:
+ Private()
+ :dvd(0) {
+ }
+
+ dvdcss_t dvd;
+ K3bDevice::Device* device;
+ QValueVector< QPair<int,int> > titleOffsets;
+ int currentSector;
+ bool currentSectorInTitle;
+};
+
+K3bLibDvdCss::K3bLibDvdCss()
+{
+ d = new Private();
+ s_counter++;
+}
+
+
+K3bLibDvdCss::~K3bLibDvdCss()
+{
+ close();
+ delete d;
+ s_counter--;
+ if( s_counter == 0 ) {
+ dlclose( s_libDvdCss );
+ s_libDvdCss = 0;
+ }
+}
+
+
+bool K3bLibDvdCss::open( K3bDevice::Device* dev )
+{
+ d->device = dev;
+ dev->close();
+ d->dvd = k3b_dvdcss_open( const_cast<char*>( QFile::encodeName(dev->blockDeviceName()).data() ) );
+ d->currentSector = 0;
+ d->currentSectorInTitle = false;
+ return ( d->dvd != 0 );
+}
+
+
+void K3bLibDvdCss::close()
+{
+ if( d->dvd )
+ k3b_dvdcss_close( d->dvd );
+ d->dvd = 0;
+}
+
+
+int K3bLibDvdCss::seek( int sector, int flags )
+{
+ return k3b_dvdcss_seek( d->dvd, sector, flags );
+}
+
+
+int K3bLibDvdCss::read( void* buffer, int sectors, int flags )
+{
+ return k3b_dvdcss_read( d->dvd, buffer, sectors, flags );
+}
+
+
+int K3bLibDvdCss::readWrapped( void* buffer, int firstSector, int sectors )
+{
+ // 1. are we in a title?
+ // 2. does a new title start in the read sector area?
+ // - see below, set title if firstSector is the first sector of a new title
+ // 3. does a title end in the read sector area?
+ // 3.1 does a previous title end
+ // 3.2 does the title from 2. already end
+
+ // we need to seek to the first sector. Otherwise we get faulty data.
+ bool needToSeek = ( firstSector != d->currentSector || firstSector == 0 );
+ bool inTitle = false;
+ bool startOfTitle = false;
+
+ //
+ // Make sure we never read encrypted and unencrypted data at once since libdvdcss
+ // only decrypts the whole area of read sectors or nothing at all.
+ //
+ for( unsigned int i = 0; i < d->titleOffsets.count(); ++i ) {
+ int titleStart = d->titleOffsets[i].first;
+ int titleEnd = titleStart + d->titleOffsets[i].second - 1;
+
+ // update key when entrering a new title
+ // FIXME: we also need this if we seek into a new title (not only the start of the title)
+ if( titleStart == firstSector )
+ startOfTitle = needToSeek = inTitle = true;
+
+ // check if a new title or non-title area starts inside the read sector range
+ if( firstSector < titleStart && firstSector+sectors > titleStart ) {
+ kdDebug() << "(K3bLibDvdCss) title start inside of sector range ("
+ << firstSector << "-" << (firstSector+sectors-1)
+ << "). only reading " << (titleStart - firstSector) << " sectors up to title offset "
+ << (titleStart-1) << endl;
+ sectors = titleStart - firstSector;
+ }
+
+ if( firstSector < titleEnd && firstSector+sectors > titleEnd ) {
+ kdDebug() << "(K3bLibDvdCss) title end inside of sector range ("
+ << firstSector << "-" << (firstSector+sectors-1)
+ << "). only reading " << (titleEnd - firstSector + 1) << " sectors up to title offset "
+ << titleEnd << endl;
+ sectors = titleEnd - firstSector + 1;
+ inTitle = true;
+ }
+
+ // is our read range part of one title
+ if( firstSector >= titleStart && firstSector+sectors-1 <= titleEnd )
+ inTitle = true;
+ }
+
+ if( needToSeek ) {
+ int flags = DVDCSS_NOFLAGS;
+ if( startOfTitle )
+ flags = DVDCSS_SEEK_KEY;
+ else if( inTitle )
+ flags = DVDCSS_SEEK_MPEG;
+
+ kdDebug() << "(K3bLibDvdCss) need to seek from " << d->currentSector << " to " << firstSector << " with " << flags << endl;
+
+ d->currentSector = seek( firstSector, flags );
+ if( d->currentSector != firstSector ) {
+ kdDebug() << "(K3bLibDvdCss) seek failed: " << d->currentSector << endl;
+ return -1;
+ }
+
+ kdDebug() << "(K3bLibDvdCss) seek done: " << d->currentSector << endl;
+ }
+
+
+ int flags = DVDCSS_NOFLAGS;
+ if( inTitle )
+ flags = DVDCSS_READ_DECRYPT;
+
+ int ret = read( buffer, sectors, flags );
+ if( ret >= 0 )
+ d->currentSector += ret;
+ else
+ d->currentSector = 0; // force a seek the next time
+
+ return ret;
+}
+
+
+bool K3bLibDvdCss::crackAllKeys()
+{
+ //
+ // Loop over all titles and crack the keys (inspired by libdvdread)
+ //
+ kdDebug() << "(K3bLibDvdCss) cracking all keys." << endl;
+
+ d->titleOffsets.clear();
+
+ K3bIso9660 iso( new K3bIso9660DeviceBackend( d->device ) );
+ iso.setPlainIso9660( true );
+ if( !iso.open() ) {
+ kdDebug() << "(K3bLibDvdCss) could not open iso9660 fs." << endl;
+ return false;
+ }
+
+#ifdef K3B_DEBUG
+ iso.debug();
+#endif
+
+ const K3bIso9660Directory* dir = iso.firstIsoDirEntry();
+
+ int title = 0;
+ for( ; title < 100; ++title ) {
+ QString filename;
+
+ // first we get the menu vob
+ if( title == 0 )
+ filename.sprintf( "VIDEO_TS/VIDEO_TS.VOB" );
+ else
+ filename.sprintf( "VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
+
+ const K3bIso9660File* file = dynamic_cast<const K3bIso9660File*>( dir->entry( filename ) );
+ if( file && file->size() > 0 ) {
+ d->titleOffsets.append( qMakePair( (int)file->startSector(), (int)(file->size() / 2048U) ) );
+ kdDebug() << "(K3bLibDvdCss) Get key for /" << filename << " at " << file->startSector() << endl;
+ if( seek( (int)file->startSector(), DVDCSS_SEEK_KEY ) < 0 ) {
+ kdDebug() << "(K3bLibDvdCss) unable to seek to " << file->startSector() << endl;
+ return false;
+ }
+ }
+
+ if( title > 0 ) {
+ QPair<int,int> p;
+ int vob = 1;
+ for( ; vob < 100; ++vob ) {
+ filename.sprintf( "VIDEO_TS/VTS_%02d_%d.VOB", title, vob );
+ file = dynamic_cast<const K3bIso9660File*>( dir->entry( filename ) );
+ if( file ) {
+ if( file->size() % 2048 )
+ kdError() << "(K3bLibDvdCss) FILESIZE % 2048 != 0!!!" << endl;
+ if( vob == 1 ) {
+ p.first = file->startSector();
+ p.second = file->size() / 2048;
+ kdDebug() << "(K3bLibDvdCss) Get key for /" << filename << " at " << file->startSector() << endl;
+ if( seek( (int)file->startSector(), DVDCSS_SEEK_KEY ) < 0 ) {
+ kdDebug() << "(K3bLibDvdCss) unable to seek to " << file->startSector() << endl;
+ return false;
+ }
+ }
+ else {
+ p.second += file->size() / 2048;
+ }
+ }
+ else {
+ // last vob
+ break;
+ }
+ }
+ --vob;
+
+ // last title
+ if( vob == 0 )
+ break;
+
+ kdDebug() << "(K3bLibDvdCss) Title " << title << " " << vob << " vobs with length " << p.second << endl;
+ d->titleOffsets.append( p );
+ }
+ }
+
+ --title;
+
+ kdDebug() << "(K3bLibDvdCss) found " << title << " titles." << endl;
+
+ return (title > 0);
+}
+
+
+K3bLibDvdCss* K3bLibDvdCss::create()
+{
+ if( s_libDvdCss == 0 ) {
+ s_libDvdCss = dlopen( "libdvdcss.so.2", RTLD_LAZY|RTLD_GLOBAL );
+ if( s_libDvdCss ) {
+ k3b_dvdcss_open = (dvdcss_t (*)(char*))dlsym( s_libDvdCss, "dvdcss_open" );
+ k3b_dvdcss_close = (int (*)( dvdcss_t ))dlsym( s_libDvdCss, "dvdcss_close" );
+ k3b_dvdcss_seek = (int (*)( dvdcss_t, int, int ))dlsym( s_libDvdCss, "dvdcss_seek" );
+ k3b_dvdcss_read = (int (*)( dvdcss_t, void*, int, int ))dlsym( s_libDvdCss, "dvdcss_read" );
+
+ if( !k3b_dvdcss_open || !k3b_dvdcss_close || !k3b_dvdcss_seek || !k3b_dvdcss_read ) {
+ kdDebug() << "(K3bLibDvdCss) unable to resolve libdvdcss." << endl;
+ dlclose( s_libDvdCss );
+ s_libDvdCss = 0;
+ }
+ }
+ else
+ kdDebug() << "(K3bLibDvdCss) unable to load libdvdcss." << endl;
+ }
+
+ if( s_libDvdCss )
+ return new K3bLibDvdCss();
+ else
+ return 0;
+}
diff --git a/libk3b/tools/k3blibdvdcss.h b/libk3b/tools/k3blibdvdcss.h
new file mode 100644
index 0000000..308296f
--- /dev/null
+++ b/libk3b/tools/k3blibdvdcss.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * $Id: k3blibdvdcss.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_LIBDVDCSS_H_
+#define _K3B_LIBDVDCSS_H_
+
+#include "k3b_export.h"
+
+namespace K3bDevice {
+ class Device;
+}
+
+
+/**
+ * Wrapper class for libdvdcss. dynamically openes the library if it
+ * is available on the system.
+ */
+class LIBK3B_EXPORT K3bLibDvdCss
+{
+ public:
+ ~K3bLibDvdCss();
+
+ static const int DVDCSS_BLOCK_SIZE = 2048;
+ static const int DVDCSS_NOFLAGS = 0;
+ static const int DVDCSS_READ_DECRYPT = (1 << 0);
+ static const int DVDCSS_SEEK_MPEG = (1 << 0);
+ static const int DVDCSS_SEEK_KEY = (1 << 1);
+
+ /**
+ * Try to open a Video DVD and authenticate it.
+ * @return true if the Video DVD could be authenticated successfully, false otherwise.
+ */
+ bool open( K3bDevice::Device* dev );
+ void close();
+
+ int seek( int sector, int flags );
+ int read( void* buffer, int sectors, int flags );
+
+ /**
+ * This method optimized the seek calls to maximize reading performance.
+ * It also makes sure we never read unscrambled and scrambled data at the same time.
+ *
+ * You have to call crackAllKeys() before using this. Do never call this in combination
+ * with seek or read!
+ */
+ int readWrapped( void* buffer, int firstSector, int sectors );
+
+ /**
+ * Cache all CSS keys to guarantee smooth reading further on.
+ * This method also creates a title offset list which is needed by readWrapped.
+ */
+ bool crackAllKeys();
+
+ /**
+ * returns 0 if the libdvdcss could not
+ * be found on the system.
+ * Otherwise you have to take care of
+ * deleting.
+ */
+ static K3bLibDvdCss* create();
+
+ private:
+ class Private;
+ Private* d;
+
+ K3bLibDvdCss();
+
+ static void* s_libDvdCss;
+ static int s_counter;
+};
+
+#endif
diff --git a/libk3b/tools/k3blistview.cpp b/libk3b/tools/k3blistview.cpp
new file mode 100644
index 0000000..34a3aa0
--- /dev/null
+++ b/libk3b/tools/k3blistview.cpp
@@ -0,0 +1,1290 @@
+/*
+ *
+ * $Id: k3blistview.cpp 768493 2008-01-30 08:44:05Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+
+#include "k3blistview.h"
+
+#include "k3bmsfedit.h"
+
+#include <qstringlist.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+#include <qheader.h>
+#include <qrect.h>
+#include <qpushbutton.h>
+#include <qiconset.h>
+#include <qcombobox.h>
+#include <qspinbox.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+#include <qevent.h>
+#include <qvalidator.h>
+#include <qfont.h>
+#include <qpalette.h>
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qprogressbar.h>
+#include <qimage.h>
+
+#include <kpixmapeffect.h>
+
+#include <limits.h>
+
+
+
+// ///////////////////////////////////////////////
+//
+// K3BLISTVIEWITEM
+//
+// ///////////////////////////////////////////////
+
+
+class K3bListViewItem::ColumnInfo
+{
+public:
+ ColumnInfo()
+ : showProgress(false),
+ progressValue(0),
+ totalProgressSteps(100),
+ margin(0),
+ validator(0) {
+ editorType = NONE;
+ button = false;
+ comboEditable = false;
+ next = 0;
+ fontSet = false;
+ backgroundColorSet = false;
+ foregroundColorSet = false;
+ }
+
+ ~ColumnInfo() {
+ if( next )
+ delete next;
+ }
+
+ bool button;
+ int editorType;
+ QStringList comboItems;
+ bool comboEditable;
+ bool fontSet;
+ bool backgroundColorSet;
+ bool foregroundColorSet;
+ QFont font;
+ QColor backgroundColor;
+ QColor foregroundColor;
+ ColumnInfo* next;
+
+ bool showProgress;
+ int progressValue;
+ int totalProgressSteps;
+ int margin;
+
+ QValidator* validator;
+};
+
+
+
+K3bListViewItem::K3bListViewItem(QListView *parent)
+ : KListViewItem( parent )
+{
+ init();
+}
+
+K3bListViewItem::K3bListViewItem(QListViewItem *parent)
+ : KListViewItem( parent )
+{
+ init();
+}
+
+K3bListViewItem::K3bListViewItem(QListView *parent, QListViewItem *after)
+ : KListViewItem( parent, after )
+{
+ init();
+}
+
+K3bListViewItem::K3bListViewItem(QListViewItem *parent, QListViewItem *after)
+ : KListViewItem( parent, after )
+{
+ init();
+}
+
+
+K3bListViewItem::K3bListViewItem(QListView *parent,
+ const QString& s1, const QString& s2,
+ const QString& s3, const QString& s4,
+ const QString& s5, const QString& s6,
+ const QString& s7, const QString& s8)
+ : KListViewItem( parent, s1, s2, s3, s4, s5, s6, s7, s8 )
+{
+ init();
+}
+
+
+K3bListViewItem::K3bListViewItem(QListViewItem *parent,
+ const QString& s1, const QString& s2,
+ const QString& s3, const QString& s4,
+ const QString& s5, const QString& s6,
+ const QString& s7, const QString& s8)
+ : KListViewItem( parent, s1, s2, s3, s4, s5, s6, s7, s8 )
+{
+ init();
+}
+
+
+K3bListViewItem::K3bListViewItem(QListView *parent, QListViewItem *after,
+ const QString& s1, const QString& s2,
+ const QString& s3, const QString& s4,
+ const QString& s5, const QString& s6,
+ const QString& s7, const QString& s8)
+ : KListViewItem( parent, after, s1, s2, s3, s4, s5, s6, s7, s8 )
+{
+ init();
+}
+
+
+K3bListViewItem::K3bListViewItem(QListViewItem *parent, QListViewItem *after,
+ const QString& s1, const QString& s2,
+ const QString& s3, const QString& s4,
+ const QString& s5, const QString& s6,
+ const QString& s7, const QString& s8)
+ : KListViewItem( parent, after, s1, s2, s3, s4, s5, s6, s7, s8 )
+{
+ init();
+}
+
+
+K3bListViewItem::~K3bListViewItem()
+{
+ if( K3bListView* lv = dynamic_cast<K3bListView*>(listView()) )
+ if( lv->currentlyEditedItem() == this )
+ lv->hideEditor();
+
+ if( m_columns )
+ delete m_columns;
+}
+
+
+void K3bListViewItem::init()
+{
+ m_columns = 0;
+ m_vMargin = 0;
+}
+
+
+int K3bListViewItem::width( const QFontMetrics& fm, const QListView* lv, int c ) const
+{
+ return KListViewItem::width( fm, lv, c ) + getColumnInfo(c)->margin*2;
+}
+
+
+void K3bListViewItem::setEditor( int column, int editor, const QStringList& cs )
+{
+ ColumnInfo* colInfo = getColumnInfo(column);
+
+ colInfo->editorType = editor;
+ if( !cs.isEmpty() )
+ colInfo->comboItems = cs;
+}
+
+
+void K3bListViewItem::setValidator( int column, QValidator* v )
+{
+ getColumnInfo(column)->validator = v;
+}
+
+
+QValidator* K3bListViewItem::validator( int col ) const
+{
+ return getColumnInfo(col)->validator;
+}
+
+
+void K3bListViewItem::setButton( int column, bool on )
+{
+ ColumnInfo* colInfo = getColumnInfo(column);
+
+ colInfo->button = on;
+}
+
+
+K3bListViewItem::ColumnInfo* K3bListViewItem::getColumnInfo( int col ) const
+{
+ if( !m_columns )
+ m_columns = new ColumnInfo();
+
+ ColumnInfo* info = m_columns;
+ int i = 0;
+ while( i < col ) {
+ if( !info->next )
+ info->next = new ColumnInfo();
+ info = info->next;
+ ++i;
+ }
+
+ return info;
+}
+
+
+int K3bListViewItem::editorType( int col ) const
+{
+ ColumnInfo* info = getColumnInfo( col );
+ return info->editorType;
+}
+
+
+bool K3bListViewItem::needButton( int col ) const
+{
+ ColumnInfo* info = getColumnInfo( col );
+ return info->button;
+}
+
+
+const QStringList& K3bListViewItem::comboStrings( int col ) const
+{
+ ColumnInfo* info = getColumnInfo( col );
+ return info->comboItems;
+}
+
+
+void K3bListViewItem::setFont( int col, const QFont& f )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ info->fontSet = true;
+ info->font = f;
+}
+
+
+void K3bListViewItem::setBackgroundColor( int col, const QColor& c )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ info->backgroundColorSet = true;
+ info->backgroundColor = c;
+ repaint();
+}
+
+
+void K3bListViewItem::setForegroundColor( int col, const QColor& c )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ info->foregroundColorSet = true;
+ info->foregroundColor = c;
+ repaint();
+}
+
+
+void K3bListViewItem::setDisplayProgressBar( int col, bool displ )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ info->showProgress = displ;
+}
+
+
+void K3bListViewItem::setProgress( int col, int p )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ if( !info->showProgress )
+ setDisplayProgressBar( col, true );
+ if( info->progressValue != p ) {
+ info->progressValue = p;
+ repaint();
+ }
+}
+
+
+void K3bListViewItem::setTotalSteps( int col, int steps )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ info->totalProgressSteps = steps;
+
+ repaint();
+}
+
+
+void K3bListViewItem::setMarginHorizontal( int col, int margin )
+{
+ ColumnInfo* info = getColumnInfo( col );
+ info->margin = margin;
+
+ repaint();
+}
+
+
+void K3bListViewItem::setMarginVertical( int margin )
+{
+ m_vMargin = margin;
+ repaint();
+}
+
+
+int K3bListViewItem::marginHorizontal( int col ) const
+{
+ return getColumnInfo( col )->margin;
+}
+
+
+int K3bListViewItem::marginVertical() const
+{
+ return m_vMargin;
+}
+
+
+void K3bListViewItem::setup()
+{
+ KListViewItem::setup();
+
+ setHeight( height() + 2*m_vMargin );
+}
+
+
+void K3bListViewItem::paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align )
+{
+ ColumnInfo* info = getColumnInfo( col );
+
+ p->save();
+
+ QFont oldFont( p->font() );
+ QFont newFont = info->fontSet ? info->font : oldFont;
+ p->setFont( newFont );
+ QColorGroup cgh(cg);
+ if( info->foregroundColorSet )
+ cgh.setColor( QColorGroup::Text, info->foregroundColor );
+ if( info->backgroundColorSet )
+ cgh.setColor( QColorGroup::Base, info->backgroundColor );
+
+ // in case this is the selected row has a margin we need to repaint the selection bar
+ if( isSelected() &&
+ (col == 0 || listView()->allColumnsShowFocus()) &&
+ info->margin > 0 ) {
+
+ p->fillRect( 0, 0, info->margin, height(),
+ cgh.brush( QColorGroup::Highlight ) );
+ p->fillRect( width-info->margin, 0, info->margin, height(),
+ cgh.brush( QColorGroup::Highlight ) );
+ }
+ else { // in case we use the KListView alternate color stuff
+ p->fillRect( 0, 0, info->margin, height(),
+ cgh.brush( QColorGroup::Base ) );
+ p->fillRect( width-info->margin, 0, info->margin, height(),
+ cgh.brush( QColorGroup::Base ) );
+ }
+
+ // FIXME: the margin (we can only translate horizontally since height() is used for painting)
+ p->translate( info->margin, 0 );
+
+ if( info->showProgress ) {
+ paintProgressBar( p, cgh, col, width-2*info->margin );
+ }
+ else {
+ paintK3bCell( p, cgh, col, width-2*info->margin, align );
+ }
+
+ p->restore();
+}
+
+
+void K3bListViewItem::paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align )
+{
+ QListViewItem::paintCell( p, cg, col, width, align );
+}
+
+
+void K3bListViewItem::paintProgressBar( QPainter* p, const QColorGroup& cgh, int col, int width )
+{
+ ColumnInfo* info = getColumnInfo( col );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if( listView()->isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if( listView()->hasFocus() )
+ flags |= QStyle::Style_HasFocus;
+
+ // FIXME: the QPainter is translated so 0, m_vMargin is the upper left of our paint rect
+ QRect r( 0, m_vMargin, width, height()-2*m_vMargin );
+
+ // create the double buffer pixmap
+ static QPixmap *doubleBuffer = 0;
+ if( !doubleBuffer )
+ doubleBuffer = new QPixmap;
+ doubleBuffer->resize( width, height() );
+
+ QPainter dbPainter( doubleBuffer );
+
+ // clear the background (we cannot use paintEmptyArea since it's protected in QListView)
+ if( K3bListView* lv = dynamic_cast<K3bListView*>(listView()) )
+ lv->paintEmptyArea( &dbPainter, r );
+ else
+ dbPainter.fillRect( 0, 0, width, height(),
+ cgh.brush( QPalette::backgroundRoleFromMode(listView()->viewport()->backgroundMode()) ) );
+
+ // we want a little additional margin
+ r.setLeft( r.left()+1 );
+ r.setWidth( r.width()-2 );
+ r.setTop( r.top()+1 );
+ r.setHeight( r.height()-2 );
+
+ // this might be a stupid hack but most styles do not reimplement drawPrimitive PE_ProgressBarChunk
+ // so this way the user is happy....
+ static QProgressBar* s_dummyProgressBar = 0;
+ if( !s_dummyProgressBar ) {
+ s_dummyProgressBar = new QProgressBar();
+ }
+
+ s_dummyProgressBar->setTotalSteps( info->totalProgressSteps );
+ s_dummyProgressBar->setProgress( info->progressValue );
+
+ // some styles use the widget's geometry
+ s_dummyProgressBar->setGeometry( r );
+
+ listView()->style().drawControl(QStyle::CE_ProgressBarContents, &dbPainter, s_dummyProgressBar, r, cgh, flags );
+ listView()->style().drawControl(QStyle::CE_ProgressBarLabel, &dbPainter, s_dummyProgressBar, r, cgh, flags );
+
+ // now we really paint the progress in the listview
+ p->drawPixmap( 0, 0, *doubleBuffer );
+}
+
+
+
+
+
+
+
+K3bCheckListViewItem::K3bCheckListViewItem(QListView *parent)
+ : K3bListViewItem( parent ),
+ m_checked(false)
+{
+}
+
+
+K3bCheckListViewItem::K3bCheckListViewItem(QListViewItem *parent)
+ : K3bListViewItem( parent ),
+ m_checked(false)
+{
+}
+
+
+K3bCheckListViewItem::K3bCheckListViewItem(QListView *parent, QListViewItem *after)
+ : K3bListViewItem( parent, after ),
+ m_checked(false)
+{
+}
+
+
+K3bCheckListViewItem::K3bCheckListViewItem(QListViewItem *parent, QListViewItem *after)
+ : K3bListViewItem( parent, after ),
+ m_checked(false)
+{
+}
+
+
+bool K3bCheckListViewItem::isChecked() const
+{
+ return m_checked;
+}
+
+
+void K3bCheckListViewItem::setChecked( bool checked )
+{
+ m_checked = checked;
+ repaint();
+}
+
+
+void K3bCheckListViewItem::paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align )
+{
+ K3bListViewItem::paintK3bCell( p, cg, col, width, align );
+
+ if( col == 0 ) {
+ if( m_checked ) {
+ QRect r( 0, marginVertical(), width, /*listView()->style().pixelMetric( QStyle::PM_CheckListButtonSize )*/height()-2*marginVertical() );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if( listView()->isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if( listView()->hasFocus() )
+ flags |= QStyle::Style_HasFocus;
+ if( isChecked() )
+ flags |= QStyle::Style_On;
+ else
+ flags |= QStyle::Style_Off;
+
+ listView()->style().drawPrimitive( QStyle::PE_CheckMark, p, r, cg, flags );
+ }
+ }
+}
+
+
+
+
+
+
+// ///////////////////////////////////////////////
+//
+// K3BLISTVIEW
+//
+// ///////////////////////////////////////////////
+
+
+class K3bListView::Private
+{
+public:
+ QLineEdit* spinBoxLineEdit;
+ QLineEdit* msfEditLineEdit;
+};
+
+
+K3bListView::K3bListView( QWidget* parent, const char* name )
+ : KListView( parent, name ),
+ m_noItemVMargin( 20 ),
+ m_noItemHMargin( 20 )
+{
+ d = new Private;
+
+ connect( header(), SIGNAL( sizeChange( int, int, int ) ),
+ this, SLOT( updateEditorSize() ) );
+
+ m_editorButton = 0;
+ m_editorComboBox = 0;
+ m_editorSpinBox = 0;
+ m_editorLineEdit = 0;
+ m_editorMsfEdit = 0;
+ m_currentEditItem = 0;
+ m_currentEditColumn = 0;
+ m_doubleClickForEdit = true;
+ m_lastClickedItem = 0;
+}
+
+K3bListView::~K3bListView()
+{
+ delete d;
+}
+
+
+QWidget* K3bListView::editor( K3bListViewItem::EditorType t ) const
+{
+ switch( t ) {
+ case K3bListViewItem::COMBO:
+ return m_editorComboBox;
+ case K3bListViewItem::LINE:
+ return m_editorLineEdit;
+ case K3bListViewItem::SPIN:
+ return m_editorSpinBox;
+ case K3bListViewItem::MSF:
+ return m_editorMsfEdit;
+ default:
+ return 0;
+ }
+}
+
+
+void K3bListView::clear()
+{
+ hideEditor();
+ KListView::clear();
+}
+
+
+void K3bListView::editItem( K3bListViewItem* item, int col )
+{
+ if( item == 0 )
+ hideEditor();
+ else if( item->isEnabled() ) {
+ showEditor( item, col );
+ }
+}
+
+
+void K3bListView::hideEditor()
+{
+ m_lastClickedItem = 0;
+ m_currentEditItem = 0;
+ m_currentEditColumn = 0;
+
+ if( m_editorSpinBox )
+ m_editorSpinBox->hide();
+ if( m_editorLineEdit )
+ m_editorLineEdit->hide();
+ if( m_editorComboBox )
+ m_editorComboBox->hide();
+ if( m_editorButton )
+ m_editorButton->hide();
+ if( m_editorMsfEdit )
+ m_editorMsfEdit->hide();
+}
+
+void K3bListView::showEditor( K3bListViewItem* item, int col )
+{
+ if( !item )
+ return;
+
+ if( item->needButton( col ) || item->editorType(col) != K3bListViewItem::NONE ) {
+ m_currentEditColumn = col;
+ m_currentEditItem = item;
+ }
+
+ placeEditor( item, col );
+ if( item->needButton( col ) ) {
+ m_editorButton->show();
+ }
+ switch( item->editorType(col) ) {
+ case K3bListViewItem::COMBO:
+ m_editorComboBox->show();
+ m_editorComboBox->setFocus();
+ m_editorComboBox->setValidator( item->validator(col) );
+ break;
+ case K3bListViewItem::LINE:
+ m_editorLineEdit->show();
+ m_editorLineEdit->setFocus();
+ m_editorLineEdit->setValidator( item->validator(col) );
+ break;
+ case K3bListViewItem::SPIN:
+ m_editorSpinBox->show();
+ m_editorSpinBox->setFocus();
+ break;
+ case K3bListViewItem::MSF:
+ m_editorMsfEdit->show();
+ m_editorMsfEdit->setFocus();
+ break;
+ default:
+ break;
+ }
+}
+
+
+void K3bListView::placeEditor( K3bListViewItem* item, int col )
+{
+ ensureItemVisible( item );
+ QRect r = itemRect( item );
+
+ r.setX( contentsToViewport( QPoint(header()->sectionPos( col ), 0) ).x() );
+ r.setWidth( header()->sectionSize( col ) - 1 );
+
+ // check if the column is fully visible
+ if( visibleWidth() < r.right() )
+ r.setRight(visibleWidth());
+
+ r = QRect( viewportToContents( r.topLeft() ), r.size() );
+
+ if( item->pixmap( col ) ) {
+ r.setX( r.x() + item->pixmap(col)->width() );
+ }
+
+ // the tree-stuff is painted in the first column
+ if( col == 0 ) {
+ r.setX( r.x() + item->depth() * treeStepSize() );
+ if( rootIsDecorated() )
+ r.setX( r.x() + treeStepSize() );
+ }
+
+ if( item->needButton(col) ) {
+ prepareButton( item, col );
+ m_editorButton->setFixedHeight( r.height() );
+ // for now we make a square button
+ m_editorButton->setFixedWidth( m_editorButton->height() );
+ r.setWidth( r.width() - m_editorButton->width() );
+ moveChild( m_editorButton, r.right(), r.y() );
+ }
+
+ if( QWidget* editor = prepareEditor( item, col ) ) {
+ editor->resize( r.size() );
+ // editor->resize( QSize( r.width(), editor->minimumSizeHint().height() ) );
+ moveChild( editor, r.x(), r.y() );
+ }
+}
+
+
+void K3bListView::prepareButton( K3bListViewItem*, int )
+{
+ if( !m_editorButton ) {
+ m_editorButton = new QPushButton( viewport() );
+ connect( m_editorButton, SIGNAL(clicked()),
+ this, SLOT(slotEditorButtonClicked()) );
+ }
+
+ // TODO: do some useful things
+ m_editorButton->setText( "..." );
+}
+
+
+QWidget* K3bListView::prepareEditor( K3bListViewItem* item, int col )
+{
+ switch( item->editorType(col) ) {
+ case K3bListViewItem::COMBO:
+ if( !m_editorComboBox ) {
+ m_editorComboBox = new QComboBox( viewport() );
+ connect( m_editorComboBox, SIGNAL(activated(const QString&)),
+ this, SLOT(slotEditorComboBoxActivated(const QString&)) );
+ m_editorComboBox->installEventFilter( this );
+ }
+ m_editorComboBox->clear();
+ if( item->comboStrings( col ).isEmpty() ) {
+ m_editorComboBox->insertItem( item->text( col ) );
+ }
+ else {
+ m_editorComboBox->insertStringList( item->comboStrings(col) );
+ int current = item->comboStrings(col).findIndex( item->text(col) );
+ if( current != -1 )
+ m_editorComboBox->setCurrentItem( current );
+ }
+ return m_editorComboBox;
+
+ case K3bListViewItem::LINE: {
+ if( !m_editorLineEdit ) {
+ m_editorLineEdit = new QLineEdit( viewport() );
+ m_editorLineEdit->setFrameStyle( QFrame::Box | QFrame::Plain );
+ m_editorLineEdit->setLineWidth(1);
+ m_editorLineEdit->installEventFilter( this );
+ }
+
+ QString txt = item->text( col );
+ m_editorLineEdit->setText( txt );
+
+ // select the edit text (handle extensions while doing so)
+ int pos = txt.findRev( '.' );
+ if( pos > 0 )
+ m_editorLineEdit->setSelection( 0, pos );
+ else
+ m_editorLineEdit->setSelection( 0, txt.length() );
+
+ return m_editorLineEdit;
+ }
+
+ //
+ // A QSpinBox (and thus also a K3bMsfEdit) uses a QLineEdit), thus
+ // we have to use this QLineEdit as the actual object to dead with
+ //
+
+ case K3bListViewItem::SPIN:
+ if( !m_editorSpinBox ) {
+ m_editorSpinBox = new QSpinBox( viewport() );
+ d->spinBoxLineEdit = static_cast<QLineEdit*>( m_editorSpinBox->child( 0, "QLineEdit" ) );
+ connect( m_editorSpinBox, SIGNAL(valueChanged(int)),
+ this, SLOT(slotEditorSpinBoxValueChanged(int)) );
+ // m_editorSpinBox->installEventFilter( this );
+ d->spinBoxLineEdit->installEventFilter( this );
+ }
+ // set the range
+ m_editorSpinBox->setValue( item->text(col).toInt() );
+ return m_editorSpinBox;
+
+ case K3bListViewItem::MSF:
+ if( !m_editorMsfEdit ) {
+ m_editorMsfEdit = new K3bMsfEdit( viewport() );
+ d->msfEditLineEdit = static_cast<QLineEdit*>( m_editorMsfEdit->child( 0, "QLineEdit" ) );
+ connect( m_editorMsfEdit, SIGNAL(valueChanged(int)),
+ this, SLOT(slotEditorMsfEditValueChanged(int)) );
+ // m_editorMsfEdit->installEventFilter( this );
+ d->msfEditLineEdit->installEventFilter( this );
+ }
+ m_editorMsfEdit->setText( item->text(col) );
+ return m_editorMsfEdit;
+
+ default:
+ return 0;
+ }
+}
+
+void K3bListView::setCurrentItem( QListViewItem* i )
+{
+ if( !i || i == currentItem() )
+ return;
+
+ // I cannot remember why I did this here exactly. However, it resets the
+ // m_lastClickedItem and thus invalidates the editing.
+// doRename();
+// hideEditor();
+// m_currentEditItem = 0;
+ KListView::setCurrentItem( i );
+}
+
+
+void K3bListView::setNoItemText( const QString& text )
+{
+ m_noItemText = text;
+ triggerUpdate();
+}
+
+
+void K3bListView::viewportPaintEvent( QPaintEvent* e )
+{
+ KListView::viewportPaintEvent( e );
+}
+
+
+// FIXME: move this to viewportPaintEvent
+void K3bListView::drawContentsOffset( QPainter * p, int ox, int oy, int cx, int cy, int cw, int ch )
+{
+ KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
+
+ if( childCount() == 0 && !m_noItemText.isEmpty()) {
+
+ p->setPen( Qt::darkGray );
+
+ QStringList lines = QStringList::split( "\n", m_noItemText );
+ int xpos = m_noItemHMargin;
+ int ypos = m_noItemVMargin + p->fontMetrics().height();
+
+ QStringList::Iterator end ( lines.end() );
+ for( QStringList::Iterator str = lines.begin(); str != end; ++str ) {
+ p->drawText( xpos, ypos, *str );
+ ypos += p->fontMetrics().lineSpacing();
+ }
+ }
+}
+
+void K3bListView::paintEmptyArea( QPainter* p, const QRect& rect )
+{
+ KListView::paintEmptyArea( p, rect );
+
+// if( childCount() == 0 && !m_noItemText.isEmpty()) {
+
+// QPainter pp( viewport() );
+// pp.fillRect( viewport()->rect(), viewport()->paletteBackgroundColor() );
+// pp.end();
+
+// p->setPen( Qt::darkGray );
+
+// QStringList lines = QStringList::split( "\n", m_noItemText );
+// int xpos = m_noItemHMargin;
+// int ypos = m_noItemVMargin + p->fontMetrics().height();
+
+// for( QStringList::Iterator str = lines.begin(); str != lines.end(); str++ ) {
+// p->drawText( xpos, ypos, *str );
+// ypos += p->fontMetrics().lineSpacing();
+// }
+// }
+}
+
+void K3bListView::resizeEvent( QResizeEvent* e )
+{
+ KListView::resizeEvent( e );
+ updateEditorSize();
+}
+
+
+void K3bListView::updateEditorSize()
+{
+ if( m_currentEditItem )
+ placeEditor( m_currentEditItem, m_currentEditColumn );
+}
+
+
+void K3bListView::slotEditorLineEditReturnPressed()
+{
+ if( doRename() ) {
+ // edit the next line
+ // TODO: add config for this
+ if( K3bListViewItem* nextItem = dynamic_cast<K3bListViewItem*>( m_currentEditItem->nextSibling() ) )
+ editItem( nextItem, currentEditColumn() );
+ else {
+ hideEditor();
+
+ // keep the focus here
+ viewport()->setFocus();
+ }
+ }
+}
+
+
+void K3bListView::slotEditorComboBoxActivated( const QString& )
+{
+ doRename();
+// if( renameItem( m_currentEditItem, m_currentEditColumn, str ) ) {
+// m_currentEditItem->setText( m_currentEditColumn, str );
+// emit itemRenamed( m_currentEditItem, str, m_currentEditColumn );
+// }
+// else {
+// for( int i = 0; i < m_editorComboBox->count(); ++i ) {
+// if( m_editorComboBox->text(i) == m_currentEditItem->text(m_currentEditColumn) ) {
+// m_editorComboBox->setCurrentItem( i );
+// break;
+// }
+// }
+// }
+}
+
+
+void K3bListView::slotEditorSpinBoxValueChanged( int )
+{
+// if( renameItem( m_currentEditItem, m_currentEditColumn, QString::number(value) ) ) {
+// m_currentEditItem->setText( m_currentEditColumn, QString::number(value) );
+// emit itemRenamed( m_currentEditItem, QString::number(value), m_currentEditColumn );
+// }
+// else
+// m_editorSpinBox->setValue( m_currentEditItem->text( m_currentEditColumn ).toInt() );
+}
+
+
+void K3bListView::slotEditorMsfEditValueChanged( int )
+{
+ // FIXME: do we always need to update the value. Isn't it enough to do it at the end?
+// if( renameItem( m_currentEditItem, m_currentEditColumn, QString::number(value) ) ) {
+// m_currentEditItem->setText( m_currentEditColumn, QString::number(value) );
+// emit itemRenamed( m_currentEditItem, QString::number(value), m_currentEditColumn );
+// }
+// else
+// m_editorMsfEdit->setText( m_currentEditItem->text( m_currentEditColumn ) );
+}
+
+
+bool K3bListView::doRename()
+{
+ if( m_currentEditItem ) {
+ QString newValue;
+ switch( m_currentEditItem->editorType( m_currentEditColumn ) ) {
+ case K3bListViewItem::COMBO:
+ newValue = m_editorComboBox->currentText();
+ break;
+ case K3bListViewItem::LINE:
+ newValue = m_editorLineEdit->text();
+ break;
+ case K3bListViewItem::SPIN:
+ newValue = QString::number(m_editorSpinBox->value());
+ break;
+ case K3bListViewItem::MSF:
+ newValue = QString::number(m_editorMsfEdit->value());
+ break;
+ }
+
+ if( renameItem( m_currentEditItem, m_currentEditColumn, newValue ) ) {
+ m_currentEditItem->setText( m_currentEditColumn, newValue );
+ emit itemRenamed( m_currentEditItem, newValue, m_currentEditColumn );
+ return true;
+ }
+ else {
+ switch( m_currentEditItem->editorType( m_currentEditColumn ) ) {
+ case K3bListViewItem::COMBO:
+ for( int i = 0; i < m_editorComboBox->count(); ++i ) {
+ if( m_editorComboBox->text(i) == m_currentEditItem->text(m_currentEditColumn) ) {
+ m_editorComboBox->setCurrentItem( i );
+ break;
+ }
+ }
+ break;
+ case K3bListViewItem::LINE:
+ m_editorLineEdit->setText( m_currentEditItem->text( m_currentEditColumn ) );
+ break;
+ case K3bListViewItem::SPIN:
+ m_editorSpinBox->setValue( m_currentEditItem->text( m_currentEditColumn ).toInt() );
+ break;
+ case K3bListViewItem::MSF:
+ m_editorMsfEdit->setText( m_currentEditItem->text( m_currentEditColumn ) );
+ break;
+ }
+ }
+ }
+
+
+ return false;
+}
+
+
+void K3bListView::slotEditorButtonClicked()
+{
+ slotEditorButtonClicked( m_currentEditItem, m_currentEditColumn );
+}
+
+
+bool K3bListView::renameItem( K3bListViewItem* item, int col, const QString& text )
+{
+ Q_UNUSED(item);
+ Q_UNUSED(col);
+ Q_UNUSED(text);
+ return true;
+}
+
+
+void K3bListView::slotEditorButtonClicked( K3bListViewItem* item, int col )
+{
+ emit editorButtonClicked( item, col );
+}
+
+
+bool K3bListView::eventFilter( QObject* o, QEvent* e )
+{
+ if( e->type() == QEvent::KeyPress ) {
+ QKeyEvent* ke = static_cast<QKeyEvent*>(e);
+ if( ke->key() == Key_Tab ) {
+ if( o == m_editorLineEdit ||
+ o == d->msfEditLineEdit ||
+ o == d->spinBoxLineEdit ) {
+ K3bListViewItem* lastEditItem = m_currentEditItem;
+
+ doRename();
+
+ if( lastEditItem ) {
+ // can we rename one of the other columns?
+ int col = currentEditColumn()+1;
+ while( col < columns() && lastEditItem->editorType( col ) == K3bListViewItem::NONE )
+ ++col;
+ if( col < columns() )
+ editItem( lastEditItem, col );
+ else {
+ hideEditor();
+
+ // keep the focus here
+ viewport()->setFocus();
+
+ // search for the next editable item
+ while( K3bListViewItem* nextItem =
+ dynamic_cast<K3bListViewItem*>( lastEditItem->nextSibling() ) ) {
+ // edit first column
+ col = 0;
+ while( col < columns() && nextItem->editorType( col ) == K3bListViewItem::NONE )
+ ++col;
+ if( col < columns() ) {
+ editItem( nextItem, col );
+ break;
+ }
+
+ lastEditItem = nextItem;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+ if( ke->key() == Key_Return ||
+ ke->key() == Key_Enter ) {
+ if( o == m_editorLineEdit ||
+ o == d->msfEditLineEdit ||
+ o == d->spinBoxLineEdit ) {
+ K3bListViewItem* lastEditItem = m_currentEditItem;
+ doRename();
+
+ if( K3bListViewItem* nextItem =
+ dynamic_cast<K3bListViewItem*>( lastEditItem->nextSibling() ) )
+ editItem( nextItem, currentEditColumn() );
+ else {
+ hideEditor();
+
+ // keep the focus here
+ viewport()->setFocus();
+ }
+
+ return true;
+ }
+ }
+ else if( ke->key() == Key_Escape ) {
+ if( o == m_editorLineEdit ||
+ o == d->msfEditLineEdit ||
+ o == d->spinBoxLineEdit ) {
+ hideEditor();
+
+ // keep the focus here
+ viewport()->setFocus();
+
+ return true;
+ }
+ }
+ }
+
+ else if( e->type() == QEvent::MouseButtonPress && o == viewport() ) {
+
+ // first let's grab the focus
+ viewport()->setFocus();
+
+ QMouseEvent* me = static_cast<QMouseEvent*>( e );
+ QListViewItem* item = itemAt( me->pos() );
+ int col = header()->sectionAt( me->pos().x() );
+ if( K3bCheckListViewItem* ci = dynamic_cast<K3bCheckListViewItem*>( item ) ) {
+ if( col == 0 ) {
+ // FIXME: improve this click area!
+ ci->setChecked( !ci->isChecked() );
+ return true;
+ }
+ }
+
+ if( me->button() == QMouseEvent::LeftButton ) {
+ if( item != m_currentEditItem || m_currentEditColumn != col ) {
+ doRename();
+ if( K3bListViewItem* k3bItem = dynamic_cast<K3bListViewItem*>(item) ) {
+ if( me->pos().x() > item->depth()*treeStepSize() &&
+ item->isEnabled() &&
+ (m_lastClickedItem == item || !m_doubleClickForEdit) )
+ showEditor( k3bItem, col );
+ else {
+ hideEditor();
+
+ // keep the focus here
+ viewport()->setFocus();
+ }
+ }
+ else {
+ hideEditor();
+
+ // keep the focus here
+ viewport()->setFocus();
+ }
+
+ // do not count clicks in the item tree for editing
+ if( item && me->pos().x() > item->depth()*treeStepSize() )
+ m_lastClickedItem = item;
+ }
+ }
+ }
+
+ else if( e->type() == QEvent::FocusOut ) {
+ if( o == m_editorLineEdit ||
+ o == d->msfEditLineEdit ||
+ o == d->spinBoxLineEdit ||
+ o == m_editorComboBox ) {
+ // make sure we did not lose the focus to one of the edit widgets' children
+ if( !qApp->focusWidget() || qApp->focusWidget()->parentWidget() != o ) {
+ doRename();
+ hideEditor();
+ }
+ }
+ }
+
+ return KListView::eventFilter( o, e );
+}
+
+
+void K3bListView::setK3bBackgroundPixmap( const QPixmap& pix, int pos )
+{
+ m_backgroundPixmap = pix;
+ m_backgroundPixmapPosition = pos;
+}
+
+
+void K3bListView::viewportResizeEvent( QResizeEvent* e )
+{
+ if( !m_backgroundPixmap.isNull() ) {
+
+ QSize size = viewport()->size().expandedTo( QSize( contentsWidth(), contentsHeight() ) );
+
+ QPixmap bgPix( size );
+
+ // FIXME: let the user specify the color
+ bgPix.fill( colorGroup().base() );
+
+ if( bgPix.width() < m_backgroundPixmap.width() ||
+ bgPix.height() < m_backgroundPixmap.height() ) {
+ QPixmap newBgPix( m_backgroundPixmap.convertToImage().scale( bgPix.size(), QImage::ScaleMin ) );
+ if( m_backgroundPixmapPosition == TOP_LEFT )
+ bitBlt( &bgPix, 0, 0,
+ &newBgPix, 0, 0,
+ newBgPix.width(), newBgPix.height() );
+ else {
+ int dx = bgPix.width() / 2 - m_backgroundPixmap.width() /2;
+ int dy = bgPix.height() / 2 - m_backgroundPixmap.height() /2;
+ bitBlt( &bgPix, dx, dy, &newBgPix, 0, 0,
+ newBgPix.width(), newBgPix.height() );
+ }
+ }
+ else {
+ if( m_backgroundPixmapPosition == TOP_LEFT )
+ bitBlt( &bgPix, 0, 0,
+ &m_backgroundPixmap, 0, 0,
+ m_backgroundPixmap.width(), m_backgroundPixmap.height() );
+ else {
+ int dx = bgPix.width() / 2 - m_backgroundPixmap.width() /2;
+ int dy = bgPix.height() / 2 - m_backgroundPixmap.height() /2;
+ bitBlt( &bgPix, dx, dy, &m_backgroundPixmap, 0, 0,
+ m_backgroundPixmap.width(), m_backgroundPixmap.height() );
+ }
+ }
+
+ viewport()->setPaletteBackgroundPixmap( bgPix );
+ }
+
+ KListView::viewportResizeEvent( e );
+}
+
+
+QListViewItem* K3bListView::parentItem( QListViewItem* item )
+{
+ if( !item )
+ return 0;
+ if( item->parent() )
+ return item->parent();
+ else
+ return K3bListView::parentItem( item->itemAbove() );
+}
+
+
+KPixmap K3bListView::createDragPixmap( const QPtrList<QListViewItem>& items )
+{
+ //
+ // Create drag pixmap.
+ // If there are too many items fade the pixmap using the mask
+ // always fade invisible items
+ //
+ int width = header()->width();
+ int height = 0;
+ for( QPtrListIterator<QListViewItem> it( items ); *it; ++it ) {
+ QRect r = itemRect( *it );
+
+ if( r.isValid() ) {
+ height += ( *it )->height();
+ }
+ }
+
+ // now we should have a range top->bottom which includes all visible items
+
+ // there are two situations in which we fade the pixmap on the top or the bottom:
+ // 1. there are invisible items above (below) the visible
+ // 2. the range is way too big
+
+ // FIXME: how do we determine if there are invisible items outside our range?
+
+ KPixmap pix;
+ pix.resize( width, height );
+ pix.fill( Qt::white );
+ // QBitmap mask( width, bottom-top );
+
+ // now paint all the visible items into the pixmap
+ // FIXME: only paint the visible items
+ QPainter p( &pix );
+ for( QListViewItemIterator it( this ); *it; ++it ) {
+ QListViewItem* item = *it;
+
+ // FIXME: items on other than the top level have a smaller first column
+ // the same goes for all items if root is decorated
+ bool alreadyDrawing = false;
+ QRect r = itemRect( item );
+ if( r.isValid() ) {
+ if( items.containsRef( item ) ) {
+ // paint all columns
+ int x = 0;
+ for( int i = 0; i < columns(); ++i ) {
+ item->paintCell( &p, colorGroup(), i, columnWidth( i ), columnAlignment( i ) );
+ p.translate( columnWidth( i ), 0 );
+ x += columnWidth( i );
+ }
+
+ p.translate( -x, item->height() );
+
+ alreadyDrawing = true;
+ }
+ else if( alreadyDrawing )
+ p.translate( 0, item->height() );
+
+ if( p.worldMatrix().dy() >= pix.height() )
+ break;
+ }
+ }
+
+ // make it a little lighter
+ KPixmapEffect::fade( pix, 0.3, Qt::white );
+
+ // FIXME: fade the pixmap at the right side if the items are longer than width
+
+ return pix;
+}
+
+#include "k3blistview.moc"
diff --git a/libk3b/tools/k3blistview.h b/libk3b/tools/k3blistview.h
new file mode 100644
index 0000000..f8eb2ad
--- /dev/null
+++ b/libk3b/tools/k3blistview.h
@@ -0,0 +1,296 @@
+/*
+ *
+ * $Id: k3blistview.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef K3BLISTVIEW_H
+#define K3BLISTVIEW_H
+
+
+#include <klistview.h>
+#include "k3b_export.h"
+#include <qptrvector.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <kpixmap.h>
+
+class QPainter;
+class QPushButton;
+class QIconSet;
+class QResizeEvent;
+class QComboBox;
+class QSpinBox;
+class QLineEdit;
+class QEvent;
+class QValidator;
+class K3bMsfEdit;
+
+class K3bListView;
+
+
+class LIBK3B_EXPORT K3bListViewItem : public KListViewItem
+{
+ public:
+ K3bListViewItem(QListView *parent);
+ K3bListViewItem(QListViewItem *parent);
+ K3bListViewItem(QListView *parent, QListViewItem *after);
+ K3bListViewItem(QListViewItem *parent, QListViewItem *after);
+
+ K3bListViewItem(QListView *parent,
+ const QString&, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null);
+
+ K3bListViewItem(QListViewItem *parent,
+ const QString&, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null);
+
+ K3bListViewItem(QListView *parent, QListViewItem *after,
+ const QString&, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null);
+
+ K3bListViewItem(QListViewItem *parent, QListViewItem *after,
+ const QString&, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null,
+ const QString& = QString::null, const QString& = QString::null);
+
+ virtual ~K3bListViewItem();
+
+ /**
+ * reimplemented from KListViewItem
+ */
+ void setup();
+
+ virtual int width( const QFontMetrics& fm, const QListView* lv, int c ) const;
+
+ void setEditor( int col, int type, const QStringList& = QStringList() );
+ void setButton( int col, bool );
+
+ void setValidator( int col, QValidator* v );
+ QValidator* validator( int col ) const;
+
+ int editorType( int col ) const;
+ bool needButton( int col ) const;
+ const QStringList& comboStrings( int col ) const;
+
+ enum EditorType { NONE, COMBO, LINE, SPIN, MSF };
+
+ void setFont( int col, const QFont& f );
+ void setBackgroundColor( int col, const QColor& );
+ void setForegroundColor( int col, const QColor& );
+
+ void setDisplayProgressBar( int col, bool );
+ void setProgress( int, int );
+ void setTotalSteps( int col, int steps );
+
+ /**
+ * The margin left and right of the cell
+ */
+ void setMarginHorizontal( int col, int margin );
+
+ /**
+ * The top and button margin of the cell
+ */
+ void setMarginVertical( int margin );
+
+ int marginHorizontal( int col ) const;
+ int marginVertical() const;
+
+ /**
+ * Do not reimplement this but paintK3bCell to use the margin and background stuff.
+ */
+ virtual void paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align );
+
+ virtual void paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align );
+
+ private:
+ void paintProgressBar( QPainter* p, const QColorGroup& cgh, int col, int width );
+
+ class ColumnInfo;
+ mutable ColumnInfo* m_columns;
+
+ ColumnInfo* getColumnInfo( int ) const;
+ void init();
+
+ int m_vMargin;
+};
+
+
+class LIBK3B_EXPORT K3bCheckListViewItem : public K3bListViewItem
+{
+ public:
+ K3bCheckListViewItem(QListView *parent);
+ K3bCheckListViewItem(QListViewItem *parent);
+ K3bCheckListViewItem(QListView *parent, QListViewItem *after);
+ K3bCheckListViewItem(QListViewItem *parent, QListViewItem *after);
+
+ virtual bool isChecked() const;
+ virtual void setChecked( bool checked );
+
+ protected:
+ virtual void paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align );
+
+ private:
+ bool m_checked;
+};
+
+
+
+class LIBK3B_EXPORT K3bListView : public KListView
+{
+ friend class K3bListViewItem;
+
+ Q_OBJECT
+
+ public:
+ K3bListView (QWidget *parent = 0, const char *name = 0);
+ virtual ~K3bListView();
+
+ virtual void setCurrentItem( QListViewItem* );
+
+ K3bListViewItem* currentlyEditedItem() const { return m_currentEditItem; }
+
+ QWidget* editor( K3bListViewItem::EditorType ) const;
+
+ enum BgPixPosition {
+ TOP_LEFT,
+ CENTER
+ };
+
+ /**
+ * This will set a background pixmap which is not tiled.
+ * @param pos position on the viewport.
+ */
+ void setK3bBackgroundPixmap( const QPixmap&, int pos = CENTER );
+
+ /**
+ * Create a faded pixmap showing the items.
+ */
+ KPixmap createDragPixmap( const QPtrList<QListViewItem>& items );
+
+ /**
+ * Searches for the first item above @p i which is one level higher.
+ * For 1st level items this will always be the listview's root item.
+ */
+ static QListViewItem* parentItem( QListViewItem* i );
+
+ signals:
+ void editorButtonClicked( K3bListViewItem*, int );
+
+ public slots:
+ void setNoItemText( const QString& );
+ // void setNoItemPixmap( const QPixmap& );
+ void setNoItemVerticalMargin( int i ) { m_noItemVMargin = i; }
+ void setNoItemHorizontalMargin( int i ) { m_noItemHMargin = i; }
+ void setDoubleClickForEdit( bool b ) { m_doubleClickForEdit = b; }
+ void hideEditor();
+ void editItem( K3bListViewItem*, int );
+
+ virtual void clear();
+
+ private slots:
+ void updateEditorSize();
+ virtual void slotEditorLineEditReturnPressed();
+ virtual void slotEditorComboBoxActivated( const QString& );
+ virtual void slotEditorSpinBoxValueChanged( int );
+ virtual void slotEditorMsfEditValueChanged( int );
+ virtual void slotEditorButtonClicked();
+
+ protected slots:
+ void showEditor( K3bListViewItem*, int col );
+ void placeEditor( K3bListViewItem*, int col );
+
+ /**
+ * This is called whenever one of the editor's contents changes
+ * the default implementation just returnes true
+ *
+ * FIXME: should be called something like mayRename
+ */
+ virtual bool renameItem( K3bListViewItem*, int, const QString& );
+
+ /**
+ * default impl just emits signal
+ * editorButtonClicked(...)
+ */
+ virtual void slotEditorButtonClicked( K3bListViewItem*, int );
+
+ protected:
+ /**
+ * calls KListView::drawContentsOffset
+ * and paints a the noItemText if no item is in the list
+ */
+ virtual void drawContentsOffset ( QPainter * p, int ox, int oy, int cx, int cy, int cw, int ch );
+ virtual void resizeEvent( QResizeEvent* );
+ virtual void paintEmptyArea( QPainter*, const QRect& rect );
+
+ /**
+ * Reimplemented for internal reasons.
+ *
+ * Further reimplementations should call this function or else some features may not work correctly.
+ *
+ * The API is unaffected.
+ */
+ virtual void viewportResizeEvent( QResizeEvent* );
+
+ /**
+ * Reimplemented for internal reasons.
+ * Further reimplementations should call this function or else
+ * some features may not work correctly.
+ *
+ * The API is unaffected.
+ */
+ virtual void viewportPaintEvent(QPaintEvent*);
+
+ virtual bool eventFilter( QObject*, QEvent* );
+
+ K3bListViewItem* currentEditItem() const { return m_currentEditItem; }
+ int currentEditColumn() const { return m_currentEditColumn; }
+
+ private:
+ QWidget* prepareEditor( K3bListViewItem* item, int col );
+ void prepareButton( K3bListViewItem* item, int col );
+ bool doRename();
+
+ QString m_noItemText;
+ // QPixmap m_noItemPixmap;
+ int m_noItemVMargin;
+ int m_noItemHMargin;
+
+ K3bListViewItem* m_currentEditItem;
+ int m_currentEditColumn;
+
+ bool m_doubleClickForEdit;
+ QListViewItem* m_lastClickedItem;
+
+ QPushButton* m_editorButton;
+ QComboBox* m_editorComboBox;
+ QSpinBox* m_editorSpinBox;
+ QLineEdit* m_editorLineEdit;
+ K3bMsfEdit* m_editorMsfEdit;
+
+ QPixmap m_backgroundPixmap;
+ int m_backgroundPixmapPosition;
+
+ class Private;
+ Private* d;
+};
+
+
+#endif
diff --git a/libk3b/tools/k3blistviewitemanimator.cpp b/libk3b/tools/k3blistviewitemanimator.cpp
new file mode 100644
index 0000000..1c729b6
--- /dev/null
+++ b/libk3b/tools/k3blistviewitemanimator.cpp
@@ -0,0 +1,137 @@
+/*
+ *
+ * $Id: k3blistviewitemanimator.cpp 689561 2007-07-18 15:19:38Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3blistviewitemanimator.h"
+
+#include <qtimer.h>
+#include <qlistview.h>
+
+#include <kpixmap.h>
+#include <kpixmapeffect.h>
+
+
+K3bListViewItemAnimator::K3bListViewItemAnimator( QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ init();
+}
+
+
+K3bListViewItemAnimator::K3bListViewItemAnimator( QListViewItem* item, int col, QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ init();
+ setItem( item, col );
+}
+
+
+K3bListViewItemAnimator::~K3bListViewItemAnimator()
+{
+}
+
+
+QListViewItem* K3bListViewItemAnimator::item() const
+{
+ return m_item;
+}
+
+
+void K3bListViewItemAnimator::init()
+{
+ m_item = 0;
+ m_column = 0;
+ m_timer = new QTimer( this );
+ connect( m_timer, SIGNAL(timeout()), this, SLOT(slotAnimate()) );
+}
+
+
+void K3bListViewItemAnimator::start()
+{
+ if( m_item && !m_pixmap.isNull() ) {
+ m_animationStep = 0;
+ m_animationBack = false;
+ m_timer->start( 150 );
+ }
+ else
+ stop();
+}
+
+
+void K3bListViewItemAnimator::stop()
+{
+ m_timer->stop();
+}
+
+
+void K3bListViewItemAnimator::setItem( QListViewItem* item, int col )
+{
+ m_item = item;
+ m_column = col;
+ m_pixmap = *item->pixmap(col);
+ m_fadeColor = item->listView()->colorGroup().base();
+ start();
+}
+
+
+void K3bListViewItemAnimator::setPixmap( const QPixmap& p )
+{
+ m_pixmap = p;
+ start();
+}
+
+
+void K3bListViewItemAnimator::setColumn( int col )
+{
+ m_column = col;
+ start();
+}
+
+
+void K3bListViewItemAnimator::setFadeColor( const QColor& c )
+{
+ m_fadeColor = c;
+ start();
+}
+
+
+void K3bListViewItemAnimator::slotAnimate()
+{
+ if( m_item->isVisible() ) {
+ double val = (double)m_animationStep;
+ val /= 10.0;
+ // we need a temp pixmap since KPixmapEffect changes our pixmap
+ KPixmap pix( m_pixmap );
+ m_item->setPixmap( m_column, KPixmapEffect::fade( pix, val, m_fadeColor ) );;
+ }
+
+ if( m_animationBack ) {
+ --m_animationStep;
+ if( m_animationStep < 0 ) {
+ // two steps full
+ m_animationStep = 0;
+ m_animationBack = false;
+ }
+ }
+ else {
+ ++m_animationStep;
+ // do not fade it completely
+ if( m_animationStep > 9 ) {
+ m_animationStep = 8;
+ m_animationBack = true;
+ }
+ }
+}
+
+#include "k3blistviewitemanimator.moc"
diff --git a/libk3b/tools/k3blistviewitemanimator.h b/libk3b/tools/k3blistviewitemanimator.h
new file mode 100644
index 0000000..200079a
--- /dev/null
+++ b/libk3b/tools/k3blistviewitemanimator.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * $Id: k3blistviewitemanimator.h 689561 2007-07-18 15:19:38Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_LISTVIEWITEM_ANIMATOR_H_
+#define _K3B_LISTVIEWITEM_ANIMATOR_H_
+
+#include <qobject.h>
+#include <qpixmap.h>
+#include "k3b_export.h"
+
+class QListViewItem;
+class QTimer;
+
+
+/**
+ * Fades an icon on a listview item in and out.
+ */
+class LIBK3B_EXPORT K3bListViewItemAnimator : public QObject
+{
+ Q_OBJECT
+
+ public:
+ K3bListViewItemAnimator( QObject* parent = 0, const char* name = 0 );
+ /**
+ * Will use the items pixmap.
+ */
+ K3bListViewItemAnimator( QListViewItem* item, int col, QObject* parent = 0, const char* name = 0 );
+ ~K3bListViewItemAnimator();
+
+ QListViewItem* item() const;
+
+ public slots:
+ void start();
+ void stop();
+
+ void setItem( QListViewItem*, int col );
+
+ /**
+ * Default is the pixmap from the item.
+ */
+ void setPixmap( const QPixmap& );
+
+ void setColumn( int col );
+
+ /**
+ * Default is the base color of the listview.
+ */
+ void setFadeColor( const QColor& );
+
+ private slots:
+ void slotAnimate();
+
+ private:
+ void init();
+
+ int m_animationStep;
+ bool m_animationBack;
+ QPixmap m_pixmap;
+ QColor m_fadeColor;
+ QListViewItem* m_item;
+ int m_column;
+
+ QTimer* m_timer;
+};
+
+#endif
diff --git a/libk3b/tools/k3bmd5job.cpp b/libk3b/tools/k3bmd5job.cpp
new file mode 100644
index 0000000..2679f33
--- /dev/null
+++ b/libk3b/tools/k3bmd5job.cpp
@@ -0,0 +1,322 @@
+/*
+ *
+ * $Id: k3bmd5job.cpp 633751 2007-02-15 08:22:49Z trueg $
+ * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3bmd5job.h"
+#include <k3biso9660.h>
+#include <k3bglobals.h>
+#include <k3bdevice.h>
+#include <k3bfilesplitter.h>
+
+#include <kmdcodec.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kio/netaccess.h>
+
+#include <qtimer.h>
+#include <qcstring.h>
+#include <qsocketnotifier.h>
+
+#include <unistd.h>
+
+
+class K3bMd5Job::K3bMd5JobPrivate
+{
+public:
+ K3bMd5JobPrivate()
+ : fileDes(-1),
+ fdNotifier(0),
+ finished(true),
+ data(0),
+ isoFile(0),
+ maxSize(0),
+ lastProgress(0) {
+ }
+
+ KMD5 md5;
+ K3bFileSplitter file;
+ QTimer timer;
+ QString filename;
+ int fileDes;
+ K3bDevice::Device* device;
+ QSocketNotifier* fdNotifier;
+
+ bool finished;
+ char* data;
+ const K3bIso9660File* isoFile;
+
+ unsigned long long maxSize;
+ unsigned long long readData;
+
+ int lastProgress;
+
+ KIO::filesize_t imageSize;
+
+ static const int BUFFERSIZE = 2048*10;
+};
+
+
+K3bMd5Job::K3bMd5Job( K3bJobHandler* jh, QObject* parent, const char* name )
+ : K3bJob( jh, parent, name )
+{
+ d = new K3bMd5JobPrivate;
+ d->data = new char[K3bMd5JobPrivate::BUFFERSIZE];
+ connect( &d->timer, SIGNAL(timeout()),
+ this, SLOT(slotUpdate()) );
+}
+
+
+K3bMd5Job::~K3bMd5Job()
+{
+ delete [] d->data;
+ delete d;
+}
+
+
+void K3bMd5Job::start()
+{
+ cancel();
+
+ jobStarted();
+ d->readData = 0;
+
+ if( d->isoFile ) {
+ d->imageSize = d->isoFile->size();
+ }
+ else if( !d->filename.isEmpty() ) {
+ if( !QFile::exists( d->filename ) ) {
+ emit infoMessage( i18n("Could not find file %1").arg(d->filename), ERROR );
+ jobFinished(false);
+ return;
+ }
+
+ d->file.setName( d->filename );
+ if( !d->file.open( IO_ReadOnly ) ) {
+ emit infoMessage( i18n("Could not open file %1").arg(d->filename), ERROR );
+ jobFinished(false);
+ return;
+ }
+
+ d->imageSize = K3b::filesize( KURL::fromPathOrURL(d->filename) );
+ }
+ else
+ d->imageSize = 0;
+
+ if( d->device ) {
+ //
+ // Let the drive determine the optimal reading speed
+ //
+ d->device->setSpeed( 0xffff, 0xffff );
+ }
+
+ d->md5.reset();
+ d->finished = false;
+ if( d->fileDes != -1 )
+ setupFdNotifier();
+ else
+ d->timer.start(0);
+}
+
+
+void K3bMd5Job::setupFdNotifier()
+{
+ // the QSocketNotifier will fire once the fd is closed
+ delete d->fdNotifier;
+ d->fdNotifier = new QSocketNotifier( d->fileDes, QSocketNotifier::Read, this );
+ connect( d->fdNotifier, SIGNAL(activated(int)), this, SLOT(slotUpdate()) );
+ d->fdNotifier->setEnabled( true );
+}
+
+
+void K3bMd5Job::cancel()
+{
+ if( !d->finished ) {
+ stopAll();
+
+ emit canceled();
+ jobFinished( false );
+ }
+}
+
+
+void K3bMd5Job::setFile( const QString& filename )
+{
+ d->filename = filename;
+ d->isoFile = 0;
+ d->fileDes = -1;
+ d->device = 0;
+}
+
+
+void K3bMd5Job::setFile( const K3bIso9660File* file )
+{
+ d->isoFile = file;
+ d->fileDes = -1;
+ d->filename.truncate(0);
+ d->device = 0;
+}
+
+
+void K3bMd5Job::setFd( int fd )
+{
+ d->fileDes = fd;
+ d->filename.truncate(0);
+ d->isoFile = 0;
+ d->device = 0;
+}
+
+
+void K3bMd5Job::setDevice( K3bDevice::Device* dev )
+{
+ d->device = dev;
+ d->fileDes = -1;
+ d->filename.truncate(0);
+ d->isoFile = 0;
+}
+
+
+void K3bMd5Job::setMaxReadSize( unsigned long long size )
+{
+ d->maxSize = size;
+}
+
+
+void K3bMd5Job::slotUpdate()
+{
+ if( !d->finished ) {
+
+ // determine bytes to read
+ unsigned int readSize = K3bMd5JobPrivate::BUFFERSIZE;
+ if( d->maxSize > 0 )
+ readSize = QMIN( readSize, d->maxSize - d->readData );
+
+ if( readSize <= 0 ) {
+ // kdDebug() << "(K3bMd5Job) reached max size of " << d->maxSize << ". Stopping." << endl;
+ emit debuggingOutput( "K3bMd5Job", QString("Reached max read of %1. Stopping after %2 bytes.").arg(d->maxSize).arg(d->readData) );
+ stopAll();
+ emit percent( 100 );
+ jobFinished(true);
+ }
+ else {
+ int read = 0;
+
+ //
+ // read from the iso9660 file
+ //
+ if( d->isoFile ) {
+ read = d->isoFile->read( d->readData, d->data, readSize );
+ }
+
+ //
+ // read from the device
+ //
+ else if( d->device ) {
+ //
+ // when reading from a device we always read multiples of 2048 bytes.
+ // Only the last sector may not be used completely.
+ //
+ unsigned long sector = d->readData/2048;
+ unsigned int sectorCnt = QMAX( readSize/2048, 1 );
+ read = -1;
+ if( d->device->read10( reinterpret_cast<unsigned char*>(d->data),
+ sectorCnt*2048,
+ sector,
+ sectorCnt ) )
+ read = QMIN( readSize, sectorCnt*2048 );
+ }
+
+ //
+ // read from the file
+ //
+ else if( d->fileDes < 0 ) {
+ read = d->file.readBlock( d->data, readSize );
+ }
+
+ //
+ // reading from the file descriptor
+ //
+ else {
+ read = ::read( d->fileDes, d->data, readSize );
+ }
+
+ if( read < 0 ) {
+ emit infoMessage( i18n("Error while reading from file %1").arg(d->filename), ERROR );
+ stopAll();
+ jobFinished(false);
+ }
+ else if( read == 0 ) {
+ // kdDebug() << "(K3bMd5Job) read all data. Total size: " << d->readData << ". Stopping." << endl;
+ emit debuggingOutput( "K3bMd5Job", QString("All data read. Stopping after %1 bytes.").arg(d->readData) );
+ stopAll();
+ emit percent( 100 );
+ jobFinished(true);
+ }
+ else {
+ d->readData += read;
+ d->md5.update( d->data, read );
+ int progress = 0;
+ if( d->isoFile || !d->filename.isEmpty() )
+ progress = (int)((double)d->readData * 100.0 / (double)d->imageSize);
+ else if( d->maxSize > 0 )
+ progress = (int)((double)d->readData * 100.0 / (double)d->maxSize);
+
+ if( progress != d->lastProgress ) {
+ d->lastProgress = progress;
+ emit percent( progress );
+ }
+ }
+ }
+ }
+}
+
+
+QCString K3bMd5Job::hexDigest()
+{
+ if( d->finished )
+ return d->md5.hexDigest();
+ else
+ return "";
+}
+
+
+QCString K3bMd5Job::base64Digest()
+{
+ if( d->finished )
+ return d->md5.base64Digest();
+ else
+ return "";
+
+}
+
+
+void K3bMd5Job::stop()
+{
+ emit debuggingOutput( "K3bMd5Job", QString("Stopped manually after %1 bytes.").arg(d->readData) );
+ stopAll();
+ jobFinished( true );
+}
+
+
+void K3bMd5Job::stopAll()
+{
+ if( d->fdNotifier )
+ d->fdNotifier->setEnabled( false );
+ if( d->file.isOpen() )
+ d->file.close();
+ d->timer.stop();
+ d->finished = true;
+}
+
+#include "k3bmd5job.moc"
diff --git a/libk3b/tools/k3bmd5job.h b/libk3b/tools/k3bmd5job.h
new file mode 100644
index 0000000..cd64795
--- /dev/null
+++ b/libk3b/tools/k3bmd5job.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * $Id: k3bmd5job.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_MD5_JOB_H_
+#define _K3B_MD5_JOB_H_
+
+#include <k3bjob.h>
+#include <qcstring.h>
+#include "k3b_export.h"
+
+namespace K3bDevice {
+ class Device;
+}
+
+class K3bIso9660File;
+
+
+class LIBK3B_EXPORT K3bMd5Job : public K3bJob
+{
+ Q_OBJECT
+
+ public:
+ K3bMd5Job( K3bJobHandler* jh , QObject* parent = 0, const char* name = 0 );
+ ~K3bMd5Job();
+
+ QCString hexDigest();
+ QCString base64Digest();
+
+ public slots:
+ void start();
+ void stop();
+ void cancel();
+
+ // FIXME: read from QIODevice and thus add K3bFileSplitter support
+
+ /**
+ * read from a file.
+ *
+ * Be aware that the K3bMd5Job uses K3bFileSplitter to read splitted
+ * images. In the future this will be changed with the introduction
+ * of a setIODevice method.
+ */
+ void setFile( const QString& filename );
+
+ /**
+ * read from an iso9660 file
+ */
+ void setFile( const K3bIso9660File* );
+
+ /**
+ * read from a device
+ * This should be used in combination with setMaxReadSize
+ */
+ void setDevice( K3bDevice::Device* dev );
+
+ /**
+ * read from the opened file descriptor.
+ * One needs to set the max read length or call stop()
+ * to finish calculation.
+ */
+ void setFd( int fd );
+
+ /**
+ * Set the maximum bytes to read.
+ */
+ void setMaxReadSize( unsigned long long );
+
+ private slots:
+ void slotUpdate();
+
+ private:
+ void setupFdNotifier();
+ void stopAll();
+
+ class K3bMd5JobPrivate;
+ K3bMd5JobPrivate* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bmsfedit.cpp b/libk3b/tools/k3bmsfedit.cpp
new file mode 100644
index 0000000..13ad0a3
--- /dev/null
+++ b/libk3b/tools/k3bmsfedit.cpp
@@ -0,0 +1,153 @@
+/*
+ *
+ * $Id: k3bmsfedit.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+
+#include "k3bmsfedit.h"
+#include "k3bglobals.h"
+
+#include <qstringlist.h>
+#include <qlineedit.h>
+#include <qstyle.h>
+#include <qfontmetrics.h>
+#include <qapplication.h>
+
+
+
+K3bMsfValidator::K3bMsfValidator( QObject* parent, const char* name )
+ : QRegExpValidator( K3b::Msf::regExp(), parent, name )
+{
+}
+
+
+
+K3bMsfEdit::K3bMsfEdit( QWidget* parent, const char* name )
+ : QSpinBox( parent, name )
+{
+ setValidator( new K3bMsfValidator( this ) );
+ setMinValue( 0 );
+ // some very high value (10000 minutes)
+ setMaxValue( 10000*60*75 );
+
+ connect( this, SIGNAL(valueChanged(int)),
+ this, SLOT(slotValueChanged(int)) );
+}
+
+
+K3bMsfEdit::~K3bMsfEdit()
+{}
+
+
+QSize K3bMsfEdit::sizeHint() const
+{
+ // more or less copied from QSpinBox
+ constPolish();
+ QSize sz = editor()->sizeHint();
+ int h = sz.height();
+ QFontMetrics fm( font() );
+ int w = fm.width( "00:00:00" );
+ int wx = fm.width( ' ' )*2;
+ int frame = style().pixelMetric( QStyle::PM_SpinBoxFrameWidth );
+ return style().sizeFromContents(QStyle::CT_SpinBox, this,
+ QSize( w + wx + downRect().width() + frame*2,
+ h + frame*2).
+ expandedTo( QApplication::globalStrut() ));
+}
+
+
+QString K3bMsfEdit::mapValueToText( int value )
+{
+ return K3b::framesToString( value, true );
+}
+
+
+K3b::Msf K3bMsfEdit::msfValue() const
+{
+ return K3b::Msf(value());
+}
+
+
+void K3bMsfEdit::setMsfValue( const K3b::Msf& msf )
+{
+ setValue( msf.totalFrames() );
+}
+
+
+int K3bMsfEdit::mapTextToValue( bool* ok )
+{
+ return K3b::Msf::fromString( text(), ok ).lba();
+}
+
+
+void K3bMsfEdit::setText( const QString& str )
+{
+ bool ok;
+ editor()->setText( str );
+ setValue( mapTextToValue( &ok) );
+}
+
+
+void K3bMsfEdit::setFrameStyle( int style )
+{
+ editor()->setFrameStyle( style );
+}
+
+void K3bMsfEdit::setLineWidth( int v )
+{
+ editor()->setLineWidth( v );
+}
+
+void K3bMsfEdit::setValue( int v )
+{
+ int i = editor()->cursorPosition();
+ QSpinBox::setValue( v );
+ editor()->setCursorPosition( i );
+}
+
+void K3bMsfEdit::stepUp()
+{
+ setValue( value() + currentStepValue() );
+}
+
+void K3bMsfEdit::stepDown()
+{
+ setValue( value() - currentStepValue() );
+}
+
+int K3bMsfEdit::currentStepValue() const
+{
+ int val = 1;
+
+ // look if we are currently editing minutes or seconds
+ QString text = editor()->text();
+ if( text.length() == 8 ) {
+ text = text.mid( editor()->cursorPosition() );
+ int num = text.contains( ':' );
+ if( num == 1 )
+ val = 75;
+ else if( num == 2 )
+ val = 60*75;
+ }
+
+ return val;
+}
+
+
+void K3bMsfEdit::slotValueChanged( int v )
+{
+ emit valueChanged( K3b::Msf(v) );
+}
+
+#include "k3bmsfedit.moc"
diff --git a/libk3b/tools/k3bmsfedit.h b/libk3b/tools/k3bmsfedit.h
new file mode 100644
index 0000000..c573910
--- /dev/null
+++ b/libk3b/tools/k3bmsfedit.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * $Id: k3bmsfedit.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef K3B_MSF_EDIT_H
+#define K3B_MSF_EDIT_H
+
+
+#include <qspinbox.h>
+#include <qstring.h>
+#include <qvalidator.h>
+
+#include <k3bmsf.h>
+#include "k3b_export.h"
+
+class K3bMsfValidator : public QRegExpValidator
+{
+ public:
+ K3bMsfValidator( QObject* parent = 0, const char* name = 0 );
+};
+
+
+class LIBK3B_EXPORT K3bMsfEdit : public QSpinBox
+{
+ Q_OBJECT
+
+ public:
+ K3bMsfEdit( QWidget* parent = 0, const char* name = 0 );
+ ~K3bMsfEdit();
+
+ QSize sizeHint() const;
+
+ void setFrameStyle( int style );
+ void setLineWidth(int);
+
+ K3b::Msf msfValue() const;
+
+ signals:
+ void valueChanged( const K3b::Msf& );
+
+ public slots:
+ void setValue( int v );
+ void setText( const QString& );
+ void setMsfValue( const K3b::Msf& );
+ void stepUp();
+ void stepDown();
+
+ protected:
+ QString mapValueToText( int );
+ int mapTextToValue( bool* ok );
+ int currentStepValue() const;
+
+ private slots:
+ void slotValueChanged( int );
+};
+
+
+#endif
diff --git a/libk3b/tools/k3bmultichoicedialog.cpp b/libk3b/tools/k3bmultichoicedialog.cpp
new file mode 100644
index 0000000..4c12554
--- /dev/null
+++ b/libk3b/tools/k3bmultichoicedialog.cpp
@@ -0,0 +1,191 @@
+/*
+ *
+ * $Id: k3bmultichoicedialog.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bmultichoicedialog.h"
+#include "k3bstdguiitems.h"
+#include <k3brichtextlabel.h>
+
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+
+#include <qlayout.h>
+#include <qsignalmapper.h>
+#include <qptrlist.h>
+#include <qlabel.h>
+#include <qhbox.h>
+#include <qmessagebox.h>
+
+
+class K3bMultiChoiceDialog::Private
+{
+public:
+ Private()
+ : mapper(0),
+ buttonLayout(0) {
+ }
+
+ QSignalMapper* mapper;
+ QPtrList<KPushButton> buttons;
+ QHBoxLayout* buttonLayout;
+
+ bool buttonClicked;
+};
+
+
+// from kmessagebox.cpp
+static QPixmap themedMessageBoxIcon(QMessageBox::Icon icon)
+{
+ QString icon_name;
+
+ switch(icon) {
+ case QMessageBox::NoIcon:
+ return QPixmap();
+ break;
+ case QMessageBox::Information:
+ icon_name = "messagebox_info";
+ break;
+ case QMessageBox::Warning:
+ icon_name = "messagebox_warning";
+ break;
+ case QMessageBox::Critical:
+ icon_name = "messagebox_critical";
+ break;
+ default:
+ break;
+ }
+
+ QPixmap ret = KApplication::kApplication()->iconLoader()->loadIcon(icon_name, KIcon::NoGroup, KIcon::SizeMedium, KIcon::DefaultState, 0, true);
+
+ if (ret.isNull())
+ return QMessageBox::standardIcon(icon);
+ else
+ return ret;
+}
+
+K3bMultiChoiceDialog::K3bMultiChoiceDialog( const QString& caption,
+ const QString& text,
+ QMessageBox::Icon icon,
+ QWidget* parent, const char* name )
+ : KDialog( parent, name )
+{
+ d = new Private();
+ d->mapper = new QSignalMapper( this );
+ connect( d->mapper, SIGNAL(mapped(int)), this, SLOT(done(int)) );
+
+ setCaption( caption );
+
+ QGridLayout* mainGrid = new QGridLayout( this );
+ mainGrid->setSpacing( spacingHint() );
+ mainGrid->setMargin( marginHint() );
+
+ QHBox* contents = new QHBox( this );
+ contents->setSpacing( KDialog::spacingHint()*2 );
+ contents->setMargin( 0 );
+
+ QLabel* pixLabel = new QLabel( contents );
+ pixLabel->setPixmap( themedMessageBoxIcon( icon ) );
+ pixLabel->setScaledContents( false );
+ QLabel* label = new K3bRichTextLabel( text, contents );
+ contents->setStretchFactor( label, 1 );
+
+ d->buttonLayout = new QHBoxLayout;
+ d->buttonLayout->setSpacing( spacingHint() );
+ d->buttonLayout->setMargin( 0 );
+
+ mainGrid->addMultiCellWidget( contents, 0, 0, 0, 2 );
+ mainGrid->addMultiCellWidget( K3bStdGuiItems::horizontalLine( this ), 1, 1, 0, 2 );
+ mainGrid->addLayout( d->buttonLayout, 2, 1 );
+
+ mainGrid->setColStretch( 0, 1 );
+ mainGrid->setColStretch( 2, 1 );
+ mainGrid->setRowStretch( 0, 1 );
+}
+
+
+K3bMultiChoiceDialog::~K3bMultiChoiceDialog()
+{
+ delete d;
+}
+
+
+int K3bMultiChoiceDialog::addButton( const KGuiItem& b )
+{
+ KPushButton* button = new KPushButton( b, this );
+ d->buttonLayout->add( button );
+ d->buttons.append(button);
+ d->mapper->setMapping( button, d->buttons.count() );
+ connect( button, SIGNAL(clicked()), d->mapper, SLOT(map()) );
+ return d->buttons.count();
+}
+
+
+void K3bMultiChoiceDialog::slotButtonClicked( int code )
+{
+ d->buttonClicked = true;
+ done( code );
+}
+
+
+int K3bMultiChoiceDialog::exec()
+{
+ d->buttonClicked = false;
+ return KDialog::exec();
+}
+
+
+void K3bMultiChoiceDialog::closeEvent( QCloseEvent* e )
+{
+ // make sure the dialog can only be closed by the buttons
+ // otherwise we may get an undefined return value in exec
+
+ if( d->buttonClicked )
+ KDialog::closeEvent( e );
+ else
+ e->ignore();
+}
+
+
+int K3bMultiChoiceDialog::choose( const QString& caption,
+ const QString& text,
+ QMessageBox::Icon icon,
+ QWidget* parent,
+ const char* name,
+ int buttonCount,
+ const KGuiItem& b1,
+ const KGuiItem& b2,
+ const KGuiItem& b3,
+ const KGuiItem& b4,
+ const KGuiItem& b5,
+ const KGuiItem& b6 )
+{
+ K3bMultiChoiceDialog dlg( caption, text, icon, parent, name );
+ dlg.addButton( b1 );
+ if( buttonCount > 1 )
+ dlg.addButton( b2 );
+ if( buttonCount > 2 )
+ dlg.addButton( b3 );
+ if( buttonCount > 3 )
+ dlg.addButton( b4 );
+ if( buttonCount > 4 )
+ dlg.addButton( b5 );
+ if( buttonCount > 5 )
+ dlg.addButton( b6 );
+
+ return dlg.exec();
+}
+
+
+#include "k3bmultichoicedialog.moc"
diff --git a/libk3b/tools/k3bmultichoicedialog.h b/libk3b/tools/k3bmultichoicedialog.h
new file mode 100644
index 0000000..f293fef
--- /dev/null
+++ b/libk3b/tools/k3bmultichoicedialog.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * $Id: k3bmultichoicedialog.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_MULTI_CHOICE_DIALOG_H_
+#define _K3B_MULTI_CHOICE_DIALOG_H_
+
+#include <kdialog.h>
+#include <kstdguiitem.h>
+#include "k3b_export.h"
+
+#include <qmessagebox.h>
+
+
+class QCloseEvent;
+
+class LIBK3B_EXPORT K3bMultiChoiceDialog : public KDialog
+{
+ Q_OBJECT
+
+ public:
+ K3bMultiChoiceDialog( const QString& caption,
+ const QString& text,
+ QMessageBox::Icon = QMessageBox::Information,
+ QWidget* parent = 0, const char* name = 0 );
+ ~K3bMultiChoiceDialog();
+
+ /**
+ * Adds a new button. returns it's number starting at 1.
+ */
+ int addButton( const KGuiItem& );
+
+ static int choose( const QString& caption,
+ const QString& text,
+ QMessageBox::Icon = QMessageBox::Information,
+ QWidget* parent = 0,
+ const char* name = 0,
+ int buttonCount = 2,
+ const KGuiItem& b1 = KStdGuiItem::yes(),
+ const KGuiItem& b2 = KStdGuiItem::no(),
+ const KGuiItem& b3 = KStdGuiItem::no(),
+ const KGuiItem& b4 = KStdGuiItem::no(),
+ const KGuiItem& b5 = KStdGuiItem::no(),
+ const KGuiItem& b6 = KStdGuiItem::no() );
+
+ public slots:
+ /**
+ * returnes the number of the clicked button starting at 1.
+ */
+ int exec();
+
+ private slots:
+ void slotButtonClicked( int );
+
+ private:
+ void closeEvent( QCloseEvent* );
+
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bpipe.cpp b/libk3b/tools/k3bpipe.cpp
new file mode 100644
index 0000000..6f15915
--- /dev/null
+++ b/libk3b/tools/k3bpipe.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bpipe.h"
+
+#include <kdebug.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+
+K3bPipe::K3bPipe()
+{
+ m_fd[0] = m_fd[1] = -1;
+}
+
+
+K3bPipe::~K3bPipe()
+{
+ close();
+}
+
+
+bool K3bPipe::open()
+{
+ close();
+
+ if( ::socketpair( AF_UNIX, SOCK_STREAM, 0, m_fd ) == 0 ) {
+ fcntl( m_fd[0], F_SETFD, FD_CLOEXEC );
+ fcntl( m_fd[1], F_SETFD, FD_CLOEXEC );
+ return true;
+ }
+ else {
+ kdDebug() << "(K3bPipe) failed to setup socket pair." << endl;
+ return false;
+ }
+}
+
+
+void K3bPipe::closeIn()
+{
+ if( m_fd[1] != -1 ) {
+ ::close( m_fd[1] );
+ m_fd[1] = -1;
+ }
+}
+
+
+void K3bPipe::closeOut()
+{
+ if( m_fd[0] != -1 ) {
+ ::close( m_fd[0] );
+ m_fd[0] = -1;
+ }
+}
+
+
+void K3bPipe::close()
+{
+ closeIn();
+ closeOut();
+}
diff --git a/libk3b/tools/k3bpipe.h b/libk3b/tools/k3bpipe.h
new file mode 100644
index 0000000..fba3455
--- /dev/null
+++ b/libk3b/tools/k3bpipe.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_PIPE_H_
+#define _K3B_PIPE_H_
+
+#include "k3b_export.h"
+
+/**
+ * The K3bPipe class represents a file descriptor pair
+ * which can for example be used to connect two processes
+ */
+class LIBK3B_EXPORT K3bPipe
+{
+ public:
+ /**
+ * Creates a closed pipe object
+ */
+ K3bPipe();
+
+ /**
+ * The destructor takes care of closing the pipe
+ */
+ ~K3bPipe();
+
+ /**
+ * Open the pipe. This creates a file descriptor pair
+ * which can be accessed using the in() and out()
+ * methods.
+ */
+ bool open();
+
+ /**
+ * Calls both closeIn() and closeOut()
+ */
+ void close();
+
+ void closeIn();
+ void closeOut();
+
+ int in() const { return m_fd[1]; }
+ int out() const { return m_fd[0]; }
+
+ private:
+ int m_fd[2];
+};
+
+#endif
diff --git a/libk3b/tools/k3bprogressdialog.cpp b/libk3b/tools/k3bprogressdialog.cpp
new file mode 100644
index 0000000..69a81f5
--- /dev/null
+++ b/libk3b/tools/k3bprogressdialog.cpp
@@ -0,0 +1,107 @@
+/*
+ *
+ * $Id: k3bprogressdialog.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bprogressdialog.h"
+
+#include <k3bbusywidget.h>
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qframe.h>
+#include <qwidgetstack.h>
+
+#include <klocale.h>
+#include <kprogress.h>
+
+
+K3bProgressDialog::K3bProgressDialog( const QString& text,
+ QWidget* parent,
+ const QString& caption,
+ const char* name )
+ : KDialogBase( parent, name, true, caption, Cancel|Ok, Ok, true )
+{
+ QFrame* main = makeMainWidget();
+ QGridLayout* mainLayout = new QGridLayout( main );
+ mainLayout->setMargin( marginHint() );
+ mainLayout->setSpacing( spacingHint() );
+
+ m_label = new QLabel( text, main );
+ m_stack = new QWidgetStack( main );
+ m_progressBar = new KProgress( m_stack );
+ m_busyWidget = new K3bBusyWidget( m_stack );
+ m_stack->addWidget( m_progressBar );
+ m_stack->addWidget( m_busyWidget );
+
+ mainLayout->addWidget( m_label, 0, 0 );
+ mainLayout->addWidget( m_stack, 1, 0 );
+
+ showButtonOK( false );
+}
+
+
+K3bProgressDialog::~K3bProgressDialog()
+{}
+
+
+int K3bProgressDialog::exec( bool progress )
+{
+ if( progress )
+ m_stack->raiseWidget( m_progressBar );
+ else
+ m_stack->raiseWidget( m_busyWidget );
+
+ m_busyWidget->showBusy( !progress );
+
+ actionButton( Cancel )->setEnabled(true);
+
+ return KDialogBase::exec();
+}
+
+
+void K3bProgressDialog::setText( const QString& text )
+{
+ m_label->setText( text );
+}
+
+
+void K3bProgressDialog::slotFinished( bool success )
+{
+ m_busyWidget->showBusy( false );
+
+ showButtonOK( true );
+ showButtonCancel( false );
+
+ if( success )
+ m_label->setText( i18n("Disk successfully erased. Please reload the disk.") );
+ else
+ m_label->setText( i18n("K3b was unable to erase the disk.") );
+}
+
+
+void K3bProgressDialog::slotCancel()
+{
+ emit cancelClicked();
+ // we simply forbid to click cancel twice
+ actionButton( Cancel )->setEnabled(false);
+}
+
+
+void K3bProgressDialog::setProgress( int p )
+{
+ m_progressBar->setProgress( p );
+}
+
+#include "k3bprogressdialog.moc"
diff --git a/libk3b/tools/k3bprogressdialog.h b/libk3b/tools/k3bprogressdialog.h
new file mode 100644
index 0000000..32a0544
--- /dev/null
+++ b/libk3b/tools/k3bprogressdialog.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * $Id: k3bprogressdialog.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_PROGRESS_DIALOG_H_
+#define _K3B_PROGRESS_DIALOG_H_
+
+#include <kdialogbase.h>
+#include "k3b_export.h"
+
+class K3bBusyWidget;
+class QLabel;
+class KProgress;
+class QWidgetStack;
+
+
+/**
+ * A progressdialog which displays a line of text and a progress
+ * bar or a moving dot for tasks that do not provide any progress
+ * information.
+ */
+class LIBK3B_EXPORT K3bProgressDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ K3bProgressDialog( const QString& text = QString::null,
+ QWidget* parent = 0,
+ const QString& caption = QString::null,
+ const char* name = 0 );
+ ~K3bProgressDialog();
+
+ int exec( bool showProgress );
+
+ public slots:
+ void setText( const QString& );
+ void slotFinished( bool success );
+ void setProgress( int p );
+
+ private slots:
+ void slotCancel();
+
+ private:
+ QLabel* m_label;
+ QWidgetStack* m_stack;
+ K3bBusyWidget* m_busyWidget;
+ KProgress* m_progressBar;
+};
+
+
+#endif
diff --git a/libk3b/tools/k3bpushbutton.cpp b/libk3b/tools/k3bpushbutton.cpp
new file mode 100644
index 0000000..11425ad
--- /dev/null
+++ b/libk3b/tools/k3bpushbutton.cpp
@@ -0,0 +1,136 @@
+/*
+ *
+ * $Id: k3bpushbutton.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bpushbutton.h"
+
+#include <qtimer.h>
+#include <qpopupmenu.h>
+#include <qevent.h>
+
+#include <kglobalsettings.h>
+#include <kapplication.h>
+
+
+
+class K3bPushButton::Private
+{
+public:
+ Private()
+ : popupTimer(0) {
+ }
+
+ QTimer* popupTimer;
+ QPoint mousePressPos;
+};
+
+
+
+K3bPushButton::K3bPushButton( QWidget* parent, const char* name )
+ : KPushButton( parent, name )
+{
+ d = new Private();
+ installEventFilter(this);
+}
+
+
+K3bPushButton::K3bPushButton( const QString& text, QWidget* parent, const char* name )
+ : KPushButton( text, parent, name )
+{
+ d = new Private();
+ installEventFilter(this);
+}
+
+
+K3bPushButton::K3bPushButton( const QIconSet& icon, const QString& text,
+ QWidget* parent, const char* name )
+ : KPushButton( icon, text, parent, name )
+{
+ d = new Private();
+ installEventFilter(this);
+}
+
+
+K3bPushButton::K3bPushButton( const KGuiItem& item, QWidget* parent, const char* name )
+ : KPushButton( item, parent, name )
+{
+ d = new Private();
+ installEventFilter(this);
+}
+
+
+K3bPushButton::~K3bPushButton()
+{
+ delete d;
+}
+
+
+void K3bPushButton::setDelayedPopupMenu( QPopupMenu* popup )
+{
+ if( !d->popupTimer ) {
+ d->popupTimer = new QTimer( this );
+ connect( d->popupTimer, SIGNAL(timeout()), this, SLOT(slotDelayedPopup()) );
+ }
+
+ setPopup( popup );
+
+ // we need to do the popup handling ourselves so we cheat a little
+ // QPushButton connects a popup slot to the pressed signal which we disconnect here
+ disconnect( this );
+}
+
+
+bool K3bPushButton::eventFilter( QObject* o, QEvent* ev )
+{
+ if( dynamic_cast<K3bPushButton*>(o) == this ) {
+
+ // Popup the menu when the left mousebutton is pressed and the mouse
+ // is moved by a small distance.
+ if( popup() ) {
+ if( ev->type() == QEvent::MouseButtonPress ) {
+ QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
+ d->mousePressPos = mev->pos();
+ d->popupTimer->start( QApplication::startDragTime() );
+ }
+ else if( ev->type() == QEvent::MouseMove ) {
+ QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
+ if( ( mev->pos() - d->mousePressPos).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
+ d->popupTimer->stop();
+ slotDelayedPopup();
+ return true;
+ }
+ }
+ }
+ }
+
+ return KPushButton::eventFilter( o, ev );
+}
+
+
+void K3bPushButton::slotDelayedPopup()
+{
+ d->popupTimer->stop();
+
+ if( isDown() ) {
+ // popup the menu.
+ // this has been taken from the QPushButton code
+ if( mapToGlobal( QPoint( 0, rect().bottom() ) ).y() + popup()->sizeHint().height() <= qApp->desktop()->height() )
+ popup()->exec( mapToGlobal( rect().bottomLeft() ) );
+ else
+ popup()->exec( mapToGlobal( rect().topLeft() - QPoint( 0, popup()->sizeHint().height() ) ) );
+ setDown( false );
+ }
+}
+
+#include "k3bpushbutton.moc"
diff --git a/libk3b/tools/k3bpushbutton.h b/libk3b/tools/k3bpushbutton.h
new file mode 100644
index 0000000..1369af3
--- /dev/null
+++ b/libk3b/tools/k3bpushbutton.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * $Id: k3bpushbutton.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_PUSH_BUTTON_H_
+#define _K3B_PUSH_BUTTON_H_
+
+
+#include <kpushbutton.h>
+#include "k3b_export.h"
+
+/**
+ * A pushbutton with delayed popu pmenu support just like the KToolBarButton
+ */
+class LIBK3B_EXPORT K3bPushButton : public KPushButton
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Default constructor.
+ */
+ K3bPushButton( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Constructor, that sets the button-text to @p text
+ */
+ K3bPushButton( const QString& text, QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Constructor, that sets an icon and the button-text to @p text
+ */
+ K3bPushButton( const QIconSet& icon, const QString& text,
+ QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Constructor that takes a KGuiItem for the text, the icon, the tooltip
+ * and the what's this help
+ */
+ K3bPushButton( const KGuiItem& item, QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destructs the button.
+ */
+ ~K3bPushButton();
+
+ /**
+ * The popup menu will show if the button is pressed down for about half a second
+ * or if the mouse is moved while pressed just like the KToolBarButton.
+ */
+ void setDelayedPopupMenu( QPopupMenu* );
+
+ protected:
+ virtual bool eventFilter( QObject*, QEvent* );
+
+ private slots:
+ void slotDelayedPopup();
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bradioaction.cpp b/libk3b/tools/k3bradioaction.cpp
new file mode 100644
index 0000000..08fbece
--- /dev/null
+++ b/libk3b/tools/k3bradioaction.cpp
@@ -0,0 +1,94 @@
+/*
+ *
+ * $Id: k3bradioaction.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bradioaction.h"
+
+#include <ktoolbarbutton.h>
+
+K3bRadioAction::K3bRadioAction( const QString& text, const KShortcut& cut,
+ QObject* parent, const char* name )
+ : KToggleAction( text, cut, parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+K3bRadioAction::K3bRadioAction( const QString& text, const KShortcut& cut,
+ const QObject* receiver, const char* slot,
+ QObject* parent, const char* name )
+ : KToggleAction( text, cut, receiver, slot, parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+K3bRadioAction::K3bRadioAction( const QString& text, const QIconSet& pix,
+ const KShortcut& cut,
+ QObject* parent, const char* name )
+ : KToggleAction( text, pix, cut, parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+K3bRadioAction::K3bRadioAction( const QString& text, const QString& pix,
+ const KShortcut& cut,
+ QObject* parent, const char* name )
+ : KToggleAction( text, pix, cut, parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+K3bRadioAction::K3bRadioAction( const QString& text, const QIconSet& pix,
+ const KShortcut& cut,
+ const QObject* receiver, const char* slot,
+ QObject* parent, const char* name )
+ : KToggleAction( text, pix, cut, receiver, slot, parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+K3bRadioAction::K3bRadioAction( const QString& text, const QString& pix,
+ const KShortcut& cut,
+ const QObject* receiver, const char* slot,
+ QObject* parent, const char* name )
+ : KToggleAction( text, pix, cut, receiver, slot, parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+K3bRadioAction::K3bRadioAction( QObject* parent, const char* name )
+ : KToggleAction( parent, name ),
+ m_alwaysEmit(false)
+{
+}
+
+void K3bRadioAction::slotActivated()
+{
+ if( isChecked() ) {
+ if( m_alwaysEmit )
+ emit activated();
+
+ const QObject *senderObj = sender();
+
+ if ( !senderObj || !::qt_cast<const KToolBarButton *>( senderObj ) )
+ return;
+
+ const_cast<KToolBarButton *>( static_cast<const KToolBarButton *>( senderObj ) )->on( true );
+
+ return;
+ }
+
+ KToggleAction::slotActivated();
+}
+
+#include "k3bradioaction.moc"
diff --git a/libk3b/tools/k3bradioaction.h b/libk3b/tools/k3bradioaction.h
new file mode 100644
index 0000000..104b598
--- /dev/null
+++ b/libk3b/tools/k3bradioaction.h
@@ -0,0 +1,122 @@
+/*
+ *
+ * $Id: k3bradioaction.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_RADIO_ACTION_H_
+#define _K3B_RADIO_ACTION_H_
+
+#include <kactionclasses.h>
+#include "k3b_export.h"
+
+/**
+ * This differs from KRadioAction only in the boolean
+ * flag which says if it should always emit the signals
+ * even if it was checked twice.
+ *
+ * Docu copied from kdelibs
+ */
+class LIBK3B_EXPORT K3bRadioAction : public KToggleAction
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructs a radio action with text and potential keyboard
+ * accelerator but nothing else. Use this only if you really
+ * know what you are doing.
+ *
+ * @param text The text that will be displayed.
+ * @param cut The corresponding keyboard accelerator (shortcut).
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( const QString& text, const KShortcut& cut = KShortcut(), QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * @param text The text that will be displayed.
+ * @param cut The corresponding keyboard accelerator (shortcut).
+ * @param receiver The SLOT's parent.
+ * @param slot The SLOT to invoke to execute this action.
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( const QString& text, const KShortcut& cut,
+ const QObject* receiver, const char* slot, QObject* parent, const char* name = 0 );
+
+ /**
+ * @param text The text that will be displayed.
+ * @param pix The icons that go with this action.
+ * @param cut The corresponding keyboard accelerator (shortcut).
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( const QString& text, const QIconSet& pix, const KShortcut& cut = KShortcut(),
+ QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * @param text The text that will be displayed.
+ * @param pix The dynamically loaded icon that goes with this action.
+ * @param cut The corresponding keyboard accelerator (shortcut).
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( const QString& text, const QString& pix, const KShortcut& cut = KShortcut(),
+ QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * @param text The text that will be displayed.
+ * @param pix The icons that go with this action.
+ * @param cut The corresponding keyboard accelerator (shortcut).
+ * @param receiver The SLOT's parent.
+ * @param slot The SLOT to invoke to execute this action.
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( const QString& text, const QIconSet& pix, const KShortcut& cut,
+ const QObject* receiver, const char* slot, QObject* parent, const char* name = 0 );
+
+ /**
+ * @param text The text that will be displayed.
+ * @param pix The dynamically loaded icon that goes with this action.
+ * @param cut The corresponding keyboard accelerator (shortcut).
+ * @param receiver The SLOT's parent.
+ * @param slot The SLOT to invoke to execute this action.
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( const QString& text, const QString& pix, const KShortcut& cut,
+ const QObject* receiver, const char* slot,
+ QObject* parent, const char* name = 0 );
+
+ /**
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ K3bRadioAction( QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * @param b if true the action will always emit the activated signal
+ * even if the toggled state did not change. The default is false.
+ * which is the same behaviour as KRadioAction
+ */
+ void setAlwaysEmitActivated( bool b ) { m_alwaysEmit = b; }
+
+ protected:
+ virtual void slotActivated();
+
+ private:
+ bool m_alwaysEmit;
+};
+
+#endif
diff --git a/libk3b/tools/k3brichtextlabel.cpp b/libk3b/tools/k3brichtextlabel.cpp
new file mode 100644
index 0000000..747bba1
--- /dev/null
+++ b/libk3b/tools/k3brichtextlabel.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * $Id: k3brichtextlabel.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2005 Waldo Bastian <bastian@kde.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3brichtextlabel.h"
+
+#include <qtooltip.h>
+#include <qstylesheet.h>
+#include <qsimplerichtext.h>
+
+#include <kglobalsettings.h>
+
+static QString qrichtextify( const QString& text )
+{
+ if ( text.isEmpty() || text[0] == '<' )
+ return text;
+
+ QStringList lines = QStringList::split('\n', text);
+ for(QStringList::Iterator it = lines.begin(); it != lines.end(); ++it)
+ {
+ *it = QStyleSheet::convertFromPlainText( *it, QStyleSheetItem::WhiteSpaceNormal );
+ }
+
+ return lines.join(QString::null);
+}
+
+K3bRichTextLabel::K3bRichTextLabel( const QString &text , QWidget *parent, const char *name )
+ : QLabel ( parent, name ) {
+ m_defaultWidth = QMIN(400, KGlobalSettings::desktopGeometry(this).width()*2/5);
+ setAlignment( Qt::WordBreak );
+ setText(text);
+}
+
+K3bRichTextLabel::K3bRichTextLabel( QWidget *parent, const char *name )
+ : QLabel ( parent, name ) {
+ m_defaultWidth = QMIN(400, KGlobalSettings::desktopGeometry(this).width()*2/5);
+ setAlignment( Qt::WordBreak );
+}
+
+void K3bRichTextLabel::setDefaultWidth(int defaultWidth)
+{
+ m_defaultWidth = defaultWidth;
+ updateGeometry();
+}
+
+QSizePolicy K3bRichTextLabel::sizePolicy() const
+{
+ return QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum, false);
+}
+
+QSize K3bRichTextLabel::minimumSizeHint() const
+{
+ QString qt_text = qrichtextify( text() );
+ int pref_width = 0;
+ int pref_height = 0;
+ QSimpleRichText rt(qt_text, font());
+ pref_width = m_defaultWidth;
+ rt.setWidth(pref_width);
+ int used_width = rt.widthUsed();
+ if (used_width <= pref_width)
+ {
+ while(true)
+ {
+ int new_width = (used_width * 9) / 10;
+ rt.setWidth(new_width);
+ int new_height = rt.height();
+ if (new_height > pref_height)
+ break;
+ used_width = rt.widthUsed();
+ if (used_width > new_width)
+ break;
+ }
+ pref_width = used_width;
+ }
+ else
+ {
+ if (used_width > (pref_width *2))
+ pref_width = pref_width *2;
+ else
+ pref_width = used_width;
+ }
+
+ return QSize(pref_width, rt.height());
+}
+
+QSize K3bRichTextLabel::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+void K3bRichTextLabel::setText( const QString &text ) {
+ QLabel::setText(text);
+}
+
+void K3bRichTextLabel::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "k3brichtextlabel.moc"
diff --git a/libk3b/tools/k3brichtextlabel.h b/libk3b/tools/k3brichtextlabel.h
new file mode 100644
index 0000000..0a25395
--- /dev/null
+++ b/libk3b/tools/k3brichtextlabel.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * $Id: k3brichtextlabel.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2005 Waldo Bastian <bastian@kde.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef K3BRICHTEXTLABEL_H
+#define K3BRICHTEXTLABEL_H
+
+#include <qlabel.h>
+
+#include <k3b_export.h>
+
+/**
+ * @short A replacement for QLabel that supports richtext and proper layout management
+ *
+ * @author Waldo Bastian <bastian@kde.org>
+ */
+
+/*
+ * QLabel
+ */
+class LIBK3B_EXPORT K3bRichTextLabel : public QLabel {
+ Q_OBJECT
+
+public:
+ /**
+ * Default constructor.
+ */
+ K3bRichTextLabel( QWidget *parent, const char *name = 0 );
+ K3bRichTextLabel( const QString &text, QWidget *parent, const char *name = 0 );
+
+ int defaultWidth() const { return m_defaultWidth; }
+ void setDefaultWidth(int defaultWidth);
+
+ virtual QSize minimumSizeHint() const;
+ virtual QSize sizeHint() const;
+ QSizePolicy sizePolicy() const;
+
+public slots:
+ void setText( const QString & );
+
+protected:
+ int m_defaultWidth;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class K3bRichTextLabelPrivate;
+ K3bRichTextLabelPrivate *d;
+};
+
+#endif // K3BRICHTEXTLABEL_H
diff --git a/libk3b/tools/k3bsignalwaiter.cpp b/libk3b/tools/k3bsignalwaiter.cpp
new file mode 100644
index 0000000..fcee2e0
--- /dev/null
+++ b/libk3b/tools/k3bsignalwaiter.cpp
@@ -0,0 +1,62 @@
+/*
+ *
+ * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bsignalwaiter.h"
+#include "k3bjob.h"
+
+#include <qeventloop.h>
+#include <qapplication.h>
+
+
+K3bSignalWaiter::K3bSignalWaiter()
+ : QObject(),
+ m_inLoop(true)
+{
+}
+
+
+K3bSignalWaiter::~K3bSignalWaiter()
+{
+}
+
+
+void K3bSignalWaiter::waitForSignal( QObject* o, const char* signal )
+{
+ K3bSignalWaiter w;
+ connect( o, signal,
+ &w, SLOT(slotSignal()) );
+
+ QApplication::eventLoop()->enterLoop();
+}
+
+
+void K3bSignalWaiter::waitForJob( K3bJob* job )
+{
+ if( !job->active() )
+ return;
+
+ waitForSignal( job, SIGNAL(finished(bool)) );
+}
+
+
+void K3bSignalWaiter::slotSignal()
+{
+ if( m_inLoop ) {
+ m_inLoop = false;
+ QApplication::eventLoop()->exitLoop();
+ }
+}
+
+#include "k3bsignalwaiter.moc"
diff --git a/libk3b/tools/k3bsignalwaiter.h b/libk3b/tools/k3bsignalwaiter.h
new file mode 100644
index 0000000..19876b4
--- /dev/null
+++ b/libk3b/tools/k3bsignalwaiter.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_SIGNAL_WAITER_H_
+#define _K3B_SIGNAL_WAITER_H_
+
+#include <qobject.h>
+
+#include <k3b_export.h>
+
+class K3bJob;
+
+class K3bSignalWaiter : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Use this to syncroneously wait for a signal.
+ */
+ LIBK3B_EXPORT static void waitForSignal( QObject* o, const char* signal );
+
+ /**
+ * Use this to syncroneously wait for a job to finish.
+ * If the job is not running at all this returns immedeately.
+ */
+ LIBK3B_EXPORT static void waitForJob( K3bJob* job );
+
+ private slots:
+ void slotSignal();
+
+ private:
+ K3bSignalWaiter();
+ ~K3bSignalWaiter();
+
+ bool m_inLoop;
+};
+
+#endif
diff --git a/libk3b/tools/k3bstdguiitems.cpp b/libk3b/tools/k3bstdguiitems.cpp
new file mode 100644
index 0000000..8a6ab00
--- /dev/null
+++ b/libk3b/tools/k3bstdguiitems.cpp
@@ -0,0 +1,215 @@
+/*
+ *
+ * $Id: k3bstdguiitems.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bstdguiitems.h"
+
+#include <qcheckbox.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qcombobox.h>
+#include <qframe.h>
+#include <qpalette.h>
+
+#include <klocale.h>
+
+
+QCheckBox* K3bStdGuiItems::simulateCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Simulate"), parent, name );
+ QWhatsThis::add( c, i18n("<p>If this option is checked K3b will perform all writing steps with the "
+ "laser turned off."
+ "<p>This is useful, for example, to test a higher writing speed "
+ "or whether your system is able to write on-the-fly."
+ "<p><b>Caution:</b> DVD+R(W) does not support simulated writing.") );
+ QToolTip::add( c, i18n("Only simulate the writing process") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::daoCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Disk at once"), parent, name );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, K3b will write the CD in 'disk at once' mode as "
+ "compared to 'track at once' (TAO)."
+ "<p>It is always recommended to use DAO where possible."
+ "<p><b>Caution:</b> Track pregaps with a length other than 2 seconds are only supported "
+ "in DAO mode.") );
+ QToolTip::add( c, i18n("Write in disk at once mode") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::burnproofCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Use Burnfree"), parent, name );
+ QToolTip::add( c, i18n("Enable Burnfree (or Just Link) to avoid buffer underruns") );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, K3b enables <em>Burnfree</em> "
+ "(or <em>Just Link</em>). This is "
+ "a feature of the CD writer which avoids buffer underruns."
+ "<p>Without <em>burnfree</em>, if the writer cannot get any more "
+ "data a buffer underrun would occurs, since the writer needs "
+ "a constant stream of data to write the CD."
+ "<p>With <em>burnfree</em> the writer can <em>mark</em> the current "
+ "position of the laser and get back to it when the buffer is filled again;"
+ "but, since this means having little data gaps on the CD, <b>it is "
+ "highly recommended to always choose an appropriate writing "
+ "speed to prevent the usage of burnfree, especially for audio CDs</b> "
+ "(in the worst case one would hear the gap)."
+ "<p><em>Burnfree</em> was formerly known as <em>Burnproof</em>, "
+ "but has since been renamed when it became part of the MMC standard.") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::onlyCreateImagesCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Only create image"), parent, name );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, K3b will only create an "
+ "image and not do any actual writing."
+ "<p>The image can later be written to a CD/DVD with most current writing "
+ "programs (including K3b of course).") );
+ QToolTip::add( c, i18n("Only create an image") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::createCacheImageCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Create image"), parent, name );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, K3b will create an image before writing "
+ "the files to the CD/DVD. Otherwise the data will be written <em>on-the-fly</em>, "
+ "i.e. no intermediate image will be created."
+ "<p><b>Caution:</b> Although writing on-the-fly should work on most systems, make sure "
+ "the data is sent to the writer fast enough.")
+ + i18n("<p>It is recommended to try a simulation first.") );
+ QToolTip::add( c, i18n("Cache the data to be written on the harddisk") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::removeImagesCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Remove image"), parent, name );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, K3b will remove any created images after the "
+ "writing has finished."
+ "<p>Uncheck this if you want to keep the images.") );
+ QToolTip::add( c, i18n("Remove images from disk when finished") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::onTheFlyCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("On the fly"), parent, name );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, K3b will not create an image first but write "
+ "the files directly to the CD/DVD."
+ "<p><b>Caution:</b> Although this should work on most systems, make sure "
+ "the data is sent to the writer fast enough.")
+ + i18n("<p>It is recommended to try a simulation first.") );
+ QToolTip::add( c, i18n("Write files directly to CD/DVD without creating an image") );
+ return c;
+}
+
+QCheckBox* K3bStdGuiItems::cdTextCheckbox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Write CD-TEXT"), parent, name );
+ QToolTip::add( c, i18n("Create CD-TEXT entries") );
+ QWhatsThis::add( c, i18n("<p>If this option is checked K3b uses some otherwise-unused space on the audio "
+ "CD to store additional information, like the artist or the CD title."
+ "<p>CD-TEXT is an extension to the audio CD standard introduced by Sony."
+ "<p>CD-TEXT will only be usable on CD players that support this extension "
+ "(mostly car CD players)."
+ "<p>Since a CD-TEXT-enhanced CDs will work in any CD player it is never a bad "
+ "idea to enable this (if you specify CD-TEXT data).") );
+ return c;
+}
+
+
+QComboBox* K3bStdGuiItems::paranoiaModeComboBox( QWidget* parent, const char* name )
+{
+ QComboBox* c = new QComboBox( parent, name );
+ c->insertItem( "0" );
+ c->insertItem( "1" );
+ c->insertItem( "2" );
+ c->insertItem( "3" );
+ c->setCurrentItem( 3 );
+ QToolTip::add( c, i18n("Set the paranoia level for reading audio CDs") );
+ QWhatsThis::add( c, i18n("<p>Sets the correction mode for digital audio extraction."
+ "<ul><li>0: No checking, data is copied directly from the drive. "
+ "<li>1: Perform overlapped reading to avoid jitter.</li>"
+ "<li>2: Like 1 but with additional checks of the read audio data.</li>"
+ "<li>3: Like 2 but with additional scratch detection and repair.</li></ul>"
+ "<p><b>The extraction speed reduces from 0 to 3.</b>") );
+ return c;
+}
+
+
+QCheckBox* K3bStdGuiItems::startMultisessionCheckBox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Start multisession CD"), parent, name );
+ QToolTip::add( c, i18n("Do not close the disk to allow additional sessions to be added later") );
+ QWhatsThis::add( c, i18n("<p>If this option is checked K3b will not close the CD, and will write "
+ "a temporary table of contents.</p>"
+ "<p>This allows further sessions to be appended to the CD later.</p>") );
+ return c;
+}
+
+
+QCheckBox* K3bStdGuiItems::normalizeCheckBox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Normalize volume levels"), parent, name );
+ QToolTip::add( c, i18n("Adjust the volume levels of all tracks") );
+ QWhatsThis::add( c, i18n("<p>If this option is checked K3b will adjust the volume of all tracks "
+ "to a standard level. This is useful for things like creating mixes, "
+ "where different recording levels on different albums can cause the volume "
+ "to vary greatly from song to song."
+ "<p><b>Be aware that K3b currently does not support normalizing when writing "
+ "on the fly.</b>") );
+ return c;
+}
+
+
+QCheckBox* K3bStdGuiItems::verifyCheckBox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Verify written data"), parent, name );
+ QToolTip::add( c, i18n("Compare original with written data") );
+ QWhatsThis::add( c, i18n("<p>If this option is checked, then after successfully "
+ "writing the disk K3b will compare the original source data "
+ "with the written data to verify that the disk has been written "
+ "correctly.") );
+ return c;
+}
+
+
+QCheckBox* K3bStdGuiItems::ignoreAudioReadErrorsCheckBox( QWidget* parent, const char* name )
+{
+ QCheckBox* c = new QCheckBox( i18n("Ignore read errors"), parent, name );
+ QToolTip::add( c, i18n("Skip unreadable audio sectors") );
+ QWhatsThis::add( c, i18n("<p>If this option is checked and K3b is not able to read an "
+ "audio sector from the source CD it will be replaced with zeros "
+ "on the resulting copy."
+ "<p>Since audio CD Player are able to interpolate small errors "
+ "in the data it is no problem to let K3b skip unreadable sectors.") );
+ return c;
+}
+
+
+QFrame* K3bStdGuiItems::horizontalLine( QWidget* parent, const char* name )
+{
+ QFrame* line = new QFrame( parent, name );
+ line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
+ return line;
+}
+
+QFrame* K3bStdGuiItems::verticalLine( QWidget* parent, const char* name )
+{
+ QFrame* line = new QFrame( parent, name );
+ line->setFrameStyle( QFrame::VLine | QFrame::Sunken );
+ return line;
+}
diff --git a/libk3b/tools/k3bstdguiitems.h b/libk3b/tools/k3bstdguiitems.h
new file mode 100644
index 0000000..e118b6a
--- /dev/null
+++ b/libk3b/tools/k3bstdguiitems.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * $Id: k3bstdguiitems.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef K3B_STD_GUIITEMS_H
+#define K3B_STD_GUIITEMS_H
+#include "k3b_export.h"
+
+class QWidget;
+class QCheckBox;
+class QComboBox;
+class QFrame;
+
+
+namespace K3bStdGuiItems
+{
+ LIBK3B_EXPORT QCheckBox* simulateCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* daoCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* burnproofCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* onlyCreateImagesCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* createCacheImageCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* removeImagesCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* onTheFlyCheckbox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* cdTextCheckbox( QWidget* parent = 0, const char* name = 0);
+ LIBK3B_EXPORT QComboBox* paranoiaModeComboBox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* startMultisessionCheckBox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* normalizeCheckBox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* verifyCheckBox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QCheckBox* ignoreAudioReadErrorsCheckBox( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QFrame* horizontalLine( QWidget* parent = 0, const char* name = 0 );
+ LIBK3B_EXPORT QFrame* verticalLine( QWidget* parent = 0, const char* name = 0 );
+}
+
+#endif
diff --git a/libk3b/tools/k3bstringutils.cpp b/libk3b/tools/k3bstringutils.cpp
new file mode 100644
index 0000000..198bb9e
--- /dev/null
+++ b/libk3b/tools/k3bstringutils.cpp
@@ -0,0 +1,111 @@
+/*
+ *
+ * $Id: k3bstringutils.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bstringutils.h"
+
+#include <qfontmetrics.h>
+
+#include <kdebug.h>
+
+
+QString K3b::cutToWidth( const QFontMetrics& fm, const QString& fullText, int cutWidth )
+{
+ QString squeezedText = "...";
+ int squeezedWidth = fm.width(squeezedText);
+ int textWidth = fm.width(fullText);
+
+ if( textWidth <= cutWidth ) {
+ return fullText;
+ }
+
+ if( fm.width(fullText.right(1) + "..." ) > cutWidth ) {
+ kdDebug() << "(K3b::cutToWidth) not able to cut text to " << cutWidth << "!" << endl;
+ return fullText.right(1) + "...";
+ }
+
+ // estimate how many letters we can add to the dots
+ int letters = fullText.length() * (cutWidth - squeezedWidth) / textWidth;
+ squeezedText = fullText.left(letters) + "...";
+ squeezedWidth = fm.width(squeezedText);
+
+ if (squeezedWidth < cutWidth) {
+ // we estimated too short
+ // add letters while text < label
+ do {
+ letters++;
+ squeezedText = fullText.left(letters) + "...";
+ squeezedWidth = fm.width(squeezedText);
+ } while (squeezedWidth < cutWidth);
+ letters--;
+ squeezedText = fullText.left(letters) + "...";
+ } else if (squeezedWidth > cutWidth) {
+ // we estimated too long
+ // remove letters while text > label
+ do {
+ letters--;
+ squeezedText = fullText.left(letters) + "...";
+ squeezedWidth = fm.width(squeezedText);
+ } while (squeezedWidth > cutWidth);
+ }
+
+ return squeezedText;
+}
+
+
+// from KSqueezedTextLabel
+QString K3b::squeezeTextToWidth( const QFontMetrics& fm, const QString& fullText, int cutWidth )
+{
+ int textWidth = fm.width(fullText);
+ if (textWidth > cutWidth) {
+ // start with the dots only
+ QString squeezedText = "...";
+ int squeezedWidth = fm.width(squeezedText);
+
+ // estimate how many letters we can add to the dots on both sides
+ int letters = fullText.length() * (cutWidth - squeezedWidth) / textWidth / 2;
+ if (cutWidth < squeezedWidth) letters=1;
+ squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
+ squeezedWidth = fm.width(squeezedText);
+
+ if (squeezedWidth < cutWidth) {
+ // we estimated too short
+ // add letters while text < label
+ do {
+ letters++;
+ squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
+ squeezedWidth = fm.width(squeezedText);
+ } while (squeezedWidth < cutWidth);
+ letters--;
+ squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
+ }
+ else if (squeezedWidth > cutWidth) {
+ // we estimated too long
+ // remove letters while text > label
+ do {
+ letters--;
+ squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
+ squeezedWidth = fm.width(squeezedText);
+ } while (letters > 2 && squeezedWidth > cutWidth);
+ }
+
+ if (letters == 2)
+ kdDebug() << "(K3b::squeezeTextToWidth) WARNING: unable to squeeze text to width "
+ << cutWidth << endl;
+
+ return squeezedText;
+ }
+ else
+ return fullText;
+}
diff --git a/libk3b/tools/k3bstringutils.h b/libk3b/tools/k3bstringutils.h
new file mode 100644
index 0000000..05cfd32
--- /dev/null
+++ b/libk3b/tools/k3bstringutils.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * $Id: k3bstringutils.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_STRING_UTILS_H_
+#define _K3B_STRING_UTILS_H_
+
+#include <qstring.h>
+
+class QFontMetrics;
+
+namespace K3b
+{
+ /**
+ * Cuts the text at the end.
+ * Example: "some long text" -> "some lo..."
+ */
+ QString cutToWidth( const QFontMetrics&, const QString&, int );
+
+ /**
+ * squeezes the text.
+ * Example: "some long text" -> "some...ext"
+ */
+ QString squeezeTextToWidth( const QFontMetrics& fm, const QString& fullText, int cutWidth );
+}
+
+#endif
diff --git a/libk3b/tools/k3btempfile.cpp b/libk3b/tools/k3btempfile.cpp
new file mode 100644
index 0000000..635be40
--- /dev/null
+++ b/libk3b/tools/k3btempfile.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3btempfile.h"
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+
+static inline QString defaultTempDir()
+{
+ // we need a world-readable temp dir
+
+ // FIXME: check if the default is world-readable
+// QStringList dirs = KGlobal::dirs()->resourceDirs( "tmp" );
+// for( QStringList::const_iterator it = dirs.begin();
+// it != dirs.end(); ++it ) {
+// const QString& dir = *it;
+
+// }
+
+ // fallback to /tmp
+ return "/tmp/k3b";
+}
+
+
+K3bTempFile::K3bTempFile( const QString& filePrefix,
+ const QString& fileExtension,
+ int mode )
+ : KTempFile( filePrefix.isEmpty() ? defaultTempDir() : filePrefix,
+ fileExtension,
+ mode )
+{
+}
+
+
+K3bTempFile::~K3bTempFile()
+{
+}
diff --git a/libk3b/tools/k3btempfile.h b/libk3b/tools/k3btempfile.h
new file mode 100644
index 0000000..41a8756
--- /dev/null
+++ b/libk3b/tools/k3btempfile.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_TEMP_FILE_H_
+#define _K3B_TEMP_FILE_H_
+
+#include <ktempfile.h>
+
+#include <k3b_export.h>
+
+/**
+ * K3bTempFile does only change one thing over KTempFile:
+ * It tries to use a default temp dir which is always world-readable.
+ *
+ * This is important in the following situation:
+ *
+ * cdrecord often runs suid root. Some distributions like Mandriva
+ * set the default KDE temp dir to $HOME/tmp-$USER. Thus, if the home
+ * dir is mounted via NFS root has no read permissions htere and cdrecord
+ * fails to read the temp files.
+ */
+class LIBK3B_EXPORT K3bTempFile : public KTempFile
+{
+ public:
+ K3bTempFile( const QString& filePrefix = QString::null,
+ const QString& fileExtension = QString::null,
+ int mode = 0600 );
+ ~K3bTempFile();
+};
+
+#endif
diff --git a/libk3b/tools/k3bthreadwidget.cpp b/libk3b/tools/k3bthreadwidget.cpp
new file mode 100644
index 0000000..ea82101
--- /dev/null
+++ b/libk3b/tools/k3bthreadwidget.cpp
@@ -0,0 +1,142 @@
+/*
+ *
+ * $Id: k3bthreadwidget.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3bthreadwidget.h"
+#include "k3bdeviceselectiondialog.h"
+#include <k3bdevice.h>
+
+#include <qevent.h>
+#include <qapplication.h>
+#include <qwaitcondition.h>
+
+
+class K3bThreadWidget::Data
+{
+public:
+ int id;
+ void* data;
+ QWaitCondition con;
+};
+
+
+class K3bThreadWidget::DeviceSelectionEvent : public QCustomEvent
+{
+public:
+ DeviceSelectionEvent( QWidget* parent, const QString& text, int id )
+ : QCustomEvent( QEvent::User + 22 ),
+ m_parent(parent),
+ m_text(text),
+ m_id(id) {
+ }
+
+ QWidget* parent() const { return m_parent; }
+ const QString& text() const { return m_text; }
+ int id() const { return m_id; }
+
+private:
+ QWidget* m_parent;
+ QString m_text;
+ int m_id;
+};
+
+
+K3bThreadWidget* K3bThreadWidget::s_instance = 0;
+
+
+K3bThreadWidget::K3bThreadWidget()
+ : QObject(),
+ m_idCounter(1)
+{
+ m_dataMap.setAutoDelete(true);
+ s_instance = this;
+}
+
+
+K3bThreadWidget::~K3bThreadWidget()
+{
+ s_instance = 0;
+}
+
+
+int K3bThreadWidget::getNewId()
+{
+ // create new data
+ Data* data = new Data;
+ data->id = m_idCounter++;
+ data->data = 0;
+ m_dataMap.insert( data->id, data );
+ return data->id;
+}
+
+
+void K3bThreadWidget::clearId( int id )
+{
+ m_dataMap.remove( id );
+}
+
+
+K3bThreadWidget::Data* K3bThreadWidget::data( int id )
+{
+ return m_dataMap[id];
+}
+
+
+K3bThreadWidget* K3bThreadWidget::instance()
+{
+ if( !s_instance )
+ s_instance = new K3bThreadWidget();
+ return s_instance;
+}
+
+
+// static
+K3bDevice::Device* K3bThreadWidget::selectDevice( QWidget* parent,
+ const QString& text )
+{
+ // request a new data set
+ Data* data = K3bThreadWidget::instance()->data( K3bThreadWidget::instance()->getNewId() );
+
+ // inform the instance about the request
+ QApplication::postEvent( K3bThreadWidget::instance(),
+ new K3bThreadWidget::DeviceSelectionEvent( parent, text, data->id ) );
+
+ // wait for the result to be ready
+ data->con.wait();
+
+ K3bDevice::Device* dev = static_cast<K3bDevice::Device*>( data->data );
+
+ // delete the no longer needed data
+ K3bThreadWidget::instance()->clearId( data->id );
+
+ return dev;
+}
+
+
+void K3bThreadWidget::customEvent( QCustomEvent* e )
+{
+ if( DeviceSelectionEvent* dse = dynamic_cast<DeviceSelectionEvent*>(e) ) {
+ // create dialog
+ K3bDevice::Device* dev = K3bDeviceSelectionDialog::selectDevice( dse->parent(), dse->text() );
+
+ // return it to the thread
+ Data* dat = data( dse->id() );
+ dat->data = static_cast<void*>( dev );
+
+ // wake the thread
+ dat->con.wakeAll();
+ }
+}
+
+#include "k3bthreadwidget.moc"
diff --git a/libk3b/tools/k3bthreadwidget.h b/libk3b/tools/k3bthreadwidget.h
new file mode 100644
index 0000000..b3fedb2
--- /dev/null
+++ b/libk3b/tools/k3bthreadwidget.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * $Id: k3bthreadwidget.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_THREAD_WIDGET_H_
+#define _K3B_THREAD_WIDGET_H_
+
+#include <qobject.h>
+#include <qintdict.h>
+
+
+class QCustomEvent;
+namespace K3bDevice {
+ class Device;
+}
+
+/**
+ * This class allows a thread other than the GUI thread to perform simple GUI
+ * operations. Mainly creating some simple K3b Dialogs like Device selection.
+ *
+ * Since the calling thread cannot create the K3bThreadWidget by himself there exists
+ * exactly one instance created by K3bCore which is used by all threads.
+ */
+class K3bThreadWidget : public QObject
+{
+ Q_OBJECT
+
+ public:
+ ~K3bThreadWidget();
+
+ static K3bThreadWidget* instance();
+
+ /**
+ * Call this from a thread to show a device selection dialog.
+ */
+ static K3bDevice::Device* selectDevice( QWidget* parent,
+ const QString& text = QString::null );
+
+ protected:
+ /**
+ * communication between the threads
+ */
+ void customEvent( QCustomEvent* );
+
+ private:
+ /**
+ * used internally
+ */
+ class DeviceSelectionEvent;
+ class Data;
+
+ K3bThreadWidget();
+
+ /**
+ * Get unique id
+ */
+ int getNewId();
+ void clearId( int id );
+ Data* data( int id );
+
+ int m_idCounter;
+ QIntDict<Data> m_dataMap;
+
+ static K3bThreadWidget* s_instance;
+};
+
+#endif
diff --git a/libk3b/tools/k3bthroughputestimator.cpp b/libk3b/tools/k3bthroughputestimator.cpp
new file mode 100644
index 0000000..aa52478
--- /dev/null
+++ b/libk3b/tools/k3bthroughputestimator.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * $Id: k3bthroughputestimator.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3bthroughputestimator.h"
+
+#include <qdatetime.h>
+#include <kdebug.h>
+
+
+class K3bThroughputEstimator::Private
+{
+public:
+ Private()
+ : started(false) {
+ }
+
+ QTime firstDataTime;
+ unsigned long firstData;
+ QTime lastDataTime;
+ unsigned long lastData;
+
+ int lastThroughput;
+
+ bool started;
+};
+
+
+K3bThroughputEstimator::K3bThroughputEstimator( QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ d = new Private();
+}
+
+
+K3bThroughputEstimator::~K3bThroughputEstimator()
+{
+ delete d;
+}
+
+
+int K3bThroughputEstimator::average() const
+{
+ int msecs = d->firstDataTime.msecsTo( d->lastDataTime );
+ if( msecs > 0 )
+ return (int)( 1000.0*(double)(d->lastData - d->firstData)/(double)msecs);
+ else
+ return 0;
+}
+
+
+void K3bThroughputEstimator::reset()
+{
+ d->started = false;
+}
+
+
+void K3bThroughputEstimator::dataWritten( unsigned long data )
+{
+ if( !d->started ) {
+ d->started = true;
+ d->firstData = d->lastData = data;
+ d->firstDataTime.start();
+ d->lastDataTime.start();
+ d->lastThroughput = 0;
+ }
+ else if( data > d->lastData ) {
+ unsigned long diff = data - d->lastData;
+ int msecs = d->lastDataTime.elapsed();
+
+ //if( msecs > 0 ) {
+ // down the update sequence a little bit
+ if( msecs > 500 ) {
+ d->lastData = data;
+ d->lastDataTime.start();
+ int t = (int)(1000.0*(double)diff/(double)msecs);
+ if( t != d->lastThroughput ) {
+ d->lastThroughput = t;
+ emit throughput( t );
+ }
+ }
+ }
+}
+
+
+#include "k3bthroughputestimator.moc"
diff --git a/libk3b/tools/k3bthroughputestimator.h b/libk3b/tools/k3bthroughputestimator.h
new file mode 100644
index 0000000..aed71e0
--- /dev/null
+++ b/libk3b/tools/k3bthroughputestimator.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * $Id: k3bthroughputestimator.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_THROUGHPUT_ESTIMATOR_H_
+#define _K3B_THROUGHPUT_ESTIMATOR_H_
+
+#include <qobject.h>
+
+
+/**
+ * Little helper class that allows an estimation of the current writing
+ * speed. Just init with @p reset() then always call @p dataWritten with
+ * the already written data in KB. The class will emit throughput signals
+ * whenever the throughput changes.
+ */
+class K3bThroughputEstimator : public QObject
+{
+ Q_OBJECT
+
+ public:
+ K3bThroughputEstimator( QObject* parent = 0, const char* name = 0 );
+ ~K3bThroughputEstimator();
+
+ int average() const;
+
+ signals:
+ /**
+ * kb/s if differs from previous
+ */
+ void throughput( int );
+
+ public slots:
+ void reset();
+
+ /**
+ * @param data written kb
+ */
+ void dataWritten( unsigned long data );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3btitlelabel.cpp b/libk3b/tools/k3btitlelabel.cpp
new file mode 100644
index 0000000..9e1f18b
--- /dev/null
+++ b/libk3b/tools/k3btitlelabel.cpp
@@ -0,0 +1,266 @@
+/*
+ *
+ * $Id: k3btitlelabel.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3btitlelabel.h"
+
+#include <k3bstringutils.h>
+
+#include <qpainter.h>
+#include <qevent.h>
+#include <qfontmetrics.h>
+#include <qfont.h>
+#include <qtooltip.h>
+
+
+class K3bTitleLabel::Private
+{
+public:
+ Private() {
+ titleLength = subTitleLength = 0;
+ margin = 2;
+ alignment = Qt::AlignLeft;
+ cachedMinimumWidth = 0;
+ titleBaseLine = 0;
+ }
+
+ QString title;
+ QString subTitle;
+
+ QString displayTitle;
+ QString displaySubTitle;
+
+ int alignment;
+
+ int titleLength;
+ int subTitleLength;
+ int displayTitleLength;
+ int displaySubTitleLength;
+ int titleBaseLine;
+ int subTitleBaseLine;
+ int margin;
+
+ int cachedMinimumWidth;
+};
+
+
+class K3bTitleLabel::ToolTip : public QToolTip
+{
+public:
+ ToolTip( K3bTitleLabel* label )
+ : QToolTip( label ),
+ m_label(label) {
+ }
+
+ void maybeTip( const QPoint &pos ) {
+ QRect r = m_label->contentsRect();
+
+ int neededWidth = m_label->d->displayTitleLength;
+ if( !m_label->d->displaySubTitle.isEmpty() )
+ neededWidth += m_label->d->displaySubTitleLength + 5;
+
+ int startPos = 0;
+ if( m_label->d->alignment & Qt::AlignHCenter )
+ startPos = r.left() + ( r.width() - 2*m_label->d->margin - neededWidth ) / 2;
+ else if( m_label->d->alignment & Qt::AlignRight )
+ startPos = r.right() - m_label->d->margin - neededWidth;
+ else
+ startPos = r.left() + m_label->d->margin;
+
+ QRect titleTipRect( startPos, 0, m_label->d->displayTitleLength, m_label->height() );
+ QRect subTitleTipRect( startPos + m_label->d->displayTitleLength, 0, m_label->d->displaySubTitleLength, m_label->height() );
+
+ if( titleTipRect.contains( pos ) &&
+ m_label->d->displayTitle != m_label->d->title )
+ tip( titleTipRect, m_label->d->title );
+ else if( subTitleTipRect.contains( pos ) &&
+ m_label->d->displaySubTitle != m_label->d->subTitle )
+ tip( subTitleTipRect, m_label->d->subTitle );
+ }
+
+ K3bTitleLabel* m_label;
+};
+
+
+
+K3bTitleLabel::K3bTitleLabel( QWidget* parent, const char* name )
+ : QFrame( parent, name )
+{
+ d = new Private();
+ m_toolTip = new ToolTip( this );
+}
+
+
+K3bTitleLabel::~K3bTitleLabel()
+{
+ delete m_toolTip;
+ delete d;
+}
+
+
+void K3bTitleLabel::setTitle( const QString& title, const QString& subTitle )
+{
+ d->title = title;
+ d->subTitle = subTitle;
+ updatePositioning();
+ update();
+}
+
+
+void K3bTitleLabel::setSubTitle( const QString& subTitle )
+{
+ d->subTitle = subTitle;
+ updatePositioning();
+ update();
+}
+
+
+void K3bTitleLabel::setAlignment( int align )
+{
+ d->alignment = align;
+ update();
+}
+
+
+QSize K3bTitleLabel::sizeHint() const
+{
+ return QSize( d->titleLength + d->subTitleLength + 2*d->margin, d->titleBaseLine );
+}
+
+QSize K3bTitleLabel::minimumSizeHint() const
+{
+ return QSize( d->cachedMinimumWidth, d->titleBaseLine );
+}
+
+void K3bTitleLabel::resizeEvent( QResizeEvent* e )
+{
+ QFrame::resizeEvent( e );
+ updatePositioning();
+ update();
+}
+
+void K3bTitleLabel::drawContents( QPainter* p )
+{
+ p->save();
+
+ QRect r = contentsRect();
+ p->eraseRect( r );
+
+ QFont f(font());
+ f.setBold(true);
+ f.setPointSize( f.pointSize() + 2 );
+
+ p->setFont(f);
+
+ int neededWidth = d->displayTitleLength;
+ if( !d->displaySubTitle.isEmpty() )
+ neededWidth += d->displaySubTitleLength + 5;
+
+ int startPos = 0;
+ if( d->alignment & Qt::AlignHCenter )
+ startPos = r.left() + ( r.width() - 2*d->margin - neededWidth ) / 2;
+ else if( d->alignment & Qt::AlignRight )
+ startPos = r.right() - d->margin - neededWidth;
+ else
+ startPos = r.left() + d->margin;
+
+ // paint title
+ p->drawText( startPos, r.top() + d->titleBaseLine, d->displayTitle );
+
+ if( !d->subTitle.isEmpty() ) {
+ f.setBold(false);
+ f.setPointSize( f.pointSize() - 4 );
+ p->setFont(f);
+ p->drawText( startPos + d->displayTitleLength + 5, r.top() + d->subTitleBaseLine, d->displaySubTitle );
+ }
+
+ p->restore();
+}
+
+
+void K3bTitleLabel::setMargin( int m )
+{
+ d->margin = m;
+ updatePositioning();
+ update();
+}
+
+
+void K3bTitleLabel::updatePositioning()
+{
+ QFont f(font());
+ f.setBold(true);
+ f.setPointSize( f.pointSize() + 2 );
+ QFontMetrics titleFm(f);
+
+ f.setBold(false);
+ f.setPointSize( f.pointSize() - 4 );
+ QFontMetrics subTitleFm(f);
+
+ d->titleBaseLine = contentsRect().height()/2 + titleFm.height()/2 - titleFm.descent();
+ d->titleLength = titleFm.width( d->title );
+
+ d->subTitleBaseLine = d->titleBaseLine - titleFm.underlinePos() + subTitleFm.underlinePos();
+
+ d->subTitleLength = ( d->subTitle.isEmpty() ? 0 : subTitleFm.width( d->subTitle ) );
+
+ // cut the text to window width
+ d->displayTitle = d->title;
+ d->displaySubTitle = d->subTitle;
+ int widthAvail = contentsRect().width() - 2*margin();
+
+ // 5 pix spacing between title and subtitle
+ if( !d->subTitle.isEmpty() )
+ widthAvail -= 5;
+
+ if( d->titleLength > widthAvail/2 ) {
+ if( d->subTitleLength <= widthAvail/2 )
+ d->displayTitle = K3b::cutToWidth( titleFm, d->title, widthAvail - d->subTitleLength );
+ else
+ d->displayTitle = K3b::cutToWidth( titleFm, d->title, widthAvail/2 );
+ }
+ if( d->subTitleLength > widthAvail/2 ) {
+ if( d->titleLength <= widthAvail/2 )
+ d->displaySubTitle = K3b::cutToWidth( subTitleFm, d->subTitle, widthAvail - d->titleLength );
+ else
+ d->displaySubTitle = K3b::cutToWidth( subTitleFm, d->subTitle, widthAvail/2 );
+ }
+
+ d->displayTitleLength = titleFm.width( d->displayTitle );
+ d->displaySubTitleLength = subTitleFm.width( d->displaySubTitle );
+
+
+ //
+ // determine the minimum width for the minumum size hint
+ //
+ d->cachedMinimumWidth = 2*d->margin;
+
+ QString cutTitle = d->title;
+ if( cutTitle.length() > 2 ) {
+ cutTitle.truncate( 2 );
+ cutTitle += "...";
+ }
+ QString cutSubTitle = d->subTitle;
+ if( cutSubTitle.length() > 2 ) {
+ cutSubTitle.truncate( 2 );
+ cutSubTitle += "...";
+ }
+
+ d->cachedMinimumWidth += titleFm.width( cutTitle ) + subTitleFm.width( cutSubTitle );
+ // 5 pix spacing between title and subtitle
+ if( !d->subTitle.isEmpty() )
+ d->cachedMinimumWidth += 5;
+}
+
+#include "k3btitlelabel.moc"
diff --git a/libk3b/tools/k3btitlelabel.h b/libk3b/tools/k3btitlelabel.h
new file mode 100644
index 0000000..ba1044d
--- /dev/null
+++ b/libk3b/tools/k3btitlelabel.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * $Id: k3btitlelabel.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef _K3B_TITLE_LABEL_H_
+#define _K3B_TITLE_LABEL_H_
+
+#include <qframe.h>
+#include "k3b_export.h"
+class QPainter;
+class QResizeEvent;
+
+
+class LIBK3B_EXPORT K3bTitleLabel : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ K3bTitleLabel( QWidget* parent = 0, const char* name = 0 );
+ ~K3bTitleLabel();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ public slots:
+ /**
+ * default: 2
+ */
+ void setMargin( int );
+
+ void setTitle( const QString& title, const QString& subTitle = QString::null );
+ void setSubTitle( const QString& subTitle );
+
+ /**
+ * The title label only supports alignments left, hcenter, and right
+ *
+ * Default alignment is left.
+ */
+ // FIXME: honor right-to-left languages
+ void setAlignment( int align );
+
+ protected:
+ void resizeEvent( QResizeEvent* );
+ void drawContents( QPainter* p );
+
+ private:
+ void updatePositioning();
+
+ class ToolTip;
+ ToolTip* m_toolTip;
+
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3btoolbox.cpp b/libk3b/tools/k3btoolbox.cpp
new file mode 100644
index 0000000..b08dfc8
--- /dev/null
+++ b/libk3b/tools/k3btoolbox.cpp
@@ -0,0 +1,293 @@
+/*
+ *
+ * $Id$
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3btoolbox.h"
+
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <ktoolbarbutton.h>
+#include <kiconloader.h>
+
+#include <qtoolbutton.h>
+#include <qsizepolicy.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qstyle.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qobjectlist.h>
+
+
+/**
+ * internal class. Do not use!
+ */
+class K3bToolBoxSeparator : public QWidget
+{
+ // Q_OBJECT
+
+ public:
+ K3bToolBoxSeparator( K3bToolBox* parent );
+
+ QSize sizeHint() const;
+
+ protected:
+ void paintEvent( QPaintEvent * );
+};
+
+
+K3bToolBoxSeparator::K3bToolBoxSeparator( K3bToolBox* parent )
+ : QWidget( parent )
+{
+ setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
+}
+
+
+QSize K3bToolBoxSeparator::sizeHint() const
+{
+ int extent = style().pixelMetric( QStyle::PM_DockWindowSeparatorExtent,
+ this );
+ return QSize( extent, 0 );
+}
+
+
+void K3bToolBoxSeparator::paintEvent( QPaintEvent* )
+{
+ QPainter p( this );
+ QStyle::SFlags flags = QStyle::Style_Default|QStyle::Style_Horizontal;
+
+ style().drawPrimitive( QStyle::PE_DockWindowSeparator, &p, rect(),
+ colorGroup(), flags );
+}
+
+
+
+K3bToolBoxButton::K3bToolBoxButton( KAction* action, QWidget* parent )
+ : QToolButton( parent ),
+ m_popupMenu(0)
+{
+ setSizePolicy( QSizePolicy(QSizePolicy::Fixed, sizePolicy().verData()) );
+ setAutoRaise( true );
+
+ setIconSet( action->iconSet() );
+ setTextLabel( action->text() );
+ setEnabled( action->isEnabled() );
+
+ QWhatsThis::add( this, action->whatsThis() );
+ if( action->toolTip().isEmpty() )
+ QToolTip::add( this, action->text() );
+ else
+ QToolTip::add( this, action->toolTip() );
+
+// if( KToggleAction* ta = dynamic_cast<KToggleAction*>( action ) ) {
+// setToggleButton( true );
+
+// // initial state
+// if( ta->isChecked() )
+// toggle();
+
+// connect( ta, SIGNAL(toggled(bool)), this, SLOT(toggle()) );
+// connect( this, SIGNAL(toggled(bool)), ta, SLOT(setChecked(bool)) );
+// }
+
+// else
+ if( KActionMenu* am = dynamic_cast<KActionMenu*>( action ) ) {
+ m_popupMenu = am->popupMenu();
+ connect( this, SIGNAL(pressed()), this, SLOT(slotPopupActivated()) );
+ setPopup( m_popupMenu );
+ }
+
+ else {
+ connect( this, SIGNAL(clicked()), action, SLOT(activate()) );
+ }
+
+ connect( action, SIGNAL(enabled(bool)), this, SLOT(setEnabled(bool)) );
+}
+
+
+K3bToolBoxButton::K3bToolBoxButton( const QString& text, const QString& icon,
+ const QString& tooltip, const QString& whatsthis,
+ QObject* receiver, const char* slot,
+ QWidget* parent )
+ : QToolButton( parent ),
+ m_popupMenu(0)
+{
+ setSizePolicy( QSizePolicy(QSizePolicy::Fixed, sizePolicy().verData()) );
+ setAutoRaise( true );
+
+ setTextLabel( text );
+
+ if( icon.isEmpty() )
+ setUsesTextLabel( true );
+ else
+ setIconSet( SmallIconSet( icon ) );
+
+ QWhatsThis::add( this, whatsthis );
+ QToolTip::add( this, tooltip );
+
+ if( receiver && slot )
+ connect( this, SIGNAL(clicked()), receiver, slot );
+}
+
+
+void K3bToolBoxButton::slotPopupActivated()
+{
+ // force the toolbutton to open the popupmenu instantly
+ openPopup();
+}
+
+
+void K3bToolBoxButton::resizeEvent( QResizeEvent* e )
+{
+ QToolButton::resizeEvent( e );
+
+ // force icon-only buttons to be square
+ if( e->oldSize().height() != e->size().height() &&
+ !usesTextLabel() )
+ setFixedWidth( e->size().height() );
+}
+
+
+
+
+
+
+
+K3bToolBox::K3bToolBox( QWidget* parent, const char* name )
+ : QFrame( parent, name )
+{
+ setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed) );
+
+ m_mainLayout = new QGridLayout( this );
+ m_mainLayout->setMargin( 1 );
+ m_mainLayout->setSpacing( 0 );
+}
+
+
+K3bToolBox::~K3bToolBox()
+{
+ clear();
+}
+
+
+K3bToolBoxButton* K3bToolBox::addButton( KAction* action, bool forceText )
+{
+ if( action ) {
+ K3bToolBoxButton* b = new K3bToolBoxButton( action, this );
+ if( forceText ) {
+ b->setUsesTextLabel( true );
+ b->setTextPosition( QToolButton::BesideIcon );
+ }
+ addWidget( b );
+ return b;
+ }
+ else
+ return 0;
+}
+
+
+K3bToolBoxButton* K3bToolBox::addButton( const QString& text, const QString& icon,
+ const QString& tooltip, const QString& whatsthis,
+ QObject* receiver, const char* slot,
+ bool forceText )
+{
+ K3bToolBoxButton* b = new K3bToolBoxButton( text, icon, tooltip, whatsthis, receiver, slot, this );
+ if( forceText ) {
+ b->setUsesTextLabel( true );
+ b->setTextPosition( QToolButton::BesideIcon );
+ }
+ addWidget( b );
+ return b;
+}
+
+
+void K3bToolBox::addSpacing()
+{
+ int lastStretch = m_mainLayout->colStretch( m_mainLayout->numCols()-1 );
+ m_mainLayout->setColStretch( m_mainLayout->numCols()-1, 0 );
+ m_mainLayout->addColSpacing( m_mainLayout->numCols()-1, 8 );
+ m_mainLayout->setColStretch( m_mainLayout->numCols(), lastStretch );
+}
+
+
+void K3bToolBox::addSeparator()
+{
+ K3bToolBoxSeparator* s = new K3bToolBoxSeparator( this );
+ addWidget( s );
+}
+
+
+void K3bToolBox::addStretch()
+{
+ // add an empty widget
+ addWidget( new QWidget( this ) );
+ m_mainLayout->setColStretch( m_mainLayout->numCols(), 1 );
+}
+
+
+void K3bToolBox::addLabel( const QString& text )
+{
+ QLabel* label = new QLabel( text, this );
+ label->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
+
+ addWidget( label );
+}
+
+
+void K3bToolBox::addWidget( QWidget* w )
+{
+ w->reparent( this, QPoint() );
+
+ m_mainLayout->setColStretch( m_mainLayout->numCols()-1, 0 );
+
+ m_mainLayout->addWidget( w, 0, m_mainLayout->numCols()-1 );
+
+ if( w->sizePolicy().horData() == QSizePolicy::Fixed || w->sizePolicy().horData() == QSizePolicy::Maximum )
+ m_mainLayout->setColStretch( m_mainLayout->numCols(), 1 );
+ else {
+ m_mainLayout->setColStretch( m_mainLayout->numCols()-1, 1 );
+ m_mainLayout->setColStretch( m_mainLayout->numCols(), 0 );
+ }
+}
+
+
+K3bToolBoxButton* K3bToolBox::addToggleButton( KToggleAction* action )
+{
+ return addButton( action );
+}
+
+
+void K3bToolBox::addWidgetAction( KWidgetAction* action )
+{
+ addWidget( action->widget() );
+ m_doNotDeleteWidgets.append( action->widget() );
+}
+
+
+void K3bToolBox::clear()
+{
+ // we do not want to delete the widgets from the widgetactions becasue they
+ // might be used afterwards
+ for( QPtrListIterator<QWidget> it( m_doNotDeleteWidgets ); it.current(); ++it )
+ it.current()->reparent( 0L, QPoint() );
+
+ for( QObjectListIterator it2( *children() ); it2.current(); ++it2 )
+ if( it2.current()->isWidgetType() )
+ delete it2.current();
+}
+
+#include "k3btoolbox.moc"
diff --git a/libk3b/tools/k3btoolbox.h b/libk3b/tools/k3btoolbox.h
new file mode 100644
index 0000000..828fca1
--- /dev/null
+++ b/libk3b/tools/k3btoolbox.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * $Id$
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef K3B_TOOLBOX_H
+#define K3B_TOOLBOX_H
+
+#include <qframe.h>
+#include <qstring.h>
+#include <qtoolbutton.h>
+#include <qptrlist.h>
+#include "k3b_export.h"
+
+class KAction;
+class KToggleAction;
+class KWidgetAction;
+class QGridLayout;
+class QPopupMenu;
+class QResizeEvent;
+
+
+/**
+ * internal class. Do not use!
+ */
+class LIBK3B_EXPORT K3bToolBoxButton : public QToolButton
+{
+ Q_OBJECT
+
+ public:
+ K3bToolBoxButton( KAction*, QWidget* parent );
+ K3bToolBoxButton( const QString& text, const QString& icon,
+ const QString& tooltip, const QString& whatsthis,
+ QObject* receiver, const char* slot,
+ QWidget* parent );
+
+ private slots:
+ void slotPopupActivated();
+
+ protected:
+ void resizeEvent( QResizeEvent* );
+
+ private:
+ QPopupMenu* m_popupMenu;
+};
+
+
+class LIBK3B_EXPORT K3bToolBox : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ K3bToolBox( QWidget* parent = 0, const char* name = 0 );
+ ~K3bToolBox();
+
+ K3bToolBoxButton* addButton( const QString& text, const QString& icon,
+ const QString& tooltip = QString::null, const QString& whatsthis = QString::null,
+ QObject* receiver = 0, const char* slot = 0,
+ bool forceTextLabel = false );
+ K3bToolBoxButton* addButton( KAction*, bool forceTextLabel = false );
+ K3bToolBoxButton* addToggleButton( KToggleAction* );
+ void addWidgetAction( KWidgetAction* );
+
+ /**
+ * Be aware that the toolbox will take ownership of the widget
+ * and destroy it on destruction. Becasue of this it is not fitted
+ * for WidgetActions.
+ */
+ void addWidget( QWidget* );
+ void addLabel( const QString& );
+ void addSpacing();
+ void addSeparator();
+ void addStretch();
+
+ void clear();
+
+ protected:
+ QGridLayout* m_mainLayout;
+ QPtrList<QWidget> m_doNotDeleteWidgets;
+};
+
+
+#endif
diff --git a/libk3b/tools/k3btoolbutton.cpp b/libk3b/tools/k3btoolbutton.cpp
new file mode 100644
index 0000000..2e3e468
--- /dev/null
+++ b/libk3b/tools/k3btoolbutton.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "k3btoolbutton.h"
+
+#include <qstyle.h>
+#include <qpainter.h>
+#include <qevent.h>
+
+#include <kglobalsettings.h>
+#include <kapplication.h>
+
+
+class K3bToolButton::Private
+{
+public:
+ QPoint mousePressPos;
+ bool instantMenu;
+};
+
+
+K3bToolButton::K3bToolButton( QWidget* parent )
+ : QToolButton( parent )
+{
+ d = new Private;
+ d->instantMenu = false;
+ installEventFilter(this);
+}
+
+
+K3bToolButton::~K3bToolButton()
+{
+ delete d;
+}
+
+
+void K3bToolButton::setInstantMenu( bool b )
+{
+ d->instantMenu = b;
+}
+
+
+void K3bToolButton::drawButton( QPainter* p )
+{
+ QToolButton::drawButton( p );
+
+ //
+ // code below comes from ktoolbarbutton.cpp from the kdelibs sources
+ // see the file for copyright information
+ //
+ if( QToolButton::popup() ) {
+ QStyle::SFlags arrowFlags = QStyle::Style_Default;
+
+ if( isDown() )
+ arrowFlags |= QStyle::Style_Down;
+ if( isEnabled() )
+ arrowFlags |= QStyle::Style_Enabled;
+
+ style().drawPrimitive(QStyle::PE_ArrowDown, p,
+ QRect(width()-7, height()-7, 7, 7), colorGroup(),
+ arrowFlags, QStyleOption() );
+ }
+}
+
+
+bool K3bToolButton::eventFilter( QObject* o, QEvent* ev )
+{
+ if( dynamic_cast<K3bToolButton*>(o) == this ) {
+
+ // Popup the menu when the left mousebutton is pressed and the mouse
+ // is moved by a small distance.
+ if( QToolButton::popup() ) {
+ if( ev->type() == QEvent::MouseButtonPress ) {
+ QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
+
+ if( d->instantMenu ) {
+ setDown(true);
+ openPopup();
+ return true;
+ }
+ else {
+ d->mousePressPos = mev->pos();
+ }
+ }
+ else if( ev->type() == QEvent::MouseMove ) {
+ QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
+ if( !d->instantMenu &&
+ ( mev->pos() - d->mousePressPos).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
+ openPopup();
+ return true;
+ }
+ }
+ }
+ }
+
+ return QToolButton::eventFilter( o, ev );
+}
diff --git a/libk3b/tools/k3btoolbutton.h b/libk3b/tools/k3btoolbutton.h
new file mode 100644
index 0000000..fe96e4c
--- /dev/null
+++ b/libk3b/tools/k3btoolbutton.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
+ * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_TOOL_BUTTON_H_
+#define _K3B_TOOL_BUTTON_H_
+
+#include "k3b_export.h"
+
+#include <qtoolbutton.h>
+
+class QPainter;
+class QEvent;
+
+
+/**
+ * the K3bToolButton is an enhanced QToolButton which adds two functionalities:
+ * <li>A delayed popup menu is shown immiadetely once the mouse is dragged downwards
+ * much like the KToolBarButton
+ * <li>If a popup menu is set a little arrow indicates this.
+ */
+class LIBK3B_EXPORT K3bToolButton : public QToolButton
+{
+ public:
+ K3bToolButton( QWidget* parent = 0 );
+ ~K3bToolButton();
+
+ void setInstantMenu( bool );
+
+ protected:
+ virtual void drawButton( QPainter* );
+ virtual bool eventFilter( QObject*, QEvent* );
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/libk3b/tools/k3bvalidators.cpp b/libk3b/tools/k3bvalidators.cpp
new file mode 100644
index 0000000..9252fdd
--- /dev/null
+++ b/libk3b/tools/k3bvalidators.cpp
@@ -0,0 +1,154 @@
+/*
+ *
+ * $Id: k3bvalidators.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3bvalidators.h"
+
+#include <ctype.h>
+
+
+K3bCharValidator::K3bCharValidator( QObject* parent, const char* name )
+ : QValidator( parent, name ),
+ m_replaceChar( '_' )
+{
+}
+
+
+QValidator::State K3bCharValidator::validate( QString& s, int& pos ) const
+{
+ Q_UNUSED(pos);
+
+ for( unsigned int i = 0; i < s.length(); ++i ) {
+ State r = validateChar( s[i] );
+ if( r != Acceptable )
+ return r;
+ }
+
+ return Acceptable;
+}
+
+
+void K3bCharValidator::fixup( QString& s ) const
+{
+ for( unsigned int i = 0; i < s.length(); ++i ) {
+ if( validateChar( s[i] ) != Acceptable )
+ s[i] = m_replaceChar;
+ }
+}
+
+
+K3bLatin1Validator::K3bLatin1Validator( QObject* parent, const char* name )
+ : K3bCharValidator( parent, name )
+{
+}
+
+
+QValidator::State K3bLatin1Validator::validateChar( const QChar& c ) const
+{
+ if( !c.latin1() )
+ return Invalid;
+ else
+ return Acceptable;
+}
+
+
+K3bAsciiValidator::K3bAsciiValidator( QObject* parent, const char* name )
+ : K3bLatin1Validator( parent, name )
+{
+}
+
+
+QValidator::State K3bAsciiValidator::validateChar( const QChar& c ) const
+{
+ if( K3bLatin1Validator::validateChar( c ) == Invalid )
+ return Invalid;
+ else if( !isascii( c.latin1() ) )
+ return Invalid;
+ else
+ return Acceptable;
+}
+
+
+
+K3bValidator::K3bValidator( QObject* parent, const char* name )
+ : QRegExpValidator( parent, name ),
+ m_replaceChar('_')
+{
+}
+
+
+K3bValidator::K3bValidator( const QRegExp& rx, QObject* parent, const char* name )
+ : QRegExpValidator( rx, parent, name ),
+ m_replaceChar('_')
+{
+}
+
+
+void K3bValidator::fixup( QString& input ) const
+{
+ for( unsigned int i = 0; i < input.length(); ++i )
+ if( !regExp().exactMatch( input.mid(i, 1) ) )
+ input[i] = m_replaceChar;
+}
+
+
+QString K3bValidators::fixup( const QString& input, const QRegExp& rx, const QChar& replaceChar )
+{
+ QString s;
+ for( unsigned int i = 0; i < input.length(); ++i )
+ if( rx.exactMatch( input.mid(i, 1) ) )
+ s += input[i];
+ else
+ s += replaceChar;
+ return s;
+}
+
+
+K3bValidator* K3bValidators::isrcValidator( QObject* parent, const char* name )
+{
+ return new K3bValidator( QRegExp("^[A-Z\\d]{2,2}-[A-Z\\d]{3,3}-\\d{2,2}-\\d{5,5}$"), parent, name );
+}
+
+
+K3bValidator* K3bValidators::iso9660Validator( bool allowEmpty, QObject* parent, const char* name )
+{
+ if( allowEmpty )
+ return new K3bValidator( QRegExp( "[^/]*" ), parent, name );
+ else
+ return new K3bValidator( QRegExp( "[^/]+" ), parent, name );
+}
+
+
+K3bValidator* K3bValidators::iso646Validator( int type, bool AllowLowerCase, QObject* parent, const char* name )
+{
+ QRegExp rx;
+ switch ( type ) {
+ case Iso646_d:
+ if ( AllowLowerCase )
+ rx = QRegExp( "[a-zA-Z0-9_]*" );
+ else
+ rx = QRegExp( "[A-Z0-9_]*" );
+ break;
+ case Iso646_a:
+ default:
+ if ( AllowLowerCase )
+ rx = QRegExp( "[a-zA-Z0-9!\"\\s%&'\\(\\)\\*\\+,\\-\\./:;<=>\\?_]*" );
+ else
+ rx = QRegExp( "[A-Z0-9!\"\\s%&'\\(\\)\\*\\+,\\-\\./:;<=>\\?_]*" );
+ break;
+ }
+
+ return new K3bValidator( rx, parent, name );
+}
diff --git a/libk3b/tools/k3bvalidators.h b/libk3b/tools/k3bvalidators.h
new file mode 100644
index 0000000..89c6397
--- /dev/null
+++ b/libk3b/tools/k3bvalidators.h
@@ -0,0 +1,131 @@
+/*
+ *
+ * $Id: k3bvalidators.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef _K3B_VALIDATORS_H_
+#define _K3B_VALIDATORS_H_
+
+#include <qvalidator.h>
+#include "k3b_export.h"
+
+
+/**
+ * Simple validator that validates a string char by char
+ */
+class LIBK3B_EXPORT K3bCharValidator : public QValidator
+{
+ public:
+ K3bCharValidator( QObject* parent = 0, const char* name = 0 );
+
+ virtual State validateChar( const QChar& ) const = 0;
+
+ virtual State validate( QString& s, int& pos ) const;
+
+ /**
+ * Replaces all invalid chars with the repplace char
+ */
+ virtual void fixup( QString& ) const;
+
+ /**
+ * Default to '_'
+ */
+ void setReplaceChar( const QChar& c ) { m_replaceChar = c; }
+
+ private:
+ QChar m_replaceChar;
+};
+
+
+class LIBK3B_EXPORT K3bLatin1Validator : public K3bCharValidator
+{
+ public:
+ K3bLatin1Validator( QObject* parent = 0, const char* name = 0 );
+
+ virtual State validateChar( const QChar& ) const;
+};
+
+
+class LIBK3B_EXPORT K3bAsciiValidator : public K3bLatin1Validator
+{
+ public:
+ K3bAsciiValidator( QObject* parent = 0, const char* name = 0 );
+
+ virtual State validateChar( const QChar& ) const;
+};
+
+
+/**
+ * The K3bValidator extends QRegExpValidator with a fixup method
+ * that just replaces all characters that are not allowed with the
+ * replace character. It only makes sense for QRegExps that simply
+ * allow or forbid some characters.
+ */
+class LIBK3B_EXPORT K3bValidator : public QRegExpValidator
+{
+ public:
+ K3bValidator( QObject* parent, const char * name = 0 );
+ K3bValidator( const QRegExp& rx, QObject* parent, const char* name = 0 );
+
+ void setReplaceChar( const QChar& s ) { m_replaceChar = s; }
+ const QChar& replaceChar() const { return m_replaceChar; }
+
+ virtual void fixup( QString& ) const;
+
+ private:
+ QChar m_replaceChar;
+};
+
+
+namespace K3bValidators
+{
+ /**
+ * just replaces all characters that are not allowed with the
+ * replace character. It only makes sense for QRegExps that simply
+ * allow or forbid some characters.
+ */
+ LIBK3B_EXPORT QString fixup( const QString&, const QRegExp&, const QChar& replaceChar = '_' );
+
+ /**
+ * Validates an ISRC code of the form "CCOOOYYSSSSS" where:
+ * <ul>
+ * <li>C: country code (upper case letters or digits)</li>
+ * <li>O: owner code (upper case letters or digits)</li>
+ * <li>Y: year (digits)</li>
+ * <li>S: serial number (digits)</li>
+ * </ul>
+ */
+ LIBK3B_EXPORT K3bValidator* isrcValidator( QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * This needs to be replaced by something better in the future...
+ * Even the name sucks!
+ */
+ LIBK3B_EXPORT K3bValidator* iso9660Validator( bool allowEmpty = true, QObject* parent = 0, const char* name = 0 );
+
+ /**
+ * (1) d-characters are: A-Z, 0-9, _ (see ISO-9660:1988, Annex A, Table 15)
+ * (2) a-characters are: A-Z, 0-9, _, space, !, ", %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?
+ * (see ISO-9660:1988, Annex A, Table 14)
+ */
+ enum Iso646Type {
+ Iso646_a,
+ Iso646_d
+ };
+
+ LIBK3B_EXPORT K3bValidator* iso646Validator( int type = Iso646_a,
+ bool AllowLowerCase = false,
+ QObject* parent = 0, const char* name = 0 );
+}
+
+#endif
diff --git a/libk3b/tools/k3bwavefilewriter.cpp b/libk3b/tools/k3bwavefilewriter.cpp
new file mode 100644
index 0000000..36267c2
--- /dev/null
+++ b/libk3b/tools/k3bwavefilewriter.cpp
@@ -0,0 +1,186 @@
+/*
+ *
+ * $Id: k3bwavefilewriter.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3bwavefilewriter.h"
+#include <kdebug.h>
+
+K3bWaveFileWriter::K3bWaveFileWriter()
+ : m_outputStream( &m_outputFile )
+{
+}
+
+
+K3bWaveFileWriter::~K3bWaveFileWriter()
+{
+ close();
+}
+
+
+bool K3bWaveFileWriter::open( const QString& filename )
+{
+ close();
+
+ m_outputFile.setName( filename );
+
+ if( m_outputFile.open( IO_ReadWrite ) ) {
+ m_filename = filename;
+
+ writeEmptyHeader();
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+void K3bWaveFileWriter::close()
+{
+ if( isOpen() ) {
+ if( m_outputFile.at() > 0 ) {
+ padTo2352();
+
+ // update wave header
+ updateHeader();
+
+ m_outputFile.close();
+ }
+ else {
+ m_outputFile.close();
+ m_outputFile.remove();
+ }
+ }
+
+ m_filename = QString::null;
+}
+
+
+bool K3bWaveFileWriter::isOpen()
+{
+ return m_outputFile.isOpen();
+}
+
+
+const QString& K3bWaveFileWriter::filename() const
+{
+ return m_filename;
+}
+
+
+void K3bWaveFileWriter::write( const char* data, int len, Endianess e )
+{
+ if( isOpen() ) {
+ if( e == LittleEndian ) {
+ m_outputStream.writeRawBytes( data, len );
+ }
+ else {
+ if( len % 2 > 0 ) {
+ kdDebug() << "(K3bWaveFileWriter) data length ("
+ << len << ") is not a multiple of 2! Cannot swap bytes." << endl;
+ return;
+ }
+
+ // we need to swap the bytes
+ char* buffer = new char[len];
+ for( int i = 0; i < len-1; i+=2 ) {
+ buffer[i] = data[i+1];
+ buffer[i+1] = data[i];
+ }
+ m_outputStream.writeRawBytes( buffer, len );
+
+ delete [] buffer;
+ }
+ }
+}
+
+
+void K3bWaveFileWriter::writeEmptyHeader()
+{
+ static const char riffHeader[] =
+ {
+ 0x52, 0x49, 0x46, 0x46, // 0 "RIFF"
+ 0x00, 0x00, 0x00, 0x00, // 4 wavSize
+ 0x57, 0x41, 0x56, 0x45, // 8 "WAVE"
+ 0x66, 0x6d, 0x74, 0x20, // 12 "fmt "
+ 0x10, 0x00, 0x00, 0x00, // 16
+ 0x01, 0x00, 0x02, 0x00, // 20
+ 0x44, 0xac, 0x00, 0x00, // 24
+ 0x10, 0xb1, 0x02, 0x00, // 28
+ 0x04, 0x00, 0x10, 0x00, // 32
+ 0x64, 0x61, 0x74, 0x61, // 36 "data"
+ 0x00, 0x00, 0x00, 0x00 // 40 byteCount
+ };
+
+ m_outputStream.writeRawBytes( riffHeader, 44 );
+}
+
+
+void K3bWaveFileWriter::updateHeader()
+{
+ if( isOpen() ) {
+
+ m_outputFile.flush();
+
+ Q_INT32 dataSize( m_outputFile.at() - 44 );
+ Q_INT32 wavSize(dataSize + 44 - 8);
+ char c[4];
+
+ // jump to the wavSize position in the header
+ if( m_outputFile.at( 4 ) ) {
+ c[0] = (wavSize >> 0 ) & 0xff;
+ c[1] = (wavSize >> 8 ) & 0xff;
+ c[2] = (wavSize >> 16) & 0xff;
+ c[3] = (wavSize >> 24) & 0xff;
+ m_outputStream.writeRawBytes( c, 4 );
+ }
+ else
+ kdDebug() << "(K3bWaveFileWriter) unable to seek in file: " << m_outputFile.name() << endl;
+
+ if( m_outputFile.at( 40 ) ) {
+ c[0] = (dataSize >> 0 ) & 0xff;
+ c[1] = (dataSize >> 8 ) & 0xff;
+ c[2] = (dataSize >> 16) & 0xff;
+ c[3] = (dataSize >> 24) & 0xff;
+ m_outputStream.writeRawBytes( c, 4 );
+ }
+ else
+ kdDebug() << "(K3bWaveFileWriter) unable to seek in file: " << m_outputFile.name() << endl;
+
+ // jump back to the end
+ m_outputFile.at( m_outputFile.size() );
+ }
+}
+
+
+void K3bWaveFileWriter::padTo2352()
+{
+ int bytesToPad = ( m_outputFile.at() - 44 ) % 2352;
+ if( bytesToPad > 0 ) {
+ kdDebug() << "(K3bWaveFileWriter) padding wave file with " << bytesToPad << " bytes." << endl;
+
+ char* c = new char[bytesToPad];
+ memset( c, 0, bytesToPad );
+ m_outputStream.writeRawBytes( c, bytesToPad );
+ delete [] c;
+ }
+}
+
+
+int K3bWaveFileWriter::fd() const
+{
+ return m_outputFile.handle();
+}
diff --git a/libk3b/tools/k3bwavefilewriter.h b/libk3b/tools/k3bwavefilewriter.h
new file mode 100644
index 0000000..e5394a5
--- /dev/null
+++ b/libk3b/tools/k3bwavefilewriter.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * $Id: k3bwavefilewriter.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef K3BWAVEFILEWRITER_H
+#define K3BWAVEFILEWRITER_H
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include "k3b_export.h"
+/**
+ * @author Sebastian Trueg
+ * Creates wave files from 16bit stereo little or big endian
+ * sound samples
+ */
+class LIBK3B_EXPORT K3bWaveFileWriter
+{
+ public:
+
+ enum Endianess { BigEndian, LittleEndian };
+
+ K3bWaveFileWriter();
+ ~K3bWaveFileWriter();
+
+ /**
+ * open a new wave file.
+ * closes any opened file.
+ */
+ bool open( const QString& filename );
+
+ bool isOpen();
+ const QString& filename() const;
+
+ /**
+ * closes the file.
+ * Length of the wave file will be written into the header.
+ * If no data has been written to the file except the header
+ * it will be removed.
+ */
+ void close();
+
+ /**
+ * write 16bit samples to the file.
+ * @param e the endianess of the data
+ * (it will be swapped to little endian byte order if necessary)
+ */
+ void write( const char* data, int len, Endianess e = BigEndian );
+
+ /**
+ * returnes a filedescriptor with the already opened file
+ * or -1 if isOpen() is false
+ */
+ int fd() const;
+
+ private:
+ void writeEmptyHeader();
+ void updateHeader();
+ void padTo2352();
+
+ QFile m_outputFile;
+ QDataStream m_outputStream;
+ QString m_filename;
+};
+
+#endif
diff --git a/libk3b/tools/kcutlabel.cpp b/libk3b/tools/kcutlabel.cpp
new file mode 100644
index 0000000..accbe17
--- /dev/null
+++ b/libk3b/tools/kcutlabel.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * $Id: kcutlabel.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "kcutlabel.h"
+
+#include <k3bstringutils.h>
+
+#include <qtooltip.h>
+#include <qstringlist.h>
+#include <kdebug.h>
+
+
+KCutLabel::KCutLabel( const QString &text , QWidget *parent, const char *name )
+ : QLabel ( parent, name ),
+ m_minChars(1) {
+ QSizePolicy myLabelSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+ setSizePolicy(myLabelSizePolicy);
+ m_fullText = text;
+ cutTextToLabel();
+}
+
+KCutLabel::KCutLabel( QWidget *parent, const char *name )
+ : QLabel ( parent, name ),
+ m_minChars(1) {
+ QSizePolicy myLabelSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+ setSizePolicy(myLabelSizePolicy);
+}
+
+QSize KCutLabel::minimumSizeHint() const
+{
+ QSize sh = QLabel::minimumSizeHint();
+ if( m_minChars == 0 )
+ sh.setWidth(-1);
+ else if( m_minChars < (int)m_fullText.length() )
+ sh.setWidth( QMIN( fontMetrics().width( m_fullText.left(m_minChars) + "..." ),
+ fontMetrics().width( m_fullText ) ) );
+
+ return sh;
+}
+
+
+void KCutLabel::setMinimumVisibleText( int i )
+{
+ m_minChars = i;
+ cutTextToLabel();
+}
+
+
+void KCutLabel::resizeEvent( QResizeEvent * )
+{
+ cutTextToLabel();
+}
+
+void KCutLabel::setText( const QString &text )
+{
+ m_fullText = text;
+ cutTextToLabel();
+}
+
+
+const QString& KCutLabel::fullText() const
+{
+ return m_fullText;
+}
+
+
+void KCutLabel::cutTextToLabel()
+{
+ QToolTip::remove( this );
+ QToolTip::hide();
+
+ if( m_fullText.contains( "\n" ) ) {
+ QString newText;
+ QStringList lines = QStringList::split( "\n", m_fullText );
+ for( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
+ QString squeezedText = K3b::cutToWidth( fontMetrics(),
+ *it,
+ QMAX( size().width(),
+ QMIN( fontMetrics().width( m_fullText.left(m_minChars) + "..." ),
+ fontMetrics().width( m_fullText ) ) ) );
+ newText += squeezedText;
+ newText += "\n";
+ if( squeezedText != *it )
+ QToolTip::add( this, m_fullText );
+ }
+ newText.truncate( newText.length() - 1 ); // get rid of the last newline
+
+ QLabel::setText( newText );
+ }
+ else {
+ QString squeezedText = K3b::cutToWidth( fontMetrics(),
+ m_fullText,
+ QMAX( size().width(),
+ QMIN( fontMetrics().width( m_fullText.left(m_minChars) + "..." ),
+ fontMetrics().width( m_fullText ) ) ) );
+ QLabel::setText( squeezedText );
+ if( squeezedText != m_fullText )
+ QToolTip::add( this, m_fullText );
+ }
+}
+
+#include "kcutlabel.moc"
diff --git a/libk3b/tools/kcutlabel.h b/libk3b/tools/kcutlabel.h
new file mode 100644
index 0000000..6cf459c
--- /dev/null
+++ b/libk3b/tools/kcutlabel.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * $Id: kcutlabel.h 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * 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.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#ifndef KCUTLABEL_H
+#define KCUTLABEL_H
+
+#include <qlabel.h>
+#include "k3b_export.h"
+
+
+/*
+ * @ref QLabel
+ */
+class LIBK3B_EXPORT KCutLabel : public QLabel
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Default constructor.
+ */
+ KCutLabel( QWidget *parent = 0, const char *name = 0);
+ KCutLabel( const QString &text, QWidget *parent = 0, const char *name = 0 );
+
+ virtual QSize minimumSizeHint() const;
+
+ /**
+ * \return the full text while text() returns the cut text
+ */
+ const QString& fullText() const;
+
+ public slots:
+ void setText( const QString & );
+
+ /**
+ * \param i the number of characters that have to be visible. Default is 1.
+ */
+ void setMinimumVisibleText( int i );
+
+ protected:
+ /**
+ * used when widget is resized
+ */
+ void resizeEvent( QResizeEvent * );
+ /**
+ * does the dirty work
+ */
+ void cutTextToLabel();
+
+ private:
+ QString m_fullText;
+ int m_minChars;
+};
+
+#endif // KCUTLABEL_H
diff --git a/libk3b/tools/libisofs/COPYING b/libk3b/tools/libisofs/COPYING
new file mode 100644
index 0000000..9fe1a71
--- /dev/null
+++ b/libk3b/tools/libisofs/COPYING
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Steet, Fifth Floor, Cambridge, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/libk3b/tools/libisofs/ChangeLog b/libk3b/tools/libisofs/ChangeLog
new file mode 100644
index 0000000..78d7e66
--- /dev/null
+++ b/libk3b/tools/libisofs/ChangeLog
@@ -0,0 +1,9 @@
+K3b Changes
+- renamed the st_xxx time fileds in rr_entry to rr_st_xxx to make it compile
+
+0.1 -> 0.2
+
+- Critical directory parsing bug fixed
+- Call backs only if some sanity checks on the directory entry succeeds
+ (length checks to avoid buffer overrun if received corrupt data)
+- Preliminary El Torito boot specification support (No multiple boot entries yet)
diff --git a/libk3b/tools/libisofs/Makefile.am b/libk3b/tools/libisofs/Makefile.am
new file mode 100644
index 0000000..cd5594c
--- /dev/null
+++ b/libk3b/tools/libisofs/Makefile.am
@@ -0,0 +1,5 @@
+AM_CPPFLAGS= $(all_includes)
+
+noinst_LTLIBRARIES = libisofs.la
+
+libisofs_la_SOURCES = isofs.cpp
diff --git a/libk3b/tools/libisofs/README b/libk3b/tools/libisofs/README
new file mode 100644
index 0000000..3657861
--- /dev/null
+++ b/libk3b/tools/libisofs/README
@@ -0,0 +1,24 @@
+This is the 0.2 release of libisofs. For changes, see the ChangeLog.
+
+Libisofs implements the reading of the famous ISO-9660 (ECMA-167) file system,
+found on CD-ROM media. It also supports the Rock Ridge Interchange Protocol and
+Microsoft Joliet extensions. It allows user-mode programs to query the
+filesystem volume descriptors and traverse through the directory structure.
+Preliminary support for El-Torito boot CDs are added in version 0.2.
+
+To use it in your project, I recommend to copy bswap.h, isofs.h, iso_fs.h,
+el_torito.h rock.h and isofs.c to your sources, and include isofs.h in the
+appropriate places.
+
+Currently only the directory tables are parsed, the path tables are not.
+(The path tables contain redundant information.)
+
+Also a sample program can be compiled with the supplied Makefile. Simply
+execute 'make', it should create the executable file isofs.
+
+On big-endian systems, you need to define WORDS_BIGENDIAN (either in the
+compiler command-line, or if you defined HAVE_CONFIG_H, in config.h)
+
+
+Gyrgy Szombathelyi <gyurco@users.sourceforge.net>
+http://libcdrom.sourceforge.net/libisofs.html
diff --git a/libk3b/tools/libisofs/bswap.h b/libk3b/tools/libisofs/bswap.h
new file mode 100644
index 0000000..96bd588
--- /dev/null
+++ b/libk3b/tools/libisofs/bswap.h
@@ -0,0 +1,94 @@
+/* From the mplayer project (www.mplayerhq.hu) */
+
+#ifndef __BSWAP_H__
+#define __BSWAP_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+
+#ifdef ARCH_X86
+inline static unsigned short ByteSwap16(unsigned short x)
+{
+ __asm("xchgb %b0,%h0" :
+ "=q" (x) :
+ "0" (x));
+ return x;
+}
+#define bswap_16(x) ByteSwap16(x)
+
+inline static unsigned int ByteSwap32(unsigned int x)
+{
+#if defined(__CPU__) && (__CPU__ > 386)
+ __asm("bswap %0":
+ "=r" (x) :
+#else
+ __asm("xchgb %b0,%h0\n"
+ " rorl $16,%0\n"
+ " xchgb %b0,%h0":
+ "=q" (x) :
+#endif
+ "0" (x));
+ return x;
+}
+#define bswap_32(x) ByteSwap32(x)
+
+inline static unsigned long long int ByteSwap64(unsigned long long int x)
+{
+ register union { __extension__ unsigned long long int __ll;
+ unsigned int __l[2]; } __x;
+ asm("xchgl %0,%1":
+ "=r"(__x.__l[0]),"=r"(__x.__l[1]):
+ "0"(bswap_32((unsigned long)x)),"1"(bswap_32((unsigned long)(x>>32))));
+ return __x.__ll;
+}
+#define bswap_64(x) ByteSwap64(x)
+
+#else
+
+#define bswap_16(x) (((x) & 0x00ff) << 8 | ((x) & 0xff00) >> 8)
+
+
+/* code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. */
+#define bswap_32(x) \
+ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
+
+#define bswap_64(x) \
+ (__extension__ \
+ ({ union { __extension__ unsigned long long int __ll; \
+ unsigned int __l[2]; } __w, __r; \
+ __w.__ll = (x); \
+ __r.__l[0] = bswap_32 (__w.__l[1]); \
+ __r.__l[1] = bswap_32 (__w.__l[0]); \
+ __r.__ll; }))
+#endif /* !ARCH_X86 */
+
+#endif /* !HAVE_BYTESWAP_H */
+
+/*
+ be2me ... BigEndian to MachineEndian
+ le2me ... LittleEndian to MachineEndian
+*/
+
+#ifdef WORDS_BIGENDIAN
+#define be2me_16(x) (x)
+#define be2me_32(x) (x)
+#define be2me_64(x) (x)
+#define le2me_16(x) bswap_16(x)
+#define le2me_32(x) bswap_32(x)
+#define le2me_64(x) bswap_64(x)
+#else
+#define be2me_16(x) bswap_16(x)
+#define be2me_32(x) bswap_32(x)
+#define be2me_64(x) bswap_64(x)
+#define le2me_16(x) (x)
+#define le2me_32(x) (x)
+#define le2me_64(x) (x)
+#endif
+
+#endif
diff --git a/libk3b/tools/libisofs/el_torito.h b/libk3b/tools/libisofs/el_torito.h
new file mode 100644
index 0000000..cba83f7
--- /dev/null
+++ b/libk3b/tools/libisofs/el_torito.h
@@ -0,0 +1,63 @@
+#ifndef ELTORITO_H
+#define ELTORITO_H 1
+
+#include "iso_fs.h"
+
+#define EL_TORITO_ID "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"
+
+struct el_torito_boot_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char system_id [ISODCL ( 8, 39)]; /* achars */
+ char unused [ISODCL ( 40, 71)];
+ char boot_catalog [ISODCL ( 72, 75)]; /* 731 */
+};
+
+struct validation_entry {
+ char type [ISODCL ( 1, 1)]; /* 1 */
+ char platform [ISODCL ( 2, 2)];
+ char unused [ISODCL ( 3, 4)];
+ char id [ISODCL ( 5, 28)];
+ char cheksum [ISODCL ( 29, 30)];
+ char key [ISODCL ( 31, 31)]; /* 0x55 */
+ char key2 [ISODCL ( 32, 32)]; /* 0xaa */
+};
+
+struct default_entry {
+ char bootid [ISODCL ( 1, 1)];
+ char media [ISODCL ( 2, 2)];
+ char loadseg [ISODCL ( 3, 4)];
+ char systype [ISODCL ( 5, 5)];
+ char unused [ISODCL ( 6, 6)];
+ char seccount [ISODCL ( 7, 8)];
+ char start [ISODCL ( 9, 12)];
+ char unused2 [ISODCL ( 13, 32)];
+};
+
+struct section_header {
+ char headerid [ISODCL ( 1, 1)];
+ char platform [ISODCL ( 2, 2)];
+ char entries [ISODCL ( 3, 4)];
+ char id [ISODCL ( 5, 32)];
+};
+
+struct section_entry {
+ char bootid [ISODCL ( 1, 1)];
+ char media [ISODCL ( 2, 2)];
+ char loadseg [ISODCL ( 3, 4)];
+ char systype [ISODCL ( 5, 5)];
+ char unused [ISODCL ( 6, 6)];
+ char seccount [ISODCL ( 7, 8)];
+ char start [ISODCL ( 9, 12)];
+ char selcrit [ISODCL ( 13, 13)];
+ char vendor_selcrit [ISODCL ( 14, 32)];
+};
+
+struct section_entry_ext {
+ char extid [ISODCL ( 1, 1)];
+ char extrec [ISODCL ( 2, 2)];
+ char vendor_selcrit [ISODCL ( 3, 32)];
+};
+
+#endif
diff --git a/libk3b/tools/libisofs/iso_fs.h b/libk3b/tools/libisofs/iso_fs.h
new file mode 100644
index 0000000..43353b0
--- /dev/null
+++ b/libk3b/tools/libisofs/iso_fs.h
@@ -0,0 +1,219 @@
+/* From the linux kernel */
+
+#ifndef _ISO_FS_H
+#define _ISO_FS_H 1
+
+#include "bswap.h"
+
+/*
+ * The isofs filesystem constants/structures
+ */
+
+/* This part borrowed from the bsd386 isofs */
+#define ISODCL(from, to) (to - from + 1)
+
+struct iso_volume_descriptor {
+ char type[ISODCL(1,1)]; /* 711 */
+ char id[ISODCL(2,6)];
+ char version[ISODCL(7,7)];
+ char data[ISODCL(8,2048)];
+};
+
+/* volume descriptor types */
+#define ISO_VD_BOOT 0
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_SUPPLEMENTARY 2
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+
+struct iso_primary_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char unused1 [ISODCL ( 8, 8)];
+ char system_id [ISODCL ( 9, 40)]; /* achars */
+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
+ char unused2 [ISODCL ( 73, 80)];
+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ char unused3 [ISODCL ( 89, 120)];
+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ char path_table_size [ISODCL (133, 140)]; /* 733 */
+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
+ char publisher_id [ISODCL (319, 446)]; /* achars */
+ char preparer_id [ISODCL (447, 574)]; /* achars */
+ char application_id [ISODCL (575, 702)]; /* achars */
+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ char unused4 [ISODCL (883, 883)];
+ char application_data [ISODCL (884, 1395)];
+ char unused5 [ISODCL (1396, 2048)];
+};
+
+/* Almost the same as the primary descriptor but two fields are specified */
+struct iso_supplementary_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char flags [ISODCL ( 8, 8)]; /* 853 */
+ char system_id [ISODCL ( 9, 40)]; /* achars */
+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
+ char unused2 [ISODCL ( 73, 80)];
+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ char escape [ISODCL ( 89, 120)]; /* 856 */
+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ char path_table_size [ISODCL (133, 140)]; /* 733 */
+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
+ char publisher_id [ISODCL (319, 446)]; /* achars */
+ char preparer_id [ISODCL (447, 574)]; /* achars */
+ char application_id [ISODCL (575, 702)]; /* achars */
+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ char unused4 [ISODCL (883, 883)];
+ char application_data [ISODCL (884, 1395)];
+ char unused5 [ISODCL (1396, 2048)];
+};
+
+#define HS_STANDARD_ID "CDROM"
+
+struct hs_volume_descriptor {
+ char foo [ISODCL ( 1, 8)]; /* 733 */
+ char type [ISODCL ( 9, 9)]; /* 711 */
+ char id [ISODCL ( 10, 14)];
+ char version [ISODCL ( 15, 15)]; /* 711 */
+ char data[ISODCL(16,2048)];
+};
+
+
+struct hs_primary_descriptor {
+ char foo [ISODCL ( 1, 8)]; /* 733 */
+ char type [ISODCL ( 9, 9)]; /* 711 */
+ char id [ISODCL ( 10, 14)];
+ char version [ISODCL ( 15, 15)]; /* 711 */
+ char unused1 [ISODCL ( 16, 16)]; /* 711 */
+ char system_id [ISODCL ( 17, 48)]; /* achars */
+ char volume_id [ISODCL ( 49, 80)]; /* dchars */
+ char unused2 [ISODCL ( 81, 88)]; /* 733 */
+ char volume_space_size [ISODCL ( 89, 96)]; /* 733 */
+ char unused3 [ISODCL ( 97, 128)]; /* 733 */
+ char volume_set_size [ISODCL (129, 132)]; /* 723 */
+ char volume_sequence_number [ISODCL (133, 136)]; /* 723 */
+ char logical_block_size [ISODCL (137, 140)]; /* 723 */
+ char path_table_size [ISODCL (141, 148)]; /* 733 */
+ char type_l_path_table [ISODCL (149, 152)]; /* 731 */
+ char unused4 [ISODCL (153, 180)]; /* 733 */
+ char root_directory_record [ISODCL (181, 214)]; /* 9.1 */
+};
+
+/* We use this to help us look up the parent inode numbers. */
+
+struct iso_path_table{
+ char name_len[1]; /* 711 */
+ char ext_attr_length[1]; /* 711 */
+ char extent[4]; /* 731 */
+ char parent[2]; /* 721 */
+ char name[1];
+};
+
+/* high sierra is identical to iso, except that the date is only 6 bytes, and
+ there is an extra reserved byte after the flags */
+
+struct iso_directory_record {
+ char length [ISODCL (1, 1)]; /* 711 */
+ char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ char extent [ISODCL (3, 10)]; /* 733 */
+ char size [ISODCL (11, 18)]; /* 733 */
+ char date [ISODCL (19, 25)]; /* 7 by 711 */
+ char flags [ISODCL (26, 26)];
+ char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ char interleave [ISODCL (28, 28)]; /* 711 */
+ char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ char name_len [ISODCL (33, 33)]; /* 711 */
+ char name [1];
+};
+
+/* 8 bit numbers */
+__inline unsigned char isonum_711(char *p);
+__inline char isonum_712(char *p);
+
+/* 16 bit numbers */
+__inline unsigned short isonum_721(char *p);
+__inline unsigned short isonum_722(char *p);
+__inline unsigned short isonum_723(char *p);
+
+/* 32 bit numbers */
+__inline unsigned int isonum_731(char *p);
+__inline unsigned int isonum_732(char *p);
+__inline unsigned int isonum_733(char *p);
+
+
+/* 8 bit numbers */
+__inline unsigned char isonum_711(char *p)
+{
+ return *(unsigned char *)p;
+}
+__inline char isonum_712(char *p)
+{
+ return *p;
+}
+
+/* 16 bit numbers */
+__inline unsigned short isonum_721(char *p)
+{
+ return le2me_16(*(unsigned short *)p);
+}
+__inline unsigned short isonum_722(char *p)
+{
+ return be2me_16(*(unsigned short *)p);
+}
+__inline unsigned short isonum_723(char *p)
+{
+ /* Ignore bigendian datum due to broken mastering programs */
+ return le2me_16(*(unsigned short *)p);
+}
+
+/* 32 bit numbers */
+__inline unsigned int isonum_731(char *p)
+{
+ return le2me_32(*(unsigned int *)p);
+}
+
+__inline unsigned int isonum_732(char *p)
+{
+ return be2me_32(*(unsigned int *)p);
+}
+
+__inline unsigned int isonum_733(char *p)
+{
+ /* Ignore bigendian datum due to broken mastering programs */
+ return le2me_32(*(unsigned int *)p);
+}
+
+#endif /*_ISOFS_H*/
+
diff --git a/libk3b/tools/libisofs/isofs.cpp b/libk3b/tools/libisofs/isofs.cpp
new file mode 100644
index 0000000..e5c871b
--- /dev/null
+++ b/libk3b/tools/libisofs/isofs.cpp
@@ -0,0 +1,878 @@
+/***************************************************************************
+ isofs.c - libisofs implementation
+ -------------------
+ begin : Oct 25 2002
+ copyright : (C) 2002 by Szombathelyi Gyrgy
+ email : gyurco@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "isofs.h"
+#include "rock.h"
+
+
+
+/* internal function from the linux kernel (isofs fs) */
+static time_t getisotime(int year,int month,int day,int hour,
+ int minute,int second,int tz) {
+
+ int days, i;
+ time_t crtime;
+
+ year-=1970;
+
+ if (year < 0) {
+ crtime = 0;
+ } else {
+ int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+
+ days = year * 365;
+ if (year > 2)
+ days += (year+1) / 4;
+ for (i = 1; i < month; i++)
+ days += monlen[i-1];
+ if (((year+2) % 4) == 0 && month > 2)
+ days++;
+ days += day - 1;
+ crtime = ((((days * 24) + hour) * 60 + minute) * 60)
+ + second;
+
+ /* sign extend */
+ if (tz & 0x80)
+ tz |= (-1 << 8);
+
+ /*
+ * The timezone offset is unreliable on some disks,
+ * so we make a sanity check. In no case is it ever
+ * more than 13 hours from GMT, which is 52*15min.
+ * The time is always stored in localtime with the
+ * timezone offset being what get added to GMT to
+ * get to localtime. Thus we need to subtract the offset
+ * to get to true GMT, which is what we store the time
+ * as internally. On the local system, the user may set
+ * their timezone any way they wish, of course, so GMT
+ * gets converted back to localtime on the receiving
+ * system.
+ *
+ * NOTE: mkisofs in versions prior to mkisofs-1.10 had
+ * the sign wrong on the timezone offset. This has now
+ * been corrected there too, but if you are getting screwy
+ * results this may be the explanation. If enough people
+ * complain, a user configuration option could be added
+ * to add the timezone offset in with the wrong sign
+ * for 'compatibility' with older discs, but I cannot see how
+ * it will matter that much.
+ *
+ * Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
+ * for pointing out the sign error.
+ */
+ if (-52 <= tz && tz <= 52)
+ crtime -= tz * 15 * 60;
+ }
+ return crtime;
+
+}
+
+/**
+ * Returns the Unix from the ISO9660 9.1.5 time format
+ */
+time_t isodate_915(char * p, int hs) {
+
+ return getisotime(1900+p[0],p[1],p[2],p[3],p[4],p[5],hs==0 ? p[6] : 0);
+}
+
+/**
+ * Returns the Unix from the ISO9660 8.4.26.1 time format
+ * BUG: hundredth of seconds are ignored, because Unix time_t has one second
+ * resolution (I think it's no problem at all)
+ */
+time_t isodate_84261(char * p, int hs) {
+ int year,month,day,hour,minute,second;
+ year=(p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + p[3]-'0';
+ month=(p[4]-'0')*10 + (p[5]-'0');
+ day=(p[6]-'0')*10 + (p[7]-'0');
+ hour=(p[8]-'0')*10 + (p[9]-'0');
+ minute=(p[10]-'0')*10 + (p[11]-'0');
+ second=(p[12]-'0')*10 + (p[13]-'0');
+ return getisotime(year,month,day,hour,minute,second,hs==0 ? p[16] : 0);
+}
+
+void FreeBootTable(boot_head *boot) {
+ boot_entry *be,*next;
+
+ be=boot->defentry;
+ while (be) {
+ next=be->next;
+ free(be);
+ be=next;
+ }
+ boot->defentry=NULL;
+}
+
+int BootImageSize(readfunc* read,int media,sector_t start,int len,void* udata) {
+ int ret;
+
+ switch(media & 0xf) {
+ case 0:
+ ret=len; /* No emulation */
+ break;
+ case 1:
+ ret=80*2*15; /* 1.2 MB */
+ break;
+ case 2:
+ ret=80*2*18; /* 1.44 MB */
+ break;
+ case 3:
+ ret=80*2*36; /* 2.88 MB */
+ break;
+ case 4:
+ /* FIXME!!! */
+ ret=len; /* Hard Disk */
+ break;
+ default:
+ ret=len;
+ }
+ return ret;
+}
+
+static boot_entry *CreateBootEntry(char *be) {
+ boot_entry *entry;
+
+ entry = (boot_entry*) malloc(sizeof(boot_entry));
+ if (!entry) return NULL;
+ memset(entry, 0, sizeof(boot_entry));
+ memcpy(entry->data,be,0x20);
+ return entry;
+}
+
+int ReadBootTable(readfunc *read,sector_t sector, boot_head *head, void *udata) {
+
+ char buf[2048], *c, *be;
+ int i,end=0;
+ unsigned short sum;
+ boot_entry *defcur=NULL,*deflast=NULL;
+ register struct validation_entry *ventry=NULL;
+ register struct default_entry *dentry=NULL;
+ register struct section_header *sheader=NULL;
+ register struct section_entry *sentry=NULL;
+ register struct section_entry_ext *extsentry=NULL;
+
+ head->sections=NULL;
+ head->defentry=NULL;
+ while (1) {
+ be = (char*) &buf;
+ if ( read(be, sector, 1, udata) != 1 ) goto err;
+
+ /* first entry needs to be a validation entry */
+ if (!ventry) {
+ ventry=(struct validation_entry *) be;
+ if ( isonum_711(ventry->type) !=1 ) goto err;
+ sum=0;
+ c = (char*) ventry;
+ for (i=0;i<16;i++) { sum += isonum_721(c); c+=2; }
+ if (sum) goto err;
+ memcpy(&head->ventry,be,0x20);
+ be += 0x20;
+ }
+
+ while (!end && (be < (buf+1))) {
+ switch (isonum_711(be)) {
+ case 0x88:
+ defcur=CreateBootEntry(be);
+ if (!defcur) goto err;
+ if (deflast)
+ deflast->next=defcur;
+ else
+ head->defentry=defcur;
+ defcur->prev=deflast;
+ deflast=defcur;
+ break;
+ case 0x90:
+ case 0x91:
+ break;
+ default:
+ end=1;
+ break;
+ }
+ be += 0x20;
+ }
+ if (end) break;
+
+ sector ++;
+ }
+
+ return 0;
+
+err:
+ FreeBootTable(head);
+ return -1;
+}
+
+
+/**
+ * Creates the linked list of the volume descriptors
+ */
+iso_vol_desc *ReadISO9660(readfunc *read,sector_t sector,void *udata) {
+
+ int i;
+ struct iso_volume_descriptor buf;
+ iso_vol_desc *first=NULL,*current=NULL,*prev=NULL;
+
+ for (i=0;i<100;i++) {
+ if (read( (char*) &buf, sector+i+16, 1, udata) != 1 ) {
+ FreeISO9660(first);
+ return NULL;
+ }
+ if (!memcmp(ISO_STANDARD_ID,&buf.id,5)) {
+ switch ( isonum_711(&buf.type[0]) ) {
+
+ case ISO_VD_BOOT:
+ case ISO_VD_PRIMARY:
+ case ISO_VD_SUPPLEMENTARY:
+ current=(iso_vol_desc*) malloc(sizeof(iso_vol_desc));
+ if (!current) {
+ FreeISO9660(first);
+ return NULL;
+ }
+ current->prev=prev;
+ current->next=NULL;
+ if (prev) prev->next=current;
+ memcpy(&(current->data),&buf,2048);
+ if (!first) first=current;
+ prev=current;
+ break;
+
+ case ISO_VD_END:
+ return first;
+ break;
+ }
+ } else if (!memcmp(HS_STANDARD_ID,(struct hs_volume_descriptor*) &buf,5)) {
+ /* High Sierra format not supported (yet) */
+ }
+ }
+
+ return first;
+}
+
+/**
+ * Frees the linked list of volume descriptors
+ */
+void FreeISO9660(iso_vol_desc *data) {
+
+ iso_vol_desc *current;
+
+
+ while (data) {
+ current=data;
+ data=current->next;
+ free(current);
+ }
+}
+
+/**
+ * Frees the strings in 'rrentry'
+ */
+void FreeRR(rr_entry *rrentry) {
+ if (rrentry->name) {
+ free(rrentry->name);
+ rrentry->name=NULL;
+ }
+ if (rrentry->sl) {
+ free(rrentry->sl);
+ rrentry->name=NULL;
+ }
+}
+
+static int str_nappend(char **d,char *s,int n) {
+ int i=0;
+ char *c;
+
+/* i=strnlen(s,n)+1; */
+ while (i<n && s[i]) i++;
+ i++;
+ if (*d) i+=(strlen(*d)+1);
+ c=(char*) malloc(i);
+ if (!c) return -ENOMEM;
+ if (*d) {
+ strcpy(c,*d);
+ strncat(c,s,n);
+
+ free(*d);
+ } else
+ strncpy(c,s,n);
+ c[i-1]=0;
+ *d=c;
+ return 0;
+}
+
+static int str_append(char **d, const char *s) {
+ int i;
+ char *c;
+
+ i=strlen(s)+1;
+ if (*d) i+=(strlen(*d)+1);
+ c=(char*) malloc(i);
+ if (!c) return -ENOMEM;
+ if (*d) {
+ strcpy(c,*d);
+ strcat(c,s);
+ free(*d);
+ } else
+ strcpy(c,s);
+ c[i-1]=0;
+ *d=c;
+ return 0;
+}
+
+#define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7)
+#define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0)
+/**
+ * Parses the System Use area and fills rr_entry with values
+ */
+int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry) {
+
+ int suspoffs,susplen,i,f,ret=0;
+ char *r, *c;
+ struct rock_ridge *rr;
+
+ suspoffs=33+isonum_711(idr->name_len);
+ if (!(isonum_711(idr->name_len) & 1)) suspoffs++;
+ susplen=isonum_711(idr->length)-suspoffs;
+ r= & (((char*) idr)[suspoffs]);
+ rr = (struct rock_ridge*) r;
+
+ memset(rrentry,0,sizeof(rr_entry));
+ rrentry->len = sizeof(rr_entry);
+
+ while (susplen > 0) {
+ if (isonum_711(&rr->len) > susplen || rr->len == 0) break;
+ if (rr->signature[0]=='N' && rr->signature[1]=='M') {
+ if (!(rr->u.NM.flags & 0x26) && rr->len>5 && !rrentry->name) {
+
+ if (str_nappend(&rrentry->name,rr->u.NM.name,isonum_711(&rr->len)-5)) {
+ FreeRR(rrentry); return -ENOMEM;
+ }
+ ret++;
+ }
+ } else if (rr->signature[0]=='P' && rr->signature[1]=='X' &&
+ (isonum_711(&rr->len)==44 || isonum_711(&rr->len)==36)) {
+ rrentry->mode=isonum_733(rr->u.PX.mode);
+ rrentry->nlink=isonum_733(rr->u.PX.n_links);
+ rrentry->uid=isonum_733(rr->u.PX.uid);
+ rrentry->gid=isonum_733(rr->u.PX.gid);
+ if (isonum_711(&rr->len)==44) rrentry->serno=isonum_733(rr->u.PX.serno);
+ ret++;
+ } else if (rr->signature[0]=='P' && rr->signature[1]=='N' &&
+ isonum_711(&rr->len)==20) {
+ rrentry->dev_major=isonum_733(rr->u.PN.dev_high);
+ rrentry->dev_minor=isonum_733(rr->u.PN.dev_low);
+ ret++;
+ } else if (rr->signature[0]=='P' && rr->signature[1]=='L' &&
+ isonum_711(&rr->len)==12) {
+ rrentry->pl=isonum_733(rr->u.PL.location);
+ ret++;
+ } else if (rr->signature[0]=='C' && rr->signature[1]=='L' &&
+ isonum_711(&rr->len)==12) {
+ rrentry->cl=isonum_733(rr->u.CL.location);
+ ret++;
+ } else if (rr->signature[0]=='R' && rr->signature[1]=='E' &&
+ isonum_711(&rr->len)==4) {
+ rrentry->re=1;
+ ret++;
+ } else if (rr->signature[0]=='S' && rr->signature[1]=='L' &&
+ isonum_711(&rr->len)>7) {
+ i = isonum_711(&rr->len)-5;
+ c = (char*) rr;
+ c += 5;
+ while (i>0) {
+ switch(c[0] & ~1) {
+ case 0x2:
+ if (str_append(&rrentry->sl,".")) {
+ FreeRR(rrentry); return -ENOMEM;
+ }
+ break;
+ case 0x4:
+ if (str_append(&rrentry->sl,"..")) {
+ FreeRR(rrentry); return -ENOMEM;
+ }
+ break;
+ }
+ if ( (c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl &&
+ strlen(rrentry->sl)>1) ) {
+ if (str_append(&rrentry->sl,"/")) {
+ FreeRR(rrentry); return -ENOMEM;
+ }
+ }
+
+ if ((unsigned char)c[1]>0) {
+ if (str_nappend(&rrentry->sl,c+2,(unsigned char)c[1])) {
+ FreeRR(rrentry); return -ENOMEM;
+ }
+ }
+ i -= ((unsigned char)c[1] + 2);
+ c += ((unsigned char)c[1] + 2);
+ }
+ ret++;
+ } else if (rr->signature[0]=='T' && rr->signature[1]=='F' &&
+ isonum_711(&rr->len)>5) {
+
+ i = isonum_711(&rr->len)-5;
+ f = rr->u.TF.flags;
+ c = (char*) rr;
+ c += 5;
+
+ while (i >= rrtlen(f)) {
+ if (f & 1) {
+ rrentry->t_creat=rrctime(f,c);
+ f &= ~1;
+ } else if (f & 2) {
+ rrentry->rr_st_mtime=rrctime(f,c);
+ f &= ~2;
+ } else if (f & 4) {
+ rrentry->rr_st_atime=rrctime(f,c);
+ f &= ~4;
+ } else if (f & 8) {
+ rrentry->rr_st_ctime=rrctime(f,c);
+ f &= ~8;
+ } else if (f & 16) {
+ rrentry->t_backup=rrctime(f,c);
+ f &= ~16;
+ } else if (f & 32) {
+ rrentry->t_expire=rrctime(f,c);
+ f &= ~32;
+ } else if (f & 64) {
+ rrentry->t_effect=rrctime(f,c);
+ f &= ~64;
+ }
+
+ i -= rrtlen(f);
+ c += rrtlen(f);
+ }
+ ret++;
+
+ } else if (rr->signature[0]=='Z' && rr->signature[1]=='F' &&
+ isonum_711(&rr->len)==16) {
+ /* Linux-specific extension: transparent decompression */
+ rrentry->z_algo[0]=rr->u.ZF.algorithm[0];
+ rrentry->z_algo[1]=rr->u.ZF.algorithm[1];
+ rrentry->z_params[0]=rr->u.ZF.parms[0];
+ rrentry->z_params[1]=rr->u.ZF.parms[1];
+ rrentry->z_size=isonum_733(rr->u.ZF.real_size);
+ ret++;
+ } else {
+/* printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */
+ }
+
+ susplen -= isonum_711(&rr->len);
+ r += isonum_711(&rr->len);
+ rr = (struct rock_ridge*) r;
+ }
+
+ return ret;
+}
+
+/**
+ * Iterates over the directory entries. The directory is in 'buf',
+ * the size of the directory is 'size'. 'callback' is called for each
+ * directory entry with the parameter 'udata'.
+ */
+int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata) {
+
+ int pos=0,ret=0,siz;
+ char *buf;
+ struct iso_directory_record *idr;
+
+ if (size & 2047) {
+ siz=((size>>11)+1)<<11;
+ } else {
+ siz=size;
+ }
+
+ buf=(char*) malloc(siz);
+ if (!buf) return -ENOMEM;
+ if (read(buf,extent,siz>>11,udata)!=siz>>11) {
+ free(buf);
+ return -EIO;
+ }
+
+ while (size>0) {
+ idr=(struct iso_directory_record*) &buf[pos];
+ if (isonum_711(idr->length)==0) {
+ size-=(2048 - (pos & 0x7ff));
+ if (size<=2) break;
+ pos+=0x800;
+ pos&=0xfffff800;
+ idr=(struct iso_directory_record*) &buf[pos];
+ }
+ pos+=isonum_711(idr->length);
+ pos+=isonum_711(idr->ext_attr_length);
+ size-=isonum_711(idr->length);
+ size-=isonum_711(idr->ext_attr_length);
+ if (size<0) break;
+
+ if (isonum_711(idr->length)
+<33 ||
+ isonum_711(idr->length)<33+isonum_711(idr->name_len)) {
+ /* Invalid directory entry */
+ continue;
+ }
+ if ((ret=callback(idr,udata))) break;
+ }
+
+ free(buf);
+ return ret;
+}
+
+/**
+ * returns the joliet level from the volume descriptor
+ */
+int JolietLevel(struct iso_volume_descriptor *ivd) {
+ int ret=0;
+ register struct iso_supplementary_descriptor *isd;
+
+ isd = (struct iso_supplementary_descriptor *) ivd;
+
+ if (isonum_711(ivd->type)==ISO_VD_SUPPLEMENTARY) {
+ if (isd->escape[0]==0x25 &&
+ isd->escape[1]==0x2f) {
+
+ switch (isd->escape[2]) {
+ case 0x40:
+ ret=1;
+ break;
+ case 0x43:
+ ret=2;
+ break;
+ case 0x45:
+ ret=3;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+/********************************************************************/
+#if 0
+
+#include <time.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <iconv.h>
+
+int level=0,joliet=0,dirs,files;
+iconv_t iconv_d;
+int fd;
+
+int readf(char *buf, int start, int len,void *udata) {
+ int ret;
+
+ if ((ret=lseek(fd, start << 11, SEEK_SET))<0) return ret;
+ ret=read(fd, buf, len << 11);
+ if (ret<0) return ret;
+ return (ret >> 11);
+}
+
+void dumpchars(char *c,int len) {
+ while (len>0) {
+ printf("%c",*c);
+ len--;
+ c++;
+ }
+}
+
+void sp(int num) {
+ int i;
+ for (i=0;i<num*5;i++) { printf(" "); };
+}
+
+void dumpflags(char flags) {
+ if (flags & 1) printf("HIDDEN ");
+ if (flags & 2) printf("DIR ");
+ if (flags & 4) printf("ASF ");
+}
+
+void dumpjoliet(char *c,int len) {
+
+ char outbuf[255];
+ size_t out;
+ int ret;
+ char *outptr;
+
+ outptr=(char*) &outbuf;
+ out=255;
+ if ((iconv(iconv_d,&c,&len,&outptr,&out))<0) {
+ printf("conversion error=%d",errno);
+ return;
+ }
+ ret=255-out;
+ dumpchars((char*) &outbuf,ret);
+}
+
+void dumpchardesc(char *c,int len) {
+
+ if (joliet)
+ dumpjoliet(c,len);
+ else {
+ dumpchars(c,len);
+ }
+}
+
+void dumpiso915time(char *t, int hs) {
+
+ time_t time;
+ char *c;
+
+ time=isodate_915(t,hs);
+ c=(char*) ctime(&time);
+ if (c && c[strlen(c)-1]==0x0a) c[strlen(c)-1]=0;
+ if (c) printf("%s",c);
+}
+
+void dumpiso84261time(char *t, int hs) {
+
+ time_t time;
+ char *c;
+
+ time=isodate_84261(t,hs);
+ c=(char*) ctime(&time);
+ if (c && c[strlen(c)-1]==0x0a) c[strlen(c)-1]=0;
+ if (c) printf("%s",c);
+}
+
+void dumpdirrec(struct iso_directory_record *dir) {
+
+ if (isonum_711(dir->name_len)==1) {
+ switch (dir->name[0]) {
+ case 0:
+ printf(".");
+ break;
+ case 1:
+ printf("..");
+ break;
+ default:
+ printf("%c",dir->name[0]);
+ break;
+ }
+ }
+ dumpchardesc(dir->name,isonum_711(dir->name_len));
+ printf(" size=%d",isonum_733(dir->size));
+ printf(" extent=%d ",isonum_733(dir->extent));
+ dumpflags(isonum_711(dir->flags));
+ dumpiso915time((char*) &(dir->date),0);
+}
+
+void dumprrentry(rr_entry *rr) {
+ printf(" NM=[%s] uid=%d gid=%d nlink=%d mode=%o ",
+ rr->name,rr->uid,rr->gid,rr->nlink,rr->mode);
+ if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode))
+ printf("major=%d minor=%d ",rr->dev_major,rr->dev_minor);
+ if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ",rr->sl);
+/*
+ printf("\n");
+ if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat));
+ if (rr->rr_st_mtime) printf("rr_st_mtime: %s",ctime(&rr->rr_st_mtime));
+ if (rr->rr_st_atime) printf("rr_st_atime: %s",ctime(&rr->rr_st_atime));
+ if (rr->rr_st_ctime) printf("rr_st_ctime: %s",ctime(&rr->rr_st_ctime));
+ if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup));
+ if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire));
+ if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect));
+*/
+}
+
+void dumpsusp(char *c, int len) {
+ dumpchars(c,len);
+}
+
+void dumpboot(struct el_torito_boot_descriptor *ebd) {
+ printf("version: %d\n",isonum_711(ebd->version));
+ printf("system id: ");dumpchars(ebd->system_id,ISODCL(8,39));printf("\n");
+ printf("boot catalog start: %d\n",isonum_731(ebd->boot_catalog));
+}
+
+void dumpdefentry(struct default_entry *de) {
+ printf("Default entry: \n");
+ printf(" bootid=%x\n",isonum_711(de->bootid));
+ printf(" media emulation=%d (",isonum_711(de->media));
+ switch(isonum_711(de->media) & 0xf) {
+ case 0:
+ printf("No emulation");
+ break;
+ case 1:
+ printf("1.2 Mb floppy");
+ break;
+ case 2:
+ printf("1.44 Mb floppy");
+ break;
+ case 3:
+ printf("2.88 Mb floppy");
+ break;
+ case 4:
+ printf("Hard Disk");
+ break;
+ default:
+ printf("Unknown/Invalid");
+ break;
+ }
+ printf(")\n");
+ printf(" loadseg=%d\n",isonum_721(de->loadseg));
+ printf(" systype=%d\n",isonum_711(de->systype));
+ printf(" start lba=%d count=%d\n",isonum_731(de->start),
+ isonum_721(de->seccount));
+}
+
+void dumpbootcat(boot_head *bh) {
+ boot_entry *be;
+
+ printf("System id: ");dumpchars(bh->ventry.id,ISODCL(28,5));printf("\n");
+ be=bh->defentry;
+ while (be) {
+ dumpdefentry(be->data);
+ be=be->next;
+ }
+}
+
+void dumpdesc(struct iso_primary_descriptor *ipd) {
+
+ printf("system id: ");dumpchardesc(ipd->system_id,ISODCL(9,40));printf("\n");
+ printf("volume id: ");dumpchardesc(ipd->volume_id,ISODCL(41,72));printf("\n");
+ printf("volume space size: %d\n",isonum_733(ipd->volume_space_size));
+ printf("volume set size: %d\n",isonum_723(ipd->volume_set_size));
+ printf("volume seq num: %d\n",isonum_723(ipd->volume_set_size));
+ printf("logical block size: %d\n",isonum_723(ipd->logical_block_size));
+ printf("path table size: %d\n",isonum_733(ipd->path_table_size));
+ printf("location of type_l path table: %d\n",isonum_731(ipd->type_l_path_table));
+ printf("location of optional type_l path table: %d\n",isonum_731(ipd->opt_type_l_path_table));
+ printf("location of type_m path table: %d\n",isonum_732(ipd->type_m_path_table));
+ printf("location of optional type_m path table: %d\n",isonum_732(ipd->opt_type_m_path_table));
+/*
+ printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record);
+*/
+ printf("Volume set id: ");dumpchardesc(ipd->volume_set_id,ISODCL(191,318));printf("\n");
+ printf("Publisher id: ");dumpchardesc(ipd->publisher_id,ISODCL(319,446));printf("\n");
+ printf("Preparer id: ");dumpchardesc(ipd->preparer_id,ISODCL(447,574));printf("\n");
+ printf("Application id: ");dumpchardesc(ipd->application_id,ISODCL(575,702));printf("\n");
+ printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id,ISODCL(703,739));printf("\n");
+ printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id,ISODCL(740,776));printf("\n");
+ printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id,ISODCL(777,813));printf("\n");
+ printf("Volume creation date: ");dumpiso84261time(ipd->creation_date,0);printf("\n");
+ printf("Volume modification date: ");dumpiso84261time(ipd->modification_date,0);printf("\n");
+ printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date,0);printf("\n");
+ printf("Volume effective date: ");dumpiso84261time(ipd->effective_date,0);printf("\n");
+ printf("File structure version: %d\n",isonum_711(ipd->file_structure_version));
+}
+
+int mycallb(struct iso_directory_record *idr,void *udata) {
+ rr_entry rrentry;
+
+ sp(level);dumpdirrec(idr);
+ if (level==0) printf(" (Root directory) ");
+ printf("\n");
+
+ if (ParseRR(idr,&rrentry)>0) {
+ sp(level);printf(" ");dumprrentry(&rrentry);printf("\n");
+ }
+ FreeRR(&rrentry);
+ if ( !(idr->flags[0] & 2) ) files++;
+ if ( (idr->flags[0] & 2) && (level==0 || isonum_711(idr->name_len)>1) ) {
+ level++;
+ dirs++;
+ ProcessDir(&readf,isonum_733(idr->extent),isonum_733(idr->size),&mycallb,udata);
+ level--;
+ }
+ return 0;
+}
+
+/************************************************/
+
+int main(int argc, char *argv[]) {
+
+ int i=1,sector=0;
+ iso_vol_desc *desc;
+ boot_head boot;
+
+ if (argc<2) {
+ fprintf(stderr,"\nUsage: %s iso-file-name or device [starting sector]\n\n",argv[0]);
+ return 0;
+ }
+ if (argc>=3) {
+ sector=atoi(argv[2]);
+ printf("Using starting sector number %d\n",sector);
+ }
+ fd=open(argv[1],O_RDONLY);
+ if (fd<0) {
+ fprintf(stderr,"open error\n");
+ return -1;
+ }
+ iconv_d=iconv_open("ISO8859-2","UTF16BE");
+ if (iconv_d==0) {
+ fprintf(stderr,"iconv open error\n");
+ return -1;
+ }
+
+ desc=ReadISO9660(&readf,sector,NULL);
+ if (!desc) {
+ printf("No volume descriptors\n");
+ return -1;
+ }
+ while (desc) {
+
+ printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n",
+ i,isonum_711(desc->data.type));
+ switch (isonum_711(desc->data.type)) {
+ case ISO_VD_BOOT: {
+
+ struct el_torito_boot_descriptor* bootdesc;
+ bootdesc=&(desc->data);
+ dumpboot(bootdesc);
+ if ( !memcmp(EL_TORITO_ID,bootdesc->system_id,ISODCL(8,39)) ) {
+
+ if (ReadBootTable(&readf,isonum_731(bootdesc->boot_catalog),&boot,NULL)) {
+ printf("Boot Catalog Error\n");
+ } else {
+ dumpbootcat(&boot);
+ FreeBootTable(&boot);
+ }
+ }
+ }
+ break;
+
+ case ISO_VD_PRIMARY:
+ case ISO_VD_SUPPLEMENTARY:
+ joliet=0;
+ joliet = JolietLevel(&desc->data);
+ printf("Joliet level: %d\n",joliet);
+ dumpdesc((struct iso_primary_descriptor*) &desc->data);
+ printf("\n\n--------------- Directory structure: -------------------\n\n");
+ dirs=0;files=0;
+ mycallb( &( ((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL );
+ printf("\nnumber of directories: %d\n",dirs);
+ printf("\nnumber of files: %d\n",files);
+ break;
+
+ }
+ desc=desc->next;
+ i++;
+ }
+ iconv_close(iconv_d);
+ close(fd);
+ FreeISO9660(desc);
+ return 0;
+}
+
+#endif
diff --git a/libk3b/tools/libisofs/isofs.h b/libk3b/tools/libisofs/isofs.h
new file mode 100644
index 0000000..f284903
--- /dev/null
+++ b/libk3b/tools/libisofs/isofs.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+ isofs.h - include this file to use libisofs
+ -------------------
+ begin : Oct 25 2002
+ copyright : (C) 2002 by Szombathelyi Gyrgy
+ email : gyurco@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef ISOFS_H
+#define ISOFS_H
+
+#include <sys/time.h>
+
+#include "iso_fs.h"
+#include "el_torito.h"
+
+typedef long sector_t;
+
+typedef struct _rr_entry {
+ int len; /* length of structure */
+ char *name; /* Name from 'NM' */
+ char *sl; /* symbolic link data */
+ time_t t_creat;
+ time_t rr_st_mtime;
+ time_t rr_st_atime;
+ time_t rr_st_ctime;
+ time_t t_backup;
+ time_t t_expire;
+ time_t t_effect;
+ int mode; /* POSIX file modes */
+ int nlink;
+ int uid;
+ int gid;
+ int serno;
+ int dev_major;
+ int dev_minor;
+ int pl; /* parent location */
+ int cl; /* child location */
+ int re; /* relocated */
+ char z_algo[2]; /* zizofs algorithm */
+ char z_params[2]; /* zizofs parameters */
+ int z_size; /* zizofs real_size */
+} rr_entry;
+
+typedef struct _iso_vol_desc {
+ struct _iso_vol_desc *next;
+ struct _iso_vol_desc *prev;
+ struct iso_volume_descriptor data;
+} iso_vol_desc;
+
+typedef struct _boot_entry {
+ struct _boot_entry *next;
+ struct _boot_entry *prev;
+ struct _boot_entry *parent;
+ struct _boot_entry *child;
+ char data[32];
+} boot_entry;
+
+typedef struct _boot_head {
+ struct validation_entry ventry;
+ struct _boot_entry *defentry;
+ struct _boot_entry *sections;
+} boot_head;
+
+/**
+ * this callback function needs to read 'len' sectors from 'start' into 'buf'
+ */
+typedef int readfunc(char *buf,sector_t start, int len,void *);
+
+/**
+ * ProcessDir uses this callback
+ */
+typedef int dircallback(struct iso_directory_record *,void *);
+
+/**
+ * Returns the Unix from the ISO9660 9.1.5 (7 bytes) time format
+ * This function is from the linux kernel.
+ * Set 'hs' to non-zero if it's a HighSierra volume
+ */
+time_t isodate_915(char * p, int hs);
+
+/**
+ * Returns the Unix time from the ISO9660 8.4.26.1 (17 bytes) time format
+ * BUG: hundredth of seconds are ignored, because time_t has one second
+ * resolution (I think it's no problem at all)
+ * Set 'hs' to non-zero if it's a HighSierra volume
+ */
+time_t isodate_84261(char * p, int hs);
+
+/**
+ * Creates the linked list of the volume descriptors
+ * 'sector' is the starting sector number of where the filesystem start
+ * (starting sector of a session on a CD-ROM)
+ * If the function fails, returns NULL
+ * Don't forget to call FreeISO9660 after using the volume descriptor list!
+ */
+iso_vol_desc *ReadISO9660(readfunc *read,sector_t sector,void *udata);
+
+/**
+ * Frees the linked list of volume descriptors.
+ */
+void FreeISO9660(iso_vol_desc *data);
+
+/**
+ * Iterates over the directory entries. The directory is in 'buf',
+ * the size of the directory is 'size'. 'callback' is called for each
+ * directory entry with the parameter 'udata'.
+ */
+int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata);
+
+/**
+ * Parses the System Use area and fills rr_entry with values
+ */
+int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry);
+
+/**
+ * Frees the strings in 'rrentry'
+ */
+void FreeRR(rr_entry *rrentry);
+
+/**
+ * returns the joliet level from the volume descriptor
+ */
+int JolietLevel(struct iso_volume_descriptor *ivd);
+
+/**
+ * Returns the size of the boot image (in 512 byte sectors)
+ */
+int BootImageSize(readfunc *read,int media,sector_t start,int len,void *udata);
+
+/**
+ * Frees the boot catalog entries in 'boot'. If you ever called ReadBootTable,
+ * then don't forget to call FreeBootTable!
+ */
+void FreeBootTable(boot_head *boot);
+
+/**
+ * Reads the boot catalog into 'head'. Don't forget to call FreeBootTable!
+ */
+int ReadBootTable(readfunc *read,sector_t sector, boot_head *head, void *udata);
+
+#endif
diff --git a/libk3b/tools/libisofs/rock.h b/libk3b/tools/libisofs/rock.h
new file mode 100644
index 0000000..e859192
--- /dev/null
+++ b/libk3b/tools/libisofs/rock.h
@@ -0,0 +1,127 @@
+/* this header is from the linux kernel */
+
+#ifndef ROCK_H
+#define ROCK_H 1
+
+/* These structs are used by the system-use-sharing protocol, in which the
+ Rock Ridge extensions are embedded. It is quite possible that other
+ extensions are present on the disk, and this is fine as long as they
+ all use SUSP */
+
+struct SU_SP{
+ unsigned char magic[2];
+ unsigned char skip;
+};
+
+struct SU_CE{
+ char extent[8];
+ char offset[8];
+ char size[8];
+};
+
+struct SU_ER{
+ unsigned char len_id;
+ unsigned char len_des;
+ unsigned char len_src;
+ unsigned char ext_ver;
+ char data[1];
+};
+
+struct RR_RR{
+ char flags[1];
+};
+
+struct RR_PX{
+ char mode[8];
+ char n_links[8];
+ char uid[8];
+ char gid[8];
+ char serno[8];
+};
+
+struct RR_PN{
+ char dev_high[8];
+ char dev_low[8];
+};
+
+
+struct SL_component{
+ unsigned char flags;
+ unsigned char len;
+ char text[1];
+};
+
+struct RR_SL{
+ unsigned char flags;
+ struct SL_component link;
+};
+
+struct RR_NM{
+ unsigned char flags;
+ char name[1];
+};
+
+struct RR_CL{
+ char location[8];
+};
+
+struct RR_PL{
+ char location[8];
+};
+
+struct stamp{
+ char time[7];
+};
+
+struct RR_TF{
+ char flags;
+ struct stamp times[1]; /* Variable number of these beasts */
+};
+
+/* Linux-specific extension for transparent decompression */
+struct RR_ZF{
+ char algorithm[2];
+ char parms[2];
+ char real_size[8];
+};
+
+/* These are the bits and their meanings for flags in the TF structure. */
+#define TF_CREATE 1
+#define TF_MODIFY 2
+#define TF_ACCESS 4
+#define TF_ATTRIBUTES 8
+#define TF_BACKUP 16
+#define TF_EXPIRATION 32
+#define TF_EFFECTIVE 64
+#define TF_LONG_FORM 128
+
+struct rock_ridge{
+ char signature[2];
+ char len; /* 711 */
+ char version; /* 711 */
+ union{
+ struct SU_SP SP;
+ struct SU_CE CE;
+ struct SU_ER ER;
+ struct RR_RR RR;
+ struct RR_PX PX;
+ struct RR_PN PN;
+ struct RR_SL SL;
+ struct RR_NM NM;
+ struct RR_CL CL;
+ struct RR_PL PL;
+ struct RR_TF TF;
+ struct RR_ZF ZF;
+ } u;
+};
+
+#define RR_PX 1 /* POSIX attributes */
+#define RR_PN 2 /* POSIX devices */
+#define RR_SL 4 /* Symbolic link */
+#define RR_NM 8 /* Alternate Name */
+#define RR_CL 16 /* Child link */
+#define RR_PL 32 /* Parent link */
+#define RR_RE 64 /* Relocation directory */
+#define RR_TF 128 /* Timestamps */
+
+#endif /* ROCK_H */