mirror of
https://github.com/claunia/flac.git
synced 2025-12-16 18:54:26 +00:00
add MD5 support
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user