blob: fe5c6d3658edf10bdaf2a576350e6ec259ffc5fe [file] [log] [blame]
/*****************************************************************************/
// Copyright 2006-2007 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_fingerprint.h#2 $ */
/* $DateTime: 2012/07/11 10:36:56 $ */
/* $Change: 838485 $ */
/* $Author: tknoll $ */
/** \file
* Fingerprint (cryptographic hashing) support for generating strong hashes of image
* data.
*/
/*****************************************************************************/
#ifndef __dng_fingerprint__
#define __dng_fingerprint__
/*****************************************************************************/
#include "dng_exceptions.h"
#include "dng_types.h"
#include "dng_stream.h"
#include <cstring>
/*****************************************************************************/
/// \brief Container fingerprint (MD5 only at present).
class dng_fingerprint
{
public:
static const size_t kDNGFingerprintSize = 16;
uint8 data [kDNGFingerprintSize];
public:
dng_fingerprint ();
/// Check if fingerprint is all zeros.
bool IsNull () const;
/// Same as IsNull but expresses intention of testing validity.
bool IsValid () const
{
return !IsNull ();
}
/// Set to all zeros, a value used to indicate an invalid fingerprint.
void Clear ()
{
*this = dng_fingerprint ();
}
/// Test if two fingerprints are equal.
bool operator== (const dng_fingerprint &print) const;
/// Test if two fingerprints are not equal.
bool operator!= (const dng_fingerprint &print) const
{
return !(*this == print);
}
/// Produce a 32-bit hash value from fingerprint used for faster hashing of
/// fingerprints.
uint32 Collapse32 () const;
/// Convert fingerprint to UTF-8 string.
///
/// \param resultStr The output array to which the UTF-8 encoding of the
/// fingerprint will be written.
void ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const;
/// Convert UTF-8 string to fingerprint. Returns true on success, false on
/// failure.
///
/// \param inputStr The input array from which the UTF-8 encoding of the
/// fingerprint will be read.
///
/// \retval True indicates success.
bool FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1]);
};
/*****************************************************************************/
/// \brief Utility to compare fingerprints (e.g., for sorting).
struct dng_fingerprint_less_than
{
/// Less-than comparison.
bool operator() (const dng_fingerprint &a,
const dng_fingerprint &b) const
{
return memcmp (a.data,
b.data,
sizeof (a.data)) < 0;
}
};
/******************************************************************************/
// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
// rights reserved.
//
// License to copy and use this software is granted provided that it
// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
// Algorithm" in all material mentioning or referencing this software
// or this function.
//
// License is also granted to make and use derivative works provided
// that such works are identified as "derived from the RSA Data
// Security, Inc. MD5 Message-Digest Algorithm" in all material
// mentioning or referencing the derived work.
//
// RSA Data Security, Inc. makes no representations concerning either
// the merchantability of this software or the suitability of this
// software for any particular purpose. It is provided "as is"
// without express or implied warranty of any kind.
//
// These notices must be retained in any copies of any part of this
// documentation and/or software.
/// \brief Class to hash binary data to a fingerprint using the MD5 Message-Digest
/// Algorithm.
class dng_md5_printer
{
public:
dng_md5_printer ();
virtual ~dng_md5_printer ()
{
}
/// Reset the fingerprint.
void Reset ();
/// Append the data to the stream to be hashed.
/// \param data The data to be hashed.
/// \param inputLen The length of data, in bytes.
void Process (const void *data,
uint32 inputLen);
/// Append the string to the stream to be hashed.
/// \param text The string to be hashed.
void Process (const char *text)
{
Process (text, (uint32) strlen (text));
}
/// Get the fingerprint (i.e., result of the hash).
const dng_fingerprint & Result ();
private:
static void Encode (uint8 *output,
const uint32 *input,
uint32 len);
static void Decode (uint32 *output,
const uint8 *input,
uint32 len);
// F, G, H and I are basic MD5 functions.
static inline uint32 F (uint32 x,
uint32 y,
uint32 z)
{
return (x & y) | (~x & z);
}
static inline uint32 G (uint32 x,
uint32 y,
uint32 z)
{
return (x & z) | (y & ~z);
}
static inline uint32 H (uint32 x,
uint32 y,
uint32 z)
{
return x ^ y ^ z;
}
static inline uint32 I (uint32 x,
uint32 y,
uint32 z)
{
return y ^ (x | ~z);
}
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
static inline void FF (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += F (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
static inline void GG (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += G (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
static inline void HH (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += H (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
static inline void II (uint32 &a,
uint32 b,
uint32 c,
uint32 d,
uint32 x,
uint32 s,
uint32 ac)
{
a += I (b, c, d) + x + ac;
a = (a << s) | (a >> (32 - s));
a += b;
}
static void MD5Transform (uint32 state [4],
const uint8 block [64]);
private:
uint32 state [4];
uint32 count [2];
uint8 buffer [64];
bool final;
dng_fingerprint result;
};
/*****************************************************************************/
/// \brief A dng_stream based interface to the MD5 printing logic.
class dng_md5_printer_stream : public dng_stream, dng_md5_printer
{
private:
uint64 fNextOffset;
public:
/// Create an empty MD5 printer stream.
dng_md5_printer_stream ()
: fNextOffset (0)
{
}
virtual uint64 DoGetLength ()
{
return fNextOffset;
}
virtual void DoRead (void * /* data */,
uint32 /* count */,
uint64 /* offset */)
{
ThrowProgramError ();
}
virtual void DoSetLength (uint64 length)
{
if (length != fNextOffset)
{
ThrowProgramError ();
}
}
virtual void DoWrite (const void *data,
uint32 count2,
uint64 offset)
{
if (offset != fNextOffset)
{
ThrowProgramError ();
}
Process (data, count2);
fNextOffset += count2;
}
const dng_fingerprint & Result ()
{
Flush ();
return dng_md5_printer::Result ();
}
};
/*****************************************************************************/
#endif
/*****************************************************************************/