diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 61c79ff..88d261f 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2007.02.19.184132" +#define Cdrskin_timestamP "2007.02.19.225102" diff --git a/libburn/async.c b/libburn/async.c index 6bb1060..df07005 100644 --- a/libburn/async.c +++ b/libburn/async.c @@ -12,6 +12,7 @@ #include #include #include +#include /* #include @@ -332,7 +333,11 @@ static void *write_disc_worker_func(struct w_list *w) void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) { struct write_opts o; + char reasons[1024+80]; +#ifndef Libburn_precheck_write_ruleS int i, j, mode, mixed_mode = 0; +#endif + /* For the next lines any return indicates failure */ opts->drive->cancel = 1; @@ -360,10 +365,37 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) "Drive capabilities not inquired yet", 0, 0); return; } + + /* ts A70219 : intended to replace all further tests here and many + tests in burn_*_write_sync() + */ + strcpy(reasons, "Write job parameters seem unsuitable:\n"); + if (burn_precheck_write(opts, disc, reasons + strlen(reasons), 0) + == BURN_WRITE_NONE) { + +#ifndef Libburn_precheck_write_ruleS + libdax_msgs_submit(libdax_messenger, + opts->drive->global_index, 0x00020139, + LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH, + reasons, 0, 0); +#else + libdax_msgs_submit(libdax_messenger, + opts->drive->global_index, 0x00020139, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + reasons, 0, 0); + return; +#endif /* Libburn_precheck_write_ruleS */ + + } + + +#ifndef Libburn_precheck_write_ruleS + /* <<< covered burn_precheck_write() */ /* ts A61009 : obsolete Assert in sector_headers() */ - if (! burn_disc_write_is_ok(opts, disc)) /* issues own msgs */ + if (! burn_disc_write_is_ok(opts, disc, 0)) /* issues own msgs */ return; + /* <<< covered burn_precheck_write() */ /* ts A70122 : libburn SAO code mishandles mode changes */ for (i = 0; i < disc->sessions; i++) { if (disc->session[i]->tracks <= 0) @@ -380,6 +412,7 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc) "Cannot mix data and audio in SAO mode", 0, 0); return; } +#endif /* ! Libburn_precheck_write_ruleS */ opts->drive->cancel = 0; /* End of the return = failure area */ diff --git a/libburn/drive.c b/libburn/drive.c index da62c9f..26a89d6 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -29,6 +29,9 @@ /* ts A70107 : to get BE_CANCELLED */ #include "error.h" +/* ts A70219 : for burn_disc_get_write_mode_demands() */ +#include "options.h" + #include "libdax_msgs.h" extern struct libdax_msgs *libdax_messenger; @@ -1707,15 +1710,21 @@ int burn_disc_free_multi_caps(struct burn_multi_caps **caps) @param flag bit0= fill_up_media is active */ int burn_disc_get_write_mode_demands(struct burn_disc *disc, + struct burn_write_opts *opts, struct burn_disc_mode_demands *result, int flag) { struct burn_session *session; struct burn_track *track; int i, j, mode, unknown_track_sizes = 0, last_track_is_unknown = 0; + enum burn_disc_status s; + memset((char *) result, 0, sizeof(struct burn_disc_mode_demands)); if (disc == NULL) return 2; + s = burn_disc_get_status(opts->drive); + if (s == BURN_DISC_APPENDABLE || disc->sessions > 1) + result->will_append = 1; if (disc->sessions > 1) result->multi_session = 1; for (i = 0; i < disc->sessions; i++) { @@ -1728,17 +1737,27 @@ int burn_disc_get_write_mode_demands(struct burn_disc *disc, for (j = 0; j < session->tracks; j++) { track = session->track[j]; if (burn_track_is_open_ended(track)) { - result->unknown_track_size = 1; + if (burn_track_get_default_size(track) > 0) { + if (result->unknown_track_size == 0) + result->unknown_track_size = 2; + } else + result->unknown_track_size = 1; unknown_track_sizes++; last_track_is_unknown = 1; } else last_track_is_unknown = 0; if (mode != track->mode) result->mixed_mode = 1; - if (track->mode != BURN_MODE1) - result->exotic_track = 1; - if (track->mode == BURN_AUDIO) + if (track->mode == BURN_MODE1) { + result->block_types |= BURN_BLOCK_MODE1; + } else if (track->mode == BURN_AUDIO) { result->audio = 1; + result->block_types |= BURN_BLOCK_RAW0; + result->exotic_track = 1; + } else { + result->block_types |= opts->block_type; + result->exotic_track = 1; + } } } if (flag&1) {/* fill_up_media will define the size of the last track */ diff --git a/libburn/drive.h b/libburn/drive.h index e658b51..2c14cd6 100644 --- a/libburn/drive.h +++ b/libburn/drive.h @@ -100,12 +100,15 @@ void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag); struct burn_disc_mode_demands { int multi_session; int multi_track; - int unknown_track_size; + int unknown_track_size; /* 0=known, 1=unknown, 2=unknown+defaulted */ int mixed_mode; int audio; int exotic_track; + int block_types; + int will_append; /* because of media state or multi session disc */ }; int burn_disc_get_write_mode_demands(struct burn_disc *disc, - struct burn_disc_mode_demands *result, int flag); + struct burn_write_opts *opts, + struct burn_disc_mode_demands *result, int flag); #endif /* __DRIVE */ diff --git a/libburn/libburn.h b/libburn/libburn.h index a365d00..7edd956 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -997,6 +997,23 @@ int burn_disc_get_format_descr(struct burn_drive *drive, int index, */ void burn_disc_read(struct burn_drive *drive, const struct burn_read_opts *o); + +/* ts A70219 */ +/** Examines a completed setup for burn_disc_write() wether it is permissible + with drive and media. This function is called by burn_disc_write() but + an application might be interested in this check in advance. + @param o The options for the writing operation. + @param disc The descrition of the disc to be created + @param reasons Eventually returns a list of rejection reason statements + @param silent 1= do not issue error messages , 0= report severe problems +*/ +int burn_precheck_write( struct burn_write_opts *o, struct burn_disc *disc, + char reasons[1024], int silent); + +/* <<< enabling switch for internal usage and trust in this functiion */ +#define Libburn_precheck_write_ruleS 1 + + /** Write a disc in the drive. The drive must be grabbed successfully before calling this function. Always ensure that the drive reports a status of BURN_DISC_BLANK before calling this function. @@ -1177,6 +1194,20 @@ struct burn_disc *burn_drive_get_disc(struct burn_drive *d); enum burn_source_status burn_track_set_source(struct burn_track *t, struct burn_source *s); + +/* ts A70218 */ +/** Set a default track size to be used only if the track turns out to be of + unpredictable length and if the effective write type demands a fixed size. + This can be useful to enable write types CD SAO or DVD DAO together with + a track source like stdin. If the track source delivers fewer bytes than + announced then the track will be padded up with zeros. + @param t The track to change + @param size The size to set + @return 0=failure 1=sucess +*/ +int burn_track_set_default_size(struct burn_track *t, off_t size); + + /** Free a burn_source (decrease its refcount and maybe free it) @param s Source to free */ @@ -1196,6 +1227,7 @@ struct burn_source *burn_file_source_new(const char *path, */ struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size); + /** Tells how long a track will be on disc >>> NOTE: Not reliable with tracks of undefined length */ @@ -1241,7 +1273,9 @@ int burn_write_opts_set_write_type(struct burn_write_opts *opts, @param opts The nearly complete write opts to change @param disc The already composed session and track model @param reasons This text string collects reasons for decision resp. failure - @param flag Bitfield for control purposes (unused yet, submit 0) + @param flag Bitfield for control purposes: + bit0= do not choose type but check the one that is already set + bit1= do not issue error messages via burn_msgs queue @return Chosen write type. BURN_WRITE_NONE on failure. */ enum burn_write_types burn_write_opts_auto_write_type( @@ -1446,7 +1480,7 @@ struct burn_multi_caps { of multi-session by keeping a disc appendable. But .might_do_sao will be 0 afterwards, when checking the appendable media.) 1= media may be kept appendable by burn_write_opts_set_multi(o,1) - 0= media will not be apendable appendable + 0= media will not be appendable */ int multi_session; diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index 1b7b9fa..cf18d48 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -352,16 +352,19 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x0002012b (FATAL,HIGH) = Drive offers no suitable write mode with this job 0x0002012c (SORRY,HIGH) = Too many logical tracks recorded 0x0002012d (FATAL,HIGH) = Exceeding range of permissible write addresses - + 0x0002012e (NOTE,HIGH) = Activated track default size + 0x0002012f (SORRY,HIGH) = SAO is restricted to single fixed size session 0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking 0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive 0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn 0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode 0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO 0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO - 0x00020136 (SORRY,HIGH) = DAO Burning restricted to single fixed size track + 0x00020136 (SORRY,HIGH) = DAO burning restricted to single fixed size track 0x00020137 (HINT,HIGH) = TAO would be possible 0x00020138 (FATAL,HIGH) = Cannot reserve track + 0x00020139 (WARN,HIGH) = Unsuitable write type and/or block types detected + to become ^ SORRY ^ soon libdax_audioxtr: diff --git a/libburn/options.c b/libburn/options.c index 037da67..434344b 100644 --- a/libburn/options.c +++ b/libburn/options.c @@ -173,9 +173,6 @@ void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value) /* ts A70207 API */ -/* @param flag Bitfield for control purposes - bit0=do not look for suitable type but check preset type in opts -*/ enum burn_write_types burn_write_opts_auto_write_type( struct burn_write_opts *opts, struct burn_disc *disc, char reasons[1024], int flag) @@ -183,41 +180,45 @@ enum burn_write_types burn_write_opts_auto_write_type( struct burn_multi_caps *caps = NULL; struct burn_drive *d = opts->drive; struct burn_disc_mode_demands demands; - int ret; + enum burn_write_types wt; + int ret, would_do_sao = 0; char *reason_pt; reasons[0] = 0; - ret = burn_disc_get_write_mode_demands(disc, &demands, + ret = burn_disc_get_write_mode_demands(disc, opts, &demands, !!opts->fill_up_media); if (ret <= 0) { strcat(reasons, "cannot recognize job demands, "); - return BURN_WRITE_NONE; + {wt = BURN_WRITE_NONE; goto ex;} } if (demands.exotic_track && !d->current_is_cd_profile) { - libdax_msgs_submit(libdax_messenger, d->global_index, - 0x00020123, - LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - "DVD Media are unsuitable for desired track type", - 0, 0); + if (!(flag & 2)) + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020123, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "DVD Media are unsuitable for desired track type", + 0, 0); if (demands.audio) strcat(reasons, "audio track prohibited by non-CD, "); else strcat(reasons, "exotic track prohibited by non-CD, "); - return BURN_WRITE_NONE; + {wt = BURN_WRITE_NONE; goto ex;} } if ((flag & 1) && opts->write_type != BURN_WRITE_SAO) goto try_tao; + burn_disc_free_multi_caps(&caps); ret = burn_disc_get_multi_caps(d, BURN_WRITE_SAO, &caps, 0); if (ret < 0) { no_caps:; - libdax_msgs_submit(libdax_messenger, d->global_index, + if (!(flag & 2)) + libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002012a, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, "Cannot inquire write mode capabilities", 0, 0); strcat(reasons, "cannot inquire write mode capabilities, "); - return BURN_WRITE_NONE; + {wt = BURN_WRITE_NONE; goto ex;} } else if (ret == 0) { strcat(reasons, "SAO: no SAO offered by drive and media, "); goto no_sao; @@ -227,26 +228,42 @@ no_caps:; if ((opts->multi || demands.multi_session) && !caps->multi_session) strcat(reasons, "multi session capability lacking, "); + if (demands.will_append) + strcat(reasons, "appended session capability lacking, "); if (demands.multi_track && !caps->multi_track) strcat(reasons, "multi track capability lacking, "); - if (demands.unknown_track_size) + if (demands.unknown_track_size == 1) strcat(reasons, "track size unpredictable, "); if (demands.mixed_mode) strcat(reasons, "tracks of different modes mixed, "); + if (demands.exotic_track) + strcat(reasons, "non-audio, non-data track, "); + else if (d->current_is_cd_profile) + if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) != + demands.block_types) + strcat(reasons, "drive dislikes block type, "); if (d->current_is_cd_profile && opts->fill_up_media) strcat(reasons, "cd sao cannot do media fill up yet, "); if (strcmp(reason_pt, "SAO: ") != 0) goto no_sao; - burn_write_opts_set_write_type(opts, BURN_WRITE_SAO, BURN_BLOCK_SAO); - return BURN_WRITE_SAO; + would_do_sao = 1; + if (demands.unknown_track_size == 2 && !(flag & 1)) { + strcat(reasons, "would have to use default track sizes, "); + goto no_sao; + } +do_sao:; + if (!(flag & 1)) + burn_write_opts_set_write_type( + opts, BURN_WRITE_SAO, BURN_BLOCK_SAO); + {wt = BURN_WRITE_SAO; goto ex;} no_sao:; - burn_disc_free_multi_caps(&caps); strcat(reasons, "\n"); try_tao:; if ((flag & 1) && opts->write_type != BURN_WRITE_TAO) - goto no_tao; + goto try_raw; reason_pt = reasons + strlen(reasons); strcat(reasons, "TAO: "); + burn_disc_free_multi_caps(&caps); ret = burn_disc_get_multi_caps(d, BURN_WRITE_TAO, &caps, 0); if (ret < 0) goto no_caps; @@ -258,31 +275,57 @@ try_tao:; strcat(reasons, "multi session capability lacking, "); if (demands.multi_track && !caps->multi_track) strcat(reasons, "multi track capability lacking, "); - - if (d->current_is_cd_profile) { - - /* >>> check block types */; - - } - + if (demands.exotic_track) + strcat(reasons, "non-audio, non-data track, "); + if (d->current_is_cd_profile) + if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) != + demands.block_types) + strcat(reasons, "drive dislikes block type, "); if (strcmp(reason_pt, "TAO: ") != 0) goto no_tao; /* ( TAO data/audio block size will be handled automatically ) */ - burn_write_opts_set_write_type(opts, - BURN_WRITE_TAO, BURN_BLOCK_MODE1); - return BURN_WRITE_TAO; + if (!(flag & 1)) + burn_write_opts_set_write_type( + opts, BURN_WRITE_TAO, BURN_BLOCK_MODE1); + {wt = BURN_WRITE_TAO; goto ex;} no_tao:; + if (would_do_sao && !(flag &1)) + goto do_sao; if (!d->current_is_cd_profile) goto no_write_mode; + strcat(reasons, "\n"); +try_raw:; + if ((flag & 1) && opts->write_type != BURN_WRITE_RAW) + goto no_write_mode; - /* >>> evaluate RAW modes */; + if (!(flag & 1)) /* For now: no automatic raw write modes */ + goto no_write_mode; + + reason_pt = reasons + strlen(reasons); + strcat(reasons, "RAW: "); + if (!d->current_is_cd_profile) + strcat(reasons, "prohibited by non-CD, "); + if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) != + demands.block_types) + strcat(reasons, "drive dislikes block type, "); + if (strcmp(reason_pt, "RAW: ") != 0) + goto no_write_mode; + + /* For now: no setting of raw write modes */ + + {wt = BURN_WRITE_RAW; goto ex;} no_write_mode:; - libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002012b, + if (!(flag & (1 | 2))) + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x0002012b, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, "Drive offers no suitable write mode with this job", 0, 0); - return BURN_WRITE_NONE; + wt = BURN_WRITE_NONE; +ex:; + burn_disc_free_multi_caps(&caps); + return wt; } diff --git a/libburn/structure.c b/libburn/structure.c index b8b6a66..156a275 100644 --- a/libburn/structure.c +++ b/libburn/structure.c @@ -116,6 +116,8 @@ struct burn_track *burn_track_create(void) /* ts A70213 */ t->fill_up_media = 0; + /* ts A70218 */ + t->default_size = 0; t->entry = NULL; t->source = NULL; @@ -351,6 +353,13 @@ int burn_track_set_sectors(struct burn_track *t, int sectors) } +/* ts A70218 */ +int burn_track_set_size(struct burn_track *t, off_t size) +{ + return t->source->set_size(t->source, size); +} + + /* ts A70213 */ int burn_track_set_fillup(struct burn_track *t, int fill_up_media) { @@ -392,6 +401,22 @@ int burn_track_is_open_ended(struct burn_track *t) return !!t->open_ended; } + +/* ts A70218 : API */ +int burn_track_set_default_size(struct burn_track *t, off_t size) +{ + t->default_size = size; + return 1; +} + + +/* ts A70218 */ +off_t burn_track_get_default_size(struct burn_track *t) +{ + return t->default_size; +} + + /* ts A61101 : API function */ int burn_track_get_counters(struct burn_track *t, off_t *read_bytes, off_t *written_bytes) diff --git a/libburn/structure.h b/libburn/structure.h index 15739b3..89f25d5 100644 --- a/libburn/structure.h +++ b/libburn/structure.h @@ -31,6 +31,9 @@ struct burn_track /* ts A70213 : wether to expand this track to full available media */ int fill_up_media; + /* ts A70218 : a track size to use if it is mandarory to have some */ + off_t default_size; + /** Data source */ struct burn_source *source; /** End of Source flag */ @@ -92,13 +95,18 @@ int burn_track_get_shortage(struct burn_track *t); int burn_track_is_open_ended(struct burn_track *t); int burn_track_is_data_done(struct burn_track *t); -/* ts A70125 */ +/* ts A70125 : sets overall sectors of a track: offset+payload+padding */ int burn_track_set_sectors(struct burn_track *t, int sectors); +/* ts A70218 : sets the payload size alone */ +int burn_track_set_size(struct burn_track *t, off_t size); + /* ts A70213 */ int burn_track_set_fillup(struct burn_track *t, int fill_up_media); int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag); +/* ts A70218 */ +off_t burn_track_get_default_size(struct burn_track *t); #endif /* BURN__STRUCTURE_H */ diff --git a/libburn/write.c b/libburn/write.c index c58fd7c..2928070 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -718,7 +718,7 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s, (double) d->media_capacity_remaining); libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, - msg,0,0); + msg, 0, 0); if (nwa > d->nwa) d->nwa = nwa; @@ -820,7 +820,9 @@ ex:; } /* ts A61009 */ -int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc) +/* @param flag bit1 = do not libdax_msgs_submit() */ +int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc, + int flag) { int i, t; char msg[80]; @@ -834,9 +836,10 @@ int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc) bad_track_mode_found:; sprintf(msg, "Unsuitable track mode 0x%x in track %d of session %d", disc->session[i]->track[t]->mode, i+1, t+1); - libdax_msgs_submit(libdax_messenger, -1, 0x0002010a, - LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, - msg, 0, 0); + if (!(flag & 2)) + libdax_msgs_submit(libdax_messenger, -1, 0x0002010a, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + msg, 0, 0); return 0; } @@ -920,7 +923,7 @@ int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020138, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); return 0; } } @@ -986,7 +989,7 @@ int burn_dvd_write_track(struct burn_write_opts *o, (double) d->media_capacity_remaining); libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, - msg,0,0); + msg, 0, 0); } @@ -1167,7 +1170,7 @@ int burn_disc_setup_dvd_plus_rw(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020127, LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); } /* >>> perform OPC if needed */; @@ -1194,47 +1197,37 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020127, LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); d->nwa *= 16; /* convert to 2048 block units */ } - if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */ - /* ??? mmc5r03c.pdf 7.5.2 : - "For DVD-RW media ... If a medium is in Restricted overwrite - mode, this mode page shall not be used." + /* ??? mmc5r03c.pdf 7.5.2 : + "For DVD-RW media ... If a medium is in Restricted overwrite + mode, this mode page shall not be used." - But growisofs composes a page 5 and sends it. - mmc5r03c.pdf 5.3.16 , table 127 specifies that mode page 5 - shall be supported with feature 0026h Restricted Overwrite. - 5.3.22 describes a feature 002Ch Rigid Restrictive Overwrite - which seems to apply to DVD-RW and does not mention page 5. + But growisofs composes a page 5 and sends it. + mmc5r03c.pdf 5.3.16 , table 127 specifies that mode page 5 + shall be supported with feature 0026h Restricted Overwrite. + 5.3.22 describes a feature 002Ch Rigid Restrictive Overwrite + which seems to apply to DVD-RW and does not mention page 5. - 5.4.14 finally states that profile 0013h includes feature - 002Ch rather than 0026h. + 5.4.14 finally states that profile 0013h includes feature + 002Ch rather than 0026h. d->send_write_parameters(d, o); - */ + */ - d->busy = BURN_DRIVE_FORMATTING; + d->busy = BURN_DRIVE_FORMATTING; - /* "quick grow" to at least byte equivalent of d->nwa */ - ret = d->format_unit(d, (off_t) d->nwa * (off_t) 2048, - (d->nwa > 0) << 3); - if (ret <= 0) - return 0; - d->busy = BURN_DRIVE_WRITING; - - } else { - sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", - d->current_profile, d->current_profile_text); - libdax_msgs_submit(libdax_messenger, d->global_index, - 0x0002011e, - LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + /* "quick grow" to at least byte equivalent of d->nwa */ + ret = d->format_unit(d, (off_t) d->nwa * (off_t) 2048, + (d->nwa > 0) << 3); + if (ret <= 0) return 0; - } + + d->busy = BURN_DRIVE_WRITING; /* >>> perform OPC if needed */; @@ -1257,15 +1250,74 @@ int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o, } +/* ts A70219 : API */ +int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc, + char reasons[1024], int silent) +{ + enum burn_write_types wt; + struct burn_drive *d = o->drive; + char msg[160]; + + /* check write mode against write job */ + reasons[0] = 0; + wt = burn_write_opts_auto_write_type(o, disc, reasons, + 1 | ((!!silent) << 1)); + if (wt == BURN_WRITE_NONE) + return 0; + + sprintf(reasons, "%s: ", d->current_profile_text); + if (d->current_profile == 0x09 || d->current_profile == 0x0a) { + if (! burn_disc_write_is_ok(o, disc, (!!silent) << 1)) + strcat(reasons, "unsuitable track mode found, "); + if (o->start_byte >= 0) + strcat(reasons, "write start address not supported, "); + } else if (d->current_profile == 0x1a || d->current_profile == 0x12) { + /* DVD+RW , DVD-RAM */ + if (o->start_byte >= 0 && (o->start_byte % 2048)) + strcat(reasons, + "write start address not properly aligned to 2048, "); + } else if (d->current_profile == 0x13) { + /* DVD-RW Restricted Overwrite */ + if (o->start_byte >= 0 && (o->start_byte % 32768)) + strcat(reasons, + "write start address not properly aligned to 32k, "); + } else if (d->current_profile == 0x11 || d->current_profile == 0x14) { + if (o->start_byte >= 0) + strcat(reasons, "write start address not supported, "); + } else { + sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", + d->current_profile, d->current_profile_text); + if (!silent) + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x0002011e, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + msg, 0, 0); + strcat(reasons, "no suitable media profile detected, "); + } + if (strlen(reasons) > strlen(d->current_profile_text) + 2) + return 0; + return 1; +} + + /* ts A61218 - A70129 */ int burn_dvd_write_sync(struct burn_write_opts *o, struct burn_disc *disc) { - int i, ret, sx, tx, mode, exotic_track = 0, dao_is_ok, o_end; + int i, ret, o_end; + off_t default_size = 0; struct burn_drive *d = o->drive; + struct burn_track *t; char msg[160]; +#ifndef Libburn_precheck_write_ruleS + int exotic_track = 0, dao_is_ok, sx, tx, mode; +#endif + d->needs_close_session = 0; + +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() */ for (sx = 0; sx < disc->sessions; sx++) for (tx = 0 ; tx < disc->session[sx]->tracks; tx++) { mode = disc->session[sx]->track[tx]->mode; @@ -1277,10 +1329,11 @@ int burn_dvd_write_sync(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020123, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } + /* <<< covered by burn_precheck_write() */ if (d->current_profile == 0x1a || d->current_profile == 0x13 || d->current_profile == 0x12) { /* DVD+RW , DVD-RW Restricted Overwrite , DVD-RAM */ @@ -1292,21 +1345,28 @@ int burn_dvd_write_sync(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002011f, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } } +#endif /* ! Libburn_precheck_write_ruleS */ + if (d->current_profile == 0x1a || d->current_profile == 0x12) { /* DVD+RW , DVD-RAM */ + +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() */ if (o->start_byte >= 0 && (o->start_byte % 2048)) { sprintf(msg, "Write start address not properly aligned to 2048"); libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020125, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } +#endif /* ! Libburn_precheck_write_ruleS */ + ret = 1; if (d->current_profile == 0x1a) ret = burn_disc_setup_dvd_plus_rw(o, disc); @@ -1316,22 +1376,27 @@ int burn_dvd_write_sync(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020121, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } o->obs_pad = 0; /* no filling-up of track's last 32k buffer */ } else if (d->current_profile == 0x13) { /* DVD-RW Restricted Overwrite */ + +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() */ if (o->start_byte >= 0 && (o->start_byte % 32768)) { sprintf(msg, "Write start address not properly aligned to 32K"); libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020125, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } +#endif /* ! Libburn_precheck_write_ruleS */ + ret = burn_disc_setup_dvd_minus_rw(o, disc); if (ret <= 0) { sprintf(msg, @@ -1339,7 +1404,7 @@ int burn_dvd_write_sync(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020121, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } @@ -1348,17 +1413,21 @@ int burn_dvd_write_sync(struct burn_write_opts *o, } else if (d->current_profile == 0x11 || d->current_profile == 0x14) { /* DVD-R , DVD-RW Sequential */ - o_end = burn_track_is_open_ended(disc->session[0]->track[0]); - if(o->fill_up_media) - o_end = 0; + t = disc->session[0]->track[0]; + o_end = ( burn_track_is_open_ended(t) && !o->fill_up_media ); + default_size = burn_track_get_default_size(t); + +#ifndef Libburn_precheck_write_ruleS dao_is_ok = (disc->sessions == 1 && disc->session[0]->tracks == 1 && - (!o_end) && + (default_size > 0 || !o_end) && (!o->multi) && d->status == BURN_DISC_BLANK ); if (o->write_type == BURN_WRITE_TAO && !d->current_has_feat21h) { + + /* <<< ??? keep this automatic write type change ? */ if (dao_is_ok) { o->write_type = BURN_WRITE_SAO; libdax_msgs_submit(libdax_messenger, @@ -1366,6 +1435,8 @@ int burn_dvd_write_sync(struct burn_write_opts *o, LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, "Defaulted TAO to DAO (lack of feature 21h)", 0, 0); + + /* <<< covered by burn_precheck_write() */ } else { libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020135, @@ -1374,29 +1445,49 @@ int burn_dvd_write_sync(struct burn_write_opts *o, 0, 0); goto early_failure; } + } else if (o->write_type == BURN_WRITE_SAO && !dao_is_ok) { + + /* <<< covered by burn_precheck_write() */ libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020136, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, "DAO burning is restricted to a single fixed size track and no multi-session", - 0,0); + 0, 0); + + /* <<< ??? keep this automatic advise ? */ if (d->current_has_feat21h) libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020137, LIBDAX_MSGS_SEV_HINT, LIBDAX_MSGS_PRIO_HIGH, "TAO would be possible and could do the job", - 0,0); + 0, 0); + goto early_failure; + } + + /* <<< covered by burn_precheck_write() */ if (o->start_byte >= 0) { sprintf(msg, "Write start address not supported"); libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020124, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } +#endif /* ! Libburn_precheck_write_ruleS */ + + if (o->write_type == BURN_WRITE_SAO && o_end) { + sprintf(msg, "Activated track default size %.f", + (double) default_size); + libdax_msgs_submit(libdax_messenger, + d->global_index, 0x0002012e, + LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, + msg, 0, 0); + burn_track_set_size(t, default_size); + } ret = burn_disc_setup_dvd_minus_r(o, disc); if (ret <= 0) { sprintf(msg, @@ -1404,20 +1495,24 @@ int burn_dvd_write_sync(struct burn_write_opts *o, libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020121, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; } /* ??? padding needed ??? cowardly doing it for now */ o->obs_pad = 1; /* fill-up track's last 32k buffer */ +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() */ } else { sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", d->current_profile, d->current_profile_text); libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002011e, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto early_failure; +#endif /* ! Libburn_precheck_write_ruleS */ + } o->obs = 32*1024; /* buffer flush trigger for sector.c:get_sector() */ @@ -1459,8 +1554,9 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc) struct cue_sheet *sheet; struct burn_drive *d = o->drive; struct buffer buf; - struct burn_track *lt; + struct burn_track *lt, *t; int first = 1, i, ret, lba, nwa = 0; + off_t default_size; char msg[80]; /* ts A60924 : libburn/message.c gets obsoleted @@ -1483,14 +1579,56 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc) return; } +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() */ if (o->start_byte >= 0) { sprintf(msg, "Write start address not supported"); libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020124, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); goto fail_wo_sync; } +#endif /* ! Libburn_precheck_write_ruleS */ + + /* ts A70218 */ + if (o->write_type == BURN_WRITE_SAO) { + +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() "appended session" */ + if (disc->sessions > 1) { +sao_restriction_violated:; + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x0002012f, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "SAO is restricted to a single session with fixed track sizes", + 0, 0); + goto fail_wo_sync; + } +#endif /* ! Libburn_precheck_write_ruleS */ + + for (i = 0 ; i < disc->session[0]->tracks; i++) { + t = disc->session[0]->track[i]; + if (burn_track_is_open_ended(t)) { + default_size = burn_track_get_default_size(t); + +#ifndef Libburn_precheck_write_ruleS + /* <<< covered by burn_precheck_write() */ + if (default_size <= 0) + goto sao_restriction_violated; +#endif /* ! Libburn_precheck_write_ruleS */ + + sprintf(msg, + "Activated track default size %.f", + (double) default_size); + libdax_msgs_submit(libdax_messenger, + d->global_index, 0x0002012e, + LIBDAX_MSGS_SEV_NOTE, + LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0); + burn_track_set_size(t, default_size); + } + } + } burn_print(1, "sync write of %d CD sessions\n", disc->sessions); @@ -1514,7 +1652,7 @@ return crap. so we send the command, then ignore the result. libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, - msg,0,0); + msg,0, 0); /* >>> ts A70212 : CD-DAO/SAO : eventually expand size of last track to maximum */; @@ -1561,7 +1699,7 @@ return crap. so we send the command, then ignore the result. libdax_msgs_submit( libdax_messenger, d->global_index, 0x000002, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, - msg,0,0); + msg, 0, 0); } else { d->nwa = -150; diff --git a/libburn/write.h b/libburn/write.h index d2a03a0..f221326 100644 --- a/libburn/write.h +++ b/libburn/write.h @@ -15,7 +15,8 @@ int burn_sector_length(int trackmode); int burn_subcode_length(int trackmode); /* ts A61009 */ -int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc); +int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc, + int flag); void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc); int burn_write_leadin(struct burn_write_opts *o,