Blame src/libbluray/bdj/bdjo_parse.c

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
}