|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2010 William Hahne
|
|
Packit |
5e46da |
* Copyright (C) 2014 Petri Hintukainen <phintuka@users.sourceforge.net>
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is free software; you can redistribute it and/or
|
|
Packit |
5e46da |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License as published by the Free Software Foundation; either
|
|
Packit |
5e46da |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
5e46da |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e46da |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
5e46da |
* Lesser General Public License for more details.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License along with this library. If not, see
|
|
Packit |
5e46da |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if HAVE_CONFIG_H
|
|
Packit |
5e46da |
#include "config.h"
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "bdjo_parse.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "bdjo_data.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "disc/disc.h"
|
|
Packit |
5e46da |
#include "bdnav/bdmv_parse.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "file/file.h"
|
|
Packit |
5e46da |
#include "util/bits.h"
|
|
Packit |
5e46da |
#include "util/logging.h"
|
|
Packit |
5e46da |
#include "util/macro.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <string.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static char *_read_string(BITSTREAM* bs, uint32_t length)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
char *out = malloc(length + 1);
|
|
Packit |
5e46da |
if (out) {
|
|
Packit |
5e46da |
bs_read_string(bs, out, length);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
bs_skip(bs, length * 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return out;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_TERMINAL_INFO */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_terminal_info(BITSTREAM* bs, BDJO_TERMINAL_INFO *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
bs_skip(bs, 32); // skip length
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_read_string(bs, p->default_font, 5);
|
|
Packit |
5e46da |
p->initial_havi_config_id = bs_read(bs, 4);
|
|
Packit |
5e46da |
p->menu_call_mask = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->title_search_mask = bs_read(bs, 1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 34); // skip padding
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP_CACHE_ITEM */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _parse_app_cache_item(BITSTREAM* bs, BDJO_APP_CACHE_ITEM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
p->type = bs_read(bs, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_read_string(bs, p->ref_to_name, 5);
|
|
Packit |
5e46da |
bs_read_string(bs, p->lang_code, 3);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 24); // skip padding
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP_CACHE_INFO */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_app_cache_info(BDJO_APP_CACHE_INFO *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
X_FREE(p->item);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_app_cache_info(BITSTREAM* bs, BDJO_APP_CACHE_INFO *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 32); // skip length
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->num_item = bs_read(bs, 8);
|
|
Packit |
5e46da |
bs_skip(bs, 8); // skip padding
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->item = calloc(p->num_item, sizeof(BDJO_APP_CACHE_ITEM));
|
|
Packit |
5e46da |
if (!p->item) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_item; ii++) {
|
|
Packit |
5e46da |
_parse_app_cache_item(bs, &p->item[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_ACCESSIBLE_PLAYLISTS */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_accessible_playlists(BDJO_ACCESSIBLE_PLAYLISTS *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
X_FREE(p->pl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_accessible_playlists(BITSTREAM* bs, BDJO_ACCESSIBLE_PLAYLISTS *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 32); // skip length
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->num_pl = bs_read(bs, 11);
|
|
Packit |
5e46da |
p->access_to_all_flag = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->autostart_first_playlist_flag = bs_read(bs, 1);
|
|
Packit |
5e46da |
bs_skip(bs, 19); // skip padding
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->pl = calloc(p->num_pl, sizeof(BDJO_PLAYLIST));
|
|
Packit |
5e46da |
if (!p->pl) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_pl; ii++) {
|
|
Packit |
5e46da |
bs_read_string(bs, p->pl[ii].name, 5);
|
|
Packit |
5e46da |
bs_skip(bs, 8); // skip padding
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP_PROFILE */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _parse_app_profile(BITSTREAM *bs, BDJO_APP_PROFILE *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
p->profile_number = bs_read(bs, 16);
|
|
Packit |
5e46da |
p->major_version = bs_read(bs, 8);
|
|
Packit |
5e46da |
p->minor_version = bs_read(bs, 8);
|
|
Packit |
5e46da |
p->micro_version = bs_read(bs, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP_NAME */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_app_name(BDJO_APP_NAME *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
X_FREE(p->name);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _count_app_strings(BITSTREAM *bs, uint16_t data_length, uint16_t prefix_bytes, const char *type)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int count = 0;
|
|
Packit |
5e46da |
uint32_t bytes_read = 0;
|
|
Packit |
5e46da |
int64_t pos = bs_pos(bs) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
while (bytes_read < data_length) {
|
|
Packit |
5e46da |
bs_skip(bs, prefix_bytes * 8);
|
|
Packit |
5e46da |
uint8_t length = bs_read(bs, 8);
|
|
Packit |
5e46da |
bs_skip(bs, 8 * length);
|
|
Packit |
5e46da |
bytes_read += prefix_bytes + 1 + length;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// seek back
|
|
Packit |
5e46da |
if (bytes_read) {
|
|
Packit |
5e46da |
if (bs_seek_byte(bs, pos) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bytes_read != data_length) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "data size mismatch (%d/%d), skipping %s\n", bytes_read, data_length, type);
|
|
Packit |
5e46da |
count = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return count;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_app_name(BITSTREAM *bs, BDJO_APP_NAME *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
bs_read_string(bs, p->lang, 3);
|
|
Packit |
5e46da |
uint32_t length = bs_read(bs, 8);
|
|
Packit |
5e46da |
p->name = _read_string(bs, length);
|
|
Packit |
5e46da |
return p->name ? 1 : -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP_PARAM */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_app_param(BDJO_APP_PARAM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
X_FREE(p->param);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_app_param(BITSTREAM *bs, BDJO_APP_PARAM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t length = bs_read(bs, 8);
|
|
Packit |
5e46da |
p->param = _read_string(bs, length);
|
|
Packit |
5e46da |
return p->param ? 1 : -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_bdjo_app(BDJO_APP *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_name; ii++) {
|
|
Packit |
5e46da |
_clean_app_name(&p->name[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_param; ii++) {
|
|
Packit |
5e46da |
_clean_app_param(&p->param[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(p->profile);
|
|
Packit |
5e46da |
X_FREE(p->name);
|
|
Packit |
5e46da |
X_FREE(p->icon_locator);
|
|
Packit |
5e46da |
X_FREE(p->base_dir);
|
|
Packit |
5e46da |
X_FREE(p->classpath_extension);
|
|
Packit |
5e46da |
X_FREE(p->initial_class);
|
|
Packit |
5e46da |
X_FREE(p->param);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static char *_read_app_string(BITSTREAM *bs)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
char *result;
|
|
Packit |
5e46da |
uint8_t length = bs_read(bs, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = _read_string(bs, length);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// word align
|
|
Packit |
5e46da |
if (!(length & 1))
|
|
Packit |
5e46da |
bs_skip(bs, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_app_names(BITSTREAM *bs, BDJO_APP *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
int r;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t data_length = bs_read(bs, 16);
|
|
Packit |
5e46da |
r = _count_app_strings(bs, data_length, 3, "names");
|
|
Packit |
5e46da |
if (r < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->num_name = r;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (data_length == 0) return 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->num_name) {
|
|
Packit |
5e46da |
p->name = calloc(p->num_name, sizeof(BDJO_APP_NAME));
|
|
Packit |
5e46da |
if (!p->name) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_name; ii++) {
|
|
Packit |
5e46da |
if (_parse_app_name(bs, &p->name[ii]) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
// ignore invalid data (seek over chunk)
|
|
Packit |
5e46da |
bs_skip(bs, data_length*8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// word align
|
|
Packit |
5e46da |
bs_skip(bs, 8 * (data_length & 1));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_app_params(BITSTREAM *bs, BDJO_APP *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
int r;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t data_length = bs_read(bs, 8);
|
|
Packit |
5e46da |
r = _count_app_strings(bs, data_length, 0, "params");
|
|
Packit |
5e46da |
if (r < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->num_param = r;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->num_param) {
|
|
Packit |
5e46da |
p->param = calloc(p->num_param, sizeof(BDJO_APP_PARAM));
|
|
Packit |
5e46da |
if (!p->param) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_param; ii++) {
|
|
Packit |
5e46da |
if (_parse_app_param(bs, &p->param[ii]) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
// ignore invalid data (seek over chunk)
|
|
Packit |
5e46da |
bs_skip(bs, data_length*8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// word align
|
|
Packit |
5e46da |
if (!(data_length & 1))
|
|
Packit |
5e46da |
bs_skip(bs, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_bdjo_app(BITSTREAM *bs, BDJO_APP *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->control_code = bs_read(bs, 8);
|
|
Packit |
5e46da |
p->type = bs_read(bs, 4);
|
|
Packit |
5e46da |
bs_skip(bs, 4);
|
|
Packit |
5e46da |
p->org_id = bs_read(bs, 32);
|
|
Packit |
5e46da |
p->app_id = bs_read(bs, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 80); // skip sescriptor tag and length
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* application descriptor */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->num_profile = bs_read(bs, 4);
|
|
Packit |
5e46da |
bs_skip(bs, 12); // skip padding
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->profile = calloc(p->num_profile, sizeof(BDJO_APP_PROFILE));
|
|
Packit |
5e46da |
if (!p->profile) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_profile; ii++) {
|
|
Packit |
5e46da |
_parse_app_profile(bs, &p->profile[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->priority = bs_read(bs, 8);
|
|
Packit |
5e46da |
p->binding = bs_read(bs, 2);
|
|
Packit |
5e46da |
p->visibility = bs_read(bs, 2);
|
|
Packit |
5e46da |
bs_skip(bs, 4);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_parse_app_names(bs, p) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->icon_locator = _read_app_string(bs);
|
|
Packit |
5e46da |
if (!p->icon_locator) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->icon_flags = bs_read(bs, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->base_dir = _read_app_string(bs);
|
|
Packit |
5e46da |
if (!p->base_dir) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->classpath_extension = _read_app_string(bs);
|
|
Packit |
5e46da |
if (!p->classpath_extension) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->initial_class = _read_app_string(bs);
|
|
Packit |
5e46da |
if (!p->initial_class) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_parse_app_params(bs, p) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_APP_MANAGEMENT_TABLE */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_app_management_table(BDJO_APP_MANAGEMENT_TABLE *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_app; ii++) {
|
|
Packit |
5e46da |
_clean_bdjo_app(&p->app[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(p->app);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_app_management_table(BITSTREAM *bs, BDJO_APP_MANAGEMENT_TABLE *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 32); // length
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->num_app = bs_read(bs, 8);
|
|
Packit |
5e46da |
bs_skip(bs, 8); // skip padding
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->app = calloc(p->num_app, sizeof(BDJO_APP));
|
|
Packit |
5e46da |
if (!p->app) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < p->num_app; ii++) {
|
|
Packit |
5e46da |
/* TODO: if parsing of application data fails, ignore that app but parse others */
|
|
Packit |
5e46da |
if (_parse_bdjo_app(bs, &p->app[ii]) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_KEY_INTEREST_TABLE */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_key_interest_table(BITSTREAM *bs, BDJO_KEY_INTEREST_TABLE *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
p->vk_play = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_stop = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_ffw = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_rew = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_track_next = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_track_prev = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_pause = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_still_off = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_sec_audio_ena_dis = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->vk_sec_video_ena_dis = bs_read(bs, 1);
|
|
Packit |
5e46da |
p->pg_textst_ena_dis = bs_read(bs, 1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 21);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO_FILE_ACCESS_INFO */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_file_access_info(BDJO_FILE_ACCESS_INFO *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
X_FREE(p->path);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_file_access_info(BITSTREAM *bs, BDJO_FILE_ACCESS_INFO *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint16_t file_access_length = bs_read(bs, 16);
|
|
Packit |
5e46da |
p->path = _read_string(bs, file_access_length);
|
|
Packit |
5e46da |
return p->path ? 1 : -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* BDJO */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_bdjo(BDJO *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
_clean_app_cache_info(&p->app_cache_info);
|
|
Packit |
5e46da |
_clean_accessible_playlists(&p->accessible_playlists);
|
|
Packit |
5e46da |
_clean_app_management_table(&p->app_table);
|
|
Packit |
5e46da |
_clean_file_access_info(&p->file_access_info);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define BDJO_SIG1 ('B' << 24 | 'D' << 16 | 'J' << 8 | 'O')
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_header(BITSTREAM *bs, uint32_t *bdjo_version)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!bdmv_parse_header(bs, BDJO_SIG1, bdjo_version)) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "[bdj] BDJO > Version: %.4s\n", (const char *)bdjo_version);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// skip address table
|
|
Packit |
5e46da |
bs_skip(bs, 8*40);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static BDJO *_bdjo_parse(BD_FILE_H *fp)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BITSTREAM bs;
|
|
Packit |
5e46da |
BDJO *p;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_init(&bs, fp) < 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "?????.bdjo: read error\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p = calloc(1, sizeof(BDJO));
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Out of memory\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_parse_header(&bs, &p->bdjo_version) < 0 ||
|
|
Packit |
5e46da |
_parse_terminal_info(&bs, &p->terminal_info) < 0 ||
|
|
Packit |
5e46da |
_parse_app_cache_info(&bs, &p->app_cache_info) < 0 ||
|
|
Packit |
5e46da |
_parse_accessible_playlists(&bs, &p->accessible_playlists) < 0 ||
|
|
Packit |
5e46da |
_parse_app_management_table(&bs, &p->app_table) < 0 ||
|
|
Packit |
5e46da |
_parse_key_interest_table(&bs, &p->key_interest_table) < 0 ||
|
|
Packit |
5e46da |
_parse_file_access_info(&bs, &p->file_access_info) < 0) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bdjo_free(&p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return p;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void bdjo_free(BDJO **pp)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (pp && *pp) {
|
|
Packit |
5e46da |
_clean_bdjo(*pp);
|
|
Packit |
5e46da |
X_FREE(*pp);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDJO *bdjo_parse(const char *path)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_FILE_H *fp;
|
|
Packit |
5e46da |
BDJO *bdjo;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
fp = file_open(path, "rb");
|
|
Packit |
5e46da |
if (!fp) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to open bdjo file (%s)\n", path);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bdjo = _bdjo_parse(fp);
|
|
Packit |
5e46da |
file_close(fp);
|
|
Packit |
5e46da |
return bdjo;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static BDJO *_bdjo_get(BD_DISC *disc, const char *dir, const char *file)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_FILE_H *fp;
|
|
Packit |
5e46da |
BDJO *bdjo;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
fp = disc_open_file(disc, dir, file);
|
|
Packit |
5e46da |
if (!fp) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bdjo = _bdjo_parse(fp);
|
|
Packit |
5e46da |
file_close(fp);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return bdjo;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDJO *bdjo_get(BD_DISC *disc, const char *file)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BDJO *bdjo;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bdjo = _bdjo_get(disc, "BDMV" DIR_SEP "BDJO", file);
|
|
Packit |
5e46da |
if (bdjo) {
|
|
Packit |
5e46da |
return bdjo;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* if failed, try backup file */
|
|
Packit |
5e46da |
bdjo = _bdjo_get(disc, "BDMV" DIR_SEP "BACKUP" DIR_SEP "BDJO", file);
|
|
Packit |
5e46da |
return bdjo;
|
|
Packit |
5e46da |
}
|