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

464 lines
11 KiB

/*
*
* $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 <config.h>
#include "k3bmedium.h"
#include <k3bdeviceglobals.h>
#include <k3bglobals.h>
#include <k3biso9660.h>
#include <k3biso9660backend.h>
#include <tdelocale.h>
#include <tdeio/global.h>
/**
* Internal class used by K3bMedium
*/
class K3bMedium::Data : public TDEShared
{
public:
Data();
K3bDevice::Device* device;
K3bDevice::DiskInfo diskInfo;
K3bDevice::Toc toc;
K3bDevice::CdText cdText;
TQValueList<int> writingSpeeds;
K3bIso9660SimplePrimaryDescriptor isoDesc;
int content;
};
K3bMedium::Data::Data()
: device( 0 ),
content( K3bMedium::CONTENT_NONE )
{
}
K3bMedium::K3bMedium()
{
d = new Data;
}
K3bMedium::K3bMedium( const K3bMedium& other )
{
d = other.d;
}
K3bMedium::K3bMedium( K3bDevice::Device* dev )
{
d = new Data;
d->device = dev;
}
K3bMedium::~K3bMedium()
{
}
K3bMedium& K3bMedium::operator=( const K3bMedium& other )
{
if( this != &other )
d = other.d;
return *this;
}
void K3bMedium::detach()
{
if( d.count() > 1 )
d = new Data( *d );
}
void K3bMedium::setDevice( K3bDevice::Device* dev )
{
if( d->device != dev ) {
reset();
d->device = dev;
}
}
K3bDevice::Device* K3bMedium::device() const
{
return d->device;
}
const K3bDevice::DiskInfo& K3bMedium::diskInfo() const
{
return d->diskInfo;
}
const K3bDevice::Toc& K3bMedium::toc() const
{
return d->toc;
}
const K3bDevice::CdText& K3bMedium::cdText() const
{
return d->cdText;
}
const TQValueList<int>& K3bMedium::writingSpeeds() const
{
return d->writingSpeeds;
}
int K3bMedium::content() const
{
return d->content;
}
const K3bIso9660SimplePrimaryDescriptor& K3bMedium::iso9660Descriptor() const
{
return d->isoDesc;
}
void K3bMedium::reset()
{
detach();
d->diskInfo = K3bDevice::DiskInfo();
d->toc.clear();
d->cdText.clear();
d->writingSpeeds.clear();
d->content = CONTENT_NONE;
// clear the desc
d->isoDesc = K3bIso9660SimplePrimaryDescriptor();
}
void K3bMedium::update()
{
if( d->device ) {
reset();
d->diskInfo = d->device->diskInfo();
if( d->diskInfo.diskState() != K3bDevice::STATE_NO_MEDIA ) {
kdDebug() << "(K3bMedium) found medium:" << endl
<< "=====================================================" << endl;
d->diskInfo.debug();
kdDebug() << "=====================================================" << endl;
}
if( diskInfo().diskState() == K3bDevice::STATE_COMPLETE ||
diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) {
d->toc = d->device->readToc();
if( d->toc.contentType() == K3bDevice::AUDIO ||
d->toc.contentType() == K3bDevice::MIXED )
d->cdText = d->device->readCdText();
}
if( diskInfo().mediaType() & K3bDevice::MEDIA_WRITABLE ) {
d->writingSpeeds = d->device->determineSupportedWriteSpeeds();
}
analyseContent();
}
}
void K3bMedium::analyseContent()
{
// set basic content types
switch( toc().contentType() ) {
case K3bDevice::AUDIO:
d->content = CONTENT_AUDIO;
break;
case K3bDevice::DATA:
case K3bDevice::DVD:
d->content = CONTENT_DATA;
break;
case K3bDevice::MIXED:
d->content = CONTENT_AUDIO|CONTENT_DATA;
break;
default:
d->content = CONTENT_NONE;
}
// analyze filesystem
if( d->content & CONTENT_DATA ) {
//kdDebug() << "(K3bMedium) Checking file system." << endl;
unsigned long startSec = 0;
if( diskInfo().numSessions() > 1 ) {
// We use the last data track
// this way we get the latest session on a ms cd
K3bDevice::Toc::const_iterator it = toc().end();
--it; // this is valid since there is at least one data track
while( it != toc().begin() && (*it).type() != K3bDevice::Track::DATA )
--it;
startSec = (*it).firstSector().lba();
}
else {
// use first data track
K3bDevice::Toc::const_iterator it = toc().begin();
while( it != toc().end() && (*it).type() != K3bDevice::Track::DATA )
++it;
startSec = (*it).firstSector().lba();
}
//kdDebug() << "(K3bMedium) Checking file system at " << startSec << endl;
// force the backend since we don't need decryption
// which just slows down the whole process
K3bIso9660 iso( new K3bIso9660DeviceBackend( d->device ) );
iso.setStartSector( startSec );
iso.setPlainIso9660( true );
if( iso.open() ) {
d->isoDesc = iso.primaryDescriptor();
kdDebug() << "(K3bMedium) found volume id from start sector " << startSec
<< ": '" << d->isoDesc.volumeId << "'" << endl;
if( diskInfo().isDvdMedia() ) {
// Every VideoDVD needs to have a VIDEO_TS.IFO file
if( iso.firstIsoDirEntry()->entry( "VIDEO_TS/VIDEO_TS.IFO" ) != 0 )
d->content |= CONTENT_VIDEO_DVD;
}
else {
kdDebug() << "(K3bMedium) checking for VCD." << endl;
// check for VCD
const K3bIso9660Entry* vcdEntry = iso.firstIsoDirEntry()->entry( "VCD/INFO.VCD" );
const K3bIso9660Entry* svcdEntry = iso.firstIsoDirEntry()->entry( "SVCD/INFO.SVD" );
const K3bIso9660File* vcdInfoFile = 0;
if( vcdEntry ) {
kdDebug() << "(K3bMedium) found vcd entry." << endl;
if( vcdEntry->isFile() )
vcdInfoFile = static_cast<const K3bIso9660File*>(vcdEntry);
}
if( svcdEntry && !vcdInfoFile ) {
kdDebug() << "(K3bMedium) found svcd entry." << endl;
if( svcdEntry->isFile() )
vcdInfoFile = static_cast<const K3bIso9660File*>(svcdEntry);
}
if( vcdInfoFile ) {
char buffer[8];
if ( vcdInfoFile->read( 0, buffer, 8 ) == 8 &&
( !tqstrncmp( buffer, "VIDEO_CD", 8 ) ||
!tqstrncmp( buffer, "SUPERVCD", 8 ) ||
!tqstrncmp( buffer, "HQ-VCD ", 8 ) ) )
d->content |= CONTENT_VIDEO_CD;
}
}
} // opened iso9660
}
}
TQString K3bMedium::shortString( bool useContent ) const
{
TQString mediaTypeString = K3bDevice::mediaTypeString( diskInfo().mediaType(), true );
if( diskInfo().diskState() == K3bDevice::STATE_UNKNOWN ) {
return i18n("No medium information");
}
else if( diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) {
return i18n("No medium present");
}
else if( diskInfo().diskState() == K3bDevice::STATE_EMPTY ) {
return i18n("Empty %1 medium").arg( mediaTypeString );
}
else {
if( useContent ) {
// AUDIO + MIXED
if( toc().contentType() == K3bDevice::AUDIO ||
toc().contentType() == K3bDevice::MIXED ) {
if( !cdText().performer().isEmpty() || !cdText().title().isEmpty() ) {
return TQString("%1 - %2 (%3)")
.arg( cdText().performer() )
.arg( cdText().title() )
.arg( toc().contentType() == K3bDevice::AUDIO ? i18n("Audio CD") : i18n("Mixed CD") );
}
else if( toc().contentType() == K3bDevice::AUDIO ) {
return i18n("Audio CD");
}
else {
return i18n("%1 (Mixed CD)").arg( beautifiedVolumeId() );
}
}
// DATA CD and DVD
else if( !volumeId().isEmpty() ) {
if( content() & CONTENT_VIDEO_DVD ) {
return TQString("%1 (%2)").arg( beautifiedVolumeId() ).arg( i18n("Video DVD") );
}
else if( content() & CONTENT_VIDEO_CD ) {
return TQString("%1 (%2)").arg( beautifiedVolumeId() ).arg( i18n("Video CD") );
}
else if( diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) {
return i18n("%1 (Appendable Data %2)").arg( beautifiedVolumeId(), mediaTypeString );
}
else {
return i18n("%1 (Complete Data %2)").arg( beautifiedVolumeId(), mediaTypeString );
}
}
else {
if( diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) {
return i18n("Appendable Data %1").arg( mediaTypeString );
}
else {
return i18n("Complete Data %1").arg( mediaTypeString );
}
}
}
// without content
else {
if( diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) {
return i18n("Appendable %1 medium").arg( mediaTypeString );
}
else {
return i18n("Complete %1 medium").arg( mediaTypeString );
}
}
}
}
TQString K3bMedium::longString() const
{
TQString s = TQString("<p><nobr><b>%1 %2</b> (%3)</nobr>"
"<p>")
.arg( d->device->vendor() )
.arg( d->device->description() )
.arg( d->device->blockDeviceName() )
+ shortString( true );
if( diskInfo().diskState() == K3bDevice::STATE_COMPLETE ||
diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) {
s += "<br>" + i18n("%1 in %n track", "%1 in %n tracks", toc().count() )
.arg( TDEIO::convertSize(diskInfo().size().mode1Bytes() ) );
if( diskInfo().numSessions() > 1 )
s += i18n(" and %n session", " and %n sessions", diskInfo().numSessions() );
}
if( diskInfo().diskState() == K3bDevice::STATE_EMPTY ||
diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE )
s += "<br>" + i18n("Free space: %1")
.arg( TDEIO::convertSize( diskInfo().remainingSize().mode1Bytes() ) );
if( !diskInfo().empty() && diskInfo().rewritable() )
s += "<br>" + i18n("Capacity: %1")
.arg( TDEIO::convertSize( diskInfo().capacity().mode1Bytes() ) );
return s;
}
const TQString& K3bMedium::volumeId() const
{
return iso9660Descriptor().volumeId;
}
TQString K3bMedium::beautifiedVolumeId() const
{
const TQString& oldId = volumeId();
TQString newId;
bool newWord = true;
for( unsigned int i = 0; i < oldId.length(); ++i ) {
TQChar c = oldId[i];
//
// first let's handle the cases where we do not change
// the id anyway
//
// In case the id already contains spaces or lower case chars
// it is likely that it already looks good and does ignore
// the restricted iso9660 charset (like almost every project
// created with K3b)
//
if( c.isLetter() && c.lower() == c )
return oldId;
else if( c.isSpace() )
return oldId;
// replace underscore with space
else if( c.unicode() == 95 ) {
newId.append( ' ' );
newWord = true;
}
// from here on only upper case chars and numbers and stuff
else if( c.isLetter() ) {
if( newWord ) {
newId.append( c );
newWord = false;
}
else {
newId.append( c.lower() );
}
}
else {
newId.append( c );
}
}
return newId;
}
bool K3bMedium::operator==( const K3bMedium& other )
{
if( this->d == other.d )
return true;
return( this->device() == other.device() &&
this->diskInfo() == other.diskInfo() &&
this->toc() == other.toc() &&
this->cdText() == other.cdText() &&
this->content() == other.content() &&
this->iso9660Descriptor() == other.iso9660Descriptor() );
}
bool K3bMedium::operator!=( const K3bMedium& other )
{
if( this->d == other.d )
return false;
return( this->device() != other.device() ||
this->diskInfo() != other.diskInfo() ||
this->toc() != other.toc() ||
this->cdText() != other.cdText() ||
this->content() != other.content() ||
this->iso9660Descriptor() != other.iso9660Descriptor() );
}