RE-CONSTRUCT: optimize option logical algrithm, support condition value; move option logical calculation to driver, only to SANE_Option_Descriptor keeped in sane
This commit is contained in:
parent
8fd0ea023a
commit
06b4caf64b
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,256 @@
|
|||
//
|
||||
// device_opt: option manager of device
|
||||
//
|
||||
// Created: 2023-09-07
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sane/sane_ex.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
#include "simple_logic.h"
|
||||
#include <json/gb_json.h>
|
||||
|
||||
|
||||
class device_option
|
||||
{
|
||||
gb_json* origin_;
|
||||
gb_json* now_;
|
||||
std::vector<std::string> master_opts_; // options that value changed will affect others
|
||||
std::map<std::string, simple_logic*> slaver_;
|
||||
|
||||
typedef struct _expr_calc
|
||||
{
|
||||
std::string name;
|
||||
std::string val1;
|
||||
std::string val2;
|
||||
bool not_op;
|
||||
bool(*compare)(gb_json*, void* val, void* v1, void* v2);
|
||||
}EXPRCALC;
|
||||
std::map<std::string, EXPRCALC> compare_; // simple condition compare
|
||||
|
||||
class condition_value
|
||||
{
|
||||
typedef struct _cond_val
|
||||
{
|
||||
simple_logic *logic;
|
||||
std::string value;
|
||||
}CONDVAL;
|
||||
std::vector<CONDVAL> vals_;
|
||||
|
||||
void clear(void)
|
||||
{
|
||||
for (auto& v : vals_)
|
||||
{
|
||||
if (v.logic)
|
||||
delete v.logic;
|
||||
}
|
||||
vals_.clear();
|
||||
}
|
||||
|
||||
public:
|
||||
condition_value()
|
||||
{}
|
||||
~condition_value()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
public:
|
||||
bool set_value(gb_json* jsn, const char* type, device_option* parent); // jsn contains only ONE value or its object
|
||||
std::string value(bool(*compare)(const char*, void*), void* param)
|
||||
{
|
||||
for (auto& v : vals_)
|
||||
{
|
||||
if (!v.logic)
|
||||
return v.value;
|
||||
else if (v.logic->value(compare, param))
|
||||
return v.value;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
};
|
||||
class range_value
|
||||
{
|
||||
bool is_range_; // true - range; false - list
|
||||
int val_ind_;
|
||||
std::vector<condition_value*> vals_;
|
||||
|
||||
void clear(void)
|
||||
{
|
||||
for (auto& v : vals_)
|
||||
delete v;
|
||||
vals_.clear();
|
||||
}
|
||||
|
||||
public:
|
||||
range_value() : is_range_(false), val_ind_(0)
|
||||
{}
|
||||
~range_value()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
public:
|
||||
bool set_value(gb_json* jsn, const char* type, device_option *parent); // jsn contains all range object
|
||||
int count(void)
|
||||
{
|
||||
return vals_.size();
|
||||
}
|
||||
bool is_range(void)
|
||||
{
|
||||
return is_range_;
|
||||
}
|
||||
|
||||
// return first element in list-value or min-value of range
|
||||
std::string first_value(bool(*compare)(const char*, void*), void* param)
|
||||
{
|
||||
val_ind_ = 0;
|
||||
if (val_ind_ < count())
|
||||
return vals_[val_ind_]->value(compare, param);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
// return next element in list-value or max-value of range
|
||||
std::string next_value(bool(*compare)(const char*, void*), void* param)
|
||||
{
|
||||
if (++val_ind_ < count())
|
||||
return vals_[val_ind_]->value(compare, param);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
};
|
||||
std::map<std::string, range_value*> range_value_;
|
||||
|
||||
static bool is_equal_b(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_equal_i(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_equal_f(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_equal_s(gb_json* opt, void* val, void* v1, void* v2);
|
||||
|
||||
static bool is_less_b(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_less_i(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_less_f(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_less_s(gb_json* opt, void* val, void* v1, void* v2);
|
||||
|
||||
static bool is_great_b(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_great_i(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_great_f(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_great_s(gb_json* opt, void* val, void* v1, void* v2);
|
||||
|
||||
static bool is_between_b(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_between_i(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_between_f(gb_json* opt, void* val, void* v1, void* v2);
|
||||
static bool is_between_s(gb_json* opt, void* val, void* v1, void* v2);
|
||||
|
||||
static bool is_opt_enabled(gb_json* opt, void* val, void* v1, void* v2);
|
||||
|
||||
static bool get_equal(const char* type, bool(**f)(gb_json*, void*, void*, void*));
|
||||
static bool get_less(const char* type, bool(**f)(gb_json*, void*, void*, void*));
|
||||
static bool get_great(const char* type, bool(**f)(gb_json*, void*, void*, void*));
|
||||
static bool get_between(const char* type, bool(**f)(gb_json*, void*, void*, void*));
|
||||
|
||||
static std::string from_text_value(const char* type, const char* text_val);
|
||||
static bool parse_simple_logic_expression(gb_json* root, const char* expr, std::string* name, EXPRCALC& calc);
|
||||
static void init_condition(const char* expr, void* param);
|
||||
static bool calc_simple_logic_expression(const char* expr, void* param);
|
||||
|
||||
void clear(void);
|
||||
void init_depends(gb_json* opt);
|
||||
gb_json* copy_opt(gb_json* from);
|
||||
bool to_now(bool init);
|
||||
|
||||
public:
|
||||
device_option();
|
||||
~device_option();
|
||||
|
||||
static std::string option_value(gb_json* jsn, bool def_val);
|
||||
|
||||
template<class T>
|
||||
static condition_value* to_condition_value(gb_json* jsn, const char* key, const char* type, device_option* parent)
|
||||
{
|
||||
condition_value* ret = nullptr;
|
||||
gb_json* child = nullptr;
|
||||
|
||||
if (!jsn->get_value(key, child))
|
||||
{
|
||||
T v;
|
||||
jsn->get_value(key, v);
|
||||
child = new gb_json("", v);
|
||||
}
|
||||
|
||||
ret = new condition_value();
|
||||
if (!ret->set_value(child, type, parent))
|
||||
{
|
||||
delete ret;
|
||||
ret = nullptr;
|
||||
}
|
||||
child->release();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
bool init(const char* opt_json);
|
||||
bool refine_data(const char* name, void* value); // return true if the 'value' is out of range and refined it in the range
|
||||
int update_data(const char* name, void* value); // return scanner_err. name and value would be null if invoked for language changed
|
||||
|
||||
std::string get_option_value_type(const char* name);
|
||||
std::string get_option_value(const char* name, int type); // return whole json-text if name was null
|
||||
};
|
||||
|
||||
//{
|
||||
// "noise-size": {
|
||||
// "cat": "base",
|
||||
// "group" : "base",
|
||||
// "title" : " 噪点优化尺寸",
|
||||
// "desc" : "设置需要去除的黑",
|
||||
// "ver" : 0,
|
||||
// "pos" : 0,
|
||||
// "fix-id" : 0,
|
||||
// "type" : "int",
|
||||
// "unit" : "none",
|
||||
// "affect" : 0,
|
||||
// "readonly" : false,
|
||||
// "visible" : true,
|
||||
// "enabled" : false,
|
||||
// "size" : 4,
|
||||
// "cur" : 10,
|
||||
// "default" : 10,
|
||||
// "range" : {
|
||||
// "min": 1,
|
||||
// "max" : {
|
||||
// "paper==A3": 50, // condition value
|
||||
// "default": 45} ,
|
||||
// "step" : 1
|
||||
// },
|
||||
// "depend_or": ["is-noise-optimize==true"]
|
||||
// },
|
||||
//
|
||||
// "paper": {
|
||||
// "cat": "base",
|
||||
// "group" : "base",
|
||||
// "title" : "纸张尺寸",
|
||||
// "desc" : "设置出图大小",
|
||||
// "ver" : 0,
|
||||
// "pos" : 0,
|
||||
// "fix-id" : 0,
|
||||
// "type" : "string",
|
||||
// "unit" : "none",
|
||||
// "affect" : 0,
|
||||
// "readonly" : false,
|
||||
// "visible" : true,
|
||||
// "enabled" : false,
|
||||
// "size" : 96,
|
||||
// "cur" : "匹配原始尺寸",
|
||||
// "default" : "匹配原始尺寸",
|
||||
// "range" : ["A3", "8开", {
|
||||
// "mode==24位彩色": "A4" // condition value
|
||||
// }, "A4横向", "16开", "16开横向", "A5", "A5横向", "A6", "A6横向", "B4", "B5", "B5横向", "B6", "B6横向", "Letter", "Letter横向", "Double Letter", "LEGAL", "匹配原始尺寸", "最大扫描尺寸自动裁切", "最大扫描尺寸", "三联试卷"]
|
||||
// }
|
||||
//}
|
22880
hgdriver/hgdev/json.hpp
22880
hgdriver/hgdev/json.hpp
File diff suppressed because it is too large
Load Diff
|
@ -1,138 +0,0 @@
|
|||
#include "jsonconfig.h"
|
||||
#include <streambuf>
|
||||
|
||||
|
||||
jsonconfig::jsonconfig()
|
||||
{
|
||||
|
||||
}
|
||||
jsonconfig::jsonconfig(int devnum):DEVICEJSONPATH("")
|
||||
{
|
||||
switch (devnum)
|
||||
{
|
||||
case 100:
|
||||
DEVICEJSONPATH=G100JSONPATH;
|
||||
break;
|
||||
case 200:
|
||||
DEVICEJSONPATH=G200JSONPATH;
|
||||
break;
|
||||
case 300:
|
||||
DEVICEJSONPATH=G300JSONPATH;
|
||||
break;
|
||||
case 400:
|
||||
DEVICEJSONPATH=G400JSONPATH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
json jsonconfig::loadjson(std::string path)
|
||||
{
|
||||
json js="";
|
||||
if(path.empty())
|
||||
return js;
|
||||
std::ifstream f;
|
||||
f.open(path,std::ios::in | std::ios::binary);
|
||||
if(f.is_open()){
|
||||
//std::string text = (std::stringstream() << f.rdbuf()).str();
|
||||
std::string text ((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
js = json::parse(text);
|
||||
f.close();
|
||||
}
|
||||
return js;
|
||||
}
|
||||
|
||||
json jsonconfig::loadjson()
|
||||
{
|
||||
json js="";
|
||||
std::string path=DEVICEJSONPATH;
|
||||
if(path.empty())
|
||||
return js;
|
||||
std::ifstream f;
|
||||
f.open(path,std::ios::in | std::ios::binary);
|
||||
if(f.is_open()){
|
||||
std::string text ((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
js = json::parse(text);
|
||||
f.close();
|
||||
}
|
||||
return js;
|
||||
}
|
||||
json jsonconfig::load_json_from_text(const char* json_txt, std::vector<std::string>* children)
|
||||
{
|
||||
return json::parse(json_txt, children);
|
||||
}
|
||||
|
||||
std::string jsonconfig::getdeviceparam(unsigned param_no)
|
||||
{
|
||||
json js=loadjson();
|
||||
if (js.empty())
|
||||
return NULL;
|
||||
js[std::to_string(param_no)]["cur"]=0;
|
||||
std::string str=js[std::to_string(param_no)].dump();
|
||||
if (str.empty())
|
||||
return NULL;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool jsonconfig::savejson(std::string path,json js)
|
||||
{
|
||||
if(path.empty())
|
||||
return false;
|
||||
std::ofstream of;
|
||||
of.open(path);
|
||||
if(of.is_open())
|
||||
{
|
||||
of.write(js.dump().data(),js.dump().size());
|
||||
of.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
json jsonconfig::defaultjson()
|
||||
{
|
||||
std::string jsstr=R"({
|
||||
"info":[{
|
||||
"type":"GScanO200",
|
||||
"name":"HUAGO G100 Scanner",
|
||||
"vid":"3072",
|
||||
"pid":"100"
|
||||
},
|
||||
{
|
||||
"type":"GScanO200",
|
||||
"name":"HUAGO G200 Scanner",
|
||||
"vid":"3072",
|
||||
"pid":"200"
|
||||
},
|
||||
{
|
||||
"type":"GScanO400",
|
||||
"name":"HUAGO G300 Scanner",
|
||||
"vid":"3072",
|
||||
"pid":"300"
|
||||
},
|
||||
{
|
||||
"type":"GScanO400",
|
||||
"name":"HUAGO G400 Scanner",
|
||||
"vid":"3072",
|
||||
"pid":"400"
|
||||
},
|
||||
{
|
||||
"type":"GScanO1003399",
|
||||
"name":"HUAGO G139 Scanner",
|
||||
"vid":"3072",
|
||||
"pid":"139"
|
||||
},
|
||||
{
|
||||
"type":"GScanO1003399",
|
||||
"name":"HUAGO G239 Scanner",
|
||||
"vid":"3072",
|
||||
"pid":"239"
|
||||
}]
|
||||
})";
|
||||
return json::parse(jsstr);
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include "json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
const std::string JSONPATH ="/opt/hgscannersdk.json";
|
||||
static const std::string G100JSONPATH ="/opt/G100.json";
|
||||
static const std::string G200JSONPATH ="/opt/G200.json";
|
||||
static const std::string G300JSONPATH ="/opt/G300.json";
|
||||
static const std::string G400JSONPATH ="/opt/G400.json";
|
||||
|
||||
|
||||
class jsonconfig
|
||||
{
|
||||
public:
|
||||
static json loadjson(std::string path);
|
||||
static json load_json_from_text(const char* json_txt, std::vector<std::string>* children = nullptr);
|
||||
static bool savejson(std::string path,json js);
|
||||
static json defaultjson();
|
||||
|
||||
private:
|
||||
json loadjson();
|
||||
std::string DEVICEJSONPATH;
|
||||
|
||||
public:
|
||||
jsonconfig();
|
||||
jsonconfig(int devnum);
|
||||
~jsonconfig();
|
||||
std::string getdeviceparam(unsigned param_no);
|
||||
};
|
|
@ -0,0 +1,549 @@
|
|||
|
||||
#include "simple_logic.h"
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// logic_expression
|
||||
namespace string_util
|
||||
{
|
||||
// Function: find the ending position in str
|
||||
//
|
||||
// Parameter: str - the string beginning after the first letter 'head'
|
||||
//
|
||||
// head - the leading letter, can be emblaced
|
||||
//
|
||||
// tail - the ending letter
|
||||
//
|
||||
// Return: position at the ending letter, or '\0' in the string
|
||||
int find_end_of_pair(const char* str, char head, char tail)
|
||||
{
|
||||
int end = 0, banlance = 1;
|
||||
|
||||
while (str[end])
|
||||
{
|
||||
if (str[end] == '\\')
|
||||
{
|
||||
end++;
|
||||
if (!str[end])
|
||||
break;
|
||||
|
||||
// skip this translating-letter
|
||||
end++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[end] == head)
|
||||
{
|
||||
banlance++;
|
||||
}
|
||||
else if (str[end] == tail)
|
||||
{
|
||||
if (--banlance == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
end++;
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
void skip_space(const char*& ptr, const char* space = " \t")
|
||||
{
|
||||
char mark[2] = { 0 };
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
mark[0] = *ptr;
|
||||
if (!strstr(space, mark))
|
||||
break;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// simple_logic
|
||||
simple_logic::simple_logic() : l_(nullptr), r_(nullptr), oper_(LOGIC_OPER_NONE), expr_(""), not_(false)
|
||||
{}
|
||||
simple_logic::simple_logic(const simple_logic& r) : l_(nullptr), r_(nullptr)
|
||||
{
|
||||
copy(r);
|
||||
}
|
||||
simple_logic::~simple_logic()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void simple_logic::clear(void)
|
||||
{
|
||||
if (l_)
|
||||
delete l_;
|
||||
if (r_)
|
||||
delete r_;
|
||||
l_ = r_ = nullptr;
|
||||
|
||||
oper_ = LOGIC_OPER_NONE;
|
||||
expr_ = "";
|
||||
not_ = false;
|
||||
}
|
||||
void simple_logic::copy(const simple_logic& r)
|
||||
{
|
||||
clear();
|
||||
|
||||
oper_ = r.oper_;
|
||||
not_ = r.not_;
|
||||
expr_ = r.expr_;
|
||||
if (r.l_)
|
||||
{
|
||||
l_ = new simple_logic();
|
||||
l_->copy(*r.l_);
|
||||
}
|
||||
if (r.r_)
|
||||
{
|
||||
r_ = new simple_logic();
|
||||
r_->copy(*r.r_);
|
||||
}
|
||||
}
|
||||
void simple_logic::set_not(bool notv)
|
||||
{
|
||||
not_ = notv;
|
||||
}
|
||||
bool simple_logic::parse_internal(const char* expr, int* end, void(*leaf)(const char*, void*), void* leaf_param)
|
||||
{
|
||||
const char* ptr = expr, * first = nullptr;
|
||||
std::vector<simple_logic*> ele;
|
||||
std::vector<int> oper;
|
||||
bool need_oper = false, good = true;
|
||||
|
||||
string_util::skip_space(ptr);
|
||||
if (*ptr == 0)
|
||||
return false;
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr == '(')
|
||||
{
|
||||
if (need_oper)
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
|
||||
int len = string_util::find_end_of_pair(ptr + 1, '(', ')');
|
||||
if (ptr[++len] != ')')
|
||||
{
|
||||
*end = ptr - expr + len;
|
||||
good = false;
|
||||
break;
|
||||
}
|
||||
|
||||
std::string sub(ptr + 1, len - 1);
|
||||
simple_logic *e = new simple_logic();
|
||||
int over = 0;
|
||||
bool not_v = false;
|
||||
|
||||
if (first)
|
||||
{
|
||||
while (first < ptr)
|
||||
{
|
||||
if (*first == '!')
|
||||
not_v ^= true;
|
||||
else
|
||||
break;
|
||||
first++;
|
||||
}
|
||||
if (first < ptr)
|
||||
{
|
||||
*end = first - expr;
|
||||
good = false;
|
||||
delete e;
|
||||
break;
|
||||
}
|
||||
first = nullptr;
|
||||
}
|
||||
|
||||
if (e->parse(sub.c_str(), &over))
|
||||
{
|
||||
e->set_not(not_v);
|
||||
ele.push_back(e);
|
||||
ptr += len;
|
||||
need_oper = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*end = ptr - expr + 1 + over;
|
||||
good = false;
|
||||
delete e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*ptr == '|')
|
||||
{
|
||||
if (*(ptr + 1) == '|')
|
||||
{
|
||||
if (need_oper || first)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
simple_logic* e = new simple_logic();
|
||||
e->expr_ = std::string(first, ptr - first);
|
||||
e->oper_ = LOGIC_OPER_LEAF;
|
||||
ele.push_back(e);
|
||||
first = nullptr;
|
||||
if (leaf)
|
||||
leaf(e->expr_.c_str(), leaf_param);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
oper.push_back(LOGIC_OPER_OR);
|
||||
need_oper = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*ptr == '&')
|
||||
{
|
||||
if (*(ptr + 1) == '&')
|
||||
{
|
||||
if (need_oper || first)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
simple_logic* e = new simple_logic();
|
||||
e->expr_ = std::string(first, ptr - first);
|
||||
e->oper_ = LOGIC_OPER_LEAF;
|
||||
ele.push_back(e);
|
||||
first = nullptr;
|
||||
if (leaf)
|
||||
leaf(e->expr_.c_str(), leaf_param);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
oper.push_back(LOGIC_OPER_AND);
|
||||
need_oper = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*ptr == '^')
|
||||
{
|
||||
if (need_oper || first)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
simple_logic* e = new simple_logic();
|
||||
e->expr_ = std::string(first, ptr - first);
|
||||
e->oper_ = LOGIC_OPER_LEAF;
|
||||
ele.push_back(e);
|
||||
first = nullptr;
|
||||
if (leaf)
|
||||
leaf(e->expr_.c_str(), leaf_param);
|
||||
}
|
||||
|
||||
oper.push_back(LOGIC_OPER_XOR);
|
||||
need_oper = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// expression ...
|
||||
if (need_oper)
|
||||
{
|
||||
good = false;
|
||||
*end = ptr - expr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
first = ptr;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
string_util::skip_space(ptr);
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
if (need_oper)
|
||||
{
|
||||
*end = first - expr;
|
||||
good = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
simple_logic* e = new simple_logic();
|
||||
int over = 0;
|
||||
if (e->parse(first, &over))
|
||||
ele.push_back(e);
|
||||
else
|
||||
{
|
||||
good = false;
|
||||
*end = first - expr + over;
|
||||
delete e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (good && oper.size() == ele.size() - 1)
|
||||
{
|
||||
simple_logic* root = make_binary(ele, oper);
|
||||
l_ = root->l_;
|
||||
r_ = root->r_;
|
||||
oper_ = root->oper_;
|
||||
expr_ = root->expr_;
|
||||
root->l_ = root->r_ = nullptr;
|
||||
delete root;
|
||||
*end = ptr - expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& v : ele)
|
||||
delete v;
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
simple_logic* simple_logic::make_binary(const std::vector<simple_logic*>& eles, const std::vector<int>& opers)
|
||||
{
|
||||
if (eles.size() == 0 && opers.size() == 0)
|
||||
return nullptr;
|
||||
else if (eles.size() == 1)
|
||||
return eles[0];
|
||||
|
||||
int or_pos = -1;
|
||||
|
||||
for (int i = 0; i < opers.size(); ++i)
|
||||
{
|
||||
if (opers[i] == LOGIC_OPER_OR)
|
||||
{
|
||||
or_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
simple_logic* node = new simple_logic();
|
||||
|
||||
if (or_pos == -1)
|
||||
{
|
||||
//node->l_ = eles[0];
|
||||
//node->oper_ = opers[0];
|
||||
//
|
||||
//std::vector<simple_logic*> re;
|
||||
//std::vector<int> ro;
|
||||
//for (int i = 1; i < eles.size(); ++i)
|
||||
// re.push_back(eles[i]);
|
||||
//for (int i = 1; i < opers.size(); ++i)
|
||||
// ro.push_back(opers[i]);
|
||||
//node->r_ = make_binary(re, ro);
|
||||
node->r_ = eles[eles.size() - 1];
|
||||
node->l_ = eles[eles.size() - 2];
|
||||
node->oper_ = opers[opers.size() - 1];
|
||||
|
||||
simple_logic** left = &node->l_;
|
||||
int cnt = 2;
|
||||
|
||||
while (++cnt <= eles.size())
|
||||
{
|
||||
simple_logic* n = new simple_logic();
|
||||
n->oper_ = opers[opers.size() - cnt + 1];
|
||||
n->l_ = eles[eles.size() - cnt];
|
||||
n->r_ = *left;
|
||||
*left = n;
|
||||
left = &n->l_;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<simple_logic*> re;
|
||||
std::vector<int> ro;
|
||||
|
||||
node->oper_ = LOGIC_OPER_OR;
|
||||
for (int i = 0; i < or_pos + 1; ++i)
|
||||
re.push_back(eles[i]);
|
||||
for (int i = 0; i < or_pos; ++i)
|
||||
ro.push_back(opers[i]);
|
||||
node->l_ = make_binary(re, ro);
|
||||
|
||||
re.clear();
|
||||
ro.clear();
|
||||
for (int i = or_pos + 1; i < eles.size(); ++i)
|
||||
re.push_back(eles[i]);
|
||||
for (int i = or_pos + 1; i < opers.size(); ++i)
|
||||
ro.push_back(opers[i]);
|
||||
node->r_ = make_binary(re, ro);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
std::string simple_logic::to_string_internal(bool& single)
|
||||
{
|
||||
single = true;
|
||||
if (oper_ == LOGIC_OPER_LEAF)
|
||||
return expr_;
|
||||
else if (oper_ == LOGIC_OPER_AND || oper_ == LOGIC_OPER_OR || oper_ == LOGIC_OPER_XOR)
|
||||
{
|
||||
std::string exp("");
|
||||
|
||||
if (l_)
|
||||
{
|
||||
exp = l_->to_string_internal(single);
|
||||
if (!single)
|
||||
{
|
||||
exp += ")";
|
||||
exp.insert(0, "(");
|
||||
}
|
||||
}
|
||||
|
||||
if (oper_ == LOGIC_OPER_AND)
|
||||
exp += " && ";
|
||||
else if (oper_ == LOGIC_OPER_OR)
|
||||
exp += " || ";
|
||||
else
|
||||
exp += " ^ ";
|
||||
|
||||
if (r_)
|
||||
{
|
||||
bool s = false;
|
||||
std::string r(r_->to_string_internal(s));
|
||||
|
||||
if (!s)
|
||||
{
|
||||
r.insert(0, "(");
|
||||
r += ")";
|
||||
}
|
||||
exp += r;
|
||||
}
|
||||
|
||||
if (not_)
|
||||
{
|
||||
exp.insert(0, "!(");
|
||||
exp += ")";
|
||||
single = true;
|
||||
}
|
||||
else
|
||||
single = false;
|
||||
|
||||
return std::move(exp);
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
simple_logic& simple_logic::operator=(const simple_logic& r)
|
||||
{
|
||||
copy(r);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool simple_logic::parse(const char* expr, int* end_pos, void(*leaf)(const char*, void*), void* leaf_param)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
clear();
|
||||
if (strstr(expr, "||") == nullptr &&
|
||||
strstr(expr, "&&") == nullptr &&
|
||||
strstr(expr, "^") == nullptr)
|
||||
{
|
||||
oper_ = LOGIC_OPER_LEAF;
|
||||
expr_ = expr;
|
||||
ret = true;
|
||||
if (leaf)
|
||||
leaf(expr_.c_str(), leaf_param);
|
||||
}
|
||||
else
|
||||
{
|
||||
int end = 0;
|
||||
|
||||
ret = parse_internal(expr, &end, leaf, leaf_param);
|
||||
if (end_pos)
|
||||
*end_pos = end;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
bool simple_logic::value(bool(*simple_expr_value)(const char*, void*), void* param)
|
||||
{
|
||||
if (oper_ == LOGIC_OPER_LEAF)
|
||||
return simple_expr_value(expr_.c_str(), param);
|
||||
else if (oper_ == LOGIC_OPER_AND)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if (l_)
|
||||
ret = l_->value(simple_expr_value, param);
|
||||
if (ret && r_)
|
||||
ret &= r_->value(simple_expr_value, param);
|
||||
|
||||
return ret ^ not_;
|
||||
}
|
||||
else if (oper_ == LOGIC_OPER_OR)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (l_)
|
||||
ret = l_->value(simple_expr_value, param);
|
||||
if (!ret && r_)
|
||||
ret = r_->value(simple_expr_value, param);
|
||||
|
||||
return ret ^ not_;
|
||||
}
|
||||
else if (oper_ == LOGIC_OPER_XOR)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (l_)
|
||||
ret = l_->value(simple_expr_value, param);
|
||||
if (r_)
|
||||
ret ^= r_->value(simple_expr_value, param);
|
||||
|
||||
return ret ^ not_;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::string simple_logic::to_expression(void)
|
||||
{
|
||||
bool single = false;
|
||||
|
||||
return std::move(to_string_internal(single));
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
// simple_logic.h : include file for simple logical operation
|
||||
//
|
||||
// Purpose: to parse and execute a logical expression like 'b1 && !(b2 || b3) ^ b4 && b5'
|
||||
//
|
||||
// Date: 2023-09-03
|
||||
//
|
||||
// Author: gb
|
||||
//
|
||||
// Supporting opers: &&, ||, ^
|
||||
//
|
||||
// Priority: (&&, ^, ), (||)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class simple_logic
|
||||
{
|
||||
int oper_;
|
||||
bool not_;
|
||||
std::string expr_;
|
||||
simple_logic* l_;
|
||||
simple_logic* r_;
|
||||
|
||||
void clear(void);
|
||||
void copy(const simple_logic& r);
|
||||
void set_not(bool notv);
|
||||
bool parse_internal(const char* expr, int* end, void(*leaf)(const char*, void*), void* leaf_param);
|
||||
simple_logic* make_binary(const std::vector<simple_logic*>& eles, const std::vector<int>& opers);
|
||||
std::string to_string_internal(bool& single);
|
||||
|
||||
public:
|
||||
simple_logic();
|
||||
simple_logic(const simple_logic& r);
|
||||
~simple_logic();
|
||||
|
||||
// && == ^ > ||
|
||||
enum
|
||||
{
|
||||
LOGIC_OPER_NONE = 0,
|
||||
LOGIC_OPER_LEAF,
|
||||
LOGIC_OPER_OR,
|
||||
LOGIC_OPER_AND,
|
||||
LOGIC_OPER_XOR,
|
||||
};
|
||||
|
||||
simple_logic& operator=(const simple_logic& r);
|
||||
|
||||
public:
|
||||
bool parse(const char* expr, int *end_pos = nullptr, void(*leaf)(const char*, void*) = nullptr, void* leaf_param = nullptr); // leaf: callback for leaf notifying
|
||||
bool value(bool(*simple_expr_value)(const char*, void*), void* param);
|
||||
std::string to_expression(void);
|
||||
};
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
#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)
|
||||
{
|
||||
if (opt == nullptr)
|
||||
{
|
||||
if (fix_id)
|
||||
*fix_id = -1;
|
||||
|
||||
return &opt_0_;
|
||||
}
|
||||
|
||||
if (IS_PTR_NUMBER(opt))
|
||||
{
|
||||
int sn = (int)opt;
|
||||
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_;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
// sane_opts.h : include file for options of SANE
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sane/sane_ex.h>
|
||||
|
||||
#define FIXED_ID_BASE 0x8000
|
||||
|
||||
|
||||
class gb_json;
|
||||
|
||||
// For: option json to SANE_Option_Descriptor*, and depends logic
|
||||
//
|
||||
// NOTE: re-call method 'from_json_text' if language was changed
|
||||
class sane_opt
|
||||
{
|
||||
int fix_id_;
|
||||
int sn_;
|
||||
bool enabled_;
|
||||
|
||||
SANE_Option_Descriptor opt_desc_;
|
||||
|
||||
void clear();
|
||||
void set_opt_desc_string_value(char** buf, const char* val);
|
||||
void init_cap(gb_json* jsn);
|
||||
void init_range(gb_json* jsn);
|
||||
|
||||
public:
|
||||
sane_opt();
|
||||
~sane_opt();
|
||||
|
||||
public:
|
||||
int get_fix_id(void);
|
||||
int get_sn(void);
|
||||
SANE_Option_Descriptor* get_descriptor(void);
|
||||
const char* name(void);
|
||||
bool is_enabled(void);
|
||||
|
||||
bool from_json_text(int sn, const char* key, const char* json, void(*err_msg)(const char*) = nullptr);
|
||||
};
|
||||
|
||||
|
||||
class device_opts
|
||||
{
|
||||
std::map<int, sane_opt*> opts_;
|
||||
int opt_cnt_;
|
||||
SANE_Option_Descriptor opt_0_;
|
||||
|
||||
|
||||
void clear(void);
|
||||
bool add_or_replace_opt(int sn, const char* name, const char* jsn_text, void(*err_msg)(const char*));
|
||||
|
||||
public:
|
||||
device_opts();
|
||||
~device_opts();
|
||||
|
||||
public:
|
||||
bool init_from(const char* jsn_text/*all options*/, void(*err_msg)(const char*));
|
||||
SANE_Option_Descriptor* get_opt_descriptor(const void* opt, int* fix_id = nullptr);
|
||||
int get_option_count(void);
|
||||
};
|
Loading…
Reference in New Issue