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