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 _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 */ 244 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 313 int 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 369