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