Missed a couple of element IDs.
[libmkv.git] / src / ebml.c
blob0b845e667414d19fd28caed6842c09ae40abf700
1 /*****************************************************************************
2 * matroska.c:
3 *****************************************************************************
4 * Copyright (C) 2005 x264 project
5 * $Id: $
7 * Authors: Mike Matsnev
8 * Nathan Caldwell
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
24 #include "config.h"
25 #include "libmkv.h"
26 #include "matroska.h"
28 mk_Context *mk_createContext(mk_Writer *w, mk_Context *parent, unsigned id) {
29 mk_Context *c;
31 if (w->freelist) {
32 c = w->freelist;
33 w->freelist = w->freelist->next;
34 } else {
35 c = malloc(sizeof(*c));
36 memset(c, 0, sizeof(*c));
39 if (c == NULL)
40 return NULL;
42 c->parent = parent;
43 c->owner = w;
44 c->id = id;
46 if (c->owner->actlist)
47 c->owner->actlist->prev = &c->next;
48 c->next = c->owner->actlist;
49 c->prev = &c->owner->actlist;
50 c->owner->actlist = c;
52 return c;
55 int mk_appendContextData(mk_Context *c, const void *data, uint64_t size) {
56 uint64_t ns = c->d_cur + size;
58 if (ns > c->d_max) {
59 void *dp;
60 uint64_t dn = c->d_max ? c->d_max << 1 : 16;
61 while (ns > dn)
62 dn <<= 1;
64 dp = realloc(c->data, dn);
65 if (dp == NULL)
66 return -1;
68 c->data = dp;
69 c->d_max = dn;
72 memcpy((char*)c->data + c->d_cur, data, size);
74 c->d_cur = ns;
76 return 0;
79 int mk_writeID(mk_Context *c, unsigned id) {
80 unsigned char c_id[4] = { id >> 24, id >> 16, id >> 8, id };
82 if (c_id[0])
83 return mk_appendContextData(c, c_id, 4);
84 if (c_id[1])
85 return mk_appendContextData(c, c_id+1, 3);
86 if (c_id[2])
87 return mk_appendContextData(c, c_id+2, 2);
88 return mk_appendContextData(c, c_id+3, 1);
91 int mk_writeSize(mk_Context *c, uint64_t size) {
92 unsigned char c_size[8] = { 0x01, size >> 48, size >> 40, size >> 32, size >> 24, size >> 16, size >> 8, size };
94 if (size < 0x7fll) {
95 c_size[7] |= 0x80;
96 return mk_appendContextData(c, c_size+7, 1);
98 if (size < 0x3fffll) {
99 c_size[6] |= 0x40;
100 return mk_appendContextData(c, c_size+6, 2);
102 if (size < 0x1fffffll) {
103 c_size[5] |= 0x20;
104 return mk_appendContextData(c, c_size+5, 3);
106 if (size < 0x0fffffffll) {
107 c_size[4] |= 0x10;
108 return mk_appendContextData(c, c_size+4, 4);
110 if (size < 0x07ffffffffll) {
111 c_size[3] |= 0x08;
112 return mk_appendContextData(c, c_size+3, 5);
114 if (size < 0x03ffffffffffll) {
115 c_size[2] |= 0x04;
116 return mk_appendContextData(c, c_size+2, 6);
118 if (size < 0x01ffffffffffffll) {
119 c_size[1] |= 0x02;
120 return mk_appendContextData(c, c_size+1, 7);
122 return mk_appendContextData(c, c_size, 8);
125 int mk_writeSSize(mk_Context *c, int64_t size) {
126 uint64_t u_size = (uint64_t)llabs(size);
127 unsigned size_size = mk_ebmlSizeSize( u_size << 1 ); // We need to shift by one to get the correct size here.
129 switch (size_size)
131 case 1:
132 size += 0x3fll;
133 break;
134 case 2:
135 size += 0x1fffll;
136 break;
137 case 3:
138 size += 0x0fffffll;
139 break;
140 case 4:
141 size += 0x07ffffffll;
142 break;
143 case 5:
144 size += 0x03ffffffffll;
145 break;
146 case 6:
147 size += 0x01ffffffffffll;
148 break;
149 case 7:
150 size += 0x00ffffffffffffll;
151 break;
152 default: // Matroska currently doesn't support any int > 56-bit.
153 return -1;
156 return mk_writeSize(c, size);
159 int mk_flushContextID(mk_Context *c) {
160 unsigned char size_undf[8] = {0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
162 if (c->id == 0)
163 return 0;
165 CHECK(mk_writeID(c->parent, c->id));
166 CHECK(mk_appendContextData(c->parent, &size_undf, 8));
168 c->id = 0;
170 return 0;
173 int mk_flushContextData(mk_Context *c) {
174 mk_Writer *w = c->owner;
176 if (c->d_cur == 0)
177 return 0;
179 if (c->parent)
180 CHECK(mk_appendContextData(c->parent, c->data, c->d_cur));
181 else {
182 if (fwrite(c->data, c->d_cur, 1, w->fp) != 1)
183 return -1;
184 w->f_pos += c->d_cur;
185 if (w->f_pos > w->f_eof)
186 w->f_eof = w->f_pos;
189 c->d_cur = 0;
191 return 0;
194 int mk_closeContext(mk_Context *c, int64_t *off) {
195 if (c->id) {
196 CHECK(mk_writeID(c->parent, c->id));
197 CHECK(mk_writeSize(c->parent, c->d_cur));
200 if (c->parent && off != NULL)
201 *off += c->parent->d_cur;
203 CHECK(mk_flushContextData(c));
205 if (c->next)
206 c->next->prev = c->prev;
207 *(c->prev) = c->next;
208 c->next = c->owner->freelist;
209 c->owner->freelist = c;
211 return 0;
214 void mk_destroyContexts(mk_Writer *w) {
215 mk_Context *cur, *next;
217 for (cur = w->freelist; cur; cur = next) {
218 next = cur->next;
219 free(cur->data);
220 free(cur);
223 for (cur = w->actlist; cur; cur = next) {
224 next = cur->next;
225 free(cur->data);
226 free(cur);
229 w->freelist = w->actlist = w->root = NULL;
232 int mk_writeStr(mk_Context *c, unsigned id, const char *str) {
233 size_t len = strlen(str);
235 CHECK(mk_writeID(c, id));
236 CHECK(mk_writeSize(c, len));
237 CHECK(mk_appendContextData(c, str, len));
238 return 0;
241 int mk_writeBin(mk_Context *c, unsigned id, const void *data, unsigned size) {
242 CHECK(mk_writeID(c, id));
243 CHECK(mk_writeSize(c, size));
244 CHECK(mk_appendContextData(c, data, size));
245 return 0;
248 int mk_writeUInt(mk_Context *c, unsigned id, uint64_t ui) {
249 unsigned char c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
250 unsigned i = 0;
252 CHECK(mk_writeID(c, id));
253 while (i < 7 && c_ui[i] == 0)
254 ++i;
255 CHECK(mk_writeSize(c, 8 - i));
256 CHECK(mk_appendContextData(c, c_ui+i, 8 - i));
257 return 0;
260 int mk_writeSInt(mk_Context *c, unsigned id, int64_t si) {
261 unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
262 unsigned i = 0;
264 CHECK(mk_writeID(c, id));
265 if (si < 0)
266 while (i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80)
267 ++i;
268 else
269 while (i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80))
270 ++i;
271 CHECK(mk_writeSize(c, 8 - i));
272 CHECK(mk_appendContextData(c, c_si+i, 8 - i));
273 return 0;
276 int mk_writeFloatRaw(mk_Context *c, float f) {
277 union {
278 float f;
279 unsigned u;
280 } u;
281 unsigned char c_f[4];
283 u.f = f;
284 c_f[0] = u.u >> 24;
285 c_f[1] = u.u >> 16;
286 c_f[2] = u.u >> 8;
287 c_f[3] = u.u;
289 return mk_appendContextData(c, c_f, 4);
292 int mk_writeFloat(mk_Context *c, unsigned id, float f) {
293 CHECK(mk_writeID(c, id));
294 CHECK(mk_writeSize(c, 4));
295 CHECK(mk_writeFloatRaw(c, f));
296 return 0;
299 int mk_writeVoid(mk_Context *c, uint64_t length) {
300 char *c_void = calloc(length, sizeof(char));
302 CHECK(mk_writeID(c, EBML_ID_VOID));
303 CHECK(mk_writeSize(c, length));
304 CHECK(mk_appendContextData(c, c_void, length));
305 free(c_void);
306 return 0;
309 unsigned mk_ebmlSizeSize(uint64_t s) {
310 if (s < 0x7fll)
311 return 1;
312 if (s < 0x3fffll)
313 return 2;
314 if (s < 0x1fffffll)
315 return 3;
316 if (s < 0x0fffffffll)
317 return 4;
318 if (s < 0x07ffffffffll)
319 return 5;
320 if (s < 0x03ffffffffffll)
321 return 6;
322 if (s < 0x01ffffffffffffll)
323 return 7;
324 return 8;
327 unsigned mk_ebmlSIntSize(int64_t si) {
328 unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
329 unsigned i = 0;
331 if (si < 0)
332 while (i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80)
333 ++i;
334 else
335 while (i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80))
336 ++i;
338 return 8 - i;