text: /******************************************************************************
   *
   * Copyright (C) 2020 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at:
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   *****************************************************************************
   * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
   */
  #include <string.h>
  #include <algorithm>
  #include "gsmamr_dec.h"
  
  // Constants for AMR-NB
  constexpr int32_t kSamplesPerFrame = L_FRAME;
  constexpr int32_t kBitsPerSample = 16;
  constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
  const bitstream_format kBitStreamFormats[2] = {MIME_IETF, IF2};
  const int32_t kLocalWmfDecBytesPerFrame[8] = {12, 13, 15, 17, 19, 20, 26, 31};
  const int32_t kLocalIf2DecBytesPerFrame[8] = {13, 14, 16, 18, 19, 21, 26, 31};
  
  class Codec {
   public:
    Codec() = default;
    ~Codec() { deInitDecoder(); }
    int16_t initDecoder();
    void deInitDecoder();
    void decodeFrames(const uint8_t *data, size_t size);
  
   private:
    void *mAmrHandle = nullptr;
  };
  
  int16_t Codec::initDecoder() { return GSMInitDecode(&mAmrHandle, (Word8 *)"AMRNBDecoder"); }
  
  void Codec::deInitDecoder() { GSMDecodeFrameExit(&mAmrHandle); }
  
  void Codec::decodeFrames(const uint8_t *data, size_t size) {
    while (size > 0) {
      uint8_t mode = *data;
      bool bit = mode & 0x01;
      bitstream_format bitsreamFormat = kBitStreamFormats[bit];
      int32_t frameSize = 0;
      /* Find frame type */
      Frame_Type_3GPP frameType = static_cast<Frame_Type_3GPP>((mode >> 3) & 0x07);
      ++data;
      --size;
      if (bit) {
        frameSize = kLocalIf2DecBytesPerFrame[frameType];
      } else {
        frameSize = kLocalWmfDecBytesPerFrame[frameType];
      }
      int16_t outputBuf[kOutputBufferSize];
      uint8_t *inputBuf = new uint8_t[frameSize];
      if (!inputBuf) {
        return;
      }
      int32_t minSize = std::min((int32_t)size, frameSize);
      memcpy(inputBuf, data, minSize);
      AMRDecode(mAmrHandle, frameType, inputBuf, outputBuf, bitsreamFormat);
      /* AMRDecode() decodes minSize number of bytes if decode is successful.
       * AMRDecode() returns -1 if decode fails.
       * Even if no bytes are decoded, increment by minSize to ensure fuzzer proceeds
       * to feed next data */
      data += minSize;
      size -= minSize;
      delete[] inputBuf;
    }
  }
  
  extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size < 2) {
      return 0;
    }
    Codec *codec = new Codec();
    if (!codec) {
      return 0;
    }
    if (codec->initDecoder() == 0) {
      codec->decodeFrames(data, size);
    }
    delete codec;
    return 0;
  }
  