|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2010 fraxinas
|
|
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 "meta_parse.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "meta_data.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "disc/disc.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 |
#include "util/strutl.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <string.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef HAVE_STRINGS_H
|
|
Packit |
5e46da |
#include <strings.h>
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef HAVE_LIBXML2
|
|
Packit |
5e46da |
#include <libxml/parser.h>
|
|
Packit |
5e46da |
#include <libxml/xmlmemory.h>
|
|
Packit |
5e46da |
#include <libxml/tree.h>
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define DEFAULT_LANGUAGE "eng"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define BAD_CAST_CONST (const xmlChar *)
|
|
Packit |
5e46da |
#define XML_FREE(p) (xmlFree(p), p = NULL)
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define MAX_META_FILE_SIZE 0xfffff
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
struct meta_root {
|
|
Packit |
5e46da |
uint8_t dl_count;
|
|
Packit |
5e46da |
META_DL * dl_entries;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef HAVE_LIBXML2
|
|
Packit |
5e46da |
static void _parseManifestNode(xmlNode * a_node, META_DL *disclib)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
xmlNode *cur_node = NULL;
|
|
Packit |
5e46da |
xmlChar *tmp;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
|
|
Packit |
5e46da |
if (cur_node->type == XML_ELEMENT_NODE) {
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "title")) {
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "name")) {
|
|
Packit |
5e46da |
disclib->di_name = (char*)xmlNodeGetContent(cur_node);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "alternative")) {
|
|
Packit |
5e46da |
disclib->di_alternative = (char*)xmlNodeGetContent(cur_node);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "numSets")) {
|
|
Packit |
5e46da |
disclib->di_num_sets = atoi((char*)(tmp = xmlNodeGetContent(cur_node)));
|
|
Packit |
5e46da |
XML_FREE(tmp);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "setNumber")) {
|
|
Packit |
5e46da |
disclib->di_set_number = atoi((char*)(tmp = xmlNodeGetContent(cur_node)));
|
|
Packit |
5e46da |
XML_FREE(tmp);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
else if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "tableOfContents")) {
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "titleName") && (tmp = xmlGetProp(cur_node, BAD_CAST_CONST "titleNumber"))) {
|
|
Packit |
5e46da |
META_TITLE *new_entries = realloc(disclib->toc_entries, ((disclib->toc_count + 1)*sizeof(META_TITLE)));
|
|
Packit |
5e46da |
if (new_entries) {
|
|
Packit |
5e46da |
int i = disclib->toc_count;
|
|
Packit |
5e46da |
disclib->toc_count++;
|
|
Packit |
5e46da |
disclib->toc_entries = new_entries;
|
|
Packit |
5e46da |
disclib->toc_entries[i].title_number = atoi((const char*)tmp);
|
|
Packit |
5e46da |
disclib->toc_entries[i].title_name = (char*)xmlNodeGetContent(cur_node);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
XML_FREE(tmp);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
else if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "description")) {
|
|
Packit |
5e46da |
if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "thumbnail") && (tmp = xmlGetProp(cur_node, BAD_CAST_CONST "href"))) {
|
|
Packit |
5e46da |
META_THUMBNAIL *new_thumbnails = realloc(disclib->thumbnails, ((disclib->thumb_count + 1)*sizeof(META_THUMBNAIL)));
|
|
Packit |
5e46da |
if (new_thumbnails) {
|
|
Packit |
5e46da |
uint8_t i = disclib->thumb_count;
|
|
Packit |
5e46da |
disclib->thumb_count++;
|
|
Packit |
5e46da |
disclib->thumbnails = new_thumbnails;
|
|
Packit |
5e46da |
disclib->thumbnails[i].path = (char *)tmp;
|
|
Packit |
5e46da |
if ((tmp = xmlGetProp(cur_node, BAD_CAST_CONST "size"))) {
|
|
Packit |
5e46da |
int x = 0, y = 0;
|
|
Packit |
5e46da |
sscanf((const char*)tmp, "%ix%i", &x, &y);
|
|
Packit |
5e46da |
disclib->thumbnails[i].xres = x;
|
|
Packit |
5e46da |
disclib->thumbnails[i].yres = y;
|
|
Packit |
5e46da |
XML_FREE(tmp);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
else {
|
|
Packit |
5e46da |
disclib->thumbnails[i].xres = disclib->thumbnails[i].yres = -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
_parseManifestNode(cur_node->children, disclib);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _findMetaXMLfiles(META_ROOT *meta, BD_DISC *disc)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DIR_H *dir;
|
|
Packit |
5e46da |
BD_DIRENT ent;
|
|
Packit |
5e46da |
dir = disc_open_dir(disc, "BDMV" DIR_SEP "META" DIR_SEP "DL");
|
|
Packit |
5e46da |
if (dir == NULL) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "Failed to open meta dir BDMV/META/DL/\n");
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
int res;
|
|
Packit |
5e46da |
for (res = dir_read(dir, &ent;; !res; res = dir_read(dir, &ent)) {
|
|
Packit |
5e46da |
if (ent.d_name[0] == '.')
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
else if (strncasecmp(ent.d_name, "bdmt_", 5) == 0) {
|
|
Packit |
5e46da |
META_DL *new_dl_entries = realloc(meta->dl_entries, ((meta->dl_count + 1)*sizeof(META_DL)));
|
|
Packit |
5e46da |
if (new_dl_entries) {
|
|
Packit |
5e46da |
uint8_t i = meta->dl_count;
|
|
Packit |
5e46da |
meta->dl_count++;
|
|
Packit |
5e46da |
meta->dl_entries = new_dl_entries;
|
|
Packit |
5e46da |
memset(&meta->dl_entries[i], 0, sizeof(meta->dl_entries[i]));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
meta->dl_entries[i].filename = str_dup(ent.d_name);
|
|
Packit |
5e46da |
strncpy(meta->dl_entries[i].language_code, ent.d_name+5,3);
|
|
Packit |
5e46da |
meta->dl_entries[i].language_code[3] = '\0';
|
|
Packit |
5e46da |
str_tolower(meta->dl_entries[i].language_code);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
dir_close(dir);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
META_ROOT *meta_parse(BD_DISC *disc)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
#ifdef HAVE_LIBXML2
|
|
Packit |
5e46da |
META_ROOT *root = calloc(1, sizeof(META_ROOT));
|
|
Packit |
5e46da |
unsigned i;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!root) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
root->dl_count = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_findMetaXMLfiles(root, disc);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (i = 0; i < root->dl_count; i++) {
|
|
Packit |
5e46da |
uint8_t *data = NULL;
|
|
Packit |
5e46da |
size_t size;
|
|
Packit |
5e46da |
size = disc_read_file(disc, "BDMV" DIR_SEP "META" DIR_SEP "DL",
|
|
Packit |
5e46da |
root->dl_entries[i].filename,
|
|
Packit |
5e46da |
&data);
|
|
Packit |
5e46da |
if (!data || size == 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "Failed to read BDMV/META/DL/%s\n", root->dl_entries[i].filename);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
xmlDocPtr doc;
|
|
Packit |
5e46da |
doc = xmlReadMemory((char*)data, (int)size, NULL, NULL, 0);
|
|
Packit |
5e46da |
if (doc == NULL) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "Failed to parse BDMV/META/DL/%s\n", root->dl_entries[i].filename);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
xmlNode *root_element = NULL;
|
|
Packit |
5e46da |
root_element = xmlDocGetRootElement(doc);
|
|
Packit |
5e46da |
root->dl_entries[i].di_name = root->dl_entries[i].di_alternative = NULL;
|
|
Packit |
5e46da |
root->dl_entries[i].di_num_sets = root->dl_entries[i].di_set_number = -1;
|
|
Packit |
5e46da |
root->dl_entries[i].toc_count = root->dl_entries[i].thumb_count = 0;
|
|
Packit |
5e46da |
root->dl_entries[i].toc_entries = NULL;
|
|
Packit |
5e46da |
root->dl_entries[i].thumbnails = NULL;
|
|
Packit |
5e46da |
_parseManifestNode(root_element, &root->dl_entries[i]);
|
|
Packit |
5e46da |
xmlFreeDoc(doc);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(data);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
xmlCleanupParser();
|
|
Packit |
5e46da |
return root;
|
|
Packit |
5e46da |
#else
|
|
Packit |
5e46da |
(void)disc;
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "configured without libxml2 - can't parse meta info\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
const META_DL *meta_get(const META_ROOT *meta_root, const char *language_code)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
#ifdef HAVE_LIBXML2
|
|
Packit |
5e46da |
unsigned i;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (meta_root == NULL || meta_root->dl_count == 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "meta_get not possible, no info available!\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (language_code) {
|
|
Packit |
5e46da |
for (i = 0; i < meta_root->dl_count; i++) {
|
|
Packit |
5e46da |
if (strcmp(language_code, meta_root->dl_entries[i].language_code) == 0) {
|
|
Packit |
5e46da |
return &meta_root->dl_entries[i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "requested disclib language '%s' not found\n", language_code);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (i = 0; i < meta_root->dl_count; i++) {
|
|
Packit |
5e46da |
if (strcmp(DEFAULT_LANGUAGE, meta_root->dl_entries[i].language_code) == 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "using default disclib language '"DEFAULT_LANGUAGE"'\n");
|
|
Packit |
5e46da |
return &meta_root->dl_entries[i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DIR, "requested disclib language '%s' or default '"DEFAULT_LANGUAGE"' not found, using '%s' instead\n", language_code, meta_root->dl_entries[0].language_code);
|
|
Packit |
5e46da |
return &meta_root->dl_entries[0];
|
|
Packit |
5e46da |
#else
|
|
Packit |
5e46da |
(void)meta_root;
|
|
Packit |
5e46da |
(void)language_code;
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void meta_free(META_ROOT **p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
(void)p;
|
|
Packit |
5e46da |
#ifdef HAVE_LIBXML2
|
|
Packit |
5e46da |
if (p && *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint8_t i;
|
|
Packit |
5e46da |
for (i = 0; i < (*p)->dl_count; i++) {
|
|
Packit |
5e46da |
uint32_t t;
|
|
Packit |
5e46da |
for (t = 0; t < (*p)->dl_entries[i].toc_count; t++) {
|
|
Packit |
5e46da |
XML_FREE((*p)->dl_entries[i].toc_entries[t].title_name);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (t = 0; t < (*p)->dl_entries[i].thumb_count; t++) {
|
|
Packit |
5e46da |
XML_FREE((*p)->dl_entries[i].thumbnails[t].path);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE((*p)->dl_entries[i].toc_entries);
|
|
Packit |
5e46da |
X_FREE((*p)->dl_entries[i].thumbnails);
|
|
Packit |
5e46da |
X_FREE((*p)->dl_entries[i].filename);
|
|
Packit |
5e46da |
XML_FREE((*p)->dl_entries[i].di_name);
|
|
Packit |
5e46da |
XML_FREE((*p)->dl_entries[i].di_alternative);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE((*p)->dl_entries);
|
|
Packit |
5e46da |
X_FREE(*p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
}
|