Additional bulletproofing to hufftree decoding; reject underpopulated
authorMonty <xiphmont@xiph.org>
Mon, 28 Apr 2008 21:42:52 +0000 (21:42 +0000)
committerMonty <xiphmont@xiph.org>
Mon, 28 Apr 2008 21:42:52 +0000 (21:42 +0000)
trees up-front.

svn path=/trunk/vorbis/; revision=14811

doc/Vorbis_I_spec.pdf
examples/decoder_example.c
lib/block.c
lib/sharedbook.c

index af8695f..fdf75e1 100644 (file)
Binary files a/doc/Vorbis_I_spec.pdf and b/doc/Vorbis_I_spec.pdf differ
index 2ca4205..1507773 100644 (file)
@@ -198,108 +198,111 @@ int main(){
 
     /* OK, got and parsed all three headers. Initialize the Vorbis
        packet->PCM decoder. */
-    vorbis_synthesis_init(&vd,&vi); /* central decode state */
-    vorbis_block_init(&vd,&vb);     /* local state for most of the decode
-                                      so multiple block decodes can
-                                      proceed in parallel.  We could init
-                                      multiple vorbis_block structures
-                                      for vd here */
-    
-    /* The rest is just a straight decode loop until end of stream */
-    while(!eos){
+    if(vorbis_synthesis_init(&vd,&vi)==0){ /* central decode state */
+      vorbis_block_init(&vd,&vb);          /* local state for most of the decode
+                                             so multiple block decodes can
+                                             proceed in parallel.  We could init
+                                             multiple vorbis_block structures
+                                             for vd here */
+      
+      /* The rest is just a straight decode loop until end of stream */
       while(!eos){
-       int result=ogg_sync_pageout(&oy,&og);
-       if(result==0)break; /* need more data */
-       if(result<0){ /* missing or corrupt data at this page position */
-         fprintf(stderr,"Corrupt or missing data in bitstream; "
-                 "continuing...\n");
-       }else{
-         ogg_stream_pagein(&os,&og); /* can safely ignore errors at
-                                        this point */
-         while(1){
-           result=ogg_stream_packetout(&os,&op);
-
-           if(result==0)break; /* need more data */
-           if(result<0){ /* missing or corrupt data at this page position */
-             /* no reason to complain; already complained above */
-           }else{
-             /* we have a packet.  Decode it */
-             float **pcm;
-             int samples;
-             
-             if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
-               vorbis_synthesis_blockin(&vd,&vb);
-             /* 
-                
-             **pcm is a multichannel float vector.  In stereo, for
-             example, pcm[0] is left, and pcm[1] is right.  samples is
-             the size of each channel.  Convert the float values
-             (-1.<=range<=1.) to whatever PCM format and write it out */
+       while(!eos){
+         int result=ogg_sync_pageout(&oy,&og);
+         if(result==0)break; /* need more data */
+         if(result<0){ /* missing or corrupt data at this page position */
+           fprintf(stderr,"Corrupt or missing data in bitstream; "
+                   "continuing...\n");
+         }else{
+           ogg_stream_pagein(&os,&og); /* can safely ignore errors at
+                                          this point */
+           while(1){
+             result=ogg_stream_packetout(&os,&op);
              
-             while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
-               int j;
-               int clipflag=0;
-               int bout=(samples<convsize?samples:convsize);
+             if(result==0)break; /* need more data */
+             if(result<0){ /* missing or corrupt data at this page position */
+               /* no reason to complain; already complained above */
+             }else{
+               /* we have a packet.  Decode it */
+               float **pcm;
+               int samples;
                
-               /* convert floats to 16 bit signed ints (host order) and
-                  interleave */
-               for(i=0;i<vi.channels;i++){
-                 ogg_int16_t *ptr=convbuffer+i;
-                 float  *mono=pcm[i];
-                 for(j=0;j<bout;j++){
+               if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
+                 vorbis_synthesis_blockin(&vd,&vb);
+               /* 
+                  
+               **pcm is a multichannel float vector.  In stereo, for
+               example, pcm[0] is left, and pcm[1] is right.  samples is
+               the size of each channel.  Convert the float values
+               (-1.<=range<=1.) to whatever PCM format and write it out */
+               
+               while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
+                 int j;
+                 int clipflag=0;
+                 int bout=(samples<convsize?samples:convsize);
+                 
+                 /* convert floats to 16 bit signed ints (host order) and
+                    interleave */
+                 for(i=0;i<vi.channels;i++){
+                   ogg_int16_t *ptr=convbuffer+i;
+                   float  *mono=pcm[i];
+                   for(j=0;j<bout;j++){
 #if 1
-                   int val=mono[j]*32767.f;
+                     int val=mono[j]*32767.f;
 #else /* optional dither */
-                   int val=mono[j]*32767.f+drand48()-0.5f;
+                     int val=mono[j]*32767.f+drand48()-0.5f;
 #endif
-                   /* might as well guard against clipping */
-                   if(val>32767){
-                     val=32767;
-                     clipflag=1;
-                   }
-                   if(val<-32768){
-                     val=-32768;
-                     clipflag=1;
+                     /* might as well guard against clipping */
+                     if(val>32767){
+                       val=32767;
+                       clipflag=1;
+                     }
+                     if(val<-32768){
+                       val=-32768;
+                       clipflag=1;
+                     }
+                     *ptr=val;
+                     ptr+=vi.channels;
                    }
-                   *ptr=val;
-                   ptr+=vi.channels;
                  }
-               }
-               
-               if(clipflag)
-                 fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence));
-               
-               
-               fwrite(convbuffer,2*vi.channels,bout,stdout);
-               
-               vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
-                                                  many samples we
-                                                  actually consumed */
-             }     
+                 
+                 if(clipflag)
+                   fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence));
+                 
+                 
+                 fwrite(convbuffer,2*vi.channels,bout,stdout);
+                 
+                 vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
+                                                     many samples we
+                                                     actually consumed */
+               }           
+             }
            }
+           if(ogg_page_eos(&og))eos=1;
          }
-         if(ogg_page_eos(&og))eos=1;
+       }
+       if(!eos){
+         buffer=ogg_sync_buffer(&oy,4096);
+         bytes=fread(buffer,1,4096,stdin);
+         ogg_sync_wrote(&oy,bytes);
+         if(bytes==0)eos=1;
        }
       }
-      if(!eos){
-       buffer=ogg_sync_buffer(&oy,4096);
-       bytes=fread(buffer,1,4096,stdin);
-       ogg_sync_wrote(&oy,bytes);
-       if(bytes==0)eos=1;
-      }
+      
+      /* ogg_page and ogg_packet structs always point to storage in
+        libvorbis.  They're never freed or manipulated directly */
+      
+      vorbis_block_clear(&vb);
+      vorbis_dsp_clear(&vd);
+    }else{
+      fprintf(stderr,"Error: Corrupt header during playback initialization.\n");
     }
-    
+
     /* clean up this logical bitstream; before exit we see if we're
        followed by another [chained] */
-
-    ogg_stream_clear(&os);
-  
-    /* ogg_page and ogg_packet structs always point to storage in
-       libvorbis.  They're never freed or manipulated directly */
     
-    vorbis_block_clear(&vb);
-    vorbis_dsp_clear(&vd);
-       vorbis_comment_clear(&vc);
+    ogg_stream_clear(&os);
+    vorbis_comment_clear(&vc);
     vorbis_info_clear(&vi);  /* must be called last */
   }
 
index 50ab425..10d4024 100644 (file)
@@ -235,7 +235,8 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){
     if(!ci->fullbooks){
       ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
       for(i=0;i<ci->books;i++){
-       vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]);
+       if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
+         return -1;
        /* decode codebooks are now standalone after init */
        vorbis_staticbook_destroy(ci->book_param[i]);
        ci->book_param[i]=NULL;
@@ -694,9 +695,11 @@ int vorbis_synthesis_restart(vorbis_dsp_state *v){
 }
 
 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
-  if(_vds_shared_init(v,vi,0)) return 1;
+  if(_vds_shared_init(v,vi,0)){
+    vorbis_dsp_clear(v);
+    return 1;
+  }
   vorbis_synthesis_restart(v);
-
   return 0;
 }
 
index 4b9f65f..14f22ef 100644 (file)
@@ -124,7 +124,14 @@ ogg_uint32_t *_make_words(long *l,long n,long sparsecount){
     }else
       if(sparsecount==0)count++;
   }
-    
+  
+  /* sanity check the huffman tree; an underpopulated tree must be rejected. */
+  for(i=1;i<33;i++)
+    if(marker[i] & (0xffffffffUL>>(32-i))){
+      _ogg_free(r);
+      return(NULL);
+    }
+
   /* bitreverse the words because our bitwise packer/unpacker is LSb
      endian */
   for(i=0,count=0;i<n;i++){