CVE-2017-14160: fix bounds check on very low sample rates.
[platform/upstream/libvorbis.git] / lib / res0.c
index 48caa27..6d623d7 100644 (file)
@@ -5,13 +5,12 @@
  * 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/                  *
  *                                                                  *
  ********************************************************************
 
  function: residue backend 0, 1 and 2 implementation
- last mod: $Id$
 
  ********************************************************************/
 
 #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 +60,7 @@ typedef struct {
   float      training_min[8][64];
   float     tmin;
   float     tmax;
+  int       submap;
 #endif
 
 } vorbis_look_residue0;
@@ -86,16 +89,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 +124,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);
@@ -148,15 +151,6 @@ void res0_free_look(vorbis_look_residue *i){
   }
 }
 
-static int ilog(unsigned int v){
-  int ret=0;
-  while(v){
-    ret++;
-    v>>=1;
-  }
-  return(ret);
-}
-
 static int icount(unsigned int v){
   int ret=0;
   while(v){
@@ -173,7 +167,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 */
@@ -182,11 +176,11 @@ void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){
      bitmask of one indicates this partition class has bits to write
      this pass */
   for(j=0;j<info->partitions;j++){
-    if(ilog(info->secondstages[j])>3){
+    if(ov_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]);
@@ -208,16 +202,27 @@ vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
   info->partitions=oggpack_read(opb,6)+1;
   info->groupbook=oggpack_read(opb,8);
 
+  /* check for premature EOP */
+  if(info->groupbook<0)goto errout;
+
   for(j=0;j<info->partitions;j++){
     int cascade=oggpack_read(opb,3);
-    if(oggpack_read(opb,1))
-      cascade|=(oggpack_read(opb,5)<<3);
+    int cflag=oggpack_read(opb,1);
+    if(cflag<0) goto errout;
+    if(cflag){
+      int c=oggpack_read(opb,5);
+      if(c<0) goto errout;
+      cascade|=(c<<3);
+    }
     info->secondstages[j]=cascade;
 
     acc+=icount(cascade);
   }
-  for(j=0;j<acc;j++)
-    info->booklist[j]=oggpack_read(opb,8);
+  for(j=0;j<acc;j++){
+    int book=oggpack_read(opb,8);
+    if(book<0) goto errout;
+    info->booklist[j]=book;
+  }
 
   if(info->groupbook>=ci->books)goto errout;
   for(j=0;j<acc;j++){
@@ -227,15 +232,21 @@ 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;
     int partvals = 1;
+    if (dim<1) goto errout;
     while(dim>0){
       partvals *= info->partitions;
       if(partvals > entries) goto errout;
       dim--;
     }
+    info->partvals = partvals;
   }
 
   return(info);
@@ -263,7 +274,7 @@ vorbis_look_residue *res0_look(vorbis_dsp_state *vd,
   look->partbooks=_ogg_calloc(look->parts,sizeof(*look->partbooks));
 
   for(j=0;j<look->parts;j++){
-    int stages=ilog(info->secondstages[j]);
+    int stages=ov_ilog(info->secondstages[j]);
     if(stages){
       if(stages>maxstage)maxstage=stages;
       look->partbooks[j]=_ogg_calloc(stages,sizeof(*look->partbooks[j]));
@@ -305,66 +316,77 @@ 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,
+#ifdef TRAIN_RES
+static int _encodepart(oggpack_buffer *opb,int *vec, int n,
                        codebook *book,long *acc){
+#else
+static int _encodepart(oggpack_buffer *opb,int *vec, int n,
+                       codebook *book){
+#endif
   int i,bits=0;
   int dim=book->dim;
   int step=n/dim;
@@ -373,19 +395,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;
@@ -394,45 +416,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");
@@ -444,14 +466,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;
@@ -464,34 +486,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");
@@ -500,22 +522,33 @@ 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,
+                      vorbis_look_residue *vl,
+                      int **in,int ch,
                       long **partword,
-                      int (*encode)(oggpack_buffer *,float *,int,
-                                    codebook *,long *)){
+#ifdef TRAIN_RES
+                      int (*encode)(oggpack_buffer *,int *,int,
+                                    codebook *,long *),
+                      int submap
+#else
+                      int (*encode)(oggpack_buffer *,int *,int,
+                                    codebook *)
+#endif
+){
   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;
@@ -525,27 +558,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++){
@@ -554,8 +587,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);
@@ -563,27 +596,26 @@ 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)){
             codebook *statebook=look->partbooks[partword[j][i]][s];
             if(statebook){
               int ret;
-              long *accumulator=NULL;
-              
 #ifdef TRAIN_RES
+              long *accumulator=NULL;
               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];
@@ -591,11 +623,13 @@ static int _01forward(oggpack_buffer *opb,
                     look->training_max[s][partword[j][i]]=samples[l];
                 }
               }
-#endif
-              
               ret=encode(opb,in[j]+offset,samples_per_partition,
                          statebook,accumulator);
-              
+#else
+              ret=encode(opb,in[j]+offset,samples_per_partition,
+                         statebook);
+#endif
+
               look->postbits+=ret;
               resbits[partword[j][i]]+=ret;
             }
@@ -604,19 +638,6 @@ static int _01forward(oggpack_buffer *opb,
       }
     }
   }
-  
-  /*{
-    long total=0;
-    long totalbits=0;
-    fprintf(stderr,"%d :: ",vb->mode);
-    for(k=0;k<possible_partitions;k++){
-    fprintf(stderr,"%ld/%1.2g, ",resvals[k],(float)resbits[k]/resvals[k]);
-    total+=resvals[k];
-    totalbits+=resbits[k];
-    }
-    
-    fprintf(stderr,":: %ld:%1.2g\n",total,(double)totalbits/total);
-    }*/
 
   return(0);
 }
@@ -624,7 +645,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;
@@ -637,31 +658,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++){
@@ -674,7 +695,7 @@ static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
               }
             }
           }
-      } 
+      }
     }
   }
  errout:
@@ -682,54 +703,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;
@@ -743,36 +716,27 @@ 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;
+  (void)vb;
   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);
+#ifdef TRAIN_RES
+    return _01forward(opb,vl,in,used,partword,_encodepart,submap);
+#else
+    (void)submap;
+    return _01forward(opb,vl,in,used,partword,_encodepart);
+#endif
   }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])
@@ -796,7 +760,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++;
@@ -811,34 +775,27 @@ 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);
+#ifdef TRAIN_RES
+    return _01forward(opb,vl,&work,1,partword,_encodepart,submap);
+#else
+    (void)submap;
+    return _01forward(opb,vl,&work,1,partword,_encodepart);
+#endif
   }else{
     return(0);
   }
@@ -862,26 +819,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,
@@ -889,7 +846,7 @@ int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
                 goto eopbreak;
             }
           }
-      } 
+      }
     }
   }
  errout:
@@ -930,4 +887,3 @@ const vorbis_func_residue residue2_exportbundle={
   &res2_forward,
   &res2_inverse
 };
-