blob: 4f7272869def3fd9978a9de5e5ff08637337d158 [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
Andreas Huber1a7ca642010-05-07 10:37:02 -0700179int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
Gloria Wang79130732010-02-08 14:41:04 -0800180 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
Andreas Huber1a7ca642010-05-07 10:37:02 -0700216int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
Gloria Wang79130732010-02-08 14:41:04 -0800217 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);
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700221 if(!vc->vendor)goto err_out;
Gloria Wang79130732010-02-08 14:41:04 -0800222 _v_readstring(opb,vc->vendor,vendorlen);
223 vc->comments=oggpack_read(opb,32);
224 if(vc->comments<0)goto err_out;
225 vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700226 if (!vc->user_comments){
227 vc->comments=0;
228 goto err_out;
229 }
Gloria Wang79130732010-02-08 14:41:04 -0800230 vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700231 if (!vc->comment_lengths)goto err_out;
Gloria Wang79130732010-02-08 14:41:04 -0800232
233 for(i=0;i<vc->comments;i++){
234 int len=oggpack_read(opb,32);
235 if(len<0)goto err_out;
236 vc->comment_lengths[i]=len;
237 vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700238 if(!vc->user_comments[i])goto err_out;
Gloria Wang79130732010-02-08 14:41:04 -0800239 _v_readstring(opb,vc->user_comments[i],len);
240 }
241 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
242
243 return(0);
244 err_out:
245 vorbis_comment_clear(vc);
246 return(OV_EBADHEADER);
247}
248
249/* all of the real encoding details are here. The modes, books,
250 everything */
Andreas Huber1a7ca642010-05-07 10:37:02 -0700251int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
Gloria Wang79130732010-02-08 14:41:04 -0800252 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
253 int i;
254 if(!ci)return(OV_EFAULT);
255
256 /* codebooks */
257 ci->books=oggpack_read(opb,8)+1;
258 ci->book_param=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->book_param));
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700259 if(!ci->book_param){
260 ci->books=0;
261 goto err_out;
262 }
Gloria Wang79130732010-02-08 14:41:04 -0800263 for(i=0;i<ci->books;i++)
264 if(vorbis_book_unpack(opb,ci->book_param+i))goto err_out;
265
266 /* time backend settings, not actually used */
267 i=oggpack_read(opb,6);
268 for(;i>=0;i--)
269 if(oggpack_read(opb,16)!=0)goto err_out;
270
271 /* floor backend settings */
272 ci->floors=oggpack_read(opb,6)+1;
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700273 ci->floor_param=_ogg_calloc(ci->floors, sizeof(*ci->floor_param));
274 ci->floor_type=_ogg_calloc(ci->floors, sizeof(*ci->floor_type));
275 if(!ci->floor_param || !ci->floor_type){
276 ci->floors=0;
277 goto err_out;
278 }
Gloria Wang79130732010-02-08 14:41:04 -0800279 for(i=0;i<ci->floors;i++){
280 ci->floor_type[i]=(char)oggpack_read(opb,16);
281 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
282 if(ci->floor_type[i])
283 ci->floor_param[i]=floor1_info_unpack(vi,opb);
284 else
285 ci->floor_param[i]=floor0_info_unpack(vi,opb);
286 if(!ci->floor_param[i])goto err_out;
287 }
288
289 /* residue backend settings */
290 ci->residues=oggpack_read(opb,6)+1;
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700291 ci->residue_param=_ogg_calloc(ci->residues, sizeof(*ci->residue_param));
292 if (!ci->residue_param){
293 ci->residues=0;
294 goto err_out;
295 }
Gloria Wang79130732010-02-08 14:41:04 -0800296 for(i=0;i<ci->residues;i++)
297 if(res_unpack(ci->residue_param+i,vi,opb))goto err_out;
298
299 /* map backend settings */
300 ci->maps=oggpack_read(opb,6)+1;
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700301 ci->map_param=_ogg_calloc(ci->maps, sizeof(*ci->map_param));
302 if (!ci->map_param){
303 ci->maps=0;
304 goto err_out;
305 }
Gloria Wang79130732010-02-08 14:41:04 -0800306 for(i=0;i<ci->maps;i++){
307 if(oggpack_read(opb,16)!=0)goto err_out;
308 if(mapping_info_unpack(ci->map_param+i,vi,opb))goto err_out;
309 }
310
311 /* mode settings */
312 ci->modes=oggpack_read(opb,6)+1;
313 ci->mode_param=
Marco Nelissenafa1f6b2013-10-11 15:46:30 -0700314 (vorbis_info_mode *)_ogg_calloc(ci->modes, sizeof(*ci->mode_param));
315 if (!ci->mode_param){
316 ci->modes=0;
317 goto err_out;
318 }
Gloria Wang79130732010-02-08 14:41:04 -0800319 for(i=0;i<ci->modes;i++){
320 ci->mode_param[i].blockflag=(unsigned char)oggpack_read(opb,1);
321 if(oggpack_read(opb,16))goto err_out;
322 if(oggpack_read(opb,16))goto err_out;
323 ci->mode_param[i].mapping=(unsigned char)oggpack_read(opb,8);
324 if(ci->mode_param[i].mapping>=ci->maps)goto err_out;
325 }
326
327 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
328
329 return(0);
330 err_out:
331 vorbis_info_clear(vi);
332 return(OV_EBADHEADER);
333}
334
335/* The Vorbis header is in three packets; the initial small packet in
336 the first page that identifies basic parameters, a second packet
337 with bitstream comments and a third packet that holds the
338 codebook. */
339
340int vorbis_dsp_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
341 oggpack_buffer opb;
342
343 if(op){
344 oggpack_readinit(&opb,op->packet);
345
346 /* Which of the three types of header is this? */
347 /* Also verify header-ness, vorbis */
348 {
349 char buffer[6];
350 int packtype=oggpack_read(&opb,8);
351 memset(buffer,0,6);
352 _v_readstring(&opb,buffer,6);
353 if(memcmp(buffer,"vorbis",6)){
354 /* not a vorbis header */
355 return(OV_ENOTVORBIS);
356 }
357 switch(packtype){
358 case 0x01: /* least significant *bit* is read first */
359 if(!op->b_o_s){
360 /* Not the initial packet */
361 return(OV_EBADHEADER);
362 }
363 if(vi->rate!=0){
364 /* previously initialized info header */
365 return(OV_EBADHEADER);
366 }
367
368 return(_vorbis_unpack_info(vi,&opb));
369
370 case 0x03: /* least significant *bit* is read first */
371 if(vi->rate==0){
372 /* um... we didn't get the initial header */
373 return(OV_EBADHEADER);
374 }
375
376 return(_vorbis_unpack_comment(vc,&opb));
377
378 case 0x05: /* least significant *bit* is read first */
379 if(vi->rate==0 || vc->vendor==NULL){
380 /* um... we didn;t get the initial header or comments yet */
381 return(OV_EBADHEADER);
382 }
383
384 return(_vorbis_unpack_books(vi,&opb));
385
386 default:
387 /* Not a valid vorbis header type */
388 return(OV_EBADHEADER);
389 break;
390 }
391 }
392 }
393 return(OV_EBADHEADER);
394}
395