1 /************************************************************************
2  * Copyright (C) 2002-2009, Xiph.org Foundation
3  * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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.
16  *     * 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.
20  *
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  ************************************************************************
33 
34  function: maintain the info structure, info <-> header packets
35 
36  ************************************************************************/
37 
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 */
_v_readstring(oggpack_buffer * o,char * buf,int bytes)52 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
53   while(bytes--){
54     *buf++=(char)oggpack_read(o,8);
55   }
56 }
57 
vorbis_comment_init(vorbis_comment * vc)58 void 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 */
tagcompare(const char * s1,const char * s2,int n)64 static 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 
vorbis_comment_query(vorbis_comment * vc,char * tag,int count)74 char *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 
vorbis_comment_query_count(vorbis_comment * vc,char * tag)95 int 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 
vorbis_comment_clear(vorbis_comment * vc)110 void 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 */
vorbis_info_blocksize(vorbis_info * vi,int zo)124 int 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 */
vorbis_info_init(vorbis_info * vi)130 void 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 
vorbis_info_clear(vorbis_info * vi)135 void 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 
_vorbis_unpack_info(vorbis_info * vi,oggpack_buffer * opb)179 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 
_vorbis_unpack_comment(vorbis_comment * vc,oggpack_buffer * opb)216 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   if(!vc->vendor)goto err_out;
222   _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));
226   if (!vc->user_comments){
227       vc->comments=0;
228       goto err_out;
229   }
230   vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
231   if (!vc->comment_lengths)goto err_out;
232 
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);
238     if(!vc->user_comments[i])goto err_out;
239     _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 */
_vorbis_unpack_books(vorbis_info * vi,oggpack_buffer * opb)251 int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
252   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));
259   if(!ci->book_param){
260     ci->books=0;
261     goto err_out;
262   }
263   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;
273   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   }
279   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;
291   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   }
296   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;
301   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   }
306   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=
314     (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   }
319   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 
vorbis_dsp_headerin(vorbis_info * vi,vorbis_comment * vc,ogg_packet * op)340 int 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 
396