1 /*
2     Copyright (C) 2018 Rocky Bernstein <rocky@gnu.org>
3     Copyright (C) 2001, 2004 Herbert Valerio Riedel <hvr@gnu.org>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 /* We don't want to pull in cdio's config */
29 #define __CDIO_CONFIG_H__
30 #include <cdio/cdio.h>
31 #include <cdio/bytesex.h>
32 #include <cdio/iso9660.h>
33 
34 /* Public headers */
35 #include <libvcd/sector.h>
36 #include <libvcd/logging.h>
37 
38 /* Private headers */
39 #include "vcd_assert.h"
40 #include "image_sink.h"
41 #include "stream_stdio.h"
42 #include "util.h"
43 
44 /* reader */
45 
46 #define DEFAULT_VCD_DEVICE "videocd.bin"
47 
48 /****************************************************************************
49  * writer
50  */
51 
52 typedef struct {
53   bool sector_2336_flag;
54   VcdDataSink *bin_snk;
55   VcdDataSink *cue_snk;
56   char *bin_fname;
57   char *cue_fname;
58 
59   bool init;
60 } _img_bincue_snk_t;
61 
62 static void
_sink_init(_img_bincue_snk_t * _obj)63 _sink_init (_img_bincue_snk_t *_obj)
64 {
65   if (_obj->init)
66     return;
67 
68   if (!(_obj->bin_snk = vcd_data_sink_new_stdio (_obj->bin_fname)))
69     vcd_error ("init failed");
70 
71   if (!(_obj->cue_snk = vcd_data_sink_new_stdio (_obj->cue_fname)))
72     vcd_error ("init failed");
73 
74   _obj->init = true;
75 }
76 
77 static void
_sink_free(void * user_data)78 _sink_free (void *user_data)
79 {
80   _img_bincue_snk_t *_obj = user_data;
81 
82   vcd_data_sink_destroy (_obj->bin_snk);
83   vcd_data_sink_destroy (_obj->cue_snk);
84   free (_obj->bin_fname);
85   free (_obj->cue_fname);
86   free (_obj);
87 }
88 
89 static int
_set_cuesheet(void * user_data,const CdioList_t * vcd_cue_list)90 _set_cuesheet (void *user_data, const CdioList_t *vcd_cue_list)
91 {
92   _img_bincue_snk_t *_obj = user_data;
93   CdioListNode_t *node;
94   int track_no, index_no;
95   const vcd_cue_t *_last_cue = 0;
96 
97   _sink_init (_obj);
98 
99   vcd_data_sink_printf (_obj->cue_snk, "FILE \"%s\" BINARY\r\n",
100 			_obj->bin_fname);
101 
102   track_no = 0;
103   index_no = 0;
104   _CDIO_LIST_FOREACH (node, (CdioList_t *) vcd_cue_list)
105     {
106       const vcd_cue_t *_cue = _cdio_list_node_data (node);
107       char *psz_msf;
108 
109       msf_t _msf = { 0, 0, 0 };
110 
111       switch (_cue->type)
112 	{
113 	case VCD_CUE_TRACK_START:
114 	  track_no++;
115 	  index_no = 0;
116 
117 	  vcd_data_sink_printf (_obj->cue_snk,
118 				"  TRACK %2.2d MODE2/%d\r\n"
119 				"    FLAGS DCP\r\n",
120 				track_no, (_obj->sector_2336_flag ? 2336 : 2352));
121 
122 	  if (_last_cue && _last_cue->type == VCD_CUE_PREGAP_START)
123 	    {
124 	      cdio_lba_to_msf (_last_cue->lsn, &_msf);
125 	      psz_msf = cdio_msf_to_str(&_msf);
126 
127 	      vcd_data_sink_printf (_obj->cue_snk,
128 				    "    INDEX %2.2d %s\r\n",
129 				    index_no, psz_msf);
130 	      free(psz_msf);
131 	    }
132 
133 	  index_no++;
134 
135 	  cdio_lba_to_msf (_cue->lsn, &_msf);
136 	  psz_msf = cdio_msf_to_str(&_msf);
137 
138 	  vcd_data_sink_printf (_obj->cue_snk,
139 				"    INDEX %2.2d %s\r\n",
140 				index_no, psz_msf);
141 	  free(psz_msf);
142 	  break;
143 
144 	case VCD_CUE_PREGAP_START:
145 	  /* handled in next iteration */
146 	  break;
147 
148 	case VCD_CUE_SUBINDEX:
149 	  vcd_assert (_last_cue != 0);
150 
151 	  index_no++;
152 	  vcd_assert (index_no <= CDIO_CD_MAX_TRACKS);
153 
154 	  cdio_lba_to_msf (_cue->lsn, &_msf);
155 	  psz_msf = cdio_msf_to_str(&_msf);
156 
157 	  vcd_data_sink_printf (_obj->cue_snk,
158 				"    INDEX %2.2d %s\r\n",
159 				index_no, psz_msf);
160 	  free(psz_msf);
161 	  break;
162 
163 	case VCD_CUE_END:
164 	  vcd_data_sink_close (_obj->cue_snk);
165 	  return 0;
166 	  break;
167 
168 	case VCD_CUE_LEADIN:
169 	  break;
170 	}
171 
172       _last_cue = _cue;
173     }
174 
175   vcd_assert_not_reached ();
176 
177   return -1;
178 }
179 
180 static int
_vcd_image_bincue_write(void * user_data,const void * data,lsn_t lsn)181 _vcd_image_bincue_write (void *user_data, const void *data, lsn_t lsn)
182 {
183   const char *buf = data;
184   _img_bincue_snk_t *_obj = user_data;
185   long offset = lsn;
186 
187   _sink_init (_obj);
188 
189   offset *= _obj->sector_2336_flag ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW;
190 
191   vcd_data_sink_seek(_obj->bin_snk, offset);
192 
193   if (_obj->sector_2336_flag)
194     vcd_data_sink_write(_obj->bin_snk, buf + 12 + 4, M2RAW_SECTOR_SIZE, 1);
195   else
196     vcd_data_sink_write(_obj->bin_snk, buf, CDIO_CD_FRAMESIZE_RAW, 1);
197 
198   return 0;
199 }
200 
201 static int
_sink_set_arg(void * user_data,const char key[],const char value[])202 _sink_set_arg (void *user_data, const char key[], const char value[])
203 {
204   _img_bincue_snk_t *_obj = user_data;
205 
206   if (!strcmp (key, "bin"))
207     {
208       free (_obj->bin_fname);
209 
210       if (!value)
211 	return -2;
212 
213       _obj->bin_fname = strdup (value);
214     }
215   else if (!strcmp (key, "cue"))
216     {
217       free (_obj->cue_fname);
218 
219       if (!value)
220 	return -2;
221 
222       _obj->cue_fname = strdup (value);
223     }
224   else if (!strcmp (key, "sector"))
225     {
226       if (!strcmp (value, "2336"))
227 	_obj->sector_2336_flag = true;
228       else if (!strcmp (value, "2352"))
229 	_obj->sector_2336_flag = false;
230       else
231 	return -2;
232     }
233   else
234     return -1;
235 
236   return 0;
237 }
238 
239 VcdImageSink_t *
vcd_image_sink_new_bincue(void)240 vcd_image_sink_new_bincue (void)
241 {
242   _img_bincue_snk_t *_data;
243 
244   vcd_image_sink_funcs _funcs = {
245     .set_cuesheet = _set_cuesheet,
246     .write        = _vcd_image_bincue_write,
247     .free         = _sink_free,
248     .set_arg      = _sink_set_arg
249   };
250 
251   _data = calloc(1, sizeof (_img_bincue_snk_t));
252 
253   _data->bin_fname = strdup ("videocd.bin");
254   _data->cue_fname = strdup ("videocd.cue");
255 
256   return vcd_image_sink_new (_data, &_funcs);
257 }
258