extras-legacy/java/trunk/src/java/org/pykix/libburnia/libburn/Drive.java

738 lines
21 KiB
Java

/*
* Drive.java
*
* Copyright (c) 2007 Vreixo Formoso
*
* This library 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 COPYING file for details.
*/
package org.pykix.libburnia.libburn;
import org.pykix.libburnia.bindings.Proxy;
/**
* References a physical drive in the system.
*
* @author Vreixo Formoso
* @since 0.1
*/
public class Drive extends Proxy {
Drive(long ptr) {
super(ptr);
}
/**
* Grab the drive. This must be done before the drive can be used
* (for reading, writing, etc).
*
* @param load
* <code>true</code> to make the drive attempt to load a disc
* (close its tray door, etc).
* @throws BurnException
* if it wasn't possible to grab the drive
*/
public void grab(boolean load) throws BurnException {
if ( !burn_drive_grab(pointerOf(this), load ? 1 : 0) ) {
throw new BurnException("Can't grab the drive");
}
}
/**
* Release the drive. This should not be done until the drive is no longer
* busy (see burn_drive_get_status). The drive is (O_EXCL) unlocked.
*
* @param eject
* <code>true</code> to make the drive eject the disc in it.
*/
public void release(boolean eject) {
burn_drive_release( pointerOf(this), eject ? 1 : 0 );
}
/**
* Returns what kind of disc the drive is holding.
*
* <p>
* This function may need to be called more than once to get a proper
* status from it.
*
* @return
* The status of the drive, or what kind of disc is in it.
*/
public DiscStatus getDiscStatus() {
switch ( burn_disc_get_status( pointerOf(this) ) ) {
case 0:
return DiscStatus.UNREADY;
case 1:
return DiscStatus.BLANK;
case 2:
return DiscStatus.EMPTY;
case 3:
return DiscStatus.APPENDABLE;
case 4:
return DiscStatus.FULL;
case 5:
return DiscStatus.UNGRABBED;
case 6:
return DiscStatus.UNSUITABLE;
default:
throw new RuntimeException("Unexpected value");
}
}
/**
* Tells the MMC Profile identifier of the loaded media. The drive must be
* grabbed in order to get a profile other than {@link Profile#NONE}.
*
* <p>
* libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW",
* 0x11 "DVD-R", 0x12 "DVD-RAM", 0x13 "DVD-RW restricted overwrite",
* 0x14 "DVD-RW Sequential Recording" or 0x1a "DVD+RW".
*
* <p>
* If enabled by burn_allow_untested_profiles() it also writes to profile
* 0x15 "DVD-R/DL Sequential Recording".
*
* @return
* The profile of the loaded media.
*/
/*
* I've implemented this in a different way that libburn, I prefer returning
* profile as an enum. It has a lot of advantages for the programmer,
* and only one problem: this cannot distinguish between different unknown
* profiles.
*/
public Profile getProfile() {
return Profile.get( burn_disc_get_profile( pointerOf(this) ) );
}
/**
* Tells whether a disc can be erased or not.
*
* @return
* <code>true</code> is inserted disc is erasable,
* <code>false</code> if not.
*/
public boolean isErasable() {
return burn_disc_erasable( pointerOf(this) );
}
/**
* Returns the progress and status of a drive.
*
* @param progress
* Will be filled with the progress of the operation,
* you can pass <code>null</code> if you don't care
* @return
* the current status of the drive.
*/
public DriveStatus getDriveStatus(Progress progress) {
switch ( burn_drive_get_status( pointerOf(this),
progress == null ? 0 : pointerOf(progress) ) ) {
case 0:
return DriveStatus.IDLE;
case 1:
return DriveStatus.SPAWNING;
case 2:
return DriveStatus.READING;
case 3:
return DriveStatus.WRITING;
case 4:
return DriveStatus.WRITING_LEADIN;
case 5:
return DriveStatus.WRITING_LEADOUT;
case 6:
return DriveStatus.ERASING;
case 7:
return DriveStatus.GRABBING;
case 8:
return DriveStatus.WRITING_PREGAP;
case 9:
return DriveStatus.CLOSING_TRACK;
case 10:
return DriveStatus.CLOSING_SESSION;
case 11:
return DriveStatus.FORMATTING;
default:
throw new RuntimeException("Unexpected drive status");
}
}
/**
* Erase a disc in the drive.
*
* <p>
* The drive must be grabbed successfully <b>BEFORE</b> calling this
* function. Always ensure that the drive reports a status of
* {@link DiscStatus#FULL} or {@link DiscStatus#APPENDABLE} before
* calling this function. An erase operation is not cancellable, as
* control of the operation is passed wholly to the drive and
* there is no way to interrupt it safely.
*
* @see #getDiscStatus()
*
* @param fast
* <code>true</code> to do a fast erase, where only the disc's
* headers are erased; <code>false</code> to erase the entire disc.
* With DVD-RW, fast blanking yields media capable only of DAO.
*/
public void erase(boolean fast) {
burn_disc_erase(pointerOf(this), fast);
}
/**
* Creates a WriteOpts object for burning to this drive.
*
* @return
* a WriteOpts object
*/
public WriteOpts newWriteOpts() {
return new WriteOpts( burn_write_opts_new(pointerOf(this)) );
}
/**
* Return the best possible estimation of the currently available capacity
* of the media. This might depend on particular write option settings.
* For inquiring the space with such a set of options, the drive has to be
* grabbed and {@link DriveStatus#IDLE}. If not, then one will only get a
* canned value from the most recent automatic inquiry (e.g. during last
* drive grabbing).
*
* <p>
* An eventual start address from burn_write_opts_set_start_byte() will be
* subtracted from the obtained capacity estimation. Negative results get
* defaulted to 0.
*
* @param opts
* If not <code>null</code>, write parameters to be set on drive
* before query.
* @return
* number of most probably available free bytes.
*/
public long getAvailableSpace(WriteOpts opts) {
return burn_disc_available_space( pointerOf(this),
opts == null ? 0 : pointerOf(opts) );
}
/**
* Write a disc in the drive.
*
* <p>
* The drive must be grabbed successfully before calling this function.
* Always ensure that the drive reports a status of
* {@link DiscStatus#BLANK} or {@link DiscStatus#APPENDABLE} before
* calling this function.
*
* <p>
* Note: write type {@link WriteType#SAO} is currently not capable of
* writing a mix of data and audio tracks. You must use
* {@link WriteType#TAO} for such sessions.
* To be set by {@link WriteOpts#setWriteType(WriteType, BlockTypes)}.
*
* @param o
* The options for the writing operation.
* @param d
* The {@link Disc} object that described the disc to be created.
*/
/*
* ok, this not need to be a member of Drive, but as
* read, erase, etc are also here...
*/
public void write( WriteOpts o, Disc disc) {
burn_disc_write( pointerOf(o), pointerOf(disc) );
}
/**
* Format media for use with libburn. This currently applies to DVD-RW
* in state "Sequential Recording" (profile 0014h) which get formatted to
* state "Restricted Overwrite" (profile 0013h). DVD+RW can be "de-iced"
* by setting bit2 of flag. Other media cannot be formatted yet.
*
* @param size
* The size in bytes to be used with the format command. It should
* be divisible by 32*1024. The effect of this parameter may
* depend on the media profile.
* @param flag
* Bitfield for control purposes:
* <ul>
* <li>bit0= after formatting, write the given number of zero-bytes
* to the media and eventually perform preliminary closing.
* <li>bit1= insist in size 0 even if there is a better default known
* <li>bit2= format to maximum available size
* <li>bit3= -reserved-
* <li>bit4= enforce re-format of (partly) formatted media
* <li>bit7= MMC expert application mode (else libburn tries to
* choose a suitable format type):
* <li>bit8 to bit15 contain the index of the format to use. See
* burn_disc_get_formats(), burn_disc_get_format_descr().
* Acceptable types are: 0x00, 0x10, 0x11, 0x13, 0x15, 0x26.
* If bit7 is set, bit4 is set automatically.
* </ul>
*/
public void format(long size, int flag) {
burn_disc_format(pointerOf(this), size, flag);
}
/**
* Cancel an operation on a drive.
*
* <p>
* This will only work when the drive's busy state is
* {@link DriveStatus#READING} or {@link DriveStatus#WRITING}.
*
* @see #getDriveStatus(Progress)
*/
public void cancel() {
burn_drive_cancel( pointerOf(this) );
}
/**
* Inquire wether the most recent write run was successful. Reasons for
* non-success may be: rejection of burn parameters, abort during fatal
* errors during write, a call to {@link #cancel()} by the application
* thread.
*
* @return
* <code>true</code> if burn seems to have went well,
* <code>false</code> if burn failed.
*/
public boolean wroteWell() {
return burn_drive_wrote_well( pointerOf(this) );
}
/**
* Get the drive's disc object.
*
* @return
* the Disc object or <code>null</code> on failure.
*/
public Disc getDisc() {
long ptr = burn_drive_get_disc( pointerOf(this) );
if ( ptr == 0 ) {
return null;
}
Disc disc = (Disc) proxyFor(ptr);
if ( disc == null) {
disc = new Disc(ptr);
}
return disc;
}
/**
* Sets drive read and write speed.
*
* @param read
* Read speed in k/s (0 is max).
* @param write
* Write speed in k/s (0 is max).
*/
public void setSpeed(int read, int write) {
burn_drive_set_speed( pointerOf(this), read, write);
}
/**
* Creates a ReadOpts object for reading from this drive.
*
* @return
* the ReadOpts object.
*/
public ReadOpts newReadOpts() {
return new ReadOpts( burn_read_opts_new(pointerOf(this)) );
}
/**
* Gets the maximum write speed for a drive and eventually loaded media.
*
* <p>
* The return value might change by the media type of already loaded media,
* again by call burn_drive_grab() and again by call burn_disc_read_atip().
*
* @return
* Maximum write speed in K/s.
*/
public int getWriteSpeed() {
return burn_drive_get_write_speed( pointerOf(this) );
}
/**
* Gets the minimum write speed for the drive and eventually loaded media.
*
* <p>
* The return value might change by the media type of already loaded media,
* again by call burn_drive_grab() and again by call burn_disc_read_atip().
*
* @return
* Minimum write speed in K/s.
*/
public int getMinWriteSpeed() {
return burn_drive_get_min_write_speed( pointerOf(this) );
}
/**
* Gets the maximum read speed for the drive.
*
* @return
* Maximum read speed in K/s.
*/
public int getReadSpeed() {
return burn_drive_get_read_speed( pointerOf(this) );
}
/**
* Obtain a copy of the current speed descriptor list. The drive's list
* gets updated on various occasions such as {@link #grab(boolean)} but
* the copy obtained here stays untouched.
*
* <p>
* Speeds may appear several times in the list. The list content depends
* much on drive and media type. It seems that .source == 1 applies mostly
* to CD media whereas .source == 2 applies to any media.
*
* @return
* The speed list, may be empty.
* @throws BurnException
* If severe error occurs.
*/
public SpeedDescriptor[] getSpeedList() throws BurnException {
SpeedDescriptor[] lst = burn_drive_get_speedlist(pointerOf(this));
if (lst == null) {
throw new BurnException("Can't get speed list");
}
return lst;
}
/**
* <b>WARNING:</b>
* This revives an old bug-like behavior that might be dangerous.
*
* Sets the drive status to {@link DiscStatus#BLANK} if it is
* {@link DiscStatus#UNREADY} or {@link DiscStatus#UNSUITABLE}.
* Thus marking media as writable which actually failed to declare
* themselves either blank or (partially) filled.
*
* @return
* <code>true</code> on success, <code>false</code> if drive is
* in an unsuitable status.
*/
public boolean pretendBlank() {
return burn_disc_pretend_blank( pointerOf(this) );
}
/**
* <b>WARNING:</b>
* This overrides the safety measures against unsuitable media.
*
* Sets the drive status to {@link DiscStatus#FULL} if it is
* {@link DiscStatus#UNREADY} or {@link DiscStatus#UNSUITABLE}.
* Thus marking media as blankable which actually failed to declare
* themselves either blank or (partially) filled.
*
* @return
* <code>true</code> on success, <code>false</code> if drive is
* in an unsuitable status.
*/
public boolean pretendFull() {
return burn_disc_pretend_full( pointerOf(this) );
}
/**
* Reads ATIP information from inserted media. To be obtained via
* {@link #getWriteSpeed()}, {@link #getMinWriteSpeed()},
* burn_drive_get_start_end_lba(). The drive must be grabbed for this call.
*
* @return
* <code>true</code> on success, <code>false</code> if no valid ATIP
* info read.
* @throws BurnException
* On a severe error.
*/
public boolean readAtip() throws BurnException {
switch ( burn_disc_read_atip( pointerOf(this) ) ) {
case 1:
return true;
case 0:
return false;
default:
throw new BurnException("Severe error reading ATIP");
}
}
/**
* Returns start lba of the media which is currently inserted in the drive.
* The drive has to be grabbed to have hope for reply.
*
* <p>
* Shortcomming (not a feature): unless {@link #readAtip()} was called
* only blank media will return valid info.
*
* @return
* the start lba value
* @throws BurnException
* On invalid lba value.
*/
/*
* TODO mmm, I really don't like to throw an Exception here...
*/
public int getStartLba() throws BurnException {
/* flag is unused yet */
return burn_drive_get_start_lba(pointerOf(this), 0);
}
/**
* Returns end lba of the media which is currently inserted in the drive.
* The drive has to be grabbed to have hope for reply.
*
* <p>
* Shortcomming (not a feature): unless {@link #readAtip()} was called
* only blank media will return valid info.
*
* @return
* the end lba value
* @throws BurnException
* On invalid lba value.
*/
/*
* TODO mmm, I really don't like to throw an Exception here...
*/
public int getEndLba() throws BurnException {
/* flag is unused yet */
return burn_drive_get_end_lba(pointerOf(this), 0);
}
/**
* Read start lba of a track from media.
*
* <p>
* Usually a track lba is obtained from the result of
* {@link Track#getEntry()}. This call retrieves an updated lba,
* and can address the invisible track to come.
*
* <p>
* The drive must be grabbed for this call. One may not issue this call
* during ongoing {@link #write(WriteOpts, Disc)} or {@link #erase(boolean)}.
*
* @param o
* If not <code>null</code>, write parameters to be set on drive
* before query
* @param trackno
* 0=next track to come, >0 number of existing track
* @return
* start lba
* @throws BurnException
* On error
*/
public int getTrackLba(WriteOpts o, int trackno) throws BurnException {
return burn_disc_track_lba( pointerOf(this),
o == null ? 0 : pointerOf(o), trackno);
}
/**
* Read Next Writeable Address of a track from media.
*
* <p>
* The drive must be grabbed for this call. One may not issue this call
* during ongoing {@link #write(WriteOpts, Disc)} or {@link #erase(boolean)}.
*
* @param o
* If not <code>null</code>, write parameters to be set on drive
* before query
* @param trackno
* 0=next track to come, >0 number of existing track
* @return
* Next Writeable Address
* @throws BurnException
* If error or non valid nwa
*/
public int getTrackNwa(WriteOpts o, int trackno) throws BurnException {
return burn_disc_track_nwa( pointerOf(this),
o == null ? 0 : pointerOf(o), trackno);
}
/**
* Read start lba of the first track in the last complete session.
*
* <p>
* This is the first parameter of mkisofs option -C. The second parameter
* is nwa as obtained by {@link #getTrackNwa(WriteOpts, int)} with
* trackno 0.
*
* @return
* returns the start address of that track
* @throws BurnException
* on error
*/
public int getMsc1() throws BurnException {
return burn_disc_get_msc1(pointerOf(this));
}
/**
* Creates a {@link MultiCaps} with values which are appropriate for the
* drive and the loaded media. The drive must be grabbed for this call.
*
* @param wt
* With {@link WriteType#NONE} the best capabilities of all write modes
* get returned. If set to a write mode like {@link WriteType#SAO} the
* capabilities with that particular mode are returned and the
* {@link MultiCaps#isWritingPossible()} return value is
* <code>false</code> if the desired mode is not possible.
* @return
* The MultiCaps object.
* @throws BurnException
* On error.
*/
public MultiCaps getMultiCaps(WriteType wt) throws BurnException {
/* flag param unused yet */
return burn_disc_get_multi_caps(pointerOf(this),
wt.ordinal(), 0);
}
/**
* TODO not implemented in libburn
*
* Read a disc from the drive and write it to an fd pair. The drive must be
* grabbed successfully BEFORE calling this function. Always ensure that the
* drive reports a status of BURN_DISC_FULL before calling this function.
*
* @param opts
* The options for the read operation.
*/
public void read(ReadOpts opts) {
burn_disc_read( pointerOf(this), pointerOf(opts) );
}
/**
* Inquire the formatting status, the associated sizes and the number of
* available formats. The info is media specific and stems from MMC command
* 23h READ FORMAT CAPACITY. See mmc5r03c.pdf 6.24 for background details.
* Media type can be determined via burn_disc_get_profile().
*
* @return
*
* @throws BurnException
* On failure
*/
public Formats getFormats() throws BurnException {
Formats f = burn_disc_get_formats( pointerOf(this) );
if ( f != null ) {
return f;
} else {
throw new BurnException("Can't get formats");
}
}
/**
* Inquire parameters of an available media format.
*
* @param index
* he index of the format item. Beginning with 0 up to reply
* parameter from {@link #getFormats()} :
* {@link Formats#getNumFormats()} - 1
* @return
* @throws BurnException
* On error
*/
public FormatDesc getFormatDescr(int index) throws BurnException {
FormatDesc fd = burn_disc_get_format_descr(pointerOf(this), index);
if ( fd == null ) {
throw new BurnException("Can't get format desc");
}
return fd;
}
private static native boolean burn_drive_grab(long drive, int load);
private static native void burn_drive_release(long drive, int eject);
private static native int burn_disc_get_status(long drive);
private static native short burn_disc_get_profile(long d);
private static native boolean burn_disc_erasable(long d);
private static native int burn_drive_get_status(long drive, long p);
private static native void burn_disc_erase(long drive, boolean fast);
private static native long burn_write_opts_new(long drive);
private static native long burn_disc_available_space(long d, long o);
private static native void burn_disc_write(long o, long disc);
private static native void burn_disc_format(long drive, long size, int flag);
private static native void burn_drive_cancel(long drive);
private static native boolean burn_drive_wrote_well(long d);
private static native long burn_drive_get_disc(long d);
private static native void burn_drive_set_speed(long d, int r, int w);
private static native int burn_drive_get_write_speed(long d);
private static native int burn_drive_get_min_write_speed(long d);
private static native int burn_drive_get_read_speed(long d);
private static native long burn_read_opts_new(long drive);
private static native SpeedDescriptor[] burn_drive_get_speedlist(long d);
private static native boolean burn_disc_pretend_blank(long drive);
private static native boolean burn_disc_pretend_full(long drive);
private static native int burn_disc_read_atip(long drive);
/*
* These two functions are wrapping for the single C function:
* int burn_drive_get_start_end_lba(struct burn_drive *drive,
* int *start_lba, int *end_lba, int flag);
*/
private static native int burn_drive_get_start_lba(long drive, int flag)
throws BurnException;
private static native int burn_drive_get_end_lba(long drive, int flag)
throws BurnException;
/*
* These two functions are wrapping for the single C function:
* int burn_disc_track_lba_nwa(struct burn_drive *d,
* struct burn_write_opts *o, int trackno, int *lba, int *nwa);
*/
private static native int burn_disc_track_lba(long d, long o, int trackno)
throws BurnException;
private static native int burn_disc_track_nwa(long d, long o, int trackno)
throws BurnException;
private static native int burn_disc_get_msc1(long d)
throws BurnException;
private static native MultiCaps burn_disc_get_multi_caps(long d,
int wt, int flag) throws BurnException;
private static native void burn_disc_read(long d, long o);
private static native Formats burn_disc_get_formats(long drive);
private static native FormatDesc burn_disc_get_format_descr(long d,
int index);
}