Correct a longstanding bug in the 16u2 codebook; the bug was harmless (though it...
[platform/upstream/libvorbis.git] / lib / res0.c
index 7bdde0e..e5c7c87 100644 (file)
@@ -5,7 +5,7 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010             *
  * by the Xiph.Org Foundation http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 #include "misc.h"
 #include "os.h"
 
+//#define TRAIN_RES 1
+//#define TRAIN_RESAUX 1
+
 #if defined(TRAIN_RES) || defined (TRAIN_RESAUX)
 #include <stdio.h>
-#endif 
+#endif
 
 typedef struct {
   vorbis_info_residue0 *info;
-  
+
   int         parts;
   int         stages;
   codebook   *fullbooks;
@@ -58,6 +61,7 @@ typedef struct {
   float      training_min[8][64];
   float     tmin;
   float     tmax;
+  int       submap;
 #endif
 
 } vorbis_look_residue0;
@@ -86,16 +90,16 @@ void res0_free_look(vorbis_look_residue *i){
             char buffer[80];
             FILE *of;
             codebook *statebook=look->partbooks[j][k];
-            
+
             /* long and short into the same bucket by current convention */
-            sprintf(buffer,"res_part%d_pass%d.vqd",j,k);
+            sprintf(buffer,"res_sub%d_part%d_pass%d.vqd",look->submap,j,k);
             of=fopen(buffer,"a");
 
             for(l=0;l<statebook->entries;l++)
               fprintf(of,"%d:%ld\n",l,look->training_data[k][j][l]);
-            
+
             fclose(of);
-            
+
             /*fprintf(stderr,"%d(%.2f|%.2f) ",k,
               look->training_min[k][j],look->training_max[k][j]);*/
 
@@ -121,7 +125,7 @@ void res0_free_look(vorbis_look_residue *i){
             "(%g/frame) \n",look->frames,look->phrasebits,
             look->resbitsflat,
             (look->phrasebits+look->resbitsflat)/(float)look->frames);
-    
+
     for(j=0;j<look->parts;j++){
       long acc=0;
       fprintf(stderr,"\t[%d] == ",j);
@@ -173,7 +177,7 @@ void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){
   oggpack_write(opb,info->begin,24);
   oggpack_write(opb,info->end,24);
 
-  oggpack_write(opb,info->grouping-1,24);  /* residue vectors to group and 
+  oggpack_write(opb,info->grouping-1,24);  /* residue vectors to group and
                                              code with a partitioned book */
   oggpack_write(opb,info->partitions-1,6); /* possible partition choices */
   oggpack_write(opb,info->groupbook,8);  /* group huffman book */
@@ -184,9 +188,9 @@ void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){
   for(j=0;j<info->partitions;j++){
     if(ilog(info->secondstages[j])>3){
       /* yes, this is a minor hack due to not thinking ahead */
-      oggpack_write(opb,info->secondstages[j],3); 
+      oggpack_write(opb,info->secondstages[j],3);
       oggpack_write(opb,1,1);
-      oggpack_write(opb,info->secondstages[j]>>3,5); 
+      oggpack_write(opb,info->secondstages[j]>>3,5);
     }else
       oggpack_write(opb,info->secondstages[j],4); /* trailing zero */
     acc+=icount(info->secondstages[j]);
@@ -238,6 +242,10 @@ vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
 
   /* verify the phrasebook is not specifying an impossible or
      inconsistent partitioning scheme. */
+  /* modify the phrasebook ranging check from r16327; an early beta
+     encoder had a bug where it used an oversized phrasebook by
+     accident.  These files should continue to be playable, but don't
+     allow an exploit */
   {
     int entries = ci->book_param[info->groupbook]->entries;
     int dim = ci->book_param[info->groupbook]->dim;
@@ -247,6 +255,7 @@ vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
       if(partvals > entries) goto errout;
       dim--;
     }
+    info->partvals = partvals;
   }
 
   return(info);
@@ -316,65 +325,71 @@ vorbis_look_residue *res0_look(vorbis_dsp_state *vd,
 }
 
 /* break an abstraction and copy some code for performance purposes */
-static int local_book_besterror(codebook *book,float *a){
-  int dim=book->dim,i,k,o;
-  int best=0;
-  encode_aux_threshmatch *tt=book->c->thresh_tree;
-
-  /* find the quant val of each scalar */
-  for(k=0,o=dim;k<dim;++k){
-    float val=a[--o];
-    i=tt->threshvals>>1;
-
-    if(val<tt->quantthresh[i]){      
-      if(val<tt->quantthresh[i-1]){
-        for(--i;i>0;--i)
-          if(val>=tt->quantthresh[i-1])
-            break;
-      }
-    }else{
-      
-      for(++i;i<tt->threshvals-1;++i)
-        if(val<tt->quantthresh[i])break;
-      
+static int local_book_besterror(codebook *book,int *a){
+  int dim=book->dim;
+  int i,j,o;
+  int minval=book->minval;
+  int del=book->delta;
+  int qv=book->quantvals;
+  int ze=(qv>>1);
+  int index=0;
+  /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
+  int p[8]={0,0,0,0,0,0,0,0};
+
+  if(del!=1){
+    for(i=0,o=dim;i<dim;i++){
+      int v = (a[--o]-minval+(del>>1))/del;
+      int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1));
+      index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
+      p[o]=v*del+minval;
+    }
+  }else{
+    for(i=0,o=dim;i<dim;i++){
+      int v = a[--o]-minval;
+      int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1));
+      index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
+      p[o]=v*del+minval;
     }
-
-    best=(best*tt->quantvals)+tt->quantmap[i];
   }
-  /* regular lattices are easy :-) */
-  
-  if(book->c->lengthlist[best]<=0){
+
+  if(book->c->lengthlist[index]<=0){
     const static_codebook *c=book->c;
-    int i,j;
-    float bestf=0.f;
-    float *e=book->valuelist;
-    best=-1;
+    int best=-1;
+    /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
+    int e[8]={0,0,0,0,0,0,0,0};
+    int maxval = book->minval + book->delta*(book->quantvals-1);
     for(i=0;i<book->entries;i++){
       if(c->lengthlist[i]>0){
-        float this=0.f;
+        int this=0;
         for(j=0;j<dim;j++){
-          float val=(e[j]-a[j]);
+          int val=(e[j]-a[j]);
           this+=val*val;
         }
-        if(best==-1 || this<bestf){
-          bestf=this;
-          best=i;
+        if(best==-1 || this<best){
+          memcpy(p,e,sizeof(p));
+          best=this;
+          index=i;
         }
       }
-      e+=dim;
+      /* assumes the value patterning created by the tools in vq/ */
+      j=0;
+      while(e[j]>=maxval)
+        e[j++]=0;
+      if(e[j]>=0)
+        e[j]+=book->delta;
+      e[j]= -e[j];
     }
   }
 
-  if(best>-1){
-    float *ptr=book->valuelist+best*dim;
+  if(index>-1){
     for(i=0;i<dim;i++)
-      *a++ -= *ptr++;
+      *a++ -= p[i];
   }
 
-  return(best);
+  return(index);
 }
 
-static int _encodepart(oggpack_buffer *opb,float *vec, int n,
+static int _encodepart(oggpack_buffer *opb,int *vec, int n,
                        codebook *book,long *acc){
   int i,bits=0;
   int dim=book->dim;
@@ -384,19 +399,19 @@ static int _encodepart(oggpack_buffer *opb,float *vec, int n,
     int entry=local_book_besterror(book,vec+i*dim);
 
 #ifdef TRAIN_RES
-    if(entry>0)
+    if(entry>=0)
       acc[entry]++;
 #endif
-      
+
     bits+=vorbis_book_encode(book,entry,opb);
-  
+
   }
 
   return(bits);
 }
 
 static long **_01class(vorbis_block *vb,vorbis_look_residue *vl,
-                       float **in,int ch){
+                       int **in,int ch){
   long i,j,k;
   vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
   vorbis_info_residue0 *info=look->info;
@@ -405,45 +420,45 @@ static long **_01class(vorbis_block *vb,vorbis_look_residue *vl,
   int samples_per_partition=info->grouping;
   int possible_partitions=info->partitions;
   int n=info->end-info->begin;
-  
+
   int partvals=n/samples_per_partition;
   long **partword=_vorbis_block_alloc(vb,ch*sizeof(*partword));
   float scale=100./samples_per_partition;
-  
+
   /* we find the partition type for each partition of each
      channel.  We'll go back and do the interleaved encoding in a
      bit.  For now, clarity */
-  
+
   for(i=0;i<ch;i++){
     partword[i]=_vorbis_block_alloc(vb,n/samples_per_partition*sizeof(*partword[i]));
     memset(partword[i],0,n/samples_per_partition*sizeof(*partword[i]));
   }
-  
+
   for(i=0;i<partvals;i++){
     int offset=i*samples_per_partition+info->begin;
     for(j=0;j<ch;j++){
-      float max=0.;
-      float ent=0.;
+      int max=0;
+      int ent=0;
       for(k=0;k<samples_per_partition;k++){
-        if(fabs(in[j][offset+k])>max)max=fabs(in[j][offset+k]);
-        ent+=fabs(rint(in[j][offset+k]));
+        if(abs(in[j][offset+k])>max)max=abs(in[j][offset+k]);
+        ent+=abs(in[j][offset+k]);
       }
       ent*=scale;
-      
+
       for(k=0;k<possible_partitions-1;k++)
         if(max<=info->classmetric1[k] &&
-           (info->classmetric2[k]<0 || (int)ent<info->classmetric2[k]))
+           (info->classmetric2[k]<0 || ent<info->classmetric2[k]))
           break;
-      
-      partword[j][i]=k;  
+
+      partword[j][i]=k;
     }
   }
-  
+
 #ifdef TRAIN_RESAUX
   {
     FILE *of;
     char buffer[80];
-    
+
     for(i=0;i<ch;i++){
       sprintf(buffer,"resaux_%d.vqd",look->train_seq);
       of=fopen(buffer,"a");
@@ -455,14 +470,14 @@ static long **_01class(vorbis_block *vb,vorbis_look_residue *vl,
   }
 #endif
   look->frames++;
-  
+
   return(partword);
 }
 
 /* designed for stereo or other modes where the partition size is an
    integer multiple of the number of channels encoded in the current
    submap */
-static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,float **in,
+static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,int **in,
                       int ch){
   long i,j,k,l;
   vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
@@ -475,34 +490,34 @@ static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,float **in,
 
   int partvals=n/samples_per_partition;
   long **partword=_vorbis_block_alloc(vb,sizeof(*partword));
-  
+
 #if defined(TRAIN_RES) || defined (TRAIN_RESAUX)
   FILE *of;
   char buffer[80];
 #endif
-  
-  partword[0]=_vorbis_block_alloc(vb,n*ch/samples_per_partition*sizeof(*partword[0]));
-  memset(partword[0],0,n*ch/samples_per_partition*sizeof(*partword[0]));
-  
+
+  partword[0]=_vorbis_block_alloc(vb,partvals*sizeof(*partword[0]));
+  memset(partword[0],0,partvals*sizeof(*partword[0]));
+
   for(i=0,l=info->begin/ch;i<partvals;i++){
-    float magmax=0.f;
-    float angmax=0.f;
+    int magmax=0;
+    int angmax=0;
     for(j=0;j<samples_per_partition;j+=ch){
-      if(fabs(in[0][l])>magmax)magmax=fabs(in[0][l]);
+      if(abs(in[0][l])>magmax)magmax=abs(in[0][l]);
       for(k=1;k<ch;k++)
-        if(fabs(in[k][l])>angmax)angmax=fabs(in[k][l]);
-        l++;
+        if(abs(in[k][l])>angmax)angmax=abs(in[k][l]);
+      l++;
     }
-    
+
     for(j=0;j<possible_partitions-1;j++)
       if(magmax<=info->classmetric1[j] &&
          angmax<=info->classmetric2[j])
         break;
-    
+
     partword[0][i]=j;
-    
-  }  
-  
+
+  }
+
 #ifdef TRAIN_RESAUX
   sprintf(buffer,"resaux_%d.vqd",look->train_seq);
   of=fopen(buffer,"a");
@@ -511,22 +526,27 @@ static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,float **in,
   fprintf(of,"\n");
   fclose(of);
 #endif
-  
+
   look->frames++;
-  
+
   return(partword);
 }
 
 static int _01forward(oggpack_buffer *opb,
                       vorbis_block *vb,vorbis_look_residue *vl,
-                      float **in,int ch,
+                      int **in,int ch,
                       long **partword,
-                      int (*encode)(oggpack_buffer *,float *,int,
-                                    codebook *,long *)){
+                      int (*encode)(oggpack_buffer *,int *,int,
+                                    codebook *,long *),
+                      int submap){
   long i,j,k,s;
   vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
   vorbis_info_residue0 *info=look->info;
 
+#ifdef TRAIN_RES
+  look->submap=submap;
+#endif
+
   /* move all this setup out later */
   int samples_per_partition=info->grouping;
   int possible_partitions=info->partitions;
@@ -536,27 +556,27 @@ static int _01forward(oggpack_buffer *opb,
   int partvals=n/samples_per_partition;
   long resbits[128];
   long resvals[128];
-  
+
 #ifdef TRAIN_RES
   for(i=0;i<ch;i++)
-    for(j=info->begin;j<end;j++){
+    for(j=info->begin;j<info->end;j++){
       if(in[i][j]>look->tmax)look->tmax=in[i][j];
       if(in[i][j]<look->tmin)look->tmin=in[i][j];
     }
 #endif
-  
+
   memset(resbits,0,sizeof(resbits));
   memset(resvals,0,sizeof(resvals));
-  
+
   /* we code the partition words for each channel, then the residual
      words for a partition per channel until we've written all the
      residual words for that partition word.  Then write the next
      partition channel words... */
-  
+
   for(s=0;s<look->stages;s++){
-    
+
     for(i=0;i<partvals;){
-      
+
       /* first we encode a partition codeword for each channel */
       if(s==0){
         for(j=0;j<ch;j++){
@@ -565,8 +585,8 @@ static int _01forward(oggpack_buffer *opb,
             val*=possible_partitions;
             if(i+k<partvals)
               val+=partword[j][i+k];
-          }        
-          
+          }
+
           /* training hack */
           if(val<look->phrasebook->entries)
             look->phrasebits+=vorbis_book_encode(look->phrasebook,val,opb);
@@ -574,14 +594,14 @@ static int _01forward(oggpack_buffer *opb,
           else
             fprintf(stderr,"!");
 #endif
-          
+
         }
       }
-      
+
       /* now we encode interleaved residual values for the partitions */
       for(k=0;k<partitions_per_word && i<partvals;k++,i++){
         long offset=i*samples_per_partition+info->begin;
-          
+
         for(j=0;j<ch;j++){
           if(s==0)resvals[partword[j][i]]+=samples_per_partition;
           if(info->secondstages[partword[j][i]]&(1<<s)){
@@ -589,12 +609,12 @@ static int _01forward(oggpack_buffer *opb,
             if(statebook){
               int ret;
               long *accumulator=NULL;
-              
+
 #ifdef TRAIN_RES
               accumulator=look->training_data[s][partword[j][i]];
               {
                 int l;
-                float *samples=in[j]+offset;
+                int *samples=in[j]+offset;
                 for(l=0;l<samples_per_partition;l++){
                   if(samples[l]<look->training_min[s][partword[j][i]])
                     look->training_min[s][partword[j][i]]=samples[l];
@@ -603,10 +623,10 @@ static int _01forward(oggpack_buffer *opb,
                 }
               }
 #endif
-              
+
               ret=encode(opb,in[j]+offset,samples_per_partition,
                          statebook,accumulator);
-              
+
               look->postbits+=ret;
               resbits[partword[j][i]]+=ret;
             }
@@ -615,7 +635,7 @@ static int _01forward(oggpack_buffer *opb,
       }
     }
   }
-  
+
   /*{
     long total=0;
     long totalbits=0;
@@ -625,7 +645,7 @@ static int _01forward(oggpack_buffer *opb,
     total+=resvals[k];
     totalbits+=resbits[k];
     }
-    
+
     fprintf(stderr,":: %ld:%1.2g\n",total,(double)totalbits/total);
     }*/
 
@@ -635,7 +655,7 @@ static int _01forward(oggpack_buffer *opb,
 /* a truncated packet here just means 'stop working'; it's not an error */
 static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
                       float **in,int ch,
-                      long (*decodepart)(codebook *, float *, 
+                      long (*decodepart)(codebook *, float *,
                                          oggpack_buffer *,int)){
 
   long i,j,k,l,s;
@@ -648,31 +668,31 @@ static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
   int max=vb->pcmend>>1;
   int end=(info->end<max?info->end:max);
   int n=end-info->begin;
-  
+
   if(n>0){
     int partvals=n/samples_per_partition;
     int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
     int ***partword=alloca(ch*sizeof(*partword));
-    
+
     for(j=0;j<ch;j++)
       partword[j]=_vorbis_block_alloc(vb,partwords*sizeof(*partword[j]));
-    
+
     for(s=0;s<look->stages;s++){
-      
-      /* each loop decodes on partition codeword containing 
+
+      /* each loop decodes on partition codeword containing
          partitions_per_word partitions */
       for(i=0,l=0;i<partvals;l++){
         if(s==0){
           /* fetch the partition word for each channel */
           for(j=0;j<ch;j++){
             int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
-            
-            if(temp==-1)goto eopbreak;
+
+            if(temp==-1 || temp>=info->partvals)goto eopbreak;
             partword[j][l]=look->decodemap[temp];
             if(partword[j][l]==NULL)goto errout;
           }
         }
-        
+
         /* now we decode residual values for the partitions */
         for(k=0;k<partitions_per_word && i<partvals;k++,i++)
           for(j=0;j<ch;j++){
@@ -685,7 +705,7 @@ static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
               }
             }
           }
-      } 
+      }
     }
   }
  errout:
@@ -693,54 +713,6 @@ static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
   return(0);
 }
 
-#if 0
-/* residue 0 and 1 are just slight variants of one another. 0 is
-   interleaved, 1 is not */
-long **res0_class(vorbis_block *vb,vorbis_look_residue *vl,
-                  float **in,int *nonzero,int ch){
-  /* we encode only the nonzero parts of a bundle */
-  int i,used=0;
-  for(i=0;i<ch;i++)
-    if(nonzero[i])
-      in[used++]=in[i];
-  if(used)
-    /*return(_01class(vb,vl,in,used,_interleaved_testhack));*/
-    return(_01class(vb,vl,in,used));
-  else
-    return(0);
-}
-
-int res0_forward(vorbis_block *vb,vorbis_look_residue *vl,
-                 float **in,float **out,int *nonzero,int ch,
-                 long **partword){
-  /* we encode only the nonzero parts of a bundle */
-  int i,j,used=0,n=vb->pcmend/2;
-  for(i=0;i<ch;i++)
-    if(nonzero[i]){
-      if(out)
-        for(j=0;j<n;j++)
-          out[i][j]+=in[i][j];
-      in[used++]=in[i];
-    }
-  if(used){
-    int ret=_01forward(vb,vl,in,used,partword,
-                      _interleaved_encodepart);
-    if(out){
-      used=0;
-      for(i=0;i<ch;i++)
-        if(nonzero[i]){
-          for(j=0;j<n;j++)
-            out[i][j]-=in[used][j];
-          used++;
-        }
-    }
-    return(ret);
-  }else{
-    return(0);
-  }
-}
-#endif
-
 int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
                  float **in,int *nonzero,int ch){
   int i,used=0;
@@ -754,36 +726,21 @@ int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
 }
 
 int res1_forward(oggpack_buffer *opb,vorbis_block *vb,vorbis_look_residue *vl,
-                 float **in,float **out,int *nonzero,int ch,
-                 long **partword){
-  int i,j,used=0,n=vb->pcmend/2;
+                 int **in,int *nonzero,int ch, long **partword, int submap){
+  int i,used=0;
   for(i=0;i<ch;i++)
-    if(nonzero[i]){
-      if(out)
-        for(j=0;j<n;j++)
-          out[i][j]+=in[i][j];
+    if(nonzero[i])
       in[used++]=in[i];
-    }
 
   if(used){
-    int ret=_01forward(opb,vb,vl,in,used,partword,_encodepart);
-    if(out){
-      used=0;
-      for(i=0;i<ch;i++)
-        if(nonzero[i]){
-          for(j=0;j<n;j++)
-            out[i][j]-=in[used][j];
-          used++;
-        }
-    }
-    return(ret);
+    return _01forward(opb,vb,vl,in,used,partword,_encodepart,submap);
   }else{
     return(0);
   }
 }
 
 long **res1_class(vorbis_block *vb,vorbis_look_residue *vl,
-                  float **in,int *nonzero,int ch){
+                  int **in,int *nonzero,int ch){
   int i,used=0;
   for(i=0;i<ch;i++)
     if(nonzero[i])
@@ -807,7 +764,7 @@ int res1_inverse(vorbis_block *vb,vorbis_look_residue *vl,
 }
 
 long **res2_class(vorbis_block *vb,vorbis_look_residue *vl,
-                  float **in,int *nonzero,int ch){
+                  int **in,int *nonzero,int ch){
   int i,used=0;
   for(i=0;i<ch;i++)
     if(nonzero[i])used++;
@@ -822,34 +779,22 @@ long **res2_class(vorbis_block *vb,vorbis_look_residue *vl,
 
 int res2_forward(oggpack_buffer *opb,
                  vorbis_block *vb,vorbis_look_residue *vl,
-                 float **in,float **out,int *nonzero,int ch,
-                 long **partword){
+                 int **in,int *nonzero,int ch, long **partword,int submap){
   long i,j,k,n=vb->pcmend/2,used=0;
 
   /* don't duplicate the code; use a working vector hack for now and
      reshape ourselves into a single channel res1 */
   /* ugly; reallocs for each coupling pass :-( */
-  float *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work));
+  int *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work));
   for(i=0;i<ch;i++){
-    float *pcm=in[i];
+    int *pcm=in[i];
     if(nonzero[i])used++;
     for(j=0,k=i;j<n;j++,k+=ch)
       work[k]=pcm[j];
   }
-  
+
   if(used){
-    int ret=_01forward(opb,vb,vl,&work,1,partword,_encodepart);
-    /* update the sofar vector */
-    if(out){
-      for(i=0;i<ch;i++){
-        float *pcm=in[i];
-        float *sofar=out[i];
-        for(j=0,k=i;j<n;j++,k+=ch)
-          sofar[j]+=pcm[j]-work[k];
-        
-      }
-    }
-    return(ret);
+    return _01forward(opb,vb,vl,&work,1,partword,_encodepart,submap);
   }else{
     return(0);
   }
@@ -873,26 +818,26 @@ int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
     int partvals=n/samples_per_partition;
     int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
     int **partword=_vorbis_block_alloc(vb,partwords*sizeof(*partword));
-    
+
     for(i=0;i<ch;i++)if(nonzero[i])break;
     if(i==ch)return(0); /* no nonzero vectors */
-    
+
     for(s=0;s<look->stages;s++){
       for(i=0,l=0;i<partvals;l++){
-        
+
         if(s==0){
           /* fetch the partition word */
           int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
-          if(temp==-1)goto eopbreak;
+          if(temp==-1 || temp>info->partvals)goto eopbreak;
           partword[l]=look->decodemap[temp];
           if(partword[l]==NULL)goto errout;
         }
-        
+
         /* now we decode residual values for the partitions */
         for(k=0;k<partitions_per_word && i<partvals;k++,i++)
           if(info->secondstages[partword[l][k]]&(1<<s)){
             codebook *stagebook=look->partbooks[partword[l][k]][s];
-            
+
             if(stagebook){
               if(vorbis_book_decodevv_add(stagebook,in,
                                           i*samples_per_partition+info->begin,ch,
@@ -900,7 +845,7 @@ int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
                 goto eopbreak;
             }
           }
-      } 
+      }
     }
   }
  errout:
@@ -941,4 +886,3 @@ const vorbis_func_residue residue2_exportbundle={
   &res2_forward,
   &res2_inverse
 };
-