📄 nrg.c
字号:
/* $Id: nrg.c,v 1.3 2005/05/07 22:07:27 rockyb Exp $ Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com> Copyright (C) 2001, 2003 Herbert Valerio Riedel <hvr@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//*! This code implements low-level access functions for the Nero native CD-image format residing inside a disk file (*.nrg).*/#include "image.h"#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_GLOB_H#include <glob.h>#endif#include <cdio/bytesex.h>#include <cdio/ds.h>#include <cdio/logging.h>#include <cdio/util.h>#include <cdio/version.h>#include "cdio_assert.h"#include "_cdio_stdio.h"#include "nrg.h"static const char _rcsid[] = "$Id: nrg.c,v 1.3 2005/05/07 22:07:27 rockyb Exp $";/* reader */#define DEFAULT_CDIO_DEVICE "image.nrg"/* Link element of track structure as a linked list. Possibly redundant with above track_info_t */typedef struct { uint32_t start_lsn; uint32_t sec_count; /* Number of sectors in track. Does not include pregap before next entry. */ uint64_t img_offset; /* Bytes offset from beginning of disk image file.*/ uint32_t blocksize; /* Number of bytes in a block */ int flags; /* don't copy, 4 channel, pre-emphasis */} _mapping_t;typedef struct { /* Things common to all drivers like this. This must be first. */ generic_img_private_t gen; internal_position_t pos; /* This is common to all image drivers... */ char *psz_cue_name; char *psz_mcn; /* Media Catalog Number (5.22.3) */ track_info_t tocent[CDIO_CD_MAX_TRACKS+1]; /* entry info for each track add 1 for leadout. */ discmode_t disc_mode; /* Nero Specific stuff. Note: for the image_free to work, this *must* be last. */ bool is_dao; /* True if some of disk at once. False if some sort of track at once. */ uint32_t mtyp; /* Value of MTYP (media type?) tag */ uint8_t dtyp; /* Value of DAOX media type tag */ /* This is a hack because I don't really understnad NERO better. */ bool is_cues; CdioList *mapping; /* List of track information */ uint32_t size;} _img_private_t;static bool parse_nrg (_img_private_t *env, const char *psz_cue_name);static uint32_t _stat_size_nrg (void *user_data);#include "image_common.h"/* Updates internal track TOC, so we can later simulate ioctl(CDROMREADTOCENTRY). */static void_register_mapping (_img_private_t *env, lsn_t start_lsn, uint32_t sec_count, uint64_t img_offset, uint32_t blocksize, track_format_t track_format, bool track_green, int flags){ const int track_num=env->gen.i_tracks; track_info_t *this_track=&(env->tocent[env->gen.i_tracks]); _mapping_t *_map = _cdio_malloc (sizeof (_mapping_t)); _map->start_lsn = start_lsn; _map->sec_count = sec_count; _map->img_offset = img_offset; _map->blocksize = blocksize; _map->flags = flags; if (!env->mapping) env->mapping = _cdio_list_new (); _cdio_list_append (env->mapping, _map); env->size = MAX (env->size, (start_lsn + sec_count)); /* Update *this_track and track_num. These structures are in a sense redundant witht the obj->mapping list. Perhaps one or the other can be eliminated. */ cdio_lba_to_msf (cdio_lsn_to_lba(start_lsn), &(this_track->start_msf)); this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf); this_track->track_num = track_num+1; this_track->blocksize = blocksize; if (env->is_cues) this_track->datastart = img_offset; else this_track->datastart = 0; if (track_green) this_track->datastart += CDIO_CD_SUBHEADER_SIZE; this_track->sec_count = sec_count; this_track->track_format= track_format; this_track->track_green = track_green; switch (this_track->track_format) { case TRACK_FORMAT_AUDIO: this_track->blocksize = CDIO_CD_FRAMESIZE_RAW; this_track->datasize = CDIO_CD_FRAMESIZE_RAW; /*this_track->datastart = 0;*/ this_track->endsize = 0; break; case TRACK_FORMAT_CDI: this_track->datasize=CDIO_CD_FRAMESIZE; break; case TRACK_FORMAT_XA: if (track_green) { this_track->blocksize = CDIO_CD_FRAMESIZE; /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/ this_track->datasize = M2RAW_SECTOR_SIZE; this_track->endsize = 0; } else { /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;*/ this_track->datasize = CDIO_CD_FRAMESIZE; this_track->endsize = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE; } break; case TRACK_FORMAT_DATA: if (track_green) { /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/ this_track->datasize = CDIO_CD_FRAMESIZE; this_track->endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; } else { /* Is the below correct? */ /*this_track->datastart = 0;*/ this_track->datasize = CDIO_CD_FRAMESIZE; this_track->endsize = 0; } break; default: /*this_track->datasize=CDIO_CD_FRAMESIZE_RAW;*/ cdio_warn ("track %d has unknown format %d", env->gen.i_tracks, this_track->track_format); } env->gen.i_tracks++; cdio_debug ("start lsn: %lu sector count: %0lu -> %8ld (%08lx)", (long unsigned int) start_lsn, (long unsigned int) sec_count, (long unsigned int) img_offset, (long unsigned int) img_offset);}/* 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 boolparse_nrg (_img_private_t *env, const char *psz_nrg_name){ long unsigned int footer_start; long unsigned int size; char *footer_buf = NULL; cdio_log_level_t log_level = (NULL == env) ? CDIO_LOG_INFO : CDIO_LOG_WARN; size = cdio_stream_stat (env->gen.data_source); if (-1 == size) return false; { _footer_t buf; cdio_assert (sizeof (buf) == 12); cdio_stream_seek (env->gen.data_source, size - sizeof (buf), SEEK_SET); cdio_stream_read (env->gen.data_source, (void *) &buf, sizeof (buf), 1); if (buf.v50.ID == UINT32_TO_BE (NERO_ID)) { cdio_info ("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_info ("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 (IN ((size - footer_start), 0, 4096)); footer_buf = _cdio_malloc (size - footer_start); cdio_stream_seek (env->gen.data_source, footer_start, SEEK_SET); cdio_stream_read (env->gen.data_source, footer_buf, 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 (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); int idx; cdio_info ("CUES type image detected" ); /* CUES LSN has 150 pregap include at beginning? -/ cdio_assert (lsn == 0?); */ env->is_cues = true; /* HACK alert. */ env->gen.i_tracks = 0; env->gen.i_first_track = 1; for (idx = 1; idx < entries-1; idx += 2) { lsn_t sec_count; int addrtype = _entries[idx].addr_ctrl / 16; int control = _entries[idx].addr_ctrl % 16; int flags = 0; if ( 1 == control ) flags &= ~CDIO_TRACK_FLAG_COPY_PERMITTED; 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 (addrtype) { 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_warn ("untested (i.e. probably wrong) CUE MSF code"); break; } default: lsn = CDIO_INVALID_LSN; cdio_warn("unknown addrtype %d", addrtype); } sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn); _register_mapping (env, lsn, sec_count*2, (lsn+CDIO_PREGAP_SECTORS) * M2RAW_SECTOR_SIZE, M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true, flags); } } else { lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn); int idx; cdio_info ("CUEX type image detected"); /* LSN must start at -150 (LBA 0)? */ cdio_assert (lsn == -150); for (idx = 2; idx < entries; idx += 2) { lsn_t sec_count; int addrtype = _entries[idx].addr_ctrl >> 4; int control = _entries[idx].addr_ctrl & 0xf; int flags = 0; if ( 1 == control ) flags &= ~CDIO_TRACK_FLAG_COPY_PERMITTED; /* extractnrg.pl has addrtype for LBA's 0, and for MSF 1. ??? FIXME: Should decode as appropriate for addrtype. */ cdio_assert ( addrtype == 0 || addrtype == 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 (env, lsn, sec_count - lsn, (lsn + CDIO_PREGAP_SECTORS)*M2RAW_SECTOR_SIZE, M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true, flags); } } break; } case DAOX_ID: /* "DAOX" */ case DAOI_ID: /* "DAOI" */ { track_format_t track_format; int form2; /* We include an extra 0 byte so these can be used as C strings.*/ env->psz_mcn = _cdio_malloc (CDIO_MCN_SIZE+1); if (DAOX_ID == opcode) { _daox_array_t *_entries = (void *) chunk->data; form2 = _entries->_unknown[1]; env->dtyp = _entries->_unknown[19]; memcpy(env->psz_mcn, &(_entries->psz_mcn), CDIO_MCN_SIZE); env->psz_mcn[CDIO_MCN_SIZE] = '\0'; } else { _daoi_array_t *_entries = (void *) chunk->data; form2 = _entries->_unknown[1]; env->dtyp = _entries->_unknown[19]; memcpy(env->psz_mcn, &(_entries->psz_mcn), CDIO_MCN_SIZE); env->psz_mcn[CDIO_MCN_SIZE] = '\0'; } env->is_dao = true; cdio_debug ("DAO%c tag detected, track format %d, form %x\n", opcode==DAOX_ID ? 'X': 'I', env->dtyp, form2); switch (env->dtyp) { case 0: /* Mode 1 */ track_format = TRACK_FORMAT_DATA; env->disc_mode = CDIO_DISC_MODE_CD_DATA; break; case 2: /* Mode 2 form 1 */ form2 = 0; track_format = TRACK_FORMAT_XA; env->disc_mode = CDIO_DISC_MODE_CD_XA; break; case 3: /* Mode 2 */ track_format = TRACK_FORMAT_XA; env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */ break; case 0x6: /* Mode2 form mix */ track_format = TRACK_FORMAT_XA; env->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */ track_format = TRACK_FORMAT_XA; env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */ break; case 0x7: track_format = TRACK_FORMAT_AUDIO; env->disc_mode = CDIO_DISC_MODE_CD_DA; break; default: cdio_log (log_level, "Unknown track format %x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -