/*
This code is based on cdda.c at cdda980108.diffs and 
xreadvcd.c and Linux kernel ide-cd.c .
Written by Takanori Watanabe(takawata@shidahara1.planet.kobe-u.ac.jp)
******************************NOTICE**************************************
*Please don't reuse this code for other programs. This Code is very EVIL.*
*We're discussing much more nicer imprmentation than this. Wait for a    *
* while. Thanks.                                                         *
**************************************************************************
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/cdio.h>

#include <stdio.h>
#include <fcntl.h>

#define NB 1
#define	ATAPI_READ_CD		0xbe
#define ATAPI_READ_BIG          0x28
#define	CD_CTL_PREEMPHASIS	1
#define	CD_CTL_DIGITALCOPY	2
#define	CD_CTL_DATATRACK	4
#define	CD_CTL_FOURCHANNEL	8
#define FRAMESIZEMODE2 2328
struct atapires {
  u_char	code;
  u_char	status;
  u_char	error;
};
struct atapireq {
  u_char  cmd[16];
  caddr_t databuf;
  int     datalen;  
  struct	atapires result;
};
#define CDIOCATAPIREQ    _IOWR('c',100,struct atapireq)

typedef struct cdsector{
   char sync[12],
   header[4],
   subheader[8],
   data[2324],
   spare[4];
}cdsector_t;

main(int argc, char **argv)
{
  int fd,fdout;
  struct atapireq ar;
  struct ioc_toc_header th;
  struct ioc_read_toc_entry te;
  struct cd_toc_entry *cte;
  char buf[NB*2352],buf2[NB*2352];
  u_long start, end, i;
  int track,format, ntracks;
  cdsector_t sector;
  if (argc < 3) {
    fprintf(stderr, "usage: %s track file \n", argv[0]);
#if 0
    fprintf(stderr, "format:0...raw\n");
    fprintf(stderr, "format:1...CDDA\n");
    fprintf(stderr, "format:2...MODE1\n");
    fprintf(stderr, "format:3...MODE2\n");
#endif
    exit(1);
	}
  track = atoi(argv[1]);
  fd = open("/dev/rwcd0c", O_RDONLY,0644);
  if (fd < 0) {
    perror("open");
    exit(-1);
  }
  if(*argv[2]=='-'){
    fdout=1;
  }
  else{
    fdout= open(argv[2],O_RDWR|O_CREAT,0644);
  }
  if(fdout < 0){
    perror("open");
    exit (-1);
  }	
  format=0;/*Format:RAW*/
  if (ioctl(fd, CDIOREADTOCHEADER, &th) < 0) {
    perror("CDIOREADTOCHEADER");
    exit(-1);
  }
  
  ntracks = th.ending_track - th.starting_track + 2;
  cte = (struct cd_toc_entry *)malloc(sizeof(*cte) * ntracks);
  
  te.address_format = CD_LBA_FORMAT;
  te.starting_track = 0;
  te.data_len = ntracks * sizeof(struct cd_toc_entry);
  te.data = cte;
  
  if (ioctl(fd, CDIOREADTOCENTRYS, &te) < 0) {
    perror("CDIOREADTOCENTRYS");
    exit(-1);
  }
  
  start = ntohl(cte[track-th.starting_track].addr.lba);
  end = ntohl(cte[track+1-th.starting_track].addr.lba);
  fprintf(stderr, "track %d of %d-%d: sector %d - %d\n",
	  track, th.starting_track, th.ending_track, start, end - 1);
  for (i = start; i < end; i += 1 ) {
    bzero(&ar, sizeof ar);
    ar.cmd[0] = ATAPI_READ_CD;/*ATAPI Request Command*/
    ar.cmd[1] = format<<2; /* was 0, In this Command this means format to read
 */
    ar.cmd[2] = i >> 24;
    ar.cmd[3] = i >> 16;
    ar.cmd[4] = i >> 8;
    ar.cmd[5] = i;/* These probably means start sector*/
    ar.cmd[6] = 0;
    ar.cmd[7] = 0;
    ar.cmd[8] = NB;/*Sectors to read*/
    ar.cmd[9] = 0xf8;/*Was 0x10(What this paramater means?)*/
    ar.databuf = &sector;
    ar.datalen = 2352/*sizeof(buf)*/;
    
    if (ioctl(fd, CDIOCATAPIREQ, &ar) < 0) {
      perror("CDIOATAPIREQ");
      exit(-1);
    }
    /* assert(ar.datalen == 2352); */
#if 0
    fprintf(stderr,"%d %x %x %x\n",ar.datalen,(int)ar.result.code,(int)ar.result.status,(int)ar.result.error);
    fprintf(stderr,"%x %x %x\n",(int)sector.subheader[1],
	    (int)sector.subheader[2],(int)sector.subheader[3]);
#endif
    if ((sector.subheader[1]==1) &&
	(((sector.subheader[2]==0x62) 
	  &&(sector.subheader[3]==0x0f)) || ((sector.subheader[2]==0x64) &&
					     (sector.subheader[3]==0x7f)))){
      fprintf(stderr,"O");
      write(fdout,sector.data,2324);
    }
    else
      fprintf(stderr,"X");
  }
  close(fd);
}



