diff options
Diffstat (limited to 'src/input/vcd/libvcd/info_private.c')
-rw-r--r-- | src/input/vcd/libvcd/info_private.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/input/vcd/libvcd/info_private.c b/src/input/vcd/libvcd/info_private.c new file mode 100644 index 000000000..e0297d344 --- /dev/null +++ b/src/input/vcd/libvcd/info_private.c @@ -0,0 +1,318 @@ +/* + $Id: info_private.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 Foundation + Software, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + Like vcdinfo but exposes more of the internal structure. It is probably + better to use vcdinfo, when possible. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stddef.h> +#include <errno.h> + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <cdio/cdio.h> +#include <cdio/util.h> + +#include <libvcd/types.h> +#include <libvcd/files.h> + +#include <libvcd/info.h> + +/* Private headers */ +#include "assert.h" +#include "bytesex.h" +#include "data_structures.h" +#include "info_private.h" +#include "pbc.h" + +static const char _rcsid[] = "$Id: info_private.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +/* + This fills in unassigned LIDs in the offset table. Due to + "rejected" LOT entries, some of these might not have gotten filled + in while scanning PBC (if in fact there even was a PBC). + + Note: We assume that an unassigned LID is one whose value is 0. + */ +static void +vcdinf_update_offset_list(struct _vcdinf_pbc_ctx *obj, bool extended) +{ + if (NULL==obj) return; + { + VcdListNode *node; + VcdList *unused_lids = _vcd_list_new(); + VcdListNode *next_unused_node = _vcd_list_begin(unused_lids); + + unsigned int last_lid=0; + VcdList *offset_list = extended ? obj->offset_x_list : obj->offset_list; + + lid_t max_seen_lid=0; + + _VCD_LIST_FOREACH (node, offset_list) + { + vcdinfo_offset_t *ofs = _vcd_list_node_data (node); + if (!ofs->lid) { + /* We have a customer! Assign a LID from the free pool + or take one from the end if no skipped LIDs. + */ + VcdListNode *node=_vcd_list_node_next(next_unused_node); + if (node != NULL) { + lid_t *next_unused_lid=_vcd_list_node_data(node); + ofs->lid = *next_unused_lid; + next_unused_node=node; + } else { + max_seen_lid++; + ofs->lid = max_seen_lid; + } + } else { + /* See if we've skipped any LID numbers. */ + last_lid++; + while (last_lid != ofs->lid ) { + lid_t * lid=_vcd_malloc (sizeof(lid_t)); + *lid = last_lid; + _vcd_list_append(unused_lids, lid); + } + if (last_lid > max_seen_lid) max_seen_lid=last_lid; + } + } + _vcd_list_free(unused_lids, true); + } +} + +/*! + Calls recursive routine to populate obj->offset_list or obj->offset_x_list + by going through LOT. +*/ +void +vcdinf_visit_lot (struct _vcdinf_pbc_ctx *obj) +{ + const LotVcd *lot = obj->extended ? obj->lot_x : obj->lot; + unsigned int n, tmp; + + if (obj->extended) { + if (!obj->psd_x_size) return; + } else if (!obj->psd_size) return; + + for (n = 0; n < LOT_VCD_OFFSETS; n++) + if ((tmp = vcdinf_get_lot_offset(lot, n)) != PSD_OFS_DISABLED) + vcdinf_visit_pbc (obj, n + 1, tmp, true); + + _vcd_list_sort (obj->extended ? obj->offset_x_list : obj->offset_list, + (_vcd_list_cmp_func) vcdinf_lid_t_cmp); + + /* Now really complete the offset table with LIDs. This routine + might obviate the need for vcdinf_visit_pbc() or some of it which is + more complex. */ + vcdinf_update_offset_list(obj, obj->extended); +} + +/*! + Recursive routine to populate obj->offset_list or obj->offset_x_list + by reading playback control entries referred to via lid. +*/ +void +vcdinf_visit_pbc (struct _vcdinf_pbc_ctx *obj, lid_t lid, unsigned int offset, + bool in_lot) +{ + VcdListNode *node; + vcdinfo_offset_t *ofs; + unsigned int psd_size = obj->extended ? obj->psd_x_size : obj->psd_size; + const uint8_t *psd = obj->extended ? obj->psd_x : obj->psd; + unsigned int _rofs = offset * obj->offset_mult; + VcdList *offset_list; + + vcd_assert (psd_size % 8 == 0); + + switch (offset) + { + case PSD_OFS_DISABLED: + case PSD_OFS_MULTI_DEF: + case PSD_OFS_MULTI_DEF_NO_NUM: + return; + + default: + break; + } + + if (_rofs >= psd_size) + { + if (obj->extended) + vcd_error ("psd offset out of range in extended PSD" + " (try --no-ext-psd option)"); + else + vcd_warn ("psd offset out of range (%d >= %d)", _rofs, psd_size); + return; + } + + vcd_assert (_rofs < psd_size); + + if (!obj->offset_list) + obj->offset_list = _vcd_list_new (); + + if (!obj->offset_x_list) + obj->offset_x_list = _vcd_list_new (); + + if (obj->extended) { + offset_list = obj->offset_x_list; + } else + offset_list = obj->offset_list; + + _VCD_LIST_FOREACH (node, offset_list) + { + ofs = _vcd_list_node_data (node); + + if (offset == ofs->offset) + { + if (in_lot) + ofs->in_lot = true; + + if (lid) { + /* Our caller thinks she knows what our LID is. + This should help out getting the LID for end descriptors + if not other things as well. + */ + ofs->lid = lid; + } + + ofs->ext = obj->extended; + + return; /* already been there... */ + } + } + + ofs = _vcd_malloc (sizeof (vcdinfo_offset_t)); + + ofs->ext = obj->extended; + ofs->in_lot = in_lot; + ofs->lid = lid; + ofs->offset = offset; + ofs->type = psd[_rofs]; + + switch (ofs->type) + { + case PSD_TYPE_PLAY_LIST: + _vcd_list_append (offset_list, ofs); + { + const PsdPlayListDescriptor *d = (const void *) (psd + _rofs); + const lid_t lid = vcdinf_pld_get_lid(d); + + if (!ofs->lid) + ofs->lid = lid; + else + if (ofs->lid != lid) + vcd_warn ("LOT entry assigned LID %d, but descriptor has LID %d", + ofs->lid, lid); + + vcdinf_visit_pbc (obj, 0, vcdinf_pld_get_prev_offset(d), false); + vcdinf_visit_pbc (obj, 0, vcdinf_pld_get_next_offset(d), false); + vcdinf_visit_pbc (obj, 0, vcdinf_pld_get_return_offset(d), false); + } + break; + + case PSD_TYPE_EXT_SELECTION_LIST: + case PSD_TYPE_SELECTION_LIST: + _vcd_list_append (offset_list, ofs); + { + const PsdSelectionListDescriptor *d = + (const void *) (psd + _rofs); + + int idx; + + if (!ofs->lid) + ofs->lid = uint16_from_be (d->lid) & 0x7fff; + else + if (ofs->lid != (uint16_from_be (d->lid) & 0x7fff)) + vcd_warn ("LOT entry assigned LID %d, but descriptor has LID %d", + ofs->lid, uint16_from_be (d->lid) & 0x7fff); + + vcdinf_visit_pbc (obj, 0, vcdinf_psd_get_prev_offset(d), false); + vcdinf_visit_pbc (obj, 0, vcdinf_psd_get_next_offset(d), false); + vcdinf_visit_pbc (obj, 0, vcdinf_psd_get_return_offset(d), false); + vcdinf_visit_pbc (obj, 0, vcdinf_psd_get_default_offset(d), false); + vcdinf_visit_pbc (obj, 0, uint16_from_be (d->timeout_ofs), false); + + for (idx = 0; idx < vcdinf_get_num_selections(d); idx++) + vcdinf_visit_pbc (obj, 0, vcdinf_psd_get_offset(d, idx), + false); + } + break; + + case PSD_TYPE_END_LIST: + _vcd_list_append (offset_list, ofs); + break; + + default: + vcd_warn ("corrupt PSD???????"); + free (ofs); + return; + break; + } +} + +/*! Return the starting LBA (logical block address) for sequence + entry_num in obj. VCDINFO_NULL_LBA is returned if there is no entry. +*/ +lba_t +vcdinf_get_entry_lba(const EntriesVcd *entries, unsigned int entry_num) +{ + const msf_t *msf = vcdinf_get_entry_msf(entries, entry_num); + return (msf != NULL) ? cdio_msf_to_lba(msf) : VCDINFO_NULL_LBA; +} + +/*! Return the starting MSF (minutes/secs/frames) for sequence + entry_num in obj. NULL is returned if there is no entry. + The first entry number is 0. +*/ +const msf_t * +vcdinf_get_entry_msf(const EntriesVcd *entries, unsigned int entry_num) +{ + const unsigned int entry_count = uint16_from_be (entries->entry_count); + return entry_num < entry_count ? + &(entries->entry[entry_num].msf) + : NULL; +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ |