From aa6fec669ef750837d3e4e3bdb903879b392caba Mon Sep 17 00:00:00 2001
From: "Timothy B. Terriberry" <tterribe@xiph.org>
Date: Tue, 1 Feb 2011 15:36:59 -0800
Subject: [PATCH] Limit mode creation to supported modes.

We did no real error checking to see if a mode is supported when it
 is created.
This patch implements checks for Jean-Marc's rules:
1) A mode must have frames at least 1ms in length (no more than
    1000 per second).
2) A mode must have shorts of at most 3.33 ms (at least 300 per
    second).
It also adds error checking to dump_modes so we report the error
 instead of crashing when we fail to create a mode.
---
 libcelt/dump_modes.c |  7 +++++++
 libcelt/modes.c      | 44 +++++++++++++++++++++++++++++---------------
 2 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/libcelt/dump_modes.c b/libcelt/dump_modes.c
index 340dcfca..ac2e88b6 100644
--- a/libcelt/dump_modes.c
+++ b/libcelt/dump_modes.c
@@ -34,6 +34,7 @@
 #include "config.h"
 #endif
 
+#include <stdlib.h>
 #include <stdio.h>
 #include "modes.h"
 #include "celt.h"
@@ -308,6 +309,12 @@ int main(int argc, char **argv)
       Fs      = atoi(argv[2*i+1]);
       frame   = atoi(argv[2*i+2]);
       m[i] = celt_mode_create(Fs, frame, NULL);
+      if (m[i]==NULL)
+      {
+         fprintf(stderr,"Error creating mode with Fs=%s, frame_size=%s\n",
+               argv[2*i+1],argv[2*i+2]);
+         return EXIT_FAILURE;
+      }
    }
    file = fopen(BASENAME ".c", "w");
    dump_modes(file, m, nb);
diff --git a/libcelt/modes.c b/libcelt/modes.c
index 259a49bc..6414d2fc 100644
--- a/libcelt/modes.c
+++ b/libcelt/modes.c
@@ -331,7 +331,35 @@ CELTMode *celt_mode_create(celt_int32 Fs, int frame_size, int *error)
          *error = CELT_BAD_ARG;
       return NULL;
    }
-   
+   /* Frames of less than 1ms are not supported. */
+   if ((celt_int32)frame_size*1000 < Fs)
+   {
+      if (error)
+         *error = CELT_INVALID_MODE;
+      return NULL;
+   }
+
+   if ((celt_int32)frame_size*75 >= Fs && (frame_size%16)==0)
+   {
+     LM = 3;
+   } else if ((celt_int32)frame_size*150 >= Fs && (frame_size%8)==0)
+   {
+     LM = 2;
+   } else if ((celt_int32)frame_size*300 >= Fs && (frame_size%4)==0)
+   {
+     LM = 1;
+   } else if ((celt_int32)frame_size*300 <= Fs)
+   {
+     LM = 0;
+   }
+   /* Shorts longer than 3.3ms are not supported. */
+   else
+   {
+      if (error)
+         *error = CELT_INVALID_MODE;
+      return NULL;
+   }
+
    mode = celt_alloc(sizeof(CELTMode));
    if (mode==NULL)
       goto failure;
@@ -366,20 +394,6 @@ CELTMode *celt_mode_create(celt_int32 Fs, int frame_size, int *error)
       mode->preemph[3] =  QCONST16(1.f, 13);
    }
 
-   if ((celt_int32)frame_size*75 >= Fs && (frame_size%16)==0)
-   {
-     LM = 3;
-   } else if ((celt_int32)frame_size*150 >= Fs && (frame_size%8)==0)
-   {
-     LM = 2;
-   } else if ((celt_int32)frame_size*300 >= Fs && (frame_size%4)==0)
-   {
-     LM = 1;
-   } else
-   {
-     LM = 0;
-   }
-
    mode->maxLM = LM;
    mode->nbShortMdcts = 1<<LM;
    mode->shortMdctSize = frame_size/mode->nbShortMdcts;
-- 
GitLab