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