Home | History | Annotate | Download | only in Tremolo
      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