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 */ 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 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 */ 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 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 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 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 */ 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 */ 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 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 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 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 */ 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 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