New arhitecture
This commit is contained in:
commit
4d0f93932d
|
@ -0,0 +1,375 @@
|
||||||
|
#include "async_scanner.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <usb_io.h>
|
||||||
|
#include <sane_opt_json/device_opt.h>
|
||||||
|
#include <sane/sane_ex.h>
|
||||||
|
#include <huagao/hgscanner_error.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
async_scanner::async_scanner() : usb_(nullptr), cfg_mgr_(nullptr), scan_id_(0)
|
||||||
|
{
|
||||||
|
utils::init_log(LOG_TYPE_FILE);
|
||||||
|
init();
|
||||||
|
|
||||||
|
auto bulk_handle = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* required) -> dyn_mem_ptr
|
||||||
|
{
|
||||||
|
LPPACK_BASE pack = (LPPACK_BASE)data->ptr();
|
||||||
|
|
||||||
|
if(used)
|
||||||
|
*used = data->get_rest();
|
||||||
|
|
||||||
|
return handle_bulk_cmd(pack, used, required);
|
||||||
|
};
|
||||||
|
auto on_connect = [&](bool connected) -> void
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "USB %s\n", connected ? "connected" : "dis-connected");
|
||||||
|
// if(!connected)
|
||||||
|
// stop_scan();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto user = [&](int priv) -> bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
auto on_log = [&](const char* msg) -> void
|
||||||
|
{
|
||||||
|
utils::log_info(msg, LOG_LEVEL_DEBUG);
|
||||||
|
};
|
||||||
|
cfg_mgr_ = new device_option(user, on_log);
|
||||||
|
init();
|
||||||
|
usb_ = new async_usb_gadget(bulk_handle, on_connect);
|
||||||
|
}
|
||||||
|
|
||||||
|
async_scanner::~async_scanner()
|
||||||
|
{
|
||||||
|
if(usb_)
|
||||||
|
{
|
||||||
|
usb_->stop();
|
||||||
|
usb_->release();
|
||||||
|
}
|
||||||
|
if(cfg_mgr_)
|
||||||
|
{
|
||||||
|
cfg_mgr_->clear();
|
||||||
|
delete cfg_mgr_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_mem_ptr async_scanner::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
LPPACK_BASE pk = nullptr;
|
||||||
|
size_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
|
||||||
|
if(pack->size != base_head_size)
|
||||||
|
{
|
||||||
|
if(used)
|
||||||
|
{
|
||||||
|
utils::log_mem_info("Invalid packet", (uint8_t*)pack, *used);
|
||||||
|
}
|
||||||
|
reply = dyn_mem::memory(base_head_size);
|
||||||
|
LPPACK_BASE p = (LPPACK_BASE)reply->ptr();
|
||||||
|
BASE_PACKET_REPLY(*p, PACK_CMD_INVALID, pack->pack_id, pack->cmd);
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pack->cmd)
|
||||||
|
{
|
||||||
|
case PACK_CMD_SYNC:
|
||||||
|
reply = handle_simple_roger(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_SETTING_GET_CUR:
|
||||||
|
reply = handle_get_opt_value(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_SETTING_GET:
|
||||||
|
reply = handle_get_opt_all(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_SETTING_SET:
|
||||||
|
reply = handle_set_opt(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_FILE_WRITE_REQ:
|
||||||
|
reply = handle_file_receive(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_FILE_READ_REQ:
|
||||||
|
reply = handle_file_send(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_SCAN_START:
|
||||||
|
reply = handle_scan_start(pack, used, required);
|
||||||
|
break;
|
||||||
|
case PACK_CMD_SCAN_STOP:
|
||||||
|
reply = handle_scan_stop(pack, used, required);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(used)
|
||||||
|
{
|
||||||
|
utils::log_mem_info("Unsupported command packet", (uint8_t*)pack, *used);
|
||||||
|
}
|
||||||
|
reply = dyn_mem::memory(base_head_size);
|
||||||
|
LPPACK_BASE p = (LPPACK_BASE)reply->ptr();
|
||||||
|
BASE_PACKET_REPLY(*p, pack->cmd + 1, pack->pack_id, EINVAL);
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
void async_scanner::init(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_mem_ptr async_scanner::handle_simple_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
||||||
|
LPPACK_BASE pk = (LPPACK_BASE)reply->ptr();
|
||||||
|
|
||||||
|
*used = base_head_size;
|
||||||
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, 0);
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_get_opt_value(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
LPPACK_BASE pk = nullptr;
|
||||||
|
|
||||||
|
if(*used < base_head_size + pack->payload_len)
|
||||||
|
{
|
||||||
|
*used = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string val(cfg_mgr_->get_option_value(pack->payload, SANE_ACTION_GET_VALUE));
|
||||||
|
uint32_t err = val.empty() ? SCANNER_ERR_NO_DATA : SCANNER_ERR_OK;
|
||||||
|
LPCFGVAL cfg = nullptr;
|
||||||
|
|
||||||
|
reply = dyn_mem::memory(base_head_size + sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1);
|
||||||
|
pk = (LPPACK_BASE)reply->ptr();
|
||||||
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err);
|
||||||
|
cfg = (LPCFGVAL)pk->payload;
|
||||||
|
cfg->val_size = val.length();
|
||||||
|
cfg->val_off = 0;
|
||||||
|
cfg->name_off = val.length() + 1;
|
||||||
|
pk->payload_len = sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1;
|
||||||
|
memcpy(cfg->data, val.c_str(), val.length());
|
||||||
|
strcpy(cfg->data + cfg->name_off, pack->payload);
|
||||||
|
reply->set_len(base_head_size + pk->payload_len);
|
||||||
|
*used = base_head_size + pack->payload_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_get_opt_all(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
LPPACK_BASE pk = nullptr;
|
||||||
|
|
||||||
|
*used = base_head_size;
|
||||||
|
{
|
||||||
|
std::string val(cfg_mgr_->get_option_value(nullptr, SANE_ACTION_GET_ENTIRE_JSON));
|
||||||
|
uint32_t err = 0;
|
||||||
|
|
||||||
|
reply = dyn_mem::memory(base_head_size + val.length() + 1);
|
||||||
|
pk = (LPPACK_BASE)reply->ptr();
|
||||||
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err);
|
||||||
|
strcpy(pk->payload, val.c_str());
|
||||||
|
pk->payload_len = val.length() + 1;
|
||||||
|
reply->set_len(base_head_size + val.length() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{ uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
LPPACK_BASE pk = nullptr;
|
||||||
|
|
||||||
|
if (*used < base_head_size + pack->payload_len)
|
||||||
|
*used = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LPCFGVAL cfg = (LPCFGVAL)pack->payload,
|
||||||
|
cfg_ret = nullptr;
|
||||||
|
std::string name(cfg->data + cfg->name_off);
|
||||||
|
size_t l = base_head_size + sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1, val_size = cfg->val_size;
|
||||||
|
int32_t err = 0;
|
||||||
|
uint32_t after = 0;
|
||||||
|
|
||||||
|
reply = dyn_mem::memory(l);
|
||||||
|
pk = (LPPACK_BASE)reply->ptr();
|
||||||
|
cfg_ret = (LPCFGVAL)pk->payload;
|
||||||
|
cfg_ret->name_off = 0;
|
||||||
|
strcpy(cfg_ret->data + cfg_ret->name_off, name.c_str());
|
||||||
|
cfg_ret->val_off = name.length() + 1;
|
||||||
|
memcpy(cfg_ret->data + cfg_ret->val_off, cfg->data + cfg->val_off, cfg->val_size);
|
||||||
|
cfg_ret->val_size = cfg->val_size;
|
||||||
|
cfg_ret->max_size = cfg->max_size;
|
||||||
|
cfg_ret->type = cfg->type;
|
||||||
|
err = cfg_mgr_->update_data(cfg->data + cfg->name_off, cfg_ret->data + cfg_ret->val_off);
|
||||||
|
cfg_ret->after_do = after;
|
||||||
|
cfg_ret->val_size = val_size;
|
||||||
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err);
|
||||||
|
pk->payload_len = sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1;
|
||||||
|
reply->set_len(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
LPPACK_BASE pk = nullptr;
|
||||||
|
|
||||||
|
if(*used < pack->payload_len + pack->size)
|
||||||
|
{
|
||||||
|
*used = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LPTXFILE pfi = (LPTXFILE)pack->payload;
|
||||||
|
std::string path(pfi->path);
|
||||||
|
int err = 0;
|
||||||
|
file_saver *saver = new file_saver();
|
||||||
|
|
||||||
|
err = saver->open(path.c_str(), pfi->size);
|
||||||
|
reply = dyn_mem::memory(base_head_size);
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
|
||||||
|
*used = base_head_size + pack->payload_len;
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
saver->release();
|
||||||
|
saver = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
saver->set_packet_param(pack->cmd, pack->pack_id);
|
||||||
|
}
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "receive file (%u bytes): %s = %d\n", pfi->size, path.c_str(), err);
|
||||||
|
*required = dynamic_cast<packet_data_base_ptr>(saver);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
||||||
|
LPPACK_BASE pk = (LPPACK_BASE)reply->ptr();
|
||||||
|
|
||||||
|
if(*used < pack->payload_len + pack->size)
|
||||||
|
{
|
||||||
|
*used = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LPTXFILE pfi = (LPTXFILE)pack->payload;
|
||||||
|
std::string path(pfi->path);
|
||||||
|
int err = 0;
|
||||||
|
file_reader *reader = new file_reader();
|
||||||
|
|
||||||
|
err = reader->open(path.c_str());
|
||||||
|
reply = dyn_mem::memory(base_head_size + sizeof(TXFILE));
|
||||||
|
reply->set_len(base_head_size + sizeof(TXFILE));
|
||||||
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
|
||||||
|
*used = base_head_size + pack->payload_len;
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "To send file '%s' with %u bytes = %d\n", path.c_str(), reader->get_rest(), err);
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
reader->release();
|
||||||
|
reader = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE);
|
||||||
|
((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest();
|
||||||
|
reader->set_packet_param(pack->cmd, pack->pack_id);
|
||||||
|
}
|
||||||
|
*required = dynamic_cast<packet_data_base_ptr>(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
if(!used)
|
||||||
|
{
|
||||||
|
reply_start_ = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
||||||
|
|
||||||
|
img_cnt_ = 0;
|
||||||
|
scan_id_ = pack->pack_id;
|
||||||
|
scan_err_ = 0;
|
||||||
|
reply_start_ = false;
|
||||||
|
|
||||||
|
*used = base_head_size;
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
// scan_err_ = capture_->start();
|
||||||
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, scan_err_);
|
||||||
|
*used |= INT32_MAX + 1;
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "Received command Stop-Scan.\n");
|
||||||
|
// err = capture_->stop();
|
||||||
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
*used = base_head_size;
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_scanner::handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
||||||
|
{
|
||||||
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
||||||
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
||||||
|
LPPACK_BASE pk = (LPPACK_BASE)reply->ptr();
|
||||||
|
|
||||||
|
*used = base_head_size + pack->payload_len;
|
||||||
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, EINVAL);
|
||||||
|
reply->set_len(base_head_size);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t async_scanner::stop(void)
|
||||||
|
{
|
||||||
|
if(usb_)
|
||||||
|
{
|
||||||
|
usb_->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <functional>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <base/utils.h>
|
||||||
|
#include <base/data.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class async_usb_gadget;
|
||||||
|
class device_option;
|
||||||
|
class image_capture;
|
||||||
|
class img_processor;
|
||||||
|
class gb_json;
|
||||||
|
|
||||||
|
class async_scanner : public refer
|
||||||
|
{
|
||||||
|
async_usb_gadget *usb_;
|
||||||
|
device_option *cfg_mgr_;
|
||||||
|
|
||||||
|
MUTEX locker_;
|
||||||
|
uint32_t img_cnt_;
|
||||||
|
uint32_t scan_id_;
|
||||||
|
uint32_t scan_err_;
|
||||||
|
volatile bool reply_start_;
|
||||||
|
|
||||||
|
dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
void init(void);
|
||||||
|
|
||||||
|
dyn_mem_ptr handle_simple_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_get_opt_value(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_get_opt_all(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
dyn_mem_ptr handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required);
|
||||||
|
|
||||||
|
public:
|
||||||
|
async_scanner();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~async_scanner();
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t stop(void);
|
||||||
|
};
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "async_scanner.h"
|
||||||
|
|
||||||
|
#define BUF_LEN_FOR_PID 64
|
||||||
|
|
||||||
|
|
||||||
|
static void sigHandler(int sig)
|
||||||
|
{
|
||||||
|
// if (sig == SIGINT || sig == SIGTERM)
|
||||||
|
// remove(MY_PID_FILE);
|
||||||
|
printf("exit now for signal: %d\n", sig);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
/* Ctrl + C */
|
||||||
|
if (signal(SIGINT, sigHandler) == SIG_ERR)
|
||||||
|
{
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kill pid / killall name */
|
||||||
|
if (signal(SIGTERM, sigHandler) == SIG_ERR)
|
||||||
|
{
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
async_scanner *scanner = new async_scanner();
|
||||||
|
|
||||||
|
while(1) {std::this_thread::sleep_for(std::chrono::milliseconds(2));}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
add_rules("mode.debug", "mode.release")
|
||||||
|
|
||||||
|
target("hgscanner")
|
||||||
|
set_kind("binary")
|
||||||
|
add_syslinks("pthread", "dl")
|
||||||
|
add_includedirs("../sdk", "../usb")
|
||||||
|
add_files("*.cpp", "../sdk/base/*.c*", "../sdk/imgprc/*.c*", "../sdk/json/*.c*", "../sdk/sane_opt_json/*.c*")
|
||||||
|
--add_deps("gusb", "applog")
|
||||||
|
--add_rules("utils.bin2c",{linewidth = 32,extension = {".bin"}})
|
||||||
|
--add_files("table.bin")
|
||||||
|
add_packages("sdk")
|
||||||
|
add_deps("usb")
|
|
@ -0,0 +1,473 @@
|
||||||
|
#include "data.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
#else
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
packet_data_base::packet_data_base() : pack_cmd_(0), pack_id_(0)
|
||||||
|
, progress_notify_(PROGRESS_NOTIFYER()), user_data_(nullptr)
|
||||||
|
{}
|
||||||
|
packet_data_base::~packet_data_base()
|
||||||
|
{}
|
||||||
|
|
||||||
|
int packet_data_base::notify_progress(uint64_t total, uint64_t cur_size, uint32_t err)
|
||||||
|
{
|
||||||
|
if (progress_notify_)
|
||||||
|
progress_notify_(total, cur_size, err, user_data_);
|
||||||
|
else
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void packet_data_base::set_packet_param(uint32_t cmd, uint32_t id)
|
||||||
|
{
|
||||||
|
pack_cmd_ = cmd;
|
||||||
|
pack_id_ = id;
|
||||||
|
}
|
||||||
|
int packet_data_base::get_packet_command(void)
|
||||||
|
{
|
||||||
|
return pack_cmd_;
|
||||||
|
}
|
||||||
|
int packet_data_base::get_packet_id(void)
|
||||||
|
{
|
||||||
|
return pack_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void packet_data_base::set_progress_notify(PROGRESS_NOTIFYER notify, void* param)
|
||||||
|
{
|
||||||
|
progress_notify_ = notify;
|
||||||
|
user_data_ = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
data_holder::data_holder()
|
||||||
|
{}
|
||||||
|
data_holder::~data_holder()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
mem_holder::mem_holder(size_t size) : space_(size)
|
||||||
|
{
|
||||||
|
buf_ = (uint8_t*)malloc(size);
|
||||||
|
if (buf_)
|
||||||
|
memset(buf_, 0, size);
|
||||||
|
}
|
||||||
|
mem_holder::~mem_holder()
|
||||||
|
{
|
||||||
|
if (buf_)
|
||||||
|
free(buf_);
|
||||||
|
buf_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mem_holder::put_data(const void* data, uint32_t* size)
|
||||||
|
{
|
||||||
|
if (*size > space_ - wpos_)
|
||||||
|
*size = space_ - wpos_;
|
||||||
|
|
||||||
|
memcpy(buf_ + wpos_, data, *size);
|
||||||
|
wpos_ += *size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool mem_holder::is_complete(void)
|
||||||
|
{
|
||||||
|
return wpos_ >= space_;
|
||||||
|
}
|
||||||
|
uint32_t mem_holder::get_required(void)
|
||||||
|
{
|
||||||
|
if (wpos_ >= space_)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return space_ - wpos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mem_holder::data_length(void)
|
||||||
|
{
|
||||||
|
return wpos_;
|
||||||
|
}
|
||||||
|
uint8_t* mem_holder::data(void)
|
||||||
|
{
|
||||||
|
return buf_;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
empty_holer::empty_holer(uint64_t size) : size_(size), put_(0)
|
||||||
|
{}
|
||||||
|
empty_holer::~empty_holer()
|
||||||
|
{}
|
||||||
|
|
||||||
|
int empty_holer::put_data(const void* data, uint32_t* size)
|
||||||
|
{
|
||||||
|
if (*size >= size_ - put_)
|
||||||
|
{
|
||||||
|
*size -= size_ - put_;
|
||||||
|
put_ = size_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
put_ += *size;
|
||||||
|
}
|
||||||
|
notify_progress(size_, put_, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool empty_holer::is_complete(void)
|
||||||
|
{
|
||||||
|
return size_ == put_;
|
||||||
|
}
|
||||||
|
uint32_t empty_holer::get_required(void)
|
||||||
|
{
|
||||||
|
return size_ - put_;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
file_saver::file_saver(void) : size_(0), wrote_(0), path_(""), check_(""), dst_(nullptr), pack_cmd_(0), pack_id_(0)
|
||||||
|
{}
|
||||||
|
file_saver::~file_saver()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_saver::close(void)
|
||||||
|
{
|
||||||
|
if(dst_)
|
||||||
|
fclose(dst_);
|
||||||
|
dst_ = nullptr;
|
||||||
|
|
||||||
|
size_ = wrote_ = pack_cmd_ = pack_id_ = 0;
|
||||||
|
path_ = check_ = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int file_saver::open(const char* path, uint64_t size, const char* check)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
close();
|
||||||
|
dst_ = fopen(path, "wb");
|
||||||
|
if(dst_)
|
||||||
|
{
|
||||||
|
unsigned long long space = 0;
|
||||||
|
|
||||||
|
err = utils::get_disk_space(path, nullptr, &space, nullptr);
|
||||||
|
if (err || space < size * 1.5)
|
||||||
|
{
|
||||||
|
fclose(dst_);
|
||||||
|
dst_ = nullptr;
|
||||||
|
remove(path);
|
||||||
|
if (err == 0)
|
||||||
|
err = ENOSPC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path_ = path;
|
||||||
|
size_ = size;
|
||||||
|
check_ = check ? check : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int file_saver::put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/)
|
||||||
|
{
|
||||||
|
if(!dst_)
|
||||||
|
return ENOENT;
|
||||||
|
|
||||||
|
int w = *size > size_ - wrote_ ? size_ - wrote_ : *size,
|
||||||
|
real_w = fwrite(data, 1, w, dst_), // should handle error here !
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
*size = real_w;
|
||||||
|
wrote_ += real_w;
|
||||||
|
if(wrote_ >= size_)
|
||||||
|
{
|
||||||
|
fclose(dst_);
|
||||||
|
dst_ = nullptr;
|
||||||
|
}
|
||||||
|
else if (real_w < w) // what happens ?
|
||||||
|
{
|
||||||
|
err = ferror(dst_);
|
||||||
|
}
|
||||||
|
notify_progress(size_, wrote_, err);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool file_saver::is_complete(void)
|
||||||
|
{
|
||||||
|
return wrote_ >= size_;
|
||||||
|
}
|
||||||
|
uint32_t file_saver::get_required(void)
|
||||||
|
{
|
||||||
|
return size_ - wrote_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
data_source::data_source()
|
||||||
|
{}
|
||||||
|
data_source::~data_source()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// dyn_mem
|
||||||
|
uint64_t dyn_mem::mem_used_bytes_ = 0;
|
||||||
|
MUTEX dyn_mem::mem_lock_;
|
||||||
|
|
||||||
|
dyn_mem::dyn_mem(size_t size) : buf_(nullptr), len_(0), space_(ALIGN_TO(size, 16))
|
||||||
|
{
|
||||||
|
buf_ = (uint8_t*)malloc(space_);
|
||||||
|
if (buf_)
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(dyn_mem::mem_lock_);
|
||||||
|
dyn_mem::mem_used_bytes_ += space_;
|
||||||
|
memset(buf_, 0, space_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dyn_mem::dyn_mem(void* buf, size_t size) : buf_((uint8_t*)buf), space_(size), len_(size)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_mem::~dyn_mem()
|
||||||
|
{
|
||||||
|
if (buf_)
|
||||||
|
{
|
||||||
|
free(buf_);
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(dyn_mem::mem_lock_);
|
||||||
|
dyn_mem::mem_used_bytes_ -= space_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dyn_mem::mem_used(void)
|
||||||
|
{
|
||||||
|
return dyn_mem::mem_used_bytes_;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr dyn_mem::memory(size_t size)
|
||||||
|
{
|
||||||
|
return new dyn_mem(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dyn_mem::space(void)
|
||||||
|
{
|
||||||
|
return space_;
|
||||||
|
}
|
||||||
|
bool dyn_mem::set_len(size_t len)
|
||||||
|
{
|
||||||
|
if (len > space_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
len_ = len;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int dyn_mem::put(const void* data, int len)
|
||||||
|
{
|
||||||
|
if (len + len_ > space_)
|
||||||
|
len = space_ - len;
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
memcpy(buf_ + len_, data, len);
|
||||||
|
len_ += len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
len = 0;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
void* dyn_mem::detach(size_t* size)
|
||||||
|
{
|
||||||
|
void* buf = buf_;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = space_;
|
||||||
|
space_ = len_ = 0;
|
||||||
|
buf_ = nullptr;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dyn_mem::used(size_t len)
|
||||||
|
{
|
||||||
|
if (len >= len_)
|
||||||
|
{
|
||||||
|
len_ = 0;
|
||||||
|
}
|
||||||
|
else if (len)
|
||||||
|
{
|
||||||
|
memcpy(buf_, buf_ + len, len_ - len);
|
||||||
|
len_ -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len_;
|
||||||
|
}
|
||||||
|
dyn_mem& dyn_mem::operator+=(dyn_mem& r)
|
||||||
|
{
|
||||||
|
if (len_ + r.get_rest() > space_)
|
||||||
|
{
|
||||||
|
size_t size = ALIGN_TO(len_ + r.get_rest(), 16);
|
||||||
|
uint8_t* buf = (uint8_t*)malloc(size);
|
||||||
|
memcpy(buf, buf_, len_);
|
||||||
|
free(buf_);
|
||||||
|
buf_ = buf;
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(dyn_mem::mem_lock_);
|
||||||
|
dyn_mem::mem_used_bytes_ += size - space_;
|
||||||
|
}
|
||||||
|
space_ = size;
|
||||||
|
}
|
||||||
|
memcpy(buf_ + len_, r.buf_, r.get_rest());
|
||||||
|
len_ += r.get_rest();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dyn_mem::is_memory_block(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint32_t dyn_mem::get_rest(void)
|
||||||
|
{
|
||||||
|
return len_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return true
|
||||||
|
uint8_t* dyn_mem::ptr(void)
|
||||||
|
{
|
||||||
|
return buf_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return false
|
||||||
|
int dyn_mem::fetch_data(void* buf, uint32_t* size)
|
||||||
|
{
|
||||||
|
if (*size >= len_)
|
||||||
|
{
|
||||||
|
memcpy(buf, buf_, len_);
|
||||||
|
*size = len_;
|
||||||
|
len_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(buf, buf_, *size);
|
||||||
|
used(*size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
file_reader::file_reader() : len_(0), src_(nullptr), path_(""), consume_(0)
|
||||||
|
{}
|
||||||
|
file_reader::~file_reader()
|
||||||
|
{
|
||||||
|
if(src_)
|
||||||
|
fclose(src_);
|
||||||
|
}
|
||||||
|
|
||||||
|
int file_reader::open(const char* file)
|
||||||
|
{
|
||||||
|
if(src_)
|
||||||
|
fclose(src_);
|
||||||
|
|
||||||
|
src_ = fopen(file, "rb");
|
||||||
|
if(!src_)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
FSEEK(src_, 0, SEEK_END);
|
||||||
|
len_ = FTELL(src_);
|
||||||
|
FSEEK(src_, 0, SEEK_SET);
|
||||||
|
path_ = file;
|
||||||
|
consume_ = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int file_reader::attach(FILE* f)
|
||||||
|
{
|
||||||
|
if (src_)
|
||||||
|
{
|
||||||
|
fclose(src_);
|
||||||
|
src_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t cur = FTELL(f);
|
||||||
|
|
||||||
|
FSEEK(f, 0, SEEK_END);
|
||||||
|
len_ = FTELL(f);
|
||||||
|
FSEEK(f, cur, SEEK_SET);
|
||||||
|
if (len_ <= cur)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
src_ = f;
|
||||||
|
len_ -= cur;
|
||||||
|
consume_ = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FILE* file_reader::detach(void)
|
||||||
|
{
|
||||||
|
FILE* ret = src_;
|
||||||
|
|
||||||
|
src_ = nullptr;
|
||||||
|
len_ = 0;
|
||||||
|
path_ = "";
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_reader::is_memory_block(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t file_reader::get_rest(void)
|
||||||
|
{
|
||||||
|
return len_ - consume_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return true
|
||||||
|
uint8_t* file_reader::ptr(void)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return false
|
||||||
|
int file_reader::fetch_data(void* buf, uint32_t* size)
|
||||||
|
{
|
||||||
|
if (!src_)
|
||||||
|
return ENODATA;
|
||||||
|
|
||||||
|
size_t r = fread(buf, 1, *size, src_); // fix me if ERROR occurs !!!
|
||||||
|
|
||||||
|
consume_ += r;
|
||||||
|
*size = r;
|
||||||
|
if (consume_ >= len_)
|
||||||
|
{
|
||||||
|
fclose(src_);
|
||||||
|
src_ = nullptr;
|
||||||
|
}
|
||||||
|
notify_progress(len_, consume_, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,260 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Objects IO
|
||||||
|
//
|
||||||
|
// created on 2023-03-10
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define CLS_PTR(cls) typedef cls* cls##_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
/* packet parameter keeper, parameter of corresponding packet
|
||||||
|
*/
|
||||||
|
#define PROGRESS_NOTIFYER std::function<int(uint64_t/*total*/, uint64_t/*cur-size*/, uint32_t/*err*/, void* /*user data*/)>
|
||||||
|
|
||||||
|
class packet_data_base : public refer
|
||||||
|
{
|
||||||
|
PROGRESS_NOTIFYER progress_notify_;
|
||||||
|
void* user_data_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t pack_cmd_;
|
||||||
|
uint32_t pack_id_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
packet_data_base();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~packet_data_base();
|
||||||
|
int notify_progress(uint64_t total, uint64_t cur_size, uint32_t err);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_packet_param(uint32_t cmd, uint32_t id);
|
||||||
|
int get_packet_command(void);
|
||||||
|
int get_packet_id(void);
|
||||||
|
|
||||||
|
void set_progress_notify(PROGRESS_NOTIFYER notify = PROGRESS_NOTIFYER(), void* param = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
/* data_holder, used when data is also required for a certain packet
|
||||||
|
*/
|
||||||
|
class data_holder : public packet_data_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
data_holder();
|
||||||
|
protected:
|
||||||
|
virtual ~data_holder();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) = 0; // return error code
|
||||||
|
virtual bool is_complete(void) = 0;
|
||||||
|
virtual uint32_t get_required(void) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class mem_holder : public data_holder
|
||||||
|
{
|
||||||
|
uint8_t* buf_ = nullptr;
|
||||||
|
size_t space_ = 0;
|
||||||
|
size_t wpos_ = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
mem_holder(size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~mem_holder();
|
||||||
|
|
||||||
|
// data_holder
|
||||||
|
public:
|
||||||
|
virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override; // return error code
|
||||||
|
virtual bool is_complete(void) override;
|
||||||
|
virtual uint32_t get_required(void) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
size_t data_length(void);
|
||||||
|
uint8_t* data(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
class empty_holer : public data_holder
|
||||||
|
{
|
||||||
|
uint64_t size_;
|
||||||
|
uint64_t put_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
empty_holer(uint64_t size);
|
||||||
|
protected:
|
||||||
|
~empty_holer();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override; // return error code
|
||||||
|
virtual bool is_complete(void) override;
|
||||||
|
virtual uint32_t get_required(void) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class file_saver : public data_holder
|
||||||
|
{
|
||||||
|
uint64_t size_;
|
||||||
|
uint64_t wrote_;
|
||||||
|
std::string path_;
|
||||||
|
std::string check_;
|
||||||
|
FILE *dst_;
|
||||||
|
uint32_t pack_cmd_;
|
||||||
|
uint32_t pack_id_;
|
||||||
|
|
||||||
|
void close(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
file_saver(void);
|
||||||
|
protected:
|
||||||
|
~file_saver();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int open(const char* path, uint64_t size, const char* check = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override;
|
||||||
|
virtual bool is_complete(void) override;
|
||||||
|
virtual uint32_t get_required(void) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
/* data_source, can be a memory block or STREAM object
|
||||||
|
*/
|
||||||
|
class data_source : public packet_data_base
|
||||||
|
{
|
||||||
|
uint32_t pack_cmd_;
|
||||||
|
uint32_t pack_id_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
data_source();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~data_source();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_memory_block(void) = 0;
|
||||||
|
virtual uint32_t get_rest(void) = 0;
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return true
|
||||||
|
virtual uint8_t* ptr(void) = 0;
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return false. return error code
|
||||||
|
virtual int fetch_data(void* buf, uint32_t* size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class dyn_mem : public data_source
|
||||||
|
{
|
||||||
|
uint8_t* buf_; // data buf
|
||||||
|
size_t space_; // occupy space in bytes
|
||||||
|
size_t len_; // data length in bytes
|
||||||
|
|
||||||
|
static MUTEX mem_lock_;
|
||||||
|
static uint64_t mem_used_bytes_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
dyn_mem(size_t size);
|
||||||
|
dyn_mem(void* buf, size_t size);
|
||||||
|
|
||||||
|
static uint64_t mem_used(void);
|
||||||
|
static dyn_mem* memory(size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~dyn_mem();
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t space(void);
|
||||||
|
bool set_len(size_t len);
|
||||||
|
int put(const void* data, int len);
|
||||||
|
void* detach(size_t* size); // for constructed from dyn_mem(void* buf, size_t size)
|
||||||
|
|
||||||
|
size_t used(size_t len); // used len bytes content, move following data to head and set data length, return rest data length
|
||||||
|
dyn_mem& operator+=(dyn_mem& r);
|
||||||
|
|
||||||
|
// data_source
|
||||||
|
public:
|
||||||
|
virtual bool is_memory_block(void) override;
|
||||||
|
virtual uint32_t get_rest(void) override;
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return true
|
||||||
|
virtual uint8_t* ptr(void) override;
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return false
|
||||||
|
virtual int fetch_data(void* buf, uint32_t* size) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class file_reader : public data_source
|
||||||
|
{
|
||||||
|
size_t len_;
|
||||||
|
size_t consume_;
|
||||||
|
FILE *src_;
|
||||||
|
std::string path_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
file_reader();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~file_reader();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int open(const char* file);
|
||||||
|
int attach(FILE* f);
|
||||||
|
FILE* detach(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_memory_block(void) override;
|
||||||
|
virtual uint32_t get_rest(void) override;
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return true
|
||||||
|
virtual uint8_t* ptr(void) override;
|
||||||
|
|
||||||
|
// following API valid when is_memory_block() return false
|
||||||
|
virtual int fetch_data(void* buf, uint32_t* size) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
CLS_PTR(packet_data_base);
|
||||||
|
CLS_PTR(data_holder);
|
||||||
|
CLS_PTR(mem_holder);
|
||||||
|
CLS_PTR(data_source);
|
||||||
|
CLS_PTR(dyn_mem);
|
||||||
|
CLS_PTR(file_reader);
|
||||||
|
|
||||||
|
|
||||||
|
// callback proto
|
||||||
|
//
|
||||||
|
// parameters: usb_functionfs_event* - the function event ptr
|
||||||
|
//
|
||||||
|
// dyn_mem_ptr - the packet buffer, read-only
|
||||||
|
//
|
||||||
|
// uint32_t* - to return how many data in bytes the handler consumed, the most high bit is to indicate whether should notify the returned packet has sent
|
||||||
|
//
|
||||||
|
// normally, the value should be sizeof(PACK_BASE) + PACK_BASE::payload_len, i.e. the handler consume all data of an entire packet
|
||||||
|
//
|
||||||
|
// when invalid packet, suggest use the entire data
|
||||||
|
//
|
||||||
|
// packet_data_base_ptr* - return data_holder or data_source or nullptr £¨The number of bytes required for this packet, 0 is over for this packet£©
|
||||||
|
//
|
||||||
|
// data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file'
|
||||||
|
//
|
||||||
|
// data_source: the reply content may be a large data (a large file content)
|
||||||
|
//
|
||||||
|
// return value of all routines is the reply packet, nullptr if the packet need not reply
|
||||||
|
//
|
||||||
|
// NOTE: when parameter uint32_t* and packet_data_base_ptr* both are nullptr, it is notifying the command reply packet has sent, callback should return nullptr only
|
||||||
|
//
|
||||||
|
#define FUNCTION_PROTO_PARAMETERS dyn_mem_ptr, uint32_t*, packet_data_base_ptr*
|
||||||
|
#define FUNCTION_PROTO_COMMAND_HANDLE dyn_mem_ptr(FUNCTION_PROTO_PARAMETERS)
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
#include "encrypt.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// exporting api:
|
||||||
|
dyn_mem_ptr packet_encrypt(dyn_mem_ptr packet, uint32_t cmd_type, uint32_t type, uint8_t enc_data)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr ret = packet;
|
||||||
|
LPPACK_BASE pack = (LPPACK_BASE)packet->ptr();
|
||||||
|
|
||||||
|
ret->add_ref();
|
||||||
|
if (cmd_type == ENCRYPT_CMD_XOR_PID)
|
||||||
|
pack->cmd ^= pack->pack_id;
|
||||||
|
else if (cmd_type == ENCRYPT_CMD_ADD_PID)
|
||||||
|
pack->cmd += pack->pack_id;
|
||||||
|
else if (cmd_type == ENCRYPT_CMD_SUB_PID)
|
||||||
|
pack->cmd -= pack->pack_id;
|
||||||
|
|
||||||
|
pack->enc_cmd = cmd_type;
|
||||||
|
if (type != ENCRYPT_NONE)
|
||||||
|
{
|
||||||
|
std::string cont("");
|
||||||
|
if (type == ENCRYPT_BASE64)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (type == ENCRYPT_AES)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (type == ENCRYPT_ZIP)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cont.length())
|
||||||
|
{
|
||||||
|
// space is enough ?
|
||||||
|
if (cont.length() + sizeof(PACK_BASE) > packet->space())
|
||||||
|
{
|
||||||
|
ret->release();
|
||||||
|
ret = dyn_mem::memory(sizeof(PACK_BASE) + cont.length());
|
||||||
|
memcpy(ret->ptr(), packet->ptr(), sizeof(PACK_BASE));
|
||||||
|
pack = (LPPACK_BASE)ret->ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy cipher text and set encrypt type ...
|
||||||
|
memcpy(pack->payload, cont.c_str(), cont.length());
|
||||||
|
ret->set_len(sizeof(PACK_BASE) + cont.length());
|
||||||
|
pack->payload_len = cont.length();
|
||||||
|
pack->encrypt = type;
|
||||||
|
pack->enc_data = enc_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr packet_decrypt(dyn_mem_ptr packet)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr ret = packet;
|
||||||
|
LPPACK_BASE pack = (LPPACK_BASE)packet->ptr();
|
||||||
|
|
||||||
|
ret->add_ref();
|
||||||
|
if (pack->enc_cmd == ENCRYPT_CMD_XOR_PID)
|
||||||
|
pack->cmd ^= pack->pack_id;
|
||||||
|
else if (pack->enc_cmd == ENCRYPT_CMD_ADD_PID)
|
||||||
|
pack->cmd -= pack->pack_id;
|
||||||
|
else if (pack->enc_cmd == ENCRYPT_CMD_SUB_PID)
|
||||||
|
pack->cmd += pack->pack_id;
|
||||||
|
|
||||||
|
if (pack->encrypt != ENCRYPT_NONE && pack->payload_len && packet->get_rest() >= sizeof(PACK_BASE) + pack->payload_len)
|
||||||
|
{
|
||||||
|
std::string cont("");
|
||||||
|
if (pack->encrypt == ENCRYPT_BASE64)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pack->encrypt == ENCRYPT_AES)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pack->encrypt == ENCRYPT_ZIP)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cont.length())
|
||||||
|
{
|
||||||
|
// have out-packet data ?
|
||||||
|
if (packet->get_rest() > sizeof(PACK_BASE) + pack->payload_len)
|
||||||
|
cont += std::string(pack->payload + pack->payload_len, packet->get_rest() - (sizeof(PACK_BASE) + pack->payload_len));
|
||||||
|
|
||||||
|
// space is enough ?
|
||||||
|
if (cont.length() + sizeof(PACK_BASE) > packet->space())
|
||||||
|
{
|
||||||
|
ret->release();
|
||||||
|
ret = dyn_mem::memory(sizeof(PACK_BASE) + cont.length());
|
||||||
|
memcpy(ret->ptr(), packet->ptr(), sizeof(PACK_BASE));
|
||||||
|
pack = (LPPACK_BASE)ret->ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy plain text and set encrypt type to none ...
|
||||||
|
memcpy(pack->payload, cont.c_str(), cont.length());
|
||||||
|
ret->set_len(sizeof(PACK_BASE) + cont.length());
|
||||||
|
pack->encrypt = ENCRYPT_NONE;
|
||||||
|
pack->payload_len = cont.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Objects for encrypting/decrypting
|
||||||
|
//
|
||||||
|
// created on 2023-04-04
|
||||||
|
|
||||||
|
|
||||||
|
#include "data.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum encryptor
|
||||||
|
{
|
||||||
|
ENCRYPT_NONE = 0,
|
||||||
|
ENCRYPT_BASE64,
|
||||||
|
ENCRYPT_AES,
|
||||||
|
ENCRYPT_ZIP,
|
||||||
|
};
|
||||||
|
enum encrypt_cmd
|
||||||
|
{
|
||||||
|
ENCRYPT_CMD_NONE = 0,
|
||||||
|
ENCRYPT_CMD_XOR_PID, // cmd ^= pack_id
|
||||||
|
ENCRYPT_CMD_ADD_PID, // cmd += pack_id
|
||||||
|
ENCRYPT_CMD_SUB_PID, // cmd -= pack_id
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: encrypting & decrypting packet
|
||||||
|
//
|
||||||
|
// Parameters: packet - pointer to the base packet
|
||||||
|
//
|
||||||
|
// data - cipher/plain data
|
||||||
|
//
|
||||||
|
// size - [in]: bytes of source 'data';
|
||||||
|
//
|
||||||
|
// cmd_type - member 'cmd' encrypting method
|
||||||
|
//
|
||||||
|
// type - payload encrypting method
|
||||||
|
//
|
||||||
|
// enc_data - encrypting data for payload encrypting method
|
||||||
|
//
|
||||||
|
// Return: 'cmd' returned on origin packet, and returning value is for payload only. nullptr on failure
|
||||||
|
//
|
||||||
|
// NOTE: nullptr also returned if data was nullptr or size was ZERO
|
||||||
|
//
|
||||||
|
dyn_mem_ptr packet_encrypt(dyn_mem_ptr packet, uint32_t cmd_type = ENCRYPT_CMD_NONE, uint32_t type = ENCRYPT_NONE, uint8_t enc_data = 0);
|
||||||
|
dyn_mem_ptr packet_decrypt(dyn_mem_ptr packet);
|
|
@ -0,0 +1,243 @@
|
||||||
|
|
||||||
|
#include "ini_file.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
#define bzero(b, s) memset(b, 0, s)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
simple_ini::simple_ini()
|
||||||
|
{}
|
||||||
|
simple_ini::~simple_ini()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
std::string simple_ini::temporary_path(void)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
char path[MAX_PATH] = { 0 };
|
||||||
|
|
||||||
|
if (GetTempPathA(_countof(path) - 1, path))
|
||||||
|
{
|
||||||
|
if (path[lstrlenA(path) - 1] == '\\')
|
||||||
|
path[lstrlenA(path) - 1] = 0;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
#else
|
||||||
|
return "/tmp";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
bool simple_ini::skip_empty(char*& ptr)
|
||||||
|
{
|
||||||
|
char* p = ptr;
|
||||||
|
while(*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n')
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
return ptr > p;
|
||||||
|
}
|
||||||
|
void simple_ini::trime(char*& ptr)
|
||||||
|
{
|
||||||
|
skip_empty(ptr);
|
||||||
|
|
||||||
|
char* tail = ptr + strlen(ptr) - 1;
|
||||||
|
while (tail >= ptr)
|
||||||
|
{
|
||||||
|
if (*tail != ' ' && *tail != '\t' && *tail != '\r' && *tail != '\n')
|
||||||
|
break;
|
||||||
|
tail--;
|
||||||
|
}
|
||||||
|
tail[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int simple_ini::load(const char* local_file)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
file_ = local_file;
|
||||||
|
#else
|
||||||
|
values_.clear();
|
||||||
|
|
||||||
|
FILE* src = fopen(local_file, "rb");
|
||||||
|
if (src)
|
||||||
|
{
|
||||||
|
char line[256];
|
||||||
|
char* oper = NULL;
|
||||||
|
SECKEY sec;
|
||||||
|
|
||||||
|
bzero(line, sizeof(line));
|
||||||
|
while (fgets(line, sizeof(line) - 1, src))
|
||||||
|
{
|
||||||
|
oper = line;
|
||||||
|
simple_ini::skip_empty(oper);
|
||||||
|
if (strstr(oper, "//") == oper ||
|
||||||
|
strstr(oper, "#") == oper ||
|
||||||
|
*oper == 0)
|
||||||
|
{
|
||||||
|
bzero(line, sizeof(line));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*oper == '[')
|
||||||
|
{
|
||||||
|
oper++;
|
||||||
|
if (strstr(oper, (char*)"]"))
|
||||||
|
strstr(oper, (char*)"]")[0] = 0;
|
||||||
|
if (sec.sec != oper)
|
||||||
|
{
|
||||||
|
if (sec.vals.size())
|
||||||
|
values_.push_back(sec);
|
||||||
|
sec.vals.clear();
|
||||||
|
|
||||||
|
sec.sec = oper;
|
||||||
|
std::vector<SECKEY>::iterator it = std::find(values_.begin(), values_.end(), oper);
|
||||||
|
if (it != values_.end())
|
||||||
|
{
|
||||||
|
sec = *it;
|
||||||
|
values_.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char* v = strstr(oper, "=");
|
||||||
|
if (v)
|
||||||
|
{
|
||||||
|
*v++ = 0;
|
||||||
|
trime(oper);
|
||||||
|
if (*oper)
|
||||||
|
{
|
||||||
|
trime(v);
|
||||||
|
|
||||||
|
KEYVAL kv;
|
||||||
|
kv.key = oper;
|
||||||
|
kv.val = v;
|
||||||
|
sec.vals.push_back(kv);
|
||||||
|
std::sort(sec.vals.begin(), sec.vals.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bzero(line, sizeof(line));
|
||||||
|
}
|
||||||
|
fclose(src);
|
||||||
|
if (sec.vals.size())
|
||||||
|
values_.push_back(sec);
|
||||||
|
std::sort(values_.begin(), values_.end());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = errno;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#if !defined(WIN32) && !defined(_WIN64)
|
||||||
|
int simple_ini::save(const char* local_file)
|
||||||
|
{
|
||||||
|
FILE* dst = fopen(local_file, "wb");
|
||||||
|
if (dst)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < values_.size(); ++i)
|
||||||
|
{
|
||||||
|
std::string val(values_[i].sec);
|
||||||
|
|
||||||
|
val.insert(0, "[");
|
||||||
|
val += "]\r\n";
|
||||||
|
fwrite(val.c_str(), 1, val.length(), dst);
|
||||||
|
for (size_t j = 0; j < values_[i].vals.size(); ++j)
|
||||||
|
{
|
||||||
|
val = values_[i].vals[j].key + "=" + values_[i].vals[j].val + "\r\n";
|
||||||
|
fwrite(val.c_str(), 1, val.length(), dst);
|
||||||
|
}
|
||||||
|
val = "\r\n";
|
||||||
|
fwrite(val.c_str(), 1, val.length(), dst);
|
||||||
|
}
|
||||||
|
fclose(dst);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string simple_ini::get(const char* sec, const char* key, const char* default_val)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
char str[MAX_PATH] = { 0 };
|
||||||
|
GetPrivateProfileStringA(sec, key, default_val, str, _countof(str), file_.c_str());
|
||||||
|
|
||||||
|
return str;
|
||||||
|
#else
|
||||||
|
std::vector<SECKEY>::iterator it = std::find(values_.begin(), values_.end(), sec);
|
||||||
|
if (it == values_.end())
|
||||||
|
return default_val;
|
||||||
|
|
||||||
|
std::vector<KEYVAL>::iterator it1 = std::find(it->vals.begin(), it->vals.end(), key);
|
||||||
|
if (it1 == it->vals.end())
|
||||||
|
return default_val;
|
||||||
|
else
|
||||||
|
return it1->val;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void simple_ini::set(const char* sec, const char* key, const char* val)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
WritePrivateProfileStringA(sec, key, val, file_.c_str());
|
||||||
|
#else
|
||||||
|
std::vector<SECKEY>::iterator it = std::find(values_.begin(), values_.end(), sec);
|
||||||
|
if (it == values_.end())
|
||||||
|
{
|
||||||
|
KEYVAL kv;
|
||||||
|
SECKEY sk;
|
||||||
|
|
||||||
|
kv.key = key;
|
||||||
|
kv.val = val;
|
||||||
|
sk.sec = sec;
|
||||||
|
sk.vals.push_back(kv);
|
||||||
|
values_.push_back(sk);
|
||||||
|
std::sort(values_.begin(), values_.end());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<KEYVAL>::iterator it1 = std::find(it->vals.begin(), it->vals.end(), key);
|
||||||
|
if (it1 == it->vals.end())
|
||||||
|
{
|
||||||
|
KEYVAL kv;
|
||||||
|
|
||||||
|
kv.key = key;
|
||||||
|
kv.val = val;
|
||||||
|
it->vals.push_back(kv);
|
||||||
|
std::sort(it->vals.begin(), it->vals.end());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it1->val = val;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void simple_ini::remove(const char* sec, const char* key)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
#else
|
||||||
|
std::vector<SECKEY>::iterator it = std::find(values_.begin(), values_.end(), sec);
|
||||||
|
if (it == values_.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<KEYVAL>::iterator it1 = std::find(it->vals.begin(), it->vals.end(), key);
|
||||||
|
if (it1 != it->vals.end())
|
||||||
|
it->vals.erase(it1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void simple_ini::remove(const char* sec)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
#else
|
||||||
|
std::vector<SECKEY>::iterator it = std::find(values_.begin(), values_.end(), sec);
|
||||||
|
if (it != values_.end())
|
||||||
|
values_.erase(it);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void simple_ini::clear(void)
|
||||||
|
{
|
||||||
|
values_.clear();
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
#include <Windows.h>
|
||||||
|
#else
|
||||||
|
#include <string.h>
|
||||||
|
#define stricmp strcasecmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
class simple_ini
|
||||||
|
{
|
||||||
|
typedef struct _key_val
|
||||||
|
{
|
||||||
|
std::string key;
|
||||||
|
std::string val;
|
||||||
|
|
||||||
|
bool operator==(const char* k)
|
||||||
|
{
|
||||||
|
return key == k;
|
||||||
|
}
|
||||||
|
bool operator<(const struct _key_val& r)
|
||||||
|
{
|
||||||
|
return key.compare(r.key) < 0;
|
||||||
|
}
|
||||||
|
}KEYVAL;
|
||||||
|
typedef struct _sec_key
|
||||||
|
{
|
||||||
|
std::string sec;
|
||||||
|
std::vector<KEYVAL> vals;
|
||||||
|
bool operator==(const char* s)
|
||||||
|
{
|
||||||
|
return sec == s;
|
||||||
|
}
|
||||||
|
bool operator<(const struct _sec_key& r)
|
||||||
|
{
|
||||||
|
return sec.compare(r.sec) < 0;
|
||||||
|
}
|
||||||
|
}SECKEY;
|
||||||
|
std::vector<SECKEY> values_;
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
std::string file_;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
simple_ini();
|
||||||
|
~simple_ini();
|
||||||
|
|
||||||
|
static std::string temporary_path(void);
|
||||||
|
static bool skip_empty(char*& ptr);
|
||||||
|
static void trime(char*& ptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int load(const char* local_file);
|
||||||
|
#if !defined(WIN32) && !defined(_WIN64)
|
||||||
|
int save(const char* local_file);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string get(const char* sec, const char* key, const char* default_val = "");
|
||||||
|
void set(const char* sec, const char* key, const char* val);
|
||||||
|
void remove(const char* sec, const char* key);
|
||||||
|
void remove(const char* sec);
|
||||||
|
void clear(void);
|
||||||
|
};
|
|
@ -0,0 +1,379 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// packet structures and command
|
||||||
|
//
|
||||||
|
// created on 2022-12-06
|
||||||
|
//
|
||||||
|
#if !defined(WIN32)
|
||||||
|
#include <bits/stdint-uintn.h>
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define TEMPORARY_API
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// definitions ...
|
||||||
|
#define CONFIG_NAME_MAX_LEN 32 // max bytes of configuration name
|
||||||
|
#define FLOAT_PRECISION .000001f
|
||||||
|
#define IS_FLOAT_EQUAL(x, y) (-FLOAT_PRECISION <= (x) - (y) && (x) - (y) <= FLOAT_PRECISION)
|
||||||
|
#define MAKE_WORD(b0, b1) (((b0) & 0xff) | (((b1) << 8) & 0x0ff00))
|
||||||
|
#define MAKE_STR(str) #str
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
#define ROGER(cmd) cmd##_ROGER
|
||||||
|
#define PAIR_COMMAND(cmd) \
|
||||||
|
cmd, \
|
||||||
|
cmd##_ROGER
|
||||||
|
|
||||||
|
#define RETURN_STR_ENUM(v, e) \
|
||||||
|
if(v == e) \
|
||||||
|
return #e;
|
||||||
|
|
||||||
|
#define STRUCT_CONSTRUCTOR(st_name) \
|
||||||
|
st_name() \
|
||||||
|
{ \
|
||||||
|
memset(this, 0, sizeof(st_name));\
|
||||||
|
}
|
||||||
|
|
||||||
|
// protocol version, The first thing to do after connecting is to check whether the field is compatible !!!
|
||||||
|
#define PROTOCOL_VER MAKE_WORD(0, 1)
|
||||||
|
|
||||||
|
// NOTE: All text transmitted by pack cmd is in UTF-8 format !!!
|
||||||
|
|
||||||
|
|
||||||
|
enum ep0_req
|
||||||
|
{
|
||||||
|
USB_REQ_EP0_GET_PROTO_VER = 100, // get protocol version (PROTOCOL_VER), req = me, ind = 0, val = 0, len = 2
|
||||||
|
USB_REQ_EP0_GET_STATUS, // 获取各工作线程状态, return EP0REPLYSTATUS. req = me, ind = 0, val = 0, len = sizeof(EP0REPLYSTATUS)
|
||||||
|
USB_REQ_EP0_RESET_BULK, // 关闭并重新打开BULK端点, return error number (uint32_t). req = me, ind = 0, val = 0, len = sizeof(uint32_t)
|
||||||
|
USB_REQ_EP0_CANCEL_CMD, // 取消当前指令的继续执行(一般用于中止大数据的传输). req = me, ind = 0, val = 0, len = sizeof(uint32_t) * 2 [(uint32_t)cmd + (uint32_t)pack-id]
|
||||||
|
USB_REQ_EP0_SET_ENCRYPT, // 设置加密方式, req = me, ind = 0, val = 0, len = sizeof(PACK_BASE)
|
||||||
|
USB_REQ_EP0_SET_BULK_BUFFER, // 设置bulk缓冲区大小系数, req = me, ind = coef, val = 0, len = 0
|
||||||
|
};
|
||||||
|
enum bulk_status
|
||||||
|
{
|
||||||
|
BULK_STATUS_NOT_START = 0, // has not initialized
|
||||||
|
BULK_STATUS_IDLE, // wait IO
|
||||||
|
BULK_STATUS_IO, // in reading or writing
|
||||||
|
BULK_STATUS_ERROR, // error occurs
|
||||||
|
BULK_STATUS_RESET, // in reset(close and reopen) process
|
||||||
|
};
|
||||||
|
|
||||||
|
enum packet_cmd
|
||||||
|
{
|
||||||
|
PACK_CMD_NULL,
|
||||||
|
|
||||||
|
PAIR_COMMAND(PACK_CMD_HEART_BEAT), // notify peers you are still alive, receiver should reply the same pack
|
||||||
|
PAIR_COMMAND(PACK_CMD_INVALID), // reply when received an invalid packet
|
||||||
|
PAIR_COMMAND(PACK_CMD_SYNC),
|
||||||
|
|
||||||
|
// attributes get/set, all content in PACK_BASE::payload should be in JSON style - all readonly attributes move to readonly SANE-options on 2023-03-20
|
||||||
|
//PACK_CMD_ATTR_SYS_VER_GET = 10, // get system version on device, [in]: PACK_BASE, [out] PACK_BASE::payload - {"os":"linux", "ver":"4.4.194", ...}
|
||||||
|
//PACK_CMD_ATTR_FIRMWARE_VER_GET, // get firmware version, [in]: PACK_BASE, [out] PACK_BASE::payload - {"firmware":"G2393A1234", "CIS":"CIS-123", ...}
|
||||||
|
//PACK_CMD_ATTR_SERIAL_NUM_GET, // get device serial num, [in]: PACK_BASE, [out] PACK_BASE::payload - {"serial":"20221206001"}
|
||||||
|
//PACK_CMD_ATTR_SERIAL_NUM_SET, // set device serial num, [in]: PACK_BASE::payload - {"serial":"20221206001"}, [out] PACK_BASE
|
||||||
|
//PACK_CMD_ATTR_MAC_GET, // get mac address, [in]: PACK_BASE, [out] PACK_BASE::payload - {"mac":"12:34:56:78:9a:bc"}
|
||||||
|
//PACK_CMD_ATTR_IP_GET, // get ip address, [in]: PACK_BASE, [out] PACK_BASE::payload - {"ipv4":"192.168.1.123", "ipv6":"::1"}
|
||||||
|
//PACK_CMD_ATTR_HARDWARE_INFO_GET, // get hardwares information on device, [in]: PACK_BASE, [out] PACK_BASE::payload - {"CPU":"ARM x86", "mem":"16GB", ...}
|
||||||
|
//PACK_CMD_ATTR_HISTORY_COUNT_GET, // get history count, [in]: PACK_BASE, [out] PACK_BASE::payload - {"history-count":12345, ...}
|
||||||
|
//PACK_CMD_ATTR_ROLLER_COUNT_GET, // get roller count, [in]: PACK_BASE, [out] PACK_BASE::payload - {"roller-count":2345}
|
||||||
|
//PACK_CMD_ATTR_ROLLER_COUNT_SET, // set roller count, [in]: PACK_BASE::payload - {"roller-count":2345}, [out] PACK_BASE
|
||||||
|
|
||||||
|
// configuration get/set
|
||||||
|
PACK_CMD_STATUS_ROGER = 100, // device -> host. PACK_BASE::result -> status
|
||||||
|
PAIR_COMMAND(PACK_CMD_SETTING_GET), // get all settings supported by the device, [in]: PACK_BASE, [out]: PACK_BASE::payload - configuration JSON, see SANE-configuration format
|
||||||
|
PAIR_COMMAND(PACK_CMD_SETTING_GET_CUR), // get current value of given setting, [in]: PACK_BASE::payload - (char*)name, [out]: PACK_BASE::payload - LPCFGVAL
|
||||||
|
PAIR_COMMAND(PACK_CMD_SETTING_SET), // set value of given setting, [in]: PACK_BASE::payload - LPCFGVAL, [out]: PACK_BASE::payload - LPCFGVAL
|
||||||
|
PAIR_COMMAND(PACK_CMD_SETTING_RESTORE), // restore given settings, [in]: PACK_BASE::payload - LPCFGVAL, [out]: PACK_BASE::payload - LPCFGVAL
|
||||||
|
|
||||||
|
// scan command
|
||||||
|
PACK_CMD_SCAN_BASE = 200,
|
||||||
|
PAIR_COMMAND(PACK_CMD_SCAN_START), // start scanning, [in]: PACK_BASE, [out]: PACK_BASE
|
||||||
|
PAIR_COMMAND(PACK_CMD_SCAN_IMG), // device -> host, PACK_BASE::payload - LPPACKIMAGE
|
||||||
|
PAIR_COMMAND(PACK_CMD_SCAN_PAPER), // device -> host, ONE paper has passed through the CIS. PACK_BASE::data - index of this paper
|
||||||
|
PACK_CMD_SCAN_FINISHED_ROGER, // device -> host, PACK_BASE::data is scanner_status
|
||||||
|
PAIR_COMMAND(PACK_CMD_SCAN_STOP), // stop scanning, [in]: PACK_BASE, [out]: PACK_BASE
|
||||||
|
//PAIR_COMMAND(PACK_CMD_SCAN_IMAGE_REQ), // get image request, [in]: PACK_BASE, [out] PACK_BASE on error, or PACK_BASE::payload - LPPACKIMAGE
|
||||||
|
//PAIR_COMMAND(PACK_CMD_SCAN_STATUS), // get scanner status, [in]: PACK_BASE, [out] PACK_BASE::result is status code
|
||||||
|
|
||||||
|
// file operation
|
||||||
|
PACK_CMD_FILE_BASE = 300,
|
||||||
|
//PAIR_COMMAND(PACK_CMD_FILE_QUERY), // query file information, [in]: PACK_BASE::payload - (char*)file-path, [out] PACK_BASE::payload - LPFILEINFO
|
||||||
|
PAIR_COMMAND(PACK_CMD_FILE_READ_REQ), // read file content, [in]: PACK_BASE::payload - LPTXFILE, [out] PACK_BASE::payload - LPTXFILE
|
||||||
|
PAIR_COMMAND(PACK_CMD_FILE_WRITE_REQ), // write a file, [in]: PACK_BASE::payload - LPTXFILE, [out] PACK_BASE
|
||||||
|
PAIR_COMMAND(PACK_CMD_FILE_MOVE), // move/rename a file, [in]: PACK_BASE::payload - src\0dst\0\0, [out] PACK_BASE
|
||||||
|
PAIR_COMMAND(PACK_CMD_FILE_REMOVE), // delete a file, [in]: PACK_BASE::payload - (char*)file-path, [out] PACK_BASE
|
||||||
|
|
||||||
|
// process operation
|
||||||
|
PACK_CMD_PROCESS_BASE = 400,
|
||||||
|
PAIR_COMMAND(PACK_CMD_PROCESS_START), // start a program [in]: PACK_BASE::payload - (char*)pe\0param\0\0, [out]: PACK_BASE::payload - (uint64_t)process-id on success or PACK_BASE on failure
|
||||||
|
PAIR_COMMAND(PACK_CMD_PROCESS_STOP), // kill a process [in]: PACK_BASE::payload - (char*)process-id, [out]: PACK_BASE
|
||||||
|
PAIR_COMMAND(PACK_CMD_PROCESS_REBOOT), // reboot system, [in]: PACK_BASE, [out]: PACK_BASE
|
||||||
|
//PAIR_COMMAND(PACK_CMD_PROCESS_EXEC_RESULT), // get result of a command, [in]: PACK_BASE::payload - (char*)command string, [out]: PACK_BASE::payload - (char*)execute result. popen(), fgets ...
|
||||||
|
//PAIR_COMMAND(PACK_CMD_PROCESS_QUERY), // query process information [in]: PACK_BASE::payload - (char*)process-id(-1 for all), [out]: LPPROCINFO
|
||||||
|
|
||||||
|
PACK_CMD_TOKEN_GET = 900, // Obtain the token of the required command, [in] PACK_BASE, [out] - PACK_BASE::payload - LPOPERTOKEN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum img_cb_type
|
||||||
|
{
|
||||||
|
IMG_CB_IMAGE = 0,
|
||||||
|
IMG_CB_STATUS,
|
||||||
|
IMG_CB_STOPPED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum scanner_status
|
||||||
|
{
|
||||||
|
SCANNER_STATUS_READY = 0x10000, // status beginning, avoiding conficts with standards/system error code
|
||||||
|
SCANNER_STATUS_NOT_OPEN,
|
||||||
|
SCANNER_STATUS_LOST_CONNECT,
|
||||||
|
SCANNER_STATUS_RESET_BULK,
|
||||||
|
SCANNER_STATUS_START_SCANNING, // start ok, but scanning-thread not working
|
||||||
|
SCANNER_STATUS_SCANNING, // start ok, and scanning-thread is working
|
||||||
|
SCANNER_STATUS_SCAN_FINISHED, // not a persistance status
|
||||||
|
SCANNER_STATUS_BUSY, // doing task exclude scanning
|
||||||
|
SCANNER_STATUS_COVER_OPENNED,
|
||||||
|
SCANNER_STATUS_COVER_CLOSED,
|
||||||
|
SCANNER_STATUS_SLEEPING,
|
||||||
|
SCANNER_STATUS_WAKED_UP,
|
||||||
|
SCANNER_STATUS_COUNT_MODE,
|
||||||
|
SCANNER_STATUS_DOUBLE_FEEDED,
|
||||||
|
SCANNER_STATUS_PAPER_JAMMED,
|
||||||
|
SCANNER_STATUS_PAPER_ASKEW,
|
||||||
|
SCANNER_STATUS_FEED_FAILED,
|
||||||
|
SCANNER_STATUS_NO_PAPER,
|
||||||
|
SCANNER_STATUS_PAPER_ON,
|
||||||
|
SCANNER_STATUS_STAPLE_ON,
|
||||||
|
SCANNER_STATUS_SIZE_ERR,
|
||||||
|
SCANNER_STATUS_DOGEAR,
|
||||||
|
SCANNER_STATUS_CFG_CHANGED, // PACK_BASE::payload - LPCFGVAL
|
||||||
|
};
|
||||||
|
|
||||||
|
// option affection if value changed, see SANE_INFO_xxx
|
||||||
|
enum opt_affect
|
||||||
|
{
|
||||||
|
OPT_AFFECT_NONE = 0,
|
||||||
|
OPT_AFFECT_INEXACT = 1,
|
||||||
|
OPT_AFFECT_OTHERS = 2,
|
||||||
|
OPT_AFFECT_IMG_PARAM = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum img_format
|
||||||
|
{
|
||||||
|
IMG_FMT_UNKNOWN = 0, // unknown format
|
||||||
|
IMG_FMT_TIFF,
|
||||||
|
IMG_FMT_BMP,
|
||||||
|
IMG_FMT_JPEG,
|
||||||
|
IMG_FMT_PNG,
|
||||||
|
IMG_FMT_SVG,
|
||||||
|
IMG_FMT_WEBP,
|
||||||
|
IMG_FMT_GIF,
|
||||||
|
};
|
||||||
|
enum img_compression
|
||||||
|
{
|
||||||
|
IMG_COMPRESSION_NONE = 0,
|
||||||
|
IMG_COMPRESSION_GROUP4,
|
||||||
|
IMG_COMPRESSION_RLE4,
|
||||||
|
IMG_COMPRESSION_RLE8,
|
||||||
|
IMG_COMPRESSION_LZW,
|
||||||
|
IMG_COMPRESSION_ZIP,
|
||||||
|
};
|
||||||
|
enum img_status
|
||||||
|
{
|
||||||
|
IMG_STATUS_OK = 0, // normal
|
||||||
|
IMG_STATUS_DOUBLE = 1 << 0, // double-feeded paper
|
||||||
|
IMG_STATUS_JAM = 1 << 1, // jammed paper
|
||||||
|
IMG_STATUS_STAPLE = 1 << 2, // staples on the paper
|
||||||
|
IMG_STATUS_SIZE_ERR = 1 << 3, // size check failed
|
||||||
|
IMG_STATUS_DOGEAR = 1 << 4, // paper has dogear - common
|
||||||
|
IMG_STATUS_DOGEAR_PARTIAL = 1 << 5, // dogear - scanned partial
|
||||||
|
IMG_STATUS_BLANK = 1 << 6, // blank image
|
||||||
|
};
|
||||||
|
enum data_type
|
||||||
|
{
|
||||||
|
DATA_TYPE_BOOL = 0, // (bool*)
|
||||||
|
DATA_TYPE_INT4, // (uint32_t*)
|
||||||
|
DATA_TYPE_FLOAT, // (double*)
|
||||||
|
DATA_TYPE_STRING, // (char*) with max_len space. befor and include me, keep same with SANE_TYPE_BOOL, SANE_TYPE_xxx ...
|
||||||
|
|
||||||
|
DATA_TYPE_INT1, // (uint8_t*)
|
||||||
|
DATA_TYPE_INT2, // (uint16_t*)
|
||||||
|
DATA_TYPE_INT8, // (uint64_t*)
|
||||||
|
DATA_TYPE_CUSTOM,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum paper_side
|
||||||
|
{
|
||||||
|
PAPER_SIDE_FRONT = 0, // single side, this is front
|
||||||
|
PAPER_SIDE_BACK, // single side, this is back
|
||||||
|
PAPER_SIDE_TOP, // VERT-compound sides, and front side is at top
|
||||||
|
PAPER_SIDE_BOTTOM, // VERT-compound sides, and front side is at bottom
|
||||||
|
PAPER_SIDE_LEFT, // HORZ-compound sides, and front side is at left
|
||||||
|
PAPER_SIDE_RIGHT, // HORZ-compound sides, and front side is at right
|
||||||
|
|
||||||
|
PAPER_SIDE_DSP, // a special type
|
||||||
|
};
|
||||||
|
enum rot_angle
|
||||||
|
{
|
||||||
|
ROT_ANGLE_0 = 0,
|
||||||
|
ROT_ANGLE_90,
|
||||||
|
ROT_ANGLE_180,
|
||||||
|
ROT_ANGLE_270,
|
||||||
|
};
|
||||||
|
enum clr_channel
|
||||||
|
{
|
||||||
|
COLOR_CHANNEL_RGB = 0,
|
||||||
|
COLOR_CHANNEL_RGBA,
|
||||||
|
COLOR_CHANNEL_GRAY,
|
||||||
|
COLOR_CHANNEL_RED,
|
||||||
|
COLOR_CHANNEL_GREEN,
|
||||||
|
COLOR_CHANNEL_BLUE,
|
||||||
|
COLOR_CHANNEL_ALPHA,
|
||||||
|
};
|
||||||
|
enum color_mode
|
||||||
|
{
|
||||||
|
COLOR_MODE_BW = 0,
|
||||||
|
COLOR_MODE_GRAY,
|
||||||
|
COLOR_MODE_RGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct _ep0_reply
|
||||||
|
{
|
||||||
|
uint8_t in_status; // BULK-IN status, enum bulk_statu
|
||||||
|
uint8_t out_status; // BULK-OUT status, enum bulk_statu
|
||||||
|
uint16_t in_err; // valid if in_statu == BULK_STATU_ERROR
|
||||||
|
uint16_t out_err; // valid if out_statu == BULK_STATU_ERROR
|
||||||
|
uint16_t task_cnt; // tasks in command queue
|
||||||
|
uint32_t task_cmd; // the cmd of the task thread is doing
|
||||||
|
uint32_t task_pack_id; // packet id of the cmd
|
||||||
|
uint32_t task_required_bytes; // required byte of this packet
|
||||||
|
uint32_t packets_to_sent; // how many packets in sent queue
|
||||||
|
uint32_t bytes_to_sent; // how many bytes data is waiting for be sent in one replying packet
|
||||||
|
}EP0REPLYSTATUS, *LPEP0REPLYSTATUS;
|
||||||
|
|
||||||
|
typedef struct _pack_base // A piece of data has only one header
|
||||||
|
{
|
||||||
|
uint32_t enc_cmd : 2; // encrypting type, for 'cmd'
|
||||||
|
uint32_t encrypt : 3; // encrypting type, for payload content. the payload must cotains self-check if was encrypted packet
|
||||||
|
uint32_t enc_data : 5; // data for encrypt
|
||||||
|
uint32_t size : 6; // bytes of this structure
|
||||||
|
uint32_t cmd : 16; // packet command
|
||||||
|
uint32_t data; // simple data in command packet depends 'cmd', or error code in reply packet
|
||||||
|
uint32_t pack_id; // maintain by the initiator, the reply packet use the same id
|
||||||
|
uint32_t payload_len; // total bytes of payload of this command packet (the data in the range will sent in ONE 'write'),
|
||||||
|
// big data can be described in payload and independent communication, and this field should not include them.
|
||||||
|
// if encrypted packet, this field is the length after encrypting
|
||||||
|
char payload[0]; // payloads, according to 'cmd'
|
||||||
|
|
||||||
|
STRUCT_CONSTRUCTOR(_pack_base)
|
||||||
|
}PACK_BASE, * LPPACK_BASE;
|
||||||
|
#define BASE_PACKET_REPLY(reply, command, id, err) \
|
||||||
|
(reply).encrypt = 0; \
|
||||||
|
(reply).enc_data = 0; \
|
||||||
|
(reply).size = sizeof(reply); \
|
||||||
|
(reply).data = err; \
|
||||||
|
(reply).cmd = command; \
|
||||||
|
(reply).pack_id = id; \
|
||||||
|
(reply).payload_len = 0;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _config_val
|
||||||
|
{
|
||||||
|
uint8_t type; // same as SANE_Value_Type
|
||||||
|
uint8_t name_off; // name offset of the option in data, end with '\0'
|
||||||
|
uint8_t val_off; // option value offset in data
|
||||||
|
uint8_t after_do; // see SANE_INFO_xxx in sane.h
|
||||||
|
uint16_t val_size; // real size of value
|
||||||
|
uint16_t max_size; // max size of this option, this value has given in gb_json::size
|
||||||
|
char data[0]; // contains value and name. fetch them according name_off and val_off members.
|
||||||
|
}CFGVAL, *LPCFGVAL;
|
||||||
|
|
||||||
|
typedef struct _img_pos
|
||||||
|
{
|
||||||
|
uint64_t paper_ind : 32; // paper index in this turn/start, based ZERO. (image-collector set)
|
||||||
|
uint64_t new_img : 1; // 0 - partial data; 1 - new image data. (image-collector set)
|
||||||
|
uint64_t img_over : 1; // 0 - has data yet; 1 - END for the image. (image-collector set)
|
||||||
|
uint64_t paper_side : 3; // enum paper_side. front of paper(When scanning multiple sheets, the paper feeding side is the front side). (image-collector set)
|
||||||
|
uint64_t back_rot : 2; // back rotation angle, enum rot_angle. (image-collector set)
|
||||||
|
uint64_t channel_ind : 4; // index of color channel, enum clr_channel. (image-collector set)
|
||||||
|
uint64_t status : 7; // img_status. (image-collector set)
|
||||||
|
uint64_t split_ind : 7; // splitting order, from left to right and then top to bottom, based ZERO
|
||||||
|
uint64_t multiout_ind : 4; // index of multi-out
|
||||||
|
uint64_t reserved : 3; // reserved
|
||||||
|
|
||||||
|
STRUCT_CONSTRUCTOR(_img_pos)
|
||||||
|
}IMGPOS, * LPIMGPOS;
|
||||||
|
typedef struct _pack_img
|
||||||
|
{
|
||||||
|
IMGPOS pos; // image pos info ...
|
||||||
|
uint32_t width; // image width in pixel. (image-collector set)
|
||||||
|
uint32_t height; // image height in pixel. (image-collector set)
|
||||||
|
uint32_t resolution_x; // image horizontal reolution. (image-collector set)
|
||||||
|
uint32_t resolution_y; // image vertical reolution. (image-collector set)
|
||||||
|
uint32_t channels : 6; // image channels per pixel. (image-collector set)
|
||||||
|
uint32_t format : 6; // image format, see 'img_format'. (image-collector set)
|
||||||
|
uint32_t bpp : 6; // bits per pixel. (image-collector set)
|
||||||
|
uint32_t bppc : 6; // bits per pixel in this channel, equal to 'bpp' if pos.channel_ind == 0x0f. (image-collector set)
|
||||||
|
uint32_t compression : 6; // image data compression, see 'img_compression'. (image-collector set)
|
||||||
|
uint32_t reserve : 2; // unused now
|
||||||
|
uint32_t info_size; // image information size in bytes, information part is used for quality of JPEG, pallete of BMP .... (image-collector set)
|
||||||
|
uint64_t data_size; // image data size in 'data' with bytes. (image-collector set)
|
||||||
|
// char data[0]; // two parts: image info (info_size) + image data (data_size)
|
||||||
|
|
||||||
|
STRUCT_CONSTRUCTOR(_pack_img)
|
||||||
|
}PACKIMAGE, * LPPACKIMAGE;
|
||||||
|
|
||||||
|
typedef struct _oper_token
|
||||||
|
{
|
||||||
|
uint32_t type; // token type
|
||||||
|
char data[128]; // token data
|
||||||
|
}OPERTOKEN, * LPOPERTOKEN;
|
||||||
|
|
||||||
|
typedef struct _tx_file
|
||||||
|
{
|
||||||
|
uint64_t size; // total size
|
||||||
|
uint64_t offset; // offset in the file
|
||||||
|
char path[2]; // file full path-name
|
||||||
|
}TXFILE, *LPTXFILE;
|
||||||
|
typedef struct _file_info
|
||||||
|
{
|
||||||
|
OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET
|
||||||
|
uint64_t size; // file size
|
||||||
|
uint16_t name_len; // bytes of file name string
|
||||||
|
uint16_t create_time_len; // bytes of create time string: '2022-12-07 12:34:56.789', or target file path in command PACK_CMD_FILE_MOVE
|
||||||
|
uint16_t modify_time_len;
|
||||||
|
uint16_t version_len; // bytes of version string
|
||||||
|
char data[0]; // 4 parts: path-file(name_len) + create-time(create_time_len) + modify-time(modify_time_len) + version(version_len)
|
||||||
|
// or 5 parts in command PACK_CMD_FILE_WRITE, add content at the last part of bytes 'size'
|
||||||
|
|
||||||
|
STRUCT_CONSTRUCTOR(_file_info)
|
||||||
|
}FILEINFO, * LPFILEINFO;
|
||||||
|
|
||||||
|
typedef struct _proc_info
|
||||||
|
{
|
||||||
|
OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET
|
||||||
|
uint32_t count; // number of elements in array proc
|
||||||
|
struct _info
|
||||||
|
{
|
||||||
|
uint16_t len; // bytes of this element, include this head
|
||||||
|
uint64_t pid; // process id
|
||||||
|
uint64_t ppid; // parent process id
|
||||||
|
uint64_t start; // started time in ns from 1970-01-01 00:00:00
|
||||||
|
uint64_t mem; // memory usage, in bytes
|
||||||
|
uint64_t cpu_clk; // cpu clock
|
||||||
|
char path_name[4];
|
||||||
|
}proc[1];
|
||||||
|
|
||||||
|
STRUCT_CONSTRUCTOR(_proc_info)
|
||||||
|
}PROCINFO, * LPPROCINFO;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// configurations ...
|
||||||
|
//
|
||||||
|
// 1 - App has whole set, group definitions
|
||||||
|
//
|
||||||
|
// 2 - device provides sub-set, or a customizing item
|
||||||
|
//
|
|
@ -0,0 +1,125 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN64)
|
||||||
|
#define OS_WIN 1
|
||||||
|
#else
|
||||||
|
#define OS_WIN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZE_KB(n) ((n) * 1024)
|
||||||
|
#define SIZE_MB(n) SIZE_KB(n * 1024)
|
||||||
|
#define SIZE_GB(n) SIZE_MB(n * 1024)
|
||||||
|
|
||||||
|
#define SEC_2_MS(s) ((s) * 1000)
|
||||||
|
#define MSEC_2_US(ms) ((ms) * 1000)
|
||||||
|
#define SEC_2_US(s) MSEC_2_US(SEC_2_MS(s))
|
||||||
|
|
||||||
|
#define ALIGN_TO(v, align) (((v) + (align) - 1) / (align) * (align))
|
||||||
|
#define ALIGN_INT(v) ALIGN_TO(v, sizeof(int))
|
||||||
|
|
||||||
|
#define RETURN_ENUM_STR(v, e) \
|
||||||
|
if(v == e) \
|
||||||
|
return #e;
|
||||||
|
|
||||||
|
|
||||||
|
#if !OS_WIN // migrate codes from windows to linux ...
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct BITMAPFILEHEADER
|
||||||
|
{
|
||||||
|
u_int16_t bfType;
|
||||||
|
u_int32_t bfSize;
|
||||||
|
u_int16_t bfReserved1;
|
||||||
|
u_int16_t bfReserved2;
|
||||||
|
u_int32_t bfOffBits;
|
||||||
|
}BITMAPFILEHEADER;
|
||||||
|
|
||||||
|
typedef struct BITMAPINFOHEADER
|
||||||
|
{
|
||||||
|
u_int32_t biSize;
|
||||||
|
u_int32_t biWidth;
|
||||||
|
u_int32_t biHeight;
|
||||||
|
u_int16_t biPlanes;
|
||||||
|
u_int16_t biBitCount;
|
||||||
|
u_int32_t biCompression;
|
||||||
|
u_int32_t biSizeImage;
|
||||||
|
u_int32_t biXPelsPerMeter;
|
||||||
|
u_int32_t biYPelsPerMeter;
|
||||||
|
u_int32_t biClrUsed;
|
||||||
|
u_int32_t biClrImportant;
|
||||||
|
}BITMAPINFODEADER;
|
||||||
|
#pragma pack(pop)
|
||||||
|
#define BI_RGB 0
|
||||||
|
#define MAKEWORD(a, b) (((a) & 0x0ff) | (((b) & 0x0ff) << 8))
|
||||||
|
#define MAKELONG(a, b) (((a) & 0x0ffff) | (((b) & 0x0ffff) << 16))
|
||||||
|
#define _countof(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
typedef long LONG;
|
||||||
|
typedef void* HANDLE;
|
||||||
|
typedef void* HWND;
|
||||||
|
typedef void* HMODULE;
|
||||||
|
typedef void* LPVOID;
|
||||||
|
typedef void* FARPROC;
|
||||||
|
typedef unsigned int DWORD;
|
||||||
|
typedef unsigned short WORD;
|
||||||
|
typedef unsigned short UINT16;
|
||||||
|
typedef unsigned char BYTE;
|
||||||
|
typedef int BOOL;
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
#define MAX_PATH 256
|
||||||
|
#define huge
|
||||||
|
#define FAR
|
||||||
|
#define NEAR
|
||||||
|
#define LOWORD(v) ((v) & 0x0ffff)
|
||||||
|
#define HIWORD(v) (((v) >> 16) & 0x0ffff)
|
||||||
|
#define PASCAL __attribute__((stdcall))
|
||||||
|
#define _countof(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
#define LOAD_WITH_ALTERED_SEARCH_PATH RTLD_NOW
|
||||||
|
#define FreeLibrary dlclose
|
||||||
|
#define GetProcAddress dlsym
|
||||||
|
#define GetPrivateProfileIntW GetPrivateProfileIntA
|
||||||
|
#define lstrlenA strlen
|
||||||
|
#define lstrlenW strlen
|
||||||
|
|
||||||
|
#define DLL_EXTESION "so"
|
||||||
|
#define PATH_SEPARATOR "/"
|
||||||
|
#define STRICMP strcasecmp
|
||||||
|
#define MKDIR(a, b) mkdir(a, b)
|
||||||
|
#define STDCALL
|
||||||
|
#define ERROR_CANCELLED 1223
|
||||||
|
#define USB_TIMEOUT_INFINITE 0
|
||||||
|
#define FSEEK fseek
|
||||||
|
#define FTELL ftell
|
||||||
|
|
||||||
|
|
||||||
|
extern DWORD GetLastError(void);
|
||||||
|
extern DWORD GetPrivateProfileIntA(const char* app, const char* key, DWORD def, const char* file);
|
||||||
|
extern DWORD GetPrivateProfileStringA(const char* app, const char* key, const char* init, char* buf, size_t len, const char* file);
|
||||||
|
extern void Sleep(DWORD milliseconds);
|
||||||
|
extern int GetModuleFileNameA(HMODULE module, char* buf, size_t len); // NOTE: parameter 'module' is consinder as a part of the module file name
|
||||||
|
extern int GetCurrentProcessId(void);
|
||||||
|
extern int GetCurrentThreadId(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#define bzero(a, l) memset(a, 0, l)
|
||||||
|
#define DLL_EXTESION "dll"
|
||||||
|
#define PATH_SEPARATOR "\\"
|
||||||
|
#define STRICMP stricmp
|
||||||
|
#define MKDIR(a, b) mkdir(a)
|
||||||
|
#define STDCALL __stdcall
|
||||||
|
#define sem_t HANDLE
|
||||||
|
#define USB_TIMEOUT_INFINITE -1
|
||||||
|
#define FSEEK _fseeki64
|
||||||
|
#define FTELL _ftelli64
|
||||||
|
#define pid_t int
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,368 @@
|
||||||
|
// utilities for platform ...
|
||||||
|
//
|
||||||
|
// Date: 2023-06-30
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "plat_types.h"
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define USE_SAFE_THREAD
|
||||||
|
|
||||||
|
|
||||||
|
enum log_type
|
||||||
|
{
|
||||||
|
LOG_TYPE_NONE = 0, // no logging
|
||||||
|
LOG_TYPE_CONSOLE, // print to console
|
||||||
|
LOG_TYPE_FILE, // write log into file
|
||||||
|
};
|
||||||
|
enum log_level
|
||||||
|
{
|
||||||
|
LOG_LEVEL_ALL = 0,
|
||||||
|
LOG_LEVEL_DEBUG,
|
||||||
|
LOG_LEVEL_WARNING,
|
||||||
|
LOG_LEVEL_FATAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
std::string utf82ansi(const char* utf8);
|
||||||
|
std::string ansi2utf8(const char* ansi);
|
||||||
|
|
||||||
|
std::string get_command_result(const char* cmd, int len = -1, int *err = nullptr);
|
||||||
|
std::string get_local_data_path(void);
|
||||||
|
std::string temporary_path(void);
|
||||||
|
std::string format_current_time(void);
|
||||||
|
std::string get_module_full_path(const char* part_name = nullptr/*nullptr to get main-pe/first module's full path*/);
|
||||||
|
std::string find_file(const char* root_dir, const char* part_name, bool recursive = false);
|
||||||
|
std::string target_file_from_link(const char* lnk_file);
|
||||||
|
std::string get_ini_value(const char* seg, const char* key, const char* cfg_file); // return "" if not found
|
||||||
|
std::string load_mini_file(const char* file, int* err); // <= 1MB
|
||||||
|
int save_2_file(void* data, size_t len, const char* file, bool append = false/*append or new*/, size_t max_size = -1/*in append mode, truncate file if size is exceeded this value if was not -1*/);
|
||||||
|
|
||||||
|
bool is_match_pattern(const char* text, const char* pattern);
|
||||||
|
const char* to_lower(std::string& str); // return str.c_str()
|
||||||
|
const char* trim(std::string& str, const char* sp = "\r\n\t "); // return str.c_str()
|
||||||
|
|
||||||
|
HMODULE load_dll(const char* path_file, int flag);
|
||||||
|
bool create_folder(const char* folder);
|
||||||
|
void set_ini_value(const char* seg, const char* key, const char* val, const char* cfg_file);
|
||||||
|
int enum_file(const char* folder, bool recursive, bool/*return false to stop enumeration*/(STDCALL* found)(const char* path_name, bool dir, void* param), void* param);
|
||||||
|
int move_file(const char* from, const char* to);
|
||||||
|
|
||||||
|
int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block);
|
||||||
|
unsigned int get_page_size(unsigned int* map_unit = nullptr);
|
||||||
|
|
||||||
|
void init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/);
|
||||||
|
void uninit(void);
|
||||||
|
void log_info(const char* info, int level = LOG_LEVEL_ALL);
|
||||||
|
void log_mem_info(const char* desc, const void* data, size_t bytes, int level = LOG_LEVEL_ALL); // log as 0x12345678 00 01 02 ...
|
||||||
|
int get_log_type(void);
|
||||||
|
int get_log_level(void);
|
||||||
|
int copy_log_file_to(const char* dst);
|
||||||
|
int clear_log_file(void);
|
||||||
|
|
||||||
|
#if OS_WIN
|
||||||
|
// Function: pump message recycle (GetMessageW)
|
||||||
|
//
|
||||||
|
// Parameters: hwnd - target window
|
||||||
|
//
|
||||||
|
// filter_min - the minimal message
|
||||||
|
//
|
||||||
|
// filter_max - the maximal message
|
||||||
|
//
|
||||||
|
// msghandler - custom message processor
|
||||||
|
// MSG*, received message by GetMessage
|
||||||
|
// bool*, return whether user handled the message, no TranslateMessage and DispatchMessage if this was true
|
||||||
|
//
|
||||||
|
// Return: whether quit the message recycle
|
||||||
|
bool run_get_message(HWND hwnd, UINT filter_min = 0, UINT filter_max = 0, std::function<bool(MSG*, bool*)> msghandler = std::function<bool(MSG*, bool*)>());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename ... Args>
|
||||||
|
void to_log(int level, const char* fmt, Args ... args)
|
||||||
|
{
|
||||||
|
if (get_log_type() != LOG_TYPE_NONE && get_log_level() <= level)
|
||||||
|
{
|
||||||
|
size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
|
||||||
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
|
|
||||||
|
snprintf(buf.get(), size, fmt, args ...);
|
||||||
|
log_info(buf.get(), (log_level)level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ... Args>
|
||||||
|
void to_log_with_api(bool(*is_enable)(int), void(*log_api)(const char*, int), int level, const char* fmt, Args ... args)
|
||||||
|
{
|
||||||
|
if (is_enable(level))
|
||||||
|
{
|
||||||
|
size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
|
||||||
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
|
|
||||||
|
snprintf(buf.get(), size, fmt, args ...);
|
||||||
|
log_api(buf.get(), (log_level)level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T swap_half(T v)
|
||||||
|
{
|
||||||
|
T mask = (1 << (sizeof(T) * 4)) - 1,
|
||||||
|
h = v & mask;
|
||||||
|
|
||||||
|
v >>= sizeof(T) * 4;
|
||||||
|
v &= mask;
|
||||||
|
h <<= sizeof(T) * 4;
|
||||||
|
v |= h;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class base64
|
||||||
|
{
|
||||||
|
char base64_ind_[128];
|
||||||
|
char base64_char_[80];
|
||||||
|
char padding_char_;
|
||||||
|
|
||||||
|
bool is_valid_base64_table(const char* table);
|
||||||
|
bool initialize_base64_table(const char* table);
|
||||||
|
|
||||||
|
public:
|
||||||
|
base64();
|
||||||
|
~base64();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool set_base64_table(const char* table = nullptr);
|
||||||
|
std::string encode(const char* data, size_t bytes, unsigned int line_bytes = -1, bool need_padding = true);
|
||||||
|
std::string decode(const char* data, size_t bytes);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#if OS_WIN
|
||||||
|
struct _time_val
|
||||||
|
{
|
||||||
|
time_t tv_sec; /* Seconds. */
|
||||||
|
time_t tv_usec; /* Microseconds. */
|
||||||
|
};
|
||||||
|
typedef struct _time_val TIMEV;
|
||||||
|
|
||||||
|
struct timezone
|
||||||
|
{
|
||||||
|
int tz_minuteswest; /* Minutes west of GMT. */
|
||||||
|
int tz_dsttime; /* Nonzero if DST is ever in effect. */
|
||||||
|
};
|
||||||
|
int gettimeofday(TIMEV* tv, struct timezone* tz);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
typedef struct timeval TIMEV;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// object life referer
|
||||||
|
//
|
||||||
|
// derived from 'refer' if your class used in multi-threads
|
||||||
|
//
|
||||||
|
#define MUTEX std::mutex
|
||||||
|
#define LOCK_WITH_NAME(n, v) std::lock_guard<MUTEX> n(v)
|
||||||
|
#define SIMPLE_LOCK(v) LOCK_WITH_NAME(locker, v)
|
||||||
|
|
||||||
|
class refer
|
||||||
|
{
|
||||||
|
volatile int32_t ref_;
|
||||||
|
MUTEX mutex_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
refer();
|
||||||
|
virtual ~refer();
|
||||||
|
|
||||||
|
virtual void on_born(void);
|
||||||
|
virtual void on_dead(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int32_t add_ref(void);
|
||||||
|
virtual int32_t release(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
// time utility
|
||||||
|
class chronograph
|
||||||
|
{
|
||||||
|
TIMEV bgn_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
chronograph();
|
||||||
|
~chronograph();
|
||||||
|
|
||||||
|
static bool now(TIMEV* tv);
|
||||||
|
static bool now(uint64_t* seconds, uint64_t* u_seconds);
|
||||||
|
static std::string now(bool with_ms = true/*whether with milliseconds*/); // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint64_t elapse_s(void);
|
||||||
|
uint64_t elapse_ms(void);
|
||||||
|
uint64_t elapse_us(void);
|
||||||
|
void reset(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
// event
|
||||||
|
class platform_event : public refer
|
||||||
|
{
|
||||||
|
sem_t sem_;
|
||||||
|
volatile bool waiting_;
|
||||||
|
std::string dbg_info_;
|
||||||
|
bool log_ = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
platform_event(const char* info = "");
|
||||||
|
~platform_event();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool try_wait(void);
|
||||||
|
bool wait(unsigned timeout = USB_TIMEOUT_INFINITE/*ms*/); // USB_TIMEOUT_INFINITE is waiting unfinite, true when watied and false for wait timeout
|
||||||
|
void trigger(void);
|
||||||
|
bool is_waiting(void);
|
||||||
|
void enable_log(bool enable);
|
||||||
|
|
||||||
|
void set_debug_info(const char* info);
|
||||||
|
};
|
||||||
|
|
||||||
|
// share memory
|
||||||
|
class shared_memory : public refer
|
||||||
|
{
|
||||||
|
unsigned long long key_;
|
||||||
|
void* obj_;
|
||||||
|
bool first_;
|
||||||
|
size_t bytes_;
|
||||||
|
size_t len_;
|
||||||
|
|
||||||
|
void init(void);
|
||||||
|
void clear(void);
|
||||||
|
char* get_buf(void);
|
||||||
|
void release_buf(void* buf);
|
||||||
|
|
||||||
|
#if !defined(WIN32) && !defined(_WIN64)
|
||||||
|
static std::string get_proc_name_by_pid(pid_t pid);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
shared_memory(unsigned long long key, size_t size = 1024);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~shared_memory();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool is_ok(void);
|
||||||
|
bool is_first(void);
|
||||||
|
std::string read(void);
|
||||||
|
int write(const char* data, size_t len);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class safe_fifo
|
||||||
|
{
|
||||||
|
MUTEX lock_;
|
||||||
|
std::deque<T> que_;
|
||||||
|
platform_event* wait_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
safe_fifo(const char* who) : wait_(new platform_event(who && *who ? who : "fifo"))
|
||||||
|
{}
|
||||||
|
~safe_fifo()
|
||||||
|
{
|
||||||
|
wait_->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
size_t save(const T& t, bool notify = false)
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(lock_);
|
||||||
|
size_t cnt = que_.size();
|
||||||
|
|
||||||
|
que_.push_back(std::move(t));
|
||||||
|
if (notify)
|
||||||
|
wait_->trigger();
|
||||||
|
|
||||||
|
return cnt + 1;
|
||||||
|
}
|
||||||
|
bool take(T& t, bool wait = false)
|
||||||
|
{
|
||||||
|
if (wait && size() == 0)
|
||||||
|
{
|
||||||
|
wait_->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(lock_);
|
||||||
|
|
||||||
|
if (que_.size())
|
||||||
|
{
|
||||||
|
t = std::move(que_.front());
|
||||||
|
que_.pop_front();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t size(void)
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(lock_);
|
||||||
|
|
||||||
|
return que_.size();
|
||||||
|
}
|
||||||
|
void clear(void)
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(lock_);
|
||||||
|
|
||||||
|
que_.clear();
|
||||||
|
}
|
||||||
|
void trigger(void)
|
||||||
|
{
|
||||||
|
wait_->trigger();
|
||||||
|
}
|
||||||
|
void enable_wait_log(bool enable)
|
||||||
|
{
|
||||||
|
wait_->enable_log(enable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class safe_thread
|
||||||
|
{
|
||||||
|
typedef struct _safe_thrd
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::shared_ptr<std::thread> thread;
|
||||||
|
}SAFETHRD;
|
||||||
|
volatile bool run_ = true;
|
||||||
|
MUTEX lock_;
|
||||||
|
std::unique_ptr<std::thread> notify_thread_;
|
||||||
|
std::vector<SAFETHRD> threads_;
|
||||||
|
safe_fifo<std::string> excep_que_;
|
||||||
|
std::function<void(const char*)> excep_handler_ = std::function<void(const char*)>();
|
||||||
|
|
||||||
|
void thread_worker(std::function<void(void)> func, std::string name);
|
||||||
|
void thread_notify_exception(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
safe_thread(void);
|
||||||
|
~safe_thread();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_exception_handler(std::function<void(const char*)> on_exception = std::function<void(const char*)>());
|
||||||
|
int start(std::function<void(void)> f, const char* thread_name);
|
||||||
|
int stop(const char* thread_name);
|
||||||
|
};
|
|
@ -0,0 +1,380 @@
|
||||||
|
// this file is include huagao scanner error definitions
|
||||||
|
//
|
||||||
|
// created: 2022-02-07
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define RETURN_IF(var, enum_val) \
|
||||||
|
if(var == enum_val) \
|
||||||
|
return #enum_val;
|
||||||
|
#define RETURN_DESC_IF(var, hgerr) \
|
||||||
|
if(var == hgerr) \
|
||||||
|
return from_default_language(STATU_DESC_##hgerr);
|
||||||
|
|
||||||
|
enum scanner_err
|
||||||
|
{
|
||||||
|
SCANNER_ERR_OK = 0, // 成功,正常状态
|
||||||
|
|
||||||
|
// 1:软件逻辑错误
|
||||||
|
SCANNER_ERR_INVALID_PARAMETER = 0x100, // 非法的参数调用
|
||||||
|
SCANNER_ERR_USER_CANCELED, // 用户取消了操作
|
||||||
|
SCANNER_ERR_INSUFFICIENT_MEMORY, // 分配的内存不足
|
||||||
|
SCANNER_ERR_ACCESS_DENIED, // 访问被拒绝
|
||||||
|
SCANNER_ERR_IO_PENDING, // 异步访问,数据稍后返回
|
||||||
|
SCANNER_ERR_NOT_EXACT, // 数据不精确,精确的数据已经在同一缓存中返回
|
||||||
|
SCANNER_ERR_CONFIGURATION_CHANGED, // 设备的配置项发生改变,需要重新加载显示
|
||||||
|
SCANNER_ERR_NOT_OPEN, // 设备未打开
|
||||||
|
SCANNER_ERR_NOT_START, // 设备没有启动
|
||||||
|
SCANNER_ERR_NOT_ANY_MORE, // 用于回调返回,在本次扫描中,对相同操作不再回调
|
||||||
|
SCANNER_ERR_NO_DATA, // 没有数据
|
||||||
|
SCANNER_ERR_HAS_DATA_YET, // 有数据未被读取(异步操作中)
|
||||||
|
SCANNER_ERR_OUT_OF_RANGE, // 相关操作超出范围
|
||||||
|
SCANNER_ERR_IO, // IO错误
|
||||||
|
SCANNER_ERR_TIMEOUT, // 超时错误
|
||||||
|
SCANNER_ERR_OPEN_FILE_FAILED, // 打开本地文件失败
|
||||||
|
SCANNER_ERR_CREATE_FILE_FAILED, // 创建本地文件失败
|
||||||
|
SCANNER_ERR_WRITE_FILE_FAILED, // 写本地文件失败
|
||||||
|
SCANNER_ERR_DATA_DAMAGED, // 数据损坏(内置资源数据损坏)
|
||||||
|
SCANNER_ERR_OPENED_BY_OTHER_PROCESS, // 设备已经被其它进程打开占用
|
||||||
|
SCANNER_ERR_LANG_PAK_LOST, // 语言包丢失
|
||||||
|
SCANNER_ERR_RELOAD_IMAGE_PARAM, // 配置成功,会影响图像参数,应用需要重新加载图像参数 - added on 2023-02-18 for XSANE修改影响图像参数的属性后扫描崩溃的问题
|
||||||
|
SCANNER_ERR_RELOAD_OPT_PARAM, // SCANNER_ERR_CONFIGURATION_CHANGED + SCANNER_ERR_RELOAD_IMAGE_PARAM - added on 2023-02-18 for XSANE修改影响图像参数的属性后扫描崩溃的问题
|
||||||
|
SCANNER_ERR_THROW_EXCEPTION, // catched exception
|
||||||
|
|
||||||
|
// 2:USB错误
|
||||||
|
SCANNER_ERR_USB_INIT_FAILED = 0x5b00, // libusb_init 失败
|
||||||
|
SCANNER_ERR_USB_REGISTER_PNP_FAILED, // 注册USB监听事件失败
|
||||||
|
SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED, // failed in calling libusb_claim_interface
|
||||||
|
|
||||||
|
// 3:硬件错误
|
||||||
|
SCANNER_ERR_DEVICE_NOT_FOUND = 0x0de00, // 设备未找到
|
||||||
|
SCANNER_ERR_DEVICE_NOT_SUPPORT, // 设备不支持该操作
|
||||||
|
SCANNER_ERR_DEVICE_BUSY, // 设备正忙,不能响应该操作
|
||||||
|
SCANNER_ERR_DEVICE_SLEEPING, // 设备处于睡眠状态
|
||||||
|
SCANNER_ERR_DEVICE_COUNT_MODE, // 设备处于计数扫描状态?
|
||||||
|
SCANNER_ERR_DEVICE_STOPPED, // 扫描停止
|
||||||
|
SCANNER_ERR_DEVICE_COVER_OPENNED, // 扫描仪盖板呈打开状态
|
||||||
|
SCANNER_ERR_DEVICE_NO_PAPER, // 没有纸张输入
|
||||||
|
SCANNER_ERR_DEVICE_FEEDING_PAPER, // 搓纸失败
|
||||||
|
SCANNER_ERR_DEVICE_DOUBLE_FEEDING, // 双张检测
|
||||||
|
SCANNER_ERR_DEVICE_PAPER_JAMMED, // 卡纸
|
||||||
|
SCANNER_ERR_DEVICE_STAPLE_ON, // 有钉书钉
|
||||||
|
SCANNER_ERR_DEVICE_PAPER_SKEW, // 纸张倾斜
|
||||||
|
SCANNER_ERR_DEVICE_SIZE_CHECK, // 尺寸检测错误
|
||||||
|
SCANNER_ERR_DEVICE_DOGEAR, // 纸张有折角
|
||||||
|
SCANNER_ERR_DEVICE_NO_IMAGE, // 设备没取到图
|
||||||
|
SCANNER_ERR_DEVICE_SCANN_ERROR, // 设备扫图失败
|
||||||
|
SCANNER_ERR_DEVICE_PC_BUSY, // PC繁忙或出错
|
||||||
|
SCANNER_ERR_DEVICE_ISLOCK, // 设备被锁定
|
||||||
|
SCANNER_ERR_DEVICE_UPGRADE_SUCCESSFUL, // 固件升级成功
|
||||||
|
SCANNER_ERR_DEVICE_UPGRADE_FAIL, // 固件升级失败+
|
||||||
|
SCANNER_ERR_DEVICE_AUTO_FAIL_OVER, // 设备平场自动校正结束
|
||||||
|
SCANNER_ERR_DEVICE_AUTO_FAIL_INFO, // 设备平场自动校正信息传输
|
||||||
|
SCANNER_ERR_DEVICE_DISTORTION, // 畸变修正失败
|
||||||
|
SCANNER_ERR_DEVICE_MAYBE_IS_HOLE, // 纸张有孔洞
|
||||||
|
SCANNER_ERR_DEVICE_DEVS_BOOTING, // 请稍等 - 设备正在准备
|
||||||
|
SCANNER_ERR_DEVICE_UNKNOWN_STATUS, // 设备处于未知状态
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 状态信息描述符
|
||||||
|
//
|
||||||
|
// #define STATU_DESC_PREPARE_START "准备启动……"
|
||||||
|
#define STATU_DESC_PREPARE_START "\345\207\206\345\244\207\345\220\257\345\212\250\342\200\246\342\200\246"
|
||||||
|
#define ID_STATU_DESC_PREPARE_START 62135
|
||||||
|
|
||||||
|
// #define STATU_DESC_REWRITE_CONFIGURATION "写入配置……"
|
||||||
|
#define STATU_DESC_REWRITE_CONFIGURATION "\345\206\231\345\205\245\351\205\215\347\275\256\342\200\246\342\200\246"
|
||||||
|
#define ID_STATU_DESC_REWRITE_CONFIGURATION 16489
|
||||||
|
|
||||||
|
// #define STATU_DESC_CLEAR_CACHE "清理缓存……"
|
||||||
|
#define STATU_DESC_CLEAR_CACHE "\346\270\205\347\220\206\347\274\223\345\255\230\342\200\246\342\200\246"
|
||||||
|
#define ID_STATU_DESC_CLEAR_CACHE 6523
|
||||||
|
|
||||||
|
// #define STATU_DESC_START_SUCCESS "启动成功"
|
||||||
|
#define STATU_DESC_START_SUCCESS "\345\220\257\345\212\250\346\210\220\345\212\237"
|
||||||
|
#define ID_STATU_DESC_START_SUCCESS 33731
|
||||||
|
|
||||||
|
// #define STATU_DESC_START_FAIL "启动失败"
|
||||||
|
#define STATU_DESC_START_FAIL "\345\220\257\345\212\250\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_START_FAIL 51358
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCAN_WORKING "正在扫描……"
|
||||||
|
#define STATU_DESC_SCAN_WORKING "\346\255\243\345\234\250\346\211\253\346\217\217\342\200\246\342\200\246"
|
||||||
|
#define ID_STATU_DESC_SCAN_WORKING 21315
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCAN_STOPPED "扫描完成"
|
||||||
|
#define STATU_DESC_SCAN_STOPPED "\346\211\253\346\217\217\345\256\214\346\210\220"
|
||||||
|
#define ID_STATU_DESC_SCAN_STOPPED 17731
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCAN_CANCELED "扫描已取消"
|
||||||
|
#define STATU_DESC_SCAN_CANCELED "\346\211\253\346\217\217\345\267\262\345\217\226\346\266\210"
|
||||||
|
#define ID_STATU_DESC_SCAN_CANCELED 63314
|
||||||
|
|
||||||
|
// #define STATU_DESC_WAIT_FOR_MEM "内存不足,等待内存释放……"
|
||||||
|
#define STATU_DESC_WAIT_FOR_MEM "\345\206\205\345\255\230\344\270\215\350\266\263\357\274\214\347\255\211\345\276\205\345\206\205\345\255\230\351\207\212\346\224\276\342\200\246\342\200\246"
|
||||||
|
#define ID_STATU_DESC_WAIT_FOR_MEM 7697
|
||||||
|
|
||||||
|
// #define STATU_DESC_DEVICE_RESET "正在重置,如果设备迟迟没有动作,请重新扫描……"
|
||||||
|
#define STATU_DESC_DEVICE_RESET "\346\255\243\345\234\250\351\207\215\347\275\256\357\274\214\345\246\202\346\236\234\350\256\276\345\244\207\350\277\237\350\277\237\346\262\241\346\234\211\345\212\250\344\275\234\357\274\214\350\257\267\351\207\215\346\226\260\346\211\253\346\217\217\342\200\246\342\200\246"
|
||||||
|
#define ID_STATU_DESC_DEVICE_RESET 47482
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_OK "操作成功"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_OK "\346\223\215\344\275\234\346\210\220\345\212\237"
|
||||||
|
//#define ID_STATU_DESC_SCANNER_ERR_OK 3249
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_USER_CANCELED "操作被取消"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_USER_CANCELED "\346\223\215\344\275\234\350\242\253\345\217\226\346\266\210"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_USER_CANCELED 48546
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DATA_DAMAGED "数据损坏"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DATA_DAMAGED "\346\225\260\346\215\256\346\215\237\345\235\217"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DATA_DAMAGED 45852
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_INVALID_PARAMETER "非法的参数调用"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_INVALID_PARAMETER "\351\235\236\346\263\225\347\232\204\345\217\202\346\225\260\350\260\203\347\224\250"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_INVALID_PARAMETER 6119
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY "内存不足或内存分配失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY "\345\206\205\345\255\230\344\270\215\350\266\263\346\210\226\345\206\205\345\255\230\345\210\206\351\205\215\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY 56958
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_ACCESS_DENIED "访问被拒绝"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_ACCESS_DENIED "\350\256\277\351\227\256\350\242\253\346\213\222\347\273\235"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_ACCESS_DENIED 56275
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_IO_PENDING "异步访问,数据稍后返回"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_IO_PENDING "\345\274\202\346\255\245\350\256\277\351\227\256\357\274\214\346\225\260\346\215\256\347\250\215\345\220\216\350\277\224\345\233\236"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_IO_PENDING 25758
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_NOT_EXACT "数据不精确,精确的数据已经在同一缓存中返回"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_NOT_EXACT "\346\225\260\346\215\256\344\270\215\347\262\276\347\241\256\357\274\214\347\262\276\347\241\256\347\232\204\346\225\260\346\215\256\345\267\262\347\273\217\345\234\250\345\220\214\344\270\200\347\274\223\345\255\230\344\270\255\350\277\224\345\233\236"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_NOT_EXACT 64193
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_CONFIGURATION_CHANGED "设备的配置项发生改变,需要重新加载显示"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_CONFIGURATION_CHANGED "\350\256\276\345\244\207\347\232\204\351\205\215\347\275\256\351\241\271\345\217\221\347\224\237\346\224\271\345\217\230\357\274\214\351\234\200\350\246\201\351\207\215\346\226\260\345\212\240\350\275\275\346\230\276\347\244\272"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_CONFIGURATION_CHANGED 26730
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_RELOAD_IMAGE_PARAM "图像参数已经改变,请重新加载"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_RELOAD_IMAGE_PARAM "\345\233\276\345\203\217\345\217\202\346\225\260\345\267\262\347\273\217\346\224\271\345\217\230\357\274\214\350\257\267\351\207\215\346\226\260\345\212\240\350\275\275"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_RELOAD_IMAGE_PARAM 54637
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_RELOAD_OPT_PARAM "关联属性状态及图像参数已经改变,请重新加载"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_RELOAD_OPT_PARAM "\345\205\263\350\201\224\345\261\236\346\200\247\347\212\266\346\200\201\345\217\212\345\233\276\345\203\217\345\217\202\346\225\260\345\267\262\347\273\217\346\224\271\345\217\230\357\274\214\350\257\267\351\207\215\346\226\260\345\212\240\350\275\275"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_RELOAD_OPT_PARAM 4762
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_NOT_OPEN "设备未打开"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_NOT_OPEN "\350\256\276\345\244\207\346\234\252\346\211\223\345\274\200"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_NOT_OPEN 38521
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_NOT_START "设备没有启动"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_NOT_START "\350\256\276\345\244\207\346\262\241\346\234\211\345\220\257\345\212\250"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_NOT_START 5681
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_NOT_ANY_MORE "在本次扫描中,对相同操作不再询问"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_NOT_ANY_MORE "\345\234\250\346\234\254\346\254\241\346\211\253\346\217\217\344\270\255\357\274\214\345\257\271\347\233\270\345\220\214\346\223\215\344\275\234\344\270\215\345\206\215\350\257\242\351\227\256"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_NOT_ANY_MORE 16267
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_NO_DATA "没有数据"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_NO_DATA "\346\262\241\346\234\211\346\225\260\346\215\256"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_NO_DATA 15331
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_HAS_DATA_YET "有数据未被读取"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_HAS_DATA_YET "\346\234\211\346\225\260\346\215\256\346\234\252\350\242\253\350\257\273\345\217\226"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_HAS_DATA_YET 31030
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_OUT_OF_RANGE "操作超出范围"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_OUT_OF_RANGE "\346\223\215\344\275\234\350\266\205\345\207\272\350\214\203\345\233\264"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_OUT_OF_RANGE 22268
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_IO "IO错误,请重启设备或拔插USB"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_IO "IO\351\224\231\350\257\257\357\274\214\350\257\267\351\207\215\345\220\257\350\256\276\345\244\207\346\210\226\346\213\224\346\217\222USB"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_IO 27027
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_TIMEOUT "操作超时"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_TIMEOUT "\346\223\215\344\275\234\350\266\205\346\227\266"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_TIMEOUT 65371
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_OPEN_FILE_FAILED "打开本地文件失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_OPEN_FILE_FAILED "\346\211\223\345\274\200\346\234\254\345\234\260\346\226\207\344\273\266\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_OPEN_FILE_FAILED 52380
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_CREATE_FILE_FAILED "创建本地文件失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_CREATE_FILE_FAILED "\345\210\233\345\273\272\346\234\254\345\234\260\346\226\207\344\273\266\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_CREATE_FILE_FAILED 23361
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_WRITE_FILE_FAILED "写本地文件失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_WRITE_FILE_FAILED "\345\206\231\346\234\254\345\234\260\346\226\207\344\273\266\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_WRITE_FILE_FAILED 22164
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_OPENED_BY_OTHER_PROCESS "设备已经被其它进程占用"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_OPENED_BY_OTHER_PROCESS "\350\256\276\345\244\207\345\267\262\347\273\217\350\242\253\345\205\266\345\256\203\350\277\233\347\250\213\345\215\240\347\224\250"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_OPENED_BY_OTHER_PROCESS 62384
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_USB_INIT_FAILED "USB通信初始化失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_USB_INIT_FAILED "USB\351\200\232\344\277\241\345\210\235\345\247\213\345\214\226\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_USB_INIT_FAILED 49159
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_USB_REGISTER_PNP_FAILED "注册USB监听事件失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_USB_REGISTER_PNP_FAILED "\346\263\250\345\206\214USB\347\233\221\345\220\254\344\272\213\344\273\266\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_USB_REGISTER_PNP_FAILED 5685
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED "声明USB接口失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED "\345\243\260\346\230\216USB\346\216\245\345\217\243\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED 21918
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND "设备未找到"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND "\350\256\276\345\244\207\346\234\252\346\211\276\345\210\260"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND 43988
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORT "设备不支持该操作"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORT "\350\256\276\345\244\207\344\270\215\346\224\257\346\214\201\350\257\245\346\223\215\344\275\234"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORT 15726
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_BUSY "设备正忙,不能响应该操作"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_BUSY "\350\256\276\345\244\207\346\255\243\345\277\231\357\274\214\344\270\215\350\203\275\345\223\215\345\272\224\350\257\245\346\223\215\344\275\234"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_BUSY 29315
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING "设备处于睡眠状态"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING "\350\256\276\345\244\207\345\244\204\344\272\216\347\235\241\347\234\240\347\212\266\346\200\201"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING 26372
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_NOTIFY_SLEEP 正在唤醒...请等待十秒再次扫描
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_NOTIFY_SLEEP "\346\255\243\345\234\250\345\224\244\351\206\222...\350\257\267\347\255\211\345\276\205\345\215\201\347\247\222\345\206\215\346\254\241\346\211\253\346\217\217"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOTIFY_SLEEP 64756
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE "设备处于计数模式扫描状态"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE "\350\256\276\345\244\207\345\244\204\344\272\216\350\256\241\346\225\260\346\250\241\345\274\217\346\211\253\346\217\217\347\212\266\346\200\201"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE 602
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_STOPPED "扫描停止"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_STOPPED "\346\211\253\346\217\217\345\201\234\346\255\242"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_STOPPED 45291
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED "请关闭扫描仪盖板"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED "\350\257\267\345\205\263\351\227\255\346\211\253\346\217\217\344\273\252\347\233\226\346\235\277"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED 29725
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER "无纸"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER "\346\227\240\347\272\270"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER 61284
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER "搓纸失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER "\346\220\223\347\272\270\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER 60256
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING "有多张纸被同时搓进扫描仪"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING "\346\234\211\345\244\232\345\274\240\347\272\270\350\242\253\345\220\214\346\227\266\346\220\223\350\277\233\346\211\253\346\217\217\344\273\252"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING 58398
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED "扫描仪卡纸"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED "\346\211\253\346\217\217\344\273\252\345\215\241\347\272\270"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED 39928
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON "纸张上检测到有钉书钉"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON "\347\272\270\345\274\240\344\270\212\346\243\200\346\265\213\345\210\260\346\234\211\351\222\211\344\271\246\351\222\211"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON 3126
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW "纸张倾斜"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW "\347\272\270\345\274\240\345\200\276\346\226\234"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW 5570
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK "纸张尺寸检测错误"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK "\347\272\270\345\274\240\345\260\272\345\257\270\346\243\200\346\265\213\351\224\231\350\257\257"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK 32107
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR "纸张有折角"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR "\347\272\270\345\274\240\346\234\211\346\212\230\350\247\222"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR 61565
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE "设备没取到图"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE "\350\256\276\345\244\207\346\262\241\345\217\226\345\210\260\345\233\276"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE 41789
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR "扫描失败"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR "\346\211\253\346\217\217\345\244\261\350\264\245"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR 14901
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY "PC繁忙或出错"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY "PC\347\271\201\345\277\231\346\210\226\345\207\272\351\224\231"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY 61142
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK "设备被锁定"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK "\350\256\276\345\244\207\350\242\253\351\224\201\345\256\232"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK 1535
|
||||||
|
|
||||||
|
// #define STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK "此固件不支持待纸扫描"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORTED "\346\255\244\345\233\272\344\273\266\344\270\215\346\224\257\346\214\201\345\276\205\347\272\270\346\211\253\346\217\217"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORTED 9610
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_OVER "自动平场校正结束"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_OVER "\350\207\252\345\212\250\345\271\263\345\234\272\346\240\241\346\255\243\347\273\223\346\235\237"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_OVER 38824
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_DISTORTION "疑是非专用畸变修正纸"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_DISTORTION "\347\226\221\346\230\257\351\235\236\344\270\223\347\224\250\347\225\270\345\217\230\344\277\256\346\255\243\347\272\270"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DISTORTION 32402
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_OUTTIME "取图通信超时"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_OUTTIME "\345\217\226\345\233\276\351\200\232\344\277\241\350\266\205\346\227\266"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_OUTTIME 10438
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_GET_USER_CANCEL_SCAN "用户取消扫描"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_GET_USER_CANCEL_SCAN "\347\224\250\346\210\267\345\217\226\346\266\210\346\211\253\346\217\217"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_GET_USER_CANCEL_SCAN 39020
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_FAIL_OUTTIME "设备校正超时"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_FAIL_OUTTIME "\350\256\276\345\244\207\346\240\241\346\255\243\350\266\205\346\227\266"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_FAIL_OUTTIME 21710
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_ROUND_SACN_OVER "此轮扫描完成"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_ROUND_SACN_OVER "\346\255\244\350\275\256\346\211\253\346\217\217\345\256\214\346\210\220"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_ROUND_SACN_OVER 57619
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS "设备"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS "\350\256\276\345\244\207\342\200\234"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DEVS 603
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_IS_CLOSE "已经关闭"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_IS_CLOSE "\342\200\235\345\267\262\347\273\217\345\205\263\351\227\255\343\200\202"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_IS_CLOSE 35078
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_ERROR "未知错误,请重启设备,等待设备复位成功在启动软件。"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_ERROR "\346\234\252\347\237\245\351\224\231\350\257\257\357\274\214\350\257\267\351\207\215\345\220\257\350\256\276\345\244\207\357\274\214\347\255\211\345\276\205\350\256\276\345\244\207\345\244\215\344\275\215\346\210\220\345\212\237\345\234\250\345\220\257\345\212\250\350\275\257\344\273\266"
|
||||||
|
#define ID_STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_ERROR 22744
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_MAYBE_IS_HOLE "疑是纸张有较大孔洞"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_MAYBE_IS_HOLE "\347\226\221\346\230\257\347\272\270\345\274\240\346\234\211\350\276\203\345\244\247\345\255\224\346\264\236"
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_EXIT_WAIT_SCAN "退出待纸扫描"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_EXIT_WAIT_SCAN "\351\200\200\345\207\272\345\276\205\347\272\270\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_ERR "获取图像异常"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_ERR "\350\216\267\345\217\226\345\233\276\345\203\217\345\274\202\345\270\270"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS_BOOTING "请稍等-设备正在准备中"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS_BOOTING "\350\257\267\347\250\215\347\255\211-\350\256\276\345\244\207\346\255\243\345\234\250\345\207\206\345\244\207\344\270\255"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS_BOOTING "设备启动成功-可以开始扫描"
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS_START_SUCCES "\350\256\276\345\244\207\345\220\257\345\212\250\346\210\220\345\212\237-\345\217\257\344\273\245\345\274\200\345\247\213\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_LANG_PAK_LOST 语言包缺失词条
|
||||||
|
#define STATU_DESC_SCANNER_ERR_LANG_PAK_LOST "\350\257\255\350\250\200\345\214\205\347\274\272\345\244\261\350\257\215\346\235\241"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_UPGRADE_SUCCESSFUL 设备升级成功
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_UPGRADE_SUCCESSFUL "\350\256\276\345\244\207\345\215\207\347\272\247\346\210\220\345\212\237"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_UPGRADE_FAIL 设备升级失败
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_UPGRADE_FAIL "\350\256\276\345\244\207\345\215\207\347\272\247\345\244\261\350\264\245"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_INFO 自动平场校正信息
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_INFO "\350\207\252\345\212\250\345\271\263\345\234\272\346\240\241\346\255\243\344\277\241\346\201\257"
|
||||||
|
|
||||||
|
//#define STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_STATUS 设备处于未知状态
|
||||||
|
#define STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_STATUS "\350\256\276\345\244\207\345\244\204\344\272\216\346\234\252\347\237\245\347\212\266\346\200\201"
|
||||||
|
|
||||||
|
// 状态信息描述符 - OVER
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,794 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2009 Dave Gamble
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* cJSON */
|
||||||
|
/* JSON parser in C. */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "cJSON.h"
|
||||||
|
|
||||||
|
static const char *ep;
|
||||||
|
|
||||||
|
const char *cJSON_GetErrorPtr(void) {return ep;}
|
||||||
|
|
||||||
|
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
||||||
|
{
|
||||||
|
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||||
|
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||||
|
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* ask_memory(size_t bytes)
|
||||||
|
{
|
||||||
|
// printf("allocate %u bytes memory in cJSON\n", bytes);
|
||||||
|
|
||||||
|
return malloc(bytes);
|
||||||
|
}
|
||||||
|
static void *(*cJSON_malloc)(size_t sz) = ask_memory;
|
||||||
|
static void (*cJSON_free)(void *ptr) = free;
|
||||||
|
|
||||||
|
static char* cJSON_strdup(const char* str)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
char* copy;
|
||||||
|
|
||||||
|
len = strlen(str) + 1;
|
||||||
|
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||||
|
memcpy(copy,str,len);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||||
|
{
|
||||||
|
if (!hooks) { /* Reset hooks */
|
||||||
|
cJSON_malloc = ask_memory;
|
||||||
|
cJSON_free = free;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:ask_memory;
|
||||||
|
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal constructor. */
|
||||||
|
static cJSON *cJSON_New_Item(void)
|
||||||
|
{
|
||||||
|
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||||
|
if (node) memset(node,0,sizeof(cJSON));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete a cJSON structure. */
|
||||||
|
void cJSON_Delete(cJSON *c)
|
||||||
|
{
|
||||||
|
cJSON *next;
|
||||||
|
while (c)
|
||||||
|
{
|
||||||
|
next=c->next;
|
||||||
|
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
|
||||||
|
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
|
||||||
|
if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
|
||||||
|
cJSON_free(c);
|
||||||
|
c=next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the input text to generate a number, and populate the result into item. */
|
||||||
|
static const char *parse_number(cJSON *item,const char *num)
|
||||||
|
{
|
||||||
|
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
|
||||||
|
|
||||||
|
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||||
|
if (*num=='0') num++; /* is zero */
|
||||||
|
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||||
|
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
|
||||||
|
if (*num=='e' || *num=='E') /* Exponent? */
|
||||||
|
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
|
||||||
|
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
|
||||||
|
}
|
||||||
|
|
||||||
|
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
||||||
|
|
||||||
|
item->valuedouble=n;
|
||||||
|
item->valueint=(int)n;
|
||||||
|
item->type=cJSON_Number;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; }
|
||||||
|
|
||||||
|
typedef struct {char *buffer; int length; int offset; } printbuffer;
|
||||||
|
|
||||||
|
static char* ensure(printbuffer *p,int needed)
|
||||||
|
{
|
||||||
|
char *newbuffer;int newsize;
|
||||||
|
if (!p || !p->buffer) return 0;
|
||||||
|
needed+=p->offset;
|
||||||
|
if (needed<=p->length) return p->buffer+p->offset;
|
||||||
|
|
||||||
|
newsize=pow2gt(needed);
|
||||||
|
newbuffer=(char*)cJSON_malloc(newsize);
|
||||||
|
if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
|
||||||
|
if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
|
||||||
|
cJSON_free(p->buffer);
|
||||||
|
p->length=newsize;
|
||||||
|
p->buffer=newbuffer;
|
||||||
|
return newbuffer+p->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int update(printbuffer *p)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
if (!p || !p->buffer) return 0;
|
||||||
|
str=p->buffer+p->offset;
|
||||||
|
return p->offset+strlen(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render the number nicely from the given item into a string. */
|
||||||
|
static char *print_number(cJSON *item,printbuffer *p)
|
||||||
|
{
|
||||||
|
char *str=0;
|
||||||
|
double d=item->valuedouble;
|
||||||
|
if (d==0)
|
||||||
|
{
|
||||||
|
if (p) str=ensure(p,2);
|
||||||
|
else str=(char*)cJSON_malloc(2); /* special case for 0. */
|
||||||
|
if (str) strcpy(str,"0");
|
||||||
|
}
|
||||||
|
else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
||||||
|
{
|
||||||
|
if (p) str=ensure(p,21);
|
||||||
|
else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
||||||
|
if (str) sprintf(str,"%d",item->valueint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p) str=ensure(p,64);
|
||||||
|
else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
|
||||||
|
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
|
||||||
|
else sprintf(str,"%f",d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned parse_hex4(const char *str)
|
||||||
|
{
|
||||||
|
unsigned h=0;
|
||||||
|
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||||
|
h=h<<4;str++;
|
||||||
|
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||||
|
h=h<<4;str++;
|
||||||
|
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||||
|
h=h<<4;str++;
|
||||||
|
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||||
|
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
|
static const char *parse_string(cJSON *item,const char *str)
|
||||||
|
{
|
||||||
|
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
|
||||||
|
if (*str!='\"') {ep=str;return 0;} /* not a string! */
|
||||||
|
|
||||||
|
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
|
||||||
|
|
||||||
|
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
|
||||||
|
if (!out) return 0;
|
||||||
|
|
||||||
|
ptr=str+1;ptr2=out;
|
||||||
|
while (*ptr!='\"' && *ptr)
|
||||||
|
{
|
||||||
|
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr++;
|
||||||
|
switch (*ptr)
|
||||||
|
{
|
||||||
|
case 'b': *ptr2++='\b'; break;
|
||||||
|
case 'f': *ptr2++='\f'; break;
|
||||||
|
case 'n': *ptr2++='\n'; break;
|
||||||
|
case 'r': *ptr2++='\r'; break;
|
||||||
|
case 't': *ptr2++='\t'; break;
|
||||||
|
case 'u': /* transcode utf16 to utf8. */
|
||||||
|
uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
|
||||||
|
|
||||||
|
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
|
||||||
|
|
||||||
|
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
|
||||||
|
{
|
||||||
|
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
|
||||||
|
uc2=parse_hex4(ptr+3);ptr+=6;
|
||||||
|
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
|
||||||
|
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
|
||||||
|
}
|
||||||
|
|
||||||
|
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||||
|
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||||
|
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||||
|
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||||
|
}
|
||||||
|
ptr2+=len;
|
||||||
|
break;
|
||||||
|
default: *ptr2++=*ptr; break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ptr2=0;
|
||||||
|
if (*ptr=='\"') ptr++;
|
||||||
|
item->valuestring=out;
|
||||||
|
item->type=cJSON_String;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
char* cJSON_utf8_2_unic(const char* utf8)
|
||||||
|
{
|
||||||
|
char* unic = (char*)malloc(strlen(utf8) * 3 + 8);
|
||||||
|
unsigned char * cur = unic;
|
||||||
|
|
||||||
|
while (*cur = *utf8++)
|
||||||
|
{
|
||||||
|
if ((*cur & 0x0f0) == 0x0e0)
|
||||||
|
{
|
||||||
|
if (((unsigned char)utf8[0] & 0x0c0) == 0x80 &&
|
||||||
|
((unsigned char)utf8[1] & 0x0c0) == 0x80)
|
||||||
|
{
|
||||||
|
char* hex = "0123456789ABCDEF";
|
||||||
|
unsigned short us = *cur & 0x0f;
|
||||||
|
us <<= 6;
|
||||||
|
us += utf8[0] & 0x3f;
|
||||||
|
us <<= 6;
|
||||||
|
us += utf8[1] & 0x3f;
|
||||||
|
|
||||||
|
*cur++ = '\\';
|
||||||
|
*cur++ = 'u';
|
||||||
|
cur[3] = hex[us & 0x0f];
|
||||||
|
us >>= 4;
|
||||||
|
cur[2] = hex[us & 0x0f];
|
||||||
|
us >>= 4;
|
||||||
|
cur[1] = hex[us & 0x0f];
|
||||||
|
us >>= 4;
|
||||||
|
cur[0] = hex[us & 0x0f];
|
||||||
|
cur += 3;
|
||||||
|
utf8 += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
*cur++ = 0;
|
||||||
|
|
||||||
|
return unic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render the cstring provided to an escaped version that can be printed. */
|
||||||
|
static char *print_string_ptr(const char *str,printbuffer *p)
|
||||||
|
{
|
||||||
|
const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
|
||||||
|
|
||||||
|
for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
|
||||||
|
if (!flag)
|
||||||
|
{
|
||||||
|
len=ptr-str;
|
||||||
|
if (p) out=ensure(p,len+3);
|
||||||
|
else out=(char*)cJSON_malloc(len+3);
|
||||||
|
if (!out) return 0;
|
||||||
|
ptr2=out;*ptr2++='\"';
|
||||||
|
strcpy(ptr2,str);
|
||||||
|
ptr2[len]='\"';
|
||||||
|
ptr2[len+1]=0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
if (p) out=ensure(p,3);
|
||||||
|
else out=(char*)cJSON_malloc(3);
|
||||||
|
if (!out) return 0;
|
||||||
|
strcpy(out,"\"\"");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
|
||||||
|
|
||||||
|
if (p) out=ensure(p,len+3);
|
||||||
|
else out=(char*)cJSON_malloc(len+3);
|
||||||
|
if (!out) return 0;
|
||||||
|
|
||||||
|
ptr2=out;ptr=str;
|
||||||
|
*ptr2++='\"';
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
|
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ptr2++='\\';
|
||||||
|
switch (token=*ptr++)
|
||||||
|
{
|
||||||
|
case '\\': *ptr2++='\\'; break;
|
||||||
|
case '\"': *ptr2++='\"'; break;
|
||||||
|
case '\b': *ptr2++='b'; break;
|
||||||
|
case '\f': *ptr2++='f'; break;
|
||||||
|
case '\n': *ptr2++='n'; break;
|
||||||
|
case '\r': *ptr2++='r'; break;
|
||||||
|
case '\t': *ptr2++='t'; break;
|
||||||
|
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ptr2++='\"';*ptr2++=0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
/* Invote print_string_ptr (which is useful) on an item. */
|
||||||
|
static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);}
|
||||||
|
|
||||||
|
/* Predeclare these prototypes. */
|
||||||
|
static const char *parse_value(cJSON *item,const char *value);
|
||||||
|
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
|
||||||
|
static const char *parse_array(cJSON *item,const char *value);
|
||||||
|
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
|
||||||
|
static const char *parse_object(cJSON *item,const char *value);
|
||||||
|
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
|
||||||
|
|
||||||
|
/* Utility to jump whitespace and cr/lf */
|
||||||
|
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
|
||||||
|
|
||||||
|
/* Parse an object - create a new root, and populate. */
|
||||||
|
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
|
||||||
|
{
|
||||||
|
const char *end=0;
|
||||||
|
cJSON *c=cJSON_New_Item();
|
||||||
|
ep=0;
|
||||||
|
if (!c) return 0; /* memory fail */
|
||||||
|
|
||||||
|
end=parse_value(c,skip(value));
|
||||||
|
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
|
||||||
|
|
||||||
|
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
|
||||||
|
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
|
||||||
|
if (return_parse_end) *return_parse_end=end;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
/* Default options for cJSON_Parse */
|
||||||
|
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
|
||||||
|
|
||||||
|
/* Render a cJSON item/entity/structure to text. */
|
||||||
|
char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
|
||||||
|
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}
|
||||||
|
|
||||||
|
char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
|
||||||
|
{
|
||||||
|
printbuffer p;
|
||||||
|
p.buffer=(char*)cJSON_malloc(prebuffer);
|
||||||
|
p.length=prebuffer;
|
||||||
|
p.offset=0;
|
||||||
|
return print_value(item,0,fmt,&p);
|
||||||
|
return p.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parser core - when encountering text, process appropriately. */
|
||||||
|
static const char *parse_value(cJSON *item,const char *value)
|
||||||
|
{
|
||||||
|
if (!value) return 0; /* Fail on null. */
|
||||||
|
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||||
|
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||||
|
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||||
|
if (*value=='\"') { return parse_string(item,value); }
|
||||||
|
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||||
|
if (*value=='[') { return parse_array(item,value); }
|
||||||
|
if (*value=='{') { return parse_object(item,value); }
|
||||||
|
|
||||||
|
ep=value;return 0; /* failure. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render a value to text. */
|
||||||
|
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
|
||||||
|
{
|
||||||
|
char *out=0;
|
||||||
|
if (!item) return 0;
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
switch ((item->type)&255)
|
||||||
|
{
|
||||||
|
case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;}
|
||||||
|
case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;}
|
||||||
|
case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;}
|
||||||
|
case cJSON_Number: out=print_number(item,p);break;
|
||||||
|
case cJSON_String: out=print_string(item,p);break;
|
||||||
|
case cJSON_Array: out=print_array(item,depth,fmt,p);break;
|
||||||
|
case cJSON_Object: out=print_object(item,depth,fmt,p);break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch ((item->type)&255)
|
||||||
|
{
|
||||||
|
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||||
|
case cJSON_False: out=cJSON_strdup("false");break;
|
||||||
|
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||||
|
case cJSON_Number: out=print_number(item,0);break;
|
||||||
|
case cJSON_String: out=print_string(item,0);break;
|
||||||
|
case cJSON_Array: out=print_array(item,depth,fmt,0);break;
|
||||||
|
case cJSON_Object: out=print_object(item,depth,fmt,0);break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build an array from input text. */
|
||||||
|
static const char *parse_array(cJSON *item,const char *value)
|
||||||
|
{
|
||||||
|
cJSON *child;
|
||||||
|
if (*value!='[') {ep=value;return 0;} /* not an array! */
|
||||||
|
|
||||||
|
item->type=cJSON_Array;
|
||||||
|
value=skip(value+1);
|
||||||
|
if (*value==']') return value+1; /* empty array. */
|
||||||
|
|
||||||
|
item->child=child=cJSON_New_Item();
|
||||||
|
if (!item->child) return 0; /* memory fail */
|
||||||
|
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
|
||||||
|
if (!value) return 0;
|
||||||
|
|
||||||
|
while (*value==',')
|
||||||
|
{
|
||||||
|
cJSON *new_item;
|
||||||
|
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||||
|
child->next=new_item;new_item->prev=child;child=new_item;
|
||||||
|
value=skip(parse_value(child,skip(value+1)));
|
||||||
|
if (!value) return 0; /* memory fail */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*value==']') return value+1; /* end of array */
|
||||||
|
ep=value;return 0; /* malformed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render an array to text */
|
||||||
|
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
|
||||||
|
{
|
||||||
|
char **entries;
|
||||||
|
char *out=0,*ptr,*ret;int len=5;
|
||||||
|
cJSON *child=item->child;
|
||||||
|
int numentries=0,i=0,fail=0;
|
||||||
|
size_t tmplen=0;
|
||||||
|
|
||||||
|
/* How many entries in the array? */
|
||||||
|
while (child) numentries++,child=child->next;
|
||||||
|
/* Explicitly handle numentries==0 */
|
||||||
|
if (!numentries)
|
||||||
|
{
|
||||||
|
if (p) out=ensure(p,3);
|
||||||
|
else out=(char*)cJSON_malloc(3);
|
||||||
|
if (out) strcpy(out,"[]");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
/* Compose the output array. */
|
||||||
|
i=p->offset;
|
||||||
|
ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++;
|
||||||
|
child=item->child;
|
||||||
|
while (child && !fail)
|
||||||
|
{
|
||||||
|
print_value(child,depth+1,fmt,p);
|
||||||
|
p->offset=update(p);
|
||||||
|
if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
|
||||||
|
child=child->next;
|
||||||
|
}
|
||||||
|
ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
|
||||||
|
out=(p->buffer)+i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Allocate an array to hold the values for each */
|
||||||
|
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||||
|
if (!entries) return 0;
|
||||||
|
memset(entries,0,numentries*sizeof(char*));
|
||||||
|
/* Retrieve all the results: */
|
||||||
|
child=item->child;
|
||||||
|
while (child && !fail)
|
||||||
|
{
|
||||||
|
ret=print_value(child,depth+1,fmt,0);
|
||||||
|
entries[i++]=ret;
|
||||||
|
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
|
||||||
|
child=child->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't fail, try to ask_memory the output string */
|
||||||
|
if (!fail) out=(char*)cJSON_malloc(len);
|
||||||
|
/* If that fails, we fail. */
|
||||||
|
if (!out) fail=1;
|
||||||
|
|
||||||
|
/* Handle failure. */
|
||||||
|
if (fail)
|
||||||
|
{
|
||||||
|
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
|
||||||
|
cJSON_free(entries);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compose the output array. */
|
||||||
|
*out='[';
|
||||||
|
ptr=out+1;*ptr=0;
|
||||||
|
for (i=0;i<numentries;i++)
|
||||||
|
{
|
||||||
|
tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
|
||||||
|
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
|
||||||
|
cJSON_free(entries[i]);
|
||||||
|
}
|
||||||
|
cJSON_free(entries);
|
||||||
|
*ptr++=']';*ptr++=0;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build an object from the text. */
|
||||||
|
static const char *parse_object(cJSON *item,const char *value)
|
||||||
|
{
|
||||||
|
cJSON *child;
|
||||||
|
if (*value!='{') {ep=value;return 0;} /* not an object! */
|
||||||
|
|
||||||
|
item->type=cJSON_Object;
|
||||||
|
value=skip(value+1);
|
||||||
|
if (*value=='}') return value+1; /* empty array. */
|
||||||
|
|
||||||
|
item->child=child=cJSON_New_Item();
|
||||||
|
if (!item->child) return 0;
|
||||||
|
value=skip(parse_string(child,skip(value)));
|
||||||
|
if (!value) return 0;
|
||||||
|
child->string=child->valuestring;child->valuestring=0;
|
||||||
|
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||||
|
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||||
|
if (!value) return 0;
|
||||||
|
|
||||||
|
while (*value==',')
|
||||||
|
{
|
||||||
|
cJSON *new_item;
|
||||||
|
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||||
|
child->next=new_item;new_item->prev=child;child=new_item;
|
||||||
|
value=skip(parse_string(child,skip(value+1)));
|
||||||
|
if (!value) return 0;
|
||||||
|
child->string=child->valuestring;child->valuestring=0;
|
||||||
|
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||||
|
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||||
|
if (!value) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*value=='}') return value+1; /* end of array */
|
||||||
|
ep=value;return 0; /* malformed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render an object to text. */
|
||||||
|
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
|
||||||
|
{
|
||||||
|
char **entries=0,**names=0;
|
||||||
|
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
|
||||||
|
cJSON *child=item->child;
|
||||||
|
int numentries=0,fail=0;
|
||||||
|
size_t tmplen=0;
|
||||||
|
/* Count the number of entries. */
|
||||||
|
while (child) numentries++,child=child->next;
|
||||||
|
/* Explicitly handle empty object case */
|
||||||
|
if (!numentries)
|
||||||
|
{
|
||||||
|
if (p) out=ensure(p,fmt?depth+4:3);
|
||||||
|
else out=(char*)cJSON_malloc(fmt?depth+4:3);
|
||||||
|
if (!out) return 0;
|
||||||
|
ptr=out;*ptr++='{';
|
||||||
|
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
|
||||||
|
*ptr++='}';*ptr++=0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
/* Compose the output: */
|
||||||
|
i=p->offset;
|
||||||
|
len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0;
|
||||||
|
*ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len;
|
||||||
|
child=item->child;depth++;
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
if (fmt)
|
||||||
|
{
|
||||||
|
ptr=ensure(p,depth); if (!ptr) return 0;
|
||||||
|
for (j=0;j<depth;j++) *ptr++='\t';
|
||||||
|
p->offset+=depth;
|
||||||
|
}
|
||||||
|
print_string_ptr(child->string,p);
|
||||||
|
p->offset=update(p);
|
||||||
|
|
||||||
|
len=fmt?2:1;
|
||||||
|
ptr=ensure(p,len); if (!ptr) return 0;
|
||||||
|
*ptr++=':';if (fmt) *ptr++='\t';
|
||||||
|
p->offset+=len;
|
||||||
|
|
||||||
|
print_value(child,depth,fmt,p);
|
||||||
|
p->offset=update(p);
|
||||||
|
|
||||||
|
len=(fmt?1:0)+(child->next?1:0);
|
||||||
|
ptr=ensure(p,len+1); if (!ptr) return 0;
|
||||||
|
if (child->next) *ptr++=',';
|
||||||
|
if (fmt) *ptr++='\n';*ptr=0;
|
||||||
|
p->offset+=len;
|
||||||
|
child=child->next;
|
||||||
|
}
|
||||||
|
ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0;
|
||||||
|
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||||
|
*ptr++='}';*ptr=0;
|
||||||
|
out=(p->buffer)+i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Allocate space for the names and the objects */
|
||||||
|
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||||
|
if (!entries) return 0;
|
||||||
|
names=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||||
|
if (!names) {cJSON_free(entries);return 0;}
|
||||||
|
memset(entries,0,sizeof(char*)*numentries);
|
||||||
|
memset(names,0,sizeof(char*)*numentries);
|
||||||
|
|
||||||
|
/* Collect all the results into our arrays: */
|
||||||
|
child=item->child;depth++;if (fmt) len+=depth;
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
names[i]=str=print_string_ptr(child->string,0);
|
||||||
|
entries[i++]=ret=print_value(child,depth,fmt,0);
|
||||||
|
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
|
||||||
|
child=child->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to allocate the output string */
|
||||||
|
if (!fail) out=(char*)cJSON_malloc(len);
|
||||||
|
if (!out) fail=1;
|
||||||
|
|
||||||
|
/* Handle failure */
|
||||||
|
if (fail)
|
||||||
|
{
|
||||||
|
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
|
||||||
|
cJSON_free(names);cJSON_free(entries);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compose the output: */
|
||||||
|
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
|
||||||
|
for (i=0;i<numentries;i++)
|
||||||
|
{
|
||||||
|
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
|
||||||
|
tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
|
||||||
|
*ptr++=':';if (fmt) *ptr++='\t';
|
||||||
|
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||||
|
if (i!=numentries-1) *ptr++=',';
|
||||||
|
if (fmt) *ptr++='\n';*ptr=0;
|
||||||
|
cJSON_free(names[i]);cJSON_free(entries[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_free(names);cJSON_free(entries);
|
||||||
|
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||||
|
*ptr++='}';*ptr++=0;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get Array size/item / object item. */
|
||||||
|
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||||
|
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
|
||||||
|
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||||
|
|
||||||
|
/* Utility for array list handling. */
|
||||||
|
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||||
|
/* Utility for handling references. */
|
||||||
|
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
|
||||||
|
|
||||||
|
/* Add item to array/object. */
|
||||||
|
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||||
|
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||||
|
void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
|
||||||
|
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
|
||||||
|
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
|
||||||
|
|
||||||
|
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
|
||||||
|
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
|
||||||
|
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
|
||||||
|
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
|
||||||
|
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
|
||||||
|
|
||||||
|
/* Replace array/object items with new ones. */
|
||||||
|
void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
|
||||||
|
newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
|
||||||
|
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
|
||||||
|
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
|
||||||
|
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
|
||||||
|
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
|
||||||
|
|
||||||
|
/* Create basic types: */
|
||||||
|
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
|
||||||
|
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
|
||||||
|
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
|
||||||
|
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
|
||||||
|
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
|
||||||
|
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
|
||||||
|
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
|
||||||
|
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
|
||||||
|
|
||||||
|
/* Create Arrays: */
|
||||||
|
cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||||
|
cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||||
|
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||||
|
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||||
|
|
||||||
|
/* Duplication */
|
||||||
|
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
|
||||||
|
{
|
||||||
|
cJSON *newitem,*cptr,*nptr=0,*newchild;
|
||||||
|
/* Bail on bad ptr */
|
||||||
|
if (!item) return 0;
|
||||||
|
/* Create new item */
|
||||||
|
newitem=cJSON_New_Item();
|
||||||
|
if (!newitem) return 0;
|
||||||
|
/* Copy over all vars */
|
||||||
|
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
|
||||||
|
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
|
||||||
|
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
|
||||||
|
/* If non-recursive, then we're done! */
|
||||||
|
if (!recurse) return newitem;
|
||||||
|
/* Walk the ->next chain for the child. */
|
||||||
|
cptr=item->child;
|
||||||
|
while (cptr)
|
||||||
|
{
|
||||||
|
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
|
||||||
|
if (!newchild) {cJSON_Delete(newitem);return 0;}
|
||||||
|
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
|
||||||
|
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
|
||||||
|
cptr=cptr->next;
|
||||||
|
}
|
||||||
|
return newitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cJSON_Minify(char *gb_json)
|
||||||
|
{
|
||||||
|
char *into=gb_json;
|
||||||
|
while (*gb_json)
|
||||||
|
{
|
||||||
|
if (*gb_json==' ') gb_json++;
|
||||||
|
else if (*gb_json=='\t') gb_json++; /* Whitespace characters. */
|
||||||
|
else if (*gb_json=='\r') gb_json++;
|
||||||
|
else if (*gb_json=='\n') gb_json++;
|
||||||
|
else if (*gb_json=='/' && gb_json[1]=='/') while (*gb_json && *gb_json!='\n') gb_json++; /* double-slash comments, to end of line. */
|
||||||
|
else if (*gb_json=='/' && gb_json[1]=='*') {while (*gb_json && !(*gb_json=='*' && gb_json[1]=='/')) gb_json++;gb_json+=2;} /* multiline comments. */
|
||||||
|
else if (*gb_json=='\"'){*into++=*gb_json++;while (*gb_json && *gb_json!='\"'){if (*gb_json=='\\') *into++=*gb_json++;*into++=*gb_json++;}*into++=*gb_json++;} /* string literals, which are \" sensitive. */
|
||||||
|
else *into++=*gb_json++; /* All other characters. */
|
||||||
|
}
|
||||||
|
*into=0; /* and null-terminate. */
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2009 Dave Gamble
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef cJSON__h
|
||||||
|
#define cJSON__h
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* cJSON Types: */
|
||||||
|
#define cJSON_False 0
|
||||||
|
#define cJSON_True 1
|
||||||
|
#define cJSON_NULL 2
|
||||||
|
#define cJSON_Number 3
|
||||||
|
#define cJSON_String 4
|
||||||
|
#define cJSON_Array 5
|
||||||
|
#define cJSON_Object 6
|
||||||
|
|
||||||
|
#define cJSON_IsReference 256
|
||||||
|
#define cJSON_StringIsConst 512
|
||||||
|
|
||||||
|
|
||||||
|
typedef void *(*malloc_fnxx)(size_t sz);
|
||||||
|
typedef void (*free_fnxx)(void *ptr);
|
||||||
|
|
||||||
|
/* The cJSON structure: */
|
||||||
|
typedef struct cJSON {
|
||||||
|
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||||
|
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||||
|
|
||||||
|
int type; /* The type of the item, as above. */
|
||||||
|
|
||||||
|
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||||
|
int valueint; /* The item's number, if type==cJSON_Number */
|
||||||
|
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||||
|
|
||||||
|
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||||
|
} cJSON;
|
||||||
|
|
||||||
|
typedef struct cJSON_Hooks {
|
||||||
|
malloc_fnxx malloc_fn;
|
||||||
|
free_fnxx free_fn;
|
||||||
|
} cJSON_Hooks;
|
||||||
|
|
||||||
|
/* Supply malloc, realloc and free functions to cJSON */
|
||||||
|
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||||
|
|
||||||
|
|
||||||
|
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||||
|
extern cJSON *cJSON_Parse(const char *value);
|
||||||
|
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||||
|
extern char *cJSON_Print(cJSON *item);
|
||||||
|
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||||
|
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||||
|
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||||
|
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
|
||||||
|
/* Delete a cJSON entity and all subentities. */
|
||||||
|
extern void cJSON_Delete(cJSON *c);
|
||||||
|
|
||||||
|
/* Returns the number of items in an array (or object). */
|
||||||
|
extern int cJSON_GetArraySize(cJSON *array);
|
||||||
|
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||||
|
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||||
|
/* Get item "string" from object. Case insensitive. */
|
||||||
|
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||||
|
|
||||||
|
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||||
|
extern const char *cJSON_GetErrorPtr(void);
|
||||||
|
|
||||||
|
/* These calls create a cJSON item of the appropriate type. */
|
||||||
|
extern cJSON *cJSON_CreateNull(void);
|
||||||
|
extern cJSON *cJSON_CreateTrue(void);
|
||||||
|
extern cJSON *cJSON_CreateFalse(void);
|
||||||
|
extern cJSON *cJSON_CreateBool(int b);
|
||||||
|
extern cJSON *cJSON_CreateNumber(double num);
|
||||||
|
extern cJSON *cJSON_CreateString(const char *string);
|
||||||
|
extern cJSON *cJSON_CreateArray(void);
|
||||||
|
extern cJSON *cJSON_CreateObject(void);
|
||||||
|
|
||||||
|
/* These utilities create an Array of count items. */
|
||||||
|
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
|
||||||
|
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
|
||||||
|
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
|
||||||
|
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||||
|
|
||||||
|
/* Append item to the specified array/object. */
|
||||||
|
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||||
|
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||||
|
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
|
||||||
|
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||||
|
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||||
|
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||||
|
|
||||||
|
/* Remove/Detatch items from Arrays/Objects. */
|
||||||
|
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||||
|
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||||
|
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||||
|
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||||
|
|
||||||
|
/* Update array items. */
|
||||||
|
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||||
|
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||||
|
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||||
|
|
||||||
|
/* Duplicate a cJSON item */
|
||||||
|
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
|
||||||
|
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||||
|
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||||
|
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||||
|
|
||||||
|
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||||
|
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
|
||||||
|
|
||||||
|
extern void cJSON_Minify(char *gb_json);
|
||||||
|
|
||||||
|
// convert e681a2 to \u6062, call 'free' to free the returned value
|
||||||
|
extern char* cJSON_utf8_2_unic(const char* utf8);
|
||||||
|
|
||||||
|
/* Macros for creating things quickly. */
|
||||||
|
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||||
|
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||||
|
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||||
|
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||||
|
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||||
|
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||||
|
|
||||||
|
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||||
|
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||||
|
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,962 @@
|
||||||
|
#include "gb_json.h"
|
||||||
|
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace special_char_trans
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char* writedown_text;
|
||||||
|
char readable_char;
|
||||||
|
}transferred_chars[] = { { "\\\"", '\"' }
|
||||||
|
, { "\\'", '\'' }
|
||||||
|
, { "\\a", '\a' }
|
||||||
|
, { "\\b", '\b' }
|
||||||
|
, { "\\f", '\f' }
|
||||||
|
, { "\\n", '\n' }
|
||||||
|
, { "\\r", '\r' }
|
||||||
|
, { "\\t", '\t' }
|
||||||
|
, { "\\v", '\v' }
|
||||||
|
// , { "\\?", '\?' }
|
||||||
|
, { "\\\\", '\\' }
|
||||||
|
, { "\\/", '/' }
|
||||||
|
// , { "\\0", '\0' }
|
||||||
|
};
|
||||||
|
|
||||||
|
void to_writedown(std::string& str)
|
||||||
|
{
|
||||||
|
std::string trans(str);
|
||||||
|
const char* ptr = trans.c_str();
|
||||||
|
|
||||||
|
str.clear();
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
|
bool rep = false;
|
||||||
|
if (*ptr == '\\')
|
||||||
|
{
|
||||||
|
if (ptr[1] == '\\')
|
||||||
|
{
|
||||||
|
str += "\\\\";
|
||||||
|
ptr++;
|
||||||
|
rep = true;
|
||||||
|
}
|
||||||
|
else if( ptr[1] == '/' ||
|
||||||
|
ptr[1] == 'a' ||
|
||||||
|
ptr[1] == 'b' ||
|
||||||
|
ptr[1] == 'f' ||
|
||||||
|
ptr[1] == 'n' ||
|
||||||
|
ptr[1] == 'r' ||
|
||||||
|
ptr[1] == 't' ||
|
||||||
|
ptr[1] == 'u' ||
|
||||||
|
ptr[1] == 'v')
|
||||||
|
{
|
||||||
|
str += "\\";
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str += "\\\\";
|
||||||
|
rep = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeof(transferred_chars) / sizeof(transferred_chars[0]); ++i)
|
||||||
|
{
|
||||||
|
if (*ptr == transferred_chars[i].readable_char)
|
||||||
|
{
|
||||||
|
str += transferred_chars[i].writedown_text;
|
||||||
|
rep = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rep)
|
||||||
|
str.append(1, *ptr);
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// life callback ...
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
static void record_life_empty(gb_json*, bool, void*)
|
||||||
|
{}
|
||||||
|
static void(*g_life)(gb_json*, bool, void*) = &record_life_empty;
|
||||||
|
static void* g_life_param = nullptr;
|
||||||
|
|
||||||
|
void set_gbjson_life_callback(void(*life)(gb_json*, bool, void*), void* param)
|
||||||
|
{
|
||||||
|
g_life_param = param;
|
||||||
|
g_life = life ? life : &record_life_empty;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// gb_json ...
|
||||||
|
gb_json::gb_json(char* json_txt) : ref_(1), type_(VAL_TYPE_OBJECT), key_(""), strval_(""), cur_child_(-1)
|
||||||
|
{
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, true, g_life_param);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
simple_val_.dval = .0f;
|
||||||
|
if(json_txt)
|
||||||
|
attach_text(json_txt);
|
||||||
|
}
|
||||||
|
gb_json::gb_json(const char* key, bool val) : ref_(1), type_(VAL_TYPE_BOOL), key_(key ? key : ""), strval_(""), cur_child_(-1)
|
||||||
|
{
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, true, g_life_param);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
simple_val_.bval = val;
|
||||||
|
}
|
||||||
|
gb_json::gb_json(const char* key, int val) : ref_(1), type_(VAL_TYPE_INT), key_(key ? key : ""), strval_(""), cur_child_(-1)
|
||||||
|
{
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, true, g_life_param);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
simple_val_.nval = val;
|
||||||
|
}
|
||||||
|
gb_json::gb_json(const char* key, double val) : ref_(1), type_(VAL_TYPE_FLOAT), key_(key ? key : ""), strval_(""), cur_child_(-1)
|
||||||
|
{
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, true, g_life_param);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
simple_val_.dval = val;
|
||||||
|
}
|
||||||
|
gb_json::gb_json(const char* key, const char* val) : ref_(1), type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val ? val : ""), cur_child_(-1)
|
||||||
|
{
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, true, g_life_param);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
gb_json::gb_json(const char* key, const std::string& val) : ref_(1), type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val), cur_child_(-1)
|
||||||
|
{
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, true, g_life_param);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
gb_json::~gb_json()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
g_life(this, false, g_life_param);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gb_json::object_key(gb_json* jsn)
|
||||||
|
{
|
||||||
|
return "\"" + jsn->key() + "\":";
|
||||||
|
}
|
||||||
|
std::string gb_json::array_key(gb_json* jsn)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void gb_json::from_cjson(cJSON* cj)
|
||||||
|
{
|
||||||
|
key_ = cj && cj->string ? cj->string : "";
|
||||||
|
while (cj)
|
||||||
|
{
|
||||||
|
gb_json* child = nullptr;
|
||||||
|
if (cj->type == cJSON_True)
|
||||||
|
{
|
||||||
|
child = new gb_json(cj->string, true);
|
||||||
|
}
|
||||||
|
else if(cj->type == cJSON_False)
|
||||||
|
{
|
||||||
|
child = new gb_json(cj->string, false);
|
||||||
|
}
|
||||||
|
else if (cj->type == cJSON_Number)
|
||||||
|
{
|
||||||
|
if (cj->valuedouble - (int)cj->valuedouble < .00001)
|
||||||
|
{
|
||||||
|
child = new gb_json(cj->string, cj->valueint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = new gb_json(cj->string, cj->valuedouble);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cj->type == cJSON_String)
|
||||||
|
{
|
||||||
|
child = new gb_json(cj->string, cj->valuestring);
|
||||||
|
}
|
||||||
|
else if (cj->type == cJSON_Object || cj->type == cJSON_Array)
|
||||||
|
{
|
||||||
|
child = new gb_json();
|
||||||
|
child->from_cjson(cj->child);
|
||||||
|
child->key_ = cj->string ? cj->string : "";
|
||||||
|
if (child->key_.empty())
|
||||||
|
child->type_ = VAL_TYPE_OBJECT;
|
||||||
|
}
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
cj = cj->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (arr_val_.size() == 1 && arr_val_[0]->arr_val_.size() == 0)
|
||||||
|
//{
|
||||||
|
// gb_json* child = arr_val_[0];
|
||||||
|
//
|
||||||
|
// if (!child->key_.empty()) // array
|
||||||
|
// {
|
||||||
|
// arr_val_.clear();
|
||||||
|
// type_ = child->type_;
|
||||||
|
// key_ = child->key_;
|
||||||
|
// simple_val_.dval = child->simple_val_.dval;
|
||||||
|
// strval_ = child->strval_;
|
||||||
|
// for (auto& v : child->arr_val_)
|
||||||
|
// arr_val_.push_back(v);
|
||||||
|
// child->arr_val_.clear();
|
||||||
|
// child->release();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (arr_val_.size())
|
||||||
|
{
|
||||||
|
type_ = arr_val_[0]->key().empty() ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gb_json* gb_json::find_child(const char* key, bool remove)
|
||||||
|
{
|
||||||
|
gb_json* ret = nullptr;
|
||||||
|
|
||||||
|
if (type_ == VAL_TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < arr_val_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (arr_val_[i]->key() == key)
|
||||||
|
{
|
||||||
|
ret = arr_val_[i];
|
||||||
|
if (remove)
|
||||||
|
arr_val_.erase(arr_val_.begin() + i);
|
||||||
|
else
|
||||||
|
ret->add_ref();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t gb_json::add_ref()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(ref_mutex_);
|
||||||
|
int32_t ref = ++ref_;
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
int32_t gb_json::release()
|
||||||
|
{
|
||||||
|
int32_t ref = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(ref_mutex_);
|
||||||
|
ref = --ref_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref == 0)
|
||||||
|
delete this;
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_cJSON(cJSON* root, std::vector<cJSON*>* existing)
|
||||||
|
{
|
||||||
|
if (!root)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& v : *existing)
|
||||||
|
{
|
||||||
|
if (v == root)
|
||||||
|
{
|
||||||
|
printf("cJSON* 0x%08x is repeat!\n", v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
existing->push_back(root);
|
||||||
|
check_cJSON(root->child, existing);
|
||||||
|
|
||||||
|
cJSON* next = root->next;
|
||||||
|
while (next)
|
||||||
|
{
|
||||||
|
check_cJSON(next, existing);
|
||||||
|
next = next->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool gb_json::attach_text(char* json_txt)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
cJSON* jsn = cJSON_Parse(json_txt);
|
||||||
|
if (jsn)
|
||||||
|
{
|
||||||
|
char *text = cJSON_Print(jsn);
|
||||||
|
if (text)
|
||||||
|
{
|
||||||
|
if (0)
|
||||||
|
{
|
||||||
|
FILE* dst = fopen("e:\\test-json.txt", "wb");
|
||||||
|
fwrite(text, 1, strlen(text), dst);
|
||||||
|
fclose(dst);
|
||||||
|
}
|
||||||
|
free(text);
|
||||||
|
}
|
||||||
|
std::vector<cJSON*> repeat;
|
||||||
|
|
||||||
|
if(0)
|
||||||
|
check_cJSON(jsn, &repeat);
|
||||||
|
from_cjson(jsn->child);
|
||||||
|
cJSON_Delete(jsn);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void gb_json::clear(bool as_array)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
for (auto& v : arr_val_)
|
||||||
|
v->release();
|
||||||
|
}
|
||||||
|
type_ = as_array ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT;
|
||||||
|
simple_val_.dval = .0f;
|
||||||
|
key_ = "";
|
||||||
|
strval_ = "";
|
||||||
|
arr_val_.clear();
|
||||||
|
cur_child_ = -1;
|
||||||
|
}
|
||||||
|
std::string gb_json::to_string(void)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_NULL)
|
||||||
|
return "";
|
||||||
|
if (type_ == VAL_TYPE_BOOL)
|
||||||
|
return (simple_val_.bval ? "true" : "false");
|
||||||
|
if (type_ == VAL_TYPE_INT)
|
||||||
|
return std::to_string(simple_val_.nval);
|
||||||
|
if (type_ == VAL_TYPE_FLOAT)
|
||||||
|
return std::to_string(simple_val_.dval);
|
||||||
|
if (type_ == VAL_TYPE_STRING)
|
||||||
|
{
|
||||||
|
char* u = cJSON_utf8_2_unic(strval_.c_str());
|
||||||
|
std::string r(u);
|
||||||
|
|
||||||
|
free(u);
|
||||||
|
special_char_trans::to_writedown(r);
|
||||||
|
|
||||||
|
return "\"" + r + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string(*k)(gb_json*) = type_ == VAL_TYPE_OBJECT ? gb_json::object_key : gb_json::array_key;
|
||||||
|
std::string str(type_ == VAL_TYPE_OBJECT ? "{" : "[");
|
||||||
|
|
||||||
|
if (arr_val_.size())
|
||||||
|
{
|
||||||
|
str += k(arr_val_[0]) + arr_val_[0]->to_string();
|
||||||
|
for(size_t i = 1; i < arr_val_.size(); ++i)
|
||||||
|
str += "," + k(arr_val_[i]) + arr_val_[i]->to_string();
|
||||||
|
}
|
||||||
|
str += type_ == VAL_TYPE_OBJECT ? "}" : "]";
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& gb_json::key(void)
|
||||||
|
{
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
bool gb_json::is_array(void)
|
||||||
|
{
|
||||||
|
return type_ == VAL_TYPE_ARRAY;
|
||||||
|
}
|
||||||
|
bool gb_json::is_leaf_node(void)
|
||||||
|
{
|
||||||
|
return type_ == VAL_TYPE_BOOL ||
|
||||||
|
type_ == VAL_TYPE_INT ||
|
||||||
|
type_ == VAL_TYPE_FLOAT ||
|
||||||
|
type_ == VAL_TYPE_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gb_json::get_value(const char* key, bool& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
if (child->type_ == VAL_TYPE_BOOL)
|
||||||
|
{
|
||||||
|
val = child->simple_val_.bval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else if (type_ == VAL_TYPE_BOOL && key_ == key)
|
||||||
|
{
|
||||||
|
val = simple_val_.bval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::get_value(const char* key, int& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
if (child->type_ == VAL_TYPE_INT)
|
||||||
|
{
|
||||||
|
val = child->simple_val_.nval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else if (type_ == VAL_TYPE_INT && key_ == key)
|
||||||
|
{
|
||||||
|
val = simple_val_.nval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::get_value(const char* key, double& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
if (child->type_ == VAL_TYPE_FLOAT)
|
||||||
|
{
|
||||||
|
val = child->simple_val_.dval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else if (type_ == VAL_TYPE_FLOAT && key_ == key)
|
||||||
|
{
|
||||||
|
val = simple_val_.dval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// added on 2023-04-27: for cJSON consider both int and float as CJSON_Number, we consider int if the value is just an integer
|
||||||
|
if(!ret)
|
||||||
|
{
|
||||||
|
int v = 0;
|
||||||
|
ret = get_value(key, v);
|
||||||
|
if(ret)
|
||||||
|
val = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::get_value(const char* key, std::string& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
if (child->type_ == VAL_TYPE_STRING)
|
||||||
|
{
|
||||||
|
val = child->strval_;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else if (type_ == VAL_TYPE_STRING && key_ == key)
|
||||||
|
{
|
||||||
|
val = strval_;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::get_value(const char* key, gb_json*& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
gb_json *child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
if (child->type_ == VAL_TYPE_OBJECT || child->type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
val = child;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gb_json::children(void)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
|
||||||
|
return arr_val_.size();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gb_json* gb_json::child(size_t ind)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
if (ind >= 0 && ind < arr_val_.size())
|
||||||
|
{
|
||||||
|
arr_val_[ind]->add_ref();
|
||||||
|
|
||||||
|
return arr_val_[ind];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
gb_json* gb_json::first_child(void)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
cur_child_ = 0;
|
||||||
|
if (arr_val_.size())
|
||||||
|
{
|
||||||
|
arr_val_[0]->add_ref();
|
||||||
|
|
||||||
|
return arr_val_[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
gb_json* gb_json::next_child(void)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
if (++cur_child_ < arr_val_.size())
|
||||||
|
{
|
||||||
|
arr_val_[cur_child_]->add_ref();
|
||||||
|
|
||||||
|
return arr_val_[cur_child_];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gb_json::set_value(const char* key, bool val)
|
||||||
|
{
|
||||||
|
if (type_ != VAL_TYPE_OBJECT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->clear();
|
||||||
|
child->type_ = VAL_TYPE_BOOL;
|
||||||
|
child->key() = key ? key : "";
|
||||||
|
child->simple_val_.bval = val;
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = new gb_json(key, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool gb_json::set_value(const char* key, int val)
|
||||||
|
{
|
||||||
|
if (type_ != VAL_TYPE_OBJECT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->clear();
|
||||||
|
child->type_ = VAL_TYPE_INT;
|
||||||
|
child->key() = key ? key : "";
|
||||||
|
child->simple_val_.nval = val;
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = new gb_json(key, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool gb_json::set_value(const char* key, double val)
|
||||||
|
{
|
||||||
|
if (type_ != VAL_TYPE_OBJECT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->clear();
|
||||||
|
child->type_ = VAL_TYPE_FLOAT;
|
||||||
|
child->key() = key ? key : "";
|
||||||
|
child->simple_val_.dval = val;
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = new gb_json(key, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool gb_json::set_value(const char* key, const char* val)
|
||||||
|
{
|
||||||
|
if (type_ != VAL_TYPE_OBJECT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gb_json* child = find_child(key);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->clear();
|
||||||
|
child->type_ = VAL_TYPE_STRING;
|
||||||
|
child->key() = key ? key : "";
|
||||||
|
child->strval_ = val ? val : "";
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = new gb_json(key, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool gb_json::set_value(const char* key, gb_json* val)
|
||||||
|
{
|
||||||
|
if (type_ != VAL_TYPE_OBJECT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arr_val_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (arr_val_[i]->key() == key)
|
||||||
|
{
|
||||||
|
arr_val_[i]->release();
|
||||||
|
arr_val_[i] = val;
|
||||||
|
val->add_ref();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arr_val_.push_back(val);
|
||||||
|
val->key() = key;
|
||||||
|
val->add_ref();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_json& gb_json::operator+=(bool val)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
gb_json* child = new gb_json(nullptr, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator+=(int val)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
gb_json* child = new gb_json(nullptr, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator+=(double val)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
gb_json* child = new gb_json(nullptr, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator+=(const char* val)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
gb_json* child = new gb_json(nullptr, val);
|
||||||
|
arr_val_.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator+=(gb_json* val)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
val->add_ref();
|
||||||
|
arr_val_.push_back(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_json& gb_json::operator-=(int ind)
|
||||||
|
{
|
||||||
|
remove(ind);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool gb_json::remove(const char* key)
|
||||||
|
{
|
||||||
|
gb_json* child = find_child(key, true);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->release();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool gb_json::remove(gb_json* child)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < arr_val_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (arr_val_[i] == child)
|
||||||
|
{
|
||||||
|
arr_val_[i]->release();
|
||||||
|
arr_val_.erase(arr_val_.begin() + i);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool gb_json::remove(int ind)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
if (ind >= 0 && ind < arr_val_.size())
|
||||||
|
{
|
||||||
|
arr_val_[ind]->release();
|
||||||
|
arr_val_.erase(arr_val_.begin() + ind);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gb_json::index(gb_json* child)
|
||||||
|
{
|
||||||
|
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < arr_val_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (arr_val_[i] == child)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int gb_json::index_move_to(gb_json* child, int ind)
|
||||||
|
{
|
||||||
|
int i = index(child);
|
||||||
|
|
||||||
|
if (i == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
arr_val_.erase(arr_val_.begin() + i);
|
||||||
|
if (ind < 0)
|
||||||
|
ind = 0;
|
||||||
|
if (ind > arr_val_.size())
|
||||||
|
ind = arr_val_.size();
|
||||||
|
arr_val_.insert(arr_val_.begin() + ind, child);
|
||||||
|
|
||||||
|
return ind;
|
||||||
|
}
|
||||||
|
int gb_json::insert(int ind, const char* key, gb_json* child)
|
||||||
|
{
|
||||||
|
int i = index(child);
|
||||||
|
|
||||||
|
if (i == -1)
|
||||||
|
{
|
||||||
|
if (ind < 0)
|
||||||
|
ind = 0;
|
||||||
|
else if (ind > arr_val_.size())
|
||||||
|
ind = arr_val_.size();
|
||||||
|
|
||||||
|
child->key() = key ? key : "";
|
||||||
|
arr_val_.insert(arr_val_.begin() + ind, child);
|
||||||
|
child->add_ref();
|
||||||
|
}
|
||||||
|
else if(i != ind)
|
||||||
|
{
|
||||||
|
arr_val_.erase(arr_val_.begin() + i);
|
||||||
|
if (ind < 0)
|
||||||
|
ind = 0;
|
||||||
|
if (ind > arr_val_.size())
|
||||||
|
ind = arr_val_.size();
|
||||||
|
child->key() = key ? key : "";
|
||||||
|
arr_val_.insert(arr_val_.begin() + ind, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gb_json::value(bool& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (is_leaf_node() && type_ == VAL_TYPE_BOOL)
|
||||||
|
{
|
||||||
|
val = simple_val_.bval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::value(int& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (is_leaf_node() && type_ == VAL_TYPE_INT)
|
||||||
|
{
|
||||||
|
val = simple_val_.nval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::value(double& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (is_leaf_node() && type_ == VAL_TYPE_FLOAT)
|
||||||
|
{
|
||||||
|
val = simple_val_.dval;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool gb_json::value(std::string& val)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (is_leaf_node() && type_ == VAL_TYPE_STRING)
|
||||||
|
{
|
||||||
|
val = strval_;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator=(bool val)
|
||||||
|
{
|
||||||
|
if (is_leaf_node())
|
||||||
|
{
|
||||||
|
simple_val_.bval = val;
|
||||||
|
type_ = VAL_TYPE_BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator=(int val)
|
||||||
|
{
|
||||||
|
if (is_leaf_node())
|
||||||
|
{
|
||||||
|
simple_val_.nval = val;
|
||||||
|
type_ = VAL_TYPE_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator=(double val)
|
||||||
|
{
|
||||||
|
if (is_leaf_node())
|
||||||
|
{
|
||||||
|
simple_val_.dval = val;
|
||||||
|
type_ = VAL_TYPE_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
gb_json& gb_json::operator=(const char* val)
|
||||||
|
{
|
||||||
|
if (is_leaf_node())
|
||||||
|
{
|
||||||
|
strval_ = val ? val : "";
|
||||||
|
type_ = VAL_TYPE_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gb_json::operator==(const gb_json& r)
|
||||||
|
{
|
||||||
|
if (type_ != r.type_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (type_ == VAL_TYPE_BOOL)
|
||||||
|
return simple_val_.bval == r.simple_val_.bval;
|
||||||
|
if (type_ == VAL_TYPE_INT)
|
||||||
|
return simple_val_.nval == r.simple_val_.nval;
|
||||||
|
if (type_ == VAL_TYPE_FLOAT)
|
||||||
|
return fabs(simple_val_.dval - r.simple_val_.dval) < .00001;
|
||||||
|
if (type_ == VAL_TYPE_STRING)
|
||||||
|
return strval_ == r.strval_;
|
||||||
|
if (arr_val_.size() != r.arr_val_.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < arr_val_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!(*arr_val_[i] == *r.arr_val_[i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool gb_json::operator!=(const gb_json& r)
|
||||||
|
{
|
||||||
|
return !(*this == r);
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
struct cJSON;
|
||||||
|
|
||||||
|
class gb_json
|
||||||
|
{
|
||||||
|
volatile int32_t ref_;
|
||||||
|
std::mutex ref_mutex_;
|
||||||
|
|
||||||
|
enum val_type
|
||||||
|
{
|
||||||
|
VAL_TYPE_NULL = 0,
|
||||||
|
VAL_TYPE_BOOL,
|
||||||
|
VAL_TYPE_INT,
|
||||||
|
VAL_TYPE_FLOAT,
|
||||||
|
VAL_TYPE_STRING,
|
||||||
|
VAL_TYPE_OBJECT,
|
||||||
|
VAL_TYPE_ARRAY,
|
||||||
|
};
|
||||||
|
val_type type_;
|
||||||
|
std::string key_;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool bval;
|
||||||
|
int nval;
|
||||||
|
double dval;
|
||||||
|
}simple_val_;
|
||||||
|
std::string strval_;
|
||||||
|
std::vector<gb_json*> arr_val_;
|
||||||
|
size_t cur_child_;
|
||||||
|
|
||||||
|
static std::string object_key(gb_json* jsn);
|
||||||
|
static std::string array_key(gb_json* jsn);
|
||||||
|
|
||||||
|
void from_cjson(cJSON* cj);
|
||||||
|
gb_json* find_child(const char* key, bool remove = false);
|
||||||
|
|
||||||
|
public:
|
||||||
|
gb_json(char* json_txt = 0);
|
||||||
|
gb_json(const char* key, bool val);
|
||||||
|
gb_json(const char* key, int val);
|
||||||
|
gb_json(const char* key, double val);
|
||||||
|
gb_json(const char* key, const char* val);
|
||||||
|
gb_json(const char* key, const std::string& val);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~gb_json();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int32_t add_ref();
|
||||||
|
int32_t release();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// parse/un-parse ...
|
||||||
|
bool attach_text(char* json_txt);
|
||||||
|
void clear(bool as_array = false);
|
||||||
|
std::string to_string(void);
|
||||||
|
|
||||||
|
// attributes ...
|
||||||
|
std::string& key(void);
|
||||||
|
bool is_array(void);
|
||||||
|
bool is_leaf_node(void); // whether this object is a leaf node contains final value
|
||||||
|
|
||||||
|
// value access ...
|
||||||
|
bool get_value(const char* key, bool& val);
|
||||||
|
bool get_value(const char* key, int& val);
|
||||||
|
bool get_value(const char* key, double& val);
|
||||||
|
bool get_value(const char* key, std::string& val);
|
||||||
|
bool get_value(const char* key, gb_json*& val);
|
||||||
|
|
||||||
|
// enumeration ...
|
||||||
|
size_t children(void); // return children count if was object or array, or else -1 returned
|
||||||
|
gb_json* child(size_t ind);
|
||||||
|
gb_json* first_child(void);
|
||||||
|
gb_json* next_child(void);
|
||||||
|
|
||||||
|
// change the item matching 'key', otherwise add a new item
|
||||||
|
bool set_value(const char* key, bool val);
|
||||||
|
bool set_value(const char* key, int val);
|
||||||
|
bool set_value(const char* key, double val);
|
||||||
|
bool set_value(const char* key, const char* val);
|
||||||
|
bool set_value(const char* key, gb_json* val);
|
||||||
|
|
||||||
|
// operator+= only for array
|
||||||
|
gb_json& operator+=(bool val);
|
||||||
|
gb_json& operator+=(int val);
|
||||||
|
gb_json& operator+=(double val);
|
||||||
|
gb_json& operator+=(const char* val);
|
||||||
|
gb_json& operator+=(gb_json* val);
|
||||||
|
|
||||||
|
// remove item
|
||||||
|
gb_json& operator-=(int ind);
|
||||||
|
bool remove(const char* key);
|
||||||
|
bool remove(gb_json* child);
|
||||||
|
bool remove(int ind);
|
||||||
|
|
||||||
|
// position management, return index
|
||||||
|
int index(gb_json* child);
|
||||||
|
int index_move_to(gb_json* child, int ind);
|
||||||
|
int insert(int ind, const char* key, gb_json* child);
|
||||||
|
|
||||||
|
// leaf node value ...
|
||||||
|
bool value(bool& val);
|
||||||
|
bool value(int& val);
|
||||||
|
bool value(double& val);
|
||||||
|
bool value(std::string& val);
|
||||||
|
gb_json& operator=(bool val);
|
||||||
|
gb_json& operator=(int val);
|
||||||
|
gb_json& operator=(double val);
|
||||||
|
gb_json& operator=(const char* val);
|
||||||
|
|
||||||
|
bool operator==(const gb_json& r);
|
||||||
|
bool operator!=(const gb_json& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef DUMP_JSON_OBJECT_LIFE
|
||||||
|
void set_gbjson_life_callback(void(*life)(gb_json*, bool, void*), void* param);
|
||||||
|
#endif
|
|
@ -0,0 +1,252 @@
|
||||||
|
/* sane - Scanner Access Now Easy.
|
||||||
|
Copyright (C) 1997-1999 David Mosberger-Tang and Andreas Beck
|
||||||
|
This file is part of the SANE package.
|
||||||
|
|
||||||
|
This file is in the public domain. You may use and modify it as
|
||||||
|
you see fit, as long as this copyright message is included and
|
||||||
|
that there is an indication as to what modifications have been
|
||||||
|
made (if any).
|
||||||
|
|
||||||
|
SANE is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
This file declares SANE application interface. See the SANE
|
||||||
|
standard for a detailed explanation of the interface. */
|
||||||
|
#ifndef sane_h
|
||||||
|
#define sane_h
|
||||||
|
|
||||||
|
#ifndef BACKEND_NAME
|
||||||
|
#define BACKEND_NAME hgsane
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SANE types and defines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SANE_CURRENT_MAJOR 1
|
||||||
|
#define SANE_CURRENT_MINOR 0
|
||||||
|
|
||||||
|
#define SANE_VERSION_CODE(major, minor, build) \
|
||||||
|
( (((SANE_Word) (major) & 0xff) << 24) \
|
||||||
|
| (((SANE_Word) (minor) & 0xff) << 16) \
|
||||||
|
| (((SANE_Word) (build) & 0xffff) << 0))
|
||||||
|
|
||||||
|
#define SANE_VERSION_MAJOR(code) ((((SANE_Word)(code)) >> 24) & 0xff)
|
||||||
|
#define SANE_VERSION_MINOR(code) ((((SANE_Word)(code)) >> 16) & 0xff)
|
||||||
|
#define SANE_VERSION_BUILD(code) ((((SANE_Word)(code)) >> 0) & 0xffff)
|
||||||
|
|
||||||
|
#define SANE_FALSE 0
|
||||||
|
#define SANE_TRUE 1
|
||||||
|
|
||||||
|
typedef unsigned char SANE_Byte;
|
||||||
|
typedef int SANE_Word;
|
||||||
|
typedef SANE_Word SANE_Bool;
|
||||||
|
typedef SANE_Word SANE_Int;
|
||||||
|
typedef char SANE_Char;
|
||||||
|
typedef SANE_Char *SANE_String;
|
||||||
|
typedef const SANE_Char *SANE_String_Const;
|
||||||
|
typedef void *SANE_Handle;
|
||||||
|
typedef SANE_Word SANE_Fixed;
|
||||||
|
|
||||||
|
#define SANE_FIXED_SCALE_SHIFT 16
|
||||||
|
#define SANE_FIX(v) ((SANE_Word) ((v) * (1 << SANE_FIXED_SCALE_SHIFT)))
|
||||||
|
#define SANE_UNFIX(v) ((double)(v) / (1 << SANE_FIXED_SCALE_SHIFT))
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_STATUS_GOOD = 0, /* everything A-OK */
|
||||||
|
SANE_STATUS_UNSUPPORTED, /* operation is not supported */
|
||||||
|
SANE_STATUS_CANCELLED, /* operation was cancelled */
|
||||||
|
SANE_STATUS_DEVICE_BUSY, /* device is busy; try again later */
|
||||||
|
SANE_STATUS_INVAL, /* data is invalid (includes no dev at open) */
|
||||||
|
SANE_STATUS_EOF, /* no more data available (end-of-file) */
|
||||||
|
SANE_STATUS_JAMMED, /* document feeder jammed */
|
||||||
|
SANE_STATUS_NO_DOCS, /* document feeder out of documents */
|
||||||
|
SANE_STATUS_COVER_OPEN, /* scanner cover is open */
|
||||||
|
SANE_STATUS_IO_ERROR, /* error during device I/O */
|
||||||
|
SANE_STATUS_NO_MEM, /* out of memory */
|
||||||
|
SANE_STATUS_ACCESS_DENIED /* access to resource has been denied */
|
||||||
|
}
|
||||||
|
SANE_Status;
|
||||||
|
|
||||||
|
/* following are for later sane version, older frontends wont support */
|
||||||
|
#if 0
|
||||||
|
#define SANE_STATUS_WARMING_UP 12 /* lamp not ready, please retry */
|
||||||
|
#define SANE_STATUS_HW_LOCKED 13 /* scanner mechanism locked for transport */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_TYPE_BOOL = 0,
|
||||||
|
SANE_TYPE_INT,
|
||||||
|
SANE_TYPE_FIXED,
|
||||||
|
SANE_TYPE_STRING,
|
||||||
|
SANE_TYPE_BUTTON,
|
||||||
|
SANE_TYPE_GROUP
|
||||||
|
}
|
||||||
|
SANE_Value_Type;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_UNIT_NONE = 0, /* the value is unit-less (e.g., # of scans) */
|
||||||
|
SANE_UNIT_PIXEL, /* value is number of pixels */
|
||||||
|
SANE_UNIT_BIT, /* value is number of bits */
|
||||||
|
SANE_UNIT_MM, /* value is millimeters */
|
||||||
|
SANE_UNIT_DPI, /* value is resolution in dots/inch */
|
||||||
|
SANE_UNIT_PERCENT, /* value is a percentage */
|
||||||
|
SANE_UNIT_MICROSECOND /* value is micro seconds */
|
||||||
|
}
|
||||||
|
SANE_Unit;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_String_Const name; /* unique device name */
|
||||||
|
SANE_String_Const vendor; /* device vendor string */
|
||||||
|
SANE_String_Const model; /* device model name */
|
||||||
|
SANE_String_Const type; /* device type (e.g., "flatbed scanner") */
|
||||||
|
}
|
||||||
|
SANE_Device;
|
||||||
|
|
||||||
|
#define SANE_CAP_SOFT_SELECT (1 << 0)
|
||||||
|
#define SANE_CAP_HARD_SELECT (1 << 1)
|
||||||
|
#define SANE_CAP_SOFT_DETECT (1 << 2)
|
||||||
|
#define SANE_CAP_EMULATED (1 << 3)
|
||||||
|
#define SANE_CAP_AUTOMATIC (1 << 4)
|
||||||
|
#define SANE_CAP_INACTIVE (1 << 5)
|
||||||
|
#define SANE_CAP_ADVANCED (1 << 6)
|
||||||
|
|
||||||
|
#define SANE_OPTION_IS_ACTIVE(cap) (((cap) & SANE_CAP_INACTIVE) == 0)
|
||||||
|
#define SANE_OPTION_IS_SETTABLE(cap) (((cap) & SANE_CAP_SOFT_SELECT) != 0)
|
||||||
|
|
||||||
|
#define SANE_INFO_INEXACT (1 << 0)
|
||||||
|
#define SANE_INFO_RELOAD_OPTIONS (1 << 1)
|
||||||
|
#define SANE_INFO_RELOAD_PARAMS (1 << 2)
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_CONSTRAINT_NONE = 0,
|
||||||
|
SANE_CONSTRAINT_RANGE,
|
||||||
|
SANE_CONSTRAINT_WORD_LIST,
|
||||||
|
SANE_CONSTRAINT_STRING_LIST
|
||||||
|
}
|
||||||
|
SANE_Constraint_Type;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_Word min; /* minimum (element) value */
|
||||||
|
SANE_Word max; /* maximum (element) value */
|
||||||
|
SANE_Word quant; /* quantization value (0 if none) */
|
||||||
|
}
|
||||||
|
SANE_Range;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_String_Const name; /* name of this option (command-line name) */
|
||||||
|
SANE_String_Const title; /* title of this option (single-line) */
|
||||||
|
SANE_String_Const desc; /* description of this option (multi-line) */
|
||||||
|
SANE_Value_Type type; /* how are values interpreted? */
|
||||||
|
SANE_Unit unit; /* what is the (physical) unit? */
|
||||||
|
SANE_Int size;
|
||||||
|
SANE_Int cap; /* capabilities */
|
||||||
|
|
||||||
|
SANE_Constraint_Type constraint_type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
const SANE_String_Const *string_list; /* NULL-terminated list */
|
||||||
|
const SANE_Word *word_list; /* first element is list-length */
|
||||||
|
const SANE_Range *range;
|
||||||
|
}
|
||||||
|
constraint;
|
||||||
|
}
|
||||||
|
SANE_Option_Descriptor;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_ACTION_GET_VALUE = 0,
|
||||||
|
SANE_ACTION_SET_VALUE,
|
||||||
|
SANE_ACTION_SET_AUTO
|
||||||
|
}
|
||||||
|
SANE_Action;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_FRAME_GRAY, /* band covering human visual range */
|
||||||
|
SANE_FRAME_RGB, /* pixel-interleaved red/green/blue bands */
|
||||||
|
SANE_FRAME_RED, /* red band only */
|
||||||
|
SANE_FRAME_GREEN, /* green band only */
|
||||||
|
SANE_FRAME_BLUE /* blue band only */
|
||||||
|
}
|
||||||
|
SANE_Frame;
|
||||||
|
|
||||||
|
/* push remaining types down to match existing backends */
|
||||||
|
/* these are to be exposed in a later version of SANE */
|
||||||
|
/* most front-ends will require updates to understand them */
|
||||||
|
#if 0
|
||||||
|
#define SANE_FRAME_TEXT 0x0A /* backend specific textual data */
|
||||||
|
#define SANE_FRAME_JPEG 0x0B /* complete baseline JPEG file */
|
||||||
|
#define SANE_FRAME_G31D 0x0C /* CCITT Group 3 1-D Compressed (MH) */
|
||||||
|
#define SANE_FRAME_G32D 0x0D /* CCITT Group 3 2-D Compressed (MR) */
|
||||||
|
#define SANE_FRAME_G42D 0x0E /* CCITT Group 4 2-D Compressed (MMR) */
|
||||||
|
|
||||||
|
#define SANE_FRAME_IR 0x0F /* bare infrared channel */
|
||||||
|
#define SANE_FRAME_RGBI 0x10 /* red+green+blue+infrared */
|
||||||
|
#define SANE_FRAME_GRAYI 0x11 /* gray+infrared */
|
||||||
|
#define SANE_FRAME_XML 0x12 /* undefined schema */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_Frame format;
|
||||||
|
SANE_Bool last_frame;
|
||||||
|
SANE_Int bytes_per_line;
|
||||||
|
SANE_Int pixels_per_line;
|
||||||
|
SANE_Int lines;
|
||||||
|
SANE_Int depth;
|
||||||
|
}
|
||||||
|
SANE_Parameters;
|
||||||
|
|
||||||
|
struct SANE_Auth_Data;
|
||||||
|
|
||||||
|
#define SANE_MAX_USERNAME_LEN 128
|
||||||
|
#define SANE_MAX_PASSWORD_LEN 128
|
||||||
|
|
||||||
|
typedef void (*SANE_Auth_Callback) (SANE_String_Const resource,
|
||||||
|
SANE_Char *username,
|
||||||
|
SANE_Char *password);
|
||||||
|
|
||||||
|
extern SANE_Status sane_init (SANE_Int * version_code,
|
||||||
|
SANE_Auth_Callback authorize);
|
||||||
|
extern void sane_exit (void);
|
||||||
|
extern SANE_Status sane_get_devices (const SANE_Device *** device_list,
|
||||||
|
SANE_Bool local_only);
|
||||||
|
extern SANE_Status sane_open (SANE_String_Const devicename,
|
||||||
|
SANE_Handle * handle);
|
||||||
|
extern void sane_close (SANE_Handle handle);
|
||||||
|
extern const SANE_Option_Descriptor *
|
||||||
|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option);
|
||||||
|
extern SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option,
|
||||||
|
SANE_Action action, void *value,
|
||||||
|
SANE_Int * info);
|
||||||
|
extern SANE_Status sane_get_parameters (SANE_Handle handle,
|
||||||
|
SANE_Parameters * params);
|
||||||
|
extern SANE_Status sane_start (SANE_Handle handle);
|
||||||
|
extern SANE_Status sane_read (SANE_Handle handle, SANE_Byte * data,
|
||||||
|
SANE_Int max_length, SANE_Int * length);
|
||||||
|
extern void sane_cancel (SANE_Handle handle);
|
||||||
|
extern SANE_Status sane_set_io_mode (SANE_Handle handle,
|
||||||
|
SANE_Bool non_blocking);
|
||||||
|
extern SANE_Status sane_get_select_fd (SANE_Handle handle,
|
||||||
|
SANE_Int * fd);
|
||||||
|
extern SANE_String_Const sane_strstatus (SANE_Status status);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* sane_h */
|
|
@ -0,0 +1,897 @@
|
||||||
|
/* sane - Scanner Access Now Easy.
|
||||||
|
对sane标准头文件的扩展
|
||||||
|
|
||||||
|
Author: Gongbing
|
||||||
|
|
||||||
|
Date: 2022-01-14
|
||||||
|
|
||||||
|
Path: SANE_CONFIG_DIR
|
||||||
|
This environment variable specifies the list of directories that may contain theconfiguration file. Under UNIX,
|
||||||
|
the directories are separated by a colon (:'),under os/2,they are separated by a semi-colon (;'). If this variable
|
||||||
|
is not set,the configuration file is searched in two default directories: first, the currentworking directory(".")
|
||||||
|
and then in letc/sane.d. If the value of the environmentvariable ends with the directory separator character,then
|
||||||
|
the default directoriesare searched after the explicitly specified directories. For example,setting SANE_CONFIG_DIR
|
||||||
|
to" /tmp/config :" would result in directories tmp/config, ., andletclsane.d being searched (in this order).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef sane_ex_h
|
||||||
|
#define sane_ex_h
|
||||||
|
|
||||||
|
|
||||||
|
#define SIZE_KB(n) ((n) * 1024)
|
||||||
|
#define SIZE_MB(n) SIZE_KB(n * 1024)
|
||||||
|
#define SIZE_GB(n) SIZE_MB(n * 1024)
|
||||||
|
|
||||||
|
#define SEC_2_MS(s) ((s) * 1000)
|
||||||
|
#define MSEC_2_US(ms) ((ms) * 1000)
|
||||||
|
#define SEC_2_US(s) MSEC_2_US(SEC_2_MS(s))
|
||||||
|
|
||||||
|
#define ALIGN_TO(v, align) (((v) + (align) - 1) / (align) * (align))
|
||||||
|
#define ALIGN_INT(v) ALIGN_TO(v, sizeof(int))
|
||||||
|
|
||||||
|
#include <base/plat_types.h>
|
||||||
|
|
||||||
|
#ifndef EXPORT_SANE_API
|
||||||
|
#ifdef OEM_HANWANG
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_hwsane_##tail
|
||||||
|
#elif defined(OEM_LISICHENG)
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_lscsane_##tail
|
||||||
|
#elif defined(OEM_CANGTIAN)
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_ctssane_##tail
|
||||||
|
#elif defined(OEM_ZHONGJING)
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_zjsane_##tail
|
||||||
|
#elif defined(OEM_ZIGUANG)
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_zgsane_##tail
|
||||||
|
#elif defined(OEM_DELI)
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_dlsane_##tail
|
||||||
|
#elif defined(OEM_NEUTRAL)
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_neusane_##tail
|
||||||
|
#else
|
||||||
|
#define ENTIRE_API(pre, tail) pre##_hgsane_##tail
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define sane_init ENTIRE_API(sane, init)
|
||||||
|
#define sane_init_ex ENTIRE_API(sane, init_ex)
|
||||||
|
#define sane_exit ENTIRE_API(sane, exit)
|
||||||
|
#define sane_get_devices ENTIRE_API(sane, get_devices)
|
||||||
|
#define sane_open ENTIRE_API(sane, open)
|
||||||
|
#define sane_close ENTIRE_API(sane, close)
|
||||||
|
#define sane_get_option_descriptor ENTIRE_API(sane, get_option_descriptor)
|
||||||
|
#define sane_control_option ENTIRE_API(sane, control_option)
|
||||||
|
#define sane_get_parameters ENTIRE_API(sane, get_parameters)
|
||||||
|
#define sane_start ENTIRE_API(sane, start)
|
||||||
|
#define sane_read ENTIRE_API(sane, read)
|
||||||
|
#define sane_cancel ENTIRE_API(sane, cancel)
|
||||||
|
#define sane_set_io_mode ENTIRE_API(sane, set_io_mode)
|
||||||
|
#define sane_get_select_fd ENTIRE_API(sane, get_select_fd)
|
||||||
|
#define sane_strstatus ENTIRE_API(sane, strstatus)
|
||||||
|
#define sane_io_control ENTIRE_API(sane, io_control)
|
||||||
|
#define sane_err_desc ENTIRE_API(sane, err_desc)
|
||||||
|
#define sane_get_option_descriptor_ex ENTIRE_API(get_option_descriptor_ex)
|
||||||
|
#define sane_control_option_ex ENTIRE_API(control_option_ex)
|
||||||
|
#define sane_read_ext_info ENTIRE_API(sane, read_ext_info)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define SANE_OPT_NAME(name) SANE_STD_OPT_NAME_##name
|
||||||
|
#define SANE_OPT_FIXED_ID(id) SANE_OPT_ID_##id
|
||||||
|
#define IS_SANE_OPT(v, sd) strcmp(v, SANE_OPT_NAME(sd)) == 0
|
||||||
|
#define MAX_OPT_NAME_LEN 64
|
||||||
|
#define JSON_SANE_TYPE_BOOL "bool"
|
||||||
|
#define JSON_SANE_TYPE_INT "int"
|
||||||
|
#define JSON_SANE_TYPE_FIXED "float"
|
||||||
|
#define JSON_SANE_TYPE_STRING "string"
|
||||||
|
#define JSON_SANE_TYPE_GROUP "group"
|
||||||
|
#define JSON_SANE_TYPE_BUTTON "button"
|
||||||
|
|
||||||
|
// 用户权限
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
USER_PRIVILEGE_COMMON = 0, // 普通用户权限
|
||||||
|
USER_PRIVILEGE_LOCAL_MGR = 10, // 本地管理员权限
|
||||||
|
USER_PRIVILEGE_TECH_SUPPORTING = 20, // 技术支持权限
|
||||||
|
USER_PRIVILEGE_DEVLOPER = 100, // 开发者权限(查看所有属性)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 属性可见
|
||||||
|
enum opt_visible_level // "visible" field
|
||||||
|
{
|
||||||
|
OPT_VISIBLE_ALL = 0, // visible on ui and accessible
|
||||||
|
OPT_VISIBLE_ACCESS, // accessible only
|
||||||
|
OPT_VISIBLE_HIDE, // invisible and inaccessible unless user has DEVELOPE privilege
|
||||||
|
OPT_VISIBLE_NOT_SUPPORT, // device does not support this option
|
||||||
|
};
|
||||||
|
|
||||||
|
// sane-standard-option-name defined by third-app
|
||||||
|
//
|
||||||
|
// PART I: 参数类型与华高一致,可直接通过改name字段为标准值实现
|
||||||
|
#define SANE_STD_OPT_NAME_RESTORE "restore" // OPTION_TITLE_HFMRSZ
|
||||||
|
#define SANE_STD_OPT_NAME_HELP "help" // OPTION_TITLE_BZ
|
||||||
|
#define SANE_STD_OPT_NAME_IS_MULTI_OUT "is-multiout" // OPTION_TITLE_DLSC
|
||||||
|
#define SANE_STD_OPT_NAME_MULTI_OUT_TYPE "multiout-type" // OPTION_TITLE_DLSCLX
|
||||||
|
#define SANE_STD_OPT_NAME_COLOR_MODE "mode" // OPTION_TITLE_YSMS
|
||||||
|
#define SANE_STD_OPT_NAME_BINARY_THRESHOLD "binary-threshold" // OPTION_TITLE_HBTXYZ
|
||||||
|
#define SANE_STD_OPT_NAME_REVERSE_01 "reverse-bw" // OPTION_TITLE_HBTXFSSC
|
||||||
|
#define SANE_STD_OPT_NAME_FILTER "filter" // OPTION_TITLE_HDHHBTX_CSYZQ
|
||||||
|
#define SANE_STD_OPT_NAME_RID_MULTIOUT_RED "is-rid-multiout-red" // OPTION_TITLE_24WCSTX_DLSCCH
|
||||||
|
#define SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED "is-rid-answer-sheet-red" // OPTION_TITLE_24WCSTX_DTKCH
|
||||||
|
#define SANE_STD_OPT_NAME_ERASE_BACKGROUND "is-erase-bkg" // OPTION_TITLE_BJYC
|
||||||
|
#define SANE_STD_OPT_NAME_BKG_COLOR_RANGE "bkg-color-range" // OPTION_TITLE_BJSCFDFW
|
||||||
|
#define SANE_STD_OPT_NAME_SHARPEN "sharpen" // OPTION_TITLE_RHYMH
|
||||||
|
#define SANE_STD_OPT_NAME_RID_MORR "is-rid-morr" // OPTION_TITLE_QCMW
|
||||||
|
#define SANE_STD_OPT_NAME_RID_GRID "is-rid-grid" // OPTION_TITLE_CWW
|
||||||
|
#define SANE_STD_OPT_NAME_ERROR_EXTENSION "is-err-extension" // OPTION_TITLE_CWKS
|
||||||
|
#define SANE_STD_OPT_NAME_NOISE_OPTIMIZE "is-noise-optimize" // OPTION_TITLE_HBTXZDYH
|
||||||
|
#define SANE_STD_OPT_NAME_NOISE_SIZE "noise-size" // OPTION_TITLE_ZDYHCC
|
||||||
|
#define SANE_STD_OPT_NAME_PAPER "paper" // OPTION_TITLE_ZZCC
|
||||||
|
#define SANE_STD_OPT_NAME_PAPER_W "paper-w" // 纸张宽度
|
||||||
|
#define SANE_STD_OPT_NAME_PAPER_H "paper-h" // 纸张高度
|
||||||
|
#define SANE_STD_OPT_NAME_LATERAL "lateral" // 纸张横向标志
|
||||||
|
#define SANE_STD_OPT_NAME_CUSTOM_AREA "is-custom-area" // OPTION_TITLE_ZDYSMQY
|
||||||
|
#define SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT "tl-x" // OPTION_TITLE_SMQYZCmm
|
||||||
|
#define SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT "br-x" // OPTION_TITLE_SMQYYCmm
|
||||||
|
#define SANE_STD_OPT_NAME_CUSTOM_AREA_TOP "tl-y" // OPTION_TITLE_SMQYSCmm
|
||||||
|
#define SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM "br-y" // OPTION_TITLE_SMQYXCmm
|
||||||
|
#define SANE_STD_OPT_NAME_SIZE_CHECK "is-size-check" // OPTION_TITLE_CCJC
|
||||||
|
#define SANE_STD_OPT_NAME_PAGE "page" // OPTION_TITLE_SMYM
|
||||||
|
#define SANE_STD_OPT_NAME_DISCARD_BLANK_SENS "blank-sensitivity" // OPTION_TITLE_TGKBYLMD
|
||||||
|
#define SANE_STD_OPT_NAME_RESOLUTION "resolution" // OPTION_TITLE_FBL
|
||||||
|
#define SANE_STD_OPT_NAME_TIME_TO_SLEEP "time-to-sleep" // OPTION_TITLE_XMSJ
|
||||||
|
#define SANE_STD_OPT_NAME_IMAGE_QUALITY "image-quality" // OPTION_TITLE_HZ
|
||||||
|
#define SANE_STD_OPT_NAME_EXCHANGE "is-exchange" // OPTION_TITLE_JHZFM
|
||||||
|
#define SANE_STD_OPT_NAME_SPLIT "is-split" // OPTION_TITLE_TXCF
|
||||||
|
#define SANE_STD_OPT_NAME_ANTI_SKEW "is-anti-skew" // OPTION_TITLE_ZDJP
|
||||||
|
#define SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA "is-custom-gamma" // OPTION_TITLE_QYSDQX
|
||||||
|
#define SANE_STD_OPT_NAME_GAMMA "gamma" // OPTION_TITLE_JMZ
|
||||||
|
#define SANE_STD_OPT_NAME_CUSTOM_GAMMA "custom-gamma" // OPTION_TITLE_CUSTOM_JMZ; data - SANE_Gamma*
|
||||||
|
#define SANE_STD_OPT_NAME_GRAY_GAMMA "gray-gamma-table"
|
||||||
|
#define SANE_STD_OPT_NAME_COLOR_GAMMA "color-gamma-table"
|
||||||
|
#define SANE_STD_OPT_NAME_RED_GAMMA "red-gamma-table"
|
||||||
|
#define SANE_STD_OPT_NAME_GREEN_GAMMA "green-gamma-table"
|
||||||
|
#define SANE_STD_OPT_NAME_BLUE_GAMMA "blue-gamma-table"
|
||||||
|
#define SANE_STD_OPT_NAME_BRIGHTNESS "brightness" // OPTION_TITLE_LDZ
|
||||||
|
#define SANE_STD_OPT_NAME_CONTRAST "contrast" // OPTION_TITLE_DBD
|
||||||
|
#define SANE_STD_OPT_NAME_IS_PHOTO_MODE "is-photo-mode" // OPTION_TITLE_ZPMS
|
||||||
|
#define SANE_STD_OPT_NAME_ERASE_BLACK_FRAME "is-erase-black-frame" // OPTION_TITLE_XCHK
|
||||||
|
#define SANE_STD_OPT_NAME_DARK_SAMPLE "is-dark-sample" // OPTION_TITLE_SSYZ
|
||||||
|
#define SANE_STD_OPT_NAME_THRESHOLD "threshold" // OPTION_TITLE_YZ
|
||||||
|
#define SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL "anti-noise-level" // OPTION_TITLE_BJKZDJ
|
||||||
|
#define SANE_STD_OPT_NAME_MARGIN "margin" // OPTION_TITLE_BYSJ
|
||||||
|
#define SANE_STD_OPT_NAME_FILL_BKG_MODE "bkg-fill-mode" // OPTION_TITLE_BJTCFS
|
||||||
|
#define SANE_STD_OPT_NAME_IS_ANTI_PERMEATE "is-anti-permeate" // OPTION_TITLE_FZST
|
||||||
|
#define SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL "permeate-level" // OPTION_TITLE_FZSTDJ
|
||||||
|
#define SANE_STD_OPT_NAME_RID_HOLE "is-rid-hole" // OPTION_TITLE_CKYC
|
||||||
|
#define SANE_STD_OPT_NAME_HOLE_THRESHOLD "hole-threshold" //
|
||||||
|
#define SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE "search-hole-range" // OPTION_TITLE_CKSSFWZFMBL
|
||||||
|
#define SANE_STD_OPT_NAME_RID_HOLE_L "is-rid-hole-l" // OPTION_TITLE_CKYCZC
|
||||||
|
#define SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L "search-hole-range-l" // OPTION_TITLE_ZCCKSSFWZFMBL
|
||||||
|
#define SANE_STD_OPT_NAME_RID_HOLE_R "is-rid-hole-r" // OPTION_TITLE_CKYCYC
|
||||||
|
#define SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R "search-hole-range-r" // OPTION_TITLE_YCCKSSFWZFMBL
|
||||||
|
#define SANE_STD_OPT_NAME_RID_HOLE_T "is-rid-hole-t" // OPTION_TITLE_CKYCSC
|
||||||
|
#define SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T "search-hole-range-t" // OPTION_TITLE_SCCKSSFWZFMBL
|
||||||
|
#define SANE_STD_OPT_NAME_RID_HOLE_B "is-rid-hole-b" // OPTION_TITLE_CKYCXC
|
||||||
|
#define SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B "search-hole-range-b" // OPTION_TITLE_XCCKSSFWZFMBL
|
||||||
|
#define SANE_STD_OPT_NAME_IS_FILL_COLOR "is-fill-color" // OPTION_TITLE_SCTC
|
||||||
|
#define SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK "is-ultrosonic" // OPTION_TITLE_CSBJC
|
||||||
|
#define SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE "double-feed" // OPTION_TITLE_SZTPCL
|
||||||
|
#define SANE_STD_OPT_NAME_IS_CHECK_STAPLE "is-staple" // OPTION_TITLE_ZDJC
|
||||||
|
#define SANE_STD_OPT_NAME_SCAN_MODE "scan-mode" // OPTION_TITLE_SMZS
|
||||||
|
#define SANE_STD_OPT_NAME_SCAN_COUNT "scan-count" // OPTION_TITLE_SMSL
|
||||||
|
#define SANE_STD_OPT_NAME_TEXT_DIRECTION "direction" // OPTION_TITLE_WGFX
|
||||||
|
#define SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 "is-rotate-bkg-180" // OPTION_TITLE_BMXZ180
|
||||||
|
#define SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR "is-check-dog-ear" // OPTION_TITLE_ZJJC
|
||||||
|
#define SANE_STD_OPT_NAME_DOG_EAR_SIZE "dog-ear-size" // OPTION_TITLE_ZJDX
|
||||||
|
#define SANE_STD_OPT_NAME_IS_CHECK_ASKEW "is-check-askew" // OPTION_TITLE_WXJC
|
||||||
|
#define SANE_STD_OPT_NAME_ASKEW_RANGE "askew-range" // OPTION_TITLE_WXRRD
|
||||||
|
#define SANE_STD_OPT_NAME_FEED_STRENGTH "feed-strength" // OPTION_TITLE_FZQD
|
||||||
|
#define SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH "is-auto-strength" // OPTION_TITLE_ZDFZQD
|
||||||
|
#define SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE "feed-strength-value" // OPTION_TITLE_JZSBL
|
||||||
|
#define SANE_STD_OPT_NAME_WAIT_TO_SCAN "is-wait-scan" // OPTION_TITLE_DZSM
|
||||||
|
#define SANE_STD_OPT_NAME_FOLD_TYPE "fold-type" // OPTION_TITLE_DZMS
|
||||||
|
#define SANE_STD_OPT_NAME_COLOR_CORRECTION "color-correction" // OPTION_TITLE_SPJZ
|
||||||
|
#define SANE_STD_OPT_NAME_WAIT_SCAN_EXIT "wait-scan-exit" // OPTION_TITLE_DZSMTCSJ
|
||||||
|
#define SANE_STD_OPT_NAME_DISCARDBLANK "discardblank" // OPTION_TITLE_TGKBY
|
||||||
|
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_NAME "dev-name" // 设备名称
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_VID "dev-vid" // 设备VID
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_PID "dev-pid" // 设备PID
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_MODEL "dev-model" // 设备系列
|
||||||
|
#define SANE_STD_OPT_NAME_DEV_NAME SANE_STD_OPT_NAME_DEVICE_NAME
|
||||||
|
#define SANE_STD_OPT_NAME_VID SANE_STD_OPT_NAME_DEVICE_VID
|
||||||
|
#define SANE_STD_OPT_NAME_PID SANE_STD_OPT_NAME_DEVICE_PID
|
||||||
|
#define SANE_STD_OPT_NAME_DEV_FAMILY SANE_STD_OPT_NAME_DEVICE_MODEL
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_TYPE "dev-type" // 设备型号
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_SERIAL_NO "dev-sn" // 设备序列号
|
||||||
|
#define SANE_STD_OPT_NAME_FIRMWARE_VERSION "fmw-ver" // 固件版本
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_IP_ADDR "ip-addr" // 设备IP地址
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_MAC_ADDR "mac-addr" // 设备MAC地址
|
||||||
|
#define SANE_STD_OPT_NAME_ROLLER_COUNT "roll-cnt" // 滚轴张数
|
||||||
|
#define SANE_STD_OPT_NAME_TOTAL_COUNT "total-cnt" // 历史总张数
|
||||||
|
#define SANE_STD_OPT_NAME_HISTORY_COUNT SANE_STD_OPT_NAME_TOTAL_COUNT
|
||||||
|
#define SANE_STD_OPT_NAME_GET_DEVS_L0G "devs-log" // 获取设备日志
|
||||||
|
#define SANE_STD_OPT_NAME_DRIVER_VERSION "drv-ver" // 设备VID
|
||||||
|
#define SANE_STD_OPT_NAME_MANUFACTURER "company" // 公司名称
|
||||||
|
#define SANE_STD_OPT_NAME_COPYRIGHT "copyright" // 版权
|
||||||
|
#define SANE_STD_OPT_NAME_CO_URL "co-url" // 公司网址
|
||||||
|
#define SANE_STD_OPT_NAME_CO_TEL "co-tel" // 公司电话
|
||||||
|
#define SANE_STD_OPT_NAME_CO_ADDR "co-addr" // 公司地址
|
||||||
|
#define SANE_STD_OPT_NAME_CO_GPS "co-gps" // 公司地图定位
|
||||||
|
#define SANE_STD_OPT_NAME_LOGIN "login" // 登录
|
||||||
|
#define SANE_STD_OPT_NAME_LOGOUT "logout" // 登出
|
||||||
|
#define SANE_STD_OPT_NAME_DRIVER_LOG "drv-log" // 驱动日志
|
||||||
|
#define SANE_STD_OPT_NAME_DEVICE_LOG SANE_STD_OPT_NAME_GET_DEVS_L0G
|
||||||
|
#define SANE_STD_OPT_NAME_ROLLER_LIFE "roller-life" // 滚轴最大寿命(过纸张数)
|
||||||
|
#define SANE_STD_OPT_NAME_LANGUAGE "language" // 语言
|
||||||
|
#define SANE_STD_OPT_NAME_MOTOR_VER "motor-ver" // 电机固件版本, data = char*
|
||||||
|
#define SANE_STD_OPT_NAME_TRANSFORM_IMAGE_FORMAT "trans-img-fmt" // 图像格式转换, data - SANE_ImageFormatConvert*, dst.data 调用SANE_STD_OPT_NAME_FREE_BUFFER释放
|
||||||
|
#define SANE_STD_OPT_NAME_FREE_BUFFER "free-buf" // 释放由驱动返回的内存, data - (void**)&buf
|
||||||
|
#define SANE_STD_OPT_NAME_PAPER_ON "paper-on" // check whether paper is on
|
||||||
|
#define SANE_STD_OPT_NAME_INITIAL_BOOT_TIME "initial-boot-time" // 设备的初始开机时间
|
||||||
|
#define SANE_STD_OPT_NAME_DUMP_IMG "dumpimg" // 是否输出算法各阶段中间图像
|
||||||
|
#define SANE_STD_OPT_NAME_DUMP_IMG_PATH "dump-path" // 中间图像输出路径
|
||||||
|
|
||||||
|
// PART II: 参数类型与华高不一致,需要通过“hgsane”组件在中间转换
|
||||||
|
#define SANE_STD_OPT_NAME_PAGE_W "page-width" // OPTION_TITLE_ZZCC
|
||||||
|
#define SANE_STD_OPT_NAME_PAGE_H "page-height" // OPTION_TITLE_ZZCC
|
||||||
|
#define SANE_STD_OPT_NAME_DUPLEX "duplex" // OPTION_TITLE_SMYM
|
||||||
|
// END for sane-standard-option-name defined by third-app
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// 借鉴TWAIN协议固定ID的做法,定义SANE属性的固定ID - 这里与TWAIN中的ID保持一致,以方便TWAIN的调用
|
||||||
|
enum sane_option_id
|
||||||
|
{
|
||||||
|
SANE_OPT_ID_BASE = 0x8800,
|
||||||
|
SANE_OPT_ID_IS_MULTI_OUT = 0x8801,
|
||||||
|
SANE_OPT_ID_MULTI_OUT_TYPE = 0x8802,
|
||||||
|
SANE_OPT_ID_COLOR_MODE = 0x8803,
|
||||||
|
SANE_OPT_ID_FILTER = 0x8804,
|
||||||
|
SANE_OPT_ID_RID_MULTIOUT_RED = 0x8805,
|
||||||
|
SANE_OPT_ID_RID_ANSWER_SHEET_RED = 0x8806,
|
||||||
|
SANE_OPT_ID_ERASE_BACKGROUND = 0x8807,
|
||||||
|
SANE_OPT_ID_BKG_COLOR_RANGE = 0x8808,
|
||||||
|
SANE_OPT_ID_SHARPEN = 0x8809,
|
||||||
|
SANE_OPT_ID_RID_MORR = 0x880A,
|
||||||
|
SANE_OPT_ID_RID_GRID = 0x880B,
|
||||||
|
SANE_OPT_ID_ERROR_EXTENSION = 0x880C,
|
||||||
|
SANE_OPT_ID_NOISE_OPTIMIZE = 0x880D,
|
||||||
|
SANE_OPT_ID_NOISE_SIZE = 0x880E,
|
||||||
|
SANE_OPT_ID_PAPER = 0x880F,
|
||||||
|
SANE_OPT_ID_CUSTOM_AREA = 0x8810,
|
||||||
|
SANE_OPT_ID_CUSTOM_AREA_LEFT = 0x8811,
|
||||||
|
SANE_OPT_ID_CUSTOM_AREA_RIGHT = 0x8812,
|
||||||
|
SANE_OPT_ID_CUSTOM_AREA_TOP = 0x8813,
|
||||||
|
SANE_OPT_ID_CUSTOM_AREA_BOTTOM = 0x8814,
|
||||||
|
SANE_OPT_ID_SIZE_CHECK = 0x8815,
|
||||||
|
SANE_OPT_ID_PAGE = 0x8816,
|
||||||
|
SANE_OPT_ID_DISCARD_BLANK_SENS = 0x8817,
|
||||||
|
SANE_OPT_ID_RESOLUTION = 0x8818,
|
||||||
|
SANE_OPT_ID_IMAGE_QUALITY = 0x8819,
|
||||||
|
SANE_OPT_ID_EXCHANGE = 0x881A,
|
||||||
|
SANE_OPT_ID_SPLIT = 0x881B,
|
||||||
|
SANE_OPT_ID_ANTI_SKEW = 0x881C,
|
||||||
|
SANE_OPT_ID_IS_CUSTOM_GAMMA = 0x881D,
|
||||||
|
SANE_OPT_ID_BRIGHTNESS = 0x881E,
|
||||||
|
SANE_OPT_ID_CONTRAST = 0x881F,
|
||||||
|
SANE_OPT_ID_GAMMA = 0x8820,
|
||||||
|
SANE_OPT_ID_ERASE_BLACK_FRAME = 0x8821,
|
||||||
|
SANE_OPT_ID_DARK_SAMPLE = 0x8822,
|
||||||
|
SANE_OPT_ID_THRESHOLD = 0x8823,
|
||||||
|
SANE_OPT_ID_ANTI_NOISE_LEVEL = 0x8824,
|
||||||
|
SANE_OPT_ID_MARGIN = 0x8825,
|
||||||
|
SANE_OPT_ID_FILL_BKG_MODE = 0x8826,
|
||||||
|
SANE_OPT_ID_IS_ANTI_PERMEATE = 0x8827,
|
||||||
|
SANE_OPT_ID_ANTI_PERMEATE_LEVEL = 0x8828,
|
||||||
|
SANE_OPT_ID_RID_HOLE = 0x8829,
|
||||||
|
SANE_OPT_ID_SEARCH_HOLE_RANGE = 0x882A,
|
||||||
|
SANE_OPT_ID_IS_FILL_COLOR = 0x882B,
|
||||||
|
SANE_OPT_ID_IS_ULTROSONIC_CHECK = 0x882C,
|
||||||
|
SANE_OPT_ID_IS_CHECK_STAPLE = 0x882D,
|
||||||
|
SANE_OPT_ID_SCAN_MODE = 0x882E,
|
||||||
|
SANE_OPT_ID_SCAN_COUNT = 0x882F,
|
||||||
|
SANE_OPT_ID_TEXT_DIRECTION = 0x8830,
|
||||||
|
SANE_OPT_ID_IS_ROTATE_BKG_180 = 0x8831,
|
||||||
|
SANE_OPT_ID_IS_CHECK_DOG_EAR = 0x8832,
|
||||||
|
SANE_OPT_ID_DOG_EAR_SIZE = 0x8833,
|
||||||
|
SANE_OPT_ID_IS_CHECK_ASKEW = 0x8834,
|
||||||
|
SANE_OPT_ID_ASKEW_RANGE = 0x8835,
|
||||||
|
SANE_OPT_ID_BINARY_THRESHOLD = 0x8836,
|
||||||
|
SANE_OPT_ID_IS_PHOTO_MODE = 0x8837,
|
||||||
|
SANE_OPT_ID_DOUBLE_FEED_HANDLE = 0x8838,
|
||||||
|
SANE_OPT_ID_WAIT_TO_SCAN = 0x8839,
|
||||||
|
SANE_OPT_ID_FEED_STRENGTH = 0x883A,
|
||||||
|
SANE_OPT_ID_TIME_TO_SLEEP = 0x883B,
|
||||||
|
SANE_OPT_ID_IS_AUTO_FEED_STRENGTH = 0x883C,
|
||||||
|
SANE_OPT_ID_FEED_STRENGTH_VALUE = 0x883D,
|
||||||
|
SANE_OPT_ID_REVERSE_01 = 0x883E,
|
||||||
|
SANE_OPT_ID_RID_HOLE_L = 0x883F,
|
||||||
|
SANE_OPT_ID_SEARCH_HOLE_RANGE_L = 0x8840,
|
||||||
|
SANE_OPT_ID_RID_HOLE_R = 0x8841,
|
||||||
|
SANE_OPT_ID_SEARCH_HOLE_RANGE_R = 0x8842,
|
||||||
|
SANE_OPT_ID_RID_HOLE_T = 0x8843,
|
||||||
|
SANE_OPT_ID_SEARCH_HOLE_RANGE_T = 0x8844,
|
||||||
|
SANE_OPT_ID_RID_HOLE_B = 0x8845,
|
||||||
|
SANE_OPT_ID_SEARCH_HOLE_RANGE_B = 0x8846,
|
||||||
|
SANE_OPT_ID_FOLD_TYPE = 0x8847,
|
||||||
|
SANE_OPT_ID_COLOR_CORRECTION = 0x8848,
|
||||||
|
SANE_OPT_ID_HISTORY_COUNT = 0x8849,
|
||||||
|
SANE_OPT_ID_DRIVER_VERSION = 0x884A,
|
||||||
|
SANE_OPT_ID_MANUFACTURER = 0x884B,
|
||||||
|
SANE_OPT_ID_COPYRIGHT = 0x884C,
|
||||||
|
SANE_OPT_ID_CO_URL = 0x884D,
|
||||||
|
SANE_OPT_ID_CO_TEL = 0x884E,
|
||||||
|
SANE_OPT_ID_CO_ADDR = 0x884F,
|
||||||
|
SANE_OPT_ID_CO_GPS = 0x8850,
|
||||||
|
SANE_OPT_ID_HELP = 0x8851,
|
||||||
|
SANE_OPT_ID_VID = 0x8852,
|
||||||
|
SANE_OPT_ID_PID = 0x8853,
|
||||||
|
SANE_OPT_ID_DEV_NAME = 0x8854,
|
||||||
|
SANE_OPT_ID_DEV_FAMILY = 0x8855,
|
||||||
|
SANE_OPT_ID_DEVICE_SERIAL_NO = 0x8856,
|
||||||
|
SANE_OPT_ID_FIRMWARE_VERSION = 0x8857,
|
||||||
|
SANE_OPT_ID_DEVICE_IP_ADDR = 0x8858,
|
||||||
|
SANE_OPT_ID_DEVICE_MAC_ADDR = 0x8859,
|
||||||
|
SANE_OPT_ID_CUSTOM_GAMMA = 0x885A, // data: SANE_Gamma*
|
||||||
|
SANE_OPT_ID_ROLLER_LIFE = 0x885B, // data: uint32_t*
|
||||||
|
SANE_OPT_ID_LANGUAGE = 0x885C, // data: char*
|
||||||
|
SANE_OPT_ID_MOTOR_VER = 0x885D, // 电机固件版本, data - char*
|
||||||
|
SANE_OPT_ID_TRANSFORM_IMAGE_FORMAT = 0x885E,// 图像格式转换, data - SANE_ImageFormatConvert*, dst.data 调用SANE_STD_OPT_NAME_FREE_BUFFER释放
|
||||||
|
SANE_OPT_ID_FREE_BUFFER = 0x885F, // 释放由驱动返回的内存, data - (void**)&buf
|
||||||
|
SANE_OPT_ID_PAPER_ON = 0x8860, // 是否有纸张, data - SANE_Bool*
|
||||||
|
|
||||||
|
SANE_OPT_ID_GRAY_GAMMA = 0x8861, // gray-gamma-table
|
||||||
|
SANE_OPT_ID_COLOR_GAMMA = 0x8862, // color-gamma-table
|
||||||
|
SANE_OPT_ID_RED_GAMMA = 0x8863, // red-gamma-table
|
||||||
|
SANE_OPT_ID_GREEN_GAMMA = 0x8864, // green-gamma-table
|
||||||
|
SANE_OPT_ID_BLUE_GAMMA = 0x8865, // blue-gamma-table
|
||||||
|
SANE_OPT_ID_INITIAL_BOOT_TIME = 0x8866,
|
||||||
|
SANE_OPT_ID_DISCARDBLANK = 0x8867,
|
||||||
|
SANE_OPT_ID_WAIT_SCAN_EXIT = 0x8868,
|
||||||
|
SANE_OPT_ID_RESTORE = 0x8869,
|
||||||
|
SANE_OPT_ID_PAPER_W = 0x886A, // 纸张宽度,单位为mm
|
||||||
|
SANE_OPT_ID_PAPER_H = 0x886B, // 纸张高度,单位为mm
|
||||||
|
SANE_OPT_ID_LATERAL = 0x886C, // 纸张横向标志,bool
|
||||||
|
|
||||||
|
SANE_OPT_ID_LOGIN = 0x9900,
|
||||||
|
SANE_OPT_ID_LOGOUT = 0x9901,
|
||||||
|
SANE_OPT_ID_ROLLER_COUNT = 0x9902,
|
||||||
|
SANE_OPT_ID_DRIVER_LOG = 0x9903,
|
||||||
|
SANE_OPT_ID_DEVICE_LOG = 0x9904,
|
||||||
|
};
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "sane.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define MAX_STRING_LEN 256
|
||||||
|
#define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001
|
||||||
|
#define IS_PTR_NUMBER(ptr) (((unsigned long long)(ptr)) < 0x10000)
|
||||||
|
|
||||||
|
#define CAPABILITY_ORDINARY (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT)
|
||||||
|
#define CAPABILITY_READONLY SANE_CAP_SOFT_DETECT
|
||||||
|
|
||||||
|
// 设置活动状态
|
||||||
|
#define SET_CAP_ACTIVE(cap, act) \
|
||||||
|
{ \
|
||||||
|
if(act) \
|
||||||
|
cap &= ~SANE_CAP_INACTIVE; \
|
||||||
|
else \
|
||||||
|
cap |= SANE_CAP_INACTIVE; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置为只读属性
|
||||||
|
#define SET_CAP_READONLY(cap) \
|
||||||
|
{ \
|
||||||
|
cap &= ~(CAPABILITY_ORDINARY | SANE_CAP_HARD_SELECT); \
|
||||||
|
cap |= CAPABILITY_READONLY; \
|
||||||
|
}
|
||||||
|
#define IS_CAP_READONLY(cap) (((cap) & (CAPABILITY_ORDINARY | SANE_CAP_HARD_SELECT)) == CAPABILITY_READONLY)
|
||||||
|
|
||||||
|
// 设置为软件可设置/读取
|
||||||
|
#define SET_CAP_SOFT_SETTABLE(cap) \
|
||||||
|
{ \
|
||||||
|
cap &= ~(CAPABILITY_ORDINARY | SANE_CAP_HARD_SELECT); \
|
||||||
|
cap |= SANE_CAP_HARD_SELECT; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置为由设备上的按键操作属性
|
||||||
|
#define SET_CAP_DEVICE_SETTABLE(cap, can_read) \
|
||||||
|
{ \
|
||||||
|
cap &= ~(CAPABILITY_ORDINARY | SANE_CAP_HARD_SELECT); \
|
||||||
|
cap |= can_read ? SANE_CAP_SOFT_DETECT | CAPABILITY_ORDINARY : CAPABILITY_ORDINARY;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
#define ZERO_STRUCT(struct_ptr) memset(struct_ptr, 0, sizeof(*(struct_ptr)))
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// extension for standard SANE ...
|
||||||
|
enum SANE_Action_Ex // extension for SANE_Action
|
||||||
|
{
|
||||||
|
SANE_ACTION_GET_DEFAULT_VALUE = 100, // 获取设置项默认值,参数同SANE_ACTION_GET_VALUE
|
||||||
|
SANE_ACTION_GET_FIX_ID, // 获取属性的固定ID,void* = SANE_Int*
|
||||||
|
SANE_ACTION_GET_ENTIRE_JSON, // 获取该属性JSON文本
|
||||||
|
|
||||||
|
// Function: 枚举对SANE协议不可见的固定ID属性(以使TWAIN可访问)
|
||||||
|
//
|
||||||
|
// Parameter: void* = FIXDCB*
|
||||||
|
SANE_ACTION_ENUM_INVISIBLE_FIX_ID = 0x0FEC7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SANE_Frame_Ex // after SANE_Frame
|
||||||
|
{
|
||||||
|
SANE_FRAME_RAW = 5,
|
||||||
|
SANE_FRAME_MIME, // MIME descriptor
|
||||||
|
};
|
||||||
|
|
||||||
|
// SANE_ACTION_ENUM_INVISIBLE_FIX_ID
|
||||||
|
struct _fix_id_cb
|
||||||
|
{
|
||||||
|
SANE_Bool (*cb)(int, void*);
|
||||||
|
void* param;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _sane_stream
|
||||||
|
{
|
||||||
|
SANE_Int bytes;
|
||||||
|
SANE_Byte *data;
|
||||||
|
}SANE_Stream;
|
||||||
|
|
||||||
|
typedef struct _sane_dev_ex
|
||||||
|
{
|
||||||
|
SANE_String_Const name; /* unique device name */
|
||||||
|
SANE_String_Const vendor; /* device vendor string */
|
||||||
|
SANE_String_Const model; /* device model name */
|
||||||
|
SANE_String_Const family; /* device type (e.g., "flatbed scanner") */
|
||||||
|
SANE_Bool openned; // whether openned
|
||||||
|
}SANE_Device_Ex;
|
||||||
|
typedef struct _sane_auth // for SANE_EVENT_NEED_AUTH
|
||||||
|
{
|
||||||
|
SANE_String_Const resource;
|
||||||
|
SANE_Char name[MAX_STRING_LEN];
|
||||||
|
SANE_Char pwd[MAX_STRING_LEN];
|
||||||
|
SANE_Char method[MAX_STRING_LEN];
|
||||||
|
}SANEAUTH;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_TYPE_EX_BOOL = 0,
|
||||||
|
SANE_TYPE_EX_INT,
|
||||||
|
SANE_TYPE_EX_FIXED, // same as SANE_TYPE_FIXED
|
||||||
|
SANE_TYPE_EX_STRING, // sane as SANE_TYPE_STRING
|
||||||
|
SANE_TYPE_EX_POS, // position in origin image, SANE_Rect*
|
||||||
|
SANE_TYPE_EX_IMAGE, // SANE_Image*, src_id is meanless
|
||||||
|
}SANE_Value_Ext_Type;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_Int left;
|
||||||
|
SANE_Int top;
|
||||||
|
SANE_Int right;
|
||||||
|
SANE_Int bottom;
|
||||||
|
}SANE_Rect;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_Int src_id; // unique(in this running) image ID from SANE
|
||||||
|
SANE_Int count; // length of array 'info'
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SANE_Int ext_inf_id; // Extended information ID
|
||||||
|
SANE_Value_Ext_Type type; // value type
|
||||||
|
SANE_Int inf_bytes; // length of information
|
||||||
|
union
|
||||||
|
{
|
||||||
|
SANE_Bool bval; // bool
|
||||||
|
SANE_Int ival; // integer
|
||||||
|
SANE_Fixed fval; // float value
|
||||||
|
SANE_Char *pval; // string, byte-stream or other structure
|
||||||
|
};
|
||||||
|
}info[1];
|
||||||
|
}SANE_Img_Ext_Info; // added on 2023-01-13
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SANE_Int src_id; // unique(in this running) image ID from SANE
|
||||||
|
SANE_Parameters header;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int statu : 4; // SANE_Image_Statu
|
||||||
|
unsigned int dpi : 12; // resolution, dots per inch
|
||||||
|
unsigned int reserve : 16;
|
||||||
|
}flag;
|
||||||
|
unsigned long bytes;
|
||||||
|
unsigned char *data;
|
||||||
|
}SANE_Image;
|
||||||
|
typedef struct _about_info
|
||||||
|
{
|
||||||
|
SANE_String_Const title; // APP名称
|
||||||
|
SANE_String_Const version; // 版本号
|
||||||
|
SANE_String_Const copyright; // 版权信息
|
||||||
|
unsigned int logo_bytes; // LOGO 数据长度
|
||||||
|
void* logo; // LOGO 数据
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SANE_String_Const key; // 附加信息名称,该数据为NULL时,appendix数组结束
|
||||||
|
SANE_String_Const content;// 附加信息内容
|
||||||
|
SANE_String_Const url; // 附加信息链接, NULL则忽略
|
||||||
|
}appendix[1];
|
||||||
|
}SANE_About;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_COMPRESSION_FIRST = 0,
|
||||||
|
SANE_COMPRESSION_NONE = 0, // default value
|
||||||
|
//SANE_COMPRESSION_PACBITS,
|
||||||
|
//SANE_COMPRESSION_GROUP31D,
|
||||||
|
//SANE_COMPRESSION_GROUP31DEOL,
|
||||||
|
//SANE_COMPRESSION_GROUP32D,
|
||||||
|
SANE_COMPRESSION_GROUP4 = 5, // support now ! detail is threshold converting color to BlackWhite, e.g. (void*)128
|
||||||
|
//SANE_COMPRESSION_JPEG,
|
||||||
|
//SANE_COMPRESSION_LZW,
|
||||||
|
//SANE_COMPRESSION_JBIG,
|
||||||
|
//SANE_COMPRESSION_PNG,
|
||||||
|
//SANE_COMPRESSION_RLE4,
|
||||||
|
//SANE_COMPRESSION_RLE8,
|
||||||
|
//SANE_COMPRESSION_BITFIELDS,
|
||||||
|
//SANE_COMPRESSION_ZIZ,
|
||||||
|
//SANE_COMPRESSION_JPEG2000,
|
||||||
|
|
||||||
|
SANE_COMPRESSION_LAST,
|
||||||
|
SANE_COMPRESSION_DONTCARE = 0xFFFF,
|
||||||
|
}SANE_CompressionType;
|
||||||
|
typedef struct _img_compression
|
||||||
|
{
|
||||||
|
SANE_CompressionType compression;
|
||||||
|
void* detail; // see SANE_CompressionType (该参数在当前版本不考虑,暂使用压缩类型的默认值)
|
||||||
|
}SANE_Compression;
|
||||||
|
typedef enum // 与Twpp::ImageFileFormat 保持一致
|
||||||
|
{
|
||||||
|
SANE_IMAGE_TYPE_FIRST = 0,
|
||||||
|
SANE_IMAGE_TYPE_TIFF = 0,
|
||||||
|
SANE_IMAGE_TYPE_BMP = 2, // (BITMAPINFOHEADER*)detail
|
||||||
|
SANE_IMAGE_TYPE_PNG = 7,
|
||||||
|
SANE_IMAGE_TYPE_JPG = 13,
|
||||||
|
SANE_IMAGE_TYPE_JFIF = 4,
|
||||||
|
SANE_IMAGE_TYPE_PDF = 10,
|
||||||
|
|
||||||
|
// 以下为Twpp::ImageFileFormat不存在的值
|
||||||
|
SANE_IMAGE_TYPE_GIF = 100,
|
||||||
|
SANE_IMAGE_TYPE_WEBP,
|
||||||
|
SANE_IMAGE_TYPE_SVG,
|
||||||
|
SANE_IMAGE_TYPE_LAST,
|
||||||
|
}SANE_ImageType;
|
||||||
|
typedef struct _img_final_fmt
|
||||||
|
{
|
||||||
|
SANE_ImageType img_format;
|
||||||
|
void* detail; // see SANE_ImageType (该参数在当前版本不考虑,暂使用该图像类型的默认值)
|
||||||
|
SANE_Compression compress;
|
||||||
|
}SANE_FinalImgFormat;
|
||||||
|
typedef struct _img_format_convert
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SANE_FinalImgFormat fmt; // format of the data
|
||||||
|
SANE_Bool is_file; // data is a 'path-file' if it was true, or else is raw file data
|
||||||
|
SANE_String_Const data; // represents a local file or a memory data. call 'IO_CTRL_CODE_FREE_MEMORY' to free the dst.data memory if 'is_file' was true !!!
|
||||||
|
unsigned int data_len; // bytes of 'data'
|
||||||
|
}src, dst;
|
||||||
|
}SANE_ImageFormatConvert;
|
||||||
|
|
||||||
|
typedef struct _sane_point
|
||||||
|
{
|
||||||
|
SANE_Byte x;
|
||||||
|
SANE_Byte y;
|
||||||
|
}SANE_Gamma_Point;
|
||||||
|
enum gamma_index
|
||||||
|
{
|
||||||
|
GAMMA_INDEX_GRAY = 0,
|
||||||
|
GAMMA_INDEX_COLOR,
|
||||||
|
GAMMA_INDEX_RED,
|
||||||
|
GAMMA_INDEX_GREEN,
|
||||||
|
GAMMA_INDEX_BLUE,
|
||||||
|
};
|
||||||
|
typedef struct _user_gamma // NOTE: exceeds 4KB !!!
|
||||||
|
{
|
||||||
|
SANE_Int apply_to_back : 8; // SANE_TRUE: 应用到背面; SANE_FALSE: 应用到正面
|
||||||
|
SANE_Int app_data : 24; // APP 自定义数据
|
||||||
|
SANE_Byte count[8]; // 控制点个数,顺序为(gamma_index): Gray + Color + Red + Green + Blue
|
||||||
|
SANE_Byte pt_gray[4]; // 灰度控制点 - 只记录横坐标,纵坐标请在table表中查得
|
||||||
|
SANE_Byte pt_color[4]; // 彩色控制点 - 只记录横坐标,纵坐标请在table表中查得
|
||||||
|
SANE_Byte pt_red[4]; // 红色控制点 - 只记录横坐标,纵坐标请在table表中查得
|
||||||
|
SANE_Byte pt_green[4]; // 绿色控制点 - 只记录横坐标,纵坐标请在table表中查得
|
||||||
|
SANE_Byte pt_blue[4]; // 蓝色控制点 - 只记录横坐标,纵坐标请在table表中查得
|
||||||
|
SANE_Byte table[5 * 256]; // gamma变换阵列,顺序为(gamma_index):Gray[256] + Color[256] + R[256] + G[256] + B[256]
|
||||||
|
}SANE_Gamma;
|
||||||
|
typedef struct _user_gamma_ex // from draft-2.0
|
||||||
|
{
|
||||||
|
SANE_Int size : 16; // size of this structure
|
||||||
|
SANE_Int ver : 8; // version
|
||||||
|
SANE_Int count : 8; // 控制点(point数组中有效元素)个数
|
||||||
|
SANE_Int side : 4; // 0 - 应用到正反面;1 - 应用到正面;2 - 应用到反面
|
||||||
|
SANE_Int channel : 4; // 0 - 灰度曲线;1 - 彩色曲线;2 - Red通道曲线;3 - Green通道曲线;4 - Blue通道曲线
|
||||||
|
SANE_Int app_data : 24; // APP 自定义数据
|
||||||
|
SANE_Byte point[4]; // 控制点 - 只记录横坐标,纵坐标请在table表中查得
|
||||||
|
SANE_Byte table[256]; // 变换表
|
||||||
|
}SANE_Gamma_Ex;
|
||||||
|
typedef struct CISTestResult
|
||||||
|
{
|
||||||
|
double w; //圆横轴
|
||||||
|
double h; //圆纵轴
|
||||||
|
double scaleXY; //圆3横纵比
|
||||||
|
|
||||||
|
SANE_Byte colorBlock1[3]; //彩色色块1RGB //余下保留
|
||||||
|
SANE_Byte colorBlock2[3]; //彩色色块2RGB
|
||||||
|
SANE_Byte colorBlock3[3]; //彩色色块3RGB
|
||||||
|
SANE_Byte colorBlock4[3]; //彩色色块4RGB
|
||||||
|
SANE_Byte colorBlock5[3]; //彩色色块5RGB
|
||||||
|
SANE_Byte colorBlock6[3]; //彩色色块6RGB
|
||||||
|
SANE_Byte colorBlock7[3]; //彩色色块7RGB
|
||||||
|
SANE_Byte colorBlock8[3]; //彩色色块8RGB
|
||||||
|
SANE_Byte colorBlock9[3]; //彩色色块9RGB
|
||||||
|
|
||||||
|
SANE_Byte grayBlock1; //灰度色块1灰度值
|
||||||
|
SANE_Byte grayBlock2; //灰度色块2灰度值
|
||||||
|
SANE_Byte grayBlock3; //灰度色块3灰度值
|
||||||
|
SANE_Byte grayBlock4; //灰度色块4灰度值
|
||||||
|
SANE_Byte grayBlock5; //灰度色块5灰度值
|
||||||
|
SANE_Byte grayBlock6; //灰度色块6灰度值
|
||||||
|
SANE_Byte grayBlock7; //灰度色块7灰度值
|
||||||
|
SANE_Byte grayBlock8; //灰度色块8灰度值
|
||||||
|
SANE_Byte grayBlock9; //灰度色块9灰度值
|
||||||
|
}SANE_DISTORTION_VAL;//获取畸变修正值
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_FUNCTION_PARAMETER_TYPE_STRING = 0, // SANE_String_List
|
||||||
|
SANE_FUNCTION_PARAMETER_TYPE_STREAM, // SANE_Stream
|
||||||
|
SANE_FUNCTION_PARAMETER_TYPE_USER_INPUT, // SANE_String
|
||||||
|
}SANE_Function_Parameter_Type;
|
||||||
|
typedef struct _sane_function_parameter
|
||||||
|
{
|
||||||
|
SANE_Function_Parameter_Type type;
|
||||||
|
}SANE_Function_Parameter;
|
||||||
|
typedef struct _sane_function
|
||||||
|
{
|
||||||
|
SANE_Int func_id;
|
||||||
|
SANE_Int parameter_count;
|
||||||
|
SANE_Function_Parameter parameter[1];
|
||||||
|
}SANE_Function;
|
||||||
|
typedef struct _sane_img_kits
|
||||||
|
{
|
||||||
|
SANE_Int kit_id;
|
||||||
|
SANE_String name;
|
||||||
|
SANE_String title;
|
||||||
|
SANE_String desc;
|
||||||
|
SANE_Stream icon;
|
||||||
|
SANE_Int function_count;
|
||||||
|
SANE_Function function[1];
|
||||||
|
}SANE_Image_Kits;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
AUTO_COLOR_BLACKWHITE = 0,
|
||||||
|
AUTO_COLOR_GRAY,
|
||||||
|
}SANE_AutoColorType;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
LOG_FILE_DEVICE = 0, // 设备端日志文件
|
||||||
|
LOG_FILE_DRIVER, // 驱动层日志文件
|
||||||
|
}SANE_LogFileType;
|
||||||
|
|
||||||
|
typedef enum // IO_CTRL_CODE_SET_POWER_LEVEL
|
||||||
|
{
|
||||||
|
SANE_POWER_FIRST = 0,
|
||||||
|
SANE_POWER_NONE = SANE_POWER_FIRST,
|
||||||
|
SANE_POWER_MINUTES_5,
|
||||||
|
SANE_POWER_MINUTES_10,
|
||||||
|
SANE_POWER_MINUTES_20,
|
||||||
|
SANE_POWER_MINUTES_30,
|
||||||
|
SANE_POWER_MINUTES_60,
|
||||||
|
SANE_POWER_MINUTES_120,
|
||||||
|
SANE_POWER_MINUTES_240,
|
||||||
|
SANE_POWER_LAST,
|
||||||
|
SANE_POWER_SHUTDOWN, // 关闭设备 239 设备重启和关闭设备不会触发热拔插,所以使用此命令时需要手动关闭设备和打开设备 1:rebootloader ,0:reboot
|
||||||
|
SANE_POWER_RESTART, // 重启设备
|
||||||
|
}SANE_Power;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SANE_EVENT_NONE = 0, // 无意义的回调, both data & len are NULL
|
||||||
|
SANE_EVENT_SUPPORT_ASYNC_IO, // 是否支持异步IO,返回“0”支持,其它不支持。data and len unused
|
||||||
|
SANE_EVENT_IS_MEMORY_ENOUGH, // 当前内存是否足够读取图片, data - unused;*len - needed size. return SCANNER_ERR_OK or SCANNER_ERR_INSUFFICIENT_MEM
|
||||||
|
SANE_EVENT_NEED_AUTH, // data - (SANEAUTH*); len - unused; return none-zero to giveup
|
||||||
|
SANE_EVENT_DEVICE_ARRIVED, // data - SANE_Device_Ex*; *len - sizeof(SANE_Device_Ex)
|
||||||
|
SANE_EVENT_DEVICE_LEFT, // data - SANE_Device*; *len - sizeof(SANE_Device)
|
||||||
|
SANE_EVENT_STATUS, // normal status description. data - (utf8*), len - unused, be NULL
|
||||||
|
SANE_EVENT_ERROR, // error happens, should stop operations. data - (utf8*)description, *len - error code
|
||||||
|
SANE_EVENT_WORKING, // 扫描仪正在扫描, data - (char*)description, len - unused
|
||||||
|
SANE_EVENT_USB_DATA_RECEIVED, // 从USB读取到一个图片数据包,当前只用作纸张统计。data - NULL, *len - bytes
|
||||||
|
SANE_EVENT_IMAGE_OK, // new image data is ready for UI. data - (SANE_Image*), *len - index of the image (ZERO base)
|
||||||
|
SANE_EVENT_IMAGE_EXT_INFO_OK, // new image data is ready for UI. data - (SANE_Img_Ext_Info*), *len - index of the image (ZERO base)
|
||||||
|
SANE_EVENT_SCAN_FINISHED, // 扫描仪完成扫描, data - (char*)description, *len - error code
|
||||||
|
SANE_EVENT_ABOUT_INFORMATION, // APP关于信息, data - (SANE_About*), len - unused, be NULL
|
||||||
|
SANE_EVENT_SCANNER_CLOSED, // 扫描仪已经关闭,data & len 同 SANE_EVENT_STATUS
|
||||||
|
SANE_EVENT_IMG_UPLOADED, // APP取走一张图片, data - unused, len - count
|
||||||
|
// SANE_EVENT_WIN_DEBUG_INFO, // writedown debug info on windows platform ... data - (utf8*), *len - HG_LOG_LEVEL, param - NULL !!!
|
||||||
|
|
||||||
|
// ui event ...
|
||||||
|
SANE_EVENT_UI_CLOSE_CANCEL = 0x1000,
|
||||||
|
SANE_EVENT_UI_CLOSE_NORMAL,
|
||||||
|
SANE_EVENT_UI_SCAN_COMMAND, // setting ui notify button 'scan' clicked
|
||||||
|
SANE_EVENT_UI_CLOSE_SETTING,
|
||||||
|
SANE_EVENT_TWAIN_XFER_READY,
|
||||||
|
}SANE_Event;
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
// 'start' and 'stop' will be blocked until image arrived or worker-threads stopped - 2023-11-01
|
||||||
|
// callback may return before these functions !!!
|
||||||
|
// the calling program should pay more attention to this situation !!!
|
||||||
|
typedef int(*sane_callback)( // 注册回调的对象,需要保证该回调是多线程安全的
|
||||||
|
SANE_Handle hdev // 产生事件的设备句柄
|
||||||
|
, int code // 回调事件代码
|
||||||
|
, void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义
|
||||||
|
, unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码
|
||||||
|
, void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致
|
||||||
|
); // 返回值依不同的事件代码而定,通常为“0”
|
||||||
|
extern SANE_Status sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param);
|
||||||
|
|
||||||
|
enum io_code
|
||||||
|
{
|
||||||
|
IO_CTRL_CODE_BASE = 0x00C0DE111,
|
||||||
|
IO_CTRL_CODE_TEST_SINGLE = IO_CTRL_CODE_BASE,// 单张测试扫描 data - NULL, len - NULL
|
||||||
|
IO_CTRL_CODE_ABOUT_INFO, // 获取软件关于信息。data - (SANE_About*), 如果data为空或者由len指示的内存大小不足,
|
||||||
|
// 则会在len中返回所需要的最小内存长度,并返回 SANE_STATUS_NO_MEM 错误
|
||||||
|
IO_CTRL_CODE_RESTORE_SETTINGS, // 恢复默认设置 data - NULL, len - NULL
|
||||||
|
IO_CTRL_CODE_GET_DEFAULT_VALUE, // 获取设置项默认值 data - 同sane_control_option - SANE_ACTION_GET_VALUE时的定义, *len - [in] 设置项序号,同sane_control_option中option的值
|
||||||
|
IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, // 获取图像处理最终输出(final())的图像数据格式 data - (SANE_FinalImgFormat*), len - bytes of data
|
||||||
|
IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, // 设置图像处理最终输出(final())的图像数据格式 data - (SANE_FinalImgFormat*), len - bytes of data
|
||||||
|
IO_CTRL_CODE_GET_FINAL_COMPRESSION, // 获取支持的压缩格式,data - (SANE_Int*), to receive supported SANE_CompressionType, data[0]: supported counts, data[1]: default value, data[2]: current value; data[3...]: all supported values
|
||||||
|
// *len - array length of data, or need length if it was too small
|
||||||
|
IO_CTRL_CODE_SET_FINAL_COMPRESSION, // 设置图像数据最终输出的压缩格式,data - (SANE_Compression*), len - bytes of data
|
||||||
|
|
||||||
|
IO_CTRL_CODE_SET_AUTO_COLOR_TYPE, // 设置自动匹配颜色模式, data - (SANE_AutoColorType*), *len - sizeof(data)
|
||||||
|
IO_CTRL_CODE_SET_CLEAR_ROLLER_COUNT, // 清除滚轴计数 data - NULL, len - to receive current roller count, can be NULL
|
||||||
|
IO_CTRL_CODE_SET_CLEAR_HISTORY_COUNT, // 清除历史计数 data - NULL, len - to receive current history count, can be NULL
|
||||||
|
|
||||||
|
IO_CTRL_CODE_GET_DEVICE_CODE, // 获取设备编码, data - (char*), *len - bytes of data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IO_CTRL_CODE_GET_PAPER_ON, // 获取进纸盘上是否有纸, data - (SANE_Bool*), *len - sizeof(SANE_Bool) data:false 无纸 true有纸
|
||||||
|
IO_CTRL_CODE_SET_POWER_LEVEL, // 设置功耗模式(休眠), data - (SANE_Power*), *len - sizeof(SANE_Power) (包括重启设备 关闭断电)
|
||||||
|
IO_CTRL_CODE_GET_POWER_LEVEL, // 获取功耗模式(休眠), data - (SANE_Power*), *len - sizeof(SANE_Power)
|
||||||
|
|
||||||
|
|
||||||
|
IO_CTRL_CODE_GET_CUSTOM_GAMMA, // 用于获取用户自定义gamma数值,data - SANE_Gamma*, *len - to receive current color mode
|
||||||
|
IO_CTRL_CODE_SET_CUSTOM_GAMMA, // 用于设置用户自定义gamma数值,data - SANE_Gamma*, len - unused
|
||||||
|
IO_CTRL_CODE_DISPLAY_APP_HELP, // 显示APP帮助文档 data - NULL, len - NULL
|
||||||
|
IO_CTRL_CODE_GET_PAPER_SIZE, // 获取纸张尺寸(mm)。 data - (utf8*)paper name, *len - MAKELPARAM(w, h)
|
||||||
|
IO_CTRL_CODE_GET_IMAGE_QUEUE_COUNT, // 获取图像队列的长度/数量, data - NULL, len - to receive the count
|
||||||
|
IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, // 图像格式转换(文件方式), data - SANE_ImageFormatConvert*, len - unused, be NULL
|
||||||
|
IO_CTRL_CODE_FREE_MEMORY, // 释放由该模块分配的内存, data - 内存块,*len - 内存块长度
|
||||||
|
|
||||||
|
IO_CTRL_CODE_GET_LOG_FILE, // 获取日志文件,data - char[260],用于接收日志文件路径,返回空则获取失败;*len - 日志文件类型 SANE_LogFileType.
|
||||||
|
// 返回的日志文件,如果不再使用,调用者负责删除。
|
||||||
|
IO_CTRL_CODE_GET_SCAN_ISLOCK, // 获取设备是否支持锁定设备功能,data - (SANE_Bool*), *len - sizeof(SANE_Bool)
|
||||||
|
IO_CTRL_CODE_SET_SCAN_LOCK, // 设置设备锁定, data - (SANE_Bool), len - unused
|
||||||
|
IO_CTRL_CODE_SET_SCAN_LOCK_CHECK_VAL, // 设置校验码 , data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_SET_FIRMWARE_UPGRADE, // 设置固件升级, data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_GET_HISTORY_SCAN_NUM, // 获取历史张数 data - (SANE_Int*), *len - sizeof(SANE_Int)
|
||||||
|
IO_CTRL_CODE_GET_CLEAN_PAPER_ROAD, // 清除纸道 data - (SANE_Bool*), *len - sizeof(SANE_Bool)
|
||||||
|
IO_CTRL_CODE_GET_ROLLER_NUM, // 获取滚轴张数 data - (SANE_Int*), *len - sizeof(SANE_Int)
|
||||||
|
IO_CTRL_CODE_SET_FEEDMODE, // 设置分纸强度 data - (SANE_Int*) ,*len - sizeof(SANE_Int) data: 0 ,1 ,2)
|
||||||
|
IO_CTRL_CODE_SET_SKEW_CHECK, // 设置歪斜检测 data - (SANE_Bool*), *len - sizeof(SANE_Bool)
|
||||||
|
IO_CTRL_CODE_SET_SKEW_CHECK_VAL, // 设置歪斜检测值 data - (SANE_Int*), *len - sizeof(SANE_Int)
|
||||||
|
IO_CTRL_CODE_GET_IS_MODE, // 获取是否计数模式 data - (SANE_Bool*), *len - sizeof(SANE_Bool)
|
||||||
|
IO_CTRL_CODE_SET_ULTRASONIC_MODULE, // 设置超声波检测 data - (SANE_Bool*), *len - sizeof(SANE_Bool)
|
||||||
|
IO_CTRL_CODE_SET_SPEED_MODE, // 设置速度模式 data - (SANE_Int*) ,*len - sizeof(SANE_Int) data = G100-G200:100,110,120 G300:40,50,60,70 G400:40,50,60,70,80
|
||||||
|
IO_CTRL_CODE_GET_SPEED_MODE, // 获取速度模式 data - (SANE_Int*) ,*len - sizeof(SANE_Int)
|
||||||
|
IO_CTRL_CODE_SET_CIS_IMAGE, // 获取CIS原图 data - (SANE_Bool*), *len - sizeof(SANE_Bool)
|
||||||
|
IO_CTRL_CODE_GET_IMAGE, // 批量扫描 data - NULL,*len-NULL
|
||||||
|
|
||||||
|
IO_CTRL_CODE_SET_DISTORTION_IMAGE, // 设置畸变校正图 data - NULL,*len-NULL
|
||||||
|
IO_CTRL_CODE_GET_PC_DISTORTION_CHECK_VAL, // 获取PC计算畸变校正值 data - (SANE_DISTORTION_VAL*) ,*len - sizeof(SANE_DISTORTION_VAL) //通过PC算法计算获取的畸变值
|
||||||
|
IO_CTRL_CODE_SET_DISTORTION_DEVS_CHECK_VAL, // 设置设备畸变值 data - (float*) ,*len - sizeof(float)
|
||||||
|
IO_CTRL_CODE_GET_DISTORTION_DEVS_CHECK_VAL, // 获取设备畸变值 data - (float*) ,*len - sizeof(float)
|
||||||
|
|
||||||
|
IO_CTRL_CODE_SET_DEVS_REBOOT, // 设置设备重启 data - (SANE_Int*) ,*len - sizeof(SANE_Int) data 1:loader,data 0:普通重启
|
||||||
|
IO_CTRL_CODE_SET_AUTO_FALT, // 设置自动平场校正 data - (int *),*len - sizeof(SANE_Int)
|
||||||
|
// data:0(ALL) 1(200dpi、gray) 2(200dpi、color) 3(300dpi、gray) 4(300dpi、color) 5(600dpi、gray) 6(600dpi、color)
|
||||||
|
|
||||||
|
IO_CTRL_CODE_SET_COLOR, // 设置颜色 data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_SET_DPI, // 设置DPI data - (int *) *len - sizeof(int)
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////固定的硬件信息//////////////
|
||||||
|
IO_CTRL_CODE_SET_VIDPID, // 设置VID PID, data - (int *) *len - sizeof(int)
|
||||||
|
IO_CTRL_CODE_GET_VIDPID, // 获取VID PID, data - (int *) *len - sizeof(int)
|
||||||
|
IO_CTRL_CODE_SET_SERIAL, // 设置设备序列号 data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_GET_SERIAL, // 获取设备序列号, data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_GET_HARDWARE_VERSION, // 获取硬件版本号, data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_GET_IP, // 获取设备IP, data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_SET_DEVS_MODEL, // 获取设备型号, data - (char*), *len - bytes of data
|
||||||
|
IO_CTRL_CODE_GET_DEVS_MODEL, // 设置设备型号, data - (char*), *len - bytes of data
|
||||||
|
|
||||||
|
///////////////////////未使用//////////////暂时保留
|
||||||
|
IO_CTRL_CODE_GET_SCAN_WHEN_PAPER_ON, //获取是否带纸扫描
|
||||||
|
IO_CTRL_CODE_SET_SCAN_WHEN_PAPER_ON, //设置带纸扫描
|
||||||
|
IO_CTRL_CODE_GET_SCAN_WITH_HOLE, //获取是否穿孔移除
|
||||||
|
IO_CTRL_CODE_SET_SCAN_WITH_HOLE, //设置穿孔移除
|
||||||
|
// all control code must be less than the following value
|
||||||
|
IO_CTRL_CODE_LAST = 0x10000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: 直接访问控制
|
||||||
|
//
|
||||||
|
// Parameter: h - hg_open_scanner打开的设备句柄
|
||||||
|
//
|
||||||
|
// code - 控制码
|
||||||
|
//
|
||||||
|
// data - 用户分配的内存,对应于控制码的原始数据
|
||||||
|
//
|
||||||
|
// len - data中数据长度。如果是获取操作时,长度小于所需要的长度,则返回需要的长度且返回 E_INSUFFICIENTMEM 的错误
|
||||||
|
//
|
||||||
|
// Return: 错误码
|
||||||
|
extern SANE_Status sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len);
|
||||||
|
|
||||||
|
// Function: 获取错误描述
|
||||||
|
//
|
||||||
|
// Parameters: err - 其它SANE函数返回的错误代码
|
||||||
|
//
|
||||||
|
// Return: 错误描述信息(UTF-8),调用者应立即使用,无须释放
|
||||||
|
extern const char* sane_err_desc(SANE_Status err);
|
||||||
|
|
||||||
|
// Function: 读取刚刚(调用sane_get_parameters后)获取的图片的扩展信息
|
||||||
|
//
|
||||||
|
// Parameter: ext_info - 用户分配的用户获取扩展信息的内存地址
|
||||||
|
//
|
||||||
|
// len - [in]: ext_info 空间大小; [out] - ext_info中实际存储的字节数,或者空间不足时需要的最小字节数
|
||||||
|
//
|
||||||
|
// Return: 错误码:SANE_STATUS_GOOD - 成功获取到图像扩展信息
|
||||||
|
// SANE_STATUS_NO_DOCS - 该图片没有扩展信息
|
||||||
|
// SANE_STATUS_NO_MEM - 空间不足,最小空间已经存储在参数len中
|
||||||
|
// SANE_STATUS_UNSUPPORTED - 当前版本不支持该项操作
|
||||||
|
extern SANE_Status sane_read_ext_info(SANE_Img_Ext_Info* ext_info, SANE_Int* len);
|
||||||
|
|
||||||
|
// for ui interface
|
||||||
|
typedef struct _sane_api
|
||||||
|
{
|
||||||
|
SANE_Status (*sane_get_devices_api)(const SANE_Device*** device_list, SANE_Bool local_only);
|
||||||
|
SANE_Status (*sane_open_api)(SANE_String_Const devicename, SANE_Handle* handle);
|
||||||
|
void (* sane_close_api)(SANE_Handle handle);
|
||||||
|
const SANE_Option_Descriptor* (*sane_get_option_descriptor_api)(SANE_Handle handle, SANE_Int option);
|
||||||
|
SANE_Status (*sane_control_option_api)(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info);
|
||||||
|
SANE_Status (*sane_get_parameters_api)(SANE_Handle handle, SANE_Parameters* params);
|
||||||
|
SANE_Status (*sane_start_api)(SANE_Handle handle);
|
||||||
|
SANE_Status (*sane_read_api)(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length);
|
||||||
|
void (*sane_cancel_api)(SANE_Handle handle);
|
||||||
|
SANE_Status (*sane_set_io_mode_api)(SANE_Handle handle, SANE_Bool non_blocking);
|
||||||
|
SANE_Status (*sane_get_select_fd_api)(SANE_Handle handle, SANE_Int* fd);
|
||||||
|
SANE_String_Const (*sane_strstatus_api)(SANE_Status status);
|
||||||
|
SANE_Status (*sane_io_control_api)(SANE_Handle h, unsigned long code, void* data, unsigned* len);
|
||||||
|
SANE_Status (*sane_init_api)(SANE_Int* version_code, SANE_Auth_Callback authorize);
|
||||||
|
void (*sane_exit_api)(void);
|
||||||
|
}SANEAPI, *LPSANEAPI;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include <string>
|
||||||
|
//
|
||||||
|
//template<typename ... Args>
|
||||||
|
//std::string format_string(int level, const char* fmt, Args ... args)
|
||||||
|
//{
|
||||||
|
// size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
|
||||||
|
// std::string str(size);
|
||||||
|
//
|
||||||
|
// snprintf(&str[0], size, fmt, args ...);
|
||||||
|
//
|
||||||
|
// return std::move(str);
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endif /* sane_ex_h */
|
|
@ -0,0 +1,508 @@
|
||||||
|
//
|
||||||
|
// definitions for option titles and values
|
||||||
|
//
|
||||||
|
// all multi-bytes letter are in UTF-8 format
|
||||||
|
//
|
||||||
|
// Date: 2022-09-30 14:23:02
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_HFMRSZ "恢复默认设置"
|
||||||
|
#define OPTION_TITLE_HFMRSZ "\346\201\242\345\244\215\351\273\230\350\256\244\350\256\276\347\275\256"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BZ "帮助"
|
||||||
|
#define OPTION_TITLE_BZ "\345\270\256\345\212\251"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_DLSC "多流输出"
|
||||||
|
#define OPTION_TITLE_DLSC "\345\244\232\346\265\201\350\276\223\345\207\272"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_DLSCLX "多流输出类型"
|
||||||
|
#define OPTION_TITLE_DLSCLX "\345\244\232\346\265\201\350\276\223\345\207\272\347\261\273\345\236\213"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_DLSCLX_W "无"
|
||||||
|
#define OPTION_VALUE_DLSCLX_W "\346\227\240"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_DLSCLX_CS_HD_HB "彩色+灰度+黑白"
|
||||||
|
#define OPTION_VALUE_DLSCLX_CS_HD_HB "\345\275\251\350\211\262+\347\201\260\345\272\246+\351\273\221\347\231\275"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_DLSCLX_CS_HD "彩色+灰度"
|
||||||
|
#define OPTION_VALUE_DLSCLX_CS_HD "\345\275\251\350\211\262+\347\201\260\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_DLSCLX_CS_HB "彩色+黑白"
|
||||||
|
#define OPTION_VALUE_DLSCLX_CS_HB "\345\275\251\350\211\262+\351\273\221\347\231\275"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_DLSCLX_HD_HB "灰度+黑白"
|
||||||
|
#define OPTION_VALUE_DLSCLX_HD_HB "\347\201\260\345\272\246+\351\273\221\347\231\275"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_YSMS "颜色模式"
|
||||||
|
#define OPTION_TITLE_YSMS "\351\242\234\350\211\262\346\250\241\345\274\217"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_YSMS_24WCS "24位彩色"
|
||||||
|
#define OPTION_VALUE_YSMS_24WCS "24\344\275\215\345\275\251\350\211\262"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_YSMS_256JHD "256级灰度"
|
||||||
|
#define OPTION_VALUE_YSMS_256JHD "256\347\272\247\347\201\260\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_YSMS_HB "黑白"
|
||||||
|
#define OPTION_VALUE_YSMS_HB "\351\273\221\347\231\275"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_YSMS_YSZDSB "颜色自动识别"
|
||||||
|
#define OPTION_VALUE_YSMS_YSZDSB "\351\242\234\350\211\262\350\207\252\345\212\250\350\257\206\345\210\253"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_HBTXYZ "黑白图像阈值"
|
||||||
|
#define OPTION_TITLE_HBTXYZ "\351\273\221\347\231\275\345\233\276\345\203\217\351\230\210\345\200\274"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_HBTXFSSC "黑白图像反色输出"
|
||||||
|
#define OPTION_TITLE_HBTXFSSC "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_HDHHBTX_CSYZQ "灰度或黑白图像 - 除色与增强"
|
||||||
|
#define OPTION_TITLE_HDHHBTX_CSYZQ "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262\344\270\216\345\242\236\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_BCS "不除色"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_BCS "\344\270\215\351\231\244\350\211\262"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_CHS "除红色"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_CHS "\351\231\244\347\272\242\350\211\262"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_CLS "除绿色"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_CLS "\351\231\244\347\273\277\350\211\262"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_CHULANSE "除蓝色"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_CHULANSE "\351\231\244\350\223\235\350\211\262"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_HSZQ "红色增强"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_HSZQ "\347\272\242\350\211\262\345\242\236\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_LSZQ "绿色增强"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_LSZQ "\347\273\277\350\211\262\345\242\236\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HDHHBTX_CSYZQ_LANSEZENGQIANG "蓝色增强"
|
||||||
|
#define OPTION_VALUE_HDHHBTX_CSYZQ_LANSEZENGQIANG "\350\223\235\350\211\262\345\242\236\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_24WCSTX_DLSCCH "24位彩色图像 - 多流输出除红"
|
||||||
|
#define OPTION_TITLE_24WCSTX_DLSCCH "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217 - \345\244\232\346\265\201\350\276\223\345\207\272\351\231\244\347\272\242"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_24WCSTX_DTKCH "24位彩色图像 - 答题卡除红"
|
||||||
|
#define OPTION_TITLE_24WCSTX_DTKCH "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217 - \347\255\224\351\242\230\345\215\241\351\231\244\347\272\242"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BJYC "背景移除"
|
||||||
|
#define OPTION_TITLE_BJYC "\350\203\214\346\231\257\347\247\273\351\231\244"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BJSCFDFW "背景色彩浮动范围"
|
||||||
|
#define OPTION_TITLE_BJSCFDFW "\350\203\214\346\231\257\350\211\262\345\275\251\346\265\256\345\212\250\350\214\203\345\233\264"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_RHYMH "锐化与模糊"
|
||||||
|
#define OPTION_TITLE_RHYMH "\351\224\220\345\214\226\344\270\216\346\250\241\347\263\212"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_RHYMH_W "无"
|
||||||
|
#define OPTION_VALUE_RHYMH_W "\346\227\240"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_RHYMH_RH "锐化"
|
||||||
|
#define OPTION_VALUE_RHYMH_RH "\351\224\220\345\214\226"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_RHYMH_JYBRH "进一步锐化"
|
||||||
|
#define OPTION_VALUE_RHYMH_JYBRH "\350\277\233\344\270\200\346\255\245\351\224\220\345\214\226"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_RHYMH_MH "模糊"
|
||||||
|
#define OPTION_VALUE_RHYMH_MH "\346\250\241\347\263\212"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_RHYMH_JYBMH "进一步模糊"
|
||||||
|
#define OPTION_VALUE_RHYMH_JYBMH "\350\277\233\344\270\200\346\255\245\346\250\241\347\263\212"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_QCMW "去除摩尔纹"
|
||||||
|
#define OPTION_TITLE_QCMW "\345\216\273\351\231\244\346\221\251\345\260\224\347\272\271"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CWW "除网纹"
|
||||||
|
#define OPTION_TITLE_CWW "\351\231\244\347\275\221\347\272\271"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CWKS "错误扩散"
|
||||||
|
#define OPTION_TITLE_CWKS "\351\224\231\350\257\257\346\211\251\346\225\243"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_HBTXZDYH "黑白图像噪点优化"
|
||||||
|
#define OPTION_TITLE_HBTXZDYH "\351\273\221\347\231\275\345\233\276\345\203\217\345\231\252\347\202\271\344\274\230\345\214\226"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZDYHCC "噪点优化尺寸"
|
||||||
|
#define OPTION_TITLE_ZDYHCC "\345\231\252\347\202\271\344\274\230\345\214\226\345\260\272\345\257\270"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZZCC "纸张尺寸"
|
||||||
|
#define OPTION_TITLE_ZZCC "\347\272\270\345\274\240\345\260\272\345\257\270"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A3 "A3"
|
||||||
|
#define OPTION_VALUE_ZZCC_A3 "A3"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_8K "8开"
|
||||||
|
#define OPTION_VALUE_ZZCC_8K "8\345\274\200"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A4 "A4"
|
||||||
|
#define OPTION_VALUE_ZZCC_A4 "A4"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A4HX "A4横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_A4HX "A4\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_16K "16开"
|
||||||
|
#define OPTION_VALUE_ZZCC_16K "16\345\274\200"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_16KHX "16开横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_16KHX "16\345\274\200\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A5 "A5"
|
||||||
|
#define OPTION_VALUE_ZZCC_A5 "A5"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A5HX "A5横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_A5HX "A5\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A6 "A6"
|
||||||
|
#define OPTION_VALUE_ZZCC_A6 "A6"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_A6HX "A6横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_A6HX "A6\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_B4 "B4"
|
||||||
|
#define OPTION_VALUE_ZZCC_B4 "B4"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_B5 "B5"
|
||||||
|
#define OPTION_VALUE_ZZCC_B5 "B5"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_B5HX "B5横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_B5HX "B5\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_B6 "B6"
|
||||||
|
#define OPTION_VALUE_ZZCC_B6 "B6"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_B6HX "B6横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_B6HX "B6\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_Letter "Letter"
|
||||||
|
#define OPTION_VALUE_ZZCC_Letter "Letter"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_LetterHX "Letter横向"
|
||||||
|
#define OPTION_VALUE_ZZCC_LetterHX "Letter\346\250\252\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_DoubleLetter "Double Letter"
|
||||||
|
#define OPTION_VALUE_ZZCC_DoubleLetter "Double Letter"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_LEGAL "LEGAL"
|
||||||
|
#define OPTION_VALUE_ZZCC_LEGAL "LEGAL"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_PPYSCC "匹配原始尺寸"
|
||||||
|
#define OPTION_VALUE_ZZCC_PPYSCC "\345\214\271\351\205\215\345\216\237\345\247\213\345\260\272\345\257\270"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_ZDSMCCZDCQ "最大扫描尺寸自动裁切"
|
||||||
|
#define OPTION_VALUE_ZZCC_ZDSMCCZDCQ "\346\234\200\345\244\247\346\211\253\346\217\217\345\260\272\345\257\270\350\207\252\345\212\250\350\243\201\345\210\207"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_ZDSMCC "最大扫描尺寸"
|
||||||
|
#define OPTION_VALUE_ZZCC_ZDSMCC "\346\234\200\345\244\247\346\211\253\346\217\217\345\260\272\345\257\270"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_ZZCC_SLSJ "三联试卷"
|
||||||
|
#define OPTION_VALUE_ZZCC_SLSJ "\344\270\211\350\201\224\350\257\225\345\215\267"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZDYSMQY "自定义扫描区域"
|
||||||
|
#define OPTION_TITLE_ZDYSMQY "\350\207\252\345\256\232\344\271\211\346\211\253\346\217\217\345\214\272\345\237\237"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMQYZCmm "扫描区域左侧(mm)"
|
||||||
|
#define OPTION_TITLE_SMQYZCmm "\346\211\253\346\217\217\345\214\272\345\237\237\345\267\246\344\276\247\357\274\210mm\357\274\211"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMQYYCmm "扫描区域右侧(mm)"
|
||||||
|
#define OPTION_TITLE_SMQYYCmm "\346\211\253\346\217\217\345\214\272\345\237\237\345\217\263\344\276\247\357\274\210mm\357\274\211"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMQYSCmm "扫描区域上侧(mm)"
|
||||||
|
#define OPTION_TITLE_SMQYSCmm "\346\211\253\346\217\217\345\214\272\345\237\237\344\270\212\344\276\247\357\274\210mm\357\274\211"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMQYXCmm "扫描区域下侧(mm)"
|
||||||
|
#define OPTION_TITLE_SMQYXCmm "\346\211\253\346\217\217\345\214\272\345\237\237\344\270\213\344\276\247\357\274\210mm\357\274\211"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CCJC "尺寸检测"
|
||||||
|
#define OPTION_TITLE_CCJC "\345\260\272\345\257\270\346\243\200\346\265\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMYM "扫描页面"
|
||||||
|
#define OPTION_TITLE_SMYM "\346\211\253\346\217\217\351\241\265\351\235\242"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMYM_DM "单面"
|
||||||
|
#define OPTION_VALUE_SMYM_DM "\345\215\225\351\235\242"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMYM_SM "双面"
|
||||||
|
#define OPTION_VALUE_SMYM_SM "\345\217\214\351\235\242"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMYM_TGKBYTY "跳过空白页(通用)"
|
||||||
|
#define OPTION_VALUE_SMYM_TGKBYTY "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\357\274\210\351\200\232\347\224\250\357\274\211"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMYM_TGKBYFPZ "跳过空白页(发票纸)"
|
||||||
|
#define OPTION_VALUE_SMYM_TGKBYFPZ "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\357\274\210\345\217\221\347\245\250\347\272\270\357\274\211"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMYM_DZ "对折"
|
||||||
|
#define OPTION_VALUE_SMYM_DZ "\345\257\271\346\212\230"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_TGKBYLMD "跳过空白页灵敏度"
|
||||||
|
#define OPTION_TITLE_TGKBYLMD "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\347\201\265\346\225\217\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_FBL "分辨率"
|
||||||
|
#define OPTION_TITLE_FBL "\345\210\206\350\276\250\347\216\207"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_HZ "画质"
|
||||||
|
#define OPTION_TITLE_HZ "\347\224\273\350\264\250"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HZ_W "无"
|
||||||
|
#define OPTION_VALUE_HZ_W "\346\227\240"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HZ_SDYX "速度优先"
|
||||||
|
#define OPTION_VALUE_HZ_SDYX "\351\200\237\345\272\246\344\274\230\345\205\210"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_HZ_HZYX "画质优先"
|
||||||
|
#define OPTION_VALUE_HZ_HZYX "\347\224\273\350\264\250\344\274\230\345\205\210"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_JHZFM "交换正反面"
|
||||||
|
#define OPTION_TITLE_JHZFM "\344\272\244\346\215\242\346\255\243\345\217\215\351\235\242"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_QYSDQX "启用色调曲线"
|
||||||
|
#define OPTION_TITLE_QYSDQX "\345\220\257\347\224\250\350\211\262\350\260\203\346\233\262\347\272\277"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_LDZ "亮度值"
|
||||||
|
#define OPTION_TITLE_LDZ "\344\272\256\345\272\246\345\200\274"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_DBD "对比度"
|
||||||
|
#define OPTION_TITLE_DBD "\345\257\271\346\257\224\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_JMZ "伽马值"
|
||||||
|
#define OPTION_TITLE_JMZ "\344\274\275\351\251\254\345\200\274"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZDJP "自动纠偏"
|
||||||
|
#define OPTION_TITLE_ZDJP "\350\207\252\345\212\250\347\272\240\345\201\217"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_TXCF "图像拆分"
|
||||||
|
#define OPTION_TITLE_TXCF "\345\233\276\345\203\217\346\213\206\345\210\206"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZPMS "照片模式"
|
||||||
|
#define OPTION_TITLE_ZPMS "\347\205\247\347\211\207\346\250\241\345\274\217"
|
||||||
|
|
||||||
|
//#define OPTION_TITLE_XCHK "消除黑框"
|
||||||
|
#define OPTION_TITLE_XCHK "\346\266\210\351\231\244\351\273\221\346\241\206"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BJTCFS "背景填充方式"
|
||||||
|
#define OPTION_TITLE_BJTCFS "\350\203\214\346\231\257\345\241\253\345\205\205\346\226\271\345\274\217"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_BJTCFS_TDBX "凸多边形"
|
||||||
|
#define OPTION_VALUE_BJTCFS_TDBX "\345\207\270\345\244\232\350\276\271\345\275\242"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_BJTCFS_ADBX "凹多边形"
|
||||||
|
#define OPTION_VALUE_BJTCFS_ADBX "\345\207\271\345\244\232\350\276\271\345\275\242"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SCTC "色彩填充"
|
||||||
|
#define OPTION_TITLE_SCTC "\350\211\262\345\275\251\345\241\253\345\205\205"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_YZ "阈值"
|
||||||
|
#define OPTION_TITLE_YZ "\351\230\210\345\200\274"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BJKZDJ "背景抗噪等级"
|
||||||
|
#define OPTION_TITLE_BJKZDJ "\350\203\214\346\231\257\346\212\227\345\231\252\347\255\211\347\272\247"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BYSJ "边缘缩进"
|
||||||
|
#define OPTION_TITLE_BYSJ "\350\276\271\347\274\230\347\274\251\350\277\233"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SSYZ "深色样张"
|
||||||
|
#define OPTION_TITLE_SSYZ "\346\267\261\350\211\262\346\240\267\345\274\240"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_FZST "防止渗透"
|
||||||
|
#define OPTION_TITLE_FZST "\351\230\262\346\255\242\346\270\227\351\200\217"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_FZSTDJ "防止渗透等级"
|
||||||
|
#define OPTION_TITLE_FZSTDJ "\351\230\262\346\255\242\346\270\227\351\200\217\347\255\211\347\272\247"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZSTDJ_R "弱"
|
||||||
|
#define OPTION_VALUE_FZSTDJ_R "\345\274\261"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZSTDJ_JR "较弱"
|
||||||
|
#define OPTION_VALUE_FZSTDJ_JR "\350\276\203\345\274\261"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZSTDJ_YB "一般"
|
||||||
|
#define OPTION_VALUE_FZSTDJ_YB "\344\270\200\350\210\254"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZSTDJ_JQ "较强"
|
||||||
|
#define OPTION_VALUE_FZSTDJ_JQ "\350\276\203\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZSTDJ_Q "强"
|
||||||
|
#define OPTION_VALUE_FZSTDJ_Q "\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CKYC "穿孔移除"
|
||||||
|
#define OPTION_TITLE_CKYC "\347\251\277\345\255\224\347\247\273\351\231\244"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CKSSFWZFMBL "穿孔搜索范围占幅面比例"
|
||||||
|
#define OPTION_TITLE_CKSSFWZFMBL "\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CKYCZC "穿孔移除—左侧"
|
||||||
|
#define OPTION_TITLE_CKYCZC "\347\251\277\345\255\224\347\247\273\351\231\244\342\200\224\345\267\246\344\276\247"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZCCKSSFWZFMBL "左侧穿孔搜索范围占幅面比例"
|
||||||
|
#define OPTION_TITLE_ZCCKSSFWZFMBL "\345\267\246\344\276\247\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CKYCYC "穿孔移除—右侧"
|
||||||
|
#define OPTION_TITLE_CKYCYC "\347\251\277\345\255\224\347\247\273\351\231\244\342\200\224\345\217\263\344\276\247"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_YCCKSSFWZFMBL "右侧穿孔搜索范围占幅面比例"
|
||||||
|
#define OPTION_TITLE_YCCKSSFWZFMBL "\345\217\263\344\276\247\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CKYCSC "穿孔移除—上侧"
|
||||||
|
#define OPTION_TITLE_CKYCSC "\347\251\277\345\255\224\347\247\273\351\231\244\342\200\224\344\270\212\344\276\247"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SCCKSSFWZFMBL "上侧穿孔搜索范围占幅面比例"
|
||||||
|
#define OPTION_TITLE_SCCKSSFWZFMBL "\344\270\212\344\276\247\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CKYCXC "穿孔移除—下侧"
|
||||||
|
#define OPTION_TITLE_CKYCXC "\347\251\277\345\255\224\347\247\273\351\231\244\342\200\224\344\270\213\344\276\247"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_XCCKSSFWZFMBL "下侧穿孔搜索范围占幅面比例"
|
||||||
|
#define OPTION_TITLE_XCCKSSFWZFMBL "\344\270\213\344\276\247\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_DZSM "待纸扫描"
|
||||||
|
#define OPTION_TITLE_DZSM "\345\276\205\347\272\270\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMZS "扫描张数"
|
||||||
|
#define OPTION_TITLE_SMZS "\346\211\253\346\217\217\345\274\240\346\225\260"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMZS_LXSM "连续扫描"
|
||||||
|
#define OPTION_VALUE_SMZS_LXSM "\350\277\236\347\273\255\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SMZS_SMZDZS "扫描指定张数"
|
||||||
|
#define OPTION_VALUE_SMZS_SMZDZS "\346\211\253\346\217\217\346\214\207\345\256\232\345\274\240\346\225\260"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SMSL "扫描数量"
|
||||||
|
#define OPTION_TITLE_SMSL "\346\211\253\346\217\217\346\225\260\351\207\217"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_WGFX "文稿方向"
|
||||||
|
#define OPTION_TITLE_WGFX "\346\226\207\347\250\277\346\226\271\345\220\221"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_WGFX_0 "0°"
|
||||||
|
#define OPTION_VALUE_WGFX_0 "0\302\260"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_WGFX_90 "90°"
|
||||||
|
#define OPTION_VALUE_WGFX_90 "90\302\260"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_WGFX_180 "180°"
|
||||||
|
#define OPTION_VALUE_WGFX_180 "180\302\260"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_WGFX__90 "-90°"
|
||||||
|
#define OPTION_VALUE_WGFX__90 "-90\302\260"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_WGFX_ZDWBFXSB "自动文本方向识别°"
|
||||||
|
#define OPTION_VALUE_WGFX_ZDWBFXSB "\350\207\252\345\212\250\346\226\207\346\234\254\346\226\271\345\220\221\350\257\206\345\210\253\302\260"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_BMXZ180 "背面旋转180°"
|
||||||
|
#define OPTION_TITLE_BMXZ180 "\350\203\214\351\235\242\346\227\213\350\275\254180\302\260"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_CSBJC "超声波检测"
|
||||||
|
#define OPTION_TITLE_CSBJC "\350\266\205\345\243\260\346\263\242\346\243\200\346\265\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_SZTPCL "双张图片处理"
|
||||||
|
#define OPTION_TITLE_SZTPCL "\345\217\214\345\274\240\345\233\276\347\211\207\345\244\204\347\220\206"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SZTPCL_DQTXBTZSM "丢弃图像并停止扫描"
|
||||||
|
#define OPTION_VALUE_SZTPCL_DQTXBTZSM "\344\270\242\345\274\203\345\233\276\345\203\217\345\271\266\345\201\234\346\255\242\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SZTPCL_DQTXBJXSM "丢弃图像并继续扫描"
|
||||||
|
#define OPTION_VALUE_SZTPCL_DQTXBJXSM "\344\270\242\345\274\203\345\233\276\345\203\217\345\271\266\347\273\247\347\273\255\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SZTPCL_SCTXBTZSM "上传图像并停止扫描"
|
||||||
|
#define OPTION_VALUE_SZTPCL_SCTXBTZSM "\344\270\212\344\274\240\345\233\276\345\203\217\345\271\266\345\201\234\346\255\242\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_SZTPCL_SCTXBJXSM "上传图像并继续扫描"
|
||||||
|
#define OPTION_VALUE_SZTPCL_SCTXBJXSM "\344\270\212\344\274\240\345\233\276\345\203\217\345\271\266\347\273\247\347\273\255\346\211\253\346\217\217"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZDJC "装订检测"
|
||||||
|
#define OPTION_TITLE_ZDJC "\350\243\205\350\256\242\346\243\200\346\265\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_WXJC "歪斜检测"
|
||||||
|
#define OPTION_TITLE_WXJC "\346\255\252\346\226\234\346\243\200\346\265\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_WXRRD "歪斜容忍度"
|
||||||
|
#define OPTION_TITLE_WXRRD "\346\255\252\346\226\234\345\256\271\345\277\215\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZJJC "折角检测"
|
||||||
|
#define OPTION_TITLE_ZJJC "\346\212\230\350\247\222\346\243\200\346\265\213"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZJDX "折角大小"
|
||||||
|
#define OPTION_TITLE_ZJDX "\346\212\230\350\247\222\345\244\247\345\260\217"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_FZQD "分纸强度"
|
||||||
|
#define OPTION_TITLE_FZQD "\345\210\206\347\272\270\345\274\272\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZQD_R "弱"
|
||||||
|
#define OPTION_VALUE_FZQD_R "\345\274\261"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZQD_YB "一般"
|
||||||
|
#define OPTION_VALUE_FZQD_YB "\344\270\200\350\210\254"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_FZQD_Q "强"
|
||||||
|
#define OPTION_VALUE_FZQD_Q "\345\274\272"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_XMSJ "休眠时间"
|
||||||
|
#define OPTION_TITLE_XMSJ "\344\274\221\347\234\240\346\227\266\351\227\264"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_BXM "不休眠"
|
||||||
|
#define OPTION_VALUE_XMSJ_BXM "\344\270\215\344\274\221\347\234\240"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_WFZ "五分钟"
|
||||||
|
#define OPTION_VALUE_XMSJ_WFZ "\344\272\224\345\210\206\351\222\237"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_SFZ "十分钟"
|
||||||
|
#define OPTION_VALUE_XMSJ_SFZ "\345\215\201\345\210\206\351\222\237"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_BXS "半小时"
|
||||||
|
#define OPTION_VALUE_XMSJ_BXS "\345\215\212\345\260\217\346\227\266"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_YXS "一小时"
|
||||||
|
#define OPTION_VALUE_XMSJ_YXS "\344\270\200\345\260\217\346\227\266"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_LXS "两小时"
|
||||||
|
#define OPTION_VALUE_XMSJ_LXS "\344\270\244\345\260\217\346\227\266"
|
||||||
|
|
||||||
|
// #define OPTION_VALUE_XMSJ_SXS "四小时"
|
||||||
|
#define OPTION_VALUE_XMSJ_SXS "\345\233\233\345\260\217\346\227\266"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_ZDFZQD "自动分纸强度"
|
||||||
|
#define OPTION_TITLE_ZDFZQD "\350\207\252\345\212\250\345\210\206\347\272\270\345\274\272\345\272\246"
|
||||||
|
|
||||||
|
// #define OPTION_TITLE_JZSBL "进纸失败率"
|
||||||
|
#define OPTION_TITLE_JZSBL "\350\277\233\347\272\270\345\244\261\350\264\245\347\216\207"
|
||||||
|
|
||||||
|
//#define OPTION_TITLE_DZMS "对折模式"
|
||||||
|
#define OPTION_TITLE_DZMS "\345\257\271\346\212\230\346\250\241\345\274\217"
|
||||||
|
|
||||||
|
//#define OPTION_VALUE_ZYDZ "左右对折"
|
||||||
|
#define OPTION_VALUE_ZYDZ "\345\267\246\345\217\263\345\257\271\346\212\230"
|
||||||
|
|
||||||
|
//#define OPTION_VALUE_SXDZ "上下对折"
|
||||||
|
#define OPTION_VALUE_SXDZ "\344\270\212\344\270\213\345\257\271\346\212\230"
|
||||||
|
|
||||||
|
//#define OPTION_VALUE_SXDZ "自动对折"
|
||||||
|
#define OPTION_VALUE_ZDDZ "\350\207\252\345\212\250\345\257\271\346\212\230"
|
||||||
|
|
||||||
|
//#define OPTION_TITLE_SPJZ "色偏校正"
|
||||||
|
#define OPTION_TITLE_SPJZ "\350\211\262\345\201\217\346\240\241\346\255\243"
|
||||||
|
|
||||||
|
//#define OPTION_TITLE_DZSMTCSJ "待纸扫描退出时间"
|
||||||
|
#define OPTION_TITLE_DZSMTCSJ "\345\276\205\347\272\270\346\211\253\346\217\217\351\200\200\345\207\272\346\227\266\351\227\264"
|
||||||
|
|
||||||
|
//#define OPTION_TITLE_TGKBY "跳过空白页"
|
||||||
|
#define OPTION_TITLE_TGKBY "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265"
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// reserved ...
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
#define OPTION_TITLE_GMZ OPTION_TITLE_JMZ
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// string compare ...
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
#include <string.h>
|
||||||
|
#define IMPLEMENT_OPTION_STRING_COMPARE(func_name) \
|
||||||
|
bool func_name(const char* opt_define, const char* value) \
|
||||||
|
{ \
|
||||||
|
while(*value++ == L' '); \
|
||||||
|
value--; \
|
||||||
|
return strcmp(opt_define, value) == 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
/* sane - Scanner Access Now Easy.
|
||||||
|
Copyright (C) 1996 David Mosberger-Tang and Andreas Beck
|
||||||
|
Copyright (C) 2002, 2003 Henning Meier-Geinitz
|
||||||
|
|
||||||
|
This file is part of the SANE package.
|
||||||
|
|
||||||
|
SANE is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
SANE is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with sane; see the file COPYING. If not, write to the Free
|
||||||
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
As a special exception, the authors of SANE give permission for
|
||||||
|
additional uses of the libraries contained in this release of SANE.
|
||||||
|
|
||||||
|
The exception is that, if you link a SANE library with other files
|
||||||
|
to produce an executable, this does not by itself cause the
|
||||||
|
resulting executable to be covered by the GNU General Public
|
||||||
|
License. Your use of that executable is in no way restricted on
|
||||||
|
account of linking the SANE library code into it.
|
||||||
|
|
||||||
|
This exception does not, however, invalidate any other reasons why
|
||||||
|
the executable file might be covered by the GNU General Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
If you submit changes to SANE to the maintainers to be included in
|
||||||
|
a subsequent release, you agree by submitting the changes that
|
||||||
|
those changes may be distributed with this exception intact.
|
||||||
|
|
||||||
|
If you write modifications of your own for SANE, it is your choice
|
||||||
|
whether to permit this exception to apply to your modifications.
|
||||||
|
If you do not wish that, delete this exception notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file sanei.h
|
||||||
|
* Convenience macros and function declarations for backends
|
||||||
|
* @sa sanei_backend.h sanei_thread.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Doxygen documentation */
|
||||||
|
|
||||||
|
/** @mainpage SANEI (SANE internal routines) documentation
|
||||||
|
*
|
||||||
|
* @image html sane-logo2.jpg
|
||||||
|
* @section intro Introduction
|
||||||
|
*
|
||||||
|
* The header files in the include/sane/ directory named sanei_*.h provide
|
||||||
|
* function declarations and macros that can be used by every SANE backend.
|
||||||
|
* Their implementations can be found in the sanei/ directory. The code aims
|
||||||
|
* to be platform-independent to avoid lots of \#ifdef code in the backends.
|
||||||
|
* Please use the SANEI functions wherever possible.
|
||||||
|
*
|
||||||
|
* This documentation was created by the use of doxygen, the
|
||||||
|
* doc/doxygen-sanei.conf configuration file and documentation in the sanei_*.h
|
||||||
|
* files.
|
||||||
|
*
|
||||||
|
* This documentation is far from complete. Any help is appreciated.
|
||||||
|
*
|
||||||
|
* @section additional Additional documentation
|
||||||
|
* - The SANE standard can be found at <a
|
||||||
|
* href="http://www.sane-project.org/html/">the SANE webserver</a>,
|
||||||
|
* though the PostScript version produced from the source may be more recent.
|
||||||
|
* - Information on how to write a backend: <a
|
||||||
|
* href="../backend-writing.txt">backend-writing.txt</a>.
|
||||||
|
* - General SANE documentation is on <a
|
||||||
|
* href="http://www.sane-project.org/docs.html">the SANE documentation
|
||||||
|
* page</a>.
|
||||||
|
*
|
||||||
|
* @section contact Contact
|
||||||
|
*
|
||||||
|
* The common way to contact the developers of SANE is the sane-devel
|
||||||
|
* mailing list. See the <a
|
||||||
|
* href="http://www.sane-project.org/mailing-lists.html">mailing list webpage</a>
|
||||||
|
* for details. That's the place to ask questions, report bugs, or announce
|
||||||
|
* a new backend.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef sanei_h
|
||||||
|
#define sanei_h
|
||||||
|
|
||||||
|
#include <sane/sane.h>
|
||||||
|
|
||||||
|
/** @name Public macros and functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @def STRINGIFY(x)
|
||||||
|
* Turn parameter into string.
|
||||||
|
*/
|
||||||
|
/** @def PASTE(x,y)
|
||||||
|
* Concatenate parameters.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/** @def NELEMS(a)
|
||||||
|
* Return number of elements of an array.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @fn extern SANE_Status sanei_check_value (const SANE_Option_Descriptor * opt, void * value);
|
||||||
|
* Check the constraints of a SANE option.
|
||||||
|
*
|
||||||
|
* @param opt option to check
|
||||||
|
* @param value value of the option
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - SANE_STATUS_GOOD - on success
|
||||||
|
* - SANE_STATUS_INVAL - if the value doesn't fit inside the constraint
|
||||||
|
* or any other error occured
|
||||||
|
* @sa sanei_constrain_value()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @fn extern SANE_Status sanei_constrain_value (const SANE_Option_Descriptor * opt, void * value, SANE_Word * info);
|
||||||
|
* Check the constraints of a SANE option and adjust its value if necessary.
|
||||||
|
*
|
||||||
|
* Depending on the type of the option and constraint, value is modified
|
||||||
|
* to fit inside constraint.
|
||||||
|
*
|
||||||
|
* @param opt option to check
|
||||||
|
* @param value value of the option
|
||||||
|
* @param info info is set to SANE_INFO_INEXACT if value was changed
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - SANE_STATUS_GOOD - on success
|
||||||
|
* - SANE_STATUS_INVAL - if the function wasn't able to fit value into the
|
||||||
|
* constraint or any other error occured
|
||||||
|
* @sa sanei_check_value()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
/* A few convenience macros: */
|
||||||
|
/** @hideinitializer */
|
||||||
|
#define NELEMS(a) ((int)(sizeof (a) / sizeof (a[0])))
|
||||||
|
|
||||||
|
/** @hideinitializer */
|
||||||
|
#define STRINGIFY1(x) #x
|
||||||
|
/** @hideinitializer */
|
||||||
|
#define STRINGIFY(x) STRINGIFY1(x)
|
||||||
|
|
||||||
|
/** @hideinitializer */
|
||||||
|
#define PASTE1(x,y) x##y
|
||||||
|
/** @hideinitializer */
|
||||||
|
#define PASTE(x,y) PASTE1(x,y)
|
||||||
|
|
||||||
|
extern SANE_Status sanei_check_value (const SANE_Option_Descriptor * opt,
|
||||||
|
void * value);
|
||||||
|
|
||||||
|
extern SANE_Status sanei_constrain_value (const SANE_Option_Descriptor * opt,
|
||||||
|
void * value, SANE_Word * info);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* sanei_h */
|
|
@ -0,0 +1,192 @@
|
||||||
|
/** @file sanei_backend.h
|
||||||
|
* Compatibility header file for backends
|
||||||
|
*
|
||||||
|
* This file provides some defines for macros missing on some platforms.
|
||||||
|
* It also has the SANE API entry points. sanei_backend.h must be included
|
||||||
|
* by every backend.
|
||||||
|
*
|
||||||
|
* @sa sanei.h sanei_thread.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compiler related options
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Mark unused variables/parameters
|
||||||
|
*
|
||||||
|
* Tells the compiler a variable is unused, so the compiler doesn't spit a warning.
|
||||||
|
*/
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define __sane_unused__ __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define __sane_unused__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @name Compatibility macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#include "sanei_debug.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_HW_H
|
||||||
|
/* OS/2 i/o-port access compatibility macros: */
|
||||||
|
# define inb(p) _inp8 (p)
|
||||||
|
# define outb(v,p) _outp8 ((p),(v))
|
||||||
|
# define ioperm(b,l,o) _portaccess ((b),(b)+(l)-1)
|
||||||
|
# define HAVE_IOPERM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_OS2_H
|
||||||
|
#include <fcntl.h>
|
||||||
|
#ifndef O_NONBLOCK
|
||||||
|
# ifdef O_NDELAY
|
||||||
|
# define O_NONBLOCK O_NDELAY
|
||||||
|
# else
|
||||||
|
# ifdef FNDELAY
|
||||||
|
# define O_NONBLOCK FNDELAY /* last resort */
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#endif /* HAVE_OS2_H */
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
# define PATH_MAX 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MM_PER_INCH
|
||||||
|
#define MM_PER_INCH 25.4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGPROCMASK
|
||||||
|
# define SIGACTION sigaction
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Just enough backwards compatibility that we get by in the backends
|
||||||
|
without making handstands. */
|
||||||
|
# ifdef sigset_t
|
||||||
|
# undef sigset_t
|
||||||
|
# define sigset_t int
|
||||||
|
# endif
|
||||||
|
# ifdef sigemptyset
|
||||||
|
# undef sigemptyset
|
||||||
|
# endif
|
||||||
|
# ifdef sigfillset
|
||||||
|
# undef sigfillset
|
||||||
|
# endif
|
||||||
|
# ifdef sigaddset
|
||||||
|
# undef sigaddset
|
||||||
|
# endif
|
||||||
|
# ifdef sigdelset
|
||||||
|
# undef sigdelset
|
||||||
|
# endif
|
||||||
|
# ifdef sigprocmask
|
||||||
|
# undef sigprocmask
|
||||||
|
# endif
|
||||||
|
# ifdef SIG_BLOCK
|
||||||
|
# undef SIG_BLOCK
|
||||||
|
# endif
|
||||||
|
# ifdef SIG_UNBLOCK
|
||||||
|
# undef SIG_UNBLOCK
|
||||||
|
# endif
|
||||||
|
# ifdef SIG_SETMASK
|
||||||
|
# undef SIG_SETMASK
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define sigemptyset(set) do { *(set) = 0; } while (0)
|
||||||
|
# define sigfillset(set) do { *(set) = ~0; } while (0)
|
||||||
|
# define sigaddset(set,signal) do { *(set) |= sigmask (signal); } while (0)
|
||||||
|
# define sigdelset(set,signal) do { *(set) &= ~sigmask (signal); } while (0)
|
||||||
|
# define sigaction(sig,new,old) sigvec (sig,new,old)
|
||||||
|
|
||||||
|
/* Note: it's not safe to just declare our own "struct sigaction" since
|
||||||
|
some systems (e.g., some versions of OpenStep) declare that structure,
|
||||||
|
but do not implement sigprocmask(). Hard to believe, aint it? */
|
||||||
|
# define SIGACTION sigvec
|
||||||
|
# define SIG_BLOCK 1
|
||||||
|
# define SIG_UNBLOCK 2
|
||||||
|
# define SIG_SETMASK 3
|
||||||
|
#endif /* !HAVE_SIGPROCMASK */
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Declaration of entry points:
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
extern SANE_Status ENTRY(init) (SANE_Int *, SANE_Auth_Callback);
|
||||||
|
extern SANE_Status ENTRY(get_devices) (const SANE_Device ***, SANE_Bool);
|
||||||
|
extern SANE_Status ENTRY(open) (SANE_String_Const, SANE_Handle *);
|
||||||
|
extern const SANE_Option_Descriptor *
|
||||||
|
ENTRY(get_option_descriptor) (SANE_Handle, SANE_Int);
|
||||||
|
extern SANE_Status ENTRY(control_option) (SANE_Handle, SANE_Int, SANE_Action,
|
||||||
|
void *, SANE_Word *);
|
||||||
|
extern SANE_Status ENTRY(get_parameters) (SANE_Handle, SANE_Parameters *);
|
||||||
|
extern SANE_Status ENTRY(start) (SANE_Handle);
|
||||||
|
extern SANE_Status ENTRY(read) (SANE_Handle, SANE_Byte *, SANE_Int,
|
||||||
|
SANE_Int *);
|
||||||
|
extern SANE_Status ENTRY(set_io_mode) (SANE_Handle, SANE_Bool);
|
||||||
|
extern SANE_Status ENTRY(get_select_fd) (SANE_Handle, SANE_Int *);
|
||||||
|
extern void ENTRY(cancel) (SANE_Handle);
|
||||||
|
extern void ENTRY(close) (SANE_Handle);
|
||||||
|
extern void ENTRY(exit) (void);
|
||||||
|
extern void sanei_debug_msg(int level, int max_level, const char* be, const char* fmt, va_list ap);
|
||||||
|
|
||||||
|
#ifndef STUBS
|
||||||
|
/* Now redirect sane_* calls to backend's functions: */
|
||||||
|
|
||||||
|
#define sane_init(a,b) ENTRY(init) (a,b)
|
||||||
|
#define sane_get_devices(a,b) ENTRY(get_devices) (a,b)
|
||||||
|
#define sane_open(a,b) ENTRY(open) (a,b)
|
||||||
|
#define sane_get_option_descriptor(a,b) ENTRY(get_option_descriptor) (a,b)
|
||||||
|
#define sane_control_option(a,b,c,d,e) ENTRY(control_option) (a,b,c,d,e)
|
||||||
|
#define sane_get_parameters(a,b) ENTRY(get_parameters) (a,b)
|
||||||
|
#define sane_start(a) ENTRY(start) (a)
|
||||||
|
#define sane_read(a,b,c,d) ENTRY(read) (a,b,c,d)
|
||||||
|
#define sane_set_io_mode(a,b) ENTRY(set_io_mode) (a,b)
|
||||||
|
#define sane_get_select_fd(a,b) ENTRY(get_select_fd) (a,b)
|
||||||
|
#define sane_cancel(a) ENTRY(cancel) (a)
|
||||||
|
#define sane_close(a) ENTRY(close) (a)
|
||||||
|
#define sane_exit(a) ENTRY(exit) (a)
|
||||||
|
#define sane_strstatus(a) ENTRY(strstatus)(a)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// extension for standard SANE ...
|
||||||
|
#define sane_init_ex(a, b, c) ENTRY(init_ex) (a,b,c)
|
||||||
|
#define sane_io_control(a,b,c,d) ENTRY(io_control)(a,b,c,d)
|
||||||
|
#define sane_err_desc(a) ENTRY(err_desc)(a)
|
||||||
|
|
||||||
|
#define sane_get_option_descriptor_ex(a,b) ENTRY(get_option_descriptor_ex) (a,b) // added on 2023-01-06, option can be 'key'
|
||||||
|
#define sane_control_option_ex(a,b,c,d,e) ENTRY(control_option_ex) (a,b,c,d,e) // added on 2023-01-06, option can be 'key'
|
||||||
|
#define sane_read_ext_info(a, b) ENTRY(read_ext_info)(a, b) // added on 2023-01-13
|
||||||
|
|
||||||
|
#endif /* STUBS */
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
/** Internationalization for SANE backends
|
||||||
|
*
|
||||||
|
* Add SANE_I18N() to all texts that can be translated.
|
||||||
|
* E.g. out_txt = SANE_I18N("Hello");
|
||||||
|
*/
|
||||||
|
#ifndef SANE_I18N
|
||||||
|
#define SANE_I18N(text) text
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Option_Value union
|
||||||
|
*
|
||||||
|
* Convenience union to access option values given to the backend
|
||||||
|
*/
|
||||||
|
#ifndef SANE_OPTION
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
SANE_Bool b; /**< bool */
|
||||||
|
SANE_Word w; /**< word */
|
||||||
|
SANE_Word *wa; /**< word array */
|
||||||
|
SANE_String s; /**< string */
|
||||||
|
}
|
||||||
|
Option_Value;
|
||||||
|
#define SANE_OPTION 1
|
||||||
|
#endif
|
|
@ -0,0 +1,153 @@
|
||||||
|
/** @file sanei_debug.h
|
||||||
|
* Support for printing debug messages.
|
||||||
|
*
|
||||||
|
* Use the functions of this header file to print debug or warning messages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SANEI_DEBUG_H
|
||||||
|
#define _SANEI_DEBUG_H
|
||||||
|
|
||||||
|
#include <sane/sanei.h>
|
||||||
|
|
||||||
|
/** @name Public macros
|
||||||
|
* These macros can be used in backends and other SANE-related
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
* Before including sanei_debug.h, the following macros must be set:
|
||||||
|
*
|
||||||
|
* - BACKEND_NAME - The name of your backend without double-quotes (must be set in any case)
|
||||||
|
* - STUBS - If this is defined, no macros will be included. Used in
|
||||||
|
* backends consisting of more than one .c file.
|
||||||
|
* - DEBUG_DECLARE_ONLY - Generates prototypes instead of functions. Used in
|
||||||
|
* backends consisting of more than one .c file.
|
||||||
|
* - DEBUG_NOT_STATIC - Doesn't generate static functions. Used in header files if
|
||||||
|
* they are include in more than one .c file.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @def DBG_INIT()
|
||||||
|
* Initialize sanei_debug.
|
||||||
|
*
|
||||||
|
* Call this function before you use any DBG function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @def DBG(level, fmt, ...)
|
||||||
|
* Print a message at debug level `level' or higher using a printf-like
|
||||||
|
* function. Example: DBG(1, "sane_open: opening fd \%d\\n", fd).
|
||||||
|
*
|
||||||
|
* @param level debug level
|
||||||
|
* @param fmt format (see man 3 printf for details)
|
||||||
|
* @param ... additional arguments
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @def IF_DBG(x)
|
||||||
|
* Compile code only if debugging is enabled.
|
||||||
|
*
|
||||||
|
* Expands to x if debug support is enabled at compile-time. If NDEBUG is
|
||||||
|
* defined at compile-time this macro expands to nothing.
|
||||||
|
*
|
||||||
|
* @param x code to expand when debugging is enabled
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def DBG_LEVEL
|
||||||
|
* Current debug level.
|
||||||
|
*
|
||||||
|
* You can only read this "variable".
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @def ENTRY(name)
|
||||||
|
* Expands to sane_BACKEND_NAME_name.
|
||||||
|
*
|
||||||
|
* Example: ENTRY(init) in mustek.c will expand to sane_mustek_init.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
|
||||||
|
/** @hideinitializer*/
|
||||||
|
#define ENTRY(name) PASTE(PASTE(PASTE(sane_,BACKEND_NAME),_),name)
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
|
||||||
|
extern void sanei_debug_ndebug (int level, const char *msg, ...);
|
||||||
|
|
||||||
|
# define DBG_LEVEL (0)
|
||||||
|
# define DBG_INIT()
|
||||||
|
# define DBG sanei_debug_ndebug
|
||||||
|
# define IF_DBG(x)
|
||||||
|
|
||||||
|
#else /* !NDEBUG */
|
||||||
|
|
||||||
|
/** @hideinitializer*/
|
||||||
|
# define DBG_LEVEL PASTE(sanei_debug_,BACKEND_NAME)
|
||||||
|
|
||||||
|
# if defined(BACKEND_NAME) && !defined(STUBS)
|
||||||
|
# ifdef DEBUG_DECLARE_ONLY
|
||||||
|
extern int DBG_LEVEL;
|
||||||
|
# else /* !DEBUG_DECLARE_ONLY */
|
||||||
|
int DBG_LEVEL = 0;
|
||||||
|
# endif /* DEBUG_DECLARE_ONLY */
|
||||||
|
# endif /* BACKEND_NAME && !STUBS */
|
||||||
|
|
||||||
|
/** @hideinitializer*/
|
||||||
|
# define DBG_INIT() \
|
||||||
|
sanei_init_debug (STRINGIFY(BACKEND_NAME), &DBG_LEVEL)
|
||||||
|
|
||||||
|
/** @hideinitializer*/
|
||||||
|
# define DBG_LOCAL PASTE(DBG_LEVEL,_call)
|
||||||
|
|
||||||
|
|
||||||
|
# ifndef STUBS
|
||||||
|
|
||||||
|
# ifdef DEBUG_DECLARE_ONLY
|
||||||
|
|
||||||
|
extern void DBG_LOCAL (int level, const char *msg, ...)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
# else /* !DEBUG_DECLARE_ONLY */
|
||||||
|
|
||||||
|
# include <stdarg.h>
|
||||||
|
|
||||||
|
extern void sanei_debug_msg
|
||||||
|
(int level, int max_level, const char *be, const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# ifndef DEBUG_NOT_STATIC
|
||||||
|
static
|
||||||
|
# endif /* !DEBUG_NOT_STATIC */
|
||||||
|
void DBG_LOCAL (int level, const char *msg, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#endif /* __GNUC__ */
|
||||||
|
|
||||||
|
# ifndef DEBUG_NOT_STATIC
|
||||||
|
static
|
||||||
|
# endif /* !DEBUG_NOT_STATIC */
|
||||||
|
void
|
||||||
|
DBG_LOCAL (int level, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start (ap, msg);
|
||||||
|
sanei_debug_msg (level, DBG_LEVEL, STRINGIFY(BACKEND_NAME), msg, ap);
|
||||||
|
va_end (ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif /* DEBUG_DECLARE_ONLY */
|
||||||
|
|
||||||
|
# endif /* !STUBS */
|
||||||
|
|
||||||
|
/** @hideinitializer*/
|
||||||
|
# define DBG DBG_LOCAL
|
||||||
|
|
||||||
|
extern void sanei_init_debug (const char * backend, int * debug_level_var);
|
||||||
|
|
||||||
|
/** @hideinitializer*/
|
||||||
|
# define IF_DBG(x) x
|
||||||
|
|
||||||
|
#endif /* NDEBUG */
|
||||||
|
|
||||||
|
#endif /* _SANEI_DEBUG_H */
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include "base_opt.h"
|
||||||
|
|
||||||
|
#include <json/gb_json.h>
|
||||||
|
#include <huagao/hgscanner_error.h>
|
||||||
|
|
||||||
|
|
||||||
|
sane_opt_provider::sane_opt_provider()
|
||||||
|
{
|
||||||
|
set_where(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
sane_opt_provider::~sane_opt_provider()
|
||||||
|
{
|
||||||
|
for (auto& v : following_)
|
||||||
|
v.second->release();
|
||||||
|
following_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sane_opt_provider::set_opt_json_text(char* txt)
|
||||||
|
{
|
||||||
|
gb_json* jsn = new gb_json();
|
||||||
|
bool ret = jsn->attach_text(txt);
|
||||||
|
|
||||||
|
jsn->release();
|
||||||
|
if (ret)
|
||||||
|
opt_jsn_txt_ = txt;
|
||||||
|
else
|
||||||
|
opt_jsn_txt_ = "";
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void sane_opt_provider::set_where(const char* where)
|
||||||
|
{
|
||||||
|
if (where && *where)
|
||||||
|
{
|
||||||
|
where_ = where;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buf[20] = { 0 };
|
||||||
|
|
||||||
|
sprintf(buf, "%p", this);
|
||||||
|
where_ = buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sane_opt_provider::get_opt_json(void)
|
||||||
|
{
|
||||||
|
return opt_jsn_txt_.c_str();
|
||||||
|
}
|
||||||
|
const char* sane_opt_provider::from(void)
|
||||||
|
{
|
||||||
|
return where_.c_str();
|
||||||
|
}
|
||||||
|
void sane_opt_provider::set_following_provider(const char* name, sane_opt_provider* following)
|
||||||
|
{
|
||||||
|
if (following_.count(name))
|
||||||
|
{
|
||||||
|
following_[name]->release();
|
||||||
|
following_.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (following)
|
||||||
|
{
|
||||||
|
following_[name] = following;
|
||||||
|
following->add_ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sane_opt_provider* sane_opt_provider::get_following(const char* name)
|
||||||
|
{
|
||||||
|
sane_opt_provider* prvd = nullptr;
|
||||||
|
|
||||||
|
if (following_.count(name))
|
||||||
|
{
|
||||||
|
prvd = following_[name];
|
||||||
|
if (prvd)
|
||||||
|
prvd->add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
return prvd;
|
||||||
|
}
|
||||||
|
char* sane_opt_provider::get_value(const char* name, void* value, size_t* size, int* err)
|
||||||
|
{
|
||||||
|
if (err)
|
||||||
|
*err = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
int sane_opt_provider::set_value(const char* name, void* val)
|
||||||
|
{
|
||||||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
||||||
|
}
|
||||||
|
void sane_opt_provider::enable(const char* name, bool able)
|
||||||
|
{}
|
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// SANE-Option
|
||||||
|
//
|
||||||
|
// created on 2022-10-24
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <base/utils.h> // for refer
|
||||||
|
|
||||||
|
class sane_opt_provider : public refer
|
||||||
|
{
|
||||||
|
bool is_in_another_module_;
|
||||||
|
|
||||||
|
std::string opt_jsn_txt_;
|
||||||
|
std::string where_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::map<std::string, sane_opt_provider*> following_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
sane_opt_provider();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~sane_opt_provider();
|
||||||
|
|
||||||
|
bool set_opt_json_text(char* txt);
|
||||||
|
void set_where(const char* where);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* get_opt_json(void); // if no content, return "" plz.
|
||||||
|
const char* from(void); // if no content, return "" plz.
|
||||||
|
bool is_in_another_module(void) { return is_in_another_module_; }
|
||||||
|
void set_following_provider(const char* name, sane_opt_provider* following); // when option has provided by more than one
|
||||||
|
sane_opt_provider* get_following(const char* name); // caller should ->release returned value
|
||||||
|
|
||||||
|
public:
|
||||||
|
// return malloc(), real data size stored in parameter 'size'. invoker should free() the returned value
|
||||||
|
virtual char* get_value(const char* name, void* value, size_t* size, int* err = nullptr);
|
||||||
|
virtual int set_value(const char* name, void* val);
|
||||||
|
virtual void enable(const char* name, bool able);
|
||||||
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,412 @@
|
||||||
|
//
|
||||||
|
// device_opt: option manager of device
|
||||||
|
//
|
||||||
|
// Created: 2023-09-07
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "simple_logic.h"
|
||||||
|
#include <json/gb_json.h>
|
||||||
|
#include <base/utils.h>
|
||||||
|
#include <sane/sane_ex.h>
|
||||||
|
|
||||||
|
class sane_opt_provider;
|
||||||
|
|
||||||
|
class device_option : public refer
|
||||||
|
{
|
||||||
|
gb_json* origin_;
|
||||||
|
gb_json* now_;
|
||||||
|
std::map<std::string, sane_opt_provider*> src_;
|
||||||
|
std::vector<std::string> master_opts_; // options that value changed will affect others
|
||||||
|
std::map<std::string, simple_logic*> slaver_;
|
||||||
|
std::function<bool(int)> user_;
|
||||||
|
std::function<void(const char*)> log_;
|
||||||
|
|
||||||
|
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_;
|
||||||
|
device_option* parent_; // if this value was valid, the condition value is a consistant value with vals_[0].value
|
||||||
|
|
||||||
|
void clear(void)
|
||||||
|
{
|
||||||
|
for (auto& v : vals_)
|
||||||
|
{
|
||||||
|
if (v.logic)
|
||||||
|
delete v.logic;
|
||||||
|
}
|
||||||
|
vals_.clear();
|
||||||
|
parent_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
condition_value() : parent_(nullptr)
|
||||||
|
{}
|
||||||
|
~condition_value()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool set_value(gb_json* jsn, const char* type, device_option* parent); // jsn contains only ONE value or its object, or nullptr for a consistant value
|
||||||
|
std::string value(bool(*compare)(const char*, void*), void* param);
|
||||||
|
};
|
||||||
|
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_;
|
||||||
|
std::map<std::string, condition_value*> init_value_;
|
||||||
|
std::map<std::string, condition_value*> support_value_;
|
||||||
|
std::map<std::string, std::vector<std::string> > depend_opts_; // values that depend on other option's current value <master option name, [slaver-option-nam.field ...]>
|
||||||
|
|
||||||
|
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*));
|
||||||
|
|
||||||
|
// Function: parse string function - .left(cnt), .right(cnt), .mid(start, cnt)
|
||||||
|
//
|
||||||
|
// Parameter: expr - expression of string function, e.g. mode.left(2)
|
||||||
|
//
|
||||||
|
// name - to receive the final option name, e.g. mode
|
||||||
|
//
|
||||||
|
// start - to receive the starting position of the sub-string, negative is for right()
|
||||||
|
//
|
||||||
|
// cnt - to receive the length of the sub string, -1 is to end
|
||||||
|
//
|
||||||
|
// Return: true if was string function
|
||||||
|
static bool is_string_function(const char* expr, std::string& name, int& start, int& cnt);
|
||||||
|
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_for_reconstruct(void);
|
||||||
|
gb_json* group_opt(const char* title);
|
||||||
|
int next_group(int start); // return index of the next group
|
||||||
|
int insert_group(const char* name, const char* title); // return index of the group
|
||||||
|
void insert_option(gb_json* opt, sane_opt_provider* from, const char* group = nullptr);
|
||||||
|
bool arrange_raw_json(sane_opt_provider* sop); // create origin_ and re-arrange groups
|
||||||
|
void init_depends(gb_json* opt);
|
||||||
|
gb_json* copy_opt(gb_json* from);
|
||||||
|
int visibility(gb_json* jsn);
|
||||||
|
bool to_now(bool init, bool* changed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
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;
|
||||||
|
if(jsn->get_value(key, v))
|
||||||
|
child = new gb_json("", v);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string sv("");
|
||||||
|
if (jsn->get_value(key, sv))
|
||||||
|
{
|
||||||
|
// consistant with another option ...
|
||||||
|
ret = new condition_value();
|
||||||
|
ret->set_value(nullptr, sv.c_str(), parent);
|
||||||
|
if (std::find(parent->master_opts_.begin(), parent->master_opts_.end(), sv)
|
||||||
|
== parent->master_opts_.end())
|
||||||
|
parent->master_opts_.push_back(sv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
ret = new condition_value();
|
||||||
|
if (!ret->set_value(child, type, parent))
|
||||||
|
{
|
||||||
|
delete ret;
|
||||||
|
ret = nullptr;
|
||||||
|
}
|
||||||
|
child->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool get_range(gb_json* jsn, const char* key, T& val)
|
||||||
|
{
|
||||||
|
if (jsn->get_value(key, val))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string optn("");
|
||||||
|
|
||||||
|
if (!jsn->get_value(key, optn))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gb_json* opt = nullptr;
|
||||||
|
if (now_)
|
||||||
|
now_->get_value(optn.c_str(), opt);
|
||||||
|
if (!opt && origin_)
|
||||||
|
origin_->get_value(optn.c_str(), opt);
|
||||||
|
if (!opt)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ret = opt->get_value("cur", val);
|
||||||
|
|
||||||
|
opt->release();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool refine_data_to_range(gb_json* jsn, void* value)
|
||||||
|
{
|
||||||
|
bool refined = false;
|
||||||
|
gb_json* range = nullptr;
|
||||||
|
|
||||||
|
jsn->get_value("range", range);
|
||||||
|
if (range)
|
||||||
|
{
|
||||||
|
T vl, vu, s;
|
||||||
|
if (get_range<T>(range, "min", vl))
|
||||||
|
{
|
||||||
|
if (*(T*)value < vl)
|
||||||
|
{
|
||||||
|
*(T*)value = vl;
|
||||||
|
refined = true;
|
||||||
|
}
|
||||||
|
else if (get_range<T>(range, "max", vu))
|
||||||
|
{
|
||||||
|
if (*(T*)value > vu)
|
||||||
|
{
|
||||||
|
*(T*)value = vu;
|
||||||
|
refined = true;
|
||||||
|
}
|
||||||
|
else if (get_range<T>(range, "step", s))
|
||||||
|
{
|
||||||
|
// step check, FIXED me ...
|
||||||
|
T cur(*(T*)value);
|
||||||
|
|
||||||
|
cur -= vl;
|
||||||
|
cur /= s;
|
||||||
|
if (!IS_DOUBLE_EQUAL(cur, (int)cur))
|
||||||
|
{
|
||||||
|
cur *= s;
|
||||||
|
cur += vl;
|
||||||
|
if (cur > vu)
|
||||||
|
cur = vu;
|
||||||
|
refined = !IS_DOUBLE_EQUAL(cur, *(T*)value);
|
||||||
|
*(T*)value = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gb_json* val = range->first_child();
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
while (val)
|
||||||
|
{
|
||||||
|
if (val->value(vl))
|
||||||
|
{
|
||||||
|
if (*(T*)value == vl)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
val->release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val->release();
|
||||||
|
val = range->next_child();
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
if (jsn->get_value("default", vl))
|
||||||
|
{
|
||||||
|
refined = true;
|
||||||
|
*(T*)value = vl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return refined;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ... Args>
|
||||||
|
void write_log(const char* fmt, Args ... args)
|
||||||
|
{
|
||||||
|
if (log_)
|
||||||
|
{
|
||||||
|
size_t size = snprintf(nullptr, 0, fmt, args ...) + 2;
|
||||||
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
|
|
||||||
|
snprintf(buf.get(), size, fmt, args ...);
|
||||||
|
log_(buf.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
device_option(std::function<bool(int)> user_priv = std::function<bool(int)>()
|
||||||
|
, std::function<void(const char*)> log = std::function<void(const char*)>());
|
||||||
|
~device_option();
|
||||||
|
|
||||||
|
static std::string trans_group(const char* utf8, bool to_title);
|
||||||
|
static std::string get_group(int ind, bool title);
|
||||||
|
static void set_from_default_language_api(const char*(*fdl)(const char*));
|
||||||
|
|
||||||
|
public:
|
||||||
|
void clear(void);
|
||||||
|
bool add(sane_opt_provider* sop);
|
||||||
|
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, bool reorder_if_need = true); // return scanner_err. name and value would be null if invoked for language changed
|
||||||
|
int restore(sane_opt_provider* holder); //
|
||||||
|
|
||||||
|
int count(void); // return option count
|
||||||
|
bool is_auto_restore_default(const char* name);
|
||||||
|
std::string get_name_by_sane_id(int sane_ind);
|
||||||
|
std::string get_option_value_type(const char* name, size_t* size = nullptr);
|
||||||
|
std::string get_option_value_type(int sane_ind, size_t* size = nullptr);
|
||||||
|
std::string get_option_field_string(const char* name, const char* key);
|
||||||
|
std::string get_option_value(const char* name, int type/*OPT_VAL_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null
|
||||||
|
std::string get_option_value(int sane_ind, int type/*OPT_VAL_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null
|
||||||
|
};
|
||||||
|
|
||||||
|
//{
|
||||||
|
// "resolution": {
|
||||||
|
// "cat": "base",
|
||||||
|
// "group" : "base",
|
||||||
|
// "title" : "<22>ֱ<EFBFBD><D6B1><EFBFBD>",
|
||||||
|
// "desc" : "<22><><EFBFBD><EFBFBD>ɨ<EFBFBD><C9A8>ͼ<EFBFBD><CDBC>ķֱ<C4B7><D6B1><EFBFBD>",
|
||||||
|
// "type" : "int",
|
||||||
|
// "fix-id" : 34840,
|
||||||
|
// "size" : 4,
|
||||||
|
// "cur" : 200,
|
||||||
|
// "default" : 200,
|
||||||
|
// "range" : {
|
||||||
|
// "min": 100,
|
||||||
|
// "max" : {
|
||||||
|
// "default": 600,
|
||||||
|
// "paper==<3D><><EFBFBD>ɨ<EFBFBD><C9A8>ߴ<EFBFBD><DFB4>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD> || paper==<3D><><EFBFBD>ɨ<EFBFBD><C9A8>ߴ<EFBFBD> || paper==<3D><><EFBFBD><EFBFBD><EFBFBD>Ծ<EFBFBD>" : 500
|
||||||
|
// },
|
||||||
|
// "step" : 1
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
//
|
||||||
|
// "paper": {
|
||||||
|
// "cat": "base",
|
||||||
|
// "group" : "base",
|
||||||
|
// "title" : "ֽ<>ųߴ<C5B3>",
|
||||||
|
// "desc" : "<22><><EFBFBD>ó<EFBFBD>ͼ<EFBFBD><CDBC>С",
|
||||||
|
// "type" : "string",
|
||||||
|
// "fix-id" : 34831,
|
||||||
|
// "size" : 44,
|
||||||
|
// "cur" : "ƥ<><C6A5>ԭʼ<D4AD>ߴ<EFBFBD>",
|
||||||
|
// "default" : "ƥ<><C6A5>ԭʼ<D4AD>ߴ<EFBFBD>",
|
||||||
|
// "range" : ["A3", "8<><38>", "A4", "16<31><36>", "A5", "A6", "B4", "B5", "B6", "Letter", "Double Letter", "LEGAL", "ƥ<><C6A5>ԭʼ<D4AD>ߴ<EFBFBD>", {
|
||||||
|
// "resolution<500": "<22><><EFBFBD>ɨ<EFBFBD><C9A8>ߴ<EFBFBD><DFB4>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>"
|
||||||
|
// }, {
|
||||||
|
// "resolution<500": "<22><><EFBFBD>ɨ<EFBFBD><C9A8>ߴ<EFBFBD>"
|
||||||
|
// }, {
|
||||||
|
// "resolution<500": "<22><><EFBFBD><EFBFBD><EFBFBD>Ծ<EFBFBD>"
|
||||||
|
// }]
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,594 @@
|
||||||
|
|
||||||
|
#include "simple_logic.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.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)
|
||||||
|
{
|
||||||
|
char mark[2] = { 0 };
|
||||||
|
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
|
mark[0] = *ptr;
|
||||||
|
if (!strstr(space, mark))
|
||||||
|
break;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void trim(std::string& str, int type)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
if (type & TRIM_LEFT)
|
||||||
|
{
|
||||||
|
for (; pos < str.length(); ++pos)
|
||||||
|
{
|
||||||
|
if (str[pos] != ' ')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos)
|
||||||
|
str.erase(0, pos);
|
||||||
|
}
|
||||||
|
if (type & TRIM_RIGHT)
|
||||||
|
{
|
||||||
|
pos = str.length() - 1;
|
||||||
|
for (; pos >= 0; --pos)
|
||||||
|
{
|
||||||
|
if (str[pos] != ' ')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.erase(pos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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);
|
||||||
|
if (sub.find("||") == std::string::npos &&
|
||||||
|
sub.find("&&") == std::string::npos &&
|
||||||
|
sub.find("^") == std::string::npos)
|
||||||
|
{
|
||||||
|
// count as function ...
|
||||||
|
ptr += len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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, leaf, leaf_param))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
string_util::trim(e->expr_);
|
||||||
|
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 + 1;
|
||||||
|
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);
|
||||||
|
string_util::trim(e->expr_);
|
||||||
|
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 + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*ptr == '^')
|
||||||
|
{
|
||||||
|
if (need_oper || first)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
simple_logic* e = new simple_logic();
|
||||||
|
e->expr_ = std::string(first, ptr - first);
|
||||||
|
string_util::trim(e->expr_);
|
||||||
|
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 (good && 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);
|
||||||
|
if (e->oper_ == LOGIC_OPER_LEAF && leaf)
|
||||||
|
leaf(e->expr_.c_str(), leaf_param);
|
||||||
|
}
|
||||||
|
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,79 @@
|
||||||
|
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
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);
|
||||||
|
void skip_space(const char*& ptr, const char* space = " \t");
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TRIM_LEFT = 1,
|
||||||
|
TRIM_RIGHT,
|
||||||
|
TRIM_BOTH,
|
||||||
|
};
|
||||||
|
void trim(std::string& str, int type = TRIM_BOTH);
|
||||||
|
};
|
||||||
|
|
||||||
|
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,12 @@
|
||||||
|
#define _LARGEFILE64_SOURCE
|
||||||
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
|
||||||
|
//#define CONFIG_USB_NON_BLOCKING_WRITE 1
|
||||||
|
|
||||||
|
#define CONFIG_USB_FS_SUPPORT 1 // USB 1.1 Full speed
|
||||||
|
#define CONFIG_USB_HS_SUPPORT 1 // USB 2.0 High speed
|
||||||
|
#define CONFIG_USB_SS_SUPPORT 1 // USB 3.0 SuperSpeed
|
||||||
|
|
||||||
|
#define CONFIG_READ_FILE_BUFFER_SIZE (1024*1024) // Must be a 2^x value.
|
||||||
|
#define CONFIG_MAX_TX_USB_BUFFER_SIZE (16*512) // Must be a multiple of 512 and be less than CONFIG_READ_FILE_BUFFER_SIZE
|
||||||
|
#define CONFIG_MAX_RX_USB_BUFFER_SIZE (16*512) // Must be a multiple of 512
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* CAMTP Responder
|
||||||
|
* Copyright (c) 2020 Holdtecs Technologies
|
||||||
|
*
|
||||||
|
* CAMTP Responder is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3.0 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* CAMTP Responder is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License version 3 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with CAMTP Responder; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file camtp.h
|
||||||
|
* @brief Main CAMMTP protocol functions.
|
||||||
|
* @author Barry Ruan <cubex@foxmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_CAMTP_H_
|
||||||
|
#define _INC_CAMTP_H_
|
||||||
|
|
||||||
|
#define MAX_STORAGE_NB 16
|
||||||
|
#define MAX_CFG_STRING_SIZE 512
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
typedef struct mtp_usb_cfg_
|
||||||
|
{
|
||||||
|
uint16_t usb_vendor_id;
|
||||||
|
uint16_t usb_product_id;
|
||||||
|
uint8_t usb_class;
|
||||||
|
uint8_t usb_subclass;
|
||||||
|
uint8_t usb_protocol;
|
||||||
|
uint16_t usb_dev_version;
|
||||||
|
uint16_t usb_max_packet_size;
|
||||||
|
uint8_t usb_functionfs_mode;
|
||||||
|
|
||||||
|
char usb_device_path[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
char usb_endpoint_in[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
char usb_endpoint_out[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
char usb_endpoint_intin[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
|
||||||
|
char usb_string_manufacturer[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
char usb_string_product[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
char usb_string_serial[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
char usb_string_version[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
|
||||||
|
char usb_string_interface[MAX_CFG_STRING_SIZE + 1];
|
||||||
|
|
||||||
|
int wait_connection;
|
||||||
|
int loop_on_disconnect;
|
||||||
|
|
||||||
|
int show_hidden_files;
|
||||||
|
|
||||||
|
int val_umask;
|
||||||
|
|
||||||
|
}camtp_usb_cfg;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct camtp_ctx_
|
||||||
|
{
|
||||||
|
uint32_t session_id;
|
||||||
|
|
||||||
|
camtp_usb_cfg usb_cfg;
|
||||||
|
|
||||||
|
void * usb_ctx;
|
||||||
|
|
||||||
|
volatile int cancel_req;
|
||||||
|
|
||||||
|
}camtp_ctx;
|
||||||
|
|
||||||
|
int camtp_load_config_file(camtp_ctx * context, const char * conffile);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* CAMTP Responder
|
||||||
|
* Copyright (c) 2020 Holdtecs Technologies
|
||||||
|
*
|
||||||
|
* CAMTP Responder is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3.0 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* CAMTP Responder is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License version 3 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with CAMTP Responder; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file default.h
|
||||||
|
* @brief Main CAMMTP protocol functions.
|
||||||
|
* @author Barry Ruan <cubex@foxmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_DEFAULT_CFG_H_
|
||||||
|
#define _INC_DEFAULT_CFG_H_
|
||||||
|
|
||||||
|
#ifndef CAMTPR_CONF_FILE
|
||||||
|
#define CAMTPR_CONF_FILE "/etc/camtprd/camtprd.conf"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_PACKET_SIZE 1024
|
||||||
|
|
||||||
|
#define USB_DEV_VENDOR_ID 0x04b4
|
||||||
|
//0x04B4 // Linux Foundation
|
||||||
|
#define USB_DEV_PRODUCT_ID 0x8613 // PTP Gadget
|
||||||
|
|
||||||
|
#define USB_DEV_CLASS USB_CLASS_STILL_IMAGE // Still Imaging device
|
||||||
|
#define USB_DEV_SUBCLASS 0x0 //
|
||||||
|
#define USB_DEV_PROTOCOL 0x0 //
|
||||||
|
|
||||||
|
#define USB_DEV_VERSION 0x3008
|
||||||
|
|
||||||
|
#define USB_FFS_MODE 1
|
||||||
|
|
||||||
|
#define USB_DEV "/dev/ffs-camtp/ep0"
|
||||||
|
|
||||||
|
#define USB_EP_BULK_IN "/dev/ffs-camtp/ep1"
|
||||||
|
#define USB_EP_BULK_OUT "/dev/ffs-camtp/ep2"
|
||||||
|
#define USB_EP_INT_IN "/dev/ffs-camtp/ep3"
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EP_IND_BULK_IN = 0,
|
||||||
|
EP_IND_BULK_OUT,
|
||||||
|
EP_IND_INT_IN,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MANUFACTURER "HUAGAO Technologies"
|
||||||
|
#define PRODUCT "HUAGAO"
|
||||||
|
#define SERIALNUMBER "01234567ABCDEFG"
|
||||||
|
#define USB_INTERFACE "camtp"
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,716 @@
|
||||||
|
#include "usb_dev.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include "usbstring.h"
|
||||||
|
#include "default_cfg.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
|
||||||
|
#define CONFIG_VALUE 1
|
||||||
|
#define USB_MAX_PACKAGE_LENGTH_FILE "/opt/usbpkgconfig"
|
||||||
|
|
||||||
|
static struct usb_gadget_strings strings = {
|
||||||
|
.language = 0x0409, /* en-us */
|
||||||
|
.strings = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct camtp_device_status_ {
|
||||||
|
uint16_t wLength;
|
||||||
|
uint16_t wCode;
|
||||||
|
}camtp_device_status;
|
||||||
|
|
||||||
|
static const int cacheSize = SIZE_KB(64);
|
||||||
|
|
||||||
|
usb_device::usb_device(const char* dwc3, const char* udc, const char* pwd)
|
||||||
|
: dwc3_(dwc3), udc_(udc), pwd_(pwd)
|
||||||
|
{
|
||||||
|
memset(&gadget_, 0, sizeof(gadget_));
|
||||||
|
gadget_.usb_device = -1;
|
||||||
|
for(int i = 0; i < _countof(gadget_.ep_handles); ++i)
|
||||||
|
gadget_.ep_handles[i] = -1;
|
||||||
|
|
||||||
|
memset( &ffs_strs_, 0, sizeof(ffs_strings));
|
||||||
|
ffs_strs_.header.magic = htole32(FUNCTIONFS_STRINGS_MAGIC);
|
||||||
|
ffs_strs_.header.length = htole32(sizeof(struct usb_functionfs_strings_head) + sizeof(uint16_t) + strlen(USB_INTERFACE) + 1);
|
||||||
|
ffs_strs_.header.str_count = htole32(1);
|
||||||
|
ffs_strs_.header.lang_count = htole32(1);
|
||||||
|
ffs_strs_.code = htole16(0x0409); // en-us
|
||||||
|
strcpy(ffs_strs_.string_data, USB_INTERFACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_device::~usb_device()
|
||||||
|
{
|
||||||
|
close_device();
|
||||||
|
deinit_usb_camtp_gadget();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string usb_device::endpoint_index_str(int epind)
|
||||||
|
{
|
||||||
|
RETURN_ENUM_STR(epind, EP_IND_BULK_IN);
|
||||||
|
RETURN_ENUM_STR(epind, EP_IND_BULK_OUT);
|
||||||
|
RETURN_ENUM_STR(epind, EP_IND_INT_IN);
|
||||||
|
|
||||||
|
return std::to_string(epind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_device::fill_if_descriptor(bool ffs_mode, usb_gadget * usbctx, struct usb_interface_descriptor * desc)
|
||||||
|
{
|
||||||
|
memset(desc,0,sizeof(struct usb_interface_descriptor));
|
||||||
|
|
||||||
|
desc->bLength = sizeof(struct usb_interface_descriptor);
|
||||||
|
desc->bDescriptorType = USB_DT_INTERFACE; //!< nick
|
||||||
|
desc->bInterfaceNumber = 0;
|
||||||
|
desc->iInterface = 1;
|
||||||
|
desc->bAlternateSetting = 0;
|
||||||
|
desc->bNumEndpoints = _countof(usbctx->ep_path);
|
||||||
|
|
||||||
|
desc->bInterfaceClass = USB_DEV_CLASS;
|
||||||
|
desc->bInterfaceSubClass = USB_DEV_SUBCLASS;
|
||||||
|
desc->bInterfaceProtocol = USB_DEV_PROTOCOL;
|
||||||
|
if( ffs_mode )
|
||||||
|
{
|
||||||
|
desc->iInterface = STRINGID_MANUFACTURER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc->iInterface = STRINGID_INTERFACE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void usb_device::fill_ep_descriptor(unsigned short max_packet, usb_gadget * usbctx,struct usb_endpoint_descriptor_no_audio * desc,int index,unsigned int flags)
|
||||||
|
{
|
||||||
|
memset(desc,0,sizeof(struct usb_endpoint_descriptor_no_audio));
|
||||||
|
|
||||||
|
desc->bLength = USB_DT_ENDPOINT_SIZE;
|
||||||
|
desc->bDescriptorType = USB_DT_ENDPOINT;
|
||||||
|
|
||||||
|
if(flags & EP_OUT_DIR)
|
||||||
|
desc->bEndpointAddress = USB_DIR_OUT | (index);
|
||||||
|
else
|
||||||
|
desc->bEndpointAddress = USB_DIR_IN | (index);
|
||||||
|
|
||||||
|
if(flags & EP_BULK_MODE)
|
||||||
|
{
|
||||||
|
desc->bmAttributes = USB_ENDPOINT_XFER_BULK;
|
||||||
|
desc->wMaxPacketSize = max_packet;
|
||||||
|
//printf("desc->wMaxPacketSize = %d \n",desc->wMaxPacketSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc->bmAttributes = USB_ENDPOINT_XFER_INT;
|
||||||
|
desc->wMaxPacketSize = 64; // HS size 64
|
||||||
|
desc->bInterval = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USB_SS_SUPPORT)
|
||||||
|
if(flags & EP_SS_MODE)
|
||||||
|
{
|
||||||
|
ep_cfg_descriptor * ss_descriptor;
|
||||||
|
|
||||||
|
ss_descriptor = (ep_cfg_descriptor *)desc;
|
||||||
|
|
||||||
|
ss_descriptor->ep_desc_comp.bLength = sizeof(struct usb_ss_ep_comp_descriptor);
|
||||||
|
ss_descriptor->ep_desc_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
|
||||||
|
if(flags & EP_BULK_MODE){
|
||||||
|
ss_descriptor->ep_desc_comp.bMaxBurst = 15;
|
||||||
|
ss_descriptor->ep_desc_comp.wBytesPerInterval = 0x00;
|
||||||
|
}else{
|
||||||
|
ss_descriptor->ep_desc_comp.bMaxBurst = 0;
|
||||||
|
ss_descriptor->ep_desc_comp.wBytesPerInterval = 64;//0x1c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
int usb_device::add_usb_string(usb_gadget * usbctx, int id, char * string)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while( i < MAX_USB_STRING )
|
||||||
|
{
|
||||||
|
if( !usbctx->stringtab[i].id )
|
||||||
|
{
|
||||||
|
usbctx->stringtab[i].id = id;
|
||||||
|
if(string)
|
||||||
|
{
|
||||||
|
usbctx->stringtab[i].str = (char*)malloc(strlen(string) + 1);
|
||||||
|
if(usbctx->stringtab[i].str)
|
||||||
|
{
|
||||||
|
memset(usbctx->stringtab[i].str,0,strlen(string) + 1);
|
||||||
|
strcpy(usbctx->stringtab[i].str,string);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usbctx->stringtab[i].id = 0;
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
void usb_device::fill_config_descriptor(usb_gadget * usbctx,struct usb_config_descriptor * desc,int total_size, int hs)
|
||||||
|
{
|
||||||
|
memset(desc,0,sizeof(struct usb_config_descriptor));
|
||||||
|
|
||||||
|
desc->bLength = sizeof(struct usb_config_descriptor);
|
||||||
|
desc->bDescriptorType = USB_DT_CONFIG;
|
||||||
|
desc->wTotalLength = desc->bLength + total_size;
|
||||||
|
desc->bNumInterfaces = 1;
|
||||||
|
desc->bConfigurationValue = CONFIG_VALUE;
|
||||||
|
if(hs)
|
||||||
|
desc->iConfiguration = STRINGID_CONFIG_HS;
|
||||||
|
else
|
||||||
|
desc->iConfiguration = STRINGID_CONFIG_LS;
|
||||||
|
desc->bmAttributes = USB_CONFIG_ATT_ONE;
|
||||||
|
desc->bMaxPower = 1;
|
||||||
|
}
|
||||||
|
void usb_device::fill_dev_descriptor(usb_gadget * usbctx,struct usb_device_descriptor * desc)
|
||||||
|
{
|
||||||
|
memset(desc,0,sizeof(struct usb_device_descriptor));
|
||||||
|
|
||||||
|
desc->bLength = USB_DT_DEVICE_SIZE;
|
||||||
|
desc->bDescriptorType = USB_DT_DEVICE;
|
||||||
|
desc->bDeviceClass = USB_DEV_CLASS;
|
||||||
|
desc->bDeviceSubClass = USB_DEV_SUBCLASS;
|
||||||
|
desc->bDeviceProtocol = USB_DEV_PROTOCOL;
|
||||||
|
desc->idVendor = USB_DEV_VENDOR_ID;
|
||||||
|
desc->idProduct = USB_DEV_PRODUCT_ID;
|
||||||
|
desc->bcdDevice = USB_DEV_VERSION; // Version
|
||||||
|
// Strings
|
||||||
|
desc->iManufacturer = STRINGID_MANUFACTURER;
|
||||||
|
desc->iProduct = STRINGID_PRODUCT;
|
||||||
|
desc->iSerialNumber = STRINGID_SERIAL;
|
||||||
|
desc->bNumConfigurations= 1; // Only one configuration
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void usb_device::init_usb_camtp_gadget(bool ffs_mode)
|
||||||
|
{
|
||||||
|
usb_gadget *usbctx = &gadget_; //(usb_gadget *)malloc(sizeof(usb_gadget));
|
||||||
|
int cfg_size;
|
||||||
|
|
||||||
|
if(usbctx)
|
||||||
|
{
|
||||||
|
std::ifstream fs(USB_MAX_PACKAGE_LENGTH_FILE);
|
||||||
|
int maxpackagesize = 0;
|
||||||
|
fs >> maxpackagesize;
|
||||||
|
if(maxpackagesize <= 0)
|
||||||
|
maxpackagesize = 512;
|
||||||
|
|
||||||
|
max_packet_ = maxpackagesize;
|
||||||
|
memset(usbctx, 0, sizeof(usb_gadget));
|
||||||
|
usbctx->usb_device = -1;
|
||||||
|
for(int i = 0; i < _countof(usbctx->ep_handles); ++i)
|
||||||
|
usbctx->ep_handles[i] = -1;
|
||||||
|
|
||||||
|
add_usb_string(usbctx, STRINGID_MANUFACTURER, MANUFACTURER);
|
||||||
|
add_usb_string(usbctx, STRINGID_PRODUCT, PRODUCT);
|
||||||
|
add_usb_string(usbctx, STRINGID_SERIAL, SERIALNUMBER);
|
||||||
|
add_usb_string(usbctx, STRINGID_CONFIG_HS, (char*)"High speed configuration");
|
||||||
|
add_usb_string(usbctx, STRINGID_CONFIG_LS, (char*)"Low speed configuration");
|
||||||
|
add_usb_string(usbctx, STRINGID_INTERFACE, USB_INTERFACE);
|
||||||
|
add_usb_string(usbctx, STRINGID_MAX, NULL);
|
||||||
|
|
||||||
|
strings.strings = usbctx->stringtab;
|
||||||
|
|
||||||
|
for(int i = 0; i < _countof(usbctx->ep_config); ++i)
|
||||||
|
{
|
||||||
|
usbctx->ep_config[i] = (ep_cfg*)malloc(sizeof(ep_cfg));
|
||||||
|
if(!usbctx->ep_config[i])
|
||||||
|
goto init_error;
|
||||||
|
|
||||||
|
memset(usbctx->ep_config[i], 0, sizeof(ep_cfg));
|
||||||
|
}
|
||||||
|
|
||||||
|
usbctx->ep_path[EP_IND_BULK_IN] = &ep_path_[EP_IND_BULK_IN][0];
|
||||||
|
usbctx->ep_path[EP_IND_BULK_OUT] = &ep_path_[EP_IND_BULK_OUT][0];
|
||||||
|
usbctx->ep_path[EP_IND_INT_IN] = &ep_path_[EP_IND_INT_IN][0];
|
||||||
|
|
||||||
|
cfg_size = sizeof(struct usb_interface_descriptor) + (sizeof(struct usb_endpoint_descriptor_no_audio) * _countof(usbctx->ep_config));
|
||||||
|
|
||||||
|
if( ffs_mode )
|
||||||
|
{
|
||||||
|
// FunctionFS mode
|
||||||
|
usbctx->usb_ffs_config = (usb_ffs_cfg *)malloc(sizeof(usb_ffs_cfg));
|
||||||
|
if(!usbctx->usb_ffs_config)
|
||||||
|
goto init_error;
|
||||||
|
|
||||||
|
memset(usbctx->usb_ffs_config, 0, sizeof(usb_ffs_cfg));
|
||||||
|
|
||||||
|
#ifdef OLD_FUNCTIONFS_DESCRIPTORS // Kernel < v3.15
|
||||||
|
usbctx->usb_ffs_config->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC);
|
||||||
|
#else
|
||||||
|
usbctx->usb_ffs_config->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
|
||||||
|
usbctx->usb_ffs_config->flags = htole32(0);
|
||||||
|
usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_ALL_CTRL_RECIP);
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_FS_SUPPORT
|
||||||
|
usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_HAS_FS_DESC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_HS_SUPPORT
|
||||||
|
usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_HAS_HS_DESC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_SS_SUPPORT
|
||||||
|
usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_HAS_SS_DESC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
usbctx->usb_ffs_config->length = htole32(sizeof(usb_ffs_cfg));
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_FS_SUPPORT
|
||||||
|
usbctx->usb_ffs_config->fs_count = htole32(1 + _countof(usbctx->ep_config));
|
||||||
|
|
||||||
|
fill_if_descriptor(ffs_mode, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.if_desc);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.ep_desc_in, EP_IND_BULK_IN + 1, EP_BULK_MODE | EP_IN_DIR);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.ep_desc_out, EP_IND_BULK_OUT + 1, EP_BULK_MODE | EP_OUT_DIR);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.ep_desc_int_in, EP_IND_INT_IN + 1, EP_INT_MODE | EP_IN_DIR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_HS_SUPPORT
|
||||||
|
usbctx->usb_ffs_config->hs_count = htole32(1 + _countof(usbctx->ep_config));
|
||||||
|
fill_if_descriptor(ffs_mode, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.if_desc);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.ep_desc_in, EP_IND_BULK_IN + 1, EP_BULK_MODE | EP_IN_DIR | EP_HS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.ep_desc_out, EP_IND_BULK_OUT + 1, EP_BULK_MODE | EP_OUT_DIR | EP_HS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.ep_desc_int_in, EP_IND_INT_IN + 1, EP_INT_MODE | EP_IN_DIR | EP_HS_MODE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_SS_SUPPORT
|
||||||
|
usbctx->usb_ffs_config->ss_count = htole32(1 + (_countof(usbctx->ep_config) * 2));
|
||||||
|
fill_if_descriptor(ffs_mode, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.if_desc);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.ep_desc_in, EP_IND_BULK_IN + 1, EP_BULK_MODE | EP_IN_DIR | EP_SS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.ep_desc_out, EP_IND_BULK_OUT + 1, EP_BULK_MODE | EP_OUT_DIR | EP_SS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.ep_desc_int_in, EP_IND_INT_IN + 1, EP_INT_MODE | EP_IN_DIR | EP_SS_MODE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usbctx->usb_config = (usb_cfg *)malloc(sizeof(usb_cfg));
|
||||||
|
if(!usbctx->usb_config)
|
||||||
|
goto init_error;
|
||||||
|
|
||||||
|
memset(usbctx->usb_config,0,sizeof(usb_cfg));
|
||||||
|
|
||||||
|
usbctx->usb_config->head = 0x00000000;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_FS_SUPPORT
|
||||||
|
fill_config_descriptor(usbctx, &usbctx->usb_config->cfg_fs, cfg_size, 0);
|
||||||
|
fill_if_descriptor(ffs_mode, usbctx, &usbctx->usb_config->ep_desc_fs.if_desc);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_fs.ep_desc_in, EP_IND_BULK_IN + 1, EP_BULK_MODE | EP_IN_DIR);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_fs.ep_desc_out, EP_IND_BULK_OUT + 1, EP_BULK_MODE | EP_OUT_DIR);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_fs.ep_desc_int_in, EP_IND_INT_IN + 1, EP_INT_MODE | EP_IN_DIR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_HS_SUPPORT
|
||||||
|
fill_config_descriptor(usbctx, &usbctx->usb_config->cfg_hs, cfg_size, 1);
|
||||||
|
fill_if_descriptor(ffs_mode, usbctx, &usbctx->usb_config->ep_desc_hs.if_desc);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_hs.ep_desc_in, EP_IND_BULK_IN + 1, EP_BULK_MODE | EP_IN_DIR | EP_HS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_hs.ep_desc_out, EP_IND_BULK_OUT + 1, EP_BULK_MODE | EP_OUT_DIR | EP_HS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_hs.ep_desc_int_in, EP_IND_INT_IN + 1, EP_INT_MODE | EP_IN_DIR | EP_HS_MODE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_SS_SUPPORT
|
||||||
|
fill_config_descriptor(usbctx, &usbctx->usb_config->cfg_ss, cfg_size, 1);
|
||||||
|
fill_if_descriptor(ffs_mode, usbctx, &usbctx->usb_config->ep_desc_ss.if_desc);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_ss.ep_desc_in, EP_IND_BULK_IN + 1, EP_BULK_MODE | EP_IN_DIR | EP_SS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_ss.ep_desc_out, EP_IND_BULK_OUT + 1, EP_BULK_MODE | EP_OUT_DIR | EP_SS_MODE);
|
||||||
|
fill_ep_descriptor(maxpackagesize, usbctx, &usbctx->usb_config->ep_desc_ss.ep_desc_int_in, EP_IND_INT_IN + 1, EP_INT_MODE | EP_IN_DIR | EP_SS_MODE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fill_dev_descriptor(usbctx, &usbctx->usb_config->dev_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_error:
|
||||||
|
deinit_usb_camtp_gadget();
|
||||||
|
}
|
||||||
|
void usb_device::deinit_usb_camtp_gadget()
|
||||||
|
{
|
||||||
|
usb_gadget * usbctx = &gadget_;
|
||||||
|
|
||||||
|
if( usbctx )
|
||||||
|
{
|
||||||
|
if(usbctx->usb_config)
|
||||||
|
{
|
||||||
|
free(usbctx->usb_config);
|
||||||
|
usbctx->usb_config = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(usbctx->usb_ffs_config)
|
||||||
|
{
|
||||||
|
free(usbctx->usb_ffs_config);
|
||||||
|
usbctx->usb_ffs_config = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < _countof(usbctx->ep_config); ++i)
|
||||||
|
{
|
||||||
|
if( usbctx->ep_config[i] )
|
||||||
|
free( usbctx->ep_config[i] );
|
||||||
|
usbctx->ep_config[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < _countof(usbctx->stringtab); ++i)
|
||||||
|
{
|
||||||
|
if( usbctx->stringtab[i].str )
|
||||||
|
free ( usbctx->stringtab[i].str );
|
||||||
|
usbctx->stringtab[i].str = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int usb_device::config_device(bool ffs_mode)
|
||||||
|
{
|
||||||
|
void *data = ffs_mode ? (void*)gadget_.usb_ffs_config : (void*)gadget_.usb_config;
|
||||||
|
int size = ffs_mode ? sizeof(*gadget_.usb_ffs_config) : sizeof(*gadget_.usb_config),
|
||||||
|
ret = write(gadget_.usb_device, data, size);
|
||||||
|
|
||||||
|
if(ret == size)
|
||||||
|
{
|
||||||
|
if(ffs_mode)
|
||||||
|
{
|
||||||
|
ret = write(gadget_.usb_device, &ffs_strs_, sizeof(ffs_strs_));
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
ret = errno;
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "config device with ffs_strings failed: %d - %s\n", errno, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = errno;
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "config device with '%s' failed: %d - %s\n", ffs_mode ? "ffs_config" : "usb_config", errno, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int usb_device::config_endpoint(int ep_ind)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
void * descriptor_ptr;
|
||||||
|
int descriptor_size;
|
||||||
|
int index = ep_ind;
|
||||||
|
usb_gadget* ctx = &gadget_;
|
||||||
|
|
||||||
|
ctx->ep_config[index]->head = 1;
|
||||||
|
descriptor_size = 0;
|
||||||
|
|
||||||
|
if( ctx->usb_ffs_config )
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_USB_SS_SUPPORT)
|
||||||
|
descriptor_ptr = (void *)&ctx->usb_ffs_config->ep_desc_ss;
|
||||||
|
descriptor_size = sizeof(ep_cfg_descriptor);
|
||||||
|
#elif defined(CONFIG_USB_HS_SUPPORT)
|
||||||
|
descriptor_ptr = (void *)&ctx->usb_ffs_config->ep_desc_hs;
|
||||||
|
descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio);
|
||||||
|
#elif defined(CONFIG_USB_FS_SUPPORT)
|
||||||
|
descriptor_ptr = (void *)&ctx->usb_ffs_config->ep_desc_fs;
|
||||||
|
descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio);
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error Configuration Error ! At least one USB mode support must be enabled ! (CONFIG_USB_FS_SUPPORT/CONFIG_USB_HS_SUPPORT/CONFIG_USB_SS_SUPPORT)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_USB_SS_SUPPORT)
|
||||||
|
descriptor_ptr = (void *)&ctx->usb_config->ep_desc_ss;
|
||||||
|
descriptor_size = sizeof(ep_cfg_descriptor);
|
||||||
|
#elif defined(CONFIG_USB_HS_SUPPORT)
|
||||||
|
descriptor_ptr = (void *)&ctx->usb_config->ep_desc_hs;
|
||||||
|
descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio);
|
||||||
|
#elif defined(CONFIG_USB_FS_SUPPORT)
|
||||||
|
descriptor_ptr = (void *)&ctx->usb_config->ep_desc_fs;
|
||||||
|
descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio);
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error Configuration Error ! At least one USB mode support must be enabled ! (CONFIG_USB_FS_SUPPORT/CONFIG_USB_HS_SUPPORT/CONFIG_USB_SS_SUPPORT)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USB_SS_SUPPORT)
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case EP_DESCRIPTOR_IN:
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[0], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size);
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[1], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size);
|
||||||
|
break;
|
||||||
|
case EP_DESCRIPTOR_OUT:
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[0], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size);
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[1], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size);
|
||||||
|
break;
|
||||||
|
case EP_DESCRIPTOR_INT_IN:
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[0], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size);
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[1], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case EP_DESCRIPTOR_IN:
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[0], &((EndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size);
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[1], &((EndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size);
|
||||||
|
break;
|
||||||
|
case EP_DESCRIPTOR_OUT:
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[0], &((EndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size);
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[1], &((EndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size);
|
||||||
|
break;
|
||||||
|
case EP_DESCRIPTOR_INT_IN:
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[0], &((EndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size);
|
||||||
|
memcpy(&ctx->ep_config[index]->ep_desc[1], &((EndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(ffs_mode_)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = write(ctx->ep_handles[index], ctx->ep_config[index], sizeof(ep_cfg));
|
||||||
|
|
||||||
|
if (ret != sizeof(ep_cfg))
|
||||||
|
{
|
||||||
|
ret = errno;
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "config_endpoint '%s' failed: %d - %s", usb_device::endpoint_index_str(index).c_str(), errno, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usb_device::add_endpoint(const char* path, bool bulk/*true - bulk, false - int*/, bool in)
|
||||||
|
{
|
||||||
|
int ret = 0, ind = -1;
|
||||||
|
if(bulk)
|
||||||
|
{
|
||||||
|
if(in)
|
||||||
|
ind = EP_IND_BULK_IN;
|
||||||
|
else
|
||||||
|
ind = EP_IND_BULK_OUT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(in)
|
||||||
|
ind = EP_IND_INT_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ind == -1)
|
||||||
|
ret = EINVAL;
|
||||||
|
else
|
||||||
|
ep_path_[ind] = path ? path : "";
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int usb_device::open_device(const char* dev, bool ffs_mode, int* fd)
|
||||||
|
{
|
||||||
|
int ret = close_device();
|
||||||
|
|
||||||
|
if(fd)
|
||||||
|
*fd = -1;
|
||||||
|
|
||||||
|
if(ret == 0)
|
||||||
|
{
|
||||||
|
init_usb_camtp_gadget(ffs_mode);
|
||||||
|
gadget_.usb_device = open(dev, O_RDWR | O_SYNC);
|
||||||
|
if(gadget_.usb_device == -1)
|
||||||
|
{
|
||||||
|
ret = errno;
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "Open usb device(%s) failed: %d - %s\n", dev, ret, strerror(ret));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = config_device(ffs_mode);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
close_device();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "Open usb device(%s) success.\n", dev);
|
||||||
|
ffs_mode_ = ffs_mode;
|
||||||
|
|
||||||
|
// get_system_output(R"(echo linaro | sudo -S sh -c "chmod 777 /dev/ffs-camtp -R")");
|
||||||
|
std::string cmd(dev);
|
||||||
|
size_t pos = cmd.rfind('/');
|
||||||
|
|
||||||
|
if(pos != std::string::npos)
|
||||||
|
cmd.erase(pos);
|
||||||
|
cmd += " -R\"";
|
||||||
|
cmd.insert(0, "echo " + pwd_ + " | sudo -S sh -c \"chmod 777 ");
|
||||||
|
utils::get_command_result(cmd.c_str());
|
||||||
|
}
|
||||||
|
if(fd)
|
||||||
|
*fd = gadget_.usb_device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int usb_device::open_endpoint(int ep_ind, int* fd)
|
||||||
|
{
|
||||||
|
int ret = ENOTCONN;
|
||||||
|
|
||||||
|
if(fd)
|
||||||
|
*fd = -1;
|
||||||
|
|
||||||
|
if(gadget_.usb_device >= 0)
|
||||||
|
{
|
||||||
|
if(ep_ind >= 0 && ep_ind < _countof(gadget_.ep_handles))
|
||||||
|
{
|
||||||
|
if(gadget_.ep_handles[ep_ind] >= 0)
|
||||||
|
{
|
||||||
|
ret = EALREADY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gadget_.ep_handles[ep_ind] = open(gadget_.ep_path[ep_ind], O_RDWR);
|
||||||
|
if(gadget_.ep_handles[ep_ind] == -1)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "open endpoint(%s - %s) failed: %d - %s\n", usb_device::endpoint_index_str(ep_ind).c_str(), gadget_.ep_path[ep_ind], errno, strerror(errno));
|
||||||
|
ret = errno;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = config_endpoint(ep_ind);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
close(gadget_.ep_handles[ep_ind]);
|
||||||
|
gadget_.ep_handles[ep_ind] = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "open endpoint(%s - %s) ok.\n", usb_device::endpoint_index_str(ep_ind).c_str(), gadget_.ep_path[ep_ind]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fd)
|
||||||
|
*fd = gadget_.ep_handles[ep_ind];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int usb_device::close_endpoint(int ep_ind)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if(ep_ind == -1)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < _countof(gadget_.ep_handles); ++i)
|
||||||
|
{
|
||||||
|
if(gadget_.ep_handles[i] != -1)
|
||||||
|
{
|
||||||
|
ret = close(gadget_.ep_handles[i]);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "close endpoint(%s) failed: %d(%s)\n", usb_device::endpoint_index_str(i).c_str(), errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gadget_.ep_handles[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "close all endpoints = %d\n", ret);
|
||||||
|
}
|
||||||
|
else if(ep_ind >= 0 && ep_ind < _countof(gadget_.ep_handles))
|
||||||
|
{
|
||||||
|
if(gadget_.ep_handles[ep_ind] != -1)
|
||||||
|
{
|
||||||
|
ret = close(gadget_.ep_handles[ep_ind]);
|
||||||
|
if(ret)
|
||||||
|
utils::to_log(LOG_LEVEL_FATAL, "close endpoint(%s) failed: %d(%s)\n", usb_device::endpoint_index_str(ep_ind).c_str(), errno, strerror(errno));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gadget_.ep_handles[ep_ind] = -1;
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "close endpoint(%s) ok.\n", usb_device::endpoint_index_str(ep_ind).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int usb_device::close_device(void)
|
||||||
|
{
|
||||||
|
int ret = pull_down();
|
||||||
|
|
||||||
|
if(ret == 0)
|
||||||
|
{
|
||||||
|
ret = close_endpoint(-1);
|
||||||
|
if(ret == 0)
|
||||||
|
{
|
||||||
|
deinit_usb_camtp_gadget();
|
||||||
|
if(gadget_.usb_device >= 0)
|
||||||
|
{
|
||||||
|
ret = close(gadget_.usb_device);
|
||||||
|
if(ret == 0)
|
||||||
|
gadget_.usb_device = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int usb_device::pull_up(std::string* msg)
|
||||||
|
{
|
||||||
|
std::string cmd("echo " + pwd_ + " | sudo -S sh -c \"echo " + dwc3_ + " > " + udc_ + "\"");
|
||||||
|
int err = 0;
|
||||||
|
std::string info(utils::get_command_result(cmd.c_str(), -1, &err));
|
||||||
|
|
||||||
|
if(msg)
|
||||||
|
*msg = std::move(info);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
int usb_device::pull_down(void)
|
||||||
|
{
|
||||||
|
std::string cmd("echo " + pwd_ + " | sudo -S sh -c \"echo " + "''" + " > " + udc_ + "\"");
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
utils::get_command_result(cmd.c_str(), -1, &err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usb_device::get_device_fd(void)
|
||||||
|
{
|
||||||
|
return gadget_.usb_device;
|
||||||
|
}
|
||||||
|
int usb_device::get_endpoint_fd(int ep_ind)
|
||||||
|
{
|
||||||
|
if(ep_ind >= 0 && ep_ind < _countof(gadget_.ep_handles))
|
||||||
|
return gadget_.ep_handles[ep_ind];
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t usb_device::get_max_packet(void)
|
||||||
|
{
|
||||||
|
return max_packet_;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
// USB device configuration and open
|
||||||
|
//
|
||||||
|
// Date: 2023-11-28
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "buildconf.h"
|
||||||
|
#include "camtp.h"
|
||||||
|
#include "usb_gadget.h"
|
||||||
|
#include "../sdk/base/utils.h"
|
||||||
|
|
||||||
|
class usb_device : public refer
|
||||||
|
{
|
||||||
|
usb_gadget gadget_;
|
||||||
|
std::string dwc3_; // fe900000.dwc3
|
||||||
|
std::string udc_; // /opt/cfg/usb_gadget/g1/UDC
|
||||||
|
std::string pwd_; // password of login user
|
||||||
|
std::string ep_path_[EP_NB_OF_DESCRIPTORS];
|
||||||
|
ffs_strings ffs_strs_;
|
||||||
|
bool ffs_mode_ = true;
|
||||||
|
size_t max_packet_ = 512;
|
||||||
|
|
||||||
|
void fill_if_descriptor(bool ffs_mode, usb_gadget * usbctx, struct usb_interface_descriptor * desc);
|
||||||
|
void fill_ep_descriptor(unsigned short max_packet, usb_gadget * usbctx, struct usb_endpoint_descriptor_no_audio * desc, int index, unsigned int flags);
|
||||||
|
int add_usb_string(usb_gadget * usbctx, int id, char * string);
|
||||||
|
void fill_config_descriptor(usb_gadget * usbctx,struct usb_config_descriptor * desc, int total_size, int hs);
|
||||||
|
void fill_dev_descriptor(usb_gadget * usbctx, struct usb_device_descriptor * desc);
|
||||||
|
void init_usb_camtp_gadget(bool ffs_mode);
|
||||||
|
void deinit_usb_camtp_gadget(void);
|
||||||
|
|
||||||
|
int config_device(bool ffs_mode);
|
||||||
|
int config_endpoint(int ep_ind);
|
||||||
|
|
||||||
|
public:
|
||||||
|
usb_device(const char* dwc3, const char* udc, const char* pwd);
|
||||||
|
|
||||||
|
static std::string endpoint_index_str(int epind);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~usb_device();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int add_endpoint(const char* path, bool bulk/*true - bulk, false - int*/, bool in);
|
||||||
|
int open_device(const char* dev, bool ffs_mode, int* fd = nullptr);
|
||||||
|
int open_endpoint(int ep_ind, int* fd = nullptr);
|
||||||
|
int close_endpoint(int ep_ind);
|
||||||
|
int close_device(void);
|
||||||
|
int pull_up(std::string* msg = nullptr); // turn USB-pin on, so that the host can detect me
|
||||||
|
int pull_down(void);
|
||||||
|
|
||||||
|
int get_device_fd(void);
|
||||||
|
int get_endpoint_fd(int ep_ind);
|
||||||
|
size_t get_max_packet(void);
|
||||||
|
};
|
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
* CAMTP Responder
|
||||||
|
* Copyright (c) 2020 Holdtecs Technologies
|
||||||
|
*
|
||||||
|
* CAMTP Responder is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3.0 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* CAMTP Responder is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License version 3 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with CAMTP Responder; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file usb_gadget.c
|
||||||
|
* @brief USB gadget layer
|
||||||
|
* @author ***
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_USB_GADGET_H_
|
||||||
|
#define _INC_USB_GADGET_H_
|
||||||
|
|
||||||
|
#include <linux/usb/ch9.h>
|
||||||
|
#include <linux/usb/gadgetfs.h>
|
||||||
|
#include <linux/usb/functionfs.h>
|
||||||
|
|
||||||
|
#include "usbstring.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EP_DESCRIPTOR_IN = 0,
|
||||||
|
EP_DESCRIPTOR_OUT,
|
||||||
|
EP_DESCRIPTOR_INT_IN,
|
||||||
|
|
||||||
|
EP_NB_OF_DESCRIPTORS
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EP_INT_MODE 0x00000000
|
||||||
|
#define EP_BULK_MODE 0x00000001
|
||||||
|
#define EP_IN_DIR 0x00000000
|
||||||
|
#define EP_OUT_DIR 0x00000002
|
||||||
|
#define EP_HS_MODE 0x00000004
|
||||||
|
#define EP_SS_MODE 0x00000008
|
||||||
|
|
||||||
|
typedef struct _EndPointsDesc {
|
||||||
|
struct usb_interface_descriptor if_desc;
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc_in;
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc_out;
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc_int_in;
|
||||||
|
} __attribute__((packed)) EndPointsDesc;
|
||||||
|
|
||||||
|
typedef struct _SSEndPointsDesc {
|
||||||
|
struct usb_interface_descriptor if_desc;
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc_in;
|
||||||
|
struct usb_ss_ep_comp_descriptor ep_desc_in_comp;
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc_out;
|
||||||
|
struct usb_ss_ep_comp_descriptor ep_desc_out_comp;
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc_int_in;
|
||||||
|
struct usb_ss_ep_comp_descriptor ep_desc_int_in_comp;
|
||||||
|
|
||||||
|
} __attribute__((packed)) SSEndPointsDesc;
|
||||||
|
|
||||||
|
typedef struct ep_cfg_descriptor {
|
||||||
|
struct usb_endpoint_descriptor_no_audio ep_desc;
|
||||||
|
#ifdef CONFIG_USB_SS_SUPPORT
|
||||||
|
struct usb_ss_ep_comp_descriptor ep_desc_comp;
|
||||||
|
#endif
|
||||||
|
} __attribute__((packed)) ep_cfg_descriptor;
|
||||||
|
|
||||||
|
// Direct GadgetFS mode
|
||||||
|
typedef struct _usb_cfg
|
||||||
|
{
|
||||||
|
uint32_t head;
|
||||||
|
|
||||||
|
#if CONFIG_USB_FS_SUPPORT
|
||||||
|
struct usb_config_descriptor cfg_fs;
|
||||||
|
EndPointsDesc ep_desc_fs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_USB_HS_SUPPORT
|
||||||
|
struct usb_config_descriptor cfg_hs;
|
||||||
|
EndPointsDesc ep_desc_hs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_USB_SS_SUPPORT
|
||||||
|
struct usb_config_descriptor cfg_ss;
|
||||||
|
SSEndPointsDesc ep_desc_ss;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct usb_device_descriptor dev_desc;
|
||||||
|
|
||||||
|
} __attribute__ ((packed)) usb_cfg;
|
||||||
|
|
||||||
|
// FunctionFS mode
|
||||||
|
typedef struct _usb_ffs_cfg
|
||||||
|
{
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t length;
|
||||||
|
#ifndef OLD_FUNCTIONFS_DESCRIPTORS // Kernel > v3.14
|
||||||
|
uint32_t flags;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_FS_SUPPORT
|
||||||
|
uint32_t fs_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_HS_SUPPORT
|
||||||
|
uint32_t hs_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_USB_SS_SUPPORT) && !defined(OLD_FUNCTIONFS_DESCRIPTORS)
|
||||||
|
uint32_t ss_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_FS_SUPPORT
|
||||||
|
EndPointsDesc ep_desc_fs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_HS_SUPPORT
|
||||||
|
EndPointsDesc ep_desc_hs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_USB_SS_SUPPORT) && !defined(OLD_FUNCTIONFS_DESCRIPTORS)
|
||||||
|
SSEndPointsDesc ep_desc_ss;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} __attribute__ ((packed)) usb_ffs_cfg;
|
||||||
|
|
||||||
|
typedef struct _ffs_strings
|
||||||
|
{
|
||||||
|
struct usb_functionfs_strings_head header;
|
||||||
|
uint16_t code;
|
||||||
|
char string_data[128]; // string data.
|
||||||
|
} __attribute__((packed)) ffs_strings;
|
||||||
|
|
||||||
|
typedef struct _ep_cfg
|
||||||
|
{
|
||||||
|
uint32_t head;
|
||||||
|
|
||||||
|
ep_cfg_descriptor ep_desc[2];
|
||||||
|
|
||||||
|
} __attribute__ ((packed)) ep_cfg;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STRINGID_MANUFACTURER = 1,
|
||||||
|
STRINGID_PRODUCT,
|
||||||
|
STRINGID_SERIAL,
|
||||||
|
STRINGID_CONFIG_HS,
|
||||||
|
STRINGID_CONFIG_LS,
|
||||||
|
STRINGID_INTERFACE,
|
||||||
|
STRINGID_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_USB_STRING 16
|
||||||
|
|
||||||
|
typedef struct _usb_gadget
|
||||||
|
{
|
||||||
|
int usb_device;
|
||||||
|
int ep_handles[EP_NB_OF_DESCRIPTORS];
|
||||||
|
|
||||||
|
usb_cfg *usb_config;
|
||||||
|
usb_ffs_cfg *usb_ffs_config;
|
||||||
|
|
||||||
|
ep_cfg *ep_config[EP_NB_OF_DESCRIPTORS];
|
||||||
|
char *ep_path[EP_NB_OF_DESCRIPTORS];
|
||||||
|
|
||||||
|
struct usb_string stringtab[MAX_USB_STRING];
|
||||||
|
}usb_gadget;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,636 @@
|
||||||
|
#include "usb_io.h"
|
||||||
|
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <linux/usb/functionfs.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <base/encrypt.h>
|
||||||
|
|
||||||
|
#include "usb_dev.h"
|
||||||
|
#include "default_cfg.h"
|
||||||
|
|
||||||
|
// #define TEST
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// async_usb_gadget
|
||||||
|
async_usb_gadget::async_usb_gadget(std::function<FUNCTION_PROTO_COMMAND_HANDLE> cmd_handler
|
||||||
|
, std::function<void(bool)> dev_conn)
|
||||||
|
: handle_cmd_(cmd_handler), dev_connect_(dev_conn)
|
||||||
|
, enc_head_(ENCRYPT_CMD_NONE), enc_payload_(ENCRYPT_NONE), enc_data_(0)
|
||||||
|
, cmd_que_("in-queue"), sent_que_("out-queue")
|
||||||
|
{
|
||||||
|
memset((void*)&status_, 0, sizeof(status_));
|
||||||
|
|
||||||
|
dev_ = new usb_device("fe900000.dwc3", "/opt/cfg/usb_gadget/g1/UDC", "linaro");
|
||||||
|
dev_->add_endpoint(USB_EP_BULK_IN, true, true);
|
||||||
|
dev_->add_endpoint(USB_EP_BULK_OUT, true, false);
|
||||||
|
if(dev_->open_device(USB_DEV, true))
|
||||||
|
{
|
||||||
|
dev_->release();
|
||||||
|
dev_ = nullptr;
|
||||||
|
run_ = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ep0 = [this](void) -> void
|
||||||
|
{
|
||||||
|
thread_read_ep0();
|
||||||
|
};
|
||||||
|
auto task = [this](void) -> void
|
||||||
|
{
|
||||||
|
thread_pump_task();
|
||||||
|
};
|
||||||
|
auto bulkw = [this](void) -> void
|
||||||
|
{
|
||||||
|
int fd = -1,
|
||||||
|
err = dev_->open_endpoint(EP_IND_BULK_IN, &fd);
|
||||||
|
|
||||||
|
if(err == 0)
|
||||||
|
{
|
||||||
|
thread_read_bulk(fd);
|
||||||
|
dev_->close_endpoint(EP_IND_BULK_IN);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto bulkr = [this](void) -> void
|
||||||
|
{
|
||||||
|
int fd = -1,
|
||||||
|
err = dev_->open_endpoint(EP_IND_BULK_OUT, &fd);
|
||||||
|
|
||||||
|
if(err == 0)
|
||||||
|
{
|
||||||
|
thread_write_bulk(fd);
|
||||||
|
dev_->close_endpoint(EP_IND_BULK_OUT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto excep = [&](const char* thread_name) -> void
|
||||||
|
{
|
||||||
|
threads_.stop(thread_name);
|
||||||
|
// threads_.start(task, "thread_pump_task");
|
||||||
|
};
|
||||||
|
|
||||||
|
threads_.set_exception_handler(excep);
|
||||||
|
unit_in_ = unit_out_ = dev_->get_max_packet();
|
||||||
|
threads_.start(task, "thread_pump_task");
|
||||||
|
threads_.start(bulkw, "thread_read_bulk");
|
||||||
|
threads_.start(bulkr, "thread_write_bulk");
|
||||||
|
threads_.start(ep0, "thread_read_ep0");
|
||||||
|
}
|
||||||
|
|
||||||
|
async_usb_gadget::~async_usb_gadget()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* async_usb_gadget::ep0_status_desc(int ep0_status, char* unk_buf/*>= 20 bytes*/)
|
||||||
|
{
|
||||||
|
RETURN_ENUM_STR(ep0_status, EP0_STATUS_IDLE);
|
||||||
|
RETURN_ENUM_STR(ep0_status, EP0_STATUS_READ_DATA);
|
||||||
|
RETURN_ENUM_STR(ep0_status, EP0_STATUS_READ_INVAL_DATA);
|
||||||
|
RETURN_ENUM_STR(ep0_status, EP0_STATUS_HANDLE_CMD);
|
||||||
|
|
||||||
|
sprintf(unk_buf, "Unknown status (%d)", ep0_status);
|
||||||
|
|
||||||
|
return unk_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int async_usb_gadget::wait_fd_event(int fd, int to_ms)
|
||||||
|
{
|
||||||
|
struct timeval timeout, *pto = NULL;
|
||||||
|
fd_set read_set;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
FD_ZERO(&read_set);
|
||||||
|
FD_SET(fd, &read_set);
|
||||||
|
if (to_ms != -1)
|
||||||
|
{
|
||||||
|
timeout.tv_sec = to_ms / 1000;
|
||||||
|
timeout.tv_usec = (to_ms % 1000) * 1000;
|
||||||
|
pto = &timeout;
|
||||||
|
}
|
||||||
|
ret = select(fd + 1, &read_set, NULL, NULL, pto);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
uint16_t async_usb_gadget::get_buf_coefficient(void)
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(buf_coef_lock_);
|
||||||
|
|
||||||
|
return buf_coef_;
|
||||||
|
}
|
||||||
|
void async_usb_gadget::set_buf_coefficient(int coef)
|
||||||
|
{
|
||||||
|
SIMPLE_LOCK(buf_coef_lock_);
|
||||||
|
|
||||||
|
buf_coef_ = (coef <= 0 || coef > 10000) ? 1 : coef;
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_mem_ptr async_usb_gadget::handle_ctrl_message(dyn_mem_ptr data)
|
||||||
|
{
|
||||||
|
struct usb_functionfs_event* pev = (struct usb_functionfs_event*)data->ptr();
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
|
||||||
|
switch (pev->type)
|
||||||
|
{
|
||||||
|
case FUNCTIONFS_ENABLE:
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS ENABLE\n");
|
||||||
|
if(dev_connect_)
|
||||||
|
dev_connect_(true);
|
||||||
|
break;
|
||||||
|
case FUNCTIONFS_DISABLE:
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS DISABLE\n");
|
||||||
|
if(dev_connect_)
|
||||||
|
dev_connect_(false);
|
||||||
|
break;
|
||||||
|
case FUNCTIONFS_SETUP:
|
||||||
|
reply = handle_ctrl_setup(data);
|
||||||
|
break;
|
||||||
|
case FUNCTIONFS_BIND:
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS BIND\n");
|
||||||
|
break;
|
||||||
|
case FUNCTIONFS_UNBIND:
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS UNBIND\n");
|
||||||
|
break;
|
||||||
|
case FUNCTIONFS_SUSPEND:
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS SUSPEND\n");
|
||||||
|
break;
|
||||||
|
case FUNCTIONFS_RESUME:
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 FFS RESUME\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pev->u.setup.bRequestType & USB_DIR_IN)
|
||||||
|
{
|
||||||
|
// if host need data back, and reply is null, we send nonsense data back ...
|
||||||
|
if (!reply)
|
||||||
|
{
|
||||||
|
reply = dyn_mem::memory(pev->u.setup.wLength + sizeof(uint16_t));
|
||||||
|
reply->set_len(pev->u.setup.wLength);
|
||||||
|
for (int i = 0; i <= pev->u.setup.wLength / sizeof(uint16_t); ++i)
|
||||||
|
((uint16_t*)reply->ptr())[i] = 0x0baad;
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "fake control message reply(%u bytes) while request with USB_DIR_IN flag but no reply returned.\n", reply->get_rest());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(reply)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "discard control message reply(%u bytes) while request without USB_DIR_IN flag.\n", reply->get_rest());
|
||||||
|
reply->release();
|
||||||
|
reply = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_usb_gadget::handle_ctrl_setup(dyn_mem_ptr data)
|
||||||
|
{
|
||||||
|
struct usb_functionfs_event* pev = (struct usb_functionfs_event*)data->ptr();
|
||||||
|
bool handled = (pev->u.setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR;
|
||||||
|
dyn_mem_ptr reply = nullptr;
|
||||||
|
uint32_t err = 0;
|
||||||
|
|
||||||
|
if(handled)
|
||||||
|
{
|
||||||
|
switch (pev->u.setup.bRequest)
|
||||||
|
{
|
||||||
|
case USB_REQ_EP0_GET_PROTO_VER:
|
||||||
|
reply = dyn_mem::memory(sizeof(short));
|
||||||
|
*(short*)reply->ptr() = PROTOCOL_VER;
|
||||||
|
reply->set_len(sizeof(short));
|
||||||
|
break;
|
||||||
|
case USB_REQ_EP0_GET_STATUS:
|
||||||
|
reply = dyn_mem::memory(sizeof(struct _ep0_reply));
|
||||||
|
{
|
||||||
|
reply->put((void*)&status_, sizeof(status_));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_REQ_EP0_RESET_BULK:
|
||||||
|
reply = dyn_mem::memory(sizeof(uint32_t));
|
||||||
|
reply->put(&err, sizeof(err));
|
||||||
|
break;
|
||||||
|
case USB_REQ_EP0_SET_ENCRYPT:
|
||||||
|
if (pev->u.setup.wLength == sizeof(PACK_BASE))
|
||||||
|
{
|
||||||
|
LPPACK_BASE pack = (LPPACK_BASE)&pev[1];
|
||||||
|
enc_head_ = pack->enc_cmd;
|
||||||
|
enc_payload_ = pack->encrypt;
|
||||||
|
enc_data_ = pack->enc_data;
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "Set encrypting method: command - %d; payload - %d\n", enc_head_, enc_payload_);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_REQ_EP0_SET_BULK_BUFFER:
|
||||||
|
// if(pev->u.setup.wLength == sizeof(short))
|
||||||
|
{
|
||||||
|
uint16_t pre = buf_coef_;
|
||||||
|
|
||||||
|
set_buf_coefficient(pev->u.setup.wIndex);
|
||||||
|
utils::to_log(LOG_LEVEL_DEBUG, "Set bulk buffer size coefficient from %d to %d\n", pre, buf_coef_);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
handled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!handled)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 event(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) has not handled by user business.\n"
|
||||||
|
, pev->u.setup.bRequestType, pev->u.setup.bRequest, pev->u.setup.wValue, pev->u.setup.wIndex, pev->u.setup.wLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err)
|
||||||
|
{
|
||||||
|
unsigned char* ptr = data->ptr();
|
||||||
|
size_t bulk_size = unit_in_ * get_buf_coefficient(),
|
||||||
|
total = data->get_rest(), off = 0, size = total > bulk_size ? bulk_size : total;
|
||||||
|
int w = 0;
|
||||||
|
|
||||||
|
if(data->is_memory_block())
|
||||||
|
{
|
||||||
|
while((w = write(fd, ptr + off, size)) > 0)
|
||||||
|
{
|
||||||
|
off += w;
|
||||||
|
status_.bytes_to_sent -= w;
|
||||||
|
if(off >= total)
|
||||||
|
break;
|
||||||
|
if(off + bulk_size < total)
|
||||||
|
size = bulk_size;
|
||||||
|
else
|
||||||
|
size = total - off;
|
||||||
|
}
|
||||||
|
if(w <= 0 && err)
|
||||||
|
*err = errno;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dyn_mem_ptr buf = dyn_mem::memory(bulk_size);
|
||||||
|
uint32_t len = bulk_size;
|
||||||
|
|
||||||
|
if(err)
|
||||||
|
*err = 0;
|
||||||
|
total = 0;
|
||||||
|
while((w = data->fetch_data(buf->ptr(), &len)) == 0)
|
||||||
|
{
|
||||||
|
ptr = buf->ptr();
|
||||||
|
off = 0;
|
||||||
|
w = write(fd, ptr + off, len);
|
||||||
|
while(w > 0 && w + off < len)
|
||||||
|
{
|
||||||
|
status_.bytes_to_sent -= w;
|
||||||
|
total += w;
|
||||||
|
off += w;
|
||||||
|
w = write(fd, ptr + off, len - off);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(w <= 0)
|
||||||
|
{
|
||||||
|
if(err)
|
||||||
|
*err = errno;
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "inner_write_bulk error(%d/%d): %d (%s)\n", off, len, errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status_.bytes_to_sent -= w;
|
||||||
|
total += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->get_rest() == 0)
|
||||||
|
break;
|
||||||
|
len = bulk_size;
|
||||||
|
}
|
||||||
|
buf->release();
|
||||||
|
off = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
dyn_mem_ptr async_usb_gadget::handle_bulk_command(dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* pkd)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr decrypt = packet_decrypt(data);
|
||||||
|
|
||||||
|
if (decrypt)
|
||||||
|
{
|
||||||
|
data->release();
|
||||||
|
data = decrypt;
|
||||||
|
|
||||||
|
return handle_cmd_(data, used, pkd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*used = data->get_rest();
|
||||||
|
*pkd = nullptr;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_usb_gadget::thread_read_ep0(void)
|
||||||
|
{
|
||||||
|
struct timeval timeout;
|
||||||
|
int headl = sizeof(struct usb_functionfs_event),
|
||||||
|
datal = 128, // gadget_->usb_config->dev_desc.bMaxPacketSize0,
|
||||||
|
ret = 0,
|
||||||
|
fd = dev_->get_device_fd();
|
||||||
|
dyn_mem_ptr mem = dyn_mem::memory(headl + datal);
|
||||||
|
uint8_t* ptr = mem->ptr();
|
||||||
|
uint32_t recycles = 0;
|
||||||
|
std::string msg("");
|
||||||
|
struct usb_functionfs_event* pe = (struct usb_functionfs_event*)ptr;
|
||||||
|
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 monitoring thread(%p of id %lx) started ...\n", &async_usb_gadget::thread_read_ep0, getpid());
|
||||||
|
ret = dev_->pull_up(&msg);
|
||||||
|
while(run_)
|
||||||
|
{
|
||||||
|
ret = wait_fd_event(fd);
|
||||||
|
if( ret <= 0 )
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "select EP0(%d) failed: %d(%s)\n", fd, errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeout.tv_sec = 0;
|
||||||
|
ret = read(fd, ptr, headl);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "read EP0 failed: %d(%s)\n", errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool good = true;
|
||||||
|
if(pe->u.setup.bRequestType & USB_DIR_IN)
|
||||||
|
mem->set_len(headl);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pe->u.setup.wLength > datal)
|
||||||
|
{
|
||||||
|
good = false;
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "EP0 data too long(%d > %d), we will discard this packet(0x%x, 0x%x, 0x%x, 0x%x)!\n", pe->u.setup.wLength, datal,
|
||||||
|
pe->u.setup.bRequestType, pe->u.setup.bRequest, pe->u.setup.wValue, pe->u.setup.wIndex);
|
||||||
|
|
||||||
|
// we read-out whole data here ...
|
||||||
|
int rest = pe->u.setup.wLength;
|
||||||
|
while (rest > 0)
|
||||||
|
{
|
||||||
|
read(fd, ptr + headl, rest > datal ? datal : rest);
|
||||||
|
rest -= datal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
read(fd, ptr + headl, pe->u.setup.wLength);
|
||||||
|
mem->set_len(headl + pe->u.setup.wLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (good)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr reply = handle_ctrl_message(mem);
|
||||||
|
if(reply)
|
||||||
|
{
|
||||||
|
write(fd, reply->ptr(), reply->get_rest());
|
||||||
|
reply->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mem->release();
|
||||||
|
}
|
||||||
|
void async_usb_gadget::thread_read_bulk(int fd)
|
||||||
|
{
|
||||||
|
size_t bulk_size = unit_out_ * get_buf_coefficient();
|
||||||
|
uint32_t cnt_0 = 0;
|
||||||
|
|
||||||
|
while(run_)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr buf(dyn_mem::memory(bulk_size));
|
||||||
|
int l = 0;
|
||||||
|
|
||||||
|
status_.out_status = BULK_STATUS_IO;
|
||||||
|
l = read(fd, buf->ptr(), bulk_size);
|
||||||
|
if(l <= 0)
|
||||||
|
{
|
||||||
|
buf->release();
|
||||||
|
if(errno)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "read bulk failed: %d(%s)\n", errno, strerror(errno));
|
||||||
|
status_.out_status = BULK_STATUS_ERROR;
|
||||||
|
status_.out_err = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cnt_0++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!run_)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "thread_read_bulk do reset-bulk ...\n");
|
||||||
|
buf->release();
|
||||||
|
if(!run_)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status_.out_status = BULK_STATUS_IDLE;
|
||||||
|
buf->set_len(l);
|
||||||
|
cmd_que_.save(buf, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(status_.out_status == BULK_STATUS_IDLE)
|
||||||
|
status_.out_status = BULK_STATUS_NOT_START;
|
||||||
|
}
|
||||||
|
void async_usb_gadget::thread_write_bulk(int fd)
|
||||||
|
{
|
||||||
|
status_.in_status = BULK_STATUS_IDLE;
|
||||||
|
while(run_)
|
||||||
|
{
|
||||||
|
data_source_ptr data;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if(sent_que_.take(data, true))
|
||||||
|
{
|
||||||
|
status_.packets_to_sent = sent_que_.size();
|
||||||
|
status_.bytes_to_sent = data->get_rest();
|
||||||
|
status_.in_status = BULK_STATUS_IO;
|
||||||
|
inner_write_bulk(fd, data, &err);
|
||||||
|
status_.in_status = BULK_STATUS_IDLE;
|
||||||
|
status_.bytes_to_sent = 0;
|
||||||
|
data->release();
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "write bulk failed: %d(%s)\n", errno, strerror(errno));
|
||||||
|
status_.in_status = BULK_STATUS_ERROR;
|
||||||
|
status_.in_err = err;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(status_.in_status == BULK_STATUS_IDLE)
|
||||||
|
status_.in_status = BULK_STATUS_NOT_START;
|
||||||
|
}
|
||||||
|
void async_usb_gadget::thread_pump_task(void)
|
||||||
|
{
|
||||||
|
dyn_mem_ptr prev = nullptr, data = nullptr, reply = nullptr;
|
||||||
|
bool in_err_statu = false;
|
||||||
|
uint32_t required = 0, used = 0, restore_err_cnt = 0, max_que = 0;
|
||||||
|
data_holder *dh = nullptr;
|
||||||
|
LPPACK_BASE pack = nullptr;
|
||||||
|
uint64_t total_size = 0;
|
||||||
|
|
||||||
|
while(run_)
|
||||||
|
{
|
||||||
|
data = nullptr;
|
||||||
|
if(cmd_que_.take(data, true) && data)
|
||||||
|
{
|
||||||
|
status_.task_cnt = cmd_que_.size();
|
||||||
|
if(max_que < status_.task_cnt)
|
||||||
|
max_que = status_.task_cnt;
|
||||||
|
|
||||||
|
if (in_err_statu)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
if(prev)
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "Combine partial packet with length %u and %u ...\n", prev->get_rest(), data->get_rest());
|
||||||
|
*prev += *data;
|
||||||
|
data->release();
|
||||||
|
data = prev;
|
||||||
|
prev = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
packet_data_base_ptr pack_data = nullptr;
|
||||||
|
data_source_ptr ds = nullptr;
|
||||||
|
bool notify_reply_ok = false;
|
||||||
|
|
||||||
|
if(dh == nullptr)
|
||||||
|
{
|
||||||
|
if (data->get_rest() < sizeof(PACK_BASE))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pack = (LPPACK_BASE)data->ptr();
|
||||||
|
status_.task_cmd = pack->cmd;
|
||||||
|
status_.task_pack_id = pack->pack_id;
|
||||||
|
used = data->get_rest();
|
||||||
|
reply = handle_bulk_command(data, &used, &pack_data);
|
||||||
|
notify_reply_ok = used & (INT32_MAX + 1);
|
||||||
|
used &= INT32_MAX;
|
||||||
|
if(pack_data)
|
||||||
|
{
|
||||||
|
dh = dynamic_cast<data_holder_ptr>(pack_data);
|
||||||
|
if(!dh)
|
||||||
|
{
|
||||||
|
ds = dynamic_cast<data_source_ptr>(pack_data);
|
||||||
|
if(!ds)
|
||||||
|
pack_data->release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
total_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t len = data->get_rest();
|
||||||
|
int err = dh->put_data(data->ptr(), &len);
|
||||||
|
|
||||||
|
if(len < data->get_rest())
|
||||||
|
{
|
||||||
|
utils::to_log(LOG_LEVEL_WARNING, "Put partial data %u/%u! at +%08X with error %d\n", len, data->get_rest(), total_size, err);
|
||||||
|
}
|
||||||
|
total_size += len;
|
||||||
|
if(dh->is_complete() || err)
|
||||||
|
{
|
||||||
|
reply = dyn_mem::memory(sizeof(PACK_BASE));
|
||||||
|
pack = (LPPACK_BASE)reply->ptr();
|
||||||
|
BASE_PACKET_REPLY(*pack, dh->get_packet_command() + 1, dh->get_packet_id(), err);
|
||||||
|
reply->set_len(sizeof(PACK_BASE));
|
||||||
|
|
||||||
|
utils::to_log(LOG_LEVEL_ALL, "Finished receiving file with error(Max queue size is %u): %d, total size = 0x%x\n", max_que, err, total_size);
|
||||||
|
|
||||||
|
dh->release();
|
||||||
|
dh = nullptr;
|
||||||
|
}
|
||||||
|
used = len;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
in_err_statu = true;
|
||||||
|
restore_err_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// first reply the packet ...
|
||||||
|
if(reply)
|
||||||
|
{
|
||||||
|
// encrypt ...
|
||||||
|
dyn_mem_ptr enc = packet_encrypt(reply, enc_head_, enc_payload_, enc_data_);
|
||||||
|
if (enc)
|
||||||
|
{
|
||||||
|
reply->release();
|
||||||
|
reply = enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_bulk(dynamic_cast<data_source_ptr>(reply));
|
||||||
|
if(notify_reply_ok)
|
||||||
|
handle_bulk_command(data, nullptr, nullptr);
|
||||||
|
reply->release();
|
||||||
|
reply = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// second send appendix data ...
|
||||||
|
if (ds)
|
||||||
|
{
|
||||||
|
write_bulk(ds);
|
||||||
|
ds->release();
|
||||||
|
ds = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_.task_required_bytes = dh ? dh->get_required() : 0;
|
||||||
|
if(status_.task_required_bytes == 0)
|
||||||
|
status_.task_cmd = status_.task_pack_id = 0;
|
||||||
|
|
||||||
|
data->used(used);
|
||||||
|
}while(used && data->get_rest());
|
||||||
|
|
||||||
|
if(data->get_rest())
|
||||||
|
prev = data;
|
||||||
|
else
|
||||||
|
data->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(prev)
|
||||||
|
prev->release();
|
||||||
|
if (data)
|
||||||
|
data->release();
|
||||||
|
if (reply)
|
||||||
|
reply->release();
|
||||||
|
if (dh)
|
||||||
|
dh->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
int async_usb_gadget::stop(void)
|
||||||
|
{
|
||||||
|
run_ = false;
|
||||||
|
|
||||||
|
if(dev_)
|
||||||
|
{
|
||||||
|
dev_->pull_down();
|
||||||
|
dev_->close_device();
|
||||||
|
dev_->release();
|
||||||
|
dev_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int async_usb_gadget::write_bulk(data_source_ptr data)
|
||||||
|
{
|
||||||
|
int quel = 0;
|
||||||
|
|
||||||
|
data->add_ref();
|
||||||
|
quel = sent_que_.save(data, true);
|
||||||
|
|
||||||
|
return quel;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Objects IO
|
||||||
|
//
|
||||||
|
// created on 2023-03-10
|
||||||
|
|
||||||
|
#include <base/utils.h>
|
||||||
|
#include <base/packet.h>
|
||||||
|
#include <base/data.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
// callback proto
|
||||||
|
//
|
||||||
|
// parameters: usb_functionfs_event* - the function event ptr
|
||||||
|
//
|
||||||
|
// dyn_mem_ptr - the packet buffer, read-only
|
||||||
|
//
|
||||||
|
// uint32_t* - to return how many data in bytes the handler consumed
|
||||||
|
//
|
||||||
|
// normally, the value should be sizeof(PACK_BASE) + PACK_BASE::payload_len, i.e. the handler consume all data of an entire packet
|
||||||
|
//
|
||||||
|
// when invalid packet, suggest use the entire data
|
||||||
|
//
|
||||||
|
// packet_data_base_ptr* - return data_holder or data_source or nullptr
|
||||||
|
//
|
||||||
|
// data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file'
|
||||||
|
//
|
||||||
|
// data_source: the reply content may be a large data (a large file content)
|
||||||
|
//
|
||||||
|
// return value of all routines is the reply packet, nullptr if the packet need not reply
|
||||||
|
//
|
||||||
|
#define FUNCTION_PROTO_UNHANDLED_EP0 dyn_mem_ptr(struct usb_functionfs_event*)
|
||||||
|
|
||||||
|
|
||||||
|
class usb_device;
|
||||||
|
|
||||||
|
class async_usb_gadget : public refer
|
||||||
|
{
|
||||||
|
volatile bool run_ = true;
|
||||||
|
usb_device *dev_ = nullptr;
|
||||||
|
safe_thread threads_;
|
||||||
|
size_t unit_in_ = 0x200;
|
||||||
|
size_t unit_out_ = 0x200;
|
||||||
|
uint16_t buf_coef_ = 1;
|
||||||
|
MUTEX buf_coef_lock_;
|
||||||
|
|
||||||
|
uint32_t enc_head_;
|
||||||
|
uint32_t enc_payload_;
|
||||||
|
uint8_t enc_data_;
|
||||||
|
|
||||||
|
volatile EP0REPLYSTATUS status_;
|
||||||
|
safe_fifo<dyn_mem_ptr> cmd_que_;
|
||||||
|
safe_fifo<data_source_ptr> sent_que_;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EP0_STATUS_IDLE = 0,
|
||||||
|
EP0_STATUS_READ_DATA, // ep0_statu::data is rest data len
|
||||||
|
EP0_STATUS_READ_INVAL_DATA, // ep0_statu::data is rest data len
|
||||||
|
EP0_STATUS_HANDLE_CMD,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<FUNCTION_PROTO_COMMAND_HANDLE> handle_cmd_;
|
||||||
|
std::function<void(bool)> dev_connect_;
|
||||||
|
|
||||||
|
const char* ep0_status_desc(int ep0_status, char* unk_buf/*>= 40 bytes*/);
|
||||||
|
|
||||||
|
int wait_fd_event(int fd, int to_ms = -1);
|
||||||
|
uint16_t get_buf_coefficient(void);
|
||||||
|
void set_buf_coefficient(int coef);
|
||||||
|
|
||||||
|
dyn_mem_ptr handle_ctrl_message(dyn_mem_ptr data);
|
||||||
|
dyn_mem_ptr handle_ctrl_setup(dyn_mem_ptr data); // user command ...
|
||||||
|
int inner_write_bulk(int fd, data_source_ptr data, int* err = nullptr);
|
||||||
|
dyn_mem_ptr handle_bulk_command(dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* pkd);
|
||||||
|
|
||||||
|
void thread_read_ep0(void);
|
||||||
|
void thread_read_bulk(int fd);
|
||||||
|
void thread_write_bulk(int fd);
|
||||||
|
void thread_pump_task(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
async_usb_gadget(std::function<FUNCTION_PROTO_COMMAND_HANDLE> cmd_handler = std::function<FUNCTION_PROTO_COMMAND_HANDLE>()
|
||||||
|
, std::function<void(bool)> dev_conn = std::function<void(bool)>());
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~async_usb_gadget();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int stop(void);
|
||||||
|
int write_bulk(data_source_ptr data); // return sent-que length
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* CAMTP Responder
|
||||||
|
* Copyright (c) 2020 Holdtecs Technologies
|
||||||
|
*
|
||||||
|
* CAMTP Responder is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3.0 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* CAMTP Responder is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License version 3 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with CAMTP Responder; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file usbstring.h
|
||||||
|
* @brief USB strings - Function & structures declarations.
|
||||||
|
* @author ***
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INC_USBSTRING_H_
|
||||||
|
#define _INC_USBSTRING_H_
|
||||||
|
|
||||||
|
struct usb_string {
|
||||||
|
uint8_t id;
|
||||||
|
char *str;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usb_gadget_strings {
|
||||||
|
uint16_t language; /* 0x0409 for en-us */
|
||||||
|
struct usb_string *strings;
|
||||||
|
};
|
||||||
|
|
||||||
|
int usb_gadget_get_string (struct usb_gadget_strings *table, int id, uint8_t *buf);
|
||||||
|
int unicode2charstring(char * str, uint16_t * unicodestr, int maxstrsize);
|
||||||
|
int char2unicodestring(char * unicodestr, int index, int maxsize, char * str, int unicodestrsize);
|
||||||
|
#endif
|
|
@ -0,0 +1,10 @@
|
||||||
|
add_rules("mode.debug", "mode.release")
|
||||||
|
|
||||||
|
target("usb")
|
||||||
|
set_kind("static")
|
||||||
|
add_syslinks("pthread", "dl")
|
||||||
|
add_files("*.cpp", "../sdk/base/*.c*", "../sdk/imgprc/*.c*", "../sdk/json/*.c*", "../sdk/sane_opt_json/*.c*")
|
||||||
|
add_includedirs("../sdk")
|
||||||
|
add_includedirs(".", { public = true})
|
||||||
|
add_packages("sdk")
|
||||||
|
-- add_deps("regs", "gimgproc", "applog", "capimage")
|
|
@ -0,0 +1,73 @@
|
||||||
|
set_project("GXX")
|
||||||
|
|
||||||
|
-- option("device")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default("g100")
|
||||||
|
-- set_values("g100", "g200", "g300", "g400")
|
||||||
|
-- set_category("device")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
-- option("chip")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default("rk3399")
|
||||||
|
-- set_values("rk3288", "rk3399")
|
||||||
|
-- set_category("chip")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
-- option("isp1")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default(true)
|
||||||
|
-- set_category("isp")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
-- option("testdemo")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default(true)
|
||||||
|
-- set_category("testdemo")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
-- option("testfpga")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default(true)
|
||||||
|
-- set_category("regs test")
|
||||||
|
-- set_configvar("TEST_FPGA", "ON")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
-- option("loopdebug")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default(false)
|
||||||
|
-- set_category("regs test")
|
||||||
|
-- set_configvar("LOOP_DEBUG", "ON")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
-- option("unfixed")
|
||||||
|
-- set_showmenu(true)
|
||||||
|
-- set_default(false )
|
||||||
|
-- set_configvar("CAP_UNFIXED", "ON")
|
||||||
|
-- option_end()
|
||||||
|
|
||||||
|
add_packagedirs("sdk")
|
||||||
|
-- -- if is_mode("debug") then
|
||||||
|
-- -- add_defines("DEBUG")
|
||||||
|
-- -- end
|
||||||
|
|
||||||
|
-- set_configvar("MOTOR_UART", get_config("chip") == "rk3288" and "/dev/ttyS3" or "/dev/ttyS4")
|
||||||
|
-- set_configvar("FPGA_UART", "/dev/ttyUSB0")
|
||||||
|
-- -- set_configvar("FPGA_UART", get_config("chip") == "rk3288" and "/dev/ttyS3" or "/dev/ttyS4")
|
||||||
|
-- -- set_configvar("MOTOR_UART", "/dev/ttyUSB0")
|
||||||
|
-- set_configvar("VIDEO_CLASS", has_config("isp1") and "GVideoISP1" or "gVideo")
|
||||||
|
|
||||||
|
target("conf")
|
||||||
|
set_kind("phony")
|
||||||
|
add_options("usb_isp1", "chip_type", "unfixed", "testfpga", "loopdebug")
|
||||||
|
set_configdir("$(buildir)/config")
|
||||||
|
add_configfiles("config.h.in", {prefixdir = "header"})
|
||||||
|
add_includedirs("$(buildir)/config/header", { public = true })
|
||||||
|
|
||||||
|
includes("usb", "scanner")
|
||||||
|
|
||||||
|
-- includes("regs", "deviceio", "motorboard", "capimage", "usb", "service", "scanner", "imgproc", "applog","scanservice","fpgaupdate","motorcontroller","display","testlcd","keymonitor","testkeymonitor","testdisplay","testwakeup")
|
||||||
|
|
||||||
|
-- if has_config("testdemo") then
|
||||||
|
-- includes("testmotorboard", "testcapimage", "testusb", "testscanner", "testimgproc", "testregs","testwakeup")
|
||||||
|
-- end
|
Loading…
Reference in New Issue