#include "base/win/variant_vector.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/checked_math.h"
#include "base/process/memory.h"
#include "base/win/scoped_safearray.h"
#include "base/win/scoped_variant.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
namespace win {
namespace {
template <VARTYPE ElementVartype>
int CompareAgainstSafearray(const std::vector<ScopedVariant>& vector,
const ScopedSafearray& safearray,
bool ignore_case) {
absl::optional<ScopedSafearray::LockScope<ElementVartype>> lock_scope =
safearray.CreateLockScope<ElementVartype>();
if (!lock_scope)
return 1;
VARIANT non_owning_temp;
V_VT(&non_owning_temp) = ElementVartype;
auto vector_iter = vector.begin();
auto scope_iter = lock_scope->begin();
for (; vector_iter != vector.end() && scope_iter != lock_scope->end();
++vector_iter, ++scope_iter) {
internal::VariantConverter<ElementVartype>::RawSet(&non_owning_temp,
*scope_iter);
int compare_result = vector_iter->Compare(non_owning_temp, ignore_case);
if (compare_result)
return compare_result;
}
if (vector_iter != vector.end())
return 1;
if (scope_iter != lock_scope->end())
return -1;
return 0;
}
}
VariantVector::VariantVector() = default;
VariantVector::VariantVector(VariantVector&& other)
: vartype_(std::exchange(other.vartype_, VT_EMPTY)),
vector_(std::move(other.vector_)) {}
VariantVector& VariantVector::operator=(VariantVector&& other) {
DCHECK_NE(this, &other);
vartype_ = std::exchange(other.vartype_, VT_EMPTY);
vector_ = std::move(other.vector_);
return *this;
}
VariantVector::~VariantVector() {
Reset();
}
bool VariantVector::operator==(const VariantVector& other) const {
return !Compare(other);
}
bool VariantVector::operator!=(const VariantVector& other) const {
return !VariantVector::operator==(other);
}
void VariantVector::Reset() {
vector_.clear();
vartype_ = VT_EMPTY;
}
VARIANT VariantVector::ReleaseAsScalarVariant() {
ScopedVariant scoped_variant;
if (!Empty()) {
DCHECK_EQ(Size(), 1U);
scoped_variant = std::move(vector_[0]);
Reset();
}
return scoped_variant.Release();
}
VARIANT VariantVector::ReleaseAsSafearrayVariant() {
ScopedVariant scoped_variant;
switch (Type()) {
case VT_EMPTY:
break;
case VT_BOOL:
scoped_variant.Set(CreateAndPopulateSafearray<VT_BOOL>());
break;
case VT_I1:
scoped_variant.Set(CreateAndPopulateSafearray<VT_I1>());
break;
case VT_UI1:
scoped_variant.Set(CreateAndPopulateSafearray<VT_UI1>());
break;
case VT_I2:
scoped_variant.Set(CreateAndPopulateSafearray<VT_I2>());
break;
case VT_UI2:
scoped_variant.Set(CreateAndPopulateSafearray<VT_UI2>());
break;
case VT_I4:
scoped_variant.Set(CreateAndPopulateSafearray<VT_I4>());
break;
case VT_UI4:
scoped_variant.Set(CreateAndPopulateSafearray<VT_UI4>());
break;
case VT_I8:
scoped_variant.Set(CreateAndPopulateSafearray<VT_I8>());
break;
case VT_UI8:
scoped_variant.Set(CreateAndPopulateSafearray<VT_UI8>());
break;
case VT_R4:
scoped_variant.Set(CreateAndPopulateSafearray<VT_R4>());
break;
case VT_R8:
scoped_variant.Set(CreateAndPopulateSafearray<VT_R8>());
break;
case VT_DATE:
scoped_variant.Set(CreateAndPopulateSafearray<VT_DATE>());
break;
case VT_BSTR:
scoped_variant.Set(CreateAndPopulateSafearray<VT_BSTR>());
break;
case VT_DISPATCH:
scoped_variant.Set(CreateAndPopulateSafearray<VT_DISPATCH>());
break;
case VT_UNKNOWN:
scoped_variant.Set(CreateAndPopulateSafearray<VT_UNKNOWN>());
break;
default:
NOTREACHED();
break;
}
return scoped_variant.Release();
}
int VariantVector::Compare(const VARIANT& other, bool ignore_case) const {
if (Type() != (V_VT(&other) & VT_TYPEMASK))
return (Type() < (V_VT(&other) & VT_TYPEMASK)) ? (-1) : 1;
if (Type() == VT_EMPTY)
return 0;
int compare_result = 0;
if (V_ISARRAY(&other)) {
compare_result = Compare(V_ARRAY(&other), ignore_case);
} else {
compare_result = vector_[0].Compare(other, ignore_case);
if (!compare_result && Size() > 1)
compare_result = 1;
}
return compare_result;
}
int VariantVector::Compare(const VariantVector& other, bool ignore_case) const {
if (Type() != other.Type())
return (Type() < other.Type()) ? (-1) : 1;
if (Type() == VT_EMPTY)
return 0;
auto iter1 = vector_.begin();
auto iter2 = other.vector_.begin();
for (; (iter1 != vector_.end()) && (iter2 != other.vector_.end());
++iter1, ++iter2) {
int compare_result = iter1->Compare(*iter2, ignore_case);
if (compare_result)
return compare_result;
}
if (iter1 != vector_.end())
return 1;
if (iter2 != other.vector_.end())
return -1;
return 0;
}
int VariantVector::Compare(SAFEARRAY* safearray, bool ignore_case) const {
VARTYPE safearray_vartype;
if (FAILED(SafeArrayGetVartype(safearray, &safearray_vartype)))
return 1;
if (Type() != safearray_vartype)
return (Type() < safearray_vartype) ? (-1) : 1;
ScopedSafearray scoped_safearray(safearray);
int compare_result = 0;
switch (Type()) {
case VT_BOOL:
compare_result = CompareAgainstSafearray<VT_BOOL>(
vector_, scoped_safearray, ignore_case);
break;
case VT_I1:
compare_result = CompareAgainstSafearray<VT_I1>(vector_, scoped_safearray,
ignore_case);
break;
case VT_UI1:
compare_result = CompareAgainstSafearray<VT_UI1>(
vector_, scoped_safearray, ignore_case);
break;
case VT_I2:
compare_result = CompareAgainstSafearray<VT_I2>(vector_, scoped_safearray,
ignore_case);
break;
case VT_UI2:
compare_result = CompareAgainstSafearray<VT_UI2>(
vector_, scoped_safearray, ignore_case);
break;
case VT_I4:
compare_result = CompareAgainstSafearray<VT_I4>(vector_, scoped_safearray,
ignore_case);
break;
case VT_UI4:
compare_result = CompareAgainstSafearray<VT_UI4>(
vector_, scoped_safearray, ignore_case);
break;
case VT_I8:
compare_result = CompareAgainstSafearray<VT_I8>(vector_, scoped_safearray,
ignore_case);
break;
case VT_UI8:
compare_result = CompareAgainstSafearray<VT_UI8>(
vector_, scoped_safearray, ignore_case);
break;
case VT_R4:
compare_result = CompareAgainstSafearray<VT_R4>(vector_, scoped_safearray,
ignore_case);
break;
case VT_R8:
compare_result = CompareAgainstSafearray<VT_R8>(vector_, scoped_safearray,
ignore_case);
break;
case VT_DATE:
compare_result = CompareAgainstSafearray<VT_DATE>(
vector_, scoped_safearray, ignore_case);
break;
case VT_BSTR:
compare_result = CompareAgainstSafearray<VT_BSTR>(
vector_, scoped_safearray, ignore_case);
break;
case VT_DISPATCH:
compare_result = CompareAgainstSafearray<VT_DISPATCH>(
vector_, scoped_safearray, ignore_case);
break;
case VT_UNKNOWN:
compare_result = CompareAgainstSafearray<VT_UNKNOWN>(
vector_, scoped_safearray, ignore_case);
break;
default:
NOTREACHED();
compare_result = 1;
break;
}
scoped_safearray.Release();
return compare_result;
}
template <VARTYPE ElementVartype>
SAFEARRAY* VariantVector::CreateAndPopulateSafearray() {
DCHECK(!Empty());
ScopedSafearray scoped_safearray(
SafeArrayCreateVector(ElementVartype, 0, checked_cast<ULONG>(Size())));
if (!scoped_safearray.Get()) {
constexpr size_t kElementSize =
sizeof(typename internal::VariantConverter<ElementVartype>::Type);
base::TerminateBecauseOutOfMemory(sizeof(SAFEARRAY) +
(Size() * kElementSize));
}
absl::optional<ScopedSafearray::LockScope<ElementVartype>> lock_scope =
scoped_safearray.CreateLockScope<ElementVartype>();
DCHECK(lock_scope);
for (size_t i = 0; i < Size(); ++i) {
VARIANT element = vector_[i].Release();
(*lock_scope)[i] =
internal::VariantConverter<ElementVartype>::RawGet(element);
}
Reset();
return scoped_safearray.Release();
}
}
}