Line | Count | Source (jump to first uncovered line) |
1 | | /******************************************************************** |
2 | | * * |
3 | | * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * |
4 | | * * |
5 | | * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
6 | | * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
7 | | * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
8 | | * * |
9 | | * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * |
10 | | * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * |
11 | | * * |
12 | | ******************************************************************** |
13 | | |
14 | | function: maintain the info structure, info <-> header packets |
15 | | |
16 | | ********************************************************************/ |
17 | | |
18 | | /* general handling of the header and the vorbis_info structure (and |
19 | | substructures) */ |
20 | | |
21 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | #include <ctype.h> |
24 | | #include <limits.h> |
25 | | #include <ogg/ogg.h> |
26 | | #include "ivorbiscodec.h" |
27 | | #include "codec_internal.h" |
28 | | #include "codebook.h" |
29 | | #include "registry.h" |
30 | | #include "window.h" |
31 | | #include "misc.h" |
32 | | |
33 | | /* helpers */ |
34 | 40.9k | static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ |
35 | 274k | while(bytes--){ |
36 | 233k | *buf++=oggpack_read(o,8); |
37 | 233k | } |
38 | 40.9k | } |
39 | | |
40 | 8.42k | void vorbis_comment_init(vorbis_comment *vc){ |
41 | 8.42k | memset(vc,0,sizeof(*vc)); |
42 | 8.42k | } |
43 | | |
44 | | /* This is more or less the same as strncasecmp - but that doesn't exist |
45 | | * everywhere, and this is a fairly trivial function, so we include it */ |
46 | 0 | static int tagcompare(const char *s1, const char *s2, int n){ |
47 | 0 | int c=0; |
48 | 0 | while(c < n){ |
49 | 0 | if(toupper(s1[c]) != toupper(s2[c])) |
50 | 0 | return !0; |
51 | 0 | c++; |
52 | 0 | } |
53 | 0 | return 0; |
54 | 0 | } |
55 | | |
56 | 0 | char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){ |
57 | 0 | long i; |
58 | 0 | int found = 0; |
59 | 0 | int taglen = strlen(tag)+1; /* +1 for the = we append */ |
60 | 0 | char *fulltag = (char *)alloca(taglen+ 1); |
61 | |
|
62 | 0 | strcpy(fulltag, tag); |
63 | 0 | strcat(fulltag, "="); |
64 | | |
65 | 0 | for(i=0;i<vc->comments;i++){ |
66 | 0 | if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ |
67 | 0 | if(count == found) |
68 | | /* We return a pointer to the data, not a copy */ |
69 | 0 | return vc->user_comments[i] + taglen; |
70 | 0 | else |
71 | 0 | found++; |
72 | 0 | } |
73 | 0 | } |
74 | 0 | return NULL; /* didn't find anything */ |
75 | 0 | } |
76 | | |
77 | 0 | int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ |
78 | 0 | int i,count=0; |
79 | 0 | int taglen = strlen(tag)+1; /* +1 for the = we append */ |
80 | 0 | char *fulltag = (char *)alloca(taglen+1); |
81 | 0 | strcpy(fulltag,tag); |
82 | 0 | strcat(fulltag, "="); |
83 | |
|
84 | 0 | for(i=0;i<vc->comments;i++){ |
85 | 0 | if(!tagcompare(vc->user_comments[i], fulltag, taglen)) |
86 | 0 | count++; |
87 | 0 | } |
88 | |
|
89 | 0 | return count; |
90 | 0 | } |
91 | | |
92 | 10.9k | void vorbis_comment_clear(vorbis_comment *vc){ |
93 | 10.9k | if(vc){ |
94 | 10.9k | long i; |
95 | 10.9k | if(vc->user_comments){ |
96 | 9.54k | for(i=0;i<vc->comments;i++) |
97 | 2.10k | if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); |
98 | 7.44k | _ogg_free(vc->user_comments); |
99 | 7.44k | } |
100 | 10.9k | if(vc->comment_lengths)_ogg_free(vc->comment_lengths); |
101 | 10.9k | if(vc->vendor)_ogg_free(vc->vendor); |
102 | 10.9k | memset(vc,0,sizeof(*vc)); |
103 | 10.9k | } |
104 | 10.9k | } |
105 | | |
106 | | /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long. |
107 | | They may be equal, but short will never ge greater than long */ |
108 | 0 | int vorbis_info_blocksize(vorbis_info *vi,int zo){ |
109 | 0 | codec_setup_info *ci = (codec_setup_info *)vi->codec_setup; |
110 | 0 | return ci ? ci->blocksizes[zo] : -1; |
111 | 0 | } |
112 | | |
113 | | /* used by synthesis, which has a full, alloced vi */ |
114 | 8.42k | void vorbis_info_init(vorbis_info *vi){ |
115 | 8.42k | memset(vi,0,sizeof(*vi)); |
116 | 8.42k | vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info)); |
117 | 8.42k | } |
118 | | |
119 | 11.6k | void vorbis_info_clear(vorbis_info *vi){ |
120 | 11.6k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
121 | 11.6k | int i; |
122 | | |
123 | 11.6k | if(ci){ |
124 | | |
125 | 17.6k | for(i=0;i<ci->modes;i++) |
126 | 9.24k | if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); |
127 | | |
128 | 16.5k | for(i=0;i<ci->maps;i++) /* unpack does the range checking */ |
129 | 8.11k | if(ci->map_param[i]) |
130 | 6.71k | _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); |
131 | | |
132 | 18.3k | for(i=0;i<ci->floors;i++) /* unpack does the range checking */ |
133 | 9.90k | if(ci->floor_param[i]) |
134 | 6.82k | _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); |
135 | | |
136 | 17.7k | for(i=0;i<ci->residues;i++) /* unpack does the range checking */ |
137 | 9.32k | if(ci->residue_param[i]) |
138 | 7.79k | _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); |
139 | | |
140 | 63.5k | for(i=0;i<ci->books;i++){ |
141 | 55.0k | if(ci->book_param[i]){ |
142 | | /* knows if the book was not alloced */ |
143 | 1.78k | vorbis_staticbook_destroy(ci->book_param[i]); |
144 | 1.78k | } |
145 | 55.0k | if(ci->fullbooks) |
146 | 10.5k | vorbis_book_clear(ci->fullbooks+i); |
147 | 55.0k | } |
148 | 8.42k | if(ci->fullbooks) |
149 | 6.32k | _ogg_free(ci->fullbooks); |
150 | | |
151 | 8.42k | _ogg_free(ci); |
152 | 8.42k | } |
153 | | |
154 | 11.6k | memset(vi,0,sizeof(*vi)); |
155 | 11.6k | } |
156 | | |
157 | | /* Header packing/unpacking ********************************************/ |
158 | | |
159 | 8.05k | static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ |
160 | 8.05k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
161 | 8.05k | if(!ci)return(OV_EFAULT); |
162 | | |
163 | 8.05k | vi->version=oggpack_read(opb,32); |
164 | 8.05k | if(vi->version!=0)return(OV_EVERSION); |
165 | | |
166 | 8.00k | vi->channels=oggpack_read(opb,8); |
167 | 8.00k | vi->rate=oggpack_read(opb,32); |
168 | | |
169 | 8.00k | vi->bitrate_upper=oggpack_read(opb,32); |
170 | 8.00k | vi->bitrate_nominal=oggpack_read(opb,32); |
171 | 8.00k | vi->bitrate_lower=oggpack_read(opb,32); |
172 | | |
173 | 8.00k | ci->blocksizes[0]=1<<oggpack_read(opb,4); |
174 | 8.00k | ci->blocksizes[1]=1<<oggpack_read(opb,4); |
175 | | |
176 | 8.00k | if(vi->rate<1)goto err_out; |
177 | 8.00k | if(vi->channels<1)goto err_out; |
178 | 7.99k | if(ci->blocksizes[0]<64)goto err_out; |
179 | 7.96k | if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out; |
180 | 7.95k | if(ci->blocksizes[1]>8192)goto err_out; |
181 | | |
182 | 7.94k | if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ |
183 | | |
184 | 7.94k | return(0); |
185 | 64 | err_out: |
186 | 64 | vorbis_info_clear(vi); |
187 | 64 | return(OV_EBADHEADER); |
188 | 7.94k | } |
189 | | |
190 | 7.62k | static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ |
191 | 7.62k | int i; |
192 | 7.62k | int vendorlen; |
193 | 7.62k | vendorlen=oggpack_read(opb,32); |
194 | 7.62k | if(vendorlen<0)goto err_out; |
195 | 7.58k | if(vendorlen>opb->storage-oggpack_bytes(opb))goto err_out; |
196 | 7.54k | vc->vendor=(char *)_ogg_calloc(vendorlen+1,1); |
197 | 7.54k | if(vc->vendor==NULL)goto err_out; |
198 | 7.54k | _v_readstring(opb,vc->vendor,vendorlen); |
199 | 7.54k | i=oggpack_read(opb,32); |
200 | 7.54k | if(i<0||i>=INT_MAX||i>(opb->storage-oggpack_bytes(opb))>>2)goto err_out; |
201 | 7.44k | vc->user_comments=(char **)_ogg_calloc(i+1,sizeof(*vc->user_comments)); |
202 | 7.44k | vc->comment_lengths=(int *)_ogg_calloc(i+1, sizeof(*vc->comment_lengths)); |
203 | 7.44k | if(vc->user_comments==NULL||vc->comment_lengths==NULL)goto err_out; |
204 | 7.44k | vc->comments=i; |
205 | | |
206 | 8.92k | for(i=0;i<vc->comments;i++){ |
207 | 1.59k | int len=oggpack_read(opb,32); |
208 | 1.59k | if(len<0||len>opb->storage-oggpack_bytes(opb))goto err_out; |
209 | 1.48k | vc->comment_lengths[i]=len; |
210 | 1.48k | vc->user_comments[i]=(char *)_ogg_calloc(len+1,1); |
211 | 1.48k | if(vc->user_comments[i]==NULL){ |
212 | 0 | vc->comments=i; |
213 | 0 | goto err_out; |
214 | 0 | } |
215 | 1.48k | _v_readstring(opb,vc->user_comments[i],len); |
216 | 1.48k | } |
217 | 7.33k | if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ |
218 | | |
219 | 7.32k | return(0); |
220 | 305 | err_out: |
221 | 305 | vorbis_comment_clear(vc); |
222 | 305 | return(OV_EBADHEADER); |
223 | 7.33k | } |
224 | | |
225 | | /* all of the real encoding details are here. The modes, books, |
226 | | everything */ |
227 | 7.29k | static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ |
228 | 7.29k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
229 | 7.29k | int i; |
230 | | |
231 | | /* codebooks */ |
232 | 7.29k | ci->books=oggpack_read(opb,8)+1; |
233 | 7.29k | if(ci->books<=0)goto err_out; |
234 | 19.6k | for(i=0;i<ci->books;i++){ |
235 | 12.7k | ci->book_param[i]=vorbis_staticbook_unpack(opb); |
236 | 12.7k | if(!ci->book_param[i])goto err_out; |
237 | 12.7k | } |
238 | | |
239 | | /* time backend settings */ |
240 | 6.93k | ci->times=oggpack_read(opb,6)+1; |
241 | 6.93k | if(ci->times<=0)goto err_out; |
242 | 13.8k | for(i=0;i<ci->times;i++){ |
243 | 7.00k | ci->time_type[i]=oggpack_read(opb,16); |
244 | 7.00k | if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out; |
245 | | /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb); |
246 | | Vorbis I has no time backend */ |
247 | | /*if(!ci->time_param[i])goto err_out;*/ |
248 | 7.00k | } |
249 | | |
250 | | /* floor backend settings */ |
251 | 6.86k | ci->floors=oggpack_read(opb,6)+1; |
252 | 6.86k | if(ci->floors<=0)goto err_out; |
253 | 13.6k | for(i=0;i<ci->floors;i++){ |
254 | 7.02k | ci->floor_type[i]=oggpack_read(opb,16); |
255 | 7.02k | if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; |
256 | 6.98k | ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); |
257 | 6.98k | if(!ci->floor_param[i])goto err_out; |
258 | 6.98k | } |
259 | | |
260 | | /* residue backend settings */ |
261 | 6.66k | ci->residues=oggpack_read(opb,6)+1; |
262 | 6.66k | if(ci->residues<=0)goto err_out; |
263 | 14.4k | for(i=0;i<ci->residues;i++){ |
264 | 7.92k | ci->residue_type[i]=oggpack_read(opb,16); |
265 | 7.92k | if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; |
266 | 7.88k | ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); |
267 | 7.88k | if(!ci->residue_param[i])goto err_out; |
268 | 7.88k | } |
269 | | |
270 | | /* map backend settings */ |
271 | 6.52k | ci->maps=oggpack_read(opb,6)+1; |
272 | 6.52k | if(ci->maps<=0)goto err_out; |
273 | 13.2k | for(i=0;i<ci->maps;i++){ |
274 | 6.85k | ci->map_type[i]=oggpack_read(opb,16); |
275 | 6.85k | if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; |
276 | 6.82k | ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); |
277 | 6.82k | if(!ci->map_param[i])goto err_out; |
278 | 6.82k | } |
279 | | |
280 | | /* mode settings */ |
281 | 6.37k | ci->modes=oggpack_read(opb,6)+1; |
282 | 6.37k | if(ci->modes<=0)goto err_out; |
283 | 14.9k | for(i=0;i<ci->modes;i++){ |
284 | 8.58k | ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i])); |
285 | 8.58k | ci->mode_param[i]->blockflag=oggpack_read(opb,1); |
286 | 8.58k | ci->mode_param[i]->windowtype=oggpack_read(opb,16); |
287 | 8.58k | ci->mode_param[i]->transformtype=oggpack_read(opb,16); |
288 | 8.58k | ci->mode_param[i]->mapping=oggpack_read(opb,8); |
289 | | |
290 | 8.58k | if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; |
291 | 8.57k | if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; |
292 | 8.56k | if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; |
293 | 8.55k | if(ci->mode_param[i]->mapping<0)goto err_out; |
294 | 8.55k | } |
295 | | |
296 | 6.33k | if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ |
297 | | |
298 | 6.32k | return(0); |
299 | 970 | err_out: |
300 | 970 | vorbis_info_clear(vi); |
301 | 970 | return(OV_EBADHEADER); |
302 | 6.33k | } |
303 | | |
304 | | /* Is this packet a vorbis ID header? */ |
305 | 10.1k | int vorbis_synthesis_idheader(ogg_packet *op){ |
306 | 10.1k | oggpack_buffer opb; |
307 | 10.1k | char buffer[6]; |
308 | | |
309 | 10.1k | if(op){ |
310 | 10.1k | oggpack_readinit(&opb,op->packet,op->bytes); |
311 | | |
312 | 10.1k | if(!op->b_o_s) |
313 | 272 | return(0); /* Not the initial packet */ |
314 | | |
315 | 9.89k | if(oggpack_read(&opb,8) != 1) |
316 | 1.04k | return 0; /* not an ID header */ |
317 | | |
318 | 8.84k | memset(buffer,0,6); |
319 | 8.84k | _v_readstring(&opb,buffer,6); |
320 | 8.84k | if(memcmp(buffer,"vorbis",6)) |
321 | 791 | return 0; /* not vorbis */ |
322 | | |
323 | 8.05k | return 1; |
324 | 8.84k | } |
325 | | |
326 | 0 | return 0; |
327 | 10.1k | } |
328 | | |
329 | | /* The Vorbis header is in three packets; the initial small packet in |
330 | | the first page that identifies basic parameters, a second packet |
331 | | with bitstream comments and a third packet that holds the |
332 | | codebook. */ |
333 | | |
334 | 23.0k | int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ |
335 | 23.0k | oggpack_buffer opb; |
336 | | |
337 | 23.0k | if(op){ |
338 | 23.0k | oggpack_readinit(&opb,op->packet,op->bytes); |
339 | | |
340 | | /* Which of the three types of header is this? */ |
341 | | /* Also verify header-ness, vorbis */ |
342 | 23.0k | { |
343 | 23.0k | char buffer[6]; |
344 | 23.0k | int packtype=oggpack_read(&opb,8); |
345 | 23.0k | memset(buffer,0,6); |
346 | 23.0k | _v_readstring(&opb,buffer,6); |
347 | 23.0k | if(memcmp(buffer,"vorbis",6)){ |
348 | | /* not a vorbis header */ |
349 | 35 | return(OV_ENOTVORBIS); |
350 | 35 | } |
351 | 23.0k | switch(packtype){ |
352 | 8.07k | case 0x01: /* least significant *bit* is read first */ |
353 | 8.07k | if(!op->b_o_s){ |
354 | | /* Not the initial packet */ |
355 | 1 | return(OV_EBADHEADER); |
356 | 1 | } |
357 | 8.07k | if(vi->rate!=0){ |
358 | | /* previously initialized info header */ |
359 | 23 | return(OV_EBADHEADER); |
360 | 23 | } |
361 | | |
362 | 8.05k | return(_vorbis_unpack_info(vi,&opb)); |
363 | | |
364 | 7.62k | case 0x03: /* least significant *bit* is read first */ |
365 | 7.62k | if(vi->rate==0){ |
366 | | /* um... we didn't get the initial header */ |
367 | 0 | return(OV_EBADHEADER); |
368 | 0 | } |
369 | 7.62k | if(vc->vendor!=NULL){ |
370 | | /* previously initialized comment header */ |
371 | 1 | return(OV_EBADHEADER); |
372 | 1 | } |
373 | | |
374 | 7.62k | return(_vorbis_unpack_comment(vc,&opb)); |
375 | | |
376 | 7.32k | case 0x05: /* least significant *bit* is read first */ |
377 | 7.32k | if(vi->rate==0 || vc->vendor==NULL){ |
378 | | /* um... we didn;t get the initial header or comments yet */ |
379 | 26 | return(OV_EBADHEADER); |
380 | 26 | } |
381 | 7.29k | if(vi->codec_setup==NULL){ |
382 | | /* improperly initialized vorbis_info */ |
383 | 0 | return(OV_EFAULT); |
384 | 0 | } |
385 | 7.29k | if(((codec_setup_info *)vi->codec_setup)->books>0){ |
386 | | /* previously initialized setup header */ |
387 | 0 | return(OV_EBADHEADER); |
388 | 0 | } |
389 | | |
390 | 7.29k | return(_vorbis_unpack_books(vi,&opb)); |
391 | | |
392 | 2 | default: |
393 | | /* Not a valid vorbis header type */ |
394 | 2 | return(OV_EBADHEADER); |
395 | 0 | break; |
396 | 23.0k | } |
397 | 23.0k | } |
398 | 23.0k | } |
399 | 0 | return(OV_EBADHEADER); |
400 | 23.0k | } |
401 | | |