blob: c3dadcbba72b1a326d50a2673fb0f26e615987a5 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "lorgnette/sane_constraint.h"
#include <base/logging.h>
#include <base/notreached.h>
#include <chromeos/dbus/service_constants.h>
#include "lorgnette/dbus_adaptors/org.chromium.lorgnette.Manager.h"
namespace lorgnette {
std::optional<SaneConstraint> SaneConstraint::Create(
const SANE_Option_Descriptor& descriptor) {
SaneConstraint constraint(descriptor.constraint_type, descriptor.type);
switch (descriptor.constraint_type) {
case SANE_CONSTRAINT_NONE:
return constraint;
case SANE_CONSTRAINT_RANGE:
if (!descriptor.constraint.range) {
return std::nullopt;
}
constraint.range_.emplace(*descriptor.constraint.range);
return constraint;
case SANE_CONSTRAINT_WORD_LIST: {
if (!descriptor.constraint.word_list) {
return std::nullopt;
}
SANE_Int num_words = descriptor.constraint.word_list[0];
constraint.word_list_.emplace(
descriptor.constraint.word_list + 1,
descriptor.constraint.word_list + num_words + 1);
return constraint;
}
case SANE_CONSTRAINT_STRING_LIST:
if (!descriptor.constraint.string_list) {
return std::nullopt;
}
constraint.string_list_.emplace();
for (const SANE_String_Const* str = descriptor.constraint.string_list;
*str; str++) {
constraint.string_list_->emplace_back(*str);
}
return constraint;
default:
LOG(ERROR) << "Skipping unhandled option constraint type "
<< descriptor.constraint_type << " in option "
<< descriptor.name;
return std::nullopt;
}
NOTREACHED();
}
SaneConstraint::SaneConstraint(SANE_Constraint_Type constraint_type,
SANE_Value_Type value_type)
: constraint_type_(constraint_type), value_type_(value_type) {}
SANE_Constraint_Type SaneConstraint::GetType() const {
return constraint_type_;
}
std::optional<OptionConstraint> SaneConstraint::ToOptionConstraint() const {
OptionConstraint constraint;
switch (constraint_type_) {
case SANE_CONSTRAINT_NONE:
break;
case SANE_CONSTRAINT_RANGE: {
if (!range_.has_value()) {
LOG(ERROR) << "Missing range entry in constraint";
return std::nullopt;
}
if (value_type_ == SANE_TYPE_FIXED) {
constraint.set_constraint_type(
OptionConstraint::CONSTRAINT_FIXED_RANGE);
auto* range = constraint.mutable_fixed_range();
range->set_min(SANE_UNFIX(range_->min));
range->set_max(SANE_UNFIX(range_->max));
range->set_quant(SANE_UNFIX(range_->quant));
} else {
constraint.set_constraint_type(OptionConstraint::CONSTRAINT_INT_RANGE);
auto* range = constraint.mutable_int_range();
range->set_min(range_->min);
range->set_max(range_->max);
range->set_quant(range_->quant);
}
break;
}
case SANE_CONSTRAINT_WORD_LIST: {
if (!word_list_.has_value()) {
LOG(ERROR) << "Missing word_list entry in constraint";
return std::nullopt;
}
constraint.set_constraint_type(
value_type_ == SANE_TYPE_FIXED
? OptionConstraint::CONSTRAINT_FIXED_LIST
: OptionConstraint::CONSTRAINT_INT_LIST);
for (SANE_Word value : word_list_.value()) {
if (value_type_ == SANE_TYPE_FIXED) {
constraint.add_valid_fixed(SANE_UNFIX(value));
} else {
constraint.add_valid_int(value);
}
}
break;
}
case SANE_CONSTRAINT_STRING_LIST: {
if (!string_list_.has_value()) {
LOG(ERROR) << "Missing string_list entry in constraint";
return std::nullopt;
}
constraint.set_constraint_type(OptionConstraint::CONSTRAINT_STRING_LIST);
for (const std::string& str : string_list_.value()) {
constraint.add_valid_string(str);
}
break;
}
default:
LOG(ERROR) << "Skipping unhandled option constraint type "
<< constraint_type_;
return std::nullopt;
}
return constraint;
}
std::optional<std::vector<std::string>>
SaneConstraint::GetValidStringOptionValues() const {
if (constraint_type_ != SANE_CONSTRAINT_STRING_LIST) {
LOG(ERROR) << __func__
<< ": Invalid option constraint type for string list: "
<< constraint_type_;
return std::nullopt;
}
return string_list_;
}
std::optional<std::vector<uint32_t>> SaneConstraint::GetValidIntOptionValues()
const {
std::vector<uint32_t> values;
switch (constraint_type_) {
case SANE_CONSTRAINT_WORD_LIST:
for (SANE_Word w : *word_list_) {
int value = value_type_ == SANE_TYPE_FIXED ? SANE_UNFIX(w) : w;
values.push_back(value);
}
break;
case SANE_CONSTRAINT_RANGE:
for (int i = range_->min; i <= range_->max; i += range_->quant) {
const int value = value_type_ == SANE_TYPE_FIXED ? SANE_UNFIX(i) : i;
values.push_back(value);
}
break;
default:
LOG(ERROR) << __func__
<< ": Invalid option constraint type for int list: "
<< constraint_type_;
return std::nullopt;
}
return values;
}
std::optional<OptionRange> SaneConstraint::GetOptionRange() const {
if (constraint_type_ != SANE_CONSTRAINT_RANGE) {
LOG(ERROR) << __func__ << ":Invalid option constraint type for range: "
<< constraint_type_;
return std::nullopt;
}
OptionRange option_range;
switch (value_type_) {
case SANE_TYPE_INT:
option_range.start = range_->min;
option_range.size = range_->max - range_->min;
return option_range;
case SANE_TYPE_FIXED:
option_range.start = SANE_UNFIX(range_->min);
option_range.size = SANE_UNFIX(range_->max - range_->min);
return option_range;
default:
LOG(ERROR) << __func__
<< ": Unexpected option value type for range constraint: "
<< value_type_;
return std::nullopt;
}
}
} // namespace lorgnette