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