Reading emulated toc info from overwriteable media, new API isoburn_toc_*()

This commit is contained in:
2008-05-07 17:54:55 +00:00
parent 947bb33173
commit e9171b5133
4 changed files with 527 additions and 1 deletions

View File

@ -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);
}