Exemple #1
0
/*!
  Seek to a position i_start and then read i_blocks. Number of blocks read is
  returned. One normally expects the return to be equal to i_blocks.
*/
driver_return_code_t
udf_read_sectors (const udf_t *p_udf, void *ptr, lsn_t i_start,
		 long i_blocks)
{
  driver_return_code_t ret;
  long i_read;
  off_t i_byte_offset;

  if (!p_udf) return 0;
  /* Without the cast, i_start * UDF_BLOCKSIZE may be evaluated as 32 bit */
  i_byte_offset = ((off_t)i_start) * UDF_BLOCKSIZE;
  /* Since we're using SEEK_SET, the value must be positive */
  if (i_byte_offset < 0) {
    if (sizeof(off_t) <= 4)	/* probably missing LFS */
      cdio_warn("Large File Support is required to access streams of 2 GB or more");
    return DRIVER_OP_BAD_PARAMETER;
  }

  if (p_udf->b_stream) {
    ret = cdio_stream_seek (p_udf->stream, i_byte_offset, SEEK_SET);
    if (DRIVER_OP_SUCCESS != ret) return ret;
    i_read = cdio_stream_read (p_udf->stream, ptr, UDF_BLOCKSIZE, i_blocks);
    if (i_read) return DRIVER_OP_SUCCESS;
    return DRIVER_OP_ERROR;
  } else {
    return cdio_read_data_sectors(p_udf->cdio, ptr, i_start, UDF_BLOCKSIZE,
				  i_blocks);
  }
}
Exemple #2
0
/*!
  Reads into buf the next size bytes.
  Returns -1 on error.
  FIXME:
   At present we assume a read doesn't cross sector or track
   boundaries.
*/
static ssize_t
_read_cdrdao (void *user_data, void *data, size_t size)
{
  _img_private_t *env = user_data;
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
  char *p = data;
  ssize_t final_size=0;
  ssize_t this_size;
  track_info_t  *this_track=&(env->tocent[env->pos.index]);
  ssize_t skip_size = this_track->datastart + this_track->endsize;

  while (size > 0) {
    int rem = (int) (this_track->datasize - env->pos.buff_offset);
    if (size <= rem) {
      this_size = cdio_stream_read(this_track->data_source, buf, size, 1);
      final_size += this_size;
      memcpy (p, buf, this_size);
      break;
    }

    /* Finish off reading this sector. */
    cdio_warn ("Reading across block boundaries not finished");

    size -= rem;
    this_size = cdio_stream_read(this_track->data_source, buf, rem, 1);
    final_size += this_size;
    memcpy (p, buf, this_size);
    p += this_size;
    this_size = cdio_stream_read(this_track->data_source, buf, rem, 1);

    /* Skip over stuff at end of this sector and the beginning of the next.
     */
    cdio_stream_read(this_track->data_source, buf, skip_size, 1);

    /* Get ready to read another sector. */
    env->pos.buff_offset=0;
    env->pos.lba++;

    /* Have gone into next track. */
    if (env->pos.lba >= env->tocent[env->pos.index+1].start_lba) {
      env->pos.index++;
      this_track=&(env->tocent[env->pos.index]);
      skip_size = this_track->datastart + this_track->endsize;
    }
  }
  return final_size;
}
Exemple #3
0
/* Adjust the p_iso's i_datastart, i_byte_offset and i_framesize
   based on whether we find a frame header or not.
*/
static void
adjust_fuzzy_pvd( iso9660_t *p_iso )
{
  long int i_byte_offset;

  if (!p_iso) return;

  i_byte_offset = (ISO_PVD_SECTOR * p_iso->i_framesize)
    + p_iso->i_fuzzy_offset + p_iso->i_datastart;

  /* If we have a raw 2352-byte frame then we should expect to see a sync
     frame and a header.
   */
  if (CDIO_CD_FRAMESIZE_RAW == p_iso->i_framesize) {
    char buf[CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE];

    i_byte_offset -= CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;

    if ( DRIVER_OP_SUCCESS != cdio_stream_seek (p_iso->stream, i_byte_offset,
						SEEK_SET) )
      return;
    if (sizeof(buf) == cdio_stream_read (p_iso->stream, buf, sizeof(buf), 1)) {
      /* Does the sector frame header suggest Mode 1 format? */
      if (!memcmp(CDIO_SECTOR_SYNC_HEADER, buf+CDIO_CD_SUBHEADER_SIZE,
		  CDIO_CD_SYNC_SIZE)) {
	if (buf[14+CDIO_CD_SUBHEADER_SIZE] != 0x16) {
	  cdio_warn ("Expecting the PVD sector header MSF to be 0x16, is: %x",
		     buf[14]);
	}
	if (buf[15+CDIO_CD_SUBHEADER_SIZE] != 0x1) {
	  cdio_warn ("Expecting the PVD sector mode to be Mode 1 is: %x",
		     buf[15]);
	}
	p_iso->b_mode2 = nope;
	p_iso->b_xa = nope;
      } else if (!memcmp(CDIO_SECTOR_SYNC_HEADER, buf, CDIO_CD_SYNC_SIZE)) {
	/* Frame header indicates Mode 2 Form 1*/
	if (buf[14] != 0x16) {
	  cdio_warn ("Expecting the PVD sector header MSF to be 0x16, is: %x",
		     buf[14]);
	}
	if (buf[15] != 0x2) {
	  cdio_warn ("Expecting the PVD sector mode to be Mode 2 is: %x",
		     buf[15]);
	}
	p_iso->b_mode2 = yep;
	/* Do do: check Mode 2 Form 2? */
      } else {
	  /* Has no frame header */
	  p_iso->i_framesize = M2RAW_SECTOR_SIZE;
	  p_iso->i_fuzzy_offset = (CDIO_CD_FRAMESIZE_RAW - M2RAW_SECTOR_SIZE)
	    * ISO_PVD_SECTOR + p_iso->i_fuzzy_offset + p_iso->i_datastart;
	  p_iso->i_datastart = 0;
	}
    }
  }


}
Exemple #4
0
/*!
  Seek to a position and then read n blocks. Size read is returned.
*/
long int 
iso9660_iso_seek_read (const iso9660_t *p_iso, void *ptr, lsn_t start, 
		       long int size)
{
  long int ret;
  if (NULL == p_iso) return 0;
  ret = cdio_stream_seek (p_iso->stream, start * ISO_BLOCKSIZE, SEEK_SET);
  if (ret!=0) return 0;
  return cdio_stream_read (p_iso->stream, ptr, ISO_BLOCKSIZE, size);
}
Exemple #5
0
/*!
  Seek to a position and then read n blocks. Size read is returned.
*/
static long int 
iso9660_seek_read_framesize (const iso9660_t *p_iso, void *ptr, 
			     lsn_t start, long int size, 
			     uint16_t i_framesize)
{
  long int ret;
  long int i_byte_offset;
  
  if (!p_iso) return 0;
  i_byte_offset = (start * p_iso->i_framesize) + p_iso->i_fuzzy_offset 
    + p_iso->i_datastart;

  ret = cdio_stream_seek (p_iso->stream, i_byte_offset, SEEK_SET);
  if (ret!=0) return 0;
  return cdio_stream_read (p_iso->stream, ptr, i_framesize, size);
}
Exemple #6
0
/*!
   Reads a single audio sector from CD device into data starting
   from lsn. Returns 0 if no error.
 */
static driver_return_code_t
_read_audio_sectors_cdrdao (void *user_data, void *data, lsn_t lsn,
			  unsigned int nblocks)
{
  _img_private_t *env = user_data;
  int ret;

  ret = cdio_stream_seek (env->tocent[0].data_source,
            lsn * CDIO_CD_FRAMESIZE_RAW, SEEK_SET);
  if (ret!=0) return ret;

  ret = cdio_stream_read (env->tocent[0].data_source, data,
            CDIO_CD_FRAMESIZE_RAW, nblocks);

  /* ret is number of bytes if okay, but we need to return 0 okay. */
  return ret == 0;
}
Exemple #7
0
/*!
   Reads a single mode2 sector from cd device into data starting
   from lsn. Returns 0 if no error.
 */
static driver_return_code_t
_read_mode1_sector_cdrdao (void *user_data, void *data, lsn_t lsn,
			 bool b_form2)
{
  _img_private_t *env = user_data;
  int ret;
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };

  ret = cdio_stream_seek (env->tocent[0].data_source,
			  lsn * CDIO_CD_FRAMESIZE_RAW, SEEK_SET);
  if (ret!=0) return ret;

  /* FIXME: Not completely sure the below is correct. */
  ret = cdio_stream_read (env->tocent[0].data_source, buf,
			  CDIO_CD_FRAMESIZE_RAW, 1);
  if (ret==0) return ret;

  memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE,
	  b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);

  return DRIVER_OP_SUCCESS;
}
Exemple #8
0
/*!
  Seek to a position i_start and then read i_blocks. Number of blocks read is 
  returned. One normally expects the return to be equal to i_blocks.
*/
driver_return_code_t
udf_read_sectors (const udf_t *p_udf, void *ptr, lsn_t i_start, 
		 long int i_blocks) 
{
  driver_return_code_t ret;
  long int i_read;
  long int i_byte_offset;
  
  if (!p_udf) return 0;
  i_byte_offset = (i_start * UDF_BLOCKSIZE);

  if (p_udf->b_stream) {
    ret = cdio_stream_seek (p_udf->stream, i_byte_offset, SEEK_SET);
    if (DRIVER_OP_SUCCESS != ret) return ret;
    i_read = cdio_stream_read (p_udf->stream, ptr, UDF_BLOCKSIZE, i_blocks);
    if (i_read) return DRIVER_OP_SUCCESS;
    return DRIVER_OP_ERROR;
  } else {
    return cdio_read_data_sectors(p_udf->cdio, ptr, i_start, UDF_BLOCKSIZE,
				  i_blocks);
  }
}
Exemple #9
0
/*!
   Reads a single mode1 sector from cd device into data starting
   from lsn. Returns 0 if no error.
 */
static driver_return_code_t
_read_mode2_sector_cdrdao (void *user_data, void *data, lsn_t lsn,
			 bool b_form2)
{
  _img_private_t *env = user_data;
  int ret;
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
  long unsigned int i_off = lsn * CDIO_CD_FRAMESIZE_RAW;

  /* For sms's VCD's (mwc1.toc) it is more like this:
     if (i_off > 272) i_off -= 272;
     There is that magic 272 that we find in read_audio_sectors_cdrdao again.
  */

  /* NOTE: The logic below seems a bit wrong and convoluted
     to me, but passes the regression tests. (Perhaps it is why we get
     valgrind errors in vcdxrip). Leave it the way it was for now.
     Review this sector 2336 stuff later.
  */

  ret = cdio_stream_seek (env->tocent[0].data_source, i_off, SEEK_SET);
  if (ret!=0) return ret;

  ret = cdio_stream_read (env->tocent[0].data_source, buf,
			  CDIO_CD_FRAMESIZE_RAW, 1);
  if (ret==0) return ret;


  /* See NOTE above. */
  if (b_form2)
    memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE,
	    M2RAW_SECTOR_SIZE);
  else
    memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, CDIO_CD_FRAMESIZE);

  return DRIVER_OP_SUCCESS;
}
Exemple #10
0
/* 
   Disk and track information for a Nero file are located at the end
   of the file. This routine extracts that information.

   FIXME: right now psz_nrg_name is not used. It will be in the future.
 */
static bool
parse_nrg (_img_private_t *p_env, const char *psz_nrg_name, 
	   const cdio_log_level_t log_level)
{
  off_t footer_start;
  off_t size;
  char *footer_buf = NULL;
  if (!p_env) return false;
  size = cdio_stream_stat (p_env->gen.data_source);
  if (-1 == size) return false;

  {
    _footer_t buf;
    cdio_assert (sizeof (buf) == 12);
 
    cdio_stream_seek (p_env->gen.data_source, size - sizeof (buf), SEEK_SET);
    cdio_stream_read (p_env->gen.data_source, (void *) &buf, sizeof (buf), 1);
    
    if (buf.v50.ID == UINT32_TO_BE (NERO_ID)) {
      cdio_debug ("detected Nero version 5.0 (32-bit offsets) NRG magic");
      footer_start = uint32_to_be (buf.v50.footer_ofs); 
    } else if (buf.v55.ID == UINT32_TO_BE (NER5_ID)) {
      cdio_debug ("detected Nero version 5.5.x (64-bit offsets) NRG magic");
      footer_start = uint64_from_be (buf.v55.footer_ofs);
    } else {
      cdio_log (log_level, "Image not recognized as either version 5.0 or "
		"version 5.5.x-6.x type NRG");
      return false;
    }

    cdio_debug (".NRG footer start = %ld, length = %ld", 
	       (long) footer_start, (long) (size - footer_start));

    cdio_assert ((size - footer_start) <= 4096);

    footer_buf = calloc(1, (size_t)(size - footer_start));

    cdio_stream_seek (p_env->gen.data_source, footer_start, SEEK_SET);
    cdio_stream_read (p_env->gen.data_source, footer_buf, 
		      (size_t)(size - footer_start), 1);
  }
  {
    int pos = 0;

    while (pos < size - footer_start) {
      _chunk_t *chunk = (void *) (footer_buf + pos);
      uint32_t opcode = UINT32_FROM_BE (chunk->id);
      
      bool break_out = false;
      
      switch (opcode) {

      case CUES_ID: /* "CUES" Seems to have sector size 2336 and 150 sector
		       pregap seems to be included at beginning of image.
		       */
      case CUEX_ID: /* "CUEX" */ 
	{
	  unsigned entries = UINT32_FROM_BE (chunk->len);
	  _cuex_array_t *_entries = (void *) chunk->data;
	  
	  cdio_assert (p_env->mapping == NULL);
	  
	  cdio_assert ( sizeof (_cuex_array_t) == 8 );
	  cdio_assert ( UINT32_FROM_BE (chunk->len) % sizeof(_cuex_array_t) 
			== 0 );
	  
	  entries /= sizeof (_cuex_array_t);
	  
	  if (CUES_ID == opcode) {
	    lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn);
	    unsigned int idx;
	    unsigned int i = 0;
	    
	    cdio_debug ("CUES type image detected" );

	    /* CUES LSN has 150 pregap include at beginning? -/
	       cdio_assert (lsn == 0?);
	    */
	    
	    p_env->is_cues           = true; /* HACK alert. */
	    p_env->gen.i_tracks      = 0;
	    p_env->gen.i_first_track = 1;
	    for (idx = 1; idx < entries-1; idx += 2, i++) {
	      lsn_t sec_count;
	      int cdte_format = _entries[idx].addr_ctrl / 16;
	      int cdte_ctrl   = _entries[idx].type >> 4;

	      if ( COPY_PERMITTED & cdte_ctrl ) {
		if (p_env) p_env->tocent[i].flags |= COPY_PERMITTED;
	      } else {
		if (p_env) p_env->tocent[i].flags &= ~COPY_PERMITTED;
	      }
	      
	      if ( PRE_EMPHASIS & cdte_ctrl ) {
		if (p_env) p_env->tocent[i].flags |= PRE_EMPHASIS;
	      } else {
		if (p_env) p_env->tocent[i].flags &= ~PRE_EMPHASIS;
	      }
	      
	      if ( FOUR_CHANNEL_AUDIO & cdte_ctrl ) {
		if (p_env) p_env->tocent[i].flags |= FOUR_CHANNEL_AUDIO;
	      } else {
		if (p_env) p_env->tocent[i].flags &= ~FOUR_CHANNEL_AUDIO;
	      }
	      
	      cdio_assert (_entries[idx].track == _entries[idx + 1].track);
	      
	      /* lsn and sec_count*2 aren't correct, but it comes closer on the
		 single example I have: svcdgs.nrg
		 We are picking up the wrong fields and/or not interpreting
		 them correctly.
	      */

	      switch (cdte_format) {
	      case 0:
		lsn = UINT32_FROM_BE (_entries[idx].lsn);
		break;
	      case 1: 
		{
#if 0
		  msf_t msf = (msf_t) _entries[idx].lsn;
		  lsn = cdio_msf_to_lsn(&msf);
#else
		  lsn = CDIO_INVALID_LSN;
#endif		  
		  cdio_log (log_level, 
			    "untested (i.e. probably wrong) CUE MSF code");
		  break;
		}
	      default:
		lsn = CDIO_INVALID_LSN;
		cdio_log(log_level,
			 "unknown cdte_format %d", cdte_format);
	      }
	      
	      sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn);
	      
	      _register_mapping (p_env, lsn, sec_count*2, 
				 (lsn+CDIO_PREGAP_SECTORS) * M2RAW_SECTOR_SIZE,
				 M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true);
	    }
	  } else {
	    lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn);
	    unsigned int idx;
	    unsigned int i = 0;
	    
	    cdio_debug ("CUEX type image detected");

	    /* LSN must start at -150 (LBA 0)? */
	    cdio_assert (lsn == -150); 
	    
	    for (idx = 2; idx < entries; idx += 2, i++) {
	      lsn_t sec_count;
	      int cdte_format = _entries[idx].addr_ctrl >> 4;
	      int cdte_ctrl   = _entries[idx].type >> 4;

	      if ( COPY_PERMITTED & cdte_ctrl ) {
		if (p_env) p_env->tocent[i].flags |= COPY_PERMITTED;
	      } else {
		if (p_env) p_env->tocent[i].flags &= ~COPY_PERMITTED;
	      }
	      
	      if ( PRE_EMPHASIS & cdte_ctrl ) {
		if (p_env) p_env->tocent[i].flags |= PRE_EMPHASIS;
	      } else {
		if (p_env) p_env->tocent[i].flags &= ~PRE_EMPHASIS;
	      }
	      
	      if ( FOUR_CHANNEL_AUDIO & cdte_ctrl ) {
		if (p_env) p_env->tocent[i].flags |= FOUR_CHANNEL_AUDIO;
	      } else {
		if (p_env) p_env->tocent[i].flags &= ~FOUR_CHANNEL_AUDIO;
	      }
	      
	      /* extractnrg.pl has cdte_format for LBA's 0, and
		 for MSF 1. ???

		 FIXME: Should decode as appropriate for cdte_format.
	       */
	      cdio_assert ( cdte_format == 0 || cdte_format == 1 );

	      cdio_assert (_entries[idx].track != _entries[idx + 1].track);
	      
	      lsn       = UINT32_FROM_BE (_entries[idx].lsn);
	      sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn);
	      
	      _register_mapping (p_env, lsn, sec_count - lsn, 
				 (lsn + CDIO_PREGAP_SECTORS)*M2RAW_SECTOR_SIZE,
				 M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true);
	    }
	  }
	  break;
	}
	
      case DAOX_ID: /* "DAOX" */ 
      case DAOI_ID: /* "DAOI" */
	{
	  _daox_t *_xentries = NULL;
	  _daoi_t *_ientries = NULL;
	  _dao_array_common_t *_dao_array_common = NULL;
	  _dao_common_t *_dao_common = (void *) chunk->data;
	  int disc_mode = _dao_common->unknown[1];
	  track_format_t track_format;
	  int i;

	  /* We include an extra 0 byte so these can be used as C strings.*/
	  p_env->psz_mcn = calloc(1, CDIO_MCN_SIZE+1);
	  memcpy(p_env->psz_mcn, &(_dao_common->psz_mcn), CDIO_MCN_SIZE);
	  p_env->psz_mcn[CDIO_MCN_SIZE] = '\0';

	  if (DAOX_ID == opcode) {
	    _xentries = (void *) chunk->data;
	    p_env->dtyp = _xentries->track_info[0].common.unknown[2];
	  } else {
	    _ientries = (void *) chunk->data;
	    p_env->dtyp = _ientries->track_info[0].common.unknown[2];
	  }

	  p_env->is_dao = true;
	  cdio_debug ("DAO%c tag detected, track format %d, mode %x\n", 
		      opcode==DAOX_ID ? 'X': 'I', p_env->dtyp, disc_mode);
	  switch (p_env->dtyp) {
	  case 0:
	    /* Mode 1 */
	    track_format     = TRACK_FORMAT_DATA;
	    p_env->disc_mode = CDIO_DISC_MODE_CD_DATA;
	    break;
	  case 2:
	    /* Mode 2 form 1 */
	    disc_mode             = 0;
	    track_format     = TRACK_FORMAT_XA;
	    p_env->disc_mode = CDIO_DISC_MODE_CD_XA;
	    break;
	  case 3:
	    /* Mode 2 */
	    track_format     = TRACK_FORMAT_XA;
	    p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */
	    break;
	  case 0x6:
	    /* Mode2 form mix */
	    track_format     = TRACK_FORMAT_XA;
	    p_env->disc_mode = CDIO_DISC_MODE_CD_MIXED;
	    break;
	  case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */
	    track_format     = TRACK_FORMAT_XA;
	    p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */
	    break;
	  case 0x7:
	    track_format     = TRACK_FORMAT_AUDIO;
	    p_env->disc_mode = CDIO_DISC_MODE_CD_DA;
	    break;
	  default:
	    cdio_log (log_level, "Unknown track format %x\n", 
		      p_env->dtyp);
	    track_format = TRACK_FORMAT_AUDIO;
	  }
	  if (0 == disc_mode) {
	    for (i=0; i<p_env->gen.i_tracks; i++) {
	      p_env->tocent[i].track_format= track_format;
	      p_env->tocent[i].datastart   = 0;
	      p_env->tocent[i].track_green = false;
	      if (TRACK_FORMAT_AUDIO == track_format) {
		p_env->tocent[i].blocksize   = CDIO_CD_FRAMESIZE_RAW;
		p_env->tocent[i].datasize    = CDIO_CD_FRAMESIZE_RAW;
		p_env->tocent[i].endsize     = 0;
	      } else {
		p_env->tocent[i].datasize    = CDIO_CD_FRAMESIZE;
		p_env->tocent[i].datastart  =  0;
	      }
	    }
	  } else if (2 == disc_mode) {
	    for (i=0; i<p_env->gen.i_tracks; i++) {
	      p_env->tocent[i].track_green = true;
	      p_env->tocent[i].track_format= track_format;
	      p_env->tocent[i].datasize    = CDIO_CD_FRAMESIZE;
	      if (TRACK_FORMAT_XA == track_format) {
		p_env->tocent[i].datastart   = CDIO_CD_SYNC_SIZE 
		  + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
		p_env->tocent[i].endsize     = CDIO_CD_SYNC_SIZE 
		  + CDIO_CD_ECC_SIZE;
	      } else {
		p_env->tocent[i].datastart   = CDIO_CD_SYNC_SIZE 
		  + CDIO_CD_HEADER_SIZE;
		p_env->tocent[i].endsize     = CDIO_CD_EDC_SIZE 
		  + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE;
	      
	      }
	    }
	  } else if (0x20 == disc_mode) {
	    cdio_debug ("Mixed mode CD?\n");
	  } else {
	    /* Mixed mode CD */
	    cdio_log (log_level, 
		      "Don't know if mode 1, mode 2 or mixed: %x\n", 
		      disc_mode);
	  }

	  for (i=0; i<p_env->gen.i_tracks; i++) {

	    if (DAOX_ID == opcode) {
	      _dao_array_common = &_xentries->track_info[i].common;
	    } else {
	      _dao_array_common = &_ientries->track_info[i].common;
	    }
	    p_env->tocent[i].isrc = calloc(1, CDIO_ISRC_SIZE+1);
	    memcpy(p_env->tocent[i].isrc, _dao_array_common->psz_isrc, CDIO_ISRC_SIZE);
	    p_env->tocent[i].isrc[CDIO_ISRC_SIZE] = '\0';
	    if (p_env->tocent[i].isrc[0]) {
	       cdio_info("nrg isrc has value \"%s\"", p_env->tocent[i].isrc);
	    }

	    if (!p_env->tocent[i].datasize) {
	      continue;
	    }
	    if (DAOX_ID == opcode) {
	       p_env->tocent[i].pregap = (uint64_from_be
		(_xentries->track_info[i].index0)) / (p_env->tocent[i].datasize);
	    } else {
	       p_env->tocent[i].pregap = (uint32_from_be
		(_ientries->track_info[i].index0)) / (p_env->tocent[i].datasize);
	    }
	  }

	  break;
	}
      case NERO_ID: 
      case NER5_ID: 
	cdio_error ("unexpected nrg magic ID NER%c detected",
		    opcode==NERO_ID ? 'O': '5');
	free(footer_buf);
	return false;

      case END1_ID: /* "END!" */
	cdio_debug ("nrg end tag detected");
	break_out = true;
	break;
	
      case ETNF_ID: /* "ETNF" */ {
	unsigned entries = UINT32_FROM_BE (chunk->len);
	_etnf_array_t *_entries = (void *) chunk->data;
	
	cdio_assert (p_env->mapping == NULL);
	
	cdio_assert ( sizeof (_etnf_array_t) == 20 );
	cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_etnf_array_t) 
		      == 0 );
	
	entries /= sizeof (_etnf_array_t);
	
	cdio_debug ("SAO type image (ETNF) detected");
	
	{
	  int idx;
	  for (idx = 0; idx < entries; idx++) {
	    uint32_t _len = UINT32_FROM_BE (_entries[idx].length);
	    uint32_t _start = UINT32_FROM_BE (_entries[idx].start_lsn);
	    uint32_t _start2 = UINT32_FROM_BE (_entries[idx].start);
	    uint32_t track_mode= uint32_from_be (_entries[idx].type);
	    bool     track_green = true;
	    track_format_t track_format = TRACK_FORMAT_XA;
	    uint16_t  blocksize;     
	    
	    switch (track_mode) {
	    case 0:
	      /* Mode 1 */
	      track_format   = TRACK_FORMAT_DATA;
	      track_green    = false; /* ?? */
	      blocksize      = CDIO_CD_FRAMESIZE;
	      p_env->disc_mode = CDIO_DISC_MODE_CD_DATA;
	      cdio_debug ("Format DATA, blocksize %u", CDIO_CD_FRAMESIZE);
	      break;
	    case 2:
	      /* Mode 2 form 1 */
	      track_format   = TRACK_FORMAT_XA;
	      track_green    = false; /* ?? */
	      blocksize      = CDIO_CD_FRAMESIZE;
	      p_env->disc_mode = CDIO_DISC_MODE_CD_XA;
	      cdio_debug ("Format XA, blocksize %u", CDIO_CD_FRAMESIZE);
	      break;
	    case 3:
	      /* Mode 2 */
	      track_format   = TRACK_FORMAT_XA;
	      track_green    = true;
	      blocksize      = M2RAW_SECTOR_SIZE;
	      p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */
	      cdio_debug ("Format XA, blocksize %u", M2RAW_SECTOR_SIZE);
	      break;
	    case 06:
	      /* Mode2 form mix */
	      track_format   = TRACK_FORMAT_XA;
	      track_green    = true;
	      blocksize      = M2RAW_SECTOR_SIZE;
	      p_env->disc_mode = CDIO_DISC_MODE_CD_MIXED;
	      cdio_debug ("Format MIXED CD, blocksize %u", M2RAW_SECTOR_SIZE);
	      break;
	    case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */
	      track_format   = TRACK_FORMAT_XA;
	      track_green    = true;
	      blocksize      = M2RAW_SECTOR_SIZE;
	      p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */
	      cdio_debug ("Format MIXED CD, blocksize %u", M2RAW_SECTOR_SIZE);
	      break;
	    case 7:
	      track_format   = TRACK_FORMAT_AUDIO;
	      track_green    = false;
	      blocksize      = CDIO_CD_FRAMESIZE_RAW;
	      p_env->disc_mode = CDIO_DISC_MODE_CD_DA;
	      cdio_debug ("Format CD_DA, blocksize %u", CDIO_CD_FRAMESIZE_RAW);
	      break;
	    default:
	      cdio_log (log_level, 
			"Don't know how to handle track mode (%lu)?",
			(long unsigned int) track_mode);
	      free(footer_buf);
	      return false;
	    }
	    
	    cdio_assert (_len % blocksize == 0);
	    
	    _len /= blocksize;
	    
	    cdio_assert (_start * blocksize == _start2);
	    
	    _start += idx * CDIO_PREGAP_SECTORS;
	    _register_mapping (p_env, _start, _len, _start2, blocksize,
			       track_format, track_green);

	  }
	}
	break;
      }
      
      case ETN2_ID: { /* "ETN2", same as above, but with 64bit stuff instead */
	unsigned entries = uint32_from_be (chunk->len);
	_etn2_array_t *_entries = (void *) chunk->data;
	
	cdio_assert (p_env->mapping == NULL);
	
	cdio_assert (sizeof (_etn2_array_t) == 32);
	cdio_assert (uint32_from_be (chunk->len) % sizeof (_etn2_array_t) == 0);
	
	entries /= sizeof (_etn2_array_t);
	
	cdio_debug ("SAO type image (ETN2) detected");

	{
	  int idx;
	  for (idx = 0; idx < entries; idx++) {
	    uint32_t _len = uint64_from_be (_entries[idx].length);
	    uint32_t _start = uint32_from_be (_entries[idx].start_lsn);
	    uint32_t _start2 = uint64_from_be (_entries[idx].start);
	    uint32_t track_mode= uint32_from_be (_entries[idx].type);
	    bool     track_green = true;
	    track_format_t track_format = TRACK_FORMAT_XA;
	    uint16_t  blocksize;     


	    switch (track_mode) {
	    case 0:
	      track_format = TRACK_FORMAT_DATA;
	      track_green  = false; /* ?? */
	      blocksize    = CDIO_CD_FRAMESIZE;
	      break;
	    case 2:
	      track_format = TRACK_FORMAT_XA;
	      track_green  = false; /* ?? */
	      blocksize    = CDIO_CD_FRAMESIZE;
	      break;
	    case 3:
	      track_format = TRACK_FORMAT_XA;
	      track_green  = true;
	      blocksize    = M2RAW_SECTOR_SIZE;
	      break;
	    case 7:
	      track_format = TRACK_FORMAT_AUDIO;
	      track_green  = false;
	      blocksize    = CDIO_CD_FRAMESIZE_RAW;
	      break;
	    default:
	      cdio_log (log_level, 
			"Don't know how to handle track mode (%lu)?",
			(long unsigned int) track_mode);
	      free(footer_buf);
	      return false;
	    }
	    
	    if (_len % blocksize != 0) {
	      cdio_log (log_level, 
			"length is not a multiple of blocksize " 
			 "len %lu, size %d, rem %lu", 
			 (long unsigned int) _len, blocksize, 
			 (long unsigned int) _len % blocksize);
	      if (0 == _len % CDIO_CD_FRAMESIZE) {
		cdio_log(log_level, "Adjusting blocksize to %d", 
			 CDIO_CD_FRAMESIZE);
		blocksize = CDIO_CD_FRAMESIZE;
	      } else if (0 == _len % M2RAW_SECTOR_SIZE) {
		cdio_log(log_level,
			 "Adjusting blocksize to %d", M2RAW_SECTOR_SIZE);
		blocksize = M2RAW_SECTOR_SIZE;
	      } else if (0 == _len % CDIO_CD_FRAMESIZE_RAW) {
		cdio_log(log_level, 
			 "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE_RAW);
		blocksize = CDIO_CD_FRAMESIZE_RAW;
	      }
	    }
	    
	    _len /= blocksize;
	    
	    if (_start * blocksize != _start2) {
	      cdio_log (log_level,
			"%lu * %d != %lu", 
			 (long unsigned int) _start, blocksize, 
			 (long unsigned int) _start2);
	      if (_start * CDIO_CD_FRAMESIZE == _start2) {
		cdio_log(log_level,
			 "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE);
		blocksize = CDIO_CD_FRAMESIZE;
	      } else if (_start * M2RAW_SECTOR_SIZE == _start2) {
		cdio_log(log_level,
			 "Adjusting blocksize to %d", M2RAW_SECTOR_SIZE);
		blocksize = M2RAW_SECTOR_SIZE;
	      } else if (_start * CDIO_CD_FRAMESIZE_RAW == _start2) {
		cdio_log(log_level,
			 "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE_RAW);
		blocksize = CDIO_CD_FRAMESIZE_RAW;
	      }
	    }
	    
	    _start += idx * CDIO_PREGAP_SECTORS;
	    _register_mapping (p_env, _start, _len, _start2, blocksize,
			       track_format, track_green);
	  }
	}
	break;
      }
	
      case SINF_ID: { /* "SINF" */
	
	uint32_t _sessions;
	
	cdio_assert (UINT32_FROM_BE (chunk->len) == 4);
	
	memcpy(&_sessions, chunk->data, 4);

	cdio_debug ("SINF: %lu sessions", 
		    (long unsigned int) UINT32_FROM_BE (_sessions));
      }
	break;
	
      case MTYP_ID: { /* "MTYP" */
	uint32_t mtyp_be;
	uint32_t mtyp;
	
	cdio_assert (UINT32_FROM_BE (chunk->len) == 4);

	memcpy(&mtyp_be, chunk->data, 4);
	mtyp = UINT32_FROM_BE (mtyp_be);

	cdio_debug ("MTYP: %lu", 
		    (long unsigned int) mtyp);

	if (mtyp != MTYP_AUDIO_CD) {
	  cdio_log (log_level,
		    "Unknown MTYP value: %u", (unsigned int) mtyp);
	}
	p_env->mtyp = mtyp;
      }
	break;
	
      case CDTX_ID: { /* "CD TEXT" */
        uint8_t *wdata = (uint8_t *) chunk->data;
        int len = UINT32_FROM_BE (chunk->len);
        cdio_assert (len % CDTEXT_LEN_PACK == 0);
        p_env->gen.cdtext = cdtext_init ();
        if(0 !=cdtext_data_init (p_env->gen.cdtext, wdata, len))
        {
          cdtext_destroy(p_env->gen.cdtext);
          free(p_env->gen.cdtext);
          p_env->gen.cdtext = NULL;
        }

        break;
      }

      default:
	cdio_log (log_level,
		  "unknown tag %8.8x seen", 
		  (unsigned int) UINT32_FROM_BE (chunk->id));
	break;
      }
	
      if (break_out)
	break;
      
      pos += 8;
      pos += UINT32_FROM_BE (chunk->len);
    }