DECLARE_TEST( md5, reference ) { md5_t* md5; char* md5str; md5 = md5_allocate(); md5_digest_finalize( md5 ); md5_digest_raw( md5, "testing md5 implementation", 26 ); md5_digest_finalize( md5 ); md5str = md5_get_digest( md5 ); EXPECT_STREQ( md5str, "4E24E37E5E06F23210FA1518E97A50C4" ); string_deallocate( md5str ); md5_digest_raw( md5, "testing md5 implementation", 26 ); md5_digest_raw( md5, "", 0 ); md5_digest_raw( md5, "further testing md5 implementation with long buffer > 32 bytes", 62 ); md5_digest_finalize( md5 ); md5str = md5_get_digest( md5 ); EXPECT_STREQ( md5str, "BD870884942EA7B32A9CB2547B02B871" ); string_deallocate( md5str ); md5_digest_raw( md5, digest_test_string, 2000 ); md5_digest_finalize( md5 ); md5str = md5_get_digest( md5 ); EXPECT_STREQ( md5str, "137D3C94230A0E230C4DDFC97EACCCD2" ); string_deallocate( md5str ); md5_deallocate( md5 ); return 0; }
uint128_t stream_md5( stream_t* stream ) { int64_t cur, ic, offset, lastc, num; md5_t* md5; uint128_t ret = {0}; unsigned char buf[1025]; bool ignore_lf = false; FOUNDATION_ASSERT( stream ); if( stream->vtable->md5 ) return stream->vtable->md5( stream ); if( !stream || stream_is_sequential( stream ) || !( stream->mode & STREAM_IN ) ) return ret; FOUNDATION_ASSERT( stream->vtable->read ); cur = stream_tell( stream ); stream_seek( stream, 0, STREAM_SEEK_BEGIN ); md5 = md5_allocate(); while( !stream_eos( stream ) ) { num = (int64_t)stream->vtable->read( stream, buf, 1024 ); if( !num ) continue; if( stream->mode & STREAM_BINARY ) md5_digest_raw( md5, buf, (size_t)num ); else { //If last buffer ended with CR, ignore a leading LF offset = 0; lastc = 0; if( ignore_lf && ( buf[0] == '\n' ) ) offset = 1; ignore_lf = false; //Treat all line endings (LF, CR, CR+LF) as Unix style LF. If file has mixed line endings (for example, one line ending in a single CR and next ending in a single LF), it will not work! for( ic = 0; ic < num; ++ic ) { bool was_cr = ( buf[ic] == '\r' ); bool was_lf = ( buf[ic] == '\n' ); if( was_cr || was_lf ) { if( was_cr && ( ic >= 1023 ) ) ignore_lf = true; buf[ic] = '\n'; md5_digest_raw( md5, buf + lastc, (size_t)( ic - lastc + 1 ) ); //Include the LF if( was_cr && ( buf[ic+1] == '\n' ) ) //Check for CR+LF ++ic; lastc = ic + 1; } } if( lastc < num ) md5_digest_raw( md5, buf + lastc, (size_t)( num - lastc ) ); } } stream_seek( stream, cur, STREAM_SEEK_BEGIN ); md5_finalize( md5 ); ret = md5_get_digest_raw( md5 ); md5_deallocate( md5 ); return ret; }