#ifndef MD5_H
#define MD5_H

struct MD5Context
{
  uint32 buf[4];
  uint32 bits[2];
  unsigned char in[64];

  MD5Context() { memset(this, 0, sizeof(*this)); }
};

idaman THREAD_SAFE void ida_export MD5Init(MD5Context *context);
idaman THREAD_SAFE void ida_export MD5Update(MD5Context *context, const void *buf, size_t len);
idaman THREAD_SAFE void ida_export MD5Final(uchar digest[16], MD5Context *context);
idaman THREAD_SAFE void ida_export MD5Transform(uint32 buf[4], uint32 const in[16]);

//---------------------------------------------------------------------------
struct md5_t
{
  uchar hash[16];

  md5_t()               { clear(); }
  md5_t(const md5_t &r) { assign(r); }

  const uchar &operator[](size_t i) const { return hash[i]; }
  uchar &operator[](size_t i)             { return hash[i]; }

  void clear() { memset(hash, 0, sizeof(hash)); }
  void swap(md5_t &other) { std::swap(*this, other); }

  md5_t &operator=(const md5_t &r)
  {
    if ( this != &r )
      assign(r);
    return *this;
  }

  DECLARE_COMPARISONS(md5_t)
  {
    return memcmp(hash, r.hash, sizeof(hash));
  }
  bool empty() const
  {
    for ( size_t i=0; i < sizeof(hash); i++ )
      if ( hash[i] != 0 )
        return false;
    return true;
  }


protected:
  void assign(const md5_t &r) { memmove(hash, r.hash, sizeof(hash)); }
};
DECLARE_TYPE_AS_MOVABLE(md5_t);
typedef qvector<md5_t> md5_vec_t;

struct md5_size_t
{
  int64 size = 0;
  md5_t md5;
  bool empty() const { return md5.empty(); }
  DECLARE_COMPARISONS(md5_size_t)
  {
    COMPARE_FIELDS(size);
    COMPARE_FIELDS(md5);
    return 0;
  }
  // there is no implementation for these methods in this directory
  // (they are used by vault, and the implementation is autogenerated there)
  void serialize(bytevec_t *out, int version) const;
  bool deserialize(const uchar **ptr, size_t len, int version);
};
DECLARE_TYPE_AS_MOVABLE(md5_size_t);
typedef qvector<md5_size_t> md5_sizes_t;

#endif /* !MD5_H */
