1 /*****************************************************************************
2 * matroska_ebml.c:
3 *****************************************************************************
4 * Copyright (C) 2005 Mike Matsnev
5 * Copyright (C) 2010 Andreas Öman
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
20 *****************************************************************************/
21
22 #include <assert.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include "ebml.h"
27
28 void
ebml_append_id(htsbuf_queue_t * q,uint32_t id)29 ebml_append_id(htsbuf_queue_t *q, uint32_t id)
30 {
31 uint8_t u8[4] = {id >> 24, id >> 16, id >> 8, id};
32
33 if(u8[0])
34 return htsbuf_append(q, u8, 4);
35 if(u8[1])
36 return htsbuf_append(q, u8+1, 3);
37 if(u8[2])
38 return htsbuf_append(q, u8+2, 2);
39 return htsbuf_append(q, u8+3, 1);
40 }
41
42 void
ebml_append_size(htsbuf_queue_t * q,uint32_t size)43 ebml_append_size(htsbuf_queue_t *q, uint32_t size)
44 {
45 uint8_t u8[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
46
47 if(size < 0x7f) {
48 u8[4] |= 0x80;
49 return htsbuf_append(q, u8+4, 1);
50 }
51
52 if(size < 0x3fff) {
53 u8[3] |= 0x40;
54 return htsbuf_append(q, u8+3, 2);
55 }
56 if(size < 0x1fffff) {
57 u8[2] |= 0x20;
58 return htsbuf_append(q, u8+2, 3);
59 }
60 if(size < 0x0fffffff) {
61 u8[1] |= 0x10;
62 return htsbuf_append(q, u8+1, 4);
63 }
64 return htsbuf_append(q, u8, 5);
65 }
66
67
68 void
ebml_append_xiph_size(htsbuf_queue_t * q,int size)69 ebml_append_xiph_size(htsbuf_queue_t *q, int size)
70 {
71 int i;
72 uint8_t u8[4] = {0xff, size % 0xff};
73
74 for(i=0; i<size/0xff; i++)
75 htsbuf_append(q, u8, 1);
76
77 return htsbuf_append(q, u8+1, 1);
78 }
79
80
81 void
ebml_append_bin(htsbuf_queue_t * q,unsigned id,const void * data,size_t len)82 ebml_append_bin(htsbuf_queue_t *q, unsigned id, const void *data, size_t len)
83 {
84 ebml_append_id(q, id);
85 ebml_append_size(q, len);
86 return htsbuf_append(q, data, len);
87 }
88
89 void
ebml_append_string(htsbuf_queue_t * q,unsigned id,const char * str)90 ebml_append_string(htsbuf_queue_t *q, unsigned id, const char *str)
91 {
92 return ebml_append_bin(q, id, str, strlen(str));
93 }
94
95 void
ebml_append_uint(htsbuf_queue_t * q,unsigned id,int64_t ui)96 ebml_append_uint(htsbuf_queue_t *q, unsigned id, int64_t ui)
97 {
98 uint8_t u8[8] = {ui >> 56, ui >> 48, ui >> 40, ui >> 32,
99 ui >> 24, ui >> 16, ui >> 8, ui };
100 int i = 0;
101 while( i < 7 && !u8[i] )
102 ++i;
103 return ebml_append_bin(q, id, u8 + i, 8 - i);
104 }
105
106 void
ebml_append_float(htsbuf_queue_t * q,unsigned id,float f)107 ebml_append_float(htsbuf_queue_t *q, unsigned id, float f)
108 {
109 union
110 {
111 float f;
112 unsigned u;
113 } u;
114 unsigned char c_f[4];
115
116 u.f = f;
117 c_f[0] = u.u >> 24;
118 c_f[1] = u.u >> 16;
119 c_f[2] = u.u >> 8;
120 c_f[3] = u.u;
121
122 return ebml_append_bin(q, id, c_f, 4);
123 }
124
125 void
ebml_append_master(htsbuf_queue_t * q,uint32_t id,htsbuf_queue_t * p)126 ebml_append_master(htsbuf_queue_t *q, uint32_t id, htsbuf_queue_t *p)
127 {
128 ebml_append_id(q, id);
129 ebml_append_size(q, p->hq_size);
130 htsbuf_appendq(q, p);
131 free(p);
132 }
133
134 void
ebml_append_void(htsbuf_queue_t * q)135 ebml_append_void(htsbuf_queue_t *q)
136 {
137 char n[1] = {0};
138 ebml_append_bin(q, 0xec, n, 1);
139 }
140
141
142 void
ebml_append_pad(htsbuf_queue_t * q,size_t pad)143 ebml_append_pad(htsbuf_queue_t *q, size_t pad)
144 {
145 assert(pad > 2);
146 pad -= 2;
147 assert(pad < 0x3fff);
148 pad -= pad > 0x7e;
149
150 void *data = alloca(pad);
151 memset(data, 0, pad);
152 ebml_append_bin(q, 0xec, data, pad);
153 }
154
155
156 void
ebml_append_idid(htsbuf_queue_t * q,uint32_t id0,uint32_t id)157 ebml_append_idid(htsbuf_queue_t *q, uint32_t id0, uint32_t id)
158 {
159 uint8_t u8[4] = {id >> 24, id >> 16, id >> 8, id};
160
161 if(u8[0])
162 return ebml_append_bin(q, id0, u8, 4);
163 if(u8[1])
164 return ebml_append_bin(q, id0, u8+1, 3);
165 if(u8[2])
166 return ebml_append_bin(q, id0, u8+2, 2);
167 return ebml_append_bin(q, id0, u8+3, 1);
168 }
169