/* $Id: info_private.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ Copyright (C) 2003 Rocky Bernstein 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 #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include /* 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: */