• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright (C) 2020 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19  */
20 
21 #include <stdlib.h>
22 #include <utils/String8.h>
23 #include "FLAC/stream_decoder.h"
24 
25 // First four bytes are always "fLaC" in ASCII format.
26 #define FIRST_ENCODED_BYTE_OFFSET 4
27 
28 class Codec {
29  public:
30   Codec() = default;
~Codec()31   ~Codec() { deInitDecoder(); }
32   bool initDecoder();
33   void decodeFrames(const uint8_t *data, size_t size);
34   void deInitDecoder();
35 
36  private:
37   FLAC__StreamDecoder *mDecoder = nullptr;
38   const uint8_t *mBuffer = nullptr;
39   size_t mBufferLen = 0;
40   size_t mBufferPos = 0;
41   FLAC__StreamDecoderReadStatus readCallback(FLAC__byte buffer[], size_t *bytes);
42   FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__Frame *frame,
43                                                const FLAC__int32 *const buffer[]);
44   void errorCallback(FLAC__StreamDecoderErrorStatus status);
45   void metadataCallback(const FLAC__StreamMetadata *metadata);
46 };
47 
initDecoder()48 bool Codec::initDecoder() {
49   mDecoder = FLAC__stream_decoder_new();
50   if (!mDecoder) {
51     return false;
52   }
53   FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
54   FLAC__stream_decoder_set_md5_checking(mDecoder, true);
55   // read_callback, write_callback, error_callback and metadata_callback cannot be nullptrs
56 
57   static auto read_callback = [](const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes,
58                                  void *client_data) -> FLAC__StreamDecoderReadStatus {
59     Codec *client = reinterpret_cast<Codec *>(client_data);
60     return client->readCallback(buffer, bytes);
61   };
62   static auto write_callback = [](const FLAC__StreamDecoder *, const FLAC__Frame *frame,
63                                   const FLAC__int32 *const buffer[],
64                                   void *client_data) -> FLAC__StreamDecoderWriteStatus {
65     Codec *client = reinterpret_cast<Codec *>(client_data);
66     return client->writeCallback(frame, buffer);
67   };
68   static auto error_callback = [](const FLAC__StreamDecoder *,
69                                   FLAC__StreamDecoderErrorStatus status, void *client_data) {
70     Codec *client = reinterpret_cast<Codec *>(client_data);
71     client->errorCallback(status);
72   };
73   FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_STREAMINFO);
74   static auto metadata_callback = [](const FLAC__StreamDecoder *,
75                                      const FLAC__StreamMetadata *metadata, void *client_data) {
76     Codec *client = reinterpret_cast<Codec *>(client_data);
77     client->metadataCallback(metadata);
78   };
79   void *client_data = reinterpret_cast<void *>(this);
80   FLAC__StreamDecoderInitStatus initStatus = FLAC__stream_decoder_init_stream(
81       mDecoder, read_callback, nullptr, nullptr, nullptr, nullptr, write_callback,
82       metadata_callback, error_callback, client_data);
83   if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
84     return false;
85   }
86   return true;
87 }
88 
readCallback(FLAC__byte buffer[],size_t * bytes)89 FLAC__StreamDecoderReadStatus Codec::readCallback(FLAC__byte buffer[], size_t *bytes) {
90   if (!mBuffer || mBufferLen == 0) {
91     *bytes = 0;
92     return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
93   }
94   size_t bytesRequested = *bytes;
95   if (bytesRequested > mBufferLen - mBufferPos) {
96     bytesRequested = mBufferLen - mBufferPos;
97   }
98   memcpy(buffer, mBuffer + mBufferPos, bytesRequested);
99   mBufferPos += bytesRequested;
100   *bytes = bytesRequested;
101   return (bytesRequested == 0 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
102                               : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE);
103 }
104 
writeCallback(const FLAC__Frame * frame,const FLAC__int32 * const buffer[])105 FLAC__StreamDecoderWriteStatus Codec::writeCallback(const FLAC__Frame *frame,
106                                                     const FLAC__int32 *const buffer[]) {
107   (void)frame;
108   (void)buffer;
109   return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
110 }
111 
errorCallback(FLAC__StreamDecoderErrorStatus status)112 void Codec::errorCallback(FLAC__StreamDecoderErrorStatus status) {
113   (void)status;
114   return;
115 }
116 
metadataCallback(const FLAC__StreamMetadata * metadata)117 void Codec::metadataCallback(const FLAC__StreamMetadata *metadata) {
118   (void)metadata;
119   return;
120 }
121 
decodeFrames(const uint8_t * data,size_t size)122 void Codec::decodeFrames(const uint8_t *data, size_t size) {
123   mBuffer = data;
124   mBufferLen = size;
125   size_t ofst = std::min((size_t)FIRST_ENCODED_BYTE_OFFSET, size - 1);
126   bool decodeEntireStream = data[ofst] & 0x01;
127   if (!decodeEntireStream) {
128     if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
129       return;
130     }
131     while (mBufferPos <= size) {
132       FLAC__stream_decoder_process_single(mDecoder);
133       if (FLAC__STREAM_DECODER_END_OF_STREAM == FLAC__stream_decoder_get_state(mDecoder)) {
134         return;
135       }
136     }
137   } else {
138     FLAC__stream_decoder_process_until_end_of_stream(mDecoder);
139   }
140   FLAC__stream_decoder_finish(mDecoder);
141 }
142 
deInitDecoder()143 void Codec::deInitDecoder() {
144   if (mDecoder != nullptr) {
145     FLAC__stream_decoder_delete(mDecoder);
146   }
147 }
148 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)149 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
150   if (size == 0) {
151     return 0;
152   }
153   Codec *codec = new Codec();
154   if (!codec) {
155     return 0;
156   }
157   if (codec->initDecoder()) {
158     codec->decodeFrames(data, size);
159   }
160   delete codec;
161   return 0;
162 }
163