Reading emulated toc info from overwriteable media, new API isoburn_toc_*()
This commit is contained in:
parent
e572e50cae
commit
f1dacbfaee
@ -50,6 +50,9 @@
|
||||
extern struct isoburn *isoburn_list_start; /* in isoburn.c */
|
||||
|
||||
|
||||
int isoburn_emulate_toc(struct burn_drive *d, int flag);
|
||||
|
||||
|
||||
int isoburn_initialize(char msg[1024], int flag)
|
||||
{
|
||||
int major, minor, micro, bad_match= 0;
|
||||
@ -276,6 +279,12 @@ static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d,
|
||||
(*o)->emulation_mode= -1;
|
||||
goto ex;
|
||||
}
|
||||
/* try to read emulated toc */
|
||||
ret= isoburn_emulate_toc(d, 0);
|
||||
if(ret<0) {
|
||||
(*o)->emulation_mode= -1;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -915,3 +924,372 @@ int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno,
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0-7: info return mode
|
||||
0= do not return anything in info (do not even touch it)
|
||||
1= return volume id
|
||||
@return 1 seems to be a valid ISO image , 0 seems not to be ISO, <0 error
|
||||
*/
|
||||
int isoburn_read_iso_head(struct burn_drive *d, int lba,
|
||||
int *image_blocks, char *info, int flag)
|
||||
{
|
||||
unsigned char buffer[64*1024], *data;
|
||||
int ret, i, info_mode;
|
||||
off_t data_count;
|
||||
|
||||
ret = burn_read_data(d, ((off_t) lba) * (off_t) 2048, (char *) buffer,
|
||||
(off_t) 64*1024, &data_count, 2); /* no error messages */
|
||||
if(ret<=0)
|
||||
return(0);
|
||||
|
||||
data= buffer+32*1024;
|
||||
/* is this an ISO image ? */
|
||||
if(data[0]!=1)
|
||||
return(0);
|
||||
if(strncmp((char *) (data+1),"CD001",5)!=0)
|
||||
return(0);
|
||||
|
||||
*image_blocks= data[80] | (data[81]<<8) | (data[82]<<16) | (data[83]<<24);
|
||||
info_mode= flag&255;
|
||||
if(info_mode==0) {
|
||||
;
|
||||
} else if(info_mode==1) {
|
||||
strncpy(info, (char *) (data+40), 32);
|
||||
info[32]= 0;
|
||||
for(i= strlen(info)-1; i>=0; i--)
|
||||
if(info[i]!=' ')
|
||||
break;
|
||||
else
|
||||
info[i]= 0;
|
||||
} else {
|
||||
burn_msgs_submit(0x00060000,
|
||||
"Program error: Unknown info mode with isoburn_read_iso_head()",
|
||||
0, "FATAL", NULL);
|
||||
return(-1);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int isoburn_emulate_toc(struct burn_drive *d, int flag)
|
||||
{
|
||||
int ret, image_size= 0, lba, track_blocks, session_count= 0;
|
||||
struct isoburn *o;
|
||||
struct isoburn_toc_entry *item;
|
||||
char msg[160];
|
||||
|
||||
/* is the media emulated multi-session ? */
|
||||
ret= isoburn_find_emulator(&o, d, 0);
|
||||
if(ret<0)
|
||||
return(-1);
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
if(o->emulation_mode<=0)
|
||||
return(0);
|
||||
|
||||
lba= 0;
|
||||
ret= isoburn_read_iso_head(d, lba, &image_size, NULL, 0);
|
||||
if(ret<=0)
|
||||
{ret= 0; goto failure;}
|
||||
|
||||
lba= Libisoburn_overwriteable_starT;
|
||||
while(lba<image_size) {
|
||||
|
||||
ret= isoburn_read_iso_head(d, lba, &track_blocks, NULL, 0);
|
||||
if(ret<=0) {
|
||||
if(session_count>0) {
|
||||
sprintf(msg,
|
||||
"Chain of ISO session headers broken at #%d, LBA %ds",
|
||||
session_count+1, lba);
|
||||
burn_msgs_submit(0x00060000, msg, 0, "WARNING", NULL);
|
||||
}
|
||||
{ret= 0; goto failure;}
|
||||
}
|
||||
ret= isoburn_toc_entry_new(&item, o->toc, 0);
|
||||
if(ret<=0) {
|
||||
burn_msgs_submit(0x00060000,
|
||||
"Not enough memory for emulated TOC entry object",
|
||||
0, "FATAL", NULL);
|
||||
ret= -1; goto failure;
|
||||
}
|
||||
if(o->toc==NULL)
|
||||
o->toc= item;
|
||||
session_count++;
|
||||
item->session= session_count;
|
||||
item->track_no= session_count;
|
||||
item->start_lba= lba;
|
||||
item->track_blocks= track_blocks;
|
||||
|
||||
lba+= track_blocks;
|
||||
if(lba % Libisoburn_nwa_alignemenT)
|
||||
lba+= Libisoburn_nwa_alignemenT - (lba % Libisoburn_nwa_alignemenT);
|
||||
}
|
||||
sprintf(msg,
|
||||
"Chain of ISO session headers yielded %d sessions", session_count);
|
||||
burn_msgs_submit(0x00060000, msg, 0, "DEBUG", NULL);
|
||||
return(1);
|
||||
failure:;
|
||||
isoburn_toc_entry_destroy(&(o->toc), 1);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int isoburn_toc_new_arrays(struct isoburn_toc_disc *o,
|
||||
int session_count, int track_count, int flag)
|
||||
{
|
||||
int i;
|
||||
int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag);
|
||||
|
||||
o->sessions= calloc(session_count, sizeof(struct isoburn_toc_session));
|
||||
o->session_pointers=
|
||||
calloc(session_count, sizeof(struct isoburn_toc_session *));
|
||||
o->tracks= calloc(track_count, sizeof(struct isoburn_toc_track));
|
||||
o->track_pointers= calloc(track_count, sizeof(struct isoburn_toc_track *));
|
||||
if(o->sessions!=NULL && o->session_pointers!=NULL &&
|
||||
o->tracks!=NULL && o->track_pointers!=NULL) {
|
||||
for(i= 0; i<session_count; i++) {
|
||||
o->sessions[i].session= NULL;
|
||||
o->sessions[i].track_pointers= NULL;
|
||||
o->sessions[i].track_count= 0;
|
||||
o->sessions[i].toc_entry= NULL;
|
||||
o->session_pointers[i]= NULL;
|
||||
}
|
||||
for(i= 0; i<track_count; i++) {
|
||||
o->tracks[i].track= NULL;
|
||||
o->tracks[i].toc_entry= NULL;
|
||||
o->track_pointers[i]= NULL;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
/* failed */
|
||||
isoburn_toc_destroy_arrays(o, 0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int isoburn_toc_destroy_arrays(struct isoburn_toc_disc *o, int flag)
|
||||
{
|
||||
if(o->sessions!=NULL)
|
||||
free((char *) o->sessions);
|
||||
o->sessions= NULL;
|
||||
if(o->session_pointers!=NULL)
|
||||
free((char *) o->session_pointers);
|
||||
o->session_pointers= NULL;
|
||||
if(o->tracks!=NULL)
|
||||
free((char *) o->tracks);
|
||||
o->tracks= NULL;
|
||||
if(o->track_pointers!=NULL)
|
||||
free((char *) o->track_pointers);
|
||||
o->track_pointers= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d)
|
||||
{
|
||||
int ret, session_count= 0, track_count= 0, num_tracks= 0, i, j;
|
||||
struct isoburn *o;
|
||||
struct isoburn_toc_entry *t;
|
||||
struct isoburn_toc_disc *toc_disc= NULL;
|
||||
struct burn_session **s;
|
||||
struct burn_track **tracks;
|
||||
|
||||
toc_disc= calloc(1, sizeof(struct isoburn_toc_disc));
|
||||
if(toc_disc==NULL)
|
||||
return(NULL);
|
||||
toc_disc->disc= NULL;
|
||||
toc_disc->sessions= NULL;
|
||||
toc_disc->session_pointers= NULL;
|
||||
toc_disc->tracks= NULL;
|
||||
toc_disc->track_pointers= NULL;
|
||||
toc_disc->session_count= 0;
|
||||
toc_disc->track_count= 0;
|
||||
toc_disc->toc= NULL;
|
||||
|
||||
/* is the media emulated multi-session ? */
|
||||
ret= isoburn_find_emulator(&o, d, 0);
|
||||
if(ret<=0)
|
||||
goto libburn;
|
||||
if(o->toc==NULL)
|
||||
goto libburn;
|
||||
|
||||
/* This is an emulated TOC */
|
||||
toc_disc->toc= o->toc;
|
||||
for(t= toc_disc->toc; t!=NULL; t= t->next)
|
||||
session_count++;
|
||||
ret= isoburn_toc_new_arrays(toc_disc, session_count, session_count, 0);
|
||||
if(ret<=0)
|
||||
goto failure;
|
||||
t= toc_disc->toc;
|
||||
for(i= 0; i<session_count; i++) {
|
||||
toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+i;
|
||||
toc_disc->sessions[i].track_count= 1;
|
||||
toc_disc->sessions[i].toc_entry= t;
|
||||
toc_disc->session_pointers[i]= toc_disc->sessions+i;
|
||||
toc_disc->tracks[i].toc_entry= t;
|
||||
toc_disc->track_pointers[i]= toc_disc->tracks+i;
|
||||
t= t->next;
|
||||
}
|
||||
toc_disc->session_count= session_count;
|
||||
toc_disc->track_count= session_count;
|
||||
return(toc_disc);
|
||||
|
||||
libburn:;
|
||||
/* This is a libburn provided TOC */
|
||||
toc_disc->disc= burn_drive_get_disc(d);
|
||||
if(toc_disc->disc == NULL) {
|
||||
failure:;
|
||||
free((char *) toc_disc);
|
||||
return(NULL);
|
||||
}
|
||||
s= burn_disc_get_sessions(toc_disc->disc, &session_count);
|
||||
for(i= 0; i<session_count; i++) {
|
||||
tracks = burn_session_get_tracks(s[i], &num_tracks);
|
||||
track_count+= num_tracks;
|
||||
}
|
||||
if(session_count<=0 || track_count<=0)
|
||||
goto failure;
|
||||
ret= isoburn_toc_new_arrays(toc_disc, session_count, track_count, 0);
|
||||
if(ret<=0)
|
||||
goto failure;
|
||||
track_count= 0;
|
||||
for(i= 0; i<session_count; i++) {
|
||||
tracks = burn_session_get_tracks(s[i], &num_tracks);
|
||||
toc_disc->sessions[i].session= s[i];
|
||||
toc_disc->sessions[i].track_pointers= toc_disc->track_pointers+track_count;
|
||||
toc_disc->sessions[i].track_count= num_tracks;
|
||||
toc_disc->session_pointers[i]= toc_disc->sessions+i;
|
||||
for(j= 0; j<num_tracks; j++) {
|
||||
toc_disc->tracks[track_count+j].track= tracks[j];
|
||||
toc_disc->track_pointers[track_count+j]= toc_disc->tracks+(track_count+j);
|
||||
}
|
||||
track_count+= num_tracks;
|
||||
}
|
||||
toc_disc->session_count= session_count;
|
||||
toc_disc->track_count= track_count;
|
||||
return(toc_disc);
|
||||
}
|
||||
|
||||
|
||||
int isoburn_toc_disc_get_sectors(struct isoburn_toc_disc *disc)
|
||||
{
|
||||
struct isoburn_toc_entry *t;
|
||||
int count= 0;
|
||||
|
||||
if(disc==NULL)
|
||||
return(0);
|
||||
if(disc->toc!=NULL) {
|
||||
for(t= disc->toc; t!=NULL; t= t->next)
|
||||
count+= t->track_blocks;
|
||||
} else if(disc->disc!=NULL)
|
||||
count= burn_disc_get_sectors(disc->disc);
|
||||
return(count);
|
||||
}
|
||||
|
||||
|
||||
struct isoburn_toc_session **isoburn_toc_disc_get_sessions(
|
||||
struct isoburn_toc_disc *disc, int *num)
|
||||
{
|
||||
*num= disc->session_count;
|
||||
return(disc->session_pointers);
|
||||
}
|
||||
|
||||
|
||||
int isoburn_toc_session_get_sectors(struct isoburn_toc_session *s)
|
||||
{
|
||||
struct isoburn_toc_entry *t;
|
||||
int count= 0, i;
|
||||
|
||||
if(s==NULL)
|
||||
return(0);
|
||||
if(s->toc_entry!=NULL) {
|
||||
t= s->toc_entry;
|
||||
for(i= 0; i<s->track_count; i++) {
|
||||
count+= t->track_blocks;
|
||||
t= t->next;
|
||||
}
|
||||
} else if(s->session!=NULL)
|
||||
count= burn_session_get_sectors(s->session);
|
||||
return(count);
|
||||
}
|
||||
|
||||
|
||||
int isoburn_toc_entry_finish(struct burn_toc_entry *entry,
|
||||
int session_no, int track_no, int flag)
|
||||
{
|
||||
int pmin, psec, pframe;
|
||||
|
||||
entry->extensions_valid= 1;
|
||||
entry->adr= 1;
|
||||
entry->control= 4;
|
||||
entry->session= session_no & 255;
|
||||
entry->session_msb= (session_no >> 8) & 255;
|
||||
entry->point= track_no & 255;
|
||||
entry->point_msb= (track_no >> 8) & 255;
|
||||
|
||||
burn_lba_to_msf(entry->start_lba, &pmin, &psec, &pframe);
|
||||
if(pmin<=255)
|
||||
entry->pmin= pmin;
|
||||
else
|
||||
entry->pmin= 255;
|
||||
entry->psec= psec;
|
||||
entry->pframe= pframe;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
void isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session *s,
|
||||
struct burn_toc_entry *entry)
|
||||
{
|
||||
struct isoburn_toc_track *t;
|
||||
|
||||
if(s==NULL)
|
||||
return;
|
||||
if(s->session!=NULL && s->toc_entry==NULL) {
|
||||
burn_session_get_leadout_entry(s->session, entry);
|
||||
return;
|
||||
}
|
||||
if(s->track_count<=0 || s->track_pointers==NULL || s->toc_entry==NULL)
|
||||
return;
|
||||
t= s->track_pointers[s->track_count-1];
|
||||
entry->start_lba= t->toc_entry->start_lba + t->toc_entry->track_blocks;
|
||||
entry->track_blocks= 0;
|
||||
isoburn_toc_entry_finish(entry, s->toc_entry->session, t->toc_entry->track_no,
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
struct isoburn_toc_track **isoburn_toc_session_get_tracks(
|
||||
struct isoburn_toc_session *s, int *num)
|
||||
{
|
||||
*num= s->track_count;
|
||||
return(s->track_pointers);
|
||||
}
|
||||
|
||||
|
||||
void isoburn_toc_track_get_entry(struct isoburn_toc_track *t,
|
||||
struct burn_toc_entry *entry)
|
||||
{
|
||||
if(t==0)
|
||||
return;
|
||||
if(t->track!=NULL && t->toc_entry==NULL) {
|
||||
burn_track_get_entry(t->track, entry);
|
||||
return;
|
||||
}
|
||||
if(t->toc_entry==NULL)
|
||||
return;
|
||||
entry->start_lba= t->toc_entry->start_lba;
|
||||
entry->track_blocks= t->toc_entry->track_blocks;
|
||||
isoburn_toc_entry_finish(entry, t->toc_entry->session, t->toc_entry->track_no,
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
void isoburn_toc_disc_free(struct isoburn_toc_disc *d)
|
||||
{
|
||||
if(d->disc!=NULL)
|
||||
burn_disc_free(d->disc);
|
||||
isoburn_toc_destroy_arrays(d, 0);
|
||||
free((char *) d);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,13 @@ struct isoburn_toc_entry {
|
||||
struct isoburn_toc_entry *next;
|
||||
};
|
||||
|
||||
int isoburn_toc_entry_new(struct isoburn_toc_entry **objpt,
|
||||
struct isoburn_toc_entry *boss, int flag);
|
||||
|
||||
/* @param flag bit0= delete all subordinates too
|
||||
*/
|
||||
int isoburn_toc_entry_destroy(struct isoburn_toc_entry **o, int flag);
|
||||
|
||||
|
||||
struct isoburn {
|
||||
|
||||
@ -366,6 +373,33 @@ struct isoburn_imgen_opts {
|
||||
((off_t) (Libisoburn_target_head_sizE/2048))
|
||||
|
||||
|
||||
/* Wrappers for emulation of TOC on overwriteable media */
|
||||
|
||||
struct isoburn_toc_track {
|
||||
/* Either track or toc_entry are supposed to be NULL */
|
||||
struct burn_track *track;
|
||||
struct isoburn_toc_entry *toc_entry;
|
||||
};
|
||||
|
||||
struct isoburn_toc_session {
|
||||
/* Either session or tracks and toc_entry are supposed to be NULL */
|
||||
struct burn_session *session;
|
||||
struct isoburn_toc_track **track_pointers;
|
||||
int track_count;
|
||||
struct isoburn_toc_entry *toc_entry;
|
||||
};
|
||||
|
||||
struct isoburn_toc_disc {
|
||||
/* Either disc or sessions and toc are supposed to be NULL */
|
||||
struct burn_disc *disc;
|
||||
struct isoburn_toc_session *sessions; /* storage array */
|
||||
struct isoburn_toc_session **session_pointers; /* storage array */
|
||||
struct isoburn_toc_track *tracks; /* storage array */
|
||||
struct isoburn_toc_track **track_pointers; /* storage array */
|
||||
int session_count;
|
||||
int track_count;
|
||||
struct isoburn_toc_entry *toc;
|
||||
};
|
||||
|
||||
#endif /* Isoburn_includeD */
|
||||
|
||||
|
@ -381,6 +381,120 @@ int isoburn_disc_erasable(struct burn_drive *d);
|
||||
void isoburn_disc_erase(struct burn_drive *drive, int fast);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*
|
||||
|
||||
Wrappers for emulation of TOC on overwriteable media
|
||||
|
||||
Media which match the overwriteable usage model lack of a history of sessions
|
||||
and tracks. libburn will not even hand out a burn_disc object for them and
|
||||
always declare them blank. libisoburn checks for a valid ISO filesystem
|
||||
header at LBA 0 and eventually declares them appendable.
|
||||
Nevertheless one can only determine an upper limit of the size of the overall
|
||||
image (by isoburn_get_min_start_byte()) but not a list of stored sessions
|
||||
and their LBAs, as it is possible with true multi-session media.
|
||||
|
||||
The following wrappers add the capability to obtain a session and track TOC
|
||||
from emulated multi-session images on overwriteables if the first session
|
||||
was written by libisoburn-0.1.6 or later (i.e. with a header copy at LBA 32).
|
||||
|
||||
Be aware that the structs emitted by these isoburn calls are not compatible
|
||||
with the libburn structs. I.e. you may use them only with isoburn_toc_*
|
||||
calls.
|
||||
isoburn_toc_disc needs to be freed after use. isoburn_toc_session and
|
||||
isoburn_toc_track vanish together with their isoburn_toc_disc.
|
||||
*/
|
||||
|
||||
/* Opaque handles to media, session, track */
|
||||
struct isoburn_toc_disc;
|
||||
struct isoburn_toc_session;
|
||||
struct isoburn_toc_track;
|
||||
|
||||
|
||||
/** Obtain a master handle for the table of content.
|
||||
This handle governs allocated resources which have to be released by
|
||||
isoburn_toc_disc_free() when no longer needed.
|
||||
Wrapper for: burn_drive_get_disc()
|
||||
@since 0.1.6
|
||||
@param drive The drive with the media to inspect
|
||||
@return NULL in case there is no content info, else it is a valid handle
|
||||
*/
|
||||
struct isoburn_toc_disc *isoburn_toc_drive_get_disc(struct burn_drive *d);
|
||||
|
||||
|
||||
/** Tell the number of 2048 byte blocks covered by the table of content.
|
||||
Wrapper for: burn_disc_get_sectors()
|
||||
@since 0.1.6
|
||||
@param disc The master handle of the media
|
||||
@return number of blocks, <=0 indicates unknown or unreadable state
|
||||
*/
|
||||
int isoburn_toc_disc_get_sectors(struct isoburn_toc_disc *disc);
|
||||
|
||||
|
||||
/** Get the array of session handles from the table of content.
|
||||
Wrapper for: burn_disc_get_sessions()
|
||||
@since 0.1.6
|
||||
@param disc The master handle of the media
|
||||
@param num returns the number of sessions in the array
|
||||
@return the address of the array of session handles
|
||||
*/
|
||||
struct isoburn_toc_session **isoburn_toc_disc_get_sessions(
|
||||
struct isoburn_toc_disc *disc, int *num);
|
||||
|
||||
|
||||
/** Tell the number of 2048 byte blocks covered by a particular session.
|
||||
Wrapper for: burn_session_get_sectors()
|
||||
@since 0.1.6
|
||||
@param s The session handle
|
||||
@return number of blocks, <=0 indicates unknown or unreadable state
|
||||
*/
|
||||
int isoburn_toc_session_get_sectors(struct isoburn_toc_session *s);
|
||||
|
||||
|
||||
/** Obtain a copy of the entry which describes the end of a particular session.
|
||||
Wrapper for: burn_session_get_leadout_entry()
|
||||
@since 0.1.6
|
||||
@param s The session handle
|
||||
@param entry A pointer to memory provided by the caller. It will be filled
|
||||
with info according to struct burn_toc_entry as defined
|
||||
in libburn.h
|
||||
*/
|
||||
void isoburn_toc_session_get_leadout_entry(struct isoburn_toc_session *s,
|
||||
struct burn_toc_entry *entry);
|
||||
|
||||
|
||||
/** Get the array of track handles from a particular session.
|
||||
Wrapper for: burn_session_get_tracks()
|
||||
@since 0.1.6
|
||||
@param s The session handle
|
||||
@param num returns the number of tracks in the array
|
||||
@return the address of the array of track handles
|
||||
*/
|
||||
struct isoburn_toc_track **isoburn_toc_session_get_tracks(
|
||||
struct isoburn_toc_session *s, int *num);
|
||||
|
||||
|
||||
/** Obtain a copy of the entry which describes a particular itrack.
|
||||
Wrapper for: burn_track_get_entry()
|
||||
@since 0.1.6
|
||||
@param s The track handle
|
||||
@param entry A pointer to memory provided by the caller. It will be filled
|
||||
with info according to struct burn_toc_entry as defined
|
||||
in libburn.h
|
||||
*/
|
||||
void isoburn_toc_track_get_entry(struct isoburn_toc_track *t,
|
||||
struct burn_toc_entry *entry);
|
||||
|
||||
|
||||
/** Release the memory associated with a master handle of media.
|
||||
The handle is invalid afterwards and may not be used any more.
|
||||
Wrapper for: burn_disc_free()
|
||||
@since 0.1.6
|
||||
@param disc The master handle of the media
|
||||
*/
|
||||
void isoburn_toc_disc_free(struct isoburn_toc_disc *disc);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*
|
||||
|
||||
|
@ -1 +1 @@
|
||||
#define Xorriso_timestamP "2008.05.07.071427"
|
||||
#define Xorriso_timestamP "2008.05.07.175508"
|
||||
|
Loading…
Reference in New Issue
Block a user