code_device/hgsane/sane_opt/sane_opts.cpp

431 lines
8.8 KiB
C++

#include "sane_opts.h"
#include <json/gb_json.h>
#include <algorithm>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sane_opt
sane_opt::sane_opt() : fix_id_(-1), sn_(0), enabled_(true)
{
memset(&opt_desc_, 0, sizeof(opt_desc_));
}
sane_opt::~sane_opt()
{
clear();
}
void sane_opt::clear()
{
if (opt_desc_.desc)
delete[] opt_desc_.desc;
if (opt_desc_.name)
delete[] opt_desc_.name;
if (opt_desc_.title)
delete[] opt_desc_.title;
if (opt_desc_.type == SANE_TYPE_STRING && opt_desc_.constraint_type == SANE_CONSTRAINT_STRING_LIST && opt_desc_.constraint.string_list)
delete[] opt_desc_.constraint.string_list;
else if (opt_desc_.type == SANE_TYPE_INT || opt_desc_.type == SANE_TYPE_FIXED)
{
if (opt_desc_.constraint_type == SANE_CONSTRAINT_RANGE && opt_desc_.constraint.range)
delete[] opt_desc_.constraint.range;
else if (opt_desc_.constraint_type == SANE_CONSTRAINT_WORD_LIST && opt_desc_.constraint.word_list)
delete[] opt_desc_.constraint.word_list;
}
memset(&opt_desc_, 0, sizeof(opt_desc_));
fix_id_ = -1;
sn_ = 0;
enabled_ = true;
}
void sane_opt::set_opt_desc_string_value(char** buf, const char* val)
{
int l = strlen(val) + 4;
l += 4;
l /= 4;
l *= 4;
*buf = new char[l];
if (*buf)
{
memset(*buf, 0, l);
strcpy(*buf, val);
}
}
void sane_opt::init_cap(gb_json* jsn)
{
bool bv = false;
opt_desc_.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_AUTOMATIC;
if (jsn->get_value("readonly", bv) && bv)
SET_CAP_READONLY(opt_desc_.cap);
if (jsn->get_value("enabled", bv) && !bv)
SET_CAP_ACTIVE(opt_desc_.cap, bv);
if (jsn->get_value("auto", bv) && !bv)
opt_desc_.cap &= ~SANE_CAP_AUTOMATIC;
}
void sane_opt::init_range(gb_json* jsn)
{
gb_json* child = nullptr;
if (jsn->get_value("range", child) && child)
{
if (opt_desc_.type == SANE_TYPE_STRING)
{
gb_json* val = child->first_child();
std::vector<std::string> vals;
int len = 0;
char *buf = nullptr, *oper = nullptr;
while (val)
{
std::string v("");
if (val->value(v))
{
vals.push_back(v);
len += ALIGN_TO(v.length() + 1, 4);
}
val->release();
val = child->next_child();
}
len += (vals.size() + 1) * sizeof(char*);
opt_desc_.constraint_type = SANE_CONSTRAINT_STRING_LIST;
buf = new char[len];
opt_desc_.constraint.string_list = (SANE_String_Const*)buf;
memset(buf, 0, len);
oper = buf + (vals.size() + 1) * sizeof(char*);
len = 0;
for (auto& v : vals)
{
((char**)buf)[len++] = oper;
strcpy(oper, v.c_str());
oper += ALIGN_TO(v.length() + 1, 4);
}
}
else if (opt_desc_.type == SANE_TYPE_INT)
{
int v = 0;
if (child->get_value("min", v))
{
SANE_Range* range = new SANE_Range;
opt_desc_.constraint_type = SANE_CONSTRAINT_RANGE;
opt_desc_.constraint.range = range;
range->min = v;
child->get_value("max", range->max);
child->get_value("step", range->quant);
}
else
{
std::vector<int> vals;
gb_json* val = child->first_child();
while (val)
{
if (val->value(v))
vals.push_back(v);
val->release();
val = child->next_child();
}
SANE_Word* lst = new SANE_Word[vals.size() + 1];
int ind = 0;
lst[ind++] = vals.size();
for (auto& e : vals)
lst[ind++] = e;
opt_desc_.constraint_type = SANE_CONSTRAINT_WORD_LIST;
opt_desc_.constraint.word_list = lst;
}
}
else if (opt_desc_.type == SANE_TYPE_FIXED)
{
double v = 0;
if (child->get_value("min", v))
{
SANE_Range* range = new SANE_Range;
opt_desc_.constraint_type = SANE_CONSTRAINT_RANGE;
opt_desc_.constraint.range = range;
range->min = SANE_FIX(v);
if(child->get_value("max", v))
range->max = SANE_FIX(v);
if(child->get_value("step", v))
range->quant = SANE_FIX(v);
}
else
{
std::vector<double> vals;
gb_json* val = child->first_child();
while (val)
{
if (val->value(v))
vals.push_back(v);
val->release();
val = child->next_child();
}
SANE_Word* lst = new SANE_Word[vals.size() + 1];
int ind = 0;
lst[ind++] = vals.size();
for (auto& e : vals)
lst[ind++] = SANE_FIX(e);
opt_desc_.constraint_type = SANE_CONSTRAINT_WORD_LIST;
opt_desc_.constraint.word_list = lst;
}
}
child->release();
}
}
int sane_opt::get_fix_id(void)
{
return fix_id_;
}
int sane_opt::get_sn(void)
{
return sn_;
}
SANE_Option_Descriptor* sane_opt::get_descriptor(void)
{
return &opt_desc_;
}
const char* sane_opt::name(void)
{
return opt_desc_.name;
}
bool sane_opt::is_enabled(void)
{
return enabled_;
}
bool sane_opt::from_json_text(int sn, const char* key, const char* json, void(*err_msg)(const char*))
{
bool ret = false;
std::string text(json);
gb_json *jsn = new gb_json();
char *buf = nullptr;
clear();
sn_ = sn;
while (jsn->attach_text(&text[0]))
{
jsn->get_value("fix-id", fix_id_);
if(!jsn->get_value("enabled", enabled_))
enabled_ = true;
set_opt_desc_string_value((char**)&opt_desc_.name, key);
if (jsn->get_value("title", text))
{
set_opt_desc_string_value((char**)&opt_desc_.title, text.c_str());
}
if (jsn->get_value("desc", text))
{
set_opt_desc_string_value((char**)&opt_desc_.desc, text.c_str());
}
if (!jsn->get_value("type", text))
break;
if (text == "bool")
{
opt_desc_.type = SANE_TYPE_BOOL;
}
else if (text == "int")
{
opt_desc_.type = SANE_TYPE_INT;
}
else if (text == "float")
{
opt_desc_.type = SANE_TYPE_FIXED;
}
else if (text == "string")
{
opt_desc_.type = SANE_TYPE_STRING;
}
else if (text == "group")
opt_desc_.type = SANE_TYPE_GROUP;
else if (text == "button")
opt_desc_.type = SANE_TYPE_BUTTON;
else
break;
opt_desc_.unit = SANE_UNIT_NONE;
if (jsn->get_value("unit", text))
{
if (text == "pixel")
opt_desc_.unit = SANE_UNIT_PIXEL;
else if (text == "bit")
opt_desc_.unit = SANE_UNIT_BIT;
else if (text == "mm")
opt_desc_.unit = SANE_UNIT_MM;
else if (text == "DPI")
opt_desc_.unit = SANE_UNIT_DPI;
else if (text == "%")
opt_desc_.unit = SANE_UNIT_PERCENT;
else if (text == "microsec")
opt_desc_.unit = SANE_UNIT_MICROSECOND;
else
opt_desc_.unit = SANE_UNIT_NONE;
}
jsn->get_value("size", opt_desc_.size);
// cap ...
init_cap(jsn);
// range ...
init_range(jsn);
ret = true;
break;
}
jsn->release();
return ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sane_opt
device_opts::device_opts() : opt_cnt_(0)
{
memset(&opt_0_, 0, sizeof(opt_0_));
opt_0_.cap = SANE_CAP_SOFT_DETECT;
opt_0_.name = "option-count";
opt_0_.desc = "option count of this device";
opt_0_.title = "option count";
opt_0_.type = SANE_TYPE_INT;
opt_0_.size = sizeof(SANE_Int);
}
device_opts::~device_opts()
{
clear();
}
void device_opts::clear(void)
{
for (auto& v : opts_)
{
if(v.first == v.second->get_sn()) // fix-id has the same object, we delete object at it's option number
delete v.second;
}
opts_.clear();
opt_cnt_ = 0;
}
bool device_opts::init_from(const char* jsn_text/*all options*/, void(*err_msg)(const char*))
{
bool ret = false;
gb_json* jsn = new gb_json();
std::string str(jsn_text);
int sn = 1;
clear();
if (jsn->attach_text(&str[0]))
{
gb_json* child = jsn->first_child();
str = "";
while (child)
{
str = std::move(child->to_string());
ret = add_or_replace_opt(sn++, child->key().c_str(), str.c_str(), err_msg);
if (!ret)
{
child->release();
clear();
break;
}
child->release();
child = jsn->next_child();
}
}
jsn->release();
return ret;
}
bool device_opts::add_or_replace_opt(int sn, const char* name, const char* jsn_text, void(*err_msg)(const char*))
{
if (opts_.count(sn))
{
bool en = opts_[sn]->is_enabled(),
ret = opts_[sn]->from_json_text(sn, name, jsn_text, err_msg);
return ret;
}
sane_opt* opt = new sane_opt();
if (opt->from_json_text(sn, name, jsn_text, err_msg))
{
opts_[sn] = opt;
if (opt->get_fix_id() != -1)
{
opts_[opt->get_fix_id()] = opt;
}
opt_cnt_++;
return true;
}
else
{
delete opt;
return false;
}
}
SANE_Option_Descriptor* device_opts::get_opt_descriptor(const void* opt, int* fix_id, int ind_base)
{
if (fix_id)
*fix_id = -1;
if (opt == nullptr)
{
return &opt_0_;
}
if (IS_PTR_NUMBER(opt))
{
int sn = (int)opt;
sn -= ind_base;
if (opts_.count(sn))
{
if (fix_id)
*fix_id = opts_[sn]->get_fix_id();
return opts_[sn]->get_descriptor();
}
}
else
{
const char* name = (const char*)opt;
for (auto& v : opts_)
{
if (v.second->name() == name)
{
if (fix_id)
*fix_id = v.second->get_fix_id();
return v.second->get_descriptor();
}
}
}
return nullptr;
}
int device_opts::get_option_count(void)
{
return opt_cnt_;
}