
/*
   cc -g -c \
      -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
      burn_wrap.c
*/
/* libburn wrappers for libisoburn 

   Copyright 2007 Thomas Schmitt, <scdbackup@gmx.net> 
*/

/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo 
#define Hardcoded_cd_rW 1
#define Hardcoded_cd_rw_c1     12999
#define Hardcoded_cd_rw_nwA   152660 
*/

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>


#ifndef Xorriso_standalonE

#include <libburn/libburn.h>

#include <libisofs/libisofs.h>

#else /* ! Xorriso_standalonE */

#include "../libisofs/libisofs.h"
#include "../libburn/libburn.h"

#endif /* Xorriso_standalonE */


#include "libisoburn.h"
#include "isoburn.h"


/* The global list of isoburn objects. Usually there is only one. */
extern struct isoburn *isoburn_list_start; /* in isoburn.c */


int isoburn_initialize(char msg[1024], int flag)
{
 int major, minor, micro, bad_match= 0;


/* First two ugly compile time checks for header version compatibility.
   If everthing matches, then they produce no C code. In case of mismatch,
   intentionally faulty C code will be inserted.
*/

#ifdef iso_lib_header_version_major
/* The minimum requirement of libisoburn towards the libisofs header
   at compile time is defined in libisoburn/libisoburn.h :
     isoburn_libisofs_req_major
     isoburn_libisofs_req_minor
     isoburn_libisofs_req_micro
   It gets compared against the version macros in libisofs/libisofs.h :
     iso_lib_header_version_major
     iso_lib_header_version_minor
     iso_lib_header_version_micro
   If the header is too old then the following code shall cause failure of
   cdrskin compilation rather than to allow production of a program with
   unpredictable bugs or memory corruption.
   The compiler messages supposed to appear in this case are:
      error: 'LIBISOFS_MISCONFIGURATION' undeclared (first use in this function)
      error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
      error: 'LIBISOFS_MISCONFIGURATION_' undeclared (first use in this function)
*/
/* The indendation is an advise of man gcc to help old compilers ignoring */
 #if isoburn_libisofs_req_major > iso_lib_header_version_major
 #define Isoburn_libisofs_dot_h_too_olD 1
 #endif
 #if isoburn_libisofs_req_major == iso_lib_header_version_major && isoburn_libisofs_req_minor > iso_lib_header_version_minor
 #define Isoburn_libisofs_dot_h_too_olD 1
 #endif
 #if isoburn_libisofs_req_minor == iso_lib_header_version_minor && isoburn_libisofs_req_micro > iso_lib_header_version_micro
 #define Isoburn_libisofs_dot_h_too_olD 1
 #endif

#ifdef Isoburn_libisofs_dot_h_too_olD
LIBISOFS_MISCONFIGURATION = 0;
INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
LIBISOFS_MISCONFIGURATION_ = 0;
#endif

#endif /* iso_lib_header_version_major */

/* The minimum requirement of libisoburn towards the libburn header
   at compile time is defined in libisoburn/libisoburn.h :
     isoburn_libburn_req_major
     isoburn_libburn_req_minor
     isoburn_libburn_req_micro
   It gets compared against the version macros in libburn/libburn.h :
     burn_header_version_major
     burn_header_version_minor
     burn_header_version_micro
   If the header is too old then the following code shall cause failure of
   cdrskin compilation rather than to allow production of a program with
   unpredictable bugs or memory corruption.
   The compiler messages supposed to appear in this case are:
      error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function)
      error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
      error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function)
*/

/* The indendation is an advise of man gcc to help old compilers ignoring */
 #if isoburn_libburn_req_major > burn_header_version_major
 #define Isoburn_libburn_dot_h_too_olD 1
 #endif
 #if isoburn_libburn_req_major == burn_header_version_major && isoburn_libburn_req_minor > burn_header_version_minor
 #define Isoburn_libburn_dot_h_too_olD 1
 #endif
 #if isoburn_libburn_req_minor == burn_header_version_minor && isoburn_libburn_req_micro > burn_header_version_micro
 #define Isoburn_libburn_dot_h_too_olD 1
 #endif

#ifdef Isoburn_libburn_dot_h_too_olD
LIBBURN_MISCONFIGURATION = 0;
INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
LIBBURN_MISCONFIGURATION_ = 0;
#endif

/* End of ugly compile time tests (scroll up for explanation) */



 msg[0]= 0;
 if(iso_init()<0) {
   sprintf(msg+strlen(msg), "Cannot initialize libisofs\n");
   return(0);
 }
 iso_lib_version(&major, &minor, &micro);
 sprintf(msg+strlen(msg), "libisofs-%d.%d.%d ", major, minor, micro);
#ifdef iso_lib_header_version_major
 if(iso_lib_is_compatible(iso_lib_header_version_major,
                          iso_lib_header_version_minor,
                          iso_lib_header_version_micro)) {
   sprintf(msg+strlen(msg), "ok, ");
 } else {
   sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
           iso_lib_header_version_major, iso_lib_header_version_minor,
           iso_lib_header_version_micro);
   bad_match= 1;
 }
#else
 if(iso_lib_is_compatible(isoburn_libisofs_req_major,
                          isoburn_libisofs_req_minor,
                          isoburn_libisofs_req_micro)) {
   sprintf(msg+strlen(msg), "suspicious, ");
 } else {
   sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
           isoburn_libisofs_req_major, isoburn_libisofs_req_minor,
           isoburn_libisofs_req_micro);
   bad_match= 1;
 }
#endif /* ! iso_lib_header_version_major */

 if(!burn_initialize()) {
   sprintf(msg+strlen(msg), "Cannot initialize libburn\n");
   return(0);
 }
 burn_version(&major, &minor, &micro);
 sprintf(msg+strlen(msg), "libburn-%d.%d.%d ", major, minor, micro);
 if(major > burn_header_version_major
    || (major == burn_header_version_major
        && (minor > burn_header_version_minor
            || (minor == burn_header_version_minor
                && micro >= burn_header_version_micro)))) {
   sprintf(msg+strlen(msg), "ok, ");
 } else {
   sprintf(msg+strlen(msg), "- TOO OLD -, need at least libburn-%d.%d.%d ,\n",
           burn_header_version_major, burn_header_version_minor,
           burn_header_version_micro);
   bad_match= 1;
 }

 isoburn_version(&major, &minor, &micro);
 sprintf(msg+strlen(msg), "for libisoburn-%d.%d.%d", major, minor, micro);
 if(bad_match)
   return(0);

 isoburn_destroy_all(&isoburn_list_start, 0); /* isoburn_list_start= NULL */
 return(1);
}


/* API @since 0.1.0 */
int isoburn_libisofs_req(int *major, int *minor, int *micro)
{
 *major= iso_lib_header_version_major;
 *minor= iso_lib_header_version_minor;
 *micro= iso_lib_header_version_micro;
 return(1);
}


/* API @since 0.1.0 */
int isoburn_libburn_req(int *major, int *minor, int *micro)
{
 *major= burn_header_version_major;
 *minor= burn_header_version_minor;
 *micro= burn_header_version_micro;
 return(1);
}


/** Examine the media and sets appropriate emulation if needed.
    @param flag bit0= pretent blank on overwriteable media
*/ 
static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d,
                                 int flag)
{
 int ret, lba, nwa;
 struct burn_multi_caps *caps= NULL;

 ret= burn_disc_get_multi_caps(d, BURN_WRITE_NONE, &caps, 0);
 if(ret<0) /* == 0 is read-only media, but it is too early to reject it here */
   goto ex;
 ret= isoburn_new(o, 0);
 if(ret<=0)
   goto ex;
 (*o)->drive= d;

#ifdef Hardcoded_cd_rW
 /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
 caps->start_adr= 0;
 (*o)->fabricated_disc_status= BURN_DISC_APPENDABLE;
#endif

 if(caps->start_adr) {         /* set emulation to overwriteable */
   (*o)->emulation_mode= 1;

   if(flag&1) {
     (*o)->nwa= 0;
     (*o)->fabricated_disc_status= BURN_DISC_BLANK;
   } else {
     ret= isoburn_start_emulation(*o, 0);
     if(ret<=0) {
       (*o)->emulation_mode= -1;
       goto ex;
     }
   }
 } else {

   /* >>> recognize unsuitable media (but allow read-only media) */;

#ifdef Hardcoded_cd_rW
   (*o)->nwa= Hardcoded_cd_rw_nwA;
#else
   ret= burn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa);
   if(ret>0)
     (*o)->nwa= nwa;
#endif

 }
 ret= 1;
ex:
 if(caps!=NULL)
   burn_disc_free_multi_caps(&caps);
 return(ret);
}


/**
    @param flag bit0= load
                bit1= regard overwriteable media as blank
                bit2= if the drive is a regular disk file: truncate it to
                      the write start address
*/
int isoburn_drive_aquire(struct burn_drive_info *drive_infos[],
                         char *adr, int flag)
{
 int ret, conv_ret, drive_grabbed= 0;
 char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
 struct isoburn *o= NULL;
 char msg[BURN_MSGS_MESSAGE_LEN+4096];

 conv_ret= burn_drive_convert_fs_adr(adr, libburn_drive_adr);
 if(conv_ret<=0) {
   sprintf(msg, "Unsuitable drive address: '%s'\n",adr);
   msg[BURN_MSGS_MESSAGE_LEN-1]= 0;
   burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL);
   ret= 0; goto ex;
 }

 ret= burn_drive_scan_and_grab(drive_infos, libburn_drive_adr, flag&1);
 if(ret<=0)
   goto ex;
 drive_grabbed= 1;
 ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive, !!(flag&2));
 if(ret<=0)
   goto ex;

 if(flag&4) {
   ret= isoburn_find_emulator(&o, (*drive_infos)[0].drive, 0);
   if(ret>0 && o!=NULL)
     o->truncate= 1;
 }

 ret= 1;
ex:
 if(ret<=0) {
   if(drive_grabbed)
     burn_drive_release((*drive_infos)[0].drive, 0);
   isoburn_destroy(&o, 0);
 }
 return(ret);
}


int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[],
                                char *adr, int load)
{
 int ret;

 ret= isoburn_drive_aquire(drive_infos, adr, !!load);
 return(ret);
}


int isoburn_drive_grab(struct burn_drive *drive, int load)
{
 int ret;
 struct isoburn *o= NULL;

 ret= burn_drive_grab(drive, load);
 if(ret<=0)
   goto ex;
 ret= isoburn_welcome_media(&o, drive, 0);
 if(ret<=0)
   goto ex;
 
 ret= 1;
ex:
 if(ret<=0)
   isoburn_destroy(&o,0);
 return(ret);
}


/** Retrieve media emulation and eventual isoburn emulator of drive.
    @return -1 unsuitable media, 0 generic media, 1 emulated media.
*/
int isoburn_find_emulator(struct isoburn **pt,
                                 struct burn_drive *drive, int flag)
{
 int ret;

 ret= isoburn_find_by_drive(pt, drive, 0);
 if(ret<=0)
   return(0);
 if((*pt)->emulation_mode==-1) {
   burn_msgs_submit(0x00060000,
                    "Unsuitable drive and media state", 0, "FAILURE", NULL);
   return(-1);
 }
 if((*pt)->emulation_mode==0)
   return(0);
 return(1);
} 


enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive)
{
 int ret;
 struct isoburn *o;

 ret= isoburn_find_emulator(&o, drive, 0);
 if(ret<0)
   return(BURN_DISC_UNSUITABLE);
 if(o!=NULL)
   if(o->fabricated_disc_status!=BURN_DISC_UNREADY)
     return(o->fabricated_disc_status);
 if(ret==0)
   return(burn_disc_get_status(drive));

 /* emulated status */
 if(o->emulation_mode==-1)
   return(BURN_DISC_UNSUITABLE);
 if(o->nwa>0)
   return(BURN_DISC_APPENDABLE);
 return(BURN_DISC_BLANK);
}


int isoburn_disc_erasable(struct burn_drive *d)
{
 int ret;
 struct isoburn *o;

 ret= isoburn_find_emulator(&o, d, 0);
 if(ret>0)
   if(o->emulation_mode==1)
     return(1);
 return burn_disc_erasable(d);
}


void isoburn_disc_erase(struct burn_drive *drive, int fast)
{
 int ret;
 struct isoburn *o;

 ret= isoburn_find_emulator(&o, drive, 0);
 if(ret>0) {
   if(o->emulation_mode==-1) {
     /* To cause a negative reply with burn_drive_wrote_well() */
     burn_drive_cancel(drive);
     return;
   }
   if(o->emulation_mode>0) {
     ret= isoburn_invalidate_iso(o, 0);
     if(ret<=0)
       burn_drive_cancel(drive);
     return;
   }
 }
 burn_disc_erase(drive, fast);
}


off_t isoburn_disc_available_space(struct burn_drive *d,
                                   struct burn_write_opts *opts)
{
 int ret;
 struct isoburn *o;
 struct burn_write_opts *eff_opts= NULL, *local_opts= NULL;
 off_t avail;

 eff_opts= opts;
 ret= isoburn_find_emulator(&o, d, 0);
 if(ret>0 && o!=NULL)
   if(o->emulation_mode!=0) {
     local_opts= burn_write_opts_new(d);
     eff_opts= local_opts;
     burn_write_opts_set_start_byte(eff_opts, ((off_t) o->nwa) * (off_t) 2048);
   }
 avail= burn_disc_available_space(d, eff_opts);
 if(local_opts!=NULL)
   burn_write_opts_free(local_opts);
 local_opts= NULL;
 return(avail);
}


int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba)
{
 int ret;
 struct isoburn *o;

#ifdef Hardcoded_cd_rW
 /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
 *start_lba= Hardcoded_cd_rw_c1;
 return(1);
#endif

 if(isoburn_disc_get_status(d)!=BURN_DISC_APPENDABLE &&
    isoburn_disc_get_status(d)!=BURN_DISC_FULL) {
   burn_msgs_submit(0x00060000,
                    "Media contains no recognizable data", 0, "SORRY",NULL);
   return(0);
 }
 ret= isoburn_find_emulator(&o, d, 0);
 if(ret<0)
   return(0);
 if(ret>0) if(o->emulation_mode>0) {
   *start_lba= 0;
   return(1);
 }
 return(burn_disc_get_msc1(d, start_lba));
}


int isoburn_disc_track_lba_nwa(struct burn_drive *d,
                               struct burn_write_opts *opts,
                               int trackno, int *lba, int *nwa)
{
 int ret;
 struct isoburn *o;

#ifdef Hardcoded_cd_rW
 /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
 *lba= Hardcoded_cd_rw_c1;
 *nwa= Hardcoded_cd_rw_nwA;
 return(1);
#endif

 *nwa= *lba= 0;
 ret= isoburn_find_emulator(&o, d, 0);
 if(ret<0)
   return(0);
 if(ret>0) if(o->emulation_mode>0) {
   *lba= 0;
   *nwa= o->nwa;
   return(1);
 }
 if(burn_drive_get_drive_role(d) != 1)
   return(1);
 return(burn_disc_track_lba_nwa(d, opts, trackno, lba, nwa));
}


void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
{
 int ret;
 off_t nwa= 0;
 struct isoburn *o;
 struct burn_drive *drive;
 char reasons[BURN_REASONS_LEN],msg[160+BURN_REASONS_LEN];
 char adr[BURN_DRIVE_ADR_LEN];
 enum burn_write_types write_type;
 struct stat stbuf;

 drive= burn_write_opts_get_drive(opts);
 ret= isoburn_find_emulator(&o, drive, 0);
 if(ret<0)
   return;
 if(o!=NULL) {
   o->wrote_well= -1;
   if(o->emulation_mode!=0) {
     burn_write_opts_set_multi(opts, 0);
     if(o->emulation_mode>0 && o->nwa >= 0) {
       burn_write_opts_set_start_byte(opts, ((off_t) o->nwa) * (off_t) 2048);
       nwa= o->nwa;
     }
   }
 }

 write_type= burn_write_opts_auto_write_type(opts, disc, reasons, 0);
 if (write_type == BURN_WRITE_NONE) {
    sprintf(msg, "Failed to find a suitable write mode:\n%s", reasons);
    burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL);
    if(o!=NULL)
      o->wrote_well= 0;
    /* To cause a negative reply with burn_drive_wrote_well() */
    burn_drive_cancel(drive);
    return;
 }

/*
 sprintf(reasons, "%d", (int) write_type);
 fprintf(stderr, "isoburn_EXPERIMENTAL: write_type = %s\n",
                 (write_type == BURN_WRITE_SAO ? "SAO" :
                 (write_type == BURN_WRITE_TAO ? "TAO" : reasons)));
*/

#ifdef Hardcoded_cd_rW
 /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
 fprintf(stderr, "Setting write address to LBA %d\n", Hardcoded_cd_rw_nwA);
 burn_write_opts_set_start_byte(opts,
				 ((off_t) Hardcoded_cd_rw_nwA) * (off_t) 2048);
#endif

 if(o->truncate) {
   ret= burn_drive_get_drive_role(drive);
   if(ret==2) {
     ret= burn_drive_d_get_adr(drive, adr);
     if(ret>0) {
       ret= lstat(adr, &stbuf);
       if(ret!=-1)
         if(S_ISREG(stbuf.st_mode))
           truncate(adr, nwa * (off_t) 2048);
     }
   }
 }

 burn_disc_write(opts, disc);
}


void isoburn_drive_release(struct burn_drive *drive, int eject)
{
 int ret;
 struct isoburn *o;

 ret= isoburn_find_emulator(&o, drive, 0);
 if(ret<0)
   return;
 if(o!=NULL) {
   isoburn_destroy(&o, 0);
 }
 burn_drive_release(drive, eject);
}


void isoburn_finish(void)
{
 isoburn_destroy_all(&isoburn_list_start, 0);
 burn_finish();
 iso_finish();
}


int isoburn_needs_emulation(struct burn_drive *drive)
{
 int ret;
 struct isoburn *o;
 enum burn_disc_status s;

 s= isoburn_disc_get_status(drive);
 if(s!=BURN_DISC_BLANK && s!=BURN_DISC_APPENDABLE)
   return(-1);
 ret= isoburn_find_emulator(&o, drive, 0);
 if(ret<0)
   return(-1);
 if(ret>0)
   if(o->emulation_mode>0)
     return(1);
 return(0);  
}


int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag)
{
 int ret;
 struct burn_drive *drive = o->drive;
 struct burn_multi_caps *caps= NULL;
 
 ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
 if(ret<=0)
   goto ex;
 if(!caps->start_adr) {
   burn_msgs_submit(0x00060000,
                    "Cannot set start byte address with this type of media",
                    0, "FAILURE", NULL);
   {ret= 0; goto ex;}
 }
 o->min_start_byte= value;
 if(value % caps->start_alignment)
   value+= caps->start_alignment - (value % caps->start_alignment);
 o->nwa= value/2048;
 /* If suitable for alignment, round up to full 16 sector addresses */
 if((o->nwa%16) && ((16*2048) % caps->start_alignment)==0 )
   o->nwa+= 16 - (o->nwa%16);
 ret= 1;
ex:
 if(caps!=NULL)
   burn_disc_free_multi_caps(&caps);
 return(ret);
}


int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
                               int flag)
{
 int ret;
 struct isoburn *o;

 ret= isoburn_find_emulator(&o, d, 0);
 if(ret<0)
   return(-1);
 if(ret==0) 
   return(0);
 *start_byte= o->min_start_byte;
 if(o->min_start_byte<=0)
   return(0);
 return(1);
}


int isoburn_drive_wrote_well(struct burn_drive *d)
{
 int ret;
 struct isoburn *o;
 
 ret= isoburn_find_emulator(&o, d, 0);
 if(ret<0)
   return(-1);
 if(o!=NULL)
   if(o->wrote_well>=0)
     return(o->wrote_well);
 ret= burn_drive_wrote_well(d);
 return ret;
}


int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes,
			    char **status_text)
{
 int ret;
 struct isoburn *o;
#ifdef Libisoburn_no_fifO
 size_t hsize= 0, hfree_bytes= 0;
#endif

 ret= isoburn_find_emulator(&o, d, 0);
 if(ret<0)
   return(-1);

#ifdef Libisoburn_no_fifO
 if(o==NULL)
   return(-1);
 if(o->iso_source==NULL)
   return(-1);
 ret= iso_ring_buffer_get_status(o->iso_source, &hsize, &hfree_bytes);
 if(hsize > 1024*1024*1024)
   *size= 1024*1024*1024;
 else
   *size= hsize;
 if(hfree_bytes > 1024*1024*1024)
   *free_bytes= 1024*1024*1024;
 else
   *free_bytes= hfree_bytes;
 *status_text= "";
 if(ret==0)
   *status_text= "standby";
 else if(ret==1)
   *status_text= "active";
 else if(ret==2)
   *status_text= "ending";
 else if(ret==3)
   *status_text= "failing";
 else if(ret==4)
   *status_text= "unused";
 else if(ret==5)
   *status_text= "abandoned";
 else if(ret==6)
   *status_text= "ended";
 else if(ret==7)
   *status_text= "aborted";
#else
 if(o==NULL)
   return(0);
 if(o->fifo==NULL)
   return(0);
 ret= burn_fifo_inquire_status(o->fifo, size, free_bytes, status_text);
#endif /* ! Libisoburn_no_fifO */

 return(ret);
}


#define Libisoburn_on_libisofs_after_0_6_2  yes

/* >>> todo: throw out the copies of libdax_msgs entrails */

/* <<< to be replaced by libburn-0.4.3 API call burn_sev_to_text().
   This is a copy of libdax_msgs__sev_to_text() which is not exposed
   by the API of of libburn-0.4.2 . As soon as xorriso gets based on
   libburn-0.4.4 this redundancy is to be removed.
   It is safe, nevertheless, because the severity codes are eternal.
*/
#define LIBDAX_MSGS_SEV_ALL                                          0x00000000
#define LIBDAX_MSGS_SEV_ERRFILE                                      0x08000000
#define LIBDAX_MSGS_SEV_DEBUG                                        0x10000000
#define LIBDAX_MSGS_SEV_UPDATE                                       0x20000000
#define LIBDAX_MSGS_SEV_NOTE                                         0x30000000
#define LIBDAX_MSGS_SEV_HINT                                         0x40000000
#define LIBDAX_MSGS_SEV_WARNING                                      0x50000000
#define LIBDAX_MSGS_SEV_SORRY                                        0x60000000
#define LIBDAX_MSGS_SEV_MISHAP                                       0x64000000
#define LIBDAX_MSGS_SEV_FAILURE                                      0x68000000
#define LIBDAX_MSGS_SEV_FATAL                                        0x70000000
#define LIBDAX_MSGS_SEV_ABORT                                        0x71000000
#define LIBDAX_MSGS_SEV_NEVER                                        0x7fffffff

/* @param flag bit0= -reserved-
               bit1= this is a libburn severity
*/
int isoburn__sev_to_text(int severity, char **severity_name,
                         int flag)
{
#ifdef Libisoburn_on_libisofs_after_0_6_2
 int ret;
#else
#ifdef Libisoburn_on__libburn_after_0_4_2
 int ret;
#endif
#endif
   
#ifdef Libisoburn_on_libisofs_after_0_6_2
  ret= iso_sev_to_text(severity, severity_name);
  if(ret>0)
    return(ret);
#endif /*  Libisoburn_on_libisofs_after_0_6_2 */
#ifdef Libisoburn_on__libburn_after_0_4_2
  ret= burn_sev_to_text(severity, severity_name, 0);
  if(ret>0)
    return(ret);
#endif

 if(flag&1) {
   *severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
   return(1);
 }
 *severity_name= "";
 if(severity>=LIBDAX_MSGS_SEV_NEVER)
   *severity_name= "NEVER";
 else if(severity>=LIBDAX_MSGS_SEV_ABORT)
   *severity_name= "ABORT";
 else if(severity>=LIBDAX_MSGS_SEV_FATAL)
   *severity_name= "FATAL";
 else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
   *severity_name= "FAILURE";
 else if(severity>=LIBDAX_MSGS_SEV_MISHAP)
   *severity_name= "MISHAP";
 else if(severity>=LIBDAX_MSGS_SEV_SORRY)
   *severity_name= "SORRY";
 else if(severity>=LIBDAX_MSGS_SEV_WARNING)
   *severity_name= "WARNING";
 else if(severity>=LIBDAX_MSGS_SEV_HINT)
   *severity_name= "HINT";
 else if(severity>=LIBDAX_MSGS_SEV_NOTE)
   *severity_name= "NOTE";
 else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
   *severity_name= "UPDATE";
 else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
   *severity_name= "DEBUG";
 else if(severity>=LIBDAX_MSGS_SEV_ERRFILE)
   *severity_name= "ERRFILE";
 else if(severity>=LIBDAX_MSGS_SEV_ALL)
   *severity_name= "ALL";
 else {
   *severity_name= "";
   return(0);
 }
 return(1);
}


int isoburn__text_to_sev(char *severity_name, int *severity_number, int flag)
{
 int ret= 1;

#ifdef Libisoburn_on_libisofs_after_0_6_2
  ret= iso_text_to_sev(severity_name, severity_number);
  if(ret>0)
    return(ret);
#endif /*  Libisoburn_on_libisofs_after_0_6_2 */

#ifndef Libisoburn_on__libburn_after_0_4_2
 if(severity_name[0]==0)
   *severity_number= 0;
 else if(strcmp(severity_name, "MISHAP")==0)
   *severity_number= LIBDAX_MSGS_SEV_MISHAP;
 else if(strcmp(severity_name, "ERRFILE")==0)
   *severity_number= LIBDAX_MSGS_SEV_ERRFILE;
 else
#endif /* ! Libisoburn_on__libburn_after_0_4_2 */

   ret= burn_text_to_sev(severity_name, severity_number, 0);
 return(ret);
}


int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno,
                             char min_severity[], int flag)
{
 int error_code, iso_sev, min_sev, ret;
 char *sev_text_pt, *msg_text_pt= NULL;

 error_code= iso_error_get_code(iso_error_code);
 if(error_code < 0x00030000 || error_code >= 0x00040000)
   error_code= (error_code & 0xffff) | 0x00050000;

 if(iso_error_code<0)
   msg_text_pt= (char *) iso_error_to_msg(iso_error_code);
 if(msg_text_pt==NULL)
   msg_text_pt= msg_text;
 iso_sev= iso_error_get_severity(iso_error_code);
 sev_text_pt= min_severity;

#ifdef Libisoburn_on_libisofs_after_0_6_2

 isoburn__text_to_sev(min_severity, &min_sev, 0);
 if(min_sev < iso_sev) 
   isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
 ret= iso_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, 0);

#else

 burn_text_to_sev(min_severity, &min_sev, 0);

 /* <<< Tunnel MISHAP through libburn which knows no MISHAP
        with libburn-0.4.4 this is not necessary */
 if(iso_sev==LIBDAX_MSGS_SEV_MISHAP) {
   iso_sev= LIBDAX_MSGS_SEV_SORRY;
   error_code= 0x0005ff73;
 } else if(iso_sev==LIBDAX_MSGS_SEV_ERRFILE) { /* same with ERRFILE */
   iso_sev= LIBDAX_MSGS_SEV_DEBUG;
   error_code= 0x00051001;
 }
 if(min_sev < iso_sev)
   isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
 ret= burn_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, NULL);

#endif /* ! Libisoburn_on_libisofs_after_0_6_2 */

 return(ret);
}

