1 |
/* |
2 |
$Id: nrg.c,v 1.14 2005/02/17 04:57:21 rocky Exp $ |
3 |
|
4 |
Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com> |
5 |
Copyright (C) 2001, 2003 Herbert Valerio Riedel <hvr@gnu.org> |
6 |
|
7 |
This program is free software; you can redistribute it and/or modify |
8 |
it under the terms of the GNU General Public License as published by |
9 |
the Free Software Foundation; either version 2 of the License, or |
10 |
(at your option) any later version. |
11 |
|
12 |
This program is distributed in the hope that it will be useful, |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
GNU General Public License for more details. |
16 |
|
17 |
You should have received a copy of the GNU General Public License |
18 |
along with this program; if not, write to the Free Software |
19 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
*/ |
21 |
/*! This code implements low-level access functions for the Nero native |
22 |
CD-image format residing inside a disk file (*.nrg). |
23 |
*/ |
24 |
|
25 |
#include "image.h" |
26 |
|
27 |
#ifdef HAVE_STDIO_H |
28 |
#include <stdio.h> |
29 |
#endif |
30 |
#ifdef HAVE_STDLIB_H |
31 |
#include <stdlib.h> |
32 |
#endif |
33 |
#ifdef HAVE_STRING_H |
34 |
#include <string.h> |
35 |
#endif |
36 |
#ifdef HAVE_GLOB_H |
37 |
#include <glob.h> |
38 |
#endif |
39 |
|
40 |
#include <cdio/bytesex.h> |
41 |
#include <cdio/ds.h> |
42 |
#include <cdio/logging.h> |
43 |
#include <cdio/util.h> |
44 |
#include <cdio/version.h> |
45 |
#include "cdio_assert.h" |
46 |
#include "_cdio_stdio.h" |
47 |
#include "nrg.h" |
48 |
|
49 |
static const char _rcsid[] = "$Id: nrg.c,v 1.14 2005/02/17 04:57:21 rocky Exp $"; |
50 |
|
51 |
|
52 |
/* reader */ |
53 |
|
54 |
#define DEFAULT_CDIO_DEVICE "image.nrg" |
55 |
|
56 |
/* |
57 |
Link element of track structure as a linked list. |
58 |
Possibly redundant with above track_info_t */ |
59 |
typedef struct { |
60 |
uint32_t start_lsn; |
61 |
uint32_t sec_count; /* Number of sectors in track. Does not |
62 |
include pregap before next entry. */ |
63 |
uint64_t img_offset; /* Bytes offset from beginning of disk image file.*/ |
64 |
uint32_t blocksize; /* Number of bytes in a block */ |
65 |
} _mapping_t; |
66 |
|
67 |
|
68 |
#define NEED_NERO_STRUCT |
69 |
#include "image_common.h" |
70 |
|
71 |
static bool parse_nrg (_img_private_t *env, const char *psz_cue_name); |
72 |
static lsn_t get_disc_last_lsn_nrg (void *p_user_data); |
73 |
|
74 |
/* Updates internal track TOC, so we can later |
75 |
simulate ioctl(CDROMREADTOCENTRY). |
76 |
*/ |
77 |
static void |
78 |
_register_mapping (_img_private_t *env, lsn_t start_lsn, uint32_t sec_count, |
79 |
uint64_t img_offset, uint32_t blocksize, |
80 |
track_format_t track_format, bool track_green) |
81 |
{ |
82 |
const int track_num=env->gen.i_tracks; |
83 |
track_info_t *this_track=&(env->tocent[env->gen.i_tracks]); |
84 |
_mapping_t *_map = calloc(1, sizeof (_mapping_t)); |
85 |
|
86 |
_map->start_lsn = start_lsn; |
87 |
_map->sec_count = sec_count; |
88 |
_map->img_offset = img_offset; |
89 |
_map->blocksize = blocksize; |
90 |
|
91 |
if (!env->mapping) env->mapping = _cdio_list_new (); |
92 |
_cdio_list_append (env->mapping, _map); |
93 |
|
94 |
env->size = MAX (env->size, (start_lsn + sec_count)); |
95 |
|
96 |
/* Update *this_track and track_num. These structures are |
97 |
in a sense redundant witht the obj->mapping list. Perhaps one |
98 |
or the other can be eliminated. |
99 |
*/ |
100 |
|
101 |
cdio_lba_to_msf (cdio_lsn_to_lba(start_lsn), &(this_track->start_msf)); |
102 |
this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf); |
103 |
this_track->track_num = track_num+1; |
104 |
this_track->blocksize = blocksize; |
105 |
if (env->is_cues) |
106 |
this_track->datastart = img_offset; |
107 |
else |
108 |
this_track->datastart = 0; |
109 |
|
110 |
if (track_green) |
111 |
this_track->datastart += CDIO_CD_SUBHEADER_SIZE; |
112 |
|
113 |
this_track->sec_count = sec_count; |
114 |
|
115 |
this_track->track_format= track_format; |
116 |
this_track->track_green = track_green; |
117 |
|
118 |
switch (this_track->track_format) { |
119 |
case TRACK_FORMAT_AUDIO: |
120 |
this_track->blocksize = CDIO_CD_FRAMESIZE_RAW; |
121 |
this_track->datasize = CDIO_CD_FRAMESIZE_RAW; |
122 |
/*this_track->datastart = 0;*/ |
123 |
this_track->endsize = 0; |
124 |
break; |
125 |
case TRACK_FORMAT_CDI: |
126 |
this_track->datasize=CDIO_CD_FRAMESIZE; |
127 |
break; |
128 |
case TRACK_FORMAT_XA: |
129 |
if (track_green) { |
130 |
this_track->blocksize = CDIO_CD_FRAMESIZE; |
131 |
/*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/ |
132 |
this_track->datasize = M2RAW_SECTOR_SIZE; |
133 |
this_track->endsize = 0; |
134 |
} else { |
135 |
/*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + |
136 |
CDIO_CD_SUBHEADER_SIZE;*/ |
137 |
this_track->datasize = CDIO_CD_FRAMESIZE; |
138 |
this_track->endsize = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE; |
139 |
} |
140 |
break; |
141 |
case TRACK_FORMAT_DATA: |
142 |
if (track_green) { |
143 |
/*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/ |
144 |
this_track->datasize = CDIO_CD_FRAMESIZE; |
145 |
this_track->endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE |
146 |
+ CDIO_CD_ECC_SIZE; |
147 |
} else { |
148 |
/* Is the below correct? */ |
149 |
/*this_track->datastart = 0;*/ |
150 |
this_track->datasize = CDIO_CD_FRAMESIZE; |
151 |
this_track->endsize = 0; |
152 |
} |
153 |
break; |
154 |
default: |
155 |
/*this_track->datasize=CDIO_CD_FRAMESIZE_RAW;*/ |
156 |
cdio_warn ("track %d has unknown format %d", |
157 |
env->gen.i_tracks, this_track->track_format); |
158 |
} |
159 |
|
160 |
env->gen.i_tracks++; |
161 |
|
162 |
cdio_debug ("start lsn: %lu sector count: %0lu -> %8ld (%08lx)", |
163 |
(long unsigned int) start_lsn, |
164 |
(long unsigned int) sec_count, |
165 |
(long unsigned int) img_offset, |
166 |
(long unsigned int) img_offset); |
167 |
} |
168 |
|
169 |
|
170 |
/* |
171 |
Disk and track information for a Nero file are located at the end |
172 |
of the file. This routine extracts that information. |
173 |
|
174 |
FIXME: right now psz_nrg_name is not used. It will be in the future. |
175 |
*/ |
176 |
static bool |
177 |
parse_nrg (_img_private_t *p_env, const char *psz_nrg_name) |
178 |
{ |
179 |
long unsigned int footer_start; |
180 |
long unsigned int size; |
181 |
char *footer_buf = NULL; |
182 |
cdio_log_level_t log_level = (NULL == p_env) ? CDIO_LOG_INFO : CDIO_LOG_WARN; |
183 |
|
184 |
size = cdio_stream_stat (p_env->gen.data_source); |
185 |
if (-1 == size) return false; |
186 |
|
187 |
{ |
188 |
_footer_t buf; |
189 |
cdio_assert (sizeof (buf) == 12); |
190 |
|
191 |
cdio_stream_seek (p_env->gen.data_source, size - sizeof (buf), SEEK_SET); |
192 |
cdio_stream_read (p_env->gen.data_source, (void *) &buf, sizeof (buf), 1); |
193 |
|
194 |
if (buf.v50.ID == UINT32_TO_BE (NERO_ID)) { |
195 |
cdio_debug ("detected Nero version 5.0 (32-bit offsets) NRG magic"); |
196 |
footer_start = uint32_to_be (buf.v50.footer_ofs); |
197 |
} else if (buf.v55.ID == UINT32_TO_BE (NER5_ID)) { |
198 |
cdio_debug ("detected Nero version 5.5.x (64-bit offsets) NRG magic"); |
199 |
footer_start = uint64_from_be (buf.v55.footer_ofs); |
200 |
} else { |
201 |
cdio_log (log_level, "Image not recognized as either version 5.0 or " |
202 |
"version 5.5.x-6.x type NRG"); |
203 |
return false; |
204 |
} |
205 |
|
206 |
cdio_debug (".NRG footer start = %ld, length = %ld", |
207 |
(long) footer_start, (long) (size - footer_start)); |
208 |
|
209 |
cdio_assert (IN ((size - footer_start), 0, 4096)); |
210 |
|
211 |
footer_buf = calloc(1, size - footer_start); |
212 |
|
213 |
cdio_stream_seek (p_env->gen.data_source, footer_start, SEEK_SET); |
214 |
cdio_stream_read (p_env->gen.data_source, footer_buf, |
215 |
size - footer_start, 1); |
216 |
} |
217 |
{ |
218 |
int pos = 0; |
219 |
|
220 |
while (pos < size - footer_start) { |
221 |
_chunk_t *chunk = (void *) (footer_buf + pos); |
222 |
uint32_t opcode = UINT32_FROM_BE (chunk->id); |
223 |
|
224 |
bool break_out = false; |
225 |
|
226 |
switch (opcode) { |
227 |
|
228 |
case CUES_ID: /* "CUES" Seems to have sector size 2336 and 150 sector |
229 |
pregap seems to be included at beginning of image. |
230 |
*/ |
231 |
case CUEX_ID: /* "CUEX" */ |
232 |
{ |
233 |
unsigned entries = UINT32_FROM_BE (chunk->len); |
234 |
_cuex_array_t *_entries = (void *) chunk->data; |
235 |
|
236 |
cdio_assert (p_env->mapping == NULL); |
237 |
|
238 |
cdio_assert ( sizeof (_cuex_array_t) == 8 ); |
239 |
cdio_assert ( UINT32_FROM_BE (chunk->len) % sizeof(_cuex_array_t) |
240 |
== 0 ); |
241 |
|
242 |
entries /= sizeof (_cuex_array_t); |
243 |
|
244 |
if (CUES_ID == opcode) { |
245 |
lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn); |
246 |
unsigned int idx; |
247 |
unsigned int i = 0; |
248 |
|
249 |
cdio_debug ("CUES type image detected" ); |
250 |
|
251 |
/* CUES LSN has 150 pregap include at beginning? -/ |
252 |
cdio_assert (lsn == 0?); |
253 |
*/ |
254 |
|
255 |
p_env->is_cues = true; /* HACK alert. */ |
256 |
p_env->gen.i_tracks = 0; |
257 |
p_env->gen.i_first_track = 1; |
258 |
for (idx = 1; idx < entries-1; idx += 2, i++) { |
259 |
lsn_t sec_count; |
260 |
int cdte_format = _entries[idx].addr_ctrl / 16; |
261 |
int cdte_ctrl = _entries[idx].type >> 4; |
262 |
|
263 |
if ( COPY_PERMITTED & cdte_ctrl ) { |
264 |
if (p_env) p_env->tocent[i].flags |= COPY_PERMITTED; |
265 |
} else { |
266 |
if (p_env) p_env->tocent[i].flags &= ~COPY_PERMITTED; |
267 |
} |
268 |
|
269 |
if ( PRE_EMPHASIS & cdte_ctrl ) { |
270 |
if (p_env) p_env->tocent[i].flags |= PRE_EMPHASIS; |
271 |
} else { |
272 |
if (p_env) p_env->tocent[i].flags &= ~PRE_EMPHASIS; |
273 |
} |
274 |
|
275 |
if ( FOUR_CHANNEL_AUDIO & cdte_ctrl ) { |
276 |
if (p_env) p_env->tocent[i].flags |= FOUR_CHANNEL_AUDIO; |
277 |
} else { |
278 |
if (p_env) p_env->tocent[i].flags &= ~FOUR_CHANNEL_AUDIO; |
279 |
} |
280 |
|
281 |
cdio_assert (_entries[idx].track == _entries[idx + 1].track); |
282 |
|
283 |
/* lsn and sec_count*2 aren't correct, but it comes closer on the |
284 |
single example I have: svcdgs.nrg |
285 |
We are picking up the wrong fields and/or not interpreting |
286 |
them correctly. |
287 |
*/ |
288 |
|
289 |
switch (cdte_format) { |
290 |
case 0: |
291 |
lsn = UINT32_FROM_BE (_entries[idx].lsn); |
292 |
break; |
293 |
case 1: |
294 |
{ |
295 |
#if 0 |
296 |
msf_t msf = (msf_t) _entries[idx].lsn; |
297 |
lsn = cdio_msf_to_lsn(&msf); |
298 |
#else |
299 |
lsn = CDIO_INVALID_LSN; |
300 |
#endif |
301 |
cdio_warn ("untested (i.e. probably wrong) CUE MSF code"); |
302 |
break; |
303 |
} |
304 |
default: |
305 |
lsn = CDIO_INVALID_LSN; |
306 |
cdio_warn("unknown cdte_format %d", cdte_format); |
307 |
} |
308 |
|
309 |
sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn); |
310 |
|
311 |
_register_mapping (p_env, lsn, sec_count*2, |
312 |
(lsn+CDIO_PREGAP_SECTORS) * M2RAW_SECTOR_SIZE, |
313 |
M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true); |
314 |
} |
315 |
} else { |
316 |
lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn); |
317 |
unsigned int idx; |
318 |
unsigned int i = 0; |
319 |
|
320 |
cdio_debug ("CUEX type image detected"); |
321 |
|
322 |
/* LSN must start at -150 (LBA 0)? */ |
323 |
cdio_assert (lsn == -150); |
324 |
|
325 |
for (idx = 2; idx < entries; idx += 2, i++) { |
326 |
lsn_t sec_count; |
327 |
int cdte_format = _entries[idx].addr_ctrl >> 4; |
328 |
int cdte_ctrl = _entries[idx].type >> 4; |
329 |
|
330 |
if ( COPY_PERMITTED & cdte_ctrl ) { |
331 |
if (p_env) p_env->tocent[i].flags |= COPY_PERMITTED; |
332 |
} else { |
333 |
if (p_env) p_env->tocent[i].flags &= ~COPY_PERMITTED; |
334 |
} |
335 |
|
336 |
if ( PRE_EMPHASIS & cdte_ctrl ) { |
337 |
if (p_env) p_env->tocent[i].flags |= PRE_EMPHASIS; |
338 |
} else { |
339 |
if (p_env) p_env->tocent[i].flags &= ~PRE_EMPHASIS; |
340 |
} |
341 |
|
342 |
if ( FOUR_CHANNEL_AUDIO & cdte_ctrl ) { |
343 |
if (p_env) p_env->tocent[i].flags |= FOUR_CHANNEL_AUDIO; |
344 |
} else { |
345 |
if (p_env) p_env->tocent[i].flags &= ~FOUR_CHANNEL_AUDIO; |
346 |
} |
347 |
|
348 |
/* extractnrg.pl has cdte_format for LBA's 0, and |
349 |
for MSF 1. ??? |
350 |
|
351 |
FIXME: Should decode as appropriate for cdte_format. |
352 |
*/ |
353 |
cdio_assert ( cdte_format == 0 || cdte_format == 1 ); |
354 |
|
355 |
cdio_assert (_entries[idx].track != _entries[idx + 1].track); |
356 |
|
357 |
lsn = UINT32_FROM_BE (_entries[idx].lsn); |
358 |
sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn); |
359 |
|
360 |
_register_mapping (p_env, lsn, sec_count - lsn, |
361 |
(lsn + CDIO_PREGAP_SECTORS)*M2RAW_SECTOR_SIZE, |
362 |
M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true); |
363 |
} |
364 |
} |
365 |
break; |
366 |
} |
367 |
|
368 |
case DAOX_ID: /* "DAOX" */ |
369 |
case DAOI_ID: /* "DAOI" */ |
370 |
{ |
371 |
track_format_t track_format; |
372 |
int disc_mode; |
373 |
|
374 |
/* We include an extra 0 byte so these can be used as C strings.*/ |
375 |
p_env->psz_mcn = calloc(1, CDIO_MCN_SIZE+1); |
376 |
|
377 |
if (DAOX_ID == opcode) { |
378 |
_daox_array_t *_entries = (void *) chunk->data; |
379 |
disc_mode = _entries->_unknown[1]; |
380 |
p_env->dtyp = _entries->_unknown[19]; |
381 |
memcpy(p_env->psz_mcn, &(_entries->psz_mcn), CDIO_MCN_SIZE); |
382 |
p_env->psz_mcn[CDIO_MCN_SIZE] = '\0'; |
383 |
} else { |
384 |
_daoi_array_t *_entries = (void *) chunk->data; |
385 |
disc_mode = _entries->_unknown[1]; |
386 |
p_env->dtyp = _entries->_unknown[19]; |
387 |
memcpy(p_env->psz_mcn, &(_entries->psz_mcn), CDIO_MCN_SIZE); |
388 |
p_env->psz_mcn[CDIO_MCN_SIZE] = '\0'; |
389 |
} |
390 |
|
391 |
p_env->is_dao = true; |
392 |
cdio_debug ("DAO%c tag detected, track format %d, mode %x\n", |
393 |
opcode==DAOX_ID ? 'X': 'I', p_env->dtyp, disc_mode); |
394 |
switch (p_env->dtyp) { |
395 |
case 0: |
396 |
/* Mode 1 */ |
397 |
track_format = TRACK_FORMAT_DATA; |
398 |
p_env->disc_mode = CDIO_DISC_MODE_CD_DATA; |
399 |
break; |
400 |
case 2: |
401 |
/* Mode 2 form 1 */ |
402 |
disc_mode = 0; |
403 |
track_format = TRACK_FORMAT_XA; |
404 |
p_env->disc_mode = CDIO_DISC_MODE_CD_XA; |
405 |
break; |
406 |
case 3: |
407 |
/* Mode 2 */ |
408 |
track_format = TRACK_FORMAT_XA; |
409 |
p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */ |
410 |
break; |
411 |
case 0x6: |
412 |
/* Mode2 form mix */ |
413 |
track_format = TRACK_FORMAT_XA; |
414 |
p_env->disc_mode = CDIO_DISC_MODE_CD_MIXED; |
415 |
break; |
416 |
case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */ |
417 |
track_format = TRACK_FORMAT_XA; |
418 |
p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */ |
419 |
break; |
420 |
case 0x7: |
421 |
track_format = TRACK_FORMAT_AUDIO; |
422 |
p_env->disc_mode = CDIO_DISC_MODE_CD_DA; |
423 |
break; |
424 |
default: |
425 |
cdio_log (log_level, "Unknown track format %x\n", |
426 |
p_env->dtyp); |
427 |
track_format = TRACK_FORMAT_AUDIO; |
428 |
} |
429 |
if (0 == disc_mode) { |
430 |
int i; |
431 |
for (i=0; i<p_env->gen.i_tracks; i++) { |
432 |
cdtext_init (&(p_env->gen.cdtext_track[i])); |
433 |
p_env->tocent[i].track_format= track_format; |
434 |
p_env->tocent[i].datastart = 0; |
435 |
p_env->tocent[i].track_green = false; |
436 |
if (TRACK_FORMAT_AUDIO == track_format) { |
437 |
p_env->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; |
438 |
p_env->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW; |
439 |
p_env->tocent[i].endsize = 0; |
440 |
} else { |
441 |
p_env->tocent[i].datasize = CDIO_CD_FRAMESIZE; |
442 |
p_env->tocent[i].datastart = 0; |
443 |
} |
444 |
} |
445 |
} else if (2 == disc_mode) { |
446 |
int i; |
447 |
for (i=0; i<p_env->gen.i_tracks; i++) { |
448 |
cdtext_init (&(p_env->gen.cdtext_track[i])); |
449 |
p_env->tocent[i].track_green = true; |
450 |
p_env->tocent[i].track_format= track_format; |
451 |
p_env->tocent[i].datasize = CDIO_CD_FRAMESIZE; |
452 |
if (TRACK_FORMAT_XA == track_format) { |
453 |
p_env->tocent[i].datastart = CDIO_CD_SYNC_SIZE |
454 |
+ CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; |
455 |
p_env->tocent[i].endsize = CDIO_CD_SYNC_SIZE |
456 |
+ CDIO_CD_ECC_SIZE; |
457 |
} else { |
458 |
p_env->tocent[i].datastart = CDIO_CD_SYNC_SIZE |
459 |
+ CDIO_CD_HEADER_SIZE; |
460 |
p_env->tocent[i].endsize = CDIO_CD_EDC_SIZE |
461 |
+ CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; |
462 |
|
463 |
} |
464 |
} |
465 |
} else if (0x20 == disc_mode) { |
466 |
cdio_debug ("Mixed mode CD?\n"); |
467 |
} else { |
468 |
/* Mixed mode CD */ |
469 |
cdio_log (log_level, |
470 |
"Don't know if mode 1, mode 2 or mixed: %x\n", |
471 |
disc_mode); |
472 |
} |
473 |
break; |
474 |
} |
475 |
case NERO_ID: |
476 |
case NER5_ID: |
477 |
cdio_error ("unexpected nrg magic ID NER%c detected", |
478 |
opcode==NERO_ID ? 'O': '5'); |
479 |
free(footer_buf); |
480 |
return false; |
481 |
break; |
482 |
|
483 |
case END1_ID: /* "END!" */ |
484 |
cdio_debug ("nrg end tag detected"); |
485 |
break_out = true; |
486 |
break; |
487 |
|
488 |
case ETNF_ID: /* "ETNF" */ { |
489 |
unsigned entries = UINT32_FROM_BE (chunk->len); |
490 |
_etnf_array_t *_entries = (void *) chunk->data; |
491 |
|
492 |
cdio_assert (p_env->mapping == NULL); |
493 |
|
494 |
cdio_assert ( sizeof (_etnf_array_t) == 20 ); |
495 |
cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_etnf_array_t) |
496 |
== 0 ); |
497 |
|
498 |
entries /= sizeof (_etnf_array_t); |
499 |
|
500 |
cdio_debug ("SAO type image (ETNF) detected"); |
501 |
|
502 |
{ |
503 |
int idx; |
504 |
for (idx = 0; idx < entries; idx++) { |
505 |
uint32_t _len = UINT32_FROM_BE (_entries[idx].length); |
506 |
uint32_t _start = UINT32_FROM_BE (_entries[idx].start_lsn); |
507 |
uint32_t _start2 = UINT32_FROM_BE (_entries[idx].start); |
508 |
uint32_t track_mode= uint32_from_be (_entries[idx].type); |
509 |
bool track_green = true; |
510 |
track_format_t track_format = TRACK_FORMAT_XA; |
511 |
uint16_t blocksize; |
512 |
|
513 |
switch (track_mode) { |
514 |
case 0: |
515 |
/* Mode 1 */ |
516 |
track_format = TRACK_FORMAT_DATA; |
517 |
track_green = false; /* ?? */ |
518 |
blocksize = CDIO_CD_FRAMESIZE; |
519 |
p_env->disc_mode = CDIO_DISC_MODE_CD_DATA; |
520 |
cdio_debug ("Format DATA, blocksize %u", CDIO_CD_FRAMESIZE); |
521 |
break; |
522 |
case 2: |
523 |
/* Mode 2 form 1 */ |
524 |
track_format = TRACK_FORMAT_XA; |
525 |
track_green = false; /* ?? */ |
526 |
blocksize = CDIO_CD_FRAMESIZE; |
527 |
p_env->disc_mode = CDIO_DISC_MODE_CD_XA; |
528 |
cdio_debug ("Format XA, blocksize %u", CDIO_CD_FRAMESIZE); |
529 |
break; |
530 |
case 3: |
531 |
/* Mode 2 */ |
532 |
track_format = TRACK_FORMAT_XA; |
533 |
track_green = true; |
534 |
blocksize = M2RAW_SECTOR_SIZE; |
535 |
p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */ |
536 |
cdio_debug ("Format XA, blocksize %u", M2RAW_SECTOR_SIZE); |
537 |
break; |
538 |
case 06: |
539 |
/* Mode2 form mix */ |
540 |
track_format = TRACK_FORMAT_XA; |
541 |
track_green = true; |
542 |
blocksize = M2RAW_SECTOR_SIZE; |
543 |
p_env->disc_mode = CDIO_DISC_MODE_CD_MIXED; |
544 |
cdio_debug ("Format MIXED CD, blocksize %u", M2RAW_SECTOR_SIZE); |
545 |
break; |
546 |
case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */ |
547 |
track_format = TRACK_FORMAT_XA; |
548 |
track_green = true; |
549 |
blocksize = M2RAW_SECTOR_SIZE; |
550 |
p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */ |
551 |
cdio_debug ("Format MIXED CD, blocksize %u", M2RAW_SECTOR_SIZE); |
552 |
break; |
553 |
case 7: |
554 |
track_format = TRACK_FORMAT_AUDIO; |
555 |
track_green = false; |
556 |
blocksize = CDIO_CD_FRAMESIZE_RAW; |
557 |
p_env->disc_mode = CDIO_DISC_MODE_CD_DA; |
558 |
cdio_debug ("Format CD_DA, blocksize %u", CDIO_CD_FRAMESIZE_RAW); |
559 |
break; |
560 |
default: |
561 |
cdio_log (log_level, |
562 |
"Don't know how to handle track mode (%lu)?", |
563 |
(long unsigned int) track_mode); |
564 |
free(footer_buf); |
565 |
return false; |
566 |
} |
567 |
|
568 |
cdio_assert (_len % blocksize == 0); |
569 |
|
570 |
_len /= blocksize; |
571 |
|
572 |
cdio_assert (_start * blocksize == _start2); |
573 |
|
574 |
_start += idx * CDIO_PREGAP_SECTORS; |
575 |
_register_mapping (p_env, _start, _len, _start2, blocksize, |
576 |
track_format, track_green); |
577 |
|
578 |
} |
579 |
} |
580 |
break; |
581 |
} |
582 |
|
583 |
case ETN2_ID: { /* "ETN2", same as above, but with 64bit stuff instead */ |
584 |
unsigned entries = uint32_from_be (chunk->len); |
585 |
_etn2_array_t *_entries = (void *) chunk->data; |
586 |
|
587 |
cdio_assert (p_env->mapping == NULL); |
588 |
|
589 |
cdio_assert (sizeof (_etn2_array_t) == 32); |
590 |
cdio_assert (uint32_from_be (chunk->len) % sizeof (_etn2_array_t) == 0); |
591 |
|
592 |
entries /= sizeof (_etn2_array_t); |
593 |
|
594 |
cdio_debug ("SAO type image (ETN2) detected"); |
595 |
|
596 |
{ |
597 |
int idx; |
598 |
for (idx = 0; idx < entries; idx++) { |
599 |
uint32_t _len = uint64_from_be (_entries[idx].length); |
600 |
uint32_t _start = uint32_from_be (_entries[idx].start_lsn); |
601 |
uint32_t _start2 = uint64_from_be (_entries[idx].start); |
602 |
uint32_t track_mode= uint32_from_be (_entries[idx].type); |
603 |
bool track_green = true; |
604 |
track_format_t track_format = TRACK_FORMAT_XA; |
605 |
uint16_t blocksize; |
606 |
|
607 |
|
608 |
switch (track_mode) { |
609 |
case 0: |
610 |
track_format = TRACK_FORMAT_DATA; |
611 |
track_green = false; /* ?? */ |
612 |
blocksize = CDIO_CD_FRAMESIZE; |
613 |
break; |
614 |
case 2: |
615 |
track_format = TRACK_FORMAT_XA; |
616 |
track_green = false; /* ?? */ |
617 |
blocksize = CDIO_CD_FRAMESIZE; |
618 |
break; |
619 |
case 3: |
620 |
track_format = TRACK_FORMAT_XA; |
621 |
track_green = true; |
622 |
blocksize = M2RAW_SECTOR_SIZE; |
623 |
break; |
624 |
case 7: |
625 |
track_format = TRACK_FORMAT_AUDIO; |
626 |
track_green = false; |
627 |
blocksize = CDIO_CD_FRAMESIZE_RAW; |
628 |
break; |
629 |
default: |
630 |
cdio_log (log_level, |
631 |
"Don't know how to handle track mode (%lu)?", |
632 |
(long unsigned int) track_mode); |
633 |
free(footer_buf); |
634 |
return false; |
635 |
} |
636 |
|
637 |
if (_len % blocksize != 0) { |
638 |
cdio_log (log_level, |
639 |
"length is not a multiple of blocksize " |
640 |
"len %lu, size %d, rem %lu", |
641 |
(long unsigned int) _len, blocksize, |
642 |
(long unsigned int) _len % blocksize); |
643 |
if (0 == _len % CDIO_CD_FRAMESIZE) { |
644 |
cdio_log(log_level, "Adjusting blocksize to %d", |
645 |
CDIO_CD_FRAMESIZE); |
646 |
blocksize = CDIO_CD_FRAMESIZE; |
647 |
} else if (0 == _len % M2RAW_SECTOR_SIZE) { |
648 |
cdio_log(log_level, |
649 |
"Adjusting blocksize to %d", M2RAW_SECTOR_SIZE); |
650 |
blocksize = M2RAW_SECTOR_SIZE; |
651 |
} else if (0 == _len % CDIO_CD_FRAMESIZE_RAW) { |
652 |
cdio_log(log_level, |
653 |
"Adjusting blocksize to %d", CDIO_CD_FRAMESIZE_RAW); |
654 |
blocksize = CDIO_CD_FRAMESIZE_RAW; |
655 |
} |
656 |
} |
657 |
|
658 |
_len /= blocksize; |
659 |
|
660 |
if (_start * blocksize != _start2) { |
661 |
cdio_log (log_level, |
662 |
"%lu * %d != %lu", |
663 |
(long unsigned int) _start, blocksize, |
664 |
(long unsigned int) _start2); |
665 |
if (_start * CDIO_CD_FRAMESIZE == _start2) { |
666 |
cdio_log(log_level, |
667 |
"Adjusting blocksize to %d", CDIO_CD_FRAMESIZE); |
668 |
blocksize = CDIO_CD_FRAMESIZE; |
669 |
} else if (_start * M2RAW_SECTOR_SIZE == _start2) { |
670 |
cdio_log(log_level, |
671 |
"Adjusting blocksize to %d", M2RAW_SECTOR_SIZE); |
672 |
blocksize = M2RAW_SECTOR_SIZE; |
673 |
} else if (0 == _start * CDIO_CD_FRAMESIZE_RAW == _start2) { |
674 |
cdio_log(log_level, |
675 |
"Adjusting blocksize to %d", CDIO_CD_FRAMESIZE_RAW); |
676 |
blocksize = CDIO_CD_FRAMESIZE_RAW; |
677 |
} |
678 |
} |
679 |
|
680 |
_start += idx * CDIO_PREGAP_SECTORS; |
681 |
_register_mapping (p_env, _start, _len, _start2, blocksize, |
682 |
track_format, track_green); |
683 |
} |
684 |
} |
685 |
break; |
686 |
} |
687 |
|
688 |
case SINF_ID: { /* "SINF" */ |
689 |
|
690 |
uint32_t *_sessions = (void *) chunk->data; |
691 |
|
692 |
cdio_assert (UINT32_FROM_BE (chunk->len) == 4); |
693 |
|
694 |
cdio_debug ("SINF: %lu sessions", |
695 |
(long unsigned int) UINT32_FROM_BE (*_sessions)); |
696 |
} |
697 |
break; |
698 |
|
699 |
case MTYP_ID: { /* "MTYP" */ |
700 |
uint32_t *mtyp_p = (void *) chunk->data; |
701 |
uint32_t mtyp = UINT32_FROM_BE (*mtyp_p); |
702 |
|
703 |
cdio_assert (UINT32_FROM_BE (chunk->len) == 4); |
704 |
|
705 |
cdio_debug ("MTYP: %lu", |
706 |
(long unsigned int) UINT32_FROM_BE (*mtyp_p)); |
707 |
|
708 |
if (mtyp != MTYP_AUDIO_CD) { |
709 |
cdio_log (log_level, |
710 |
"Unknown MTYP value: %u", (unsigned int) mtyp); |
711 |
} |
712 |
p_env->mtyp = mtyp; |
713 |
} |
714 |
break; |
715 |
|
716 |
case CDTX_ID: { /* "CD TEXT" */ |
717 |
|
718 |
cdio_log (log_level, |
719 |
"Don't know how to handle CD TEXT yet" ); |
720 |
break; |
721 |
} |
722 |
|
723 |
default: |
724 |
cdio_log (log_level, |
725 |
"unknown tag %8.8x seen", |
726 |
(unsigned int) UINT32_FROM_BE (chunk->id)); |
727 |
break; |
728 |
} |
729 |
|
730 |
if (break_out) |
731 |
break; |
732 |
|
733 |
pos += 8; |
734 |
pos += UINT32_FROM_BE (chunk->len); |
735 |
} |
736 |
} |
737 |
|
738 |
/* Fake out leadout track. */ |
739 |
/* Don't use get_disc_last_lsn_nrg since that will lead to recursion since |
740 |
we haven't fully initialized things yet. |
741 |
*/ |
742 |
cdio_lsn_to_msf (p_env->size, &p_env->tocent[p_env->gen.i_tracks].start_msf); |
743 |
p_env->tocent[p_env->gen.i_tracks].start_lba = cdio_lsn_to_lba(p_env->size); |
744 |
p_env->tocent[p_env->gen.i_tracks-1].sec_count = |
745 |
cdio_lsn_to_lba(p_env->size - p_env->tocent[p_env->gen.i_tracks-1].start_lba); |
746 |
|
747 |
p_env->gen.b_cdtext_init = true; |
748 |
p_env->gen.b_cdtext_error = false; |
749 |
p_env->gen.toc_init = true; |
750 |
free(footer_buf); |
751 |
return true; |
752 |
} |
753 |
|
754 |
/*! |
755 |
Initialize image structures. |
756 |
*/ |
757 |
static bool |
758 |
_init_nrg (_img_private_t *p_env) |
759 |
{ |
760 |
if (p_env->gen.init) { |
761 |
cdio_error ("init called more than once"); |
762 |
return false; |
763 |
} |
764 |
|
765 |
if (!(p_env->gen.data_source = cdio_stdio_new (p_env->gen.source_name))) { |
766 |
cdio_warn ("can't open nrg image file %s for reading", |
767 |
p_env->gen.source_name); |
768 |
return false; |
769 |
} |
770 |
|
771 |
p_env->psz_mcn = NULL; |
772 |
p_env->disc_mode = CDIO_DISC_MODE_NO_INFO; |
773 |
|
774 |
cdtext_init (&(p_env->gen.cdtext)); |
775 |
|
776 |
if ( !parse_nrg (p_env, p_env->gen.source_name) ) { |
777 |
cdio_warn ("image file %s is not a Nero image", |
778 |
p_env->gen.source_name); |
779 |
return false; |
780 |
} |
781 |
|
782 |
p_env->gen.init = true; |
783 |
return true; |
784 |
|
785 |
} |
786 |
|
787 |
/*! |
788 |
Reads into buf the next size bytes. |
789 |
Returns -1 on error. |
790 |
Would be libc's seek() but we have to adjust for the extra track header |
791 |
information in each sector. |
792 |
*/ |
793 |
static off_t |
794 |
_lseek_nrg (void *p_user_data, off_t offset, int whence) |
795 |
{ |
796 |
_img_private_t *p_env = p_user_data; |
797 |
|
798 |
/* real_offset is the real byte offset inside the disk image |
799 |
The number below was determined empirically. |
800 |
*/ |
801 |
off_t real_offset= p_env->is_dao ? 0x4b000 : 0; |
802 |
|
803 |
unsigned int i; |
804 |
|
805 |
for (i=0; i<p_env->gen.i_tracks; i++) { |
806 |
track_info_t *this_track=&(p_env->tocent[i]); |
807 |
p_env->pos.index = i; |
808 |
if ( (this_track->sec_count*this_track->datasize) >= offset) { |
809 |
int blocks = offset / this_track->datasize; |
810 |
int rem = offset % this_track->datasize; |
811 |
int block_offset = blocks * this_track->blocksize; |
812 |
real_offset += block_offset + rem; |
813 |
p_env->pos.buff_offset = rem; |
814 |
p_env->pos.lba += blocks; |
815 |
break; |
816 |
} |
817 |
real_offset += this_track->sec_count*this_track->blocksize; |
818 |
offset -= this_track->sec_count*this_track->datasize; |
819 |
p_env->pos.lba += this_track->sec_count; |
820 |
} |
821 |
|
822 |
if (i==p_env->gen.i_tracks) { |
823 |
cdio_warn ("seeking outside range of disk image"); |
824 |
return -1; |
825 |
} else |
826 |
real_offset += p_env->tocent[i].datastart; |
827 |
return cdio_stream_seek(p_env->gen.data_source, real_offset, whence); |
828 |
} |
829 |
|
830 |
/*! |
831 |
Reads into buf the next size bytes. |
832 |
Returns -1 on error. |
833 |
FIXME: |
834 |
At present we assume a read doesn't cross sector or track |
835 |
boundaries. |
836 |
*/ |
837 |
static ssize_t |
838 |
_read_nrg (void *p_user_data, void *buf, size_t size) |
839 |
{ |
840 |
_img_private_t *p_env = p_user_data; |
841 |
return cdio_stream_read(p_env->gen.data_source, buf, size, 1); |
842 |
} |
843 |
|
844 |
/*! |
845 |
Get the size of the CD in logical block address (LBA) units. |
846 |
|
847 |
@param p_cdio the CD object queried |
848 |
@return the lsn. On error 0 or CDIO_INVALD_LSN. |
849 |
*/ |
850 |
static lsn_t |
851 |
get_disc_last_lsn_nrg (void *p_user_data) |
852 |
{ |
853 |
_img_private_t *p_env = p_user_data; |
854 |
|
855 |
return p_env->size; |
856 |
} |
857 |
|
858 |
/*! |
859 |
Reads a single audio sector from CD device into data starting |
860 |
from LSN. |
861 |
*/ |
862 |
static driver_return_code_t |
863 |
_read_audio_sectors_nrg (void *p_user_data, void *data, lsn_t lsn, |
864 |
unsigned int nblocks) |
865 |
{ |
866 |
_img_private_t *p_env = p_user_data; |
867 |
|
868 |
CdioListNode_t *node; |
869 |
|
870 |
if (lsn >= p_env->size) |
871 |
{ |
872 |
cdio_warn ("trying to read beyond image size (%lu >= %lu)", |
873 |
(long unsigned int) lsn, (long unsigned int) p_env->size); |
874 |
return -1; |
875 |
} |
876 |
|
877 |
_CDIO_LIST_FOREACH (node, p_env->mapping) { |
878 |
_mapping_t *_map = _cdio_list_node_data (node); |
879 |
|
880 |
if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->sec_count - 1))) { |
881 |
int ret; |
882 |
long int img_offset = _map->img_offset; |
883 |
|
884 |
img_offset += (lsn - _map->start_lsn) * CDIO_CD_FRAMESIZE_RAW; |
885 |
|
886 |
ret = cdio_stream_seek (p_env->gen.data_source, img_offset, |
887 |
SEEK_SET); |
888 |
if (ret!=0) return ret; |
889 |
ret = cdio_stream_read (p_env->gen.data_source, data, |
890 |
CDIO_CD_FRAMESIZE_RAW, nblocks); |
891 |
if (ret==0) return ret; |
892 |
break; |
893 |
} |
894 |
} |
895 |
|
896 |
if (!node) cdio_warn ("reading into pre gap (lsn %lu)", |
897 |
(long unsigned int) lsn); |
898 |
|
899 |
return 0; |
900 |
} |
901 |
|
902 |
static driver_return_code_t |
903 |
_read_mode1_sector_nrg (void *p_user_data, void *data, lsn_t lsn, |
904 |
bool b_form2) |
905 |
{ |
906 |
_img_private_t *p_env = p_user_data; |
907 |
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; |
908 |
|
909 |
CdioListNode_t *node; |
910 |
|
911 |
if (lsn >= p_env->size) |
912 |
{ |
913 |
cdio_warn ("trying to read beyond image size (%lu >= %lu)", |
914 |
(long unsigned int) lsn, (long unsigned int) p_env->size); |
915 |
return -1; |
916 |
} |
917 |
|
918 |
_CDIO_LIST_FOREACH (node, p_env->mapping) { |
919 |
_mapping_t *_map = _cdio_list_node_data (node); |
920 |
|
921 |
if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->sec_count - 1))) { |
922 |
int ret; |
923 |
long int img_offset = _map->img_offset; |
924 |
|
925 |
img_offset += (lsn - _map->start_lsn) * _map->blocksize; |
926 |
|
927 |
ret = cdio_stream_seek (p_env->gen.data_source, img_offset, |
928 |
SEEK_SET); |
929 |
if (ret!=0) return ret; |
930 |
|
931 |
/* FIXME: Not completely sure the below is correct. */ |
932 |
ret = cdio_stream_read (p_env->gen.data_source, |
933 |
(M2RAW_SECTOR_SIZE == _map->blocksize) |
934 |
? (buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE) |
935 |
: buf, |
936 |
_map->blocksize, 1); |
937 |
if (ret==0) return ret; |
938 |
break; |
939 |
} |
940 |
} |
941 |
|
942 |
if (!node) |
943 |
cdio_warn ("reading into pre gap (lsn %lu)", (long unsigned int) lsn); |
944 |
|
945 |
memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE, |
946 |
b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); |
947 |
|
948 |
return 0; |
949 |
} |
950 |
|
951 |
/*! |
952 |
Reads nblocks of mode2 sectors from cd device into data starting |
953 |
from lsn. |
954 |
*/ |
955 |
static driver_return_code_t |
956 |
_read_mode1_sectors_nrg (void *p_user_data, void *data, lsn_t lsn, |
957 |
bool b_form2, unsigned nblocks) |
958 |
{ |
959 |
_img_private_t *p_env = p_user_data; |
960 |
int i; |
961 |
int retval; |
962 |
unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; |
963 |
|
964 |
for (i = 0; i < nblocks; i++) { |
965 |
if ( (retval = _read_mode1_sector_nrg (p_env, |
966 |
((char *)data) + (blocksize * i), |
967 |
lsn + i, b_form2)) ) |
968 |
return retval; |
969 |
} |
970 |
return 0; |
971 |
} |
972 |
|
973 |
static driver_return_code_t |
974 |
_read_mode2_sector_nrg (void *p_user_data, void *data, lsn_t lsn, |
975 |
bool b_form2) |
976 |
{ |
977 |
_img_private_t *p_env = p_user_data; |
978 |
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; |
979 |
|
980 |
CdioListNode_t *node; |
981 |
|
982 |
if (lsn >= p_env->size) |
983 |
{ |
984 |
cdio_warn ("trying to read beyond image size (%lu >= %lu)", |
985 |
(long unsigned int) lsn, (long unsigned int) p_env->size); |
986 |
return -1; |
987 |
} |
988 |
|
989 |
_CDIO_LIST_FOREACH (node, p_env->mapping) { |
990 |
_mapping_t *_map = _cdio_list_node_data (node); |
991 |
|
992 |
if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->sec_count - 1))) { |
993 |
int ret; |
994 |
long int img_offset = _map->img_offset; |
995 |
|
996 |
img_offset += (lsn - _map->start_lsn) * _map->blocksize; |
997 |
|
998 |
ret = cdio_stream_seek (p_env->gen.data_source, img_offset, |
999 |
SEEK_SET); |
1000 |
if (ret!=0) return ret; |
1001 |
ret = cdio_stream_read (p_env->gen.data_source, |
1002 |
(M2RAW_SECTOR_SIZE == _map->blocksize) |
1003 |
? (buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE) |
1004 |
: buf, |
1005 |
_map->blocksize, 1); |
1006 |
if (ret==0) return ret; |
1007 |
break; |
1008 |
} |
1009 |
} |
1010 |
|
1011 |
if (!node) |
1012 |
cdio_warn ("reading into pre gap (lsn %lu)", (long unsigned int) lsn); |
1013 |
|
1014 |
if (b_form2) |
1015 |
memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE, |
1016 |
M2RAW_SECTOR_SIZE); |
1017 |
else |
1018 |
memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, CDIO_CD_FRAMESIZE); |
1019 |
|
1020 |
return 0; |
1021 |
} |
1022 |
|
1023 |
/*! |
1024 |
Reads nblocks of mode2 sectors from cd device into data starting |
1025 |
from lsn. |
1026 |
Returns 0 if no error. |
1027 |
*/ |
1028 |
static driver_return_code_t |
1029 |
_read_mode2_sectors_nrg (void *p_user_data, void *data, lsn_t lsn, |
1030 |
bool b_form2, unsigned nblocks) |
1031 |
{ |
1032 |
_img_private_t *p_env = p_user_data; |
1033 |
int i; |
1034 |
int retval; |
1035 |
unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; |
1036 |
|
1037 |
for (i = 0; i < nblocks; i++) { |
1038 |
if ( (retval = _read_mode2_sector_nrg (p_env, |
1039 |
((char *)data) + (blocksize * i), |
1040 |
lsn + i, b_form2)) ) |
1041 |
return retval; |
1042 |
} |
1043 |
return 0; |
1044 |
} |
1045 |
|
1046 |
/* |
1047 |
Free memory resources associated with NRG object. |
1048 |
*/ |
1049 |
static void |
1050 |
_free_nrg (void *p_user_data) |
1051 |
{ |
1052 |
_img_private_t *p_env = p_user_data; |
1053 |
|
1054 |
if (NULL == p_env) return; |
1055 |
if (NULL != p_env->mapping) |
1056 |
_cdio_list_free (p_env->mapping, true); |
1057 |
|
1058 |
/* The remaining part of the image is like the other image drivers, |
1059 |
so free that in the same way. */ |
1060 |
_free_image(p_user_data); |
1061 |
} |
1062 |
|
1063 |
/*! |
1064 |
Eject media -- there's nothing to do here except free resources. |
1065 |
We always return 2. |
1066 |
*/ |
1067 |
static driver_return_code_t |
1068 |
_eject_media_nrg(void *obj) |
1069 |
{ |
1070 |
_free_nrg (obj); |
1071 |
return DRIVER_OP_UNSUPPORTED; |
1072 |
} |
1073 |
|
1074 |
/*! |
1075 |
Return an array of strings giving possible NRG disk images. |
1076 |
*/ |
1077 |
char ** |
1078 |
cdio_get_devices_nrg (void) |
1079 |
{ |
1080 |
char **drives = NULL; |
1081 |
unsigned int num_files=0; |
1082 |
#ifdef HAVE_GLOB_H |
1083 |
unsigned int i; |
1084 |
glob_t globbuf; |
1085 |
globbuf.gl_offs = 0; |
1086 |
glob("*.nrg", GLOB_DOOFFS, NULL, &globbuf); |
1087 |
for (i=0; i<globbuf.gl_pathc; i++) { |
1088 |
cdio_add_device_list(&drives, globbuf.gl_pathv[i], &num_files); |
1089 |
} |
1090 |
globfree(&globbuf); |
1091 |
#else |
1092 |
cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &num_files); |
1093 |
#endif /*HAVE_GLOB_H*/ |
1094 |
cdio_add_device_list(&drives, NULL, &num_files); |
1095 |
return drives; |
1096 |
} |
1097 |
|
1098 |
/*! |
1099 |
Return a string containing the default CD device. |
1100 |
*/ |
1101 |
char * |
1102 |
cdio_get_default_device_nrg(void) |
1103 |
{ |
1104 |
char **drives = cdio_get_devices_nrg(); |
1105 |
char *drive = (drives[0] == NULL) ? NULL : strdup(drives[0]); |
1106 |
cdio_free_device_list(drives); |
1107 |
return drive; |
1108 |
} |
1109 |
|
1110 |
static bool |
1111 |
get_hwinfo_nrg ( const CdIo *p_cdio, /*out*/ cdio_hwinfo_t *hw_info) |
1112 |
{ |
1113 |
strcpy(hw_info->psz_vendor, "libcdio"); |
1114 |
strcpy(hw_info->psz_model, "Nero"); |
1115 |
strcpy(hw_info->psz_revision, CDIO_VERSION); |
1116 |
return true; |
1117 |
|
1118 |
} |
1119 |
|
1120 |
/*! |
1121 |
Return the number of tracks in the current medium. |
1122 |
CDIO_INVALID_TRACK is returned on error. |
1123 |
*/ |
1124 |
static track_format_t |
1125 |
get_track_format_nrg(void *p_user_data, track_t track_num) |
1126 |
{ |
1127 |
_img_private_t *p_env = p_user_data; |
1128 |
|
1129 |
if (track_num > p_env->gen.i_tracks || track_num == 0) |
1130 |
return TRACK_FORMAT_ERROR; |
1131 |
|
1132 |
if ( p_env->dtyp != DTYP_INVALID) { |
1133 |
switch (p_env->dtyp) { |
1134 |
case DTYP_MODE2_XA: |
1135 |
return TRACK_FORMAT_XA; |
1136 |
case DTYP_MODE1: |
1137 |
return TRACK_FORMAT_DATA; |
1138 |
default: ; |
1139 |
} |
1140 |
} |
1141 |
|
1142 |
/*if ( MTYP_AUDIO_CD == p_env->mtyp) return TRACK_FORMAT_AUDIO; */ |
1143 |
return p_env->tocent[track_num-1].track_format; |
1144 |
} |
1145 |
|
1146 |
/*! |
1147 |
Return true if we have XA data (green, mode2 form1) or |
1148 |
XA data (green, mode2 form2). That is track begins: |
1149 |
sync - header - subheader |
1150 |
12 4 - 8 |
1151 |
|
1152 |
FIXME: there's gotta be a better design for this and get_track_format? |
1153 |
*/ |
1154 |
static bool |
1155 |
_get_track_green_nrg(void *p_user_data, track_t track_num) |
1156 |
{ |
1157 |
_img_private_t *p_env = p_user_data; |
1158 |
|
1159 |
if (track_num > p_env->gen.i_tracks || track_num == 0) |
1160 |
return false; |
1161 |
|
1162 |
if ( MTYP_AUDIO_CD == p_env->mtyp) return false; |
1163 |
return p_env->tocent[track_num-1].track_green; |
1164 |
} |
1165 |
|
1166 |
/*! |
1167 |
Check that a NRG file is valid. |
1168 |
|
1169 |
*/ |
1170 |
/* Later we'll probably do better. For now though, this gets us |
1171 |
started for now. |
1172 |
*/ |
1173 |
bool |
1174 |
cdio_is_nrg(const char *psz_nrg) |
1175 |
{ |
1176 |
unsigned int i; |
1177 |
|
1178 |
if (psz_nrg == NULL) return false; |
1179 |
|
1180 |
i=strlen(psz_nrg)-strlen("nrg"); |
1181 |
|
1182 |
if (i>0) { |
1183 |
if (psz_nrg[i]=='n' && psz_nrg[i+1]=='r' && psz_nrg[i+2]=='g') { |
1184 |
return true; |
1185 |
} |
1186 |
else if (psz_nrg[i]=='N' && psz_nrg[i+1]=='R' && psz_nrg[i+2]=='G') { |
1187 |
return true; |
1188 |
} |
1189 |
} |
1190 |
return false; |
1191 |
} |
1192 |
|
1193 |
/*! |
1194 |
Initialization routine. This is the only thing that doesn't |
1195 |
get called via a function pointer. In fact *we* are the |
1196 |
ones to set that up. |
1197 |
*/ |
1198 |
CdIo * |
1199 |
cdio_open_am_nrg (const char *psz_source_name, const char *psz_access_mode) |
1200 |
{ |
1201 |
if (psz_access_mode != NULL && strcmp(psz_access_mode, "image")) |
1202 |
cdio_warn ("there is only one access mode for nrg. Arg %s ignored", |
1203 |
psz_access_mode); |
1204 |
return cdio_open_nrg(psz_source_name); |
1205 |
} |
1206 |
|
1207 |
|
1208 |
CdIo * |
1209 |
cdio_open_nrg (const char *psz_source) |
1210 |
{ |
1211 |
CdIo *ret; |
1212 |
_img_private_t *_data; |
1213 |
|
1214 |
cdio_funcs_t _funcs; |
1215 |
|
1216 |
memset( &_funcs, 0, sizeof(_funcs) ); |
1217 |
|
1218 |
_funcs.eject_media = _eject_media_nrg; |
1219 |
_funcs.free = _free_nrg; |
1220 |
_funcs.get_arg = _get_arg_image; |
1221 |
_funcs.get_cdtext = get_cdtext_generic; |
1222 |
_funcs.get_devices = cdio_get_devices_nrg; |
1223 |
_funcs.get_default_device = cdio_get_default_device_nrg; |
1224 |
_funcs.get_disc_last_lsn = get_disc_last_lsn_nrg; |
1225 |
_funcs.get_discmode = _get_discmode_image; |
1226 |
_funcs.get_drive_cap = _get_drive_cap_image; |
1227 |
_funcs.get_first_track_num = _get_first_track_num_image; |
1228 |
_funcs.get_hwinfo = get_hwinfo_nrg; |
1229 |
_funcs.get_media_changed = get_media_changed_image; |
1230 |
_funcs.get_mcn = _get_mcn_image; |
1231 |
_funcs.get_num_tracks = _get_num_tracks_image; |
1232 |
_funcs.get_track_channels = get_track_channels_generic, |
1233 |
_funcs.get_track_copy_permit = get_track_copy_permit_image, |
1234 |
_funcs.get_track_format = get_track_format_nrg; |
1235 |
_funcs.get_track_green = _get_track_green_nrg; |
1236 |
_funcs.get_track_lba = NULL; /* Will use generic routine via msf */ |
1237 |
_funcs.get_track_msf = _get_track_msf_image; |
1238 |
_funcs.get_track_preemphasis = get_track_preemphasis_generic, |
1239 |
_funcs.lseek = _lseek_nrg; |
1240 |
_funcs.read = _read_nrg; |
1241 |
_funcs.read_audio_sectors = _read_audio_sectors_nrg; |
1242 |
_funcs.read_data_sectors = read_data_sectors_image; |
1243 |
_funcs.read_mode1_sector = _read_mode1_sector_nrg; |
1244 |
_funcs.read_mode1_sectors = _read_mode1_sectors_nrg; |
1245 |
_funcs.read_mode2_sector = _read_mode2_sector_nrg; |
1246 |
_funcs.read_mode2_sectors = _read_mode2_sectors_nrg; |
1247 |
_funcs.run_mmc_cmd = NULL; |
1248 |
_funcs.set_arg = _set_arg_image; |
1249 |
|
1250 |
_data = calloc(1, sizeof (_img_private_t)); |
1251 |
_data->gen.init = false; |
1252 |
|
1253 |
_data->gen.i_tracks = 0; |
1254 |
_data->mtyp = 0; |
1255 |
_data->dtyp = DTYP_INVALID; |
1256 |
_data->gen.i_first_track= 1; |
1257 |
_data->is_dao = false; |
1258 |
_data->is_cues = false; /* FIXME: remove is_cues. */ |
1259 |
|
1260 |
ret = cdio_new ((void *)_data, &_funcs); |
1261 |
|
1262 |
if (ret == NULL) { |
1263 |
free(_data); |
1264 |
return NULL; |
1265 |
} |
1266 |
|
1267 |
ret->driver_id = DRIVER_NRG; |
1268 |
_set_arg_image(_data, "source", (NULL == psz_source) |
1269 |
? DEFAULT_CDIO_DEVICE: psz_source); |
1270 |
_set_arg_image (_data, "access-mode", "Nero"); |
1271 |
|
1272 |
_data->psz_cue_name = strdup(_get_arg_image(_data, "source")); |
1273 |
|
1274 |
if (!cdio_is_nrg(_data->psz_cue_name)) { |
1275 |
cdio_debug ("source name %s is not recognized as a NRG image", |
1276 |
_data->psz_cue_name); |
1277 |
_free_nrg(_data); |
1278 |
return NULL; |
1279 |
} |
1280 |
|
1281 |
_set_arg_image (_data, "cue", _data->psz_cue_name); |
1282 |
|
1283 |
if (_init_nrg(_data)) |
1284 |
return ret; |
1285 |
else { |
1286 |
_free_nrg(_data); |
1287 |
free(ret); |
1288 |
return NULL; |
1289 |
} |
1290 |
|
1291 |
} |
1292 |
|
1293 |
bool |
1294 |
cdio_have_nrg (void) |
1295 |
{ |
1296 |
return true; |
1297 |
} |