media/libtremor/lib/tremor_info.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /********************************************************************
     2  *                                                                  *
     3  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
     4  *                                                                  *
     5  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
     6  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
     7  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
     8  *                                                                  *
     9  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
    10  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
    11  *                                                                  *
    12  ********************************************************************
    14  function: maintain the info structure, info <-> header packets
    16  ********************************************************************/
    18 /* general handling of the header and the vorbis_info structure (and
    19    substructures) */
    21 #include <stdlib.h>
    22 #include <string.h>
    23 #include <ctype.h>
    24 #include <limits.h>
    25 #include <ogg/ogg.h>
    26 #include "ivorbiscodec.h"
    27 #include "codec_internal.h"
    28 #include "codebook.h"
    29 #include "registry.h"
    30 #include "window.h"
    31 #include "misc.h"
    33 /* helpers */
    34 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
    35   while(bytes--){
    36     *buf++=oggpack_read(o,8);
    37   }
    38 }
    40 void vorbis_comment_init(vorbis_comment *vc){
    41   memset(vc,0,sizeof(*vc));
    42 }
    44 /* This is more or less the same as strncasecmp - but that doesn't exist
    45  * everywhere, and this is a fairly trivial function, so we include it */
    46 static int tagcompare(const char *s1, const char *s2, int n){
    47   int c=0;
    48   while(c < n){
    49     if(toupper(s1[c]) != toupper(s2[c]))
    50       return !0;
    51     c++;
    52   }
    53   return 0;
    54 }
    56 char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
    57   long i;
    58   int found = 0;
    59   int taglen = strlen(tag)+1; /* +1 for the = we append */
    60   char *fulltag = (char *)alloca(taglen+ 1);
    62   strcpy(fulltag, tag);
    63   strcat(fulltag, "=");
    65   for(i=0;i<vc->comments;i++){
    66     if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
    67       if(count == found)
    68 	/* We return a pointer to the data, not a copy */
    69       	return vc->user_comments[i] + taglen;
    70       else
    71 	found++;
    72     }
    73   }
    74   return NULL; /* didn't find anything */
    75 }
    77 int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
    78   int i,count=0;
    79   int taglen = strlen(tag)+1; /* +1 for the = we append */
    80   char *fulltag = (char *)alloca(taglen+1);
    81   strcpy(fulltag,tag);
    82   strcat(fulltag, "=");
    84   for(i=0;i<vc->comments;i++){
    85     if(!tagcompare(vc->user_comments[i], fulltag, taglen))
    86       count++;
    87   }
    89   return count;
    90 }
    92 void vorbis_comment_clear(vorbis_comment *vc){
    93   if(vc){
    94     long i;
    95     if(vc->user_comments){
    96       for(i=0;i<vc->comments;i++)
    97         if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
    98       _ogg_free(vc->user_comments);
    99     }
   100     if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
   101     if(vc->vendor)_ogg_free(vc->vendor);
   102     memset(vc,0,sizeof(*vc));
   103   }
   104 }
   106 /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
   107    They may be equal, but short will never ge greater than long */
   108 int vorbis_info_blocksize(vorbis_info *vi,int zo){
   109   codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
   110   return ci ? ci->blocksizes[zo] : -1;
   111 }
   113 /* used by synthesis, which has a full, alloced vi */
   114 void vorbis_info_init(vorbis_info *vi){
   115   memset(vi,0,sizeof(*vi));
   116   vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
   117 }
   119 void vorbis_info_clear(vorbis_info *vi){
   120   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
   121   int i;
   123   if(ci){
   125     for(i=0;i<ci->modes;i++)
   126       if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
   128     for(i=0;i<ci->maps;i++) /* unpack does the range checking */
   129       if(ci->map_param[i])
   130 	_mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
   132     for(i=0;i<ci->floors;i++) /* unpack does the range checking */
   133       if(ci->floor_param[i])
   134 	_floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
   136     for(i=0;i<ci->residues;i++) /* unpack does the range checking */
   137       if(ci->residue_param[i])
   138 	_residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
   140     for(i=0;i<ci->books;i++){
   141       if(ci->book_param[i]){
   142 	/* knows if the book was not alloced */
   143 	vorbis_staticbook_destroy(ci->book_param[i]);
   144       }
   145       if(ci->fullbooks)
   146 	vorbis_book_clear(ci->fullbooks+i);
   147     }
   148     if(ci->fullbooks)
   149 	_ogg_free(ci->fullbooks);
   151     _ogg_free(ci);
   152   }
   154   memset(vi,0,sizeof(*vi));
   155 }
   157 /* Header packing/unpacking ********************************************/
   159 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
   160   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
   161   if(!ci)return(OV_EFAULT);
   163   vi->version=oggpack_read(opb,32);
   164   if(vi->version!=0)return(OV_EVERSION);
   166   vi->channels=oggpack_read(opb,8);
   167   vi->rate=oggpack_read(opb,32);
   169   vi->bitrate_upper=oggpack_read(opb,32);
   170   vi->bitrate_nominal=oggpack_read(opb,32);
   171   vi->bitrate_lower=oggpack_read(opb,32);
   173   ci->blocksizes[0]=1<<oggpack_read(opb,4);
   174   ci->blocksizes[1]=1<<oggpack_read(opb,4);
   176   if(vi->rate<1)goto err_out;
   177   if(vi->channels<1)goto err_out;
   178   if(ci->blocksizes[0]<64)goto err_out; 
   179   if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
   180   if(ci->blocksizes[1]>8192)goto err_out;
   182   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
   184   return(0);
   185  err_out:
   186   vorbis_info_clear(vi);
   187   return(OV_EBADHEADER);
   188 }
   190 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
   191   int i;
   192   int vendorlen;
   193   vendorlen=oggpack_read(opb,32);
   194   if(vendorlen<0)goto err_out;
   195   if(vendorlen>opb->storage-oggpack_bytes(opb))goto err_out;
   196   vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
   197   if(vc->vendor==NULL)goto err_out;
   198   _v_readstring(opb,vc->vendor,vendorlen);
   199   i=oggpack_read(opb,32);
   200   if(i<0||i>=INT_MAX||i>(opb->storage-oggpack_bytes(opb))>>2)goto err_out;
   201   vc->user_comments=(char **)_ogg_calloc(i+1,sizeof(*vc->user_comments));
   202   vc->comment_lengths=(int *)_ogg_calloc(i+1, sizeof(*vc->comment_lengths));
   203   if(vc->user_comments==NULL||vc->comment_lengths==NULL)goto err_out;
   204   vc->comments=i;
   206   for(i=0;i<vc->comments;i++){
   207     int len=oggpack_read(opb,32);
   208     if(len<0||len>opb->storage-oggpack_bytes(opb))goto err_out;
   209     vc->comment_lengths[i]=len;
   210     vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
   211     if(vc->user_comments[i]==NULL){
   212       vc->comments=i;
   213       goto err_out;
   214     }
   215     _v_readstring(opb,vc->user_comments[i],len);
   216   }
   217   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
   219   return(0);
   220  err_out:
   221   vorbis_comment_clear(vc);
   222   return(OV_EBADHEADER);
   223 }
   225 /* all of the real encoding details are here.  The modes, books,
   226    everything */
   227 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
   228   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
   229   int i;
   230   if(!ci)return(OV_EFAULT);
   232   /* codebooks */
   233   ci->books=oggpack_read(opb,8)+1;
   234   if(ci->books<=0)goto err_out;
   235   for(i=0;i<ci->books;i++){
   236     ci->book_param[i]=vorbis_staticbook_unpack(opb);
   237     if(!ci->book_param[i])goto err_out;
   238   }
   240   /* time backend settings */
   241   ci->times=oggpack_read(opb,6)+1;
   242   if(ci->times<=0)goto err_out;
   243   for(i=0;i<ci->times;i++){
   244     ci->time_type[i]=oggpack_read(opb,16);
   245     if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
   246     /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
   247        Vorbis I has no time backend */
   248     /*if(!ci->time_param[i])goto err_out;*/
   249   }
   251   /* floor backend settings */
   252   ci->floors=oggpack_read(opb,6)+1;
   253   if(ci->floors<=0)goto err_out;
   254   for(i=0;i<ci->floors;i++){
   255     ci->floor_type[i]=oggpack_read(opb,16);
   256     if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
   257     ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
   258     if(!ci->floor_param[i])goto err_out;
   259   }
   261   /* residue backend settings */
   262   ci->residues=oggpack_read(opb,6)+1;
   263   if(ci->residues<=0)goto err_out;
   264   for(i=0;i<ci->residues;i++){
   265     ci->residue_type[i]=oggpack_read(opb,16);
   266     if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
   267     ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
   268     if(!ci->residue_param[i])goto err_out;
   269   }
   271   /* map backend settings */
   272   ci->maps=oggpack_read(opb,6)+1;
   273   if(ci->maps<=0)goto err_out;
   274   for(i=0;i<ci->maps;i++){
   275     ci->map_type[i]=oggpack_read(opb,16);
   276     if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
   277     ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
   278     if(!ci->map_param[i])goto err_out;
   279   }
   281   /* mode settings */
   282   ci->modes=oggpack_read(opb,6)+1;
   283   if(ci->modes<=0)goto err_out;
   284   for(i=0;i<ci->modes;i++){
   285     ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
   286     ci->mode_param[i]->blockflag=oggpack_read(opb,1);
   287     ci->mode_param[i]->windowtype=oggpack_read(opb,16);
   288     ci->mode_param[i]->transformtype=oggpack_read(opb,16);
   289     ci->mode_param[i]->mapping=oggpack_read(opb,8);
   291     if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
   292     if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
   293     if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
   294     if(ci->mode_param[i]->mapping<0)goto err_out;
   295   }
   297   if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
   299   return(0);
   300  err_out:
   301   vorbis_info_clear(vi);
   302   return(OV_EBADHEADER);
   303 }
   305 /* Is this packet a vorbis ID header? */
   306 int vorbis_synthesis_idheader(ogg_packet *op){
   307   oggpack_buffer opb;
   308   char buffer[6];
   310   if(op){
   311     oggpack_readinit(&opb,op->packet,op->bytes);
   313     if(!op->b_o_s)
   314       return(0); /* Not the initial packet */
   316     if(oggpack_read(&opb,8) != 1)
   317       return 0; /* not an ID header */
   319     memset(buffer,0,6);
   320     _v_readstring(&opb,buffer,6);
   321     if(memcmp(buffer,"vorbis",6))
   322       return 0; /* not vorbis */
   324     return 1;
   325   }
   327   return 0;
   328 }
   330 /* The Vorbis header is in three packets; the initial small packet in
   331    the first page that identifies basic parameters, a second packet
   332    with bitstream comments and a third packet that holds the
   333    codebook. */
   335 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
   336   oggpack_buffer opb;
   338   if(op){
   339     oggpack_readinit(&opb,op->packet,op->bytes);
   341     /* Which of the three types of header is this? */
   342     /* Also verify header-ness, vorbis */
   343     {
   344       char buffer[6];
   345       int packtype=oggpack_read(&opb,8);
   346       memset(buffer,0,6);
   347       _v_readstring(&opb,buffer,6);
   348       if(memcmp(buffer,"vorbis",6)){
   349 	/* not a vorbis header */
   350 	return(OV_ENOTVORBIS);
   351       }
   352       switch(packtype){
   353       case 0x01: /* least significant *bit* is read first */
   354 	if(!op->b_o_s){
   355 	  /* Not the initial packet */
   356 	  return(OV_EBADHEADER);
   357 	}
   358 	if(vi->rate!=0){
   359 	  /* previously initialized info header */
   360 	  return(OV_EBADHEADER);
   361 	}
   363 	return(_vorbis_unpack_info(vi,&opb));
   365       case 0x03: /* least significant *bit* is read first */
   366 	if(vi->rate==0){
   367 	  /* um... we didn't get the initial header */
   368 	  return(OV_EBADHEADER);
   369 	}
   371 	return(_vorbis_unpack_comment(vc,&opb));
   373       case 0x05: /* least significant *bit* is read first */
   374 	if(vi->rate==0 || vc->vendor==NULL){
   375 	  /* um... we didn;t get the initial header or comments yet */
   376 	  return(OV_EBADHEADER);
   377 	}
   379 	return(_vorbis_unpack_books(vi,&opb));
   381       default:
   382 	/* Not a valid vorbis header type */
   383 	return(OV_EBADHEADER);
   384 	break;
   385       }
   386     }
   387   }
   388   return(OV_EBADHEADER);
   389 }

mercurial