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