304 lines
8.6 KiB
C++
304 lines
8.6 KiB
C++
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "wavpack.h"
|
|
|
|
#ifdef __cplusplus
|
|
using namespace std;
|
|
#endif
|
|
|
|
#define BUF_SAMPLES 1024
|
|
|
|
typedef struct {
|
|
unsigned char ungetc_char, ungetc_flag;
|
|
unsigned char *sptr, *dptr, *eptr;
|
|
int64_t total_bytes_read;
|
|
} WavpackRawContext;
|
|
|
|
static int32_t raw_read_bytes (void *id, void *data, int32_t bcount)
|
|
{
|
|
WavpackRawContext *rcxt = (WavpackRawContext *) id;
|
|
unsigned char *outptr = (unsigned char *) data;
|
|
|
|
while (bcount) {
|
|
if (rcxt->ungetc_flag) {
|
|
*outptr++ = rcxt->ungetc_char;
|
|
rcxt->ungetc_flag = 0;
|
|
bcount--;
|
|
}
|
|
else {
|
|
size_t bytes_to_copy = rcxt->eptr - rcxt->dptr;
|
|
|
|
if (!bytes_to_copy)
|
|
break;
|
|
|
|
if (bytes_to_copy > bcount)
|
|
bytes_to_copy = bcount;
|
|
|
|
memcpy (outptr, rcxt->dptr, bytes_to_copy);
|
|
rcxt->total_bytes_read += bytes_to_copy;
|
|
rcxt->dptr += bytes_to_copy;
|
|
outptr += bytes_to_copy;
|
|
bcount -= bytes_to_copy;
|
|
}
|
|
}
|
|
|
|
return (int32_t)(outptr - (unsigned char *) data);
|
|
}
|
|
|
|
static int32_t raw_write_bytes (void *id, void *data, int32_t bcount)
|
|
{
|
|
return data ? bcount : 0;
|
|
}
|
|
|
|
static int64_t raw_get_pos (void *id)
|
|
{
|
|
WavpackRawContext *rcxt = (WavpackRawContext *) id;
|
|
return rcxt->dptr - rcxt->sptr;
|
|
}
|
|
|
|
static int raw_set_pos_abs (void *id, int64_t pos)
|
|
{
|
|
WavpackRawContext *rcxt = (WavpackRawContext *) id;
|
|
|
|
if (rcxt->sptr + pos < rcxt->sptr || rcxt->sptr + pos > rcxt->eptr)
|
|
return 1;
|
|
|
|
rcxt->dptr = rcxt->sptr + pos;
|
|
return 0;
|
|
}
|
|
|
|
static int raw_set_pos_rel (void *id, int64_t delta, int mode)
|
|
{
|
|
WavpackRawContext *rcxt = (WavpackRawContext *) id;
|
|
unsigned char *ref = NULL;
|
|
|
|
if (mode == SEEK_SET)
|
|
ref = rcxt->sptr;
|
|
else if (mode == SEEK_CUR)
|
|
ref = rcxt->dptr;
|
|
else if (mode == SEEK_END)
|
|
ref = rcxt->eptr;
|
|
|
|
if (ref + delta < rcxt->sptr || ref + delta > rcxt->eptr)
|
|
return 1;
|
|
|
|
rcxt->dptr = ref + delta;
|
|
return 0;
|
|
}
|
|
|
|
static int raw_push_back_byte (void *id, int c)
|
|
{
|
|
WavpackRawContext *rcxt = (WavpackRawContext *) id;
|
|
rcxt->ungetc_char = c;
|
|
rcxt->ungetc_flag = 1;
|
|
return c;
|
|
}
|
|
|
|
static int64_t raw_get_length (void *id)
|
|
{
|
|
WavpackRawContext *rcxt = (WavpackRawContext *) id;
|
|
return rcxt->eptr - rcxt->sptr;
|
|
}
|
|
|
|
static int raw_can_seek (void *id)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static int raw_close_stream (void *id)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static WavpackStreamReader64 raw_reader = {
|
|
raw_read_bytes, raw_write_bytes, raw_get_pos, raw_set_pos_abs, raw_set_pos_rel,
|
|
raw_push_back_byte, raw_get_length, raw_can_seek, NULL, raw_close_stream
|
|
};
|
|
|
|
static long long debug_log_mask = -1;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|
#else
|
|
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|
#endif
|
|
{
|
|
static long long times_called, opens, seeks, tag_writes, samples_decoded, text_tags, binary_tags;
|
|
int flags = OPEN_TAGS | OPEN_EDIT_TAGS | OPEN_WRAPPER | OPEN_DSD_AS_PCM | OPEN_NO_CHECKSUM | OPEN_NORMALIZE;
|
|
WavpackRawContext raw_wv;
|
|
WavpackContext *wpc;
|
|
char error [80];
|
|
int num_chans, bps, mode, qmode;
|
|
int64_t total_samples;
|
|
int retval = 0;
|
|
|
|
times_called++;
|
|
|
|
WavpackGetLibraryVersionString ();
|
|
WavpackGetLibraryVersion ();
|
|
|
|
memset (&raw_wv, 0, sizeof (WavpackRawContext));
|
|
raw_wv.dptr = raw_wv.sptr = (unsigned char *) data;
|
|
raw_wv.eptr = raw_wv.dptr + size;
|
|
wpc = WavpackOpenFileInputEx64 (&raw_reader, &raw_wv, NULL, error, flags, 15);
|
|
|
|
if (!wpc) {
|
|
retval = 1;
|
|
goto exit;
|
|
}
|
|
|
|
opens++;
|
|
num_chans = WavpackGetNumChannels (wpc);
|
|
total_samples = WavpackGetNumSamples64 (wpc);
|
|
bps = WavpackGetBytesPerSample (wpc);
|
|
qmode = WavpackGetQualifyMode (wpc);
|
|
mode = WavpackGetMode (wpc);
|
|
|
|
// call some other APIs for coverage
|
|
WavpackGetErrorMessage (wpc);
|
|
WavpackGetSampleIndex64 (wpc);
|
|
WavpackGetSampleIndex (wpc);
|
|
WavpackGetNumSamples (wpc);
|
|
WavpackGetNumErrors (wpc);
|
|
WavpackLossyBlocks (wpc);
|
|
WavpackGetProgress (wpc);
|
|
WavpackGetRatio (wpc);
|
|
WavpackGetAverageBitrate (wpc, 1);
|
|
WavpackGetInstantBitrate (wpc);
|
|
WavpackGetNativeSampleRate (wpc);
|
|
WavpackGetSampleRate (wpc);
|
|
WavpackGetChannelMask (wpc);
|
|
WavpackGetFloatNormExp (wpc);
|
|
WavpackGetBitsPerSample (wpc);
|
|
WavpackGetBytesPerSample (wpc);
|
|
WavpackGetReducedChannels (wpc);
|
|
WavpackGetVersion (wpc);
|
|
WavpackGetFileFormat (wpc);
|
|
WavpackGetFileExtension (wpc);
|
|
|
|
if (WavpackGetWrapperBytes (wpc))
|
|
WavpackGetWrapperData (wpc);
|
|
|
|
if (num_chans) {
|
|
unsigned char identities [num_chans + 1];
|
|
WavpackGetChannelIdentities (wpc, identities);
|
|
|
|
if (WavpackGetChannelLayout (wpc, NULL) & 0xff) {
|
|
unsigned char reordering [WavpackGetChannelLayout (wpc, NULL) & 0xff];
|
|
WavpackGetChannelLayout (wpc, reordering);
|
|
}
|
|
}
|
|
|
|
// Get all the metadata tags (text & binary)
|
|
if (mode & MODE_VALID_TAG) {
|
|
int num_binary_items = WavpackGetNumBinaryTagItems (wpc);
|
|
int num_items = WavpackGetNumTagItems (wpc), i;
|
|
|
|
for (i = 0; i < num_items; ++i) {
|
|
int item_len, value_len, j;
|
|
char *item, *value;
|
|
|
|
item_len = WavpackGetTagItemIndexed (wpc, i, NULL, 0);
|
|
item = (char *) malloc (item_len + 1);
|
|
WavpackGetTagItemIndexed (wpc, i, item, item_len + 1);
|
|
value_len = WavpackGetTagItem (wpc, item, NULL, 0);
|
|
value = (char *) malloc (value_len + 1);
|
|
WavpackGetTagItem (wpc, item, value, value_len + 1);
|
|
text_tags++;
|
|
free (value);
|
|
free (item);
|
|
}
|
|
|
|
for (i = 0; i < num_binary_items; ++i) {
|
|
int item_len, value_len;
|
|
char *item, *value;
|
|
|
|
item_len = WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0);
|
|
item = (char *) malloc (item_len + 1);
|
|
WavpackGetBinaryTagItemIndexed (wpc, i, item, item_len + 1);
|
|
value_len = WavpackGetBinaryTagItem (wpc, item, NULL, 0);
|
|
value = (char *) malloc (value_len);
|
|
WavpackGetBinaryTagItem (wpc, item, value, value_len);
|
|
binary_tags++;
|
|
free (value);
|
|
free (item);
|
|
}
|
|
|
|
WavpackAppendTagItem (wpc, "Artist", "The Googlers", strlen ("The Googlers"));
|
|
WavpackAppendTagItem (wpc, "Title", "Fuzz Me All Night Long", strlen ("Fuzz Me All Night Long"));
|
|
WavpackAppendTagItem (wpc, "Album", "Meet The Googlers", strlen ("Meet The Googlers"));
|
|
WavpackAppendBinaryTagItem (wpc, "Cover Art (Front)", (const char *) data, size < 4096 ? size : 4096);
|
|
}
|
|
|
|
// Decode all
|
|
if (num_chans && num_chans <= 256) {
|
|
int32_t decoded_samples [BUF_SAMPLES * num_chans];
|
|
unsigned char md5sum [16];
|
|
int unpack_result;
|
|
|
|
do {
|
|
unpack_result = WavpackUnpackSamples (wpc, decoded_samples, BUF_SAMPLES);
|
|
samples_decoded += unpack_result;
|
|
} while (unpack_result);
|
|
|
|
WavpackGetMD5Sum (wpc, md5sum);
|
|
}
|
|
|
|
// Seek to 1/3 of the way in plus 1000 samples (definitely not a block boundary)
|
|
if (WavpackSeekSample64 (wpc, total_samples / 3 + 1000)) {
|
|
++seeks;
|
|
|
|
// if we're still okay, try to write out the modified tags
|
|
if (WavpackWriteTag (wpc))
|
|
++tag_writes;
|
|
}
|
|
|
|
WavpackCloseFile (wpc);
|
|
|
|
exit:
|
|
if (!(times_called & debug_log_mask))
|
|
printf ("LLVMFuzzerTestOneInput(): %lld calls, %lld opens, %lld seeks, %lld tag writes, %lld samples, %lld text & %lld binary tags\n",
|
|
times_called, opens, seeks, tag_writes, samples_decoded, text_tags, binary_tags);
|
|
|
|
return retval;
|
|
}
|
|
|
|
#ifdef STAND_ALONE_LENGTH // max file length for stand-alone testing (sans fuzz)
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
unsigned char *buffer = (unsigned char *) malloc (STAND_ALONE_LENGTH);
|
|
int index;
|
|
|
|
// debug_log_mask = 0;
|
|
|
|
for (index = 1; index < argc; ++index) {
|
|
const char *filename = argv [index];
|
|
FILE *infile = fopen (filename, "rb");
|
|
int bytes_read;
|
|
|
|
if (!infile) {
|
|
fprintf (stderr, "can't open file %s!\n", filename);
|
|
continue;
|
|
}
|
|
|
|
bytes_read = fread (buffer, 1, STAND_ALONE_LENGTH, infile);
|
|
printf ("read %d bytes from file %s\n", bytes_read, filename);
|
|
|
|
if (bytes_read == STAND_ALONE_LENGTH)
|
|
printf ("warning: at maximum length, perhaps truncated!\n");
|
|
|
|
fclose (infile);
|
|
LLVMFuzzerTestOneInput(buffer, bytes_read);
|
|
}
|
|
|
|
free (buffer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|