1 /*
2 * This file is part of libbluray
3 * Copyright (C) 2013 Petri Hintukainen <phintuka@users.sourceforge.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see
17 * <http://www.gnu.org/licenses/>.
18 */
19
20 #if HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "textst_decode.h"
25
26 #include "pg_decode.h" // pg_decode_*()
27
28 #include "util/macro.h"
29 #include "util/bits.h"
30 #include "util/logging.h"
31
32 #include <string.h>
33 #include <stdlib.h>
34
35
_decode_int8(BITBUFFER * bb)36 static int8_t _decode_int8(BITBUFFER *bb)
37 {
38 unsigned sign = bb_read(bb, 1);
39 int8_t val = bb_read(bb, 7);
40 return sign ? -val : val;
41 }
42
_decode_int16(BITBUFFER * bb)43 static int16_t _decode_int16(BITBUFFER *bb)
44 {
45 unsigned sign = bb_read(bb, 1);
46 int16_t val = bb_read(bb, 15);
47 return sign ? -val : val;
48 }
49
_decode_pts(BITBUFFER * bb)50 static int64_t _decode_pts(BITBUFFER *bb)
51 {
52 return ((int64_t)bb_read(bb, 1)) << 32 | bb_read(bb, 32);
53 }
54
_decode_rect(BITBUFFER * bb,BD_TEXTST_RECT * p)55 static void _decode_rect(BITBUFFER *bb, BD_TEXTST_RECT *p)
56 {
57 p->xpos = bb_read(bb, 16);;
58 p->ypos = bb_read(bb, 16);;
59 p->width = bb_read(bb, 16);;
60 p->height = bb_read(bb, 16);;
61 }
62
_decode_region_info(BITBUFFER * bb,BD_TEXTST_REGION_INFO * p)63 static void _decode_region_info(BITBUFFER *bb, BD_TEXTST_REGION_INFO *p)
64 {
65 _decode_rect(bb, &p->region);
66 p->background_color = bb_read(bb, 8);
67 bb_skip(bb, 8);
68 }
69
_decode_font_style(BITBUFFER * bb,BD_TEXTST_FONT_STYLE * p)70 static void _decode_font_style(BITBUFFER *bb, BD_TEXTST_FONT_STYLE *p)
71 {
72 uint8_t font_style = bb_read(bb, 8);
73 p->bold = !!(font_style & 1);
74 p->italic = !!(font_style & 2);
75 p->outline_border = !!(font_style & 4);
76 }
77
_decode_region_style(BITBUFFER * bb,BD_TEXTST_REGION_STYLE * p)78 static void _decode_region_style(BITBUFFER *bb, BD_TEXTST_REGION_STYLE *p)
79 {
80 p->region_style_id = bb_read(bb, 8);
81
82 _decode_region_info(bb, &p->region_info);
83 _decode_rect(bb, &p->text_box);
84
85 p->text_flow = bb_read(bb, 8);
86 p->text_halign = bb_read(bb, 8);
87 p->text_valign = bb_read(bb, 8);
88 p->line_space = bb_read(bb, 8);
89 p->font_id_ref = bb_read(bb, 8);
90
91 _decode_font_style(bb, &p->font_style);
92
93 p->font_size = bb_read(bb, 8);
94 p->font_color = bb_read(bb, 8);
95 p->outline_color = bb_read(bb, 8);
96 p->outline_thickness = bb_read(bb, 8);
97 }
98
_decode_user_style(BITBUFFER * bb,BD_TEXTST_USER_STYLE * p)99 static void _decode_user_style(BITBUFFER *bb, BD_TEXTST_USER_STYLE *p)
100 {
101 p->user_style_id = bb_read(bb, 8);
102 p->region_hpos_delta = _decode_int16(bb);
103 p->region_vpos_delta = _decode_int16(bb);
104 p->text_box_hpos_delta = _decode_int16(bb);
105 p->text_box_vpos_delta = _decode_int16(bb);
106 p->text_box_width_delta = _decode_int16(bb);
107 p->text_box_height_delta = _decode_int16(bb);
108 p->font_size_delta = _decode_int8(bb);
109 p->line_space_delta = _decode_int8(bb);
110 }
111
_decode_dialog_region(BITBUFFER * bb,BD_TEXTST_DIALOG_REGION * p)112 static int _decode_dialog_region(BITBUFFER *bb, BD_TEXTST_DIALOG_REGION *p)
113 {
114 p->continous_present_flag = bb_read(bb, 1);
115 p->forced_on_flag = bb_read(bb, 1);
116 bb_skip(bb, 6);
117 p->region_style_id_ref = bb_read(bb, 8);
118
119 uint16_t data_length = bb_read(bb, 16);
120 int bytes_allocated = data_length;
121 uint16_t bytes_read = 0;
122
123 p->elem = malloc(bytes_allocated);
124 p->elem_count = 0;
125 p->line_count = 1;
126 if (!p->elem) {
127 BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
128 return 0;
129 }
130
131 uint8_t *ptr = (uint8_t *)p->elem;
132
133 while (bytes_read < data_length) {
134
135 /* parse header */
136
137 uint8_t code = bb_read(bb, 8);
138 bytes_read++;
139 if (code != 0x1b) {
140 BD_DEBUG(DBG_DECODE, "_decode_dialog_region(): missing escape\n");
141 continue;
142 }
143
144 uint8_t type = bb_read(bb, 8);
145 uint8_t length = bb_read(bb, 8);
146 bytes_read += 2 + length;
147
148 /* realloc */
149
150 int bytes_used = ((intptr_t)ptr - (intptr_t)p->elem);
151 int need = bytes_used + length + sizeof(BD_TEXTST_DATA);
152 if (bytes_allocated < need) {
153 bytes_allocated = need * 2;
154 BD_TEXTST_DATA *tmp = realloc(p->elem, bytes_allocated);
155 if (!tmp) {
156 BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
157 return 0;
158 }
159 p->elem = tmp;
160 ptr = ((uint8_t *)p->elem) + bytes_used;
161 }
162
163 /* parse content */
164
165 BD_TEXTST_DATA *data = (BD_TEXTST_DATA *)ptr;
166 memset(data, 0, sizeof(*data));
167
168 data->type = type;
169 switch (data->type) {
170 case BD_TEXTST_DATA_STRING:
171 bb_read_bytes(bb, data->data.text.string, length);
172 data->data.text.length = length;
173 ptr += length;
174 break;
175 case BD_TEXTST_DATA_FONT_ID:
176 data->data.font_id_ref = bb_read(bb, 8);
177 break;
178 case BD_TEXTST_DATA_FONT_STYLE:
179 _decode_font_style(bb, &data->data.style.style);
180 data->data.style.outline_color = bb_read(bb, 8);
181 data->data.style.outline_thickness = bb_read(bb, 8);
182 break;
183 case BD_TEXTST_DATA_FONT_SIZE:
184 data->data.font_size = bb_read(bb, 8);
185 break;
186 case BD_TEXTST_DATA_FONT_COLOR:
187 data->data.font_color = bb_read(bb, 8);
188 break;
189 case BD_TEXTST_DATA_NEWLINE:
190 p->line_count++;
191 break;
192 case BD_TEXTST_DATA_RESET_STYLE:
193 break;
194 default:
195 BD_DEBUG(DBG_DECODE, "_decode_dialog_region(): unknown marker %d (len %d)\n", type, length);
196 bb_skip(bb, 8 * length);
197 continue;
198 }
199 ptr += sizeof(BD_TEXTST_DATA);
200 p->elem_count++;
201 }
202
203 return 1;
204 }
205
_decode_palette(BITBUFFER * bb,BD_PG_PALETTE_ENTRY * p)206 static void _decode_palette(BITBUFFER *bb, BD_PG_PALETTE_ENTRY *p)
207 {
208 uint16_t entries = bb_read(bb, 16) / 5;
209 unsigned ii;
210
211 memset(p, 0, 256 * sizeof(*p));
212 for (ii = 0; ii < entries; ii++) {
213 pg_decode_palette_entry(bb, p);
214 }
215 }
216
217 /*
218 * segments
219 */
220
221
textst_decode_dialog_style(BITBUFFER * bb,BD_TEXTST_DIALOG_STYLE * p)222 BD_PRIVATE int textst_decode_dialog_style(BITBUFFER *bb, BD_TEXTST_DIALOG_STYLE *p)
223 {
224 unsigned ii;
225
226 p->player_style_flag = bb_read(bb, 1);
227 bb_skip(bb, 15);
228 p->region_style_count = bb_read(bb, 8);
229 p->user_style_count = bb_read(bb, 8);
230
231 if (p->region_style_count) {
232 p->region_style = calloc(p->region_style_count, sizeof(BD_TEXTST_REGION_STYLE));
233 if (!p->region_style) {
234 BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
235 return 0;
236 }
237 for (ii = 0; ii < p->region_style_count; ii++) {
238 _decode_region_style(bb, &p->region_style[ii]);
239 }
240 }
241
242 if (p->user_style_count) {
243 p->user_style = calloc(p->user_style_count, sizeof(BD_TEXTST_USER_STYLE));
244 if (!p->user_style) {
245 BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
246 return 0;
247 }
248 for (ii = 0; ii < p->user_style_count; ii++) {
249 _decode_user_style(bb, &p->user_style[ii]);
250 }
251 }
252
253 _decode_palette(bb, p->palette);
254
255 return 1;
256 }
257
textst_decode_dialog_presentation(BITBUFFER * bb,BD_TEXTST_DIALOG_PRESENTATION * p)258 BD_PRIVATE int textst_decode_dialog_presentation(BITBUFFER *bb, BD_TEXTST_DIALOG_PRESENTATION *p)
259 {
260 unsigned ii, palette_update_flag;
261
262 bb_skip(bb, 7);
263 p->start_pts = _decode_pts(bb);
264 bb_skip(bb, 7);
265 p->end_pts = _decode_pts(bb);
266
267 palette_update_flag = bb_read(bb, 1);
268 bb_skip(bb, 7);
269
270 if (palette_update_flag) {
271 p->palette_update = calloc(256, sizeof(BD_PG_PALETTE_ENTRY));
272 if (!p->palette_update) {
273 BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
274 return 0;
275 }
276 _decode_palette(bb, p->palette_update);
277 }
278
279 p->region_count = bb_read(bb, 8);
280 if (p->region_count) {
281 if (p->region_count > 2) {
282 BD_DEBUG(DBG_DECODE | DBG_CRIT, "too many regions (%d)\n", p->region_count);
283 return 0;
284 }
285 for (ii = 0; ii < p->region_count; ii++) {
286 if (!_decode_dialog_region(bb, &p->region[ii])) {
287 return 0;
288 }
289 }
290 }
291
292 return 1;
293 }
294
295 /*
296 * cleanup
297 */
298
textst_clean_dialog_presentation(BD_TEXTST_DIALOG_PRESENTATION * p)299 void textst_clean_dialog_presentation(BD_TEXTST_DIALOG_PRESENTATION *p)
300 {
301 if (p) {
302 X_FREE(p->palette_update);
303 X_FREE(p->region[0].elem);
304 X_FREE(p->region[1].elem);
305 }
306 }
307
_clean_style(BD_TEXTST_DIALOG_STYLE * p)308 static void _clean_style(BD_TEXTST_DIALOG_STYLE *p)
309 {
310 if (p) {
311 X_FREE(p->region_style);
312 X_FREE(p->user_style);
313 }
314 }
315
textst_free_dialog_style(BD_TEXTST_DIALOG_STYLE ** p)316 void textst_free_dialog_style(BD_TEXTST_DIALOG_STYLE **p)
317 {
318 if (p && *p) {
319 _clean_style(*p);
320 X_FREE(*p);
321 }
322 }
323