1 /*
2 Copyright (C) 2004-2008, 2011-2012, 2014, 2017
3 Rocky Bernstein <rocky@gnu.org>
4 toc reading routine adapted from cuetools
5 Copyright (C) 2003 Svend Sanjay Sorensen <ssorensen@fastmail.fm>
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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 /* This code implements low-level access functions for a CD images
22 residing inside a disk file (*.bin) and its associated cue sheet.
23 (*.cue).
24 */
25 #include "portable.h"
26
27 #ifdef HAVE_LIMITS_H
28 #include <limits.h>
29 #endif
30 #ifdef HAVE_STDIO_H
31 #include <stdio.h>
32 #endif
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39 #ifdef HAVE_STRINGS_H
40 #include <strings.h>
41 #endif
42 #ifdef HAVE_GLOB_H
43 #include <glob.h>
44 #endif
45 #ifdef HAVE_ERRNO_H
46 #include <errno.h>
47 #endif
48 #ifdef HAVE_INTTYPES_H
49 #include <inttypes.h>
50 #else
51 #define PRId64 "lld"
52 #endif
53
54 #include <ctype.h>
55
56 #include <cdio/logging.h>
57 #include <cdio/sector.h>
58 #include <cdio/util.h>
59 #include <stdio.h>
60 #include <cdio/utf8.h>
61 #include <cdio/version.h>
62
63 #include "image.h"
64 #include "cdio_assert.h"
65 #include "_cdio_stdio.h"
66
67 /* reader */
68
69 #define DEFAULT_CDIO_DEVICE "videocd.bin"
70 #define DEFAULT_CDIO_CDRDAO "videocd.toc"
71
72 #ifdef _WIN32
73 #define CDIO_FOPEN fopen_utf8
74 #else
75 #define CDIO_FOPEN fopen
76 #endif
77
78 #include "image_common.h"
79 #include "cdtext_private.h"
80
81 static lsn_t get_disc_last_lsn_cdrdao (void *p_user_data);
82 static bool parse_tocfile (_img_private_t *cd, const char *p_toc_name);
83
84
85 static bool
check_track_is_blocksize_multiple(const char * psz_fname,track_t i_track,off_t i_size,uint16_t i_blocksize)86 check_track_is_blocksize_multiple(const char *psz_fname,
87 track_t i_track, off_t i_size,
88 uint16_t i_blocksize)
89 {
90 if (i_size % i_blocksize) {
91 cdio_info ("image %s track %d size (%" PRId64 ") not a multiple"
92 " of the blocksize (%ld)",
93 psz_fname ? psz_fname : "unknown??", i_track, (int64_t)i_size,
94 (long int) i_blocksize);
95 if (i_size % M2RAW_SECTOR_SIZE == 0)
96 cdio_info ("this may be a 2336-type disc image");
97 else if (i_size % CDIO_CD_FRAMESIZE_RAW == 0)
98 cdio_info ("this may be a 2352-type disc image");
99 return false;
100 }
101 return true;
102 }
103
104
105 /*!
106 Initialize image structures.
107 */
108 static bool
_init_cdrdao(_img_private_t * env)109 _init_cdrdao (_img_private_t *env)
110 {
111 lsn_t lead_lsn;
112
113 if (env->gen.init)
114 return false;
115
116 /* Have to set init before calling get_disc_last_lsn_cdrdao() or we will
117 get into infinite recursion calling passing right here.
118 */
119 env->gen.init = true;
120 env->gen.i_first_track = 1;
121 env->psz_mcn = NULL;
122 env->disc_mode = CDIO_DISC_MODE_NO_INFO;
123
124 /* Read in TOC sheet. */
125 if ( !parse_tocfile(env, env->psz_cue_name) ) return false;
126
127 lead_lsn = get_disc_last_lsn_cdrdao( (_img_private_t *) env);
128
129 if (-1 == lead_lsn)
130 return false;
131
132 /* Fake out leadout track and sector count for last track*/
133 cdio_lsn_to_msf (lead_lsn, &env->tocent[env->gen.i_tracks].start_msf);
134 env->tocent[env->gen.i_tracks].start_lba = cdio_lsn_to_lba(lead_lsn);
135 env->tocent[env->gen.i_tracks-env->gen.i_first_track].sec_count =
136 cdio_lsn_to_lba(lead_lsn - env->tocent[env->gen.i_tracks-1].start_lba);
137
138 return true;
139 }
140
141 /*!
142 Reads into buf the next size bytes.
143 Returns -1 on error.
144 Would be libc's seek() but we have to adjust for the extra track header
145 information in each sector.
146 */
147 static off_t
_lseek_cdrdao(void * user_data,off_t offset,int whence)148 _lseek_cdrdao (void *user_data, off_t offset, int whence)
149 {
150 _img_private_t *env = user_data;
151
152 /* real_offset is the real byte offset inside the disk image
153 The number below was determined empirically. I'm guessing
154 the 1st 24 bytes of a bin file are used for something.
155 */
156 off_t real_offset=0;
157
158 unsigned int i;
159
160 env->pos.lba = 0;
161 for (i=0; i<env->gen.i_tracks; i++) {
162 track_info_t *this_track=&(env->tocent[i]);
163 env->pos.index = i;
164 if ( (this_track->sec_count*this_track->datasize) >= offset) {
165 int blocks = (int) (offset / this_track->datasize);
166 int rem = (int) (offset % this_track->datasize);
167 off_t block_offset = blocks * this_track->blocksize;
168 real_offset += block_offset + rem;
169 env->pos.buff_offset = rem;
170 env->pos.lba += (lba_t)blocks;
171 break;
172 }
173 real_offset += this_track->sec_count*this_track->blocksize;
174 offset -= this_track->sec_count*this_track->datasize;
175 env->pos.lba += this_track->sec_count;
176 }
177
178 if (i==env->gen.i_tracks) {
179 cdio_warn ("seeking outside range of disk image");
180 return -1;
181 } else {
182 real_offset += env->tocent[i].datastart;
183 return cdio_stream_seek(env->tocent[i].data_source, real_offset, whence);
184 }
185 }
186
187 /*!
188 Reads into buf the next size bytes.
189 Returns -1 on error.
190 FIXME:
191 At present we assume a read doesn't cross sector or track
192 boundaries.
193 */
194 static ssize_t
_read_cdrdao(void * user_data,void * data,size_t size)195 _read_cdrdao (void *user_data, void *data, size_t size)
196 {
197 _img_private_t *env = user_data;
198 char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
199 char *p = data;
200 ssize_t final_size=0;
201 ssize_t this_size;
202 track_info_t *this_track=&(env->tocent[env->pos.index]);
203 ssize_t skip_size = this_track->datastart + this_track->endsize;
204
205 while (size > 0) {
206 int rem = (int) (this_track->datasize - env->pos.buff_offset);
207 if (size <= rem) {
208 this_size = cdio_stream_read(this_track->data_source, buf, size, 1);
209 final_size += this_size;
210 memcpy (p, buf, this_size);
211 break;
212 }
213
214 /* Finish off reading this sector. */
215 cdio_warn ("Reading across block boundaries not finished");
216
217 size -= rem;
218 this_size = cdio_stream_read(this_track->data_source, buf, rem, 1);
219 final_size += this_size;
220 memcpy (p, buf, this_size);
221 p += this_size;
222 cdio_stream_read(this_track->data_source, buf, rem, 1);
223
224 /* Skip over stuff at end of this sector and the beginning of the next.
225 */
226 cdio_stream_read(this_track->data_source, buf, skip_size, 1);
227
228 /* Get ready to read another sector. */
229 env->pos.buff_offset=0;
230 env->pos.lba++;
231
232 /* Have gone into next track. */
233 if (env->pos.lba >= env->tocent[env->pos.index+1].start_lba) {
234 env->pos.index++;
235 this_track=&(env->tocent[env->pos.index]);
236 skip_size = this_track->datastart + this_track->endsize;
237 }
238 }
239 return final_size;
240 }
241
242 /*!
243 Return the size of the CD in logical block address (LBA) units.
244
245 FIXME: this assumes there is only one source for data or
246 one track of silence.
247 */
248 static lsn_t
get_disc_last_lsn_cdrdao(void * p_user_data)249 get_disc_last_lsn_cdrdao (void *p_user_data)
250 {
251 _img_private_t *p_env = p_user_data;
252 track_t i_leadout = p_env->gen.i_tracks;
253 uint16_t i_blocksize = p_env->tocent[i_leadout-1].blocksize;
254 off_t i_size;
255
256 if (p_env->tocent[i_leadout-1].sec_count) {
257 i_size = p_env->tocent[i_leadout-1].sec_count;
258 } else {
259 if (NULL == p_env->tocent[i_leadout-1].data_source) {
260 if (!p_env->tocent[i_leadout-1].silence) {
261 cdio_warn ("Data source for image %s is null",
262 p_env->gen.source_name);
263 return -1;
264 }
265 /* FIXME: this is only correct if there is one
266 track of silence. */
267 i_size = p_env->tocent[i_leadout-1].silence;
268 } else {
269 /* FIXME: this is only correct if there is one data source. */
270 i_size = cdio_stream_stat(p_env->tocent[i_leadout-1].data_source)
271 - p_env->tocent[i_leadout-1].offset;
272 }
273 if (i_size < 0) {
274 cdio_error ("Disc data size too small for track specification in image %s",
275 p_env->gen.source_name);
276 return (lsn_t)i_size;
277 }
278 if (check_track_is_blocksize_multiple(p_env->tocent[i_leadout-1].filename,
279 i_leadout-1, i_size, i_blocksize)) {
280 i_size /= i_blocksize;
281 } else {
282 /* Round up */
283 i_size = (i_size / i_blocksize) + 1;
284 }
285 }
286
287 i_size += p_env->tocent[i_leadout-1].start_lba;
288 i_size -= CDIO_PREGAP_SECTORS;
289
290 return (lsn_t)i_size;
291 }
292
293 #define MAXLINE 512
294 #define UNIMPLIMENTED_MSG \
295 cdio_log(log_level, "%s line %d: unimplimented keyword: %s", \
296 psz_cue_name, i_line, psz_keyword)
297
298
299 static bool
parse_tocfile(_img_private_t * cd,const char * psz_cue_name)300 parse_tocfile (_img_private_t *cd, const char *psz_cue_name)
301 {
302 /* The below declarations may be common in other image-parse routines. */
303 FILE *fp;
304 char psz_line[MAXLINE]; /* text of current line read in file fp. */
305 unsigned int i_line=0; /* line number in file of psz_line. */
306 int i = -1; /* Position in tocent. Same as
307 cd->gen.i_tracks - 1 */
308 char *psz_keyword, *psz_field, *psz_cue_name_dup;
309 cdio_log_level_t log_level = (cd) ? CDIO_LOG_WARN : CDIO_LOG_INFO ;
310 cdtext_field_t cdtext_key;
311
312 /* The below declaration(s) may be unique to this image-parse routine. */
313 unsigned int i_cdtext_nest = 0;
314
315 if (NULL == psz_cue_name)
316 return false;
317
318 psz_cue_name_dup = _cdio_strdup_fixpath(psz_cue_name);
319 if (NULL == psz_cue_name_dup)
320 return false;
321
322 fp = CDIO_FOPEN (psz_cue_name_dup, "r");
323 cdio_free(psz_cue_name_dup);
324 if (fp == NULL) {
325 cdio_log(log_level, "error opening %s for reading: %s",
326 psz_cue_name, strerror(errno));
327 return false;
328 }
329
330 if (cd) {
331 cd->gen.b_cdtext_error = false;
332 }
333
334 while (fgets(psz_line, MAXLINE, fp)) {
335
336 i_line++;
337
338 /* strip comment from line */
339 /* todo: // in quoted strings? */
340 /* //comment */
341 if ((psz_field = strstr (psz_line, "//")))
342 *psz_field = '\0';
343
344 if ((psz_keyword = strtok (psz_line, " \t\n\r"))) {
345 /* CATALOG "ddddddddddddd" */
346 if (0 == strcmp ("CATALOG", psz_keyword)) {
347 if (-1 == i) {
348 if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
349 if (13 != strlen(psz_field)) {
350 cdio_log(log_level,
351 "%s line %d after word CATALOG:",
352 psz_cue_name, i_line);
353 cdio_log(log_level,
354 "Token %s has length %ld. Should be 13 digits.",
355 psz_field, (long int) strlen(psz_field));
356
357 goto err_exit;
358 } else {
359 /* Check that we have all digits*/
360 unsigned int j;
361 for (j=0; j<13; j++) {
362 if (!isdigit((unsigned char) psz_field[j])) {
363 cdio_log(log_level,
364 "%s line %d after word CATALOG:",
365 psz_cue_name, i_line);
366 cdio_log(log_level,
367 "Character \"%c\" at postition %i of token \"%s\""
368 " is not all digits.",
369 psz_field[j], j+1, psz_field);
370 goto err_exit;
371 }
372 }
373 if (NULL != cd) cd->psz_mcn = strdup (psz_field);
374 }
375 } else {
376 cdio_log(log_level,
377 "%s line %d after word CATALOG:",
378 psz_cue_name, i_line);
379 cdio_log(log_level, "Expecting 13 digits; nothing seen.");
380 goto err_exit;
381 }
382 } else {
383 goto err_exit;
384 }
385
386 /* CD_DA | CD_ROM | CD_ROM_XA */
387 } else if (0 == strcmp ("CD_DA", psz_keyword)) {
388 if (-1 == i) {
389 if (NULL != cd)
390 cd->disc_mode = CDIO_DISC_MODE_CD_DA;
391 } else {
392 goto not_in_global_section;
393 }
394 } else if (0 == strcmp ("CD_ROM", psz_keyword)) {
395 if (-1 == i) {
396 if (NULL != cd)
397 cd->disc_mode = CDIO_DISC_MODE_CD_DATA;
398 } else {
399 goto not_in_global_section;
400 }
401
402 } else if (0 == strcmp ("CD_ROM_XA", psz_keyword)) {
403 if (-1 == i) {
404 if (NULL != cd)
405 cd->disc_mode = CDIO_DISC_MODE_CD_XA;
406 } else {
407 goto not_in_global_section;
408 }
409
410 /* TRACK <track-mode> [<sub-channel-mode>] */
411 } else if (0 == strcmp ("TRACK", psz_keyword)) {
412 i++;
413 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
414 if (0 == strcmp ("AUDIO", psz_field)) {
415 if (NULL != cd) {
416 cd->tocent[i].track_format = TRACK_FORMAT_AUDIO;
417 cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW;
418 cd->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW;
419 cd->tocent[i].datastart = 0;
420 cd->tocent[i].endsize = 0;
421 switch(cd->disc_mode) {
422 case CDIO_DISC_MODE_NO_INFO:
423 cd->disc_mode = CDIO_DISC_MODE_CD_DA;
424 break;
425 case CDIO_DISC_MODE_CD_DA:
426 case CDIO_DISC_MODE_CD_MIXED:
427 case CDIO_DISC_MODE_ERROR:
428 /* Disc type stays the same. */
429 break;
430 case CDIO_DISC_MODE_CD_DATA:
431 case CDIO_DISC_MODE_CD_XA:
432 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
433 break;
434 default:
435 cd->disc_mode = CDIO_DISC_MODE_ERROR;
436 }
437
438 }
439 } else if (0 == strcmp ("MODE1", psz_field)) {
440 if (NULL != cd) {
441 cd->tocent[i].track_format = TRACK_FORMAT_DATA;
442 cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW;
443 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
444 + CDIO_CD_HEADER_SIZE;
445 cd->tocent[i].datasize = CDIO_CD_FRAMESIZE;
446 cd->tocent[i].endsize = CDIO_CD_EDC_SIZE
447 + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE;
448 switch(cd->disc_mode) {
449 case CDIO_DISC_MODE_NO_INFO:
450 cd->disc_mode = CDIO_DISC_MODE_CD_DATA;
451 break;
452 case CDIO_DISC_MODE_CD_DATA:
453 case CDIO_DISC_MODE_CD_MIXED:
454 case CDIO_DISC_MODE_ERROR:
455 /* Disc type stays the same. */
456 break;
457 case CDIO_DISC_MODE_CD_DA:
458 case CDIO_DISC_MODE_CD_XA:
459 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
460 break;
461 default:
462 cd->disc_mode = CDIO_DISC_MODE_ERROR;
463 }
464 }
465 } else if (0 == strcmp ("MODE1_RAW", psz_field)) {
466 if (NULL != cd) {
467 cd->tocent[i].track_format = TRACK_FORMAT_DATA;
468 cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW;
469 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
470 + CDIO_CD_HEADER_SIZE;
471 cd->tocent[i].datasize = CDIO_CD_FRAMESIZE;
472 cd->tocent[i].endsize = CDIO_CD_EDC_SIZE
473 + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE;
474 switch(cd->disc_mode) {
475 case CDIO_DISC_MODE_NO_INFO:
476 cd->disc_mode = CDIO_DISC_MODE_CD_DATA;
477 break;
478 case CDIO_DISC_MODE_CD_DATA:
479 case CDIO_DISC_MODE_CD_MIXED:
480 case CDIO_DISC_MODE_ERROR:
481 /* Disc type stays the same. */
482 break;
483 case CDIO_DISC_MODE_CD_DA:
484 case CDIO_DISC_MODE_CD_XA:
485 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
486 break;
487 default:
488 cd->disc_mode = CDIO_DISC_MODE_ERROR;
489 }
490 }
491 } else if (0 == strcmp ("MODE2", psz_field)) {
492 if (NULL != cd) {
493 cd->tocent[i].track_format = TRACK_FORMAT_XA;
494 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
495 + CDIO_CD_HEADER_SIZE;
496 cd->tocent[i].datasize = M2RAW_SECTOR_SIZE;
497 cd->tocent[i].endsize = 0;
498 switch(cd->disc_mode) {
499 case CDIO_DISC_MODE_NO_INFO:
500 cd->disc_mode = CDIO_DISC_MODE_CD_XA;
501 break;
502 case CDIO_DISC_MODE_CD_XA:
503 case CDIO_DISC_MODE_CD_MIXED:
504 case CDIO_DISC_MODE_ERROR:
505 /* Disc type stays the same. */
506 break;
507 case CDIO_DISC_MODE_CD_DA:
508 case CDIO_DISC_MODE_CD_DATA:
509 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
510 break;
511 default:
512 cd->disc_mode = CDIO_DISC_MODE_ERROR;
513 }
514 }
515 } else if (0 == strcmp ("MODE2_FORM1", psz_field)) {
516 if (NULL != cd) {
517 cd->tocent[i].track_format = TRACK_FORMAT_XA;
518 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
519 + CDIO_CD_HEADER_SIZE;
520 cd->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW;
521 cd->tocent[i].endsize = 0;
522 switch(cd->disc_mode) {
523 case CDIO_DISC_MODE_NO_INFO:
524 cd->disc_mode = CDIO_DISC_MODE_CD_XA;
525 break;
526 case CDIO_DISC_MODE_CD_XA:
527 case CDIO_DISC_MODE_CD_MIXED:
528 case CDIO_DISC_MODE_ERROR:
529 /* Disc type stays the same. */
530 break;
531 case CDIO_DISC_MODE_CD_DA:
532 case CDIO_DISC_MODE_CD_DATA:
533 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
534 break;
535 default:
536 cd->disc_mode = CDIO_DISC_MODE_ERROR;
537 }
538 }
539 } else if (0 == strcmp ("MODE2_FORM2", psz_field)) {
540 if (NULL != cd) {
541 cd->tocent[i].track_format = TRACK_FORMAT_XA;
542 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
543 + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
544 cd->tocent[i].datasize = CDIO_CD_FRAMESIZE;
545 cd->tocent[i].endsize = CDIO_CD_SYNC_SIZE
546 + CDIO_CD_ECC_SIZE;
547 switch(cd->disc_mode) {
548 case CDIO_DISC_MODE_NO_INFO:
549 cd->disc_mode = CDIO_DISC_MODE_CD_XA;
550 break;
551 case CDIO_DISC_MODE_CD_XA:
552 case CDIO_DISC_MODE_CD_MIXED:
553 case CDIO_DISC_MODE_ERROR:
554 /* Disc type stays the same. */
555 break;
556 case CDIO_DISC_MODE_CD_DA:
557 case CDIO_DISC_MODE_CD_DATA:
558 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
559 break;
560 default:
561 cd->disc_mode = CDIO_DISC_MODE_ERROR;
562 }
563 }
564 } else if (0 == strcmp ("MODE2_FORM_MIX", psz_field)) {
565 if (NULL != cd) {
566 cd->tocent[i].track_format = TRACK_FORMAT_XA;
567 cd->tocent[i].datasize = M2RAW_SECTOR_SIZE;
568 cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW;
569 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE +
570 CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
571 cd->tocent[i].track_green = true;
572 cd->tocent[i].endsize = 0;
573 switch(cd->disc_mode) {
574 case CDIO_DISC_MODE_NO_INFO:
575 cd->disc_mode = CDIO_DISC_MODE_CD_XA;
576 break;
577 case CDIO_DISC_MODE_CD_XA:
578 case CDIO_DISC_MODE_CD_MIXED:
579 case CDIO_DISC_MODE_ERROR:
580 /* Disc type stays the same. */
581 break;
582 case CDIO_DISC_MODE_CD_DA:
583 case CDIO_DISC_MODE_CD_DATA:
584 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
585 break;
586 default:
587 cd->disc_mode = CDIO_DISC_MODE_ERROR;
588 }
589 }
590 } else if (0 == strcmp ("MODE2_RAW", psz_field)) {
591 if (NULL != cd) {
592 cd->tocent[i].track_format = TRACK_FORMAT_XA;
593 cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW;
594 cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE +
595 CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
596 cd->tocent[i].datasize = CDIO_CD_FRAMESIZE;
597 cd->tocent[i].track_green = true;
598 cd->tocent[i].endsize = 0;
599 switch(cd->disc_mode) {
600 case CDIO_DISC_MODE_NO_INFO:
601 cd->disc_mode = CDIO_DISC_MODE_CD_XA;
602 break;
603 case CDIO_DISC_MODE_CD_XA:
604 case CDIO_DISC_MODE_CD_MIXED:
605 case CDIO_DISC_MODE_ERROR:
606 /* Disc type stays the same. */
607 break;
608 case CDIO_DISC_MODE_CD_DA:
609 case CDIO_DISC_MODE_CD_DATA:
610 cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
611 break;
612 default:
613 cd->disc_mode = CDIO_DISC_MODE_ERROR;
614 }
615 }
616 } else {
617 cdio_log(log_level, "%s line %d after TRACK:",
618 psz_cue_name, i_line);
619 cdio_log(log_level, "'%s' not a valid mode.", psz_field);
620 goto err_exit;
621 }
622 }
623 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
624 /* \todo: set sub-channel-mode */
625 #ifdef TODO
626 if (0 == strcmp ("RW", psz_field))
627 ;
628 else if (0 == strcmp ("RW_RAW", psz_field))
629 ;
630 #endif
631 }
632 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
633 goto format_error;
634 }
635
636 /* track flags */
637 /* [NO] COPY | [NO] PRE_EMPHASIS */
638 } else if (0 == strcmp ("NO", psz_keyword)) {
639 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
640 if (0 == strcmp ("COPY", psz_field)) {
641 if (NULL != cd)
642 cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_COPY_PERMITTED;
643
644 } else if (0 == strcmp ("PRE_EMPHASIS", psz_field))
645 if (NULL != cd) {
646 cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_PRE_EMPHASIS;
647 }
648 } else {
649 goto format_error;
650 }
651 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
652 goto format_error;
653 }
654 } else if (0 == strcmp ("COPY", psz_keyword)) {
655 if (NULL != cd && i >= 0)
656 cd->tocent[i].flags |= CDIO_TRACK_FLAG_COPY_PERMITTED;
657 } else if (0 == strcmp ("PRE_EMPHASIS", psz_keyword)) {
658 if (NULL != cd && i >= 0)
659 cd->tocent[i].flags |= CDIO_TRACK_FLAG_PRE_EMPHASIS;
660 /* TWO_CHANNEL_AUDIO */
661 } else if (0 == strcmp ("TWO_CHANNEL_AUDIO", psz_keyword)) {
662 if (NULL != cd && i >= 0)
663 cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO;
664 /* FOUR_CHANNEL_AUDIO */
665 } else if (0 == strcmp ("FOUR_CHANNEL_AUDIO", psz_keyword)) {
666 if (NULL != cd && i >= 0)
667 cd->tocent[i].flags |= CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO;
668
669 /* ISRC "CCOOOYYSSSSS" */
670 } else if (0 == strcmp ("ISRC", psz_keyword)) {
671 if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
672 if (NULL != cd)
673 cd->tocent[i].isrc = strdup(psz_field);
674 } else {
675 goto format_error;
676 }
677
678 /* SILENCE <length> */
679 } else if (0 == strcmp ("SILENCE", psz_keyword)) {
680 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
681 if (NULL != cd)
682 cd->tocent[i].silence = cdio_mmssff_to_lba (psz_field);
683 } else {
684 goto format_error;
685 }
686 cdio_log(log_level, "%s line %d: SILENCE not fully implimented",
687 psz_cue_name, i_line);
688
689 /* ZERO <length> */
690 } else if (0 == strcmp ("ZERO", psz_keyword)) {
691 UNIMPLIMENTED_MSG;
692
693 /* [FILE|AUDIOFILE] "<filename>" <start-msf> [<length-msf>] */
694 } else if (0 == strcmp ("FILE", psz_keyword)
695 || 0 == strcmp ("AUDIOFILE", psz_keyword)) {
696 if (0 <= i) {
697 if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
698 /* Handle "<filename>" */
699 if (cd) {
700 char *psz_dirname = cdio_dirname(psz_cue_name);
701 char *psz_filename = cdio_abspath(psz_dirname, psz_field);
702 cd->tocent[i].filename = strdup (psz_filename);
703 free(psz_filename);
704 free(psz_dirname);
705 /* To do: do something about reusing existing files. */
706 if (!(cd->tocent[i].data_source = cdio_stdio_new (psz_field))) {
707 cdio_log (log_level,
708 "%s line %d: can't open file `%s' for reading",
709 psz_cue_name, i_line, psz_field);
710 goto err_exit;
711 }
712 } else {
713 CdioDataSource_t *s = cdio_stdio_new (psz_field);
714 if (!s) {
715 cdio_log (log_level,
716 "%s line %d: can't open file `%s' for reading",
717 psz_cue_name, i_line, psz_field);
718 cdio_stdio_destroy (s);
719 goto err_exit;
720 }
721 cdio_stdio_destroy (s);
722 }
723 }
724
725 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
726 /* Handle <start-msf> */
727 lba_t i_start_lba =
728 cdio_lsn_to_lba(cdio_mmssff_to_lba (psz_field));
729 if (CDIO_INVALID_LBA == i_start_lba) {
730 cdio_log(log_level, "%s line %d: invalid MSF string %s",
731 psz_cue_name, i_line, psz_field);
732 goto err_exit;
733 }
734
735 if (NULL != cd) {
736 cd->tocent[i].start_lba = i_start_lba;
737 cdio_lba_to_msf(i_start_lba, &(cd->tocent[i].start_msf));
738 }
739 }
740 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
741 /* Handle <length-msf> */
742 lba_t lba = cdio_mmssff_to_lba (psz_field);
743 if (CDIO_INVALID_LBA == lba) {
744 cdio_log(log_level, "%s line %d: invalid MSF string %s",
745 psz_cue_name, i_line, psz_field);
746 goto err_exit;
747 }
748 if (cd) {
749 off_t i_size = cdio_stream_stat(cd->tocent[i].data_source);
750 if (lba) {
751 if ( (lba * cd->tocent[i].datasize) > i_size) {
752 cdio_log(log_level,
753 "%s line %d: MSF length %s exceeds end of file",
754 psz_cue_name, i_line, psz_field);
755 goto err_exit;
756 }
757 } else {
758 lba = (lba_t) (i_size / cd->tocent[i].blocksize);
759 }
760 cd->tocent[i].sec_count = lba;
761 }
762 }
763 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
764 goto format_error;
765 }
766 } else {
767 goto not_in_global_section;
768 }
769
770 /* DATAFILE "<filename>" #byte-offset <start-msf> */
771 } else if (0 == strcmp ("DATAFILE", psz_keyword)) {
772 if (0 <= i) {
773 if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
774 /* Handle <filename> */
775 char *psz_dirname = cdio_dirname(psz_cue_name);
776 char *psz_filename = cdio_abspath(psz_dirname, psz_field);
777 if (cd) {
778 cd->tocent[i].filename = strdup(psz_filename);
779 /* To do: do something about reusing existing files. */
780 if (!(cd->tocent[i].data_source = cdio_stdio_new (psz_field))) {
781 cdio_log (log_level,
782 "%s line %d: can't open file `%s' for reading",
783 psz_cue_name, i_line, psz_field);
784 free(psz_filename);
785 free(psz_dirname);
786 goto err_exit;
787 }
788 } else {
789 CdioDataSource_t *s = cdio_stdio_new (psz_filename);
790 if (!s) {
791 cdio_log (log_level,
792 "%s line %d: can't open file `%s' for reading",
793 psz_cue_name, i_line, psz_field);
794 free(psz_filename);
795 free(psz_dirname);
796 goto err_exit;
797 }
798 cdio_stdio_destroy (s);
799 }
800 free(psz_filename);
801 free(psz_dirname);
802 }
803
804 psz_field = strtok (NULL, " \t\n\r");
805 if (psz_field) {
806 /* Handle optional #byte-offset */
807 if ( psz_field[0] == '#') {
808 long int offset;
809 psz_field++;
810 errno = 0;
811 offset = strtol(psz_field, (char **)NULL, 10);
812 if ( (LONG_MIN == offset || LONG_MAX == offset)
813 && 0 != errno ) {
814 cdio_log (log_level,
815 "%s line %d: can't convert `%s' to byte offset",
816 psz_cue_name, i_line, psz_field);
817 goto err_exit;
818 } else {
819 if (NULL != cd) {
820 cd->tocent[i].offset = offset;
821 }
822 }
823 psz_field = strtok (NULL, " \t\n\r");
824 }
825 }
826 if (psz_field) {
827 /* Handle start-msf */
828 lba_t lba = cdio_mmssff_to_lba (psz_field);
829 if (CDIO_INVALID_LBA == lba) {
830 cdio_log(log_level, "%s line %d: invalid MSF string %s",
831 psz_cue_name, i_line, psz_field);
832 goto err_exit;
833 }
834 if (cd) {
835 cd->tocent[i].start_lba = lba;
836 cdio_lba_to_msf(cd->tocent[i].start_lba,
837 &(cd->tocent[i].start_msf));
838 }
839 } else {
840 /* No start-msf. */
841 if (cd) {
842 if (i) {
843 uint16_t i_blocksize = cd->tocent[i-1].blocksize;
844 off_t i_size =
845 cdio_stream_stat(cd->tocent[i-1].data_source);
846
847 check_track_is_blocksize_multiple(cd->tocent[i-1].filename,
848 i-1, i_size, i_blocksize);
849 /* Append size of previous datafile. */
850 cd->tocent[i].start_lba = (lba_t) (cd->tocent[i-1].start_lba +
851 (i_size / i_blocksize));
852 }
853 cd->tocent[i].offset = 0;
854 cd->tocent[i].start_lba += CDIO_PREGAP_SECTORS;
855 cdio_lba_to_msf(cd->tocent[i].start_lba,
856 &(cd->tocent[i].start_msf));
857 }
858 }
859
860 } else {
861 goto not_in_global_section;
862 }
863
864 /* FIFO "<fifo path>" [<length>] */
865 } else if (0 == strcmp ("FIFO", psz_keyword)) {
866 goto unimplimented_error;
867
868 /* START MM:SS:FF */
869 } else if (0 == strcmp ("START", psz_keyword)) {
870 if (0 <= i) {
871 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
872 /* todo: line is too long! */
873 if (NULL != cd) {
874 cd->tocent[i].pregap = cd->tocent[i].start_lba;
875 cd->tocent[i].start_lba += cdio_mmssff_to_lba (psz_field);
876 cdio_lba_to_msf(cd->tocent[i].start_lba,
877 &(cd->tocent[i].start_msf));
878 }
879 }
880
881 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
882 goto format_error;
883 }
884 } else {
885 goto not_in_global_section;
886 }
887
888 /* PREGAP MM:SS:FF */
889 } else if (0 == strcmp ("PREGAP", psz_keyword)) {
890 if (0 <= i) {
891 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
892 if (NULL != cd)
893 cd->tocent[i].pregap = cdio_mmssff_to_lba (psz_field);
894 } else {
895 goto format_error;
896 }
897 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
898 goto format_error;
899 }
900 } else {
901 goto not_in_global_section;
902 }
903
904 /* INDEX MM:SS:FF */
905 } else if (0 == strcmp ("INDEX", psz_keyword)) {
906 if (0 <= i) {
907 if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
908 if (NULL != cd) {
909 #if 0
910 if (1 == cd->tocent[i].nindex) {
911 cd->tocent[i].indexes[1] = cd->tocent[i].indexes[0];
912 cd->tocent[i].nindex++;
913 }
914 cd->tocent[i].indexes[cd->tocent[i].nindex++] =
915 cdio_mmssff_to_lba (psz_field) + cd->tocent[i].indexes[0];
916 #else
917 ;
918
919 #endif
920 }
921 } else {
922 goto format_error;
923 }
924 if (NULL != strtok (NULL, " \t\n\r")) {
925 goto format_error;
926 }
927 } else {
928 goto not_in_global_section;
929 }
930
931 /* CD_TEXT { ... } */
932 /* todo: opening { must be on same line as CD_TEXT */
933 } else if (0 == strcmp ("CD_TEXT", psz_keyword)) {
934 if (NULL == (psz_field = strtok (NULL, " \t\n\r"))) {
935 goto format_error;
936 }
937 if ( 0 == strcmp( "{", psz_field ) ) {
938 i_cdtext_nest++;
939 } else {
940 cdio_log (log_level,
941 "%s line %d: expecting '{'", psz_cue_name, i_line);
942 goto err_exit;
943 }
944
945 // TODO: implement language mapping
946 } else if (0 == strcmp ("LANGUAGE_MAP", psz_keyword)) {
947 /* LANGUAGE d { ... } */
948 } else if (0 == strcmp ("LANGUAGE", psz_keyword)) {
949 /* Language number */
950 if (NULL == (psz_field = strtok (NULL, " \t\n\r"))) {
951 goto format_error;
952 }
953 if ( 0 == strcmp( "{", psz_field ) ) {
954 i_cdtext_nest++;
955 }
956 } else if (0 == strcmp ("{", psz_keyword)) {
957 i_cdtext_nest++;
958 } else if (0 == strcmp ("}", psz_keyword)) {
959 if (i_cdtext_nest > 0) i_cdtext_nest--;
960 } else if ( CDTEXT_FIELD_INVALID !=
961 (cdtext_key = cdtext_is_field (psz_keyword)) ) {
962 if (NULL != cd) {
963 if (NULL == cd->gen.cdtext) {
964 cd->gen.cdtext = cdtext_init ();
965 /* until language mapping is implemented ...*/
966 cd->gen.cdtext->block[cd->gen.cdtext->block_i].language_code = CDTEXT_LANGUAGE_ENGLISH;
967 }
968 cdtext_set (cd->gen.cdtext, cdtext_key, (uint8_t*) strtok (NULL, "\"\t\n\r"),
969 (-1 == i ? 0 : cd->gen.i_first_track + i),
970 "ISO-8859-1");
971 }
972
973 /* unrecognized line */
974 } else {
975 cdio_log(log_level, "%s line %d: warning: unrecognized word: %s",
976 psz_cue_name, i_line, psz_keyword);
977 goto err_exit;
978 }
979 }
980 }
981
982 if (NULL != cd) {
983 cd->gen.i_tracks = i+1;
984 cd->gen.toc_init = true;
985 }
986
987 fclose (fp);
988 return true;
989
990 unimplimented_error:
991 UNIMPLIMENTED_MSG;
992 goto err_exit;
993
994 format_error:
995 cdio_log(log_level, "%s line %d after word %s",
996 psz_cue_name, i_line, psz_keyword);
997 goto err_exit;
998
999 not_in_global_section:
1000 cdio_log(log_level, "%s line %d: word %s only allowed in global section",
1001 psz_cue_name, i_line, psz_keyword);
1002
1003 err_exit:
1004 fclose (fp);
1005 return false;
1006 }
1007
1008 /*!
1009 Reads a single audio sector from CD device into data starting
1010 from lsn. Returns 0 if no error.
1011 */
1012 static driver_return_code_t
_read_audio_sectors_cdrdao(void * user_data,void * data,lsn_t lsn,unsigned int nblocks)1013 _read_audio_sectors_cdrdao (void *user_data, void *data, lsn_t lsn,
1014 unsigned int nblocks)
1015 {
1016 _img_private_t *env = user_data;
1017 int ret;
1018
1019 ret = cdio_stream_seek (env->tocent[0].data_source,
1020 lsn * CDIO_CD_FRAMESIZE_RAW, SEEK_SET);
1021 if (ret!=0) return ret;
1022
1023 ret = cdio_stream_read (env->tocent[0].data_source, data,
1024 CDIO_CD_FRAMESIZE_RAW, nblocks);
1025
1026 /* ret is number of bytes if okay, but we need to return 0 okay. */
1027 return ret == 0;
1028 }
1029
1030 /*!
1031 Reads a single mode2 sector from cd device into data starting
1032 from lsn. Returns 0 if no error.
1033 */
1034 static driver_return_code_t
_read_mode1_sector_cdrdao(void * user_data,void * data,lsn_t lsn,bool b_form2)1035 _read_mode1_sector_cdrdao (void *user_data, void *data, lsn_t lsn,
1036 bool b_form2)
1037 {
1038 _img_private_t *env = user_data;
1039 int ret;
1040 char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
1041
1042 ret = cdio_stream_seek (env->tocent[0].data_source,
1043 lsn * CDIO_CD_FRAMESIZE_RAW, SEEK_SET);
1044 if (ret!=0) return ret;
1045
1046 /* FIXME: Not completely sure the below is correct. */
1047 ret = cdio_stream_read (env->tocent[0].data_source, buf,
1048 CDIO_CD_FRAMESIZE_RAW, 1);
1049 if (ret==0) return ret;
1050
1051 memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE,
1052 b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
1053
1054 return DRIVER_OP_SUCCESS;
1055 }
1056
1057 /*!
1058 Reads nblocks of mode1 sectors from cd device into data starting
1059 from lsn.
1060 Returns 0 if no error.
1061 */
1062 static int
_read_mode1_sectors_cdrdao(void * user_data,void * data,lsn_t lsn,bool b_form2,unsigned int nblocks)1063 _read_mode1_sectors_cdrdao (void *user_data, void *data, lsn_t lsn,
1064 bool b_form2, unsigned int nblocks)
1065 {
1066 _img_private_t *env = user_data;
1067 int i;
1068 int retval;
1069 unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
1070
1071 for (i = 0; i < nblocks; i++) {
1072 if ( (retval = _read_mode1_sector_cdrdao (env,
1073 ((char *)data) + (blocksize * i),
1074 lsn + i, b_form2)) )
1075 return retval;
1076 }
1077 return DRIVER_OP_SUCCESS;
1078 }
1079
1080 /*!
1081 Reads a single mode1 sector from cd device into data starting
1082 from lsn. Returns 0 if no error.
1083 */
1084 static driver_return_code_t
_read_mode2_sector_cdrdao(void * user_data,void * data,lsn_t lsn,bool b_form2)1085 _read_mode2_sector_cdrdao (void *user_data, void *data, lsn_t lsn,
1086 bool b_form2)
1087 {
1088 _img_private_t *env = user_data;
1089 int ret;
1090 char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
1091 long unsigned int i_off = lsn * CDIO_CD_FRAMESIZE_RAW;
1092
1093 /* For sms's VCD's (mwc1.toc) it is more like this:
1094 if (i_off > 272) i_off -= 272;
1095 There is that magic 272 that we find in read_audio_sectors_cdrdao again.
1096 */
1097
1098 /* NOTE: The logic below seems a bit wrong and convoluted
1099 to me, but passes the regression tests. (Perhaps it is why we get
1100 valgrind errors in vcdxrip). Leave it the way it was for now.
1101 Review this sector 2336 stuff later.
1102 */
1103
1104 ret = cdio_stream_seek (env->tocent[0].data_source, i_off, SEEK_SET);
1105 if (ret!=0) return ret;
1106
1107 ret = cdio_stream_read (env->tocent[0].data_source, buf,
1108 CDIO_CD_FRAMESIZE_RAW, 1);
1109 if (ret==0) return ret;
1110
1111
1112 /* See NOTE above. */
1113 if (b_form2)
1114 memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE,
1115 M2RAW_SECTOR_SIZE);
1116 else
1117 memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, CDIO_CD_FRAMESIZE);
1118
1119 return DRIVER_OP_SUCCESS;
1120 }
1121
1122 /*!
1123 Reads nblocks of mode2 sectors from cd device into data starting
1124 from lsn.
1125 Returns 0 if no error.
1126 */
1127 static driver_return_code_t
_read_mode2_sectors_cdrdao(void * user_data,void * data,lsn_t lsn,bool b_form2,unsigned int nblocks)1128 _read_mode2_sectors_cdrdao (void *user_data, void *data, lsn_t lsn,
1129 bool b_form2, unsigned int nblocks)
1130 {
1131 _img_private_t *env = user_data;
1132 int i;
1133 int retval;
1134
1135 for (i = 0; i < nblocks; i++) {
1136 if ( (retval = _read_mode2_sector_cdrdao (env,
1137 ((char *)data) + (CDIO_CD_FRAMESIZE * i),
1138 lsn + i, b_form2)) )
1139 return retval;
1140 }
1141 return 0;
1142 }
1143
1144 /*!
1145 Return an array of strings giving possible TOC disk images.
1146 */
1147 char **
cdio_get_devices_cdrdao(void)1148 cdio_get_devices_cdrdao (void)
1149 {
1150 char **drives = NULL;
1151 unsigned int num_files=0;
1152 #ifdef HAVE_GLOB_H
1153 unsigned int i;
1154 glob_t globbuf;
1155 globbuf.gl_offs = 0;
1156 glob("*.toc", GLOB_DOOFFS, NULL, &globbuf);
1157 for (i=0; i<globbuf.gl_pathc; i++) {
1158 cdio_add_device_list(&drives, globbuf.gl_pathv[i], &num_files);
1159 }
1160 globfree(&globbuf);
1161 #else
1162 cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &num_files);
1163 #endif /*HAVE_GLOB_H*/
1164 cdio_add_device_list(&drives, NULL, &num_files);
1165 return drives;
1166 }
1167
1168 /*!
1169 Return a string containing the default CD device.
1170 */
1171 char *
cdio_get_default_device_cdrdao(void)1172 cdio_get_default_device_cdrdao(void)
1173 {
1174 char **drives = cdio_get_devices_nrg();
1175 char *drive = (drives[0] == NULL) ? NULL : strdup(drives[0]);
1176 cdio_free_device_list(drives);
1177 return drive;
1178 }
1179
1180 static bool
get_hwinfo_cdrdao(const CdIo_t * p_cdio,cdio_hwinfo_t * hw_info)1181 get_hwinfo_cdrdao ( const CdIo_t *p_cdio, /*out*/ cdio_hwinfo_t *hw_info)
1182 {
1183 strncpy(hw_info->psz_vendor, "libcdio",
1184 sizeof(hw_info->psz_vendor)-1);
1185 hw_info->psz_vendor[sizeof(hw_info->psz_vendor)-1] = '\0';
1186 strncpy(hw_info->psz_model, "cdrdao",
1187 sizeof(hw_info->psz_model)-1);
1188 hw_info->psz_model[sizeof(hw_info->psz_model)-1] = '\0';
1189 strncpy(hw_info->psz_revision, CDIO_VERSION,
1190 sizeof(hw_info->psz_revision)-1);
1191 hw_info->psz_revision[sizeof(hw_info->psz_revision)-1] = '\0';
1192 return true;
1193 }
1194
1195 /*!
1196 Return the number of tracks in the current medium.
1197 CDIO_INVALID_TRACK is returned on error.
1198 */
1199 static track_format_t
_get_track_format_cdrdao(void * p_user_data,track_t i_track)1200 _get_track_format_cdrdao(void *p_user_data, track_t i_track)
1201 {
1202 _img_private_t *p_env = p_user_data;
1203
1204 if (!p_env->gen.init) return TRACK_FORMAT_ERROR;
1205
1206 if (i_track > p_env->gen.i_tracks || i_track == 0)
1207 return TRACK_FORMAT_ERROR;
1208
1209 return p_env->tocent[i_track-p_env->gen.i_first_track].track_format;
1210 }
1211
1212 /*!
1213 Return true if we have XA data (green, mode2 form1) or
1214 XA data (green, mode2 form2). That is track begins:
1215 sync - header - subheader
1216 12 4 - 8
1217
1218 FIXME: there's gotta be a better design for this and get_track_format?
1219 */
1220 static bool
_get_track_green_cdrdao(void * user_data,track_t i_track)1221 _get_track_green_cdrdao(void *user_data, track_t i_track)
1222 {
1223 _img_private_t *env = user_data;
1224
1225 if (!env->gen.init) _init_cdrdao(env);
1226
1227 if (i_track > env->gen.i_tracks || i_track == 0)
1228 return false;
1229
1230 return env->tocent[i_track-env->gen.i_first_track].track_green;
1231 }
1232
1233 /*!
1234 Return the starting LSN track number
1235 i_track in obj. Track numbers start at 1.
1236 The "leadout" track is specified either by
1237 using i_track CDIO_CDROM_LEADOUT_TRACK or the total tracks+1.
1238 False is returned if there is no track entry.
1239 */
1240 static lba_t
_get_lba_track_cdrdao(void * p_user_data,track_t i_track)1241 _get_lba_track_cdrdao(void *p_user_data, track_t i_track)
1242 {
1243 _img_private_t *p_env = p_user_data;
1244 _init_cdrdao (p_env);
1245
1246 if (i_track == CDIO_CDROM_LEADOUT_TRACK)
1247 i_track = p_env->gen.i_tracks+1;
1248
1249 if (i_track <= p_env->gen.i_tracks+1 && i_track != 0) {
1250 return p_env->tocent[i_track-1].start_lba;
1251 } else
1252 return CDIO_INVALID_LBA;
1253 }
1254
1255 /*!
1256 Check that a TOC file is valid. We parse the entire file.
1257
1258 */
1259 bool
cdio_is_tocfile(const char * psz_cue_name)1260 cdio_is_tocfile(const char *psz_cue_name)
1261 {
1262 int i;
1263
1264 if (psz_cue_name == NULL) return false;
1265
1266 i=strlen(psz_cue_name)-strlen("toc");
1267
1268 if (i>0) {
1269 if ( (psz_cue_name[i]=='t' && psz_cue_name[i+1]=='o' && psz_cue_name[i+2]=='c')
1270 || (psz_cue_name[i]=='T' && psz_cue_name[i+1]=='O' && psz_cue_name[i+2]=='C') ) {
1271 return parse_tocfile(NULL, psz_cue_name);
1272 }
1273 }
1274 return false;
1275 }
1276
1277 /*!
1278 Initialization routine. This is the only thing that doesn't
1279 get called via a function pointer. In fact *we* are the
1280 ones to set that up.
1281 */
1282 CdIo_t *
cdio_open_am_cdrdao(const char * psz_source_name,const char * psz_access_mode)1283 cdio_open_am_cdrdao (const char *psz_source_name, const char *psz_access_mode)
1284 {
1285 if (psz_access_mode != NULL && strcmp(psz_access_mode, "image"))
1286 cdio_warn ("there is only one access mode, 'image' for cdrdao. Arg %s ignored",
1287 psz_access_mode);
1288 return cdio_open_cdrdao(psz_source_name);
1289 }
1290
1291 /*!
1292 Initialization routine. This is the only thing that doesn't
1293 get called via a function pointer. In fact *we* are the
1294 ones to set that up.
1295 */
1296 CdIo_t *
cdio_open_cdrdao(const char * psz_cue_name)1297 cdio_open_cdrdao (const char *psz_cue_name)
1298 {
1299 CdIo_t *ret;
1300 _img_private_t *p_data;
1301
1302 cdio_funcs_t _funcs;
1303
1304 memset( &_funcs, 0, sizeof(_funcs) );
1305
1306 _funcs.eject_media = _eject_media_image;
1307 _funcs.free = _free_image;
1308 _funcs.get_arg = _get_arg_image;
1309 _funcs.get_cdtext = _get_cdtext_image;
1310 _funcs.get_cdtext_raw = NULL;
1311 _funcs.get_devices = cdio_get_devices_cdrdao;
1312 _funcs.get_default_device = cdio_get_default_device_cdrdao;
1313 _funcs.get_disc_last_lsn = get_disc_last_lsn_cdrdao;
1314 _funcs.get_discmode = _get_discmode_image;
1315 _funcs.get_drive_cap = _get_drive_cap_image;
1316 _funcs.get_first_track_num = _get_first_track_num_image;
1317 _funcs.get_hwinfo = get_hwinfo_cdrdao;
1318 _funcs.get_media_changed = get_media_changed_image;
1319 _funcs.get_mcn = _get_mcn_image;
1320 _funcs.get_num_tracks = _get_num_tracks_image;
1321 _funcs.get_track_channels = get_track_channels_image;
1322 _funcs.get_track_copy_permit = get_track_copy_permit_image;
1323 _funcs.get_track_format = _get_track_format_cdrdao;
1324 _funcs.get_track_green = _get_track_green_cdrdao;
1325 _funcs.get_track_lba = _get_lba_track_cdrdao;
1326 _funcs.get_track_msf = _get_track_msf_image;
1327 _funcs.get_track_preemphasis = get_track_preemphasis_image;
1328 _funcs.get_track_pregap_lba = get_track_pregap_lba_image;
1329 _funcs.get_track_isrc = get_track_isrc_image;
1330 _funcs.lseek = _lseek_cdrdao;
1331 _funcs.read = _read_cdrdao;
1332 _funcs.read_audio_sectors = _read_audio_sectors_cdrdao;
1333 _funcs.read_data_sectors = read_data_sectors_image;
1334 _funcs.read_mode1_sector = _read_mode1_sector_cdrdao;
1335 _funcs.read_mode1_sectors = _read_mode1_sectors_cdrdao;
1336 _funcs.read_mode2_sector = _read_mode2_sector_cdrdao;
1337 _funcs.read_mode2_sectors = _read_mode2_sectors_cdrdao;
1338 _funcs.run_mmc_cmd = NULL;
1339 _funcs.set_arg = _set_arg_image;
1340 _funcs.set_speed = cdio_generic_unimplemented_set_speed;
1341 _funcs.set_blocksize = cdio_generic_unimplemented_set_blocksize;
1342
1343 if (NULL == psz_cue_name) return NULL;
1344
1345 p_data = calloc(1, sizeof (_img_private_t));
1346 p_data->gen.init = false;
1347 p_data->psz_cue_name = NULL;
1348 p_data->gen.data_source = NULL;
1349 p_data->gen.source_name = NULL;
1350
1351 ret = cdio_new ((void *)p_data, &_funcs);
1352
1353 if (ret == NULL) {
1354 free(p_data);
1355 return NULL;
1356 }
1357
1358 ret->driver_id = DRIVER_CDRDAO;
1359 if (!cdio_is_tocfile(psz_cue_name)) {
1360 cdio_debug ("source name %s is not recognized as a TOC file",
1361 psz_cue_name);
1362 free(p_data);
1363 free(ret);
1364 return NULL;
1365 }
1366
1367 _set_arg_image (p_data, "cue", psz_cue_name);
1368 _set_arg_image (p_data, "source", psz_cue_name);
1369 _set_arg_image (p_data, "access-mode", "cdrdao");
1370
1371 if (_init_cdrdao(p_data)) {
1372 return ret;
1373 } else {
1374 _free_image(p_data);
1375 free(ret);
1376 return NULL;
1377 }
1378 }
1379
1380 bool
cdio_have_cdrdao(void)1381 cdio_have_cdrdao (void)
1382 {
1383 return true;
1384 }
1385