/* * This file is part of libbluray * Copyright (C) 2013 Petri Hintukainen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #if HAVE_CONFIG_H #include "config.h" #endif #include "textst_decode.h" #include "pg_decode.h" // pg_decode_*() #include "util/macro.h" #include "util/bits.h" #include "util/logging.h" #include #include static int8_t _decode_int8(BITBUFFER *bb) { unsigned sign = bb_read(bb, 1); int8_t val = bb_read(bb, 7); return sign ? -val : val; } static int16_t _decode_int16(BITBUFFER *bb) { unsigned sign = bb_read(bb, 1); int16_t val = bb_read(bb, 15); return sign ? -val : val; } static int64_t _decode_pts(BITBUFFER *bb) { return ((int64_t)bb_read(bb, 1)) << 32 | bb_read(bb, 32); } static void _decode_rect(BITBUFFER *bb, BD_TEXTST_RECT *p) { p->xpos = bb_read(bb, 16);; p->ypos = bb_read(bb, 16);; p->width = bb_read(bb, 16);; p->height = bb_read(bb, 16);; } static void _decode_region_info(BITBUFFER *bb, BD_TEXTST_REGION_INFO *p) { _decode_rect(bb, &p->region); p->background_color = bb_read(bb, 8); bb_skip(bb, 8); } static void _decode_font_style(BITBUFFER *bb, BD_TEXTST_FONT_STYLE *p) { uint8_t font_style = bb_read(bb, 8); p->bold = !!(font_style & 1); p->italic = !!(font_style & 2); p->outline_border = !!(font_style & 4); } static void _decode_region_style(BITBUFFER *bb, BD_TEXTST_REGION_STYLE *p) { p->region_style_id = bb_read(bb, 8); _decode_region_info(bb, &p->region_info); _decode_rect(bb, &p->text_box); p->text_flow = bb_read(bb, 8); p->text_halign = bb_read(bb, 8); p->text_valign = bb_read(bb, 8); p->line_space = bb_read(bb, 8); p->font_id_ref = bb_read(bb, 8); _decode_font_style(bb, &p->font_style); p->font_size = bb_read(bb, 8); p->font_color = bb_read(bb, 8); p->outline_color = bb_read(bb, 8); p->outline_thickness = bb_read(bb, 8); } static void _decode_user_style(BITBUFFER *bb, BD_TEXTST_USER_STYLE *p) { p->user_style_id = bb_read(bb, 8); p->region_hpos_delta = _decode_int16(bb); p->region_vpos_delta = _decode_int16(bb); p->text_box_hpos_delta = _decode_int16(bb); p->text_box_vpos_delta = _decode_int16(bb); p->text_box_width_delta = _decode_int16(bb); p->text_box_height_delta = _decode_int16(bb); p->font_size_delta = _decode_int8(bb); p->line_space_delta = _decode_int8(bb); } static int _decode_dialog_region(BITBUFFER *bb, BD_TEXTST_DIALOG_REGION *p) { p->continous_present_flag = bb_read(bb, 1); p->forced_on_flag = bb_read(bb, 1); bb_skip(bb, 6); p->region_style_id_ref = bb_read(bb, 8); uint16_t data_length = bb_read(bb, 16); int bytes_allocated = data_length; uint16_t bytes_read = 0; p->elem = malloc(bytes_allocated); p->elem_count = 0; p->line_count = 1; if (!p->elem) { BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n"); return 0; } uint8_t *ptr = (uint8_t *)p->elem; while (bytes_read < data_length) { /* parse header */ uint8_t code = bb_read(bb, 8); bytes_read++; if (code != 0x1b) { BD_DEBUG(DBG_DECODE, "_decode_dialog_region(): missing escape\n"); continue; } uint8_t type = bb_read(bb, 8); uint8_t length = bb_read(bb, 8); bytes_read += 2 + length; /* realloc */ int bytes_used = ((intptr_t)ptr - (intptr_t)p->elem); int need = bytes_used + length + sizeof(BD_TEXTST_DATA); if (bytes_allocated < need) { bytes_allocated = need * 2; BD_TEXTST_DATA *tmp = realloc(p->elem, bytes_allocated); if (!tmp) { BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n"); return 0; } p->elem = tmp; ptr = ((uint8_t *)p->elem) + bytes_used; } /* parse content */ BD_TEXTST_DATA *data = (BD_TEXTST_DATA *)ptr; memset(data, 0, sizeof(*data)); data->type = type; switch (data->type) { case BD_TEXTST_DATA_STRING: bb_read_bytes(bb, data->data.text.string, length); data->data.text.length = length; ptr += length; break; case BD_TEXTST_DATA_FONT_ID: data->data.font_id_ref = bb_read(bb, 8); break; case BD_TEXTST_DATA_FONT_STYLE: _decode_font_style(bb, &data->data.style.style); data->data.style.outline_color = bb_read(bb, 8); data->data.style.outline_thickness = bb_read(bb, 8); break; case BD_TEXTST_DATA_FONT_SIZE: data->data.font_size = bb_read(bb, 8); break; case BD_TEXTST_DATA_FONT_COLOR: data->data.font_color = bb_read(bb, 8); break; case BD_TEXTST_DATA_NEWLINE: p->line_count++; break; case BD_TEXTST_DATA_RESET_STYLE: break; default: BD_DEBUG(DBG_DECODE, "_decode_dialog_region(): unknown marker %d (len %d)\n", type, length); bb_skip(bb, 8 * length); continue; } ptr += sizeof(BD_TEXTST_DATA); p->elem_count++; } return 1; } static void _decode_palette(BITBUFFER *bb, BD_PG_PALETTE_ENTRY *p) { uint16_t entries = bb_read(bb, 16) / 5; unsigned ii; memset(p, 0, 256 * sizeof(*p)); for (ii = 0; ii < entries; ii++) { pg_decode_palette_entry(bb, p); } } /* * segments */ BD_PRIVATE int textst_decode_dialog_style(BITBUFFER *bb, BD_TEXTST_DIALOG_STYLE *p) { unsigned ii; p->player_style_flag = bb_read(bb, 1); bb_skip(bb, 15); p->region_style_count = bb_read(bb, 8); p->user_style_count = bb_read(bb, 8); if (p->region_style_count) { p->region_style = calloc(p->region_style_count, sizeof(BD_TEXTST_REGION_STYLE)); if (!p->region_style) { BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n"); return 0; } for (ii = 0; ii < p->region_style_count; ii++) { _decode_region_style(bb, &p->region_style[ii]); } } if (p->user_style_count) { p->user_style = calloc(p->user_style_count, sizeof(BD_TEXTST_USER_STYLE)); if (!p->user_style) { BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n"); return 0; } for (ii = 0; ii < p->user_style_count; ii++) { _decode_user_style(bb, &p->user_style[ii]); } } _decode_palette(bb, p->palette); return 1; } BD_PRIVATE int textst_decode_dialog_presentation(BITBUFFER *bb, BD_TEXTST_DIALOG_PRESENTATION *p) { unsigned ii, palette_update_flag; bb_skip(bb, 7); p->start_pts = _decode_pts(bb); bb_skip(bb, 7); p->end_pts = _decode_pts(bb); palette_update_flag = bb_read(bb, 1); bb_skip(bb, 7); if (palette_update_flag) { p->palette_update = calloc(256, sizeof(BD_PG_PALETTE_ENTRY)); if (!p->palette_update) { BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n"); return 0; } _decode_palette(bb, p->palette_update); } p->region_count = bb_read(bb, 8); if (p->region_count) { if (p->region_count > 2) { BD_DEBUG(DBG_DECODE | DBG_CRIT, "too many regions (%d)\n", p->region_count); return 0; } for (ii = 0; ii < p->region_count; ii++) { if (!_decode_dialog_region(bb, &p->region[ii])) { return 0; } } } return 1; } /* * cleanup */ void textst_clean_dialog_presentation(BD_TEXTST_DIALOG_PRESENTATION *p) { if (p) { X_FREE(p->palette_update); X_FREE(p->region[0].elem); X_FREE(p->region[1].elem); } } static void _clean_style(BD_TEXTST_DIALOG_STYLE *p) { if (p) { X_FREE(p->region_style); X_FREE(p->user_style); } } void textst_free_dialog_style(BD_TEXTST_DIALOG_STYLE **p) { if (p && *p) { _clean_style(*p); X_FREE(*p); } }