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