Commit fa37f1c0 authored by Josh Coalson's avatar Josh Coalson
Browse files

add MD5 support

parent 4397b271
......@@ -30,12 +30,16 @@ typedef enum {
FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR,
FLAC__FILE_DECODER_SEEK_ERROR,
FLAC__FILE_DECODER_STREAM_ERROR,
FLAC__FILE_DECODER_MD5_ERROR,
FLAC__FILE_DECODER_UNINITIALIZED
} FLAC__FileDecoderState;
extern const char *FLAC__FileDecoderStateString[];
struct FLAC__FileDecoderPrivate;
typedef struct {
/* this field may not change once FLAC__file_decoder_init() is called */
bool check_md5; /* if true, generate MD5 signature of decoded data and compare against signature in the Encoding metadata block */
FLAC__FileDecoderState state; /* must be FLAC__FILE_DECODER_UNINITIALIZED when passed to FLAC__file_decoder_init() */
struct FLAC__FileDecoderPrivate *guts; /* must be 0 when passed to FLAC__file_decoder_init() */
} FLAC__FileDecoder;
......@@ -50,7 +54,8 @@ FLAC__FileDecoderState FLAC__file_decoder_init(
void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data),
void *client_data
);
void FLAC__file_decoder_finish(FLAC__FileDecoder *decoder);
/* only returns false if check_md5 is set AND the stored MD5 sum is non-zero AND the stored MD5 sum and computed MD5 sum do not match */
bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder);
bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder);
bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder);
bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder);
......
......@@ -66,8 +66,9 @@ typedef enum {
* 3: (number of channels)-1
* 5: (bits per sample)-1
* 36: total samples, 0 => unknown
*128: MD5 digest of the original unencoded audio data
*---- -----------------
* 18 bytes total
* 34 bytes total
*/
typedef struct {
unsigned min_blocksize, max_blocksize;
......@@ -76,6 +77,7 @@ typedef struct {
unsigned channels;
unsigned bits_per_sample;
uint64 total_samples;
byte md5sum[16];
} FLAC__StreamMetaData_Encoding;
extern const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN; /* = 16 bits */
......@@ -86,7 +88,8 @@ extern const unsigned FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN; /* = 20 bi
extern const unsigned FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN; /* = 3 bits */
extern const unsigned FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN; /* = 5 bits */
extern const unsigned FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN; /* = 36 bits */
extern const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH; /* = 18 bytes */
extern const unsigned FLAC__STREAM_METADATA_ENCODING_MD5SUM_LEN; /* = 128 bits */
extern const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH; /* = 34 bytes */
/*****************************************************************************
*
......
......@@ -603,6 +603,10 @@ void metadata_callback(const FLAC__Encoder *encoder, const FLAC__StreamMetaData
* would also break all streams encoded in the previous format.
*/
if(-1 == fseek(f, 26, SEEK_SET)) goto samples_;
fwrite(metadata->data.encoding.md5sum, 1, 16, f);
samples_:
if(-1 == fseek(f, 21, SEEK_SET)) goto framesize_;
if(fread(&b, 1, 1, f) != 1) goto framesize_;
if(-1 == fseek(f, 21, SEEK_SET)) goto framesize_;
......
......@@ -26,6 +26,7 @@
#include "private/encoder_framing.h"
#include "private/fixed.h"
#include "private/lpc.h"
#include "private/md5.h"
#ifdef min
#undef min
......@@ -54,6 +55,7 @@ typedef struct FLAC__EncoderPrivate {
FLAC__StreamMetaData metadata;
unsigned current_sample_number;
unsigned current_frame_number;
struct MD5Context md5context;
FLAC__EncoderWriteStatus (*write_callback)(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
void (*metadata_callback)(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data);
void *client_data;
......@@ -329,6 +331,8 @@ FLAC__EncoderState FLAC__encoder_init(FLAC__Encoder *encoder, FLAC__EncoderWrite
encoder->guts->metadata.data.encoding.channels = encoder->channels;
encoder->guts->metadata.data.encoding.bits_per_sample = encoder->bits_per_sample;
encoder->guts->metadata.data.encoding.total_samples = 0; /* we don't know this yet; have to fill it in later */
memset(encoder->guts->metadata.data.encoding.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */
MD5Init(&encoder->guts->md5context);
if(!FLAC__add_metadata_block(&encoder->guts->metadata, &encoder->guts->frame))
return encoder->state = FLAC__ENCODER_FRAMING_ERROR;
......@@ -354,6 +358,7 @@ void FLAC__encoder_finish(FLAC__Encoder *encoder)
encoder->blocksize = encoder->guts->current_sample_number;
encoder_process_frame_(encoder, true); /* true => is last frame */
}
MD5Final(encoder->guts->metadata.data.encoding.md5sum, &encoder->guts->md5context);
encoder->guts->metadata_callback(encoder, &encoder->guts->metadata, encoder->guts->client_data);
if(encoder->guts != 0) {
for(i = 0; i < encoder->channels; i++) {
......@@ -488,6 +493,14 @@ bool encoder_process_frame_(FLAC__Encoder *encoder, bool is_last_frame)
assert(encoder->state == FLAC__ENCODER_OK);
/*
* Accumulate raw signal to the MD5 signature
*/
if(!FLAC__MD5Accumulate(&encoder->guts->md5context, encoder->guts->integer_signal, encoder->channels, encoder->blocksize, (encoder->bits_per_sample+7) / 8)) {
encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
return false;
}
/*
* First do a normal encoding pass
*/
......
......@@ -32,6 +32,8 @@ static bool subframe_add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const i
bool FLAC__add_metadata_block(const FLAC__StreamMetaData *metadata, FLAC__BitBuffer *bb)
{
unsigned i;
if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
return false;
......@@ -70,6 +72,10 @@ bool FLAC__add_metadata_block(const FLAC__StreamMetaData *metadata, FLAC__BitBuf
return false;
if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.encoding.total_samples, FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN))
return false;
for(i = 0; i < 16; i++) {
if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.md5sum[i], 8))
return false;
}
break;
default:
assert(0);
......
......@@ -23,6 +23,7 @@
#include <string.h> /* for strcmp() */
#include "FLAC/file_decoder.h"
#include "protected/stream_decoder.h"
#include "private/md5.h"
typedef struct FLAC__FileDecoderPrivate {
FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
......@@ -31,6 +32,9 @@ typedef struct FLAC__FileDecoderPrivate {
void *client_data;
FILE *file;
FLAC__StreamDecoder *stream;
struct MD5Context md5context;
byte stored_md5sum[16]; /* this is what is stored in the metadata */
byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
/* the rest of these are only used for seeking: */
FLAC__StreamMetaData_Encoding metadata; /* we keep this around so we can figure out how to seek quickly */
FLAC__FrameHeader last_frame_header; /* holds the info of the last frame we seeked to */
......@@ -105,6 +109,14 @@ FLAC__FileDecoderState FLAC__file_decoder_init(
if(decoder->guts->file == 0)
return decoder->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE;
/* We initialize the MD5Context even though we may never use it. This is
* because check_md5 may be turned on to start and then turned off if a
* seek occurs. So we always init the context here and finalize it in
* FLAC__file_decoder_finish() to make sure things are always cleaned up
*properly.
*/
MD5Init(&decoder->guts->md5context);
decoder->guts->stream = FLAC__stream_decoder_get_new_instance();
if(FLAC__stream_decoder_init(decoder->guts->stream, read_callback_, write_callback_, metadata_callback_, error_callback_, decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; /* this is based on internal knowledge of FLAC__stream_decoder_init() */
......@@ -112,22 +124,33 @@ FLAC__FileDecoderState FLAC__file_decoder_init(
return decoder->state;
}
void FLAC__file_decoder_finish(FLAC__FileDecoder *decoder)
bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder)
{
bool md5_failed = false;
assert(decoder != 0);
if(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED)
return;
return true;
if(decoder->guts != 0) {
if(decoder->guts->file != 0 && decoder->guts->file != stdin)
fclose(decoder->guts->file);
/* see the comment in FLAC__file_decoder_init() as to why we always
* call MD5Final()
*/
MD5Final(decoder->guts->computed_md5sum, &decoder->guts->md5context);
if(decoder->guts->stream != 0) {
FLAC__stream_decoder_finish(decoder->guts->stream);
FLAC__stream_decoder_free_instance(decoder->guts->stream);
}
if(decoder->check_md5) {
if(memcmp(decoder->guts->stored_md5sum, decoder->guts->computed_md5sum, 16))
md5_failed = true;
}
free(decoder->guts);
decoder->guts = 0;
}
decoder->state = FLAC__FILE_DECODER_UNINITIALIZED;
return !md5_failed;
}
bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder)
......@@ -207,6 +230,9 @@ bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, uint64 sample)
decoder->state = FLAC__FILE_DECODER_SEEKING;
/* turn off md5 checking if a seek is attempted */
decoder->check_md5 = false;
if(!FLAC__stream_decoder_reset(decoder->guts->stream)) {
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return false;
......@@ -301,6 +327,10 @@ FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decode
}
}
else {
if(file_decoder->check_md5) {
if(!FLAC__MD5Accumulate(&file_decoder->guts->md5context, buffer, header->channels, header->blocksize, (header->bits_per_sample+7) / 8))
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
return file_decoder->guts->write_callback(file_decoder, header, buffer, file_decoder->guts->client_data);
}
}
......@@ -310,8 +340,13 @@ void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMe
FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
(void)decoder;
if(metadata->type == FLAC__METADATA_TYPE_ENCODING)
if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
file_decoder->guts->metadata = metadata->data.encoding;
/* save the MD5 signature for comparison later */
memcpy(file_decoder->guts->stored_md5sum, metadata->data.encoding.md5sum, 16);
if(0 == memcmp(file_decoder->guts->stored_md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
file_decoder->check_md5 = false;
}
if(file_decoder->state != FLAC__FILE_DECODER_SEEKING)
file_decoder->guts->metadata_callback(file_decoder, metadata, file_decoder->guts->client_data);
}
......
......@@ -36,7 +36,8 @@ const unsigned FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN = 20; /* bits */
const unsigned FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN = 3; /* bits */
const unsigned FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN = 5; /* bits */
const unsigned FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN = 36; /* bits */
const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH = 18; /* bytes */
const unsigned FLAC__STREAM_METADATA_ENCODING_MD5SUM_LEN = 128; /* bits */
const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH = 34; /* bytes */
const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
......
......@@ -481,6 +481,13 @@ bool stream_decoder_read_metadata_(FLAC__StreamDecoder *decoder)
return false; /* the read_callback_ sets the state for us */
used_bits += FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN;
for(i = 0; i < 16; i++) {
if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
return false; /* the read_callback_ sets the state for us */
decoder->guts->stream_header.data.encoding.md5sum[i] = (byte)x;
}
used_bits += 128;
/* skip the rest of the block */
assert(used_bits % 8 == 0);
length -= (used_bits / 8);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment