blob: 248455d2627ae9ada7b464370501a5741a421b0b [file] [log] [blame]
Gloria Wang37fe1582010-03-12 14:53:20 -08001/************************************************************************
2 * Copyright (C) 2010, The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of the Android Open Source Project nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 ************************************************************************
Gloria Wang79130732010-02-08 14:41:04 -080031
32 function: maintain the info structure, info <-> header packets
33
Gloria Wang37fe1582010-03-12 14:53:20 -080034 ************************************************************************/
Gloria Wang79130732010-02-08 14:41:04 -080035
36/* general handling of the header and the vorbis_info structure (and
37 substructures) */
38
39#include <stdlib.h>
40#include <string.h>
41#include <ctype.h>
42#include "ogg.h"
43#include "ivorbiscodec.h"
44#include "codec_internal.h"
45#include "codebook.h"
46#include "misc.h"
47#include "os.h"
48
49/* helpers */
50static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
51 while(bytes--){
52 *buf++=(char)oggpack_read(o,8);
53 }
54}
55
56void vorbis_comment_init(vorbis_comment *vc){
57 memset(vc,0,sizeof(*vc));
58}
59
60/* This is more or less the same as strncasecmp - but that doesn't exist
61 * everywhere, and this is a fairly trivial function, so we include it */
62static int tagcompare(const char *s1, const char *s2, int n){
63 int c=0;
64 while(c < n){
65 if(toupper(s1[c]) != toupper(s2[c]))
66 return !0;
67 c++;
68 }
69 return 0;
70}
71
72char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
73 long i;
74 int found = 0;
75 int taglen = strlen(tag)+1; /* +1 for the = we append */
76 char *fulltag = (char *)alloca(taglen+ 1);
77
78 strcpy(fulltag, tag);
79 strcat(fulltag, "=");
80
81 for(i=0;i<vc->comments;i++){
82 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
83 if(count == found)
84 /* We return a pointer to the data, not a copy */
85 return vc->user_comments[i] + taglen;
86 else
87 found++;
88 }
89 }
90 return NULL; /* didn't find anything */
91}
92
93int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
94 int i,count=0;
95 int taglen = strlen(tag)+1; /* +1 for the = we append */
96 char *fulltag = (char *)alloca(taglen+1);
97 strcpy(fulltag,tag);
98 strcat(fulltag, "=");
99
100 for(i=0;i<vc->comments;i++){
101 if(!tagcompare(vc->user_comments[i], fulltag, taglen))
102 count++;
103 }
104
105 return count;
106}
107
108void vorbis_comment_clear(vorbis_comment *vc){
109 if(vc){
110 long i;
111 for(i=0;i<vc->comments;i++)
112 if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
113 if(vc->user_comments)_ogg_free(vc->user_comments);
114 if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
115 if(vc->vendor)_ogg_free(vc->vendor);
116 }
117 memset(vc,0,sizeof(*vc));
118}
119
120/* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
121 They may be equal, but short will never ge greater than long */
122int vorbis_info_blocksize(vorbis_info *vi,int zo){
123 codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
124 return ci ? ci->blocksizes[zo] : -1;
125}
126
127/* used by synthesis, which has a full, alloced vi */
128void vorbis_info_init(vorbis_info *vi){
129 memset(vi,0,sizeof(*vi));
130 vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
131}
132
133void vorbis_info_clear(vorbis_info *vi){
134 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
135 int i;
136
137 if(ci){
138
139 if(ci->mode_param)_ogg_free(ci->mode_param);
140
141 if(ci->map_param){
142 for(i=0;i<ci->maps;i++) /* unpack does the range checking */
143 mapping_clear_info(ci->map_param+i);
144 _ogg_free(ci->map_param);
145 }
146
147 if(ci->floor_param){
148 for(i=0;i<ci->floors;i++) /* unpack does the range checking */
149 if(ci->floor_type[i])
150 floor1_free_info(ci->floor_param[i]);
151 else
152 floor0_free_info(ci->floor_param[i]);
153 _ogg_free(ci->floor_param);
154 _ogg_free(ci->floor_type);
155 }
156
157 if(ci->residue_param){
158 for(i=0;i<ci->residues;i++) /* unpack does the range checking */
159 res_clear_info(ci->residue_param+i);
160 _ogg_free(ci->residue_param);
161 }
162
163 if(ci->book_param){
164 for(i=0;i<ci->books;i++)
165 vorbis_book_clear(ci->book_param+i);
166 _ogg_free(ci->book_param);
167 }
168
169 _ogg_free(ci);
170 }
171
172 memset(vi,0,sizeof(*vi));
173}
174
175/* Header packing/unpacking ********************************************/
176
177static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
178 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
179 if(!ci)return(OV_EFAULT);
180
181 vi->version=oggpack_read(opb,32);
182 if(vi->version!=0)return(OV_EVERSION);
183
184 vi->channels=oggpack_read(opb,8);
185 vi->rate=oggpack_read(opb,32);
186
187 vi->bitrate_upper=oggpack_read(opb,32);
188 vi->bitrate_nominal=oggpack_read(opb,32);
189 vi->bitrate_lower=oggpack_read(opb,32);
190
191 ci->blocksizes[0]=1<<oggpack_read(opb,4);
192 ci->blocksizes[1]=1<<oggpack_read(opb,4);
193
194#ifdef LIMIT_TO_64kHz
195 if(vi->rate>=64000 || ci->blocksizes[1]>4096)goto err_out;
196#else
197 if(vi->rate<64000 && ci->blocksizes[1]>4096)goto err_out;
198#endif
199
200 if(vi->rate<1)goto err_out;
201 if(vi->channels<1)goto err_out;
202 if(ci->blocksizes[0]<64)goto err_out;
203 if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
204 if(ci->blocksizes[1]>8192)goto err_out;
205
206 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
207
208 return(0);
209 err_out:
210 vorbis_info_clear(vi);
211 return(OV_EBADHEADER);
212}
213
214static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
215 int i;
216 int vendorlen=oggpack_read(opb,32);
217 if(vendorlen<0)goto err_out;
218 vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
219 _v_readstring(opb,vc->vendor,vendorlen);
220 vc->comments=oggpack_read(opb,32);
221 if(vc->comments<0)goto err_out;
222 vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
223 vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
224
225 for(i=0;i<vc->comments;i++){
226 int len=oggpack_read(opb,32);
227 if(len<0)goto err_out;
228 vc->comment_lengths[i]=len;
229 vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
230 _v_readstring(opb,vc->user_comments[i],len);
231 }
232 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
233
234 return(0);
235 err_out:
236 vorbis_comment_clear(vc);
237 return(OV_EBADHEADER);
238}
239
240/* all of the real encoding details are here. The modes, books,
241 everything */
242static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
243 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
244 int i;
245 if(!ci)return(OV_EFAULT);
246
247 /* codebooks */
248 ci->books=oggpack_read(opb,8)+1;
249 ci->book_param=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->book_param));
250 for(i=0;i<ci->books;i++)
251 if(vorbis_book_unpack(opb,ci->book_param+i))goto err_out;
252
253 /* time backend settings, not actually used */
254 i=oggpack_read(opb,6);
255 for(;i>=0;i--)
256 if(oggpack_read(opb,16)!=0)goto err_out;
257
258 /* floor backend settings */
259 ci->floors=oggpack_read(opb,6)+1;
260 ci->floor_param=_ogg_malloc(sizeof(*ci->floor_param)*ci->floors);
261 ci->floor_type=_ogg_malloc(sizeof(*ci->floor_type)*ci->floors);
262 for(i=0;i<ci->floors;i++){
263 ci->floor_type[i]=(char)oggpack_read(opb,16);
264 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
265 if(ci->floor_type[i])
266 ci->floor_param[i]=floor1_info_unpack(vi,opb);
267 else
268 ci->floor_param[i]=floor0_info_unpack(vi,opb);
269 if(!ci->floor_param[i])goto err_out;
270 }
271
272 /* residue backend settings */
273 ci->residues=oggpack_read(opb,6)+1;
274 ci->residue_param=_ogg_malloc(sizeof(*ci->residue_param)*ci->residues);
275 for(i=0;i<ci->residues;i++)
276 if(res_unpack(ci->residue_param+i,vi,opb))goto err_out;
277
278 /* map backend settings */
279 ci->maps=oggpack_read(opb,6)+1;
280 ci->map_param=_ogg_malloc(sizeof(*ci->map_param)*ci->maps);
281 for(i=0;i<ci->maps;i++){
282 if(oggpack_read(opb,16)!=0)goto err_out;
283 if(mapping_info_unpack(ci->map_param+i,vi,opb))goto err_out;
284 }
285
286 /* mode settings */
287 ci->modes=oggpack_read(opb,6)+1;
288 ci->mode_param=
289 (vorbis_info_mode *)_ogg_malloc(ci->modes*sizeof(*ci->mode_param));
290 for(i=0;i<ci->modes;i++){
291 ci->mode_param[i].blockflag=(unsigned char)oggpack_read(opb,1);
292 if(oggpack_read(opb,16))goto err_out;
293 if(oggpack_read(opb,16))goto err_out;
294 ci->mode_param[i].mapping=(unsigned char)oggpack_read(opb,8);
295 if(ci->mode_param[i].mapping>=ci->maps)goto err_out;
296 }
297
298 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
299
300 return(0);
301 err_out:
302 vorbis_info_clear(vi);
303 return(OV_EBADHEADER);
304}
305
306/* The Vorbis header is in three packets; the initial small packet in
307 the first page that identifies basic parameters, a second packet
308 with bitstream comments and a third packet that holds the
309 codebook. */
310
311int vorbis_dsp_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
312 oggpack_buffer opb;
313
314 if(op){
315 oggpack_readinit(&opb,op->packet);
316
317 /* Which of the three types of header is this? */
318 /* Also verify header-ness, vorbis */
319 {
320 char buffer[6];
321 int packtype=oggpack_read(&opb,8);
322 memset(buffer,0,6);
323 _v_readstring(&opb,buffer,6);
324 if(memcmp(buffer,"vorbis",6)){
325 /* not a vorbis header */
326 return(OV_ENOTVORBIS);
327 }
328 switch(packtype){
329 case 0x01: /* least significant *bit* is read first */
330 if(!op->b_o_s){
331 /* Not the initial packet */
332 return(OV_EBADHEADER);
333 }
334 if(vi->rate!=0){
335 /* previously initialized info header */
336 return(OV_EBADHEADER);
337 }
338
339 return(_vorbis_unpack_info(vi,&opb));
340
341 case 0x03: /* least significant *bit* is read first */
342 if(vi->rate==0){
343 /* um... we didn't get the initial header */
344 return(OV_EBADHEADER);
345 }
346
347 return(_vorbis_unpack_comment(vc,&opb));
348
349 case 0x05: /* least significant *bit* is read first */
350 if(vi->rate==0 || vc->vendor==NULL){
351 /* um... we didn;t get the initial header or comments yet */
352 return(OV_EBADHEADER);
353 }
354
355 return(_vorbis_unpack_books(vi,&opb));
356
357 default:
358 /* Not a valid vorbis header type */
359 return(OV_EBADHEADER);
360 break;
361 }
362 }
363 }
364 return(OV_EBADHEADER);
365}
366