// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/hash_value.h"

#include <stdlib.h>
#include <algorithm>

#include "base/base64.h"
#include "base/logging.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "crypto/sha2.h"
#include "starboard/memory.h"
#include "starboard/types.h"

namespace net {

namespace {

// LessThan comparator for use with std::binary_search() in determining
// whether a SHA-256 HashValue appears within a sorted array of
// SHA256HashValues.
struct SHA256ToHashValueComparator {
  bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const {
    DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag());
    return SbMemoryCompare(lhs.data, rhs.data(), rhs.size()) < 0;
  }

  bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const {
    DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag());
    return SbMemoryCompare(lhs.data(), rhs.data, lhs.size()) < 0;
  }
};

}  // namespace


HashValue::HashValue(const SHA256HashValue& hash)
    : HashValue(HASH_VALUE_SHA256) {
  fingerprint.sha256 = hash;
}

bool HashValue::FromString(const base::StringPiece value) {
  base::StringPiece base64_str;
  if (value.starts_with("sha256/")) {
    tag_ = HASH_VALUE_SHA256;
    base64_str = value.substr(7);
  } else {
    return false;
  }

  std::string decoded;
  if (!base::Base64Decode(base64_str, &decoded) || decoded.size() != size())
    return false;

  SbMemoryCopy(data(), decoded.data(), size());
  return true;
}

std::string HashValue::ToString() const {
  std::string base64_str;
  base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>(data()),
                                       size()), &base64_str);
  switch (tag_) {
    case HASH_VALUE_SHA256:
      return std::string("sha256/") + base64_str;
  }

  NOTREACHED() << "Unknown HashValueTag " << tag_;
  return std::string("unknown/" + base64_str);
}

size_t HashValue::size() const {
  switch (tag_) {
    case HASH_VALUE_SHA256:
      return sizeof(fingerprint.sha256.data);
  }

  NOTREACHED() << "Unknown HashValueTag " << tag_;
  // While an invalid tag should not happen, return a non-zero length
  // to avoid compiler warnings when the result of size() is
  // used with functions like memset.
  return sizeof(fingerprint.sha256.data);
}

unsigned char* HashValue::data() {
  return const_cast<unsigned char*>(const_cast<const HashValue*>(this)->data());
}

const unsigned char* HashValue::data() const {
  switch (tag_) {
    case HASH_VALUE_SHA256:
      return fingerprint.sha256.data;
  }

  NOTREACHED() << "Unknown HashValueTag " << tag_;
  return nullptr;
}

bool operator==(const HashValue& lhs, const HashValue& rhs) {
  if (lhs.tag_ != rhs.tag_)
    return false;

  switch (lhs.tag_) {
    case HASH_VALUE_SHA256:
      return lhs.fingerprint.sha256 == rhs.fingerprint.sha256;
  }

  NOTREACHED();
  return false;
}

bool operator!=(const HashValue& lhs, const HashValue& rhs) {
  return !(lhs == rhs);
}

bool operator<(const HashValue& lhs, const HashValue& rhs) {
  if (lhs.tag_ != rhs.tag_)
    return lhs.tag_ < rhs.tag_;

  switch (lhs.tag_) {
    case HASH_VALUE_SHA256:
      return lhs.fingerprint.sha256 < rhs.fingerprint.sha256;
  }

  NOTREACHED();
  return false;
}

bool operator>(const HashValue& lhs, const HashValue& rhs) {
  return rhs < lhs;
}

bool operator<=(const HashValue& lhs, const HashValue& rhs) {
  return !(lhs > rhs);
}

bool operator>=(const HashValue& lhs, const HashValue& rhs) {
  return !(lhs < rhs);
}

bool IsSHA256HashInSortedArray(const HashValue& hash,
                               base::span<const SHA256HashValue> array) {
  return std::binary_search(array.begin(), array.end(), hash,
                            SHA256ToHashValueComparator());
}

#if defined(STARBOARD) && SB_IS(COMPILER_MSVC)
// MSVC can not implicitly convert HashValueVector to span<HashValue>.
bool IsAnySHA256HashInSortedArray(const HashValueVector& hashes,
                                  base::span<const SHA256HashValue> array) {
  for (const auto& hash : hashes) {
    if (hash.tag() != HASH_VALUE_SHA256)
      continue;

    if (IsSHA256HashInSortedArray(hash, array))
      return true;
  }
  return false;
}
#endif

bool IsAnySHA256HashInSortedArray(base::span<const HashValue> hashes,
                                  base::span<const SHA256HashValue> array) {
  for (const auto& hash : hashes) {
    if (hash.tag() != HASH_VALUE_SHA256)
      continue;

    if (IsSHA256HashInSortedArray(hash, array))
      return true;
  }
  return false;
}

}  // namespace net
