code_device/hgsane/sane_hg_mdw.cpp

2522 lines
79 KiB
C++

#include "sane_hg_mdw.h"
#include "json.h"
#include <stdarg.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef WIN32
#include <windows.h>
#include <direct.h>
#define pthread_t DWORD
#define pthread_self GetCurrentThreadId
#define MKDIR(a, b) mkdir(a)
#else
#define MKDIR(a, b) mkdir(a, b)
#include <pthread.h>
#endif
#include "../sdk/hginclude/hg_log.h"
#include "ini_file.h"
#ifndef VERSION_BUILD
#define VERSION_BUILD 22030
#endif
#ifndef SIGUSR1
#define SIGUSR1 10
#endif
// copy to /usr/lib/x86_64-linux-gnu/sane
// export SANE_DEBUG_DLL=5
#ifndef iconv_t
#define iconv_t void*
#endif
#ifdef RUN_TEST
std::string jsontext("{\"device_type\":\"G100\",\"option_count\":51,\"1\":{\"category\":\"base\",\"name\":\"cfg-1\",\"title\":\"\\u6062\\u590d\\u9ed8\\u8ba4\\u8bbe\\u7f6e\",\"desc\":\"\\u6062\\u590d\\u9ed8\\u8ba4\\u8bbe\\u7f6e\",\"type\":\"button\",\"cur\":\"button\",\"default\":\"button\",\"size\":0},\"2\":{\"category\":\"advanced\",\"name\":\"cfg-2\",\"title\":\"\\u5e2e\\u52a9\",\"desc\":\"\\u663e\\u793a\\u8f6f\\u4ef6\\u5e2e\\u52a9\\u6587\\u6863\",\"type\":\"button\",\"cur\":\"true\",\"default\":\"true\",\"size\":4},\"3\":{\"category\":\"base\",\"name\":\"grp-1\",\"title\":\"\\u57fa\\u672c\\u8bbe\\u7f6e\",\"type\":\"group\"},\"4\":{\"category\":\"base\",\"name\":\"cfg-4\",\"title\":\"\\u989c\\u8272\\u6a21\\u5f0f\",\"desc\":\"\\u8bbe\\u7f6e\\u989c\\u8272\\u4f4d\\u6df1\",\"type\":\"string\",\"cur\":\"24\\u4f4d\\u5f69\\u8272\",\"default\":\"24\\u4f4d\\u5f69\\u8272\",\"size\":24,\"range\":[\"24\\u4f4d\\u5f69\\u8272\",\"256\\u7ea7\\u7070\\u5ea6\",\"\\u9ed1\\u767d\",\"\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"5\":{\"category\":\"base\",\"name\":\"cfg-5\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf-\\u591a\\u6d41\\u8f93\\u51fa\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u4e0d\\u9009\\u62e9\\u8f93\\u51fa\\u6a21\\u5f0f\",\"default\":\"\\u4e0d\\u9009\\u62e9\\u8f93\\u51fa\\u6a21\\u5f0f\",\"size\":28,\"range\":[\"\\u4e0d\\u9009\\u62e9\\u8f93\\u51fa\\u6a21\\u5f0f\",\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"\\u5f69\\u8272+\\u7070\\u5ea6\",\"\\u5f69\\u8272+\\u9ed1\\u767d\",\"\\u7070\\u5ea6+\\u9ed1\\u767d\"],\"depend_or\":[\"4==24\\u4f4d\\u5f69\\u8272\"]},\"6\":{\"category\":\"base\",\"name\":\"cfg-6\",\"title\":\"\\u7070\\u5ea6\\u6216\\u9ed1\\u767d\\u56fe\\u50cf - \\u9664\\u8272\",\"desc\":\"\\u9664\\u53bb\\u56fe\\u50cf\\u5f69\\u8272\",\"type\":\"string\",\"cur\":\"\\u4e0d\\u9664\\u8272\",\"default\":\"\\u4e0d\\u9664\\u8272\",\"size\":20,\"range\":[\"\\u4e0d\\u9664\\u8272\",\"\\u9664\\u7ea2\\u8272\",\"\\u9664\\u7eff\\u8272\",\"\\u9664\\u84dd\\u8272\",\"\\u7ea2\\u8272\\u589e\\u5f3a\",\"\\u7eff\\u8272\\u589e\\u5f3a\",\"\\u84dd\\u8272\\u589e\\u5f3a\"],\"depend_or\":[\"4==256\\u7ea7\\u7070\\u5ea6\",\"4==\\u9ed1\\u767d\"]},\"7\":{\"category\":\"base\",\"name\":\"cfg-7\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u591a\\u6d41\\u8f93\\u51fa\\u9664\\u7ea2\",\"desc\":\"\\u591a\\u901a\\u9053\\u8f93\\u51fa\\u4e2d\\uff0c\\u53bb\\u9664\\u7ea2\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"4==24\\u4f4d\\u5f69\\u8272\"]},\"8\":{\"category\":\"base\",\"name\":\"cfg-8\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u7b54\\u9898\\u5361\\u9664\\u7ea2\",\"desc\":\"\\u7b54\\u9898\\u5361\\u626b\\u63cf\\u4e2d\\u53bb\\u9664\\u7ea2\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"4==24\\u4f4d\\u5f69\\u8272\"]},\"9\":{\"category\":\"base\",\"name\":\"cfg-9\",\"title\":\"\\u80cc\\u666f\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u5f69\\u8272\\u56fe\\u50cf\\u80cc\\u666f\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"4==24\\u4f4d\\u5f69\\u8272\"]},\"10\":{\"category\":\"base\",\"name\":\"cfg-10\",\"title\":\" \\u80cc\\u666f\\u8272\\u5f69\\u6d6e\\u52a8\\u8303\\u56f4\",\"desc\":\"\\u8bbe\\u5b9a\\u80cc\\u666f\\u8272\\u5f69\\u7684\\u6d6e\\u52a8\\u8303\\u56f4\\uff0c\\u5728\\u8be5\\u8303\\u56f4\\u5185\\u7684\\u90fd\\u5f53\\u4f5c\\u80cc\\u666f\\u79fb\\u9664\",\"type\":\"int\",\"cur\":10,\"default\":10,\"size\":4,\"range\":{\"min\":1,\"max\":40},\"depend_or\":[\"9==true\"]},\"11\":{\"category\":\"base\",\"name\":\"cfg-11\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u566a\\u70b9\\u4f18\\u5316\",\"desc\":\"\\u566a\\u70b9\\u4f18\\u5316\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"4==\\u9ed1\\u767d\"]},\"12\":{\"category\":\"base\",\"name\":\"cfg-12\",\"title\":\" \\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"desc\":\"\\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"type\":\"int\",\"cur\":30,\"default\":30,\"size\":4,\"range\":{\"min\":10,\"max\":50},\"depend_or\":[\"11==true\"]},\"13\":{\"category\":\"base\",\"name\":\"cfg-13\",\"title\":\"\\u7eb8\\u5f20\\u5c3a\\u5bf8\",\"desc\":\"\\u8bbe\\u7f6e\\u7eb8\\u5f20\\u5927\\u5c0f\",\"type\":\"string\",\"cur\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"default\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"size\":44,\"range\":[\"A3\",\"8\\u5f00\",\"A4\",\"A4\\u6a2a\\u5411\",\"16\\u5f00\",\"16\\u5f00\\u6a2a\\u5411\",\"A5\",\"A5\\u6a2a\\u5411\",\"A6\",\"A6\\u6a2a\\u5411\",\"B4\",\"B5\",\"B5\\u6a2a\\u5411\",\"B6\",\"B6\\u6a2a\\u5411\",\"Letter\",\"Letter\\u6a2a\\u5411\",\"Double Letter\",\"LEGAL\",\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"\\u4e09\\u8054\\u8bd5\\u5377\"]},\"14\":{\"category\":\"base\",\"name\":\"cfg-14\",\"title\":\"\\u5c3a\\u5bf8\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u5b9e\\u9645\\u5c3a\\u5bf8\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"13==A3\",\"13==A4\",\"13==A4\\u6a2a\\u5411\",\"13==A5\",\"13==A5\\u6a2a\\u5411\",\"13==A6\",\"13==A6\\u6a2a\\u5411\",\"13==B4\",\"13==B5\",\"13==B5\\u6a2a\\u5411\",\"13==B6\",\"13==B6\\u6a2a\\u5411\",\"13==Double Letter\",\"13==LEGAL\",\"13==Letter\",\"13==Letter\\u6a2a\\u5411\"]},\"15\":{\"category\":\"base\",\"name\":\"cfg-15\",\"title\":\"\\u626b\\u63cf\\u9875\\u9762\",\"desc\":\"\\u8bbe\\u7f6e\\u9875\\u9762\\u626b\\u63cf\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u53cc\\u9762\",\"default\":\"\\u53cc\\u9762\",\"size\":40,\"range\":[\"\\u5355\\u9762\",\"\\u53cc\\u9762\",\"\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\",\"\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\",\"\\u5bf9\\u6298\"]},\"16\":{\"category\":\"base\",\"name\":\"cfg-16\",\"title\":\" \\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\u7075\\u654f\\u5ea6\",\"desc\":\"\\u7075\\u654f\\u5ea6\\u8d8a\\u9ad8\\uff0c\\u5219\\u8d8a\\u5bb9\\u6613\\u8df3\\u8fc7\",\"type\":\"int\",\"cur\":50,\"default\":50,\"size\":4,\"range\":{\"min\":1,\"max\":100},\"depend_or\":[\"15==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\",\"15==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\"]},\"17\":{\"category\":\"base\",\"name\":\"cfg-17\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u626b\\u63cf\\u4eea\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":{\"min\":100,\"max\":300}},\"18\":{\"category\":\"base\",\"name\":\"cfg-18\",\"title\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"desc\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"15!=\\u5355\\u9762\"]},\"19\":{\"category\":\"base\",\"name\":\"cfg-19\",\"title\":\"\\u56fe\\u50cf\\u62c6\\u5206\",\"desc\":\"\\u81ea\\u52a8\\u62c6\\u5206\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"15!=\\u5bf9\\u6298\"]},\"20\":{\"category\":\"base\",\"name\":\"cfg-20\",\"title\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"desc\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4,\"depend_or\":[\"15!=\\u5bf9\\u6298\"]},\"21\":{\"category\":\"base\",\"name\":\"cfg-21\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u7eb8\\u5f20\\u4e2d\\u7684\\u7a7f\\u5b54\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"22\":{\"category\":\"base\",\"name\":\"cfg-22\",\"title\":\" \\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":0.500000},\"depend_or\":[\"21==true\"]},\"23\":{\"category\":\"base\",\"name\":\"grp-2\",\"title\":\"\\u4eae\\u5ea6\",\"type\":\"group\"},\"24\":{\"category\":\"base\",\"name\":\"cfg-24\",\"title\":\"\\u4eae\\u5ea6\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u4eae\\u5ea6\",\"type\":\"int\",\"cur\":128,\"default\":128,\"size\":4,\"range\":{\"min\":1,\"max\":255}},\"25\":{\"category\":\"base\",\"name\":\"cfg-25\",\"title\":\"\\u5bf9\\u6bd4\\u5ea6\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u5bf9\\u6bd4\\u5ea6\",\"type\":\"int\",\"cur\":4,\"default\":4,\"size\":4,\"range\":{\"min\":1,\"max\":7}},\"26\":{\"category\":\"base\",\"name\":\"cfg-26\",\"title\":\"\\u4f3d\\u739b\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u4f3d\\u739b\\u503c\",\"type\":\"float\",\"cur\":1.000000,\"default\":1.000000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":5.000000}},\"27\":{\"category\":\"base\",\"name\":\"grp-3\",\"title\":\"\\u56fe\\u50cf\\u5904\\u7406\",\"type\":\"group\"},\"28\":{\"category\":\"base\",\"name\":\"cfg-28\",\"title\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"desc\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"type\":\"string\",\"cur\":\"\\u65e0\",\"default\":\"\\u65e0\",\"size\":20,\"range\":[\"\\u65e0\",\"\\u9510\\u5316\",\"\\u8fdb\\u4e00\\u6b65\\u9510\\u5316\",\"\\u6a21\\u7cca\",\"\\u8fdb\\u4e00\\u6b65\\u6a21\\u7cca\"]},\"29\":{\"category\":\"base\",\"name\":\"cfg-29\",\"title\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"desc\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"30\":{\"category\":\"base\",\"name\":\"cfg-30\",\"title\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"desc\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"15!=\\u5bf9\\u6298\",\"29!=true\",\"13!=\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"13!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"13!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"20!=true\"]},\"31\":{\"category\":\"advanced\",\"name\":\"cfg-31\",\"title\":\"\\u9608\\u503c\",\"desc\":\"\\u9608\\u503c\",\"type\":\"int\",\"cur\":40,\"default\":40,\"size\":4,\"range\":{\"min\":30,\"max\":50},\"depend_or\":[\"29==true\",\"13==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"13==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"13==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"20==true\"]},\"32\":{\"category\":\"advanced\",\"name\":\"cfg-32\",\"title\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"desc\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"type\":\"int\",\"cur\":8,\"default\":8,\"size\":4,\"range\":{\"min\":1,\"max\":20},\"depend_or\":[\"29==true\",\"13==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"13==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"13==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"20==true\"]},\"33\":{\"category\":\"advanced\",\"name\":\"cfg-33\",\"title\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"desc\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"type\":\"int\",\"cur\":5,\"default\":5,\"size\":4,\"range\":{\"min\":5,\"max\":30},\"depend_or\":[\"29==true\",\"13==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"13==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"20==true\",\"13==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\"]},\"34\":{\"category\":\"advanced\",\"name\":\"cfg-34\",\"title\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"desc\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"default\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"size\":40,\"range\":[\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"\\u51f9\\u591a\\u8fb9\\u5f62\"],\"depend_or\":[\"29==true\"]},\"35\":{\"category\":\"base\",\"name\":\"cfg-35\",\"title\":\"\\u9632\\u6b62\\u6e17\\u900f\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"36\":{\"category\":\"base\",\"name\":\"cfg-36\",\"title\":\" \\u9632\\u6b62\\u6e17\\u900f\\u7b49\\u7ea7\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u8f83\\u5f31\",\"default\":\"\\u8f83\\u5f31\",\"size\":12,\"range\":[\"\\u8f83\\u5f31\",\"\\u5f31\",\"\\u4e00\\u822c\",\"\\u5f3a\",\"\\u8f83\\u5f3a\"],\"depend_or\":[\"35==true\"]},\"37\":{\"category\":\"base\",\"name\":\"cfg-37\",\"title\":\"\\u53bb\\u9664\\u6469\\u5c14\\u7eb9\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"38\":{\"category\":\"base\",\"name\":\"cfg-38\",\"title\":\"\\u9519\\u8bef\\u6269\\u6563\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"39\":{\"category\":\"base\",\"name\":\"cfg-39\",\"title\":\"\\u9664\\u7f51\\u7eb9\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"40\":{\"category\":\"base\",\"name\":\"grp-4\",\"title\":\"\\u9001\\u7eb8\\u65b9\\u5f0f\\u8bbe\\u7f6e\",\"type\":\"group\"},\"41\":{\"category\":\"base\",\"name\":\"cfg-41\",\"title\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\",\"desc\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\\u9001\\u7eb8\\u72b6\\u6001\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"42\":{\"category\":\"base\",\"name\":\"cfg-42\",\"title\":\"\\u88c5\\u8ba2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u4e0a\\u662f\\u5426\\u6709\\u9489\\u4e66\\u9489\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"43\":{\"category\":\"base\",\"name\":\"cfg-43\",\"title\":\"\\u626b\\u63cf\\u5f20\\u6570\",\"desc\":\"\\u626b\\u63cf\\u7eb8\\u5f20\\u6570\\u91cf\",\"type\":\"string\",\"cur\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"default\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"size\":24,\"range\":[\"\\u8fde\\u7eed\\u626b\\u63cf\",\"\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"44\":{\"category\":\"base\",\"name\":\"cfg-44\",\"title\":\" \\u626b\\u63cf\\u6570\\u91cf\",\"desc\":\"\\u626b\\u63cf\\u6307\\u5b9a\\u6570\\u91cf\",\"type\":\"int\",\"cur\":1,\"default\":1,\"size\":4,\"depend_or\":[\"43==\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"45\":{\"category\":\"base\",\"name\":\"cfg-45\",\"title\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"desc\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"type\":\"string\",\"cur\":\"0\\u00b0\",\"default\":\"0\\u00b0\",\"size\":40,\"range\":[\"0\\u00b0\",\"90\\u00b0\",\"180\\u00b0\",\"-90\\u00b0\",\"\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b\\u00b0\"]},\"46\":{\"category\":\"base\",\"name\":\"cfg-46\",\"title\":\"\\u80cc\\u9762\\u65cb\\u8f6c180\\u00b0\",\"desc\":\"\\u80cc\\u9762\\u626b\\u63cf\\u7684\\u56fe\\u50cf\\u65cb\\u8f6c180\\u00b0\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"15!=\\u5355\\u9762\",\"15!=\\u5bf9\\u6298\",\"45!=\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b\\u00b0\"]},\"47\":{\"category\":\"base\",\"name\":\"cfg-47\",\"title\":\"\\u6298\\u89d2\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6298\\u89d2\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"48\":{\"category\":\"base\",\"name\":\"cfg-48\",\"title\":\" \\u6298\\u89d2\\u68c0\\u6d4b\\u590d\\u6742\\u5ea6\",\"desc\":\"\\u7eb8\\u5f20\\u6298\\u89d2\\u68c0\\u6d4b\\u590d\\u6742\\u5ea6\",\"type\":\"int\",\"cur\":10,\"default\":10,\"size\":4,\"range\":{\"min\":0,\"max\":100},\"depend_or\":[\"47==true\"]},\"49\":{\"category\":\"base\",\"name\":\"cfg-49\",\"title\":\"\\u6b6a\\u659c\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6b6a\\u659c\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"50\":{\"category\":\"base\",\"name\":\"cfg-50\",\"title\":\" \\u6b6a\\u659c\\u68c0\\u6d4b\\u590d\\u6742\\u5ea6\",\"desc\":\"\\u7eb8\\u5f20\\u6b6a\\u659c\\u68c0\\u6d4b\\u590d\\u6742\\u5ea6\",\"type\":\"int\",\"cur\":3,\"default\":3,\"size\":4,\"range\":{\"min\":1,\"max\":5},\"depend_or\":[\"49==true\"]}}");
#endif
namespace local_utility
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static char g_unk_err[80] = { 0 };
SANE_Status hg_err_2_sane_statu(int hgerr)
{
#define RETURN_MATCH_ERROR(hg, sane) \
if(hgerr == hg) \
return sane;
RETURN_MATCH_ERROR(HG_ERR_OK, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(HG_ERR_INVALID_PARAMETER, SANE_STATUS_INVAL);
RETURN_MATCH_ERROR(HG_ERR_INSUFFICIENT_MEMORY, SANE_STATUS_NO_MEM);
RETURN_MATCH_ERROR(HG_ERR_ACCESS_DENIED, SANE_STATUS_ACCESS_DENIED);
RETURN_MATCH_ERROR(HG_ERR_IO_PENDING, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(HG_ERR_NOT_EXACT, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(HG_ERR_CONFIGURATION_CHANGED, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(HG_ERR_NOT_OPEN, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(HG_ERR_NOT_START, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(HG_ERR_NO_DATA, SANE_STATUS_EOF);
RETURN_MATCH_ERROR(HG_ERR_HAS_DATA_YET, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(HG_ERR_OUT_OF_RANGE, SANE_STATUS_NO_MEM);
RETURN_MATCH_ERROR(HG_ERR_IO, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(HG_ERR_TIMEOUT, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(HG_ERR_DEVICE_NOT_FOUND, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(HG_ERR_DEVICE_NOT_SUPPORT, SANE_STATUS_UNSUPPORTED);
RETURN_MATCH_ERROR(HG_ERR_DEVICE_BUSY, SANE_STATUS_DEVICE_BUSY);
RETURN_MATCH_ERROR(HG_ERR_DEVICE_COVER_OPENNED, SANE_STATUS_COVER_OPEN);
RETURN_MATCH_ERROR(HG_ERR_DEVICE_NO_PAPER, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(HG_ERR_DEVICE_PAPER_JAMMED, SANE_STATUS_JAMMED);
return (SANE_Status)hgerr;
}
const char* error_text(SANE_Status statu)
{
RETURN_IF(statu, SANE_STATUS_GOOD);
RETURN_IF(statu, SANE_STATUS_UNSUPPORTED);
RETURN_IF(statu, SANE_STATUS_CANCELLED);
RETURN_IF(statu, SANE_STATUS_DEVICE_BUSY);
RETURN_IF(statu, SANE_STATUS_INVAL);
RETURN_IF(statu, SANE_STATUS_EOF);
RETURN_IF(statu, SANE_STATUS_JAMMED);
RETURN_IF(statu, SANE_STATUS_NO_DOCS);
RETURN_IF(statu, SANE_STATUS_COVER_OPEN);
RETURN_IF(statu, SANE_STATUS_IO_ERROR);
RETURN_IF(statu, SANE_STATUS_NO_MEM);
RETURN_IF(statu, SANE_STATUS_ACCESS_DENIED);
RETURN_IF(statu, HG_ERR_INVALID_PARAMETER);
RETURN_IF(statu, HG_ERR_USER_CANCELED);
RETURN_IF(statu, HG_ERR_INSUFFICIENT_MEMORY);
RETURN_IF(statu, HG_ERR_ACCESS_DENIED);
RETURN_IF(statu, HG_ERR_IO_PENDING);
RETURN_IF(statu, HG_ERR_NOT_EXACT);
RETURN_IF(statu, HG_ERR_CONFIGURATION_CHANGED);
RETURN_IF(statu, HG_ERR_NOT_OPEN);
RETURN_IF(statu, HG_ERR_NOT_START);
RETURN_IF(statu, HG_ERR_NOT_ANY_MORE);
RETURN_IF(statu, HG_ERR_NO_DATA);
RETURN_IF(statu, HG_ERR_HAS_DATA_YET);
RETURN_IF(statu, HG_ERR_OUT_OF_RANGE);
RETURN_IF(statu, HG_ERR_IO);
RETURN_IF(statu, HG_ERR_TIMEOUT);
RETURN_IF(statu, HG_ERR_OPEN_FILE_FAILED);
RETURN_IF(statu, HG_ERR_CREATE_FILE_FAILED);
RETURN_IF(statu, HG_ERR_WRITE_FILE_FAILED);
RETURN_IF(statu, HG_ERR_DATA_DAMAGED);
RETURN_IF(statu, HG_ERR_USB_INIT_FAILED);
RETURN_IF(statu, HG_ERR_USB_REGISTER_PNP_FAILED);
RETURN_IF(statu, HG_ERR_USB_CLAIM_INTERFACE_FAILED);
RETURN_IF(statu, HG_ERR_DEVICE_NOT_FOUND);
RETURN_IF(statu, HG_ERR_DEVICE_NOT_SUPPORT);
RETURN_IF(statu, HG_ERR_DEVICE_BUSY);
RETURN_IF(statu, HG_ERR_DEVICE_SLEEPING);
RETURN_IF(statu, HG_ERR_DEVICE_COUNT_MODE);
RETURN_IF(statu, HG_ERR_DEVICE_STOPPED);
RETURN_IF(statu, HG_ERR_DEVICE_COVER_OPENNED);
RETURN_IF(statu, HG_ERR_DEVICE_NO_PAPER);
RETURN_IF(statu, HG_ERR_DEVICE_FEEDING_PAPER);
RETURN_IF(statu, HG_ERR_DEVICE_DOUBLE_FEEDING);
RETURN_IF(statu, HG_ERR_DEVICE_PAPER_JAMMED);
RETURN_IF(statu, HG_ERR_DEVICE_STAPLE_ON);
RETURN_IF(statu, HG_ERR_DEVICE_PAPER_SKEW);
RETURN_IF(statu, HG_ERR_DEVICE_SIZE_CHECK);
RETURN_IF(statu, HG_ERR_DEVICE_DOGEAR);
RETURN_IF(statu, HG_ERR_DEVICE_NO_IMAGE);
RETURN_IF(statu, HG_ERR_DEVICE_SCANN_ERROR);
RETURN_IF(statu, HG_ERR_DEVICE_PC_BUSY);
sprintf(g_unk_err, "\346\234\252\347\237\245\351\224\231\350\257\257\357\274\232%X", statu);
return g_unk_err;
}
void* acquire_memory(size_t bytes, const char* info)
{
//if (!info)
// info = "";
//hg_sane_middleware::log(strlen(info) + 80, "allocate memory with %u bytes from %s\n", bytes, info);
return malloc(bytes);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static iconv_t iconv_au8 = NULL;
static iconv_t iconv_u8a = NULL;
#ifndef WIN32
static std::string convert(iconv_t h, const void* in, size_t bytes)
{
std::string ret("");
if (h)
{
size_t rest = bytes, buf_size = bytes * 2, err = 0, out = buf_size - 1;
char* buf = (char*)local_utility::acquire_memory(buf_size, "local_utility::convert"), * src = (char*)in, * cur = buf;
bzero(buf, buf_size);
err = iconv(h, (char**)&src, &rest, &cur, &out);
while (err == 0 && rest)
{
if (buf_size / bytes > 8)
break;
free(buf);
buf_size += bytes;
buf = (char*)local_utility::acquire_memory(buf_size, "local_utility::convert");
bzero(buf, buf_size);
out = buf_size - 1;
rest = bytes;
src = (char*)in;
cur = buf;
err = iconv(h, (char**)&src, &rest, &cur, &out);
}
if (err == 0)
ret = std::string(buf, buf_size - 1 - out);
free(buf);
}
return ret;
}
#endif
bool char_transfer_init(void)
{
#ifdef RUN_TEST
FILE* src = fopen("/tmp/hg_g100.txt", "rb");
bool found = false;
if (src)
{
long len = 0;
char* buf = NULL;
fseek(src, 0, SEEK_END);
len = ftell(src);
fseek(src, 0, SEEK_SET);
buf = (char*)malloc(len + 4);
bzero(buf, len + 4);
fread(buf, 1, len, src);
fclose(src);
// try parse ...
json* j = new json();
if (j->attach_text(buf))
{
jsontext = buf;
found = true;
}
delete j;
free(buf);
}
if (found)
hg_log::log(HG_LOG_LEVEL_DEBUG_INFO, "Testing configuration loaded from /tmp/hg_g100.txt ^_^\n");
else
hg_log::log(HG_LOG_LEVEL_DEBUG_INFO, "'/tmp/hg_g100.txt' is not found or data damaged. :(\n");
#endif
#ifndef WIN32
if (!iconv_au8)
{
iconv_au8 = iconv_open("gb2312", "utf-8");
if (iconv_au8 == (iconv_t)-1)
{
iconv_au8 = NULL;
return false;
}
}
if (!iconv_u8a)
{
iconv_u8a = iconv_open("utf-8", "gb2312");
if (iconv_u8a == (iconv_t)-1)
{
iconv_u8a = NULL;
return false;
}
}
#endif
return true;
}
std::string utf8_2_ansi(const char* utf8)
{
return utf8;
if (!iconv_u8a || !utf8 || *utf8 == 0)
return "";
#ifdef WIN32
return utf8;
#else
return convert(iconv_u8a, utf8, strlen(utf8));
#endif
}
std::string ansi_2_utf8(const char* ansi)
{
if (!iconv_au8 || !ansi || *ansi == 0)
return "";
#ifdef WIN32
return ansi;
#else
return ansi;
return convert(iconv_au8, ansi, strlen(ansi));
#endif
}
void char_transfer_uninit(void)
{
#ifndef WIN32
if (iconv_au8)
{
iconv_close(iconv_au8);
iconv_au8 = NULL;
}
if (iconv_u8a)
{
iconv_close(iconv_u8a);
iconv_u8a = NULL;
}
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool is_space(char ch)
{
return ch == ' ' || ch == '\t';
}
bool is_digital(char ch)
{
return ch >= '0' && ch <= '9';
}
bool is_hex_num(char ch)
{
if (is_digital(ch))
return true;
return (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
}
bool to_num(char ch, int& v, bool hex)
{
if (is_digital(ch))
{
v = ch - '0';
return true;
}
if (hex)
{
if (ch >= 'a' && ch <= 'f')
{
v = ch - 'a' + 10;
}
else if (ch >= 'A' && ch <= 'F')
{
v = ch - 'A' + 10;
}
else
{
hex = false;
}
}
return hex;
}
bool skip_space(const char*& str)
{
const char* bgn = str;
while (is_space(*str))
str++;
return str > bgn;
}
// 暂不支持科学计数法 1.2e+10
bool get_number(const char*& str, double& val)
{
const char* bgn = str;
double val_race = 10.0f,
val_sign = 1.0f,
digit_race = 1.0f,
digit_race_race = 1.0f;
val = .0f;
if (*str == '-')
{
str++;
val_sign = -1.0f;
}
if (*str == '.')
{
str++;
digit_race = digit_race_race = .1f;
val_race = 1.0f;
}
bgn = str;
while (*str && is_digital(*str))
{
int v = 0;
val *= val_race;
to_num(*str++, v, false);
val += v * digit_race;
digit_race *= digit_race_race;
}
if (*str == '.')
{
if (digit_race_race < 1.0f)
return false;
digit_race = digit_race_race = .1f;
val_race = 1.0f;
while (*str && is_digital(*str))
{
int v = 0;
val *= val_race;
to_num(*str++, v, false);
val += v * digit_race;
digit_race *= digit_race_race;
}
}
return str > bgn;
}
bool get_limit(const char*& str, std::string& l, std::string& r)
{
// set l = "a", r = "b" in text "[a, b]"
bool ret = *str == '[';
if (ret)
{
str++;
skip_space(str);
l = str;
size_t pos = l.find("]");
if (pos == -1)
return false;
l.erase(pos);
pos = l.find(",");
if (pos == -1)
return false;
r = l.substr(pos + 1);
l.erase(pos);
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void init_log(void)
{
std::string path(hg_log::pe_path()),
val("");
simple_ini ini;
bool given_path = false;
hg_log_type logt = HG_LOG_TYPE_FILE;
hg_log_level logl = HG_LOG_LEVEL_ALL;
hg_log::init(HG_LOG_TYPE_CONSOLE, HG_LOG_LEVEL_DEBUG_INFO);
HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "current path: '%s'\n", path.c_str());
if (path.empty())
path = simple_ini::temporary_path();
// pwd/hgsane.conf
//
// [log]
// type=console // or none or other as file
// level=debug // or warning or fatal or other as all
//
if (ini.load((path + "/configs/scanner.conf").c_str()) == 0)
{
val = ini.get("log", "type");
if (stricmp(val.c_str(), "console") == 0)
logt = HG_LOG_TYPE_CONSOLE;
else if (stricmp(val.c_str(), "none") == 0)
logt = HG_LOG_TYPE_NONE;
if (logt == HG_LOG_TYPE_FILE)
{
val = ini.get("log", "file");
if (!val.empty())
{
path = val;
given_path = true;
}
}
val = ini.get("log", "level");
if (stricmp(val.c_str(), "debug") == 0)
logl = HG_LOG_LEVEL_DEBUG_INFO;
else if (stricmp(val.c_str(), "warning") == 0)
logl = HG_LOG_LEVEL_WARNING;
else if (stricmp(val.c_str(), "fatal") == 0)
logl = HG_LOG_LEVEL_FATAL;
}
if (logt == HG_LOG_TYPE_FILE && !given_path)
{
std::string child("/scanner_log");
path += child;
if (MKDIR(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST)
{
path += "/log.txt";
}
else
{
HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "create folder '%s' failed(%d), now try temporary directory\n", path.c_str(), errno);
path = simple_ini::temporary_path() + child;
if (MKDIR(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST)
path += "/log.txt";
else
{
HG_VLOG_MINI_2(HG_LOG_LEVEL_DEBUG_INFO, "create temporary directory '%s' failed(%d), log to console\n", path.c_str(), errno);
logt = HG_LOG_TYPE_CONSOLE;
logl = HG_LOG_LEVEL_WARNING;
}
}
}
hg_log::init(logt, logl, &path[0]);
path = hg_log::current_time() + " hgsane is starting ...\n";
hg_log::log(HG_LOG_LEVEL_FATAL, path.c_str());
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static sane_callback cb_ui_ = NULL;
static void* cb_ui_parm_ = NULL;
static SANE_Auth_Callback cb_auth_ = NULL;
static std::string sane_event(SANE_Event ev)
{
RETURN_IF(ev, SANE_EVENT_NONE);
RETURN_IF(ev, SANE_EVENT_SUPPORT_ASYNC_IO);
RETURN_IF(ev, SANE_EVENT_IS_MEMORY_ENOUGH);
RETURN_IF(ev, SANE_EVENT_NEED_AUTH);
RETURN_IF(ev, SANE_EVENT_DEVICE_ARRIVED);
RETURN_IF(ev, SANE_EVENT_DEVICE_LEFT);
RETURN_IF(ev, SANE_EVENT_STATUS);
RETURN_IF(ev, SANE_EVENT_ERROR);
RETURN_IF(ev, SANE_EVENT_WORKING);
RETURN_IF(ev, SANE_EVENT_IMAGE_OK);
RETURN_IF(ev, SANE_EVENT_SCAN_FINISHED);
RETURN_IF(ev, SANE_EVENT_ABOUT_INFORMATION);
RETURN_IF(ev, SANE_EVENT_SCANNER_CLOSED);
RETURN_IF(ev, SANE_EVENT_WIN_DEBUG_INFO);
char unk[20];
sprintf(unk, "%d", ev);
return unk;
}
int ui_cb(scanner_handle dev, int code, void* data, unsigned int* len, void* unused)
{
if (SANE_EVENT_SUPPORT_ASYNC_IO == code)
return cb_ui_ ? HG_ERR_OK : HG_ERR_DEVICE_NOT_SUPPORT;
if (code == SANE_EVENT_WIN_DEBUG_INFO)
{
hg_log::log((hg_log_level)*len, (char*)data);
return 0;
}
SANE_Handle h = hg_sane_middleware::scanner_handle_to_sane(dev);
HG_VLOG_MINI_1(HG_LOG_LEVEL_ALL, "sane callback invoked of event %s\n", sane_event((SANE_Event)code).c_str());
if (cb_ui_)
{
return cb_ui_(h, code, data, len, cb_ui_parm_);
}
else if (cb_auth_ && code == SANE_EVENT_NEED_AUTH)
{
SANEAUTH* auth = (SANEAUTH*)data;
cb_auth_(auth->resource, auth->name, auth->pwd);
}
return 0;
}
void ui_log_cb(hg_log_level level, const char* info)
{
}
void get_version(SANE_Int* version_code)
{
if (version_code)
*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, VERSION_BUILD); // leading-char '1' is used for avoid compiler considering '0118' as an octal number :)
long v = hg_scanner_get_version();
unsigned char* byt = (unsigned char*)&v;
HG_VLOG_MINI_4(HG_LOG_LEVEL_DEBUG_INFO, "Huagao scanner driver version: %u.%u.%u.%u\n", byt[3], byt[2], byt[1], byt[0]);
}
void stop_work(void)
{
cb_ui_ = NULL;
cb_ui_parm_ = NULL;
cb_auth_ = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// test
#ifdef RUN_TEST
#include <thread>
#ifdef TEST_DEV
#include "scanner_manager.h"
#endif
static json* jsn_inst = NULL;
static sane_callback g_cb = NULL;
void* g_param = NULL;
static unsigned int scan_count = -1;
static unsigned int scan_count_ = 1;
hg_err hg_scanner_initialize(sane_callback callback, void* param)
{
#ifdef TEST_DEV
hg_scanner_mgr::instance();
#else
jsn_inst = new json(&jsontext[0]);
#endif
g_cb = callback;
g_param = param;
return HG_ERR_OK;
}
void hg_scanner_uninitialize(void)
{
}
long hg_scanner_get_version(void)
{
return SANE_VERSION_CODE(1, 0, 311);
}
static const char* scanner_name = "华高扫描仪(模拟)";
hg_err hg_scanner_enum(HGScannerInfo* scanner_list, long* count, bool local_only)
{
#ifdef TEST_DEV
return hg_scanner_mgr::instance()->hg_scanner_enum(scanner_list, count, local_only);
#endif
if (!count)
return HG_ERR_INVALID_PARAMETER;
if (*count < 1)
{
*count = 1;
return HG_ERR_INSUFFICIENT_MEMORY;
}
*count = 1;
strcpy(scanner_list->name, scanner_name);
strcpy(scanner_list->type, "G100");
strcpy(scanner_list->model, "Multi-color");
strcpy(scanner_list->vendor, "Huagao China.");
if (!jsn_inst)
{
std::string v(jsontext);
jsn_inst = new json(&v[0]);
}
return HG_ERR_OK;
}
static volatile bool run_ = true;
void* thread_pnp(void*)
{
HGScannerInfo devs[4];
long count = sizeof(devs) / sizeof(devs[0]);
int ev = SANE_EVENT_DEVICE_ARRIVED;
while (run_)
{
hg_scanner_enum(devs, &count, true);
for (int i = 0; i < count; ++i)
{
SANE_Device dev;
unsigned int len = sizeof(dev);
dev.name = devs[i].name;
dev.vendor = devs[i].vendor;
dev.model = devs[i].model;
dev.type = devs[i].type;
local_utility::ui_cb(NULL, ev, (void*)&dev, &len, NULL);
}
ev = (rand() % 2 == 0) ? SANE_EVENT_DEVICE_ARRIVED : SANE_EVENT_DEVICE_LEFT;
count = sizeof(devs) / sizeof(devs[0]);
std::this_thread::sleep_for(std::chrono::milliseconds(180 * 1000));
}
return 0;
}
hg_err hg_scanner_open(scanner_handle* h, const char* name, bool shared, const char* user, const char* pwd, const char* check, char* rsc/*rsc[80]*/)
{
if (!h || !name)
return HG_ERR_INVALID_PARAMETER;
if (strcmp(name, scanner_name))
return HG_ERR_DEVICE_NOT_FOUND;
*h = (scanner_handle)0x7e57;
return HG_ERR_OK;
}
hg_err hg_scanner_close(scanner_handle h, bool force)
{
return HG_ERR_OK;
}
hg_err hg_scanner_get_parameter(scanner_handle h, unsigned param_no, char* json_data, long* len)
{
std::string v("");
json* child = NULL;
char key[20];
hg_err err = HG_ERR_OUT_OF_RANGE;
if (!len || !jsn_inst)
err = HG_ERR_INVALID_PARAMETER;
else
{
if (param_no == 0)
{
int count = 0;
jsn_inst->get_value("option_count", count);
*len = count;
err = HG_ERR_OK;
}
else
{
bzero(key, 20);
sprintf(key, "%d", param_no);
jsn_inst->get_value(key, child);
if (child)
{
v = child->to_string();
delete child;
if (*len <= v.length())
{
err = HG_ERR_INSUFFICIENT_MEMORY;
*len = v.length() + 4;
}
else
{
strcpy(json_data, v.c_str());
*len = v.length();
err = HG_ERR_OK;
}
}
}
}
return err;
}
hg_err hg_scanner_set_parameter(scanner_handle h, unsigned param_no, void* data, long len)
{
hg_err ret = HG_ERR_OK;
//if (param_no == 15)
//{
// int dpi = *((int*)data), regular = (dpi + 50) / 100 * 100;
//
// if (dpi != regular)
// {
// *(SANE_Int*)data = regular;
//
// ret = HG_ERR_NOT_EXACT;
// }
//}
char path[20];
json* child = NULL;
sprintf(path, "%d", param_no);
jsn_inst->get_value(path, child);
if (child)
{
std::string type(""), title("");
child->get_value("title", title);
if (title == "扫描张数")
{
if (strcmp((char*)data, "连续扫描") == 0)
scan_count = -1;
else
{
scan_count = 0;
}
}
else if (title == " 扫描数量")
scan_count_ = *((int*)data);
sprintf(path, "%d/cur", param_no);
child->get_value("type", type);
if (type == "int")
{
jsn_inst->set_value(path, *((int*)data));
}
else if (type == "bool")
{
jsn_inst->set_value(path, *((bool*)data));
}
else if (type == "float")
{
jsn_inst->set_value(path, *((double*)data));
}
else if(type != "button")
{
jsn_inst->set_value(path, std::string((char*)data));
}
delete child;
}
return ret;
}
static unsigned long long fake_total = 1920 * 800 * 3;
static unsigned long long fake_read = 0;
static volatile bool cancel = false;
static int pic_ind = 0;
static bool finished = false;
#include <thread>
#include <pthread.h>
#include <chrono>
std::unique_ptr<std::thread> thread_img_handle;
typedef struct _img_header
{
int width; // in pixel
int height; // in pixel
int bits; // per channel
int channels; // RGB - 3; GRAY - 1; ...
int line_bytes; // bytes of ONE line
unsigned total_bytes;// total bytes
}IMGHEAD, * LPIMGHEAD;
void* fake_thread(void* hs)
{
std::string path(local_utility::get_self_path());
char file[128];
IMGHEAD imgh;
SANE_Image img;
unsigned count = scan_count == -1 ? -1 : scan_count_;
scanner_handle h = (scanner_handle)hs;
path += "/sample/";
local_utility::ui_cb(h, SANE_EVENT_WORKING, (void*)"scanning ...", NULL, NULL);
while (!cancel)
{
sprintf(file, "img_%x.txt", ++pic_ind);
FILE* src = fopen((path + file).c_str(), "rb");
if (src)
{
fread(&imgh, sizeof(imgh), 1, src);
fclose(src);
sprintf(file, "img_%x.dat", pic_ind);
src = fopen((path + file).c_str(), "rb");
if (src)
{
void* data = malloc(imgh.total_bytes);
fread(data, 1, imgh.total_bytes, src);
fclose(src);
img.bytes = imgh.total_bytes;
img.data = (unsigned char*)data;
img.header.bytes_per_line = imgh.line_bytes;
img.header.depth = 8;
img.header.format = SANE_FRAME_RGB;
img.header.last_frame = true;
img.header.lines = imgh.height;
img.header.pixels_per_line = imgh.width;
local_utility::ui_cb(h, SANE_EVENT_IMAGE_OK, &img, (unsigned int*)&pic_ind, NULL);
free(data);
}
else
{
unsigned int err = HG_ERR_OPEN_FILE_FAILED;
path += file;
local_utility::ui_cb(h, SANE_EVENT_ERROR, &path[0], &err, NULL);
HG_VLOG_2(HG_LOG_LEVEL_DEBUG_INFO, 512, "Open file failed(%d): %s\n", errno, path.c_str());
break;
}
}
else
{
unsigned int err = HG_ERR_OPEN_FILE_FAILED;
path += file;
local_utility::ui_cb(h, SANE_EVENT_ERROR, &path[0], &err, NULL);
HG_VLOG_2(HG_LOG_LEVEL_DEBUG_INFO, 512, "Open file failed(%d): %s\n", errno, path.c_str());
break;
}
if (pic_ind >= count)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(150 + (rand() % 150)));
}
if (cancel)
path = "scan cancled by user";
else
path = "scan finished";
unsigned ret = cancel ? SANE_STATUS_CANCELLED : SANE_STATUS_GOOD;
local_utility::ui_cb(h, SANE_EVENT_SCAN_FINISHED, &path[0], &ret, NULL);
finished = true;
return 0;
}
hg_err hg_scanner_start(scanner_handle h, void* async_event, int num)
{
//if (local_utility::cb_ui_)
//{
// if (thread_img_handle.get() && !finished)
// return HG_ERR_DEVICE_BUSY;
//}
finished = false;
fake_read = 0;
cancel = false;
srand(time(NULL));
pic_ind = 0;
local_utility::ui_cb(h, SANE_EVENT_STATUS, (void*)"ready to start ...", NULL, NULL);
if (local_utility::cb_ui_)
{
// thread_img_handle.reset(new std::thread(fake_thread, h));
pthread_t id;
pthread_create(&id, NULL, fake_thread, (void*)h);
}
return HG_ERR_OK;
}
hg_err hg_scanner_stop(scanner_handle h)
{
cancel = true;
//if (local_utility::cb_ui_)
//{
// if (thread_img_handle.get() && thread_img_handle->joinable())
// thread_img_handle->join();
// thread_img_handle.reset();
//}
return HG_ERR_OK;
}
hg_err hg_scanner_get_img_info(scanner_handle h, SANE_Parameters* bmi, long len)
{
std::string path(local_utility::get_self_path());
char file[128];
path += "/sample/";
sprintf(file, "img_%x.txt", ++pic_ind);
FILE* src = fopen((path + file).c_str(), "rb");
if (src)
{
IMGHEAD imgh;
fread(&imgh, sizeof(imgh), 1, src);
fclose(src);
bmi->bytes_per_line = imgh.line_bytes;
bmi->depth = 8;
bmi->format = SANE_FRAME_RGB;
bmi->last_frame = true;
bmi->lines = imgh.height;
bmi->pixels_per_line = imgh.width;
}
else
{
bmi->bytes_per_line = 1920 * 3;
bmi->depth = 8;
bmi->format = SANE_FRAME_RGB;
bmi->last_frame = true;
bmi->lines = 800;
bmi->pixels_per_line = 1920;
}
return HG_ERR_OK;
}
hg_err hg_scanner_read_img_data(scanner_handle h, unsigned char* data, long* len)
{
// if (*len <= 0 || fake_read >= fake_total)
// return HG_ERR_NO_DATA;
if (cancel)
return (hg_err)SANE_STATUS_CANCELLED;
std::string path(local_utility::get_self_path());
char file[128];
static int offset = 0;
path += "/sample/";
sprintf(file, "img_%x.dat", ++pic_ind);
FILE* src = fopen((path + file).c_str(), "rb");
if (src)
{
fseek(src, offset, SEEK_SET);
size_t r = fread(data, 1, *len, src);
if (r < *len)
offset = 0;
else
offset += r;
fclose(src);
*len = r;
}
else
{
int bytes = 1920 * 800 * 3 - offset;
if (bytes > *len)
bytes = *len;
for (long i = 0; i < bytes; ++i)
data[i] = rand();
if (bytes <= *len)
offset = 0;
else
offset += bytes;
}
return HG_ERR_OK;
}
hg_err hg_scanner_get_status(scanner_handle h, int setstutas)
{
return HG_ERR_OK;
}
hg_err hg_scanner_reset(scanner_handle h)
{
return HG_ERR_OK;
}
hg_err hg_scanner_control(scanner_handle h, unsigned long code, void* data, unsigned* len)
{
return HG_ERR_OK;
}
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
hg_sane_middleware* hg_sane_middleware::inst_ = NULL;
const SANE_Device** hg_sane_middleware::dev_list_ = NULL;
hg_sane_middleware::hg_sane_middleware(void)
{
signal(SIGUSR1, &hg_sane_middleware::device_pnp);
local_utility::char_transfer_init();
hg_scanner_initialize(local_utility::ui_cb, NULL);
}
hg_sane_middleware::~hg_sane_middleware()
{
local_utility::char_transfer_uninit();
for (size_t i = 0; i < opts_.size(); ++i)
{
free(opts_[i].desc);
}
for (size_t i = 0; i < openning_.size(); ++i)
hg_scanner_close(openning_[i].handle, true);
hg_scanner_uninitialize();
}
const SANE_Device** hg_sane_middleware::to_sane_device(HGScannerInfo* hgscanner, int count)
{
// 将多级指针安排在一个连续的内存空间存放
SANE_Device** ret = NULL, * dev = NULL;
SANE_String val = NULL;
unsigned long bytes = (count + 1) * (sizeof(SANE_Device) + sizeof(SANE_Device*)), total = 0;
// calculate space ...
for (int i = 0; i < count; ++i)
{
bytes += ALIGN_INT(strlen(hgscanner[i].name) + 1);
bytes += ALIGN_INT(strlen(hgscanner[i].vendor) + 1);
bytes += ALIGN_INT(strlen(hgscanner[i].model) + 1);
bytes += ALIGN_INT(strlen(hgscanner[i].type) + 1);
}
bytes = ALIGN_INT(bytes + 16);
dev = (SANE_Device*)local_utility::acquire_memory(bytes, "hg_sane_middleware::to_sane_device");
total = bytes;
if (!dev)
return NULL;
memset(dev, 0, bytes);
ret = (SANE_Device**)dev;
dev = (SANE_Device*)((SANE_Device**)dev + count + 1);
val = (SANE_String)(dev + count);
#define COPY_DEVICE_MEMBER(m) \
dev->m = val; \
strcpy(val, hgscanner[i].m); \
bytes = ALIGN_INT(strlen(val) + 1); \
val += bytes;
for (int i = 0; i < count; ++i, ++dev)
{
ret[i] = dev;
COPY_DEVICE_MEMBER(name);
COPY_DEVICE_MEMBER(vendor);
COPY_DEVICE_MEMBER(model);
COPY_DEVICE_MEMBER(type);
}
//HG_VLOG_MINI_2(HG_LOG_LEVEL_ALL, "Memory usage: %u / %u\n", val - (char*)ret, total);
return (const SANE_Device**)ret;
}
void hg_sane_middleware::free_sane_device(SANE_Device** dev)
{
char* mem = (char*)dev;
if (mem)
{
free(mem);
}
}
void hg_sane_middleware::device_pnp(int sig)
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "Device list changed (%d)...", sig);
}
SANE_Fixed hg_sane_middleware::double_2_sane_fixed(double v)
{
return SANE_FIX(v);
}
double hg_sane_middleware::sane_fixed_2_double(SANE_Fixed v)
{
return SANE_UNFIX(v);
}
std::string hg_sane_middleware::option_value_2_string(SANE_Value_Type type, void* val)
{
std::string ret("unknown");
char buf[40];
switch (type)
{
case SANE_TYPE_BOOL:
ret = *(SANE_Bool*)val ? "true" : "false";
break;
case SANE_TYPE_INT:
sprintf(buf, "%d ", *(SANE_Word*)val);
ret = buf;
break;
case SANE_TYPE_FIXED:
sprintf(buf, "%f ", hg_sane_middleware::sane_fixed_2_double(*(SANE_Word*)val));
ret = buf;
break;
case SANE_TYPE_STRING:
ret = (char*)val;
break;
case SANE_TYPE_BUTTON:
ret = "Button";
break;
case SANE_TYPE_GROUP:
ret = "Group";
break;
default:
break;
}
return ret;
}
hg_sane_middleware* hg_sane_middleware::instance(void)
{
if (!hg_sane_middleware::inst_)
hg_sane_middleware::inst_ = new hg_sane_middleware();
return hg_sane_middleware::inst_;
}
void hg_sane_middleware::clear(void)
{
if (hg_sane_middleware::inst_)
{
delete hg_sane_middleware::inst_;
hg_sane_middleware::inst_ = NULL;
}
}
scanner_handle hg_sane_middleware::sane_handle_to_scanner(SANE_Handle h)
{
int bits = sizeof(h) / 2 * 8;
unsigned long long v = (unsigned long long)h;
v ^= v >> bits;
return (scanner_handle)(v);
}
SANE_Handle hg_sane_middleware::scanner_handle_to_sane(scanner_handle h)
{
int bits = sizeof(h) / 2 * 8;
unsigned long long v = (unsigned long long)h;
v ^= v >> bits;
return (SANE_Handle)(v);
}
SANE_Option_Descriptor* hg_sane_middleware::string_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<std::string>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(char*);
SANE_Option_Descriptor *sod = NULL;
char *str = NULL, **str_arr = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(char*);
for (size_t i = 0; i < values.size(); ++i)
bytes += ALIGN_INT(values[i].length() + 1);
bytes += sizeof(char*) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::string_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = SANE_TYPE_STRING;
sod->unit = SANE_UNIT_NONE;
sod->size = values.size();
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
| SANE_CAP_AUTOMATIC; // 硬件可设置默认值
if (values.size())
{
sod->constraint_type = SANE_CONSTRAINT_STRING_LIST;
sod->constraint.string_list = (char**)str;
str_arr = (char**)str;
str += (values.size() + 1) * sizeof(char*);
for (size_t i = 0; i < values.size(); ++i)
{
str_arr[i] = str;
strcpy(str, values[i].c_str());
str += ALIGN_INT(values[i].length() + 1);
}
}
//HG_VLOG_MINI_2(HG_LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* hg_sane_middleware::number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, bool double_val, double* lower, double* upper)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor *sod = NULL;
char *str = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Range*) + sizeof(SANE_Range);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = double_val ? SANE_TYPE_FIXED : SANE_TYPE_INT;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
/*| SANE_CAP_AUTOMATIC*/; // 硬件可设置默认值
if (lower || upper)
{
sod->size = sizeof(SANE_Range);
sod->constraint_type = SANE_CONSTRAINT_RANGE;
sod->constraint.range = (SANE_Range*)str;
if (lower)
{
if (double_val)
(*(SANE_Range*)str).min = hg_sane_middleware::double_2_sane_fixed(*lower);
else
(*(SANE_Range*)str).min = *lower;
}
if (upper)
{
if (double_val)
(*(SANE_Range*)str).max = hg_sane_middleware::double_2_sane_fixed(*upper);
else
(*(SANE_Range*)str).max = *upper;
}
(*(SANE_Range*)str).quant = 0;
str = (char*)((SANE_Range*)str + 1);
}
//HG_VLOG_MINI_2(HG_LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* hg_sane_middleware::number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<int>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Word*) + sizeof(SANE_Word) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = SANE_TYPE_INT;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
/*| SANE_CAP_AUTOMATIC*/; // 硬件可设置默认值
if (values.size())
{
SANE_Word *val = (SANE_Word*)str;
sod->constraint.word_list = val;
sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
*val++ = values.size();
for (size_t i = 0; i < values.size(); ++i)
val[i] = values[i];
str = (char*)(val + values.size());
}
//HG_VLOG_MINI_2(HG_LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* hg_sane_middleware::number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<double>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Word*) + sizeof(SANE_Word) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = SANE_TYPE_FIXED;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
/*| SANE_CAP_AUTOMATIC*/; // 硬件可设置默认值
if (values.size())
{
SANE_Word* val = (SANE_Word*)str;
sod->constraint.word_list = val;
sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
*val++ = values.size();
for (size_t i = 0; i < values.size(); ++i)
val[i] = hg_sane_middleware::double_2_sane_fixed(values[i]);
str = (char*)(val + values.size());
}
//HG_VLOG_MINI_2(HG_LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Status hg_sane_middleware::open(SANE_String_Const devicename, SANE_Handle* handle, const char* name, const char* pwd, const char* method, char* rsc)
{
scanner_handle h = NULL;
hg_err err = HG_ERR_OK;
if (handle == NULL)
return SANE_STATUS_INVAL;
err = hg_scanner_open(&h, devicename, false, NULL, NULL, NULL, rsc);
if (err == HG_ERR_OK)
{
OPENDEV od;
od.dev_name = devicename;
od.handle = h;
od.scan_count = -1;
openning_.push_back(od);
*handle = hg_sane_middleware::scanner_handle_to_sane(h);
return SANE_STATUS_GOOD;
}
else if (err == HG_ERR_ACCESS_DENIED)
{
return SANE_STATUS_ACCESS_DENIED;
}
else
return SANE_STATUS_UNSUPPORTED;
}
SANE_Option_Descriptor* hg_sane_middleware::from_json(scanner_handle h, json* jsn, int opt_no)
{
std::string name(""), title(""), desc(""), val("");
std::vector<std::string> constraints;
double lower = .0f, upper = .0f;
bool db_val = false;
if (jsn->get_value("name", val))
{
name = local_utility::utf8_2_ansi(val.c_str());
}
if (jsn->get_value("title", val))
{
title = local_utility::utf8_2_ansi(val.c_str());
}
if (jsn->get_value("desc", val))
{
desc = local_utility::utf8_2_ansi(val.c_str());
}
if (!jsn->get_value("type", val))
return NULL;
SANE_Option_Descriptor* ret = NULL;
if (val == "string")
{
json* range = NULL;
std::vector<std::string> constraints;
jsn->get_value("range", range);
if (range)
{
if (range->first_child(val))
{
constraints.push_back(local_utility::utf8_2_ansi(val.c_str()));
while (range->next_child(val))
{
constraints.push_back(local_utility::utf8_2_ansi(val.c_str()));
}
}
delete range;
}
ret = hg_sane_middleware::string_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
else if (val == "int" || val == "float")
{
json* range = NULL;
jsn->get_value("range", range);
if (range)
{
if (val == "int")
{
int l = 0;
if (range->get_value("min", l))
{
int u = 0;
range->get_value("max", u);
lower = l;
upper = u;
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, &lower, &upper);
}
else
{
std::vector<int> constraints;
if (range->first_child(val))
{
constraints.push_back(atoi(val.c_str()));
while (range->next_child(val))
{
constraints.push_back(atoi(val.c_str()));
}
}
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
}
else
{
if (range->get_value("min", lower))
{
range->get_value("max", upper);
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, true, &lower, &upper);
}
else
{
std::vector<double> constraints;
if (range->first_child(val))
{
constraints.push_back(atof(val.c_str()));
while (range->next_child(val))
{
constraints.push_back(atof(val.c_str()));
}
}
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
}
delete range;
}
else
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
}
}
else if (val == "bool")
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
ret->type = SANE_TYPE_BOOL;
}
else if (val == "button")
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
ret->type = SANE_TYPE_BUTTON;
}
else if (val == "group")
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
ret->type = SANE_TYPE_GROUP;
}
// fill the 'size' field, for SANE_ACTION_GET action ...
if (ret)
{
int bytes = 0;
jsn->get_value("size", bytes);
ret->size = bytes;
val = "";
jsn->get_value("category", val);
if (val == "advanced")
{
ret->cap |= SANE_CAP_ADVANCED;
}
if (strcmp(ret->title, "\345\210\206\350\276\250\347\216\207") == 0)
{
hg_log::log(HG_LOG_LEVEL_DEBUG_INFO, "set \345\210\206\350\276\250\347\216\207 unit to DPI\n");
ret->unit = SANE_UNIT_DPI;
}
//bool enabled = true;
//if (jsn->get_value("enable", enabled) && !enabled)
// ret->cap |= SANE_CAP_INACTIVE;
// 关联项
json* depend = NULL;
SLAVEOP so;
if (jsn->get_value("depend_or", depend))
{
so.is_enable = &hg_sane_middleware::is_enable_or;
}
else if (jsn->get_value("depend_and", depend))
{
so.is_enable = &hg_sane_middleware::is_enable_and;
}
if (depend)
{
if (parse_depends(depend, so))
{
so.enable_now = (ret->cap & SANE_CAP_INACTIVE) != SANE_CAP_INACTIVE;
so.option_no = opt_no;
// initializing status ...
if (so.master.size())
{
std::string master(get_option_json(h, so.master[0].option_no));
json* m = new json();
if (m->attach_text(&master[0]))
{
bool integer = false;
master = "";
m->get_value("type", master);
integer = master == "int";
master = "";
m->get_value_as_string("cur", master, integer);
so.enable_now = so.is_enable(so.master, cur_vals_);
if (!so.enable_now)
ret->cap |= SANE_CAP_INACTIVE;
}
delete m;
}
slave_options_.push_back(so);
}
delete depend;
}
}
return ret;
}
scanner_handle hg_sane_middleware::find_openning_device(SANE_Handle h, bool rmv, OPENDEV* dev)
{
scanner_handle handle = hg_sane_middleware::sane_handle_to_scanner(h);
std::vector<OPENDEV>::iterator it = std::find(openning_.begin(), openning_.end(), handle);
if (it == openning_.end())
handle = NULL;
else
{
if (dev)
*dev = *it;
if (rmv)
openning_.erase(it);
}
return handle;
}
std::string hg_sane_middleware::get_option_json(scanner_handle handle, int opt_no)
{
char* json_txt = NULL;
long length = 0;
hg_err err = hg_scanner_get_parameter(handle, opt_no, json_txt, &length);
std::string ret("");
if (err == HG_ERR_INSUFFICIENT_MEMORY)
{
json_txt = (char*)local_utility::acquire_memory(ALIGN_INT(length + 4), "hg_sane_middleware::get_option_json");
bzero(json_txt, length + 4);
err = hg_scanner_get_parameter(handle, opt_no, json_txt, &length);
if (err == HG_ERR_OK)
{
ret = json_txt;
}
free(json_txt);
}
return ret;
}
SANE_Option_Descriptor* hg_sane_middleware::find_stored_descriptor(const char* name, int option)
{
for (size_t i = 0; i < opts_.size(); ++i)
{
if (opts_[i].dev_name == name && opts_[i].option_no == option)
return opts_[i].desc;
}
return NULL;
}
SANE_Option_Descriptor* hg_sane_middleware::find_stored_descriptor(SANE_Handle handle, int option)
{
OPENDEV dev;
scanner_handle h = find_openning_device(handle, false, &dev);
if (!h)
return NULL;
else
return find_stored_descriptor(dev.dev_name.c_str(), option);
}
bool hg_sane_middleware::get_current_value(scanner_handle handle, int option, void* value, SANE_Value_Type *type)
{
std::string val(get_option_json(handle, option));
json* jsn = new json();
int estimate = 20;
bool ret = false;
if (jsn->attach_text(&val[0]) &&
jsn->get_value("type", val))
{
SANE_Value_Type t = SANE_TYPE_STRING;
ret = true;
if (val == "int")
{
int v = 0;
jsn->get_value("cur", v);
*((SANE_Int*)value) = v;
t = SANE_TYPE_INT;
}
else if (val == "bool")
{
bool yesorno = false;
jsn->get_value("cur", yesorno);
*(SANE_Bool*)value = yesorno;
t = SANE_TYPE_BOOL;
}
else if (val == "float")
{
double v = .0f;
jsn->get_value("cur", v);
*((SANE_Fixed*)value) = hg_sane_middleware::double_2_sane_fixed(v);
t = SANE_TYPE_FIXED;
}
else
{
val = "";
jsn->get_value("cur", val);
strcpy((char*)value, val.c_str());
estimate += val.length();
}
if (type)
*type = t;
refresh_current_value(option, jsn);
jsn->get_value("title", val);
HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "<--Get option(%d - %s) value: %s\n", option, val.c_str(), hg_sane_middleware::option_value_2_string(t, value).c_str());
}
delete jsn;
return ret;
}
void hg_sane_middleware::reload_current_value(scanner_handle handle, std::vector<int>* changed)
{
long count = 0;
if (changed)
changed->clear();
hg_scanner_get_parameter(handle, 0, NULL, &count);
for (int i = 1; i < count; ++i)
{
std::string val(get_option_json(handle, i));
json* jsn = new json();
if (jsn->attach_text(&val[0]) &&
jsn->get_value("type", val))
{
if (refresh_current_value(i, jsn))
changed->push_back(i);
}
delete jsn;
}
}
SANE_Status hg_sane_middleware::get_devices(const SANE_Device*** device_list, SANE_Bool local_only)
{
if (!device_list)
return SANE_STATUS_INVAL;
HGScannerInfo* dev = NULL;
long count = 0;
hg_err hgerr = hg_scanner_enum(dev, &count, local_only);
SANE_Status ret = SANE_STATUS_GOOD;
if (hgerr == HG_ERR_INSUFFICIENT_MEMORY)
{
count += 4; // 为两次hg_scanner_enum间隙可能新增的设备预留空间
dev = (HGScannerInfo*)local_utility::acquire_memory(sizeof(HGScannerInfo) * count, "hg_sane_middleware::get_devices");
hgerr = hg_scanner_enum(dev, &count, local_only);
if (hgerr != HG_ERR_OK)
{
free(dev);
dev = NULL;
}
}
if (hgerr == HG_ERR_OK)
{
*device_list = hg_sane_middleware::to_sane_device(dev, count);
if (dev)
free(dev);
}
else
ret = local_utility::hg_err_2_sane_statu(hgerr);
if (hg_sane_middleware::dev_list_)
free(hg_sane_middleware::dev_list_);
hg_sane_middleware::dev_list_ = *device_list;
return ret;
}
SANE_Status hg_sane_middleware::open_device(SANE_String_Const devicename, SANE_Handle* handle)
{
char rsc[128];
SANE_Status ret = SANE_STATUS_GOOD;
bzero(rsc, sizeof(rsc));
ret = open(devicename, handle, NULL, NULL, NULL, rsc);
if (ret == SANE_STATUS_ACCESS_DENIED && rsc[0])
{
SANEAUTH auth;
bzero(&auth, sizeof(auth));
auth.resource = rsc;
if (local_utility::ui_cb(NULL, SANE_EVENT_NEED_AUTH, (void*)&auth, NULL, NULL))
{
return SANE_STATUS_CANCELLED;
}
ret = open(devicename, handle, auth.name, auth.pwd, auth.method, rsc);
}
return ret;
}
SANE_Status hg_sane_middleware::close_device(SANE_Handle h)
{
scanner_handle hs = find_openning_device(h, true);
SANE_Status err = SANE_STATUS_GOOD;
if (hs)
err = local_utility::hg_err_2_sane_statu(hg_scanner_close(hs, true));
return err;
}
SANE_Status hg_sane_middleware::get_image_parameters(SANE_Handle handle, SANE_Parameters* params)
{
scanner_handle h = find_openning_device(handle);
hg_err err = HG_ERR_NOT_START;
if (!params)
return SANE_STATUS_INVAL;
err = hg_scanner_get_img_info(h, params, sizeof(*params));
return local_utility::hg_err_2_sane_statu(err);
}
SANE_Status hg_sane_middleware::start(SANE_Handle h, void* async_event)
{
OPENDEV dev;
scanner_handle hs = find_openning_device(h, false, &dev);
hg_err err = HG_ERR_INVALID_PARAMETER;
if(hs)
err = hg_scanner_start(hs, async_event, dev.scan_count);
return local_utility::hg_err_2_sane_statu(err);
}
SANE_Status hg_sane_middleware::read(SANE_Handle h, void* buf, int* bytes)
{
scanner_handle hs = find_openning_device(h);
hg_err err = HG_ERR_INVALID_PARAMETER;
long r = bytes ? *bytes : 0;
if (bytes && hs)
{
err = hg_scanner_read_img_data(hs, (unsigned char*)buf, &r);
*bytes = r;
}
return local_utility::hg_err_2_sane_statu(err);
}
SANE_Status hg_sane_middleware::stop(SANE_Handle h)
{
scanner_handle hs = find_openning_device(h);
if(hs)
hg_scanner_stop(hs);
return SANE_STATUS_GOOD;
}
SANE_Option_Descriptor* hg_sane_middleware::get_option_descriptor(SANE_Handle h, SANE_Int option)
{
OPENDEV dev;
scanner_handle handle = find_openning_device(h, false, &dev);
SANE_Option_Descriptor* ret = NULL;
if (!handle)
return NULL;
ret = find_stored_descriptor(dev.dev_name.c_str(), option);
if (!ret)
{
std::string json_txt(get_option_json(handle, option));
if (json_txt.length())
{
json* jsn = new json();
if (jsn->attach_text(&json_txt[0]))
{
ret = from_json(handle, jsn, option);
if (ret)
{
DEVOPT devopt;
devopt.dev_name = dev.dev_name;
devopt.option_no = option;
devopt.desc = ret;
opts_.push_back(devopt);
refresh_current_value(option, jsn);
}
}
delete jsn;
}
}
return ret;
}
SANE_Status hg_sane_middleware::set_option(SANE_Handle h, SANE_Int option, SANE_Action action, void* value, SANE_Int* after_do)
{
OPENDEV dev;
scanner_handle handle = find_openning_device(h, false, &dev);
if (!handle || (action == SANE_ACTION_GET_VALUE && !value))
return SANE_STATUS_INVAL;
if (action == SANE_ACTION_GET_VALUE)
{
if (after_do)
*after_do = 0;
SANE_Status ret = SANE_STATUS_IO_ERROR;
if (option == 0)
{
long count = 0;
hg_scanner_get_parameter(handle, option, NULL, &count);
*((SANE_Int*)value) = count;
ret = SANE_STATUS_GOOD;
}
else
{
if(get_current_value(handle, option, value))
ret = SANE_STATUS_GOOD;
}
return ret;
}
else
{
SANE_Option_Descriptor* desc = find_stored_descriptor(dev.dev_name.c_str(), option);
if (!desc)
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_WARNING, "Option descriptor %d not found.\n", option);
return SANE_STATUS_UNSUPPORTED;
}
else if (!value && desc->type != SANE_TYPE_BUTTON)
{
HG_VLOG_MINI_2(HG_LOG_LEVEL_WARNING, "Option descriptor %d(%s) need a value!.\n", option, desc->title);
return SANE_STATUS_INVAL;
}
SANE_Status status = SANE_STATUS_GOOD;
std::string v(hg_sane_middleware::option_value_2_string(desc->type, value));
void* pass = value;
double dv = .0f;
bool bv = false;
int size = desc->size;
hg_err err = HG_ERR_OK;
if (desc->type == SANE_TYPE_BOOL)
{
bv = *((SANE_Bool*)value) == SANE_TRUE;
pass = &bv;
size = sizeof(bv);
}
else if (desc->type == SANE_TYPE_FIXED)
{
dv = hg_sane_middleware::sane_fixed_2_double(*((SANE_Fixed*)value));
pass = &dv;
size = sizeof(dv);
}
err = hg_scanner_set_parameter(handle, option, pass, size);
if (desc->type == SANE_TYPE_BOOL)
{
*((SANE_Bool*)value) = bv ? SANE_TRUE : SANE_FALSE;
}
else if (desc->type == SANE_TYPE_FIXED)
{
*((SANE_Fixed*)value) = hg_sane_middleware::double_2_sane_fixed(dv);
}
std::string prev(v);
v = hg_sane_middleware::option_value_2_string(desc->type, value);
if (prev == v)
{
HG_VLOG_MINI_3(HG_LOG_LEVEL_DEBUG_INFO, "-->Set option(%d - %s) value: %s\n", option, desc->title, v.c_str());
}
else
{
HG_VLOG_4(HG_LOG_LEVEL_DEBUG_INFO, 512, "-->Set option(%d - %s) value: %s(Applied: %s)\n", option, desc->title, prev.c_str(), v.c_str());
}
if (err == HG_ERR_OK)
{
err = (hg_err)something_after_do(handle, dev.dev_name.c_str(), option, v.c_str());
}
else if (err == HG_ERR_NOT_EXACT)
{
err = (hg_err)(something_after_do(handle, dev.dev_name.c_str(), option, v.c_str()) | SANE_INFO_INEXACT);
}
else if (err == HG_ERR_CONFIGURATION_CHANGED)
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "the setting '%s' affects other options value, RELOAD ...\n", desc->title);
on_HG_ERR_CONFIGURATION_CHANGED(handle, dev.dev_name.c_str());
err = (hg_err)SANE_INFO_RELOAD_OPTIONS;
}
else if (err == HG_ERR_ACCESS_DENIED)
status = SANE_STATUS_ACCESS_DENIED;
else
status = SANE_STATUS_INVAL;
if (after_do)
*after_do = err;
return status;
}
}
SANE_Status hg_sane_middleware::io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len)
{
OPENDEV od;
scanner_handle handle = find_openning_device(h, false, &od);
// commented at 2022-03-23 for getting app about info before open any device
//
//if (!handle)
// return SANE_STATUS_INVAL;
int ret = hg_scanner_control(handle, code, data, len);
if (ret == HG_ERR_CONFIGURATION_CHANGED)
{
int nc = code;
HG_VLOG_MINI_1(HG_LOG_LEVEL_DEBUG_INFO, "the setting '0x%08x' affects other options value, RELOAD ...\n", nc);
on_HG_ERR_CONFIGURATION_CHANGED(handle, od.dev_name.c_str());
}
return local_utility::hg_err_2_sane_statu(ret);
}
/// <summary>
/// 关联项处理
bool hg_sane_middleware::compare_val_equal(const char* cur_val, const char* limit_l, const char* limit_r)
{
return strcmp(cur_val, limit_l) == 0;
}
bool hg_sane_middleware::compare_val_not_equal(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_equal(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::compare_val_great(const char* cur_val, const char* limit_l, const char* limit_r)
{
return atof(cur_val) > atof(limit_l);
}
bool hg_sane_middleware::compare_val_not_less(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_less(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::compare_val_less(const char* cur_val, const char* limit_l, const char* limit_r)
{
return atof(cur_val) < atof(limit_l);
}
bool hg_sane_middleware::compare_val_not_great(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_great(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::compare_val_between(const char* cur_val, const char* limit_l, const char* limit_r)
{
return atof(limit_l) < atof(cur_val) && atof(cur_val) < atof(limit_r);
}
bool hg_sane_middleware::compare_val_not_between(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_between(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::is_enable_and(const std::vector<MASTEROP>& master, std::vector<CURVAL>& curvals)
{
// NOTE: logical operator '&&' should get all master's value to check, here we only consider ONE master !!!!
bool enabled = true;
for (size_t i = 0; enabled && i < master.size(); ++i)
{
std::vector<CURVAL>::iterator it = std::find(curvals.begin(), curvals.end(), master[i].option_no);
if (it == curvals.end())
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_WARNING, "option %d's current value is not found, other options depend it maybe in wrong status.\n", master[i].option_no);
continue;
}
enabled &= master[i].compare_val(it->val.c_str(), master[i].limit_l.c_str(), master[i].limit_r.c_str());
}
return enabled;
}
bool hg_sane_middleware::is_enable_or(const std::vector<MASTEROP>& master, std::vector<CURVAL>& curvals)
{
bool enabled = false;
for (size_t i = 0; !enabled && i < master.size(); ++i)
{
std::vector<CURVAL>::iterator it = std::find(curvals.begin(), curvals.end(), master[i].option_no);
if (it == curvals.end())
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_WARNING, "option %d's current value is not found, other options depend it maybe in wrong status.\n", master[i].option_no);
continue;
}
enabled |= master[i].compare_val(it->val.c_str(), master[i].limit_l.c_str(), master[i].limit_r.c_str());
}
return enabled;
}
bool hg_sane_middleware::parse_master_option(const char* depend_str, MASTEROP& mo)
{
bool ret = true;
double num = .0f;
mo.option_no = 0;
mo.compare_val = &hg_sane_middleware::compare_val_equal;
mo.limit_l = mo.limit_r = "";
local_utility::skip_space(depend_str);
ret = local_utility::get_number(depend_str, num);
if (ret)
{
mo.option_no = num;
local_utility::skip_space(depend_str);
if (*depend_str == '=')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
if (*depend_str == '[')
{
ret = local_utility::get_limit(depend_str, mo.limit_l, mo.limit_r);
mo.compare_val = &hg_sane_middleware::compare_val_between;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_equal;
mo.limit_l = depend_str;
}
}
else
{
ret = false;
}
}
else if (*depend_str == '>')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
mo.compare_val = &hg_sane_middleware::compare_val_not_less;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_great;
}
mo.limit_l = depend_str;
}
else if (*depend_str == '<')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
mo.compare_val = &hg_sane_middleware::compare_val_not_great;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_less;
}
mo.limit_l = depend_str;
}
else if (*depend_str == '!')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
if (*depend_str == '[')
{
ret = local_utility::get_limit(depend_str, mo.limit_l, mo.limit_r);
mo.compare_val = &hg_sane_middleware::compare_val_not_between;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_not_equal;
mo.limit_l = depend_str;
}
}
else
{
ret = false;
}
}
else
{
ret = false;
}
}
return ret;
}
bool hg_sane_middleware::parse_depends(json* jsn, SLAVEOP& so)
{
std::string val("");
bool ret = jsn->first_child(val);
while(ret)
{
MASTEROP mo;
ret = parse_master_option(val.c_str(), mo);
if (!ret)
break;
so.master.push_back(mo);
if (std::find(master_options_.begin(), master_options_.end(), mo.option_no) == master_options_.end())
{
master_options_.push_back(mo.option_no);
std::sort(master_options_.begin(), master_options_.end());
}
ret = jsn->next_child(val);
}
return so.master.size() > 0;
}
bool hg_sane_middleware::is_associatived(const SLAVEOP& slave, int master_opt)
{
bool result = false;
for (size_t i = 0; i < slave.master.size(); ++i)
{
if (slave.master[i].option_no == master_opt)
{
result = true;
break;
}
}
return result;
}
bool hg_sane_middleware::set_stored_option_enabled(const char* dev_name, int option, bool enable, int* size)
{
SANE_Option_Descriptor* opt = find_stored_descriptor(dev_name, option);
bool ret = false;
if (opt)
{
if(size)
*size = opt->size;
ret = true;
if (enable)
opt->cap &= ~SANE_CAP_INACTIVE;
else
opt->cap |= SANE_CAP_INACTIVE;
}
return ret;
}
int hg_sane_middleware::something_after_do(scanner_handle h, const char* dev_name, int option_no, const char* cur_val)
{
int after = 0;
OPTENABLE oe;
std::vector<OPTENABLE> changed_options;
refresh_current_value(option_no, cur_val);
if (std::find(master_options_.begin(), master_options_.end(), option_no) == master_options_.end())
{
return after;
}
oe.opt_no = option_no;
oe.enable = true;
changed_options.push_back(oe);
for (size_t i = 0; i < changed_options.size(); ++i)
{
for (size_t slave = 0; slave < slave_options_.size(); ++slave)
{
if (slave_options_[slave].option_no == changed_options[i].opt_no ||
!is_associatived(slave_options_[slave], changed_options[i].opt_no))
continue;
bool enable = changed_options[i].enable;
int bytes = 0;
if (enable)
enable = slave_options_[slave].is_enable(slave_options_[slave].master, cur_vals_);
if (enable == slave_options_[slave].enable_now)
continue;
slave_options_[slave].enable_now = enable;
if (!set_stored_option_enabled(dev_name, slave_options_[slave].option_no, enable, &bytes))
continue;
OPTEN* op = get_control_enalbe_data(slave_options_[slave]);
hg_scanner_control(h, HG_CONTROL_CODE_OPTION_ENABLE, op, NULL);
free_control_enable_data(op);
if (std::find(changed_options.begin(), changed_options.end(), slave_options_[slave].option_no) != changed_options.end())
continue;
oe.opt_no = slave_options_[slave].option_no;
oe.enable = slave_options_[slave].enable_now;
changed_options.push_back(oe);
}
}
if (changed_options.size() > 1)
after = SANE_INFO_RELOAD_OPTIONS;
return after;
}
bool hg_sane_middleware::refresh_current_value(int opt, json* jsn)
{
std::vector<CURVAL>::iterator it = std::find(cur_vals_.begin(), cur_vals_.end(), opt);
if (it == cur_vals_.end())
{
CURVAL cv;
jsn->get_value("type", cv.type);
cv.opt_no = opt;
jsn->get_value_as_string("cur", cv.val, cv.type == "int");
cur_vals_.push_back(cv);
return false;
}
else
{
std::string old(it->val);
jsn->get_value_as_string("cur", it->val, it->type == "int");
return old != it->val;
}
}
bool hg_sane_middleware::refresh_current_value(int opt, const char* val)
{
std::vector<CURVAL>::iterator it = std::find(cur_vals_.begin(), cur_vals_.end(), opt);
if (it != cur_vals_.end())
{
bool ret = strcmp(it->val.c_str(), val) == 0;
it->val = val;
return ret;
}
return false;
}
OPTEN* hg_sane_middleware::get_control_enalbe_data(const SLAVEOP& slave)
{
std::vector<int> master;
OPTEN* opt = NULL;
size_t size = sizeof(OPTEN);
for (size_t i = 0; i < slave.master.size(); ++i)
{
if (std::find(master.begin(), master.end(), slave.master[i].option_no) == master.end())
master.push_back(slave.master[i].option_no);
}
size += master.size() * sizeof(OPTVAL);
opt = (OPTEN*)malloc(size);
bzero(opt, size);
opt->enabled = slave.enable_now;
opt->opt_num = slave.option_no;
opt->master_count = 0;
for (size_t i = 0; i < master.size(); ++i)
{
std::vector<CURVAL>::iterator m = std::find(cur_vals_.begin(), cur_vals_.end(), master[i]);
if (m == cur_vals_.end())
continue;
opt->master[opt->master_count].opt_num = master[i];
if (m->type == "string")
{
opt->master[opt->master_count].data = malloc(m->val.length() + 4);
strcpy((char*)opt->master[opt->master_count].data, m->val.c_str());
}
else
{
opt->master[opt->master_count].data = malloc(sizeof(double));
if (m->type == "bool")
*((bool*)opt->master[opt->master_count].data) = (m->val == "true");
else if (m->type == "int")
*((int*)opt->master[opt->master_count].data) = atoi(m->val.c_str());
else
*((double*)opt->master[opt->master_count].data) = atof(m->val.c_str());
opt->master_count++;
}
}
return opt;
}
void hg_sane_middleware::free_control_enable_data(OPTEN* opt)
{
if (opt)
{
for (int i = 0; i < opt->master_count; ++i)
{
if (opt->master[i].data)
free(opt->master[i].data);
}
free(opt);
}
}
void hg_sane_middleware::on_HG_ERR_CONFIGURATION_CHANGED(scanner_handle handle, const char* dev_name)
{
std::vector<int> changed;
reload_current_value(handle, &changed);
if (changed.size())
{
for (size_t i = 0; i < changed.size(); ++i)
{
std::vector<CURVAL>::iterator it = std::find(cur_vals_.begin(), cur_vals_.end(), changed[i]);
if (it != cur_vals_.end())
something_after_do(handle, dev_name, it->opt_no, it->val.c_str());
}
}
}
/// </summary>
/// <summary>
/// 导出接口
/// </summary>
extern "C" { // avoid compiler exporting name in C++ style !!!
SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize)
{
local_utility::init_log();
local_utility::cb_auth_ = authorize;
hg_sane_middleware::instance();
local_utility::get_version(version_code);
return SANE_STATUS_GOOD;
}
void inner_sane_exit(void)
{
#ifdef RUN_TEST
run_ = false;
#endif
local_utility::stop_work();
hg_sane_middleware::clear();
hg_log::log(HG_LOG_LEVEL_FATAL, (hg_log::current_time() + " hgsane exited.\n").c_str());
}
SANE_Status inner_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only)
{
SANE_Status code = hg_sane_middleware::instance()->get_devices(device_list, local_only);
return code;
}
SANE_Status inner_sane_open(SANE_String_Const devicename, SANE_Handle* handle)
{
return hg_sane_middleware::instance()->open_device(devicename, handle);
}
void inner_sane_close(SANE_Handle handle)
{
hg_sane_middleware::instance()->close_device(handle);
}
const SANE_Option_Descriptor*
inner_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
{
return hg_sane_middleware::instance()->get_option_descriptor(handle, option);
}
SANE_Status inner_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info)
{
return hg_sane_middleware::instance()->set_option(handle, option, action, value, info);
}
SANE_Status inner_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params)
{
return hg_sane_middleware::instance()->get_image_parameters(handle, params);
}
SANE_Status inner_sane_start(SANE_Handle handle)
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_ALL, "[%s] - sane_start\n", hg_log::format_current_thread_id().c_str());
return hg_sane_middleware::instance()->start(handle, NULL);
}
SANE_Status inner_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length)
{
// HG_VLOG_MINI_1(HG_LOG_LEVEL_ALL, "[%s] - sane_read\n", hg_log::format_current_thread_id().c_str());
if (!length)
length = &max_length;
else
*length = max_length;
return hg_sane_middleware::instance()->read(handle, data, length);
}
void inner_sane_cancel(SANE_Handle handle)
{
hg_sane_middleware::instance()->stop(handle);
}
SANE_Status inner_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)
{
HG_VLOG_MINI_1(HG_LOG_LEVEL_ALL, "[%s] - sane_set_io_mode\n", hg_log::format_current_thread_id().c_str());
return non_blocking ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD;
}
SANE_Status inner_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd)
{
return SANE_STATUS_UNSUPPORTED;
}
SANE_String_Const inner_sane_strstatus(SANE_Status status)
{
return local_utility::error_text(status);
}
SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param)
{
local_utility::init_log();
local_utility::cb_ui_ = cb;
local_utility::cb_ui_parm_ = param;
hg_sane_middleware::instance();
local_utility::get_version(version_code);
#ifdef RUN_TEST
if (local_utility::cb_ui_)
{
// thread_img_handle.reset(new std::thread(fake_thread, h));
pthread_t id;
pthread_create(&id, NULL, thread_pnp, NULL);
}
#endif
return SANE_STATUS_GOOD;
}
SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len)
{
return hg_sane_middleware::instance()->io_control(h, code, data, len);
}
void sanei_debug_msg(int level, int max_level, const char* be, const char* fmt, va_list ap)
{
//char* f = (char*)local_utility::acquire_memory(strlen(fmt) + 20, "sanei_debug_msg");
//
//strcpy(f, "%s - ");
//strcat(f, fmt);
//strcat(f, "\n");
//hg_log::vlog(strlen(f) + 256, f, be, ap);
//free(f);
}
}