/* $Id: image_cdrdao.c,v 1.3 2005/01/01 02:43:59 rockyb Exp $ Copyright (C) 2001 Herbert Valerio Riedel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include /* Public headers */ #include #include #include #include /* Private headers */ #include "vcd_assert.h" #include "image_sink.h" #include "stream_stdio.h" #include "util.h" #include "vcd.h" static const char _rcsid[] = "$Id: image_cdrdao.c,v 1.3 2005/01/01 02:43:59 rockyb Exp $"; /* reader */ /**************************************************************************** * writer */ typedef struct { bool sector_2336_flag; char *toc_fname; char *img_base; VcdDataSink *last_bin_snk; int last_snk_idx; bool last_pause; CdioList *vcd_cue_list; } _img_cdrdao_snk_t; static void _sink_free (void *user_data) { _img_cdrdao_snk_t *_obj = user_data; /* fixme -- destroy cue list */ vcd_data_sink_destroy (_obj->last_bin_snk); free (_obj->toc_fname); free (_obj->img_base); free (_obj); } static int _set_cuesheet (void *user_data, const CdioList *vcd_cue_list) { _img_cdrdao_snk_t *_obj = user_data; VcdDataSink *toc_snk = vcd_data_sink_new_stdio (_obj->toc_fname); CdioListNode *node; int track_no, index_no; const vcd_cue_t *_last_cue = 0; unsigned last_track_lsn = 0; vcd_data_sink_printf (toc_snk, "// CDRDAO TOC\n" "// generated by %s\n\n" "CD_ROM_XA\n", vcd_version_string (false)); _obj->vcd_cue_list = _cdio_list_new (); index_no = track_no = 0; _CDIO_LIST_FOREACH (node, (CdioList *) vcd_cue_list) { const vcd_cue_t *_cue = _cdio_list_node_data (node); /* copy cue list while traversing */ { vcd_cue_t *_cue2 = _vcd_malloc (sizeof (vcd_cue_t)); *_cue2 = *_cue; _cdio_list_append (_obj->vcd_cue_list, _cue2); } switch (_cue->type) { case VCD_CUE_TRACK_START: track_no++; index_no = 0; last_track_lsn = _cue->lsn; vcd_data_sink_printf (toc_snk, "\n// Track %d\n" "TRACK %s\n COPY\n", track_no, (_obj->sector_2336_flag ? "MODE2_FORM_MIX" : "MODE2_RAW")); if (_last_cue && _last_cue->type == VCD_CUE_PREGAP_START) vcd_data_sink_printf (toc_snk, " DATAFILE \"%s_%.2d_pregap.img\"\n" " START\n", _obj->img_base, track_no); index_no++; vcd_data_sink_printf (toc_snk, " DATAFILE \"%s_%.2d.img\"\n", _obj->img_base, track_no); break; case VCD_CUE_PREGAP_START: /* handled in next iteration */ break; case VCD_CUE_SUBINDEX: index_no++; { msf_t _msf = { 0, 0, 0 }; char *psz_msf; cdio_lba_to_msf (_cue->lsn - last_track_lsn, &_msf); psz_msf = cdio_msf_to_str(&_msf); vcd_data_sink_printf (toc_snk, " INDEX %s\n", psz_msf); free(psz_msf); } break; case VCD_CUE_LEADIN: break; case VCD_CUE_END: vcd_data_sink_printf (toc_snk, "\n// EOF\n"); vcd_data_sink_close (toc_snk); vcd_data_sink_destroy (toc_snk); return 0; break; } _last_cue = _cue; } vcd_assert_not_reached (); return -1; } static int _vcd_image_cdrdao_write (void *user_data, const void *data, lsn_t lsn) { const char *buf = data; _img_cdrdao_snk_t *_obj = user_data; long offset; { CdioListNode *node; uint32_t _last = 0; uint32_t _ofs = 0; bool _lpregap = false; bool _pregap = false; int num = 0, in_track = 0; _CDIO_LIST_FOREACH (node, _obj->vcd_cue_list) { const vcd_cue_t *_cue = _cdio_list_node_data (node); switch (_cue->type) { case VCD_CUE_PREGAP_START: case VCD_CUE_END: case VCD_CUE_TRACK_START: if (_cue->lsn && IN (lsn, _last, _cue->lsn - 1)) { vcd_assert (in_track == 0); in_track = num; _ofs = _last; _pregap = _lpregap; } _last = _cue->lsn; _lpregap = (_cue->type == VCD_CUE_PREGAP_START); if (_cue->type == VCD_CUE_TRACK_START) num++; break; default: /* noop */ break; } } vcd_assert (in_track != 0); vcd_assert (_obj->last_snk_idx <= in_track); if (_obj->last_snk_idx != in_track || _obj->last_pause != _pregap) { char buf[4096] = { 0, }; if (_obj->last_bin_snk) vcd_data_sink_destroy (_obj->last_bin_snk); snprintf (buf, sizeof (buf), "%s_%.2d%s.img", _obj->img_base, (_pregap ? in_track + 1 : in_track), (_pregap ? "_pregap" : "")); _obj->last_bin_snk = vcd_data_sink_new_stdio (buf); _obj->last_snk_idx = in_track; _obj->last_pause = _pregap; } vcd_assert (lsn >= _ofs); offset = lsn - _ofs; } offset *= _obj->sector_2336_flag ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; vcd_data_sink_seek(_obj->last_bin_snk, offset); if (_obj->sector_2336_flag) vcd_data_sink_write(_obj->last_bin_snk, buf + 12 + 4, M2RAW_SECTOR_SIZE, 1); else vcd_data_sink_write(_obj->last_bin_snk, buf, CDIO_CD_FRAMESIZE_RAW, 1); return 0; } static int _sink_set_arg (void *user_data, const char key[], const char value[]) { _img_cdrdao_snk_t *_obj = user_data; if (!strcmp (key, "toc")) { free (_obj->toc_fname); if (!value) return -2; _obj->toc_fname = strdup (value); } else if (!strcmp (key, "img_base")) { free (_obj->img_base); if (!value) return -2; _obj->img_base = strdup (value); } else if (!strcmp (key, "sector")) { if (!strcmp (value, "2336")) _obj->sector_2336_flag = true; else if (!strcmp (value, "2352")) _obj->sector_2336_flag = false; else return -2; } else return -1; return 0; } VcdImageSink * vcd_image_sink_new_cdrdao (void) { _img_cdrdao_snk_t *_data; vcd_image_sink_funcs _funcs = { .set_cuesheet = _set_cuesheet, .write = _vcd_image_cdrdao_write, .free = _sink_free, .set_arg = _sink_set_arg }; _data = _vcd_malloc (sizeof (_img_cdrdao_snk_t)); _data->toc_fname = strdup ("videocd.toc"); _data->img_base = strdup ("videocd"); return vcd_image_sink_new (_data, &_funcs); }