887 lines
23 KiB
C++
887 lines
23 KiB
C++
|
// DlgInput.cpp : implementation file
|
|||
|
//
|
|||
|
|
|||
|
#include "stdafx.h"
|
|||
|
#include "hgjson.h"
|
|||
|
#include "DlgTwain.h"
|
|||
|
#include "afxdialogex.h"
|
|||
|
|
|||
|
#include <algorithm>
|
|||
|
|
|||
|
#include <file/file_util.h>
|
|||
|
#include <coding/coding.h>
|
|||
|
|
|||
|
|
|||
|
namespace util
|
|||
|
{
|
|||
|
enum
|
|||
|
{
|
|||
|
BOM_ANSI,
|
|||
|
BOM_UTF8,
|
|||
|
BOM_UNICODE,
|
|||
|
};
|
|||
|
static INTER_MODULE_CALLBACK(got_str)
|
|||
|
{
|
|||
|
*(std::string*)param += std::string(data, len);
|
|||
|
|
|||
|
return inter_module_data::SET_RESULT_CONTINUE;
|
|||
|
}
|
|||
|
static INTER_MODULE_CALLBACK(got_wstr)
|
|||
|
{
|
|||
|
*(std::wstring*)param += std::wstring((const wchar_t*)data, len / 2);
|
|||
|
|
|||
|
return inter_module_data::SET_RESULT_CONTINUE;
|
|||
|
}
|
|||
|
|
|||
|
static bool is_space(wchar_t ch)
|
|||
|
{
|
|||
|
return ch == L' ' || ch == L'\t' || ch == L'\r' || ch == L'\n';
|
|||
|
}
|
|||
|
static bool is_var_char(wchar_t ch, bool allow_num)
|
|||
|
{
|
|||
|
return ch == L'_' ||
|
|||
|
(ch >= L'0' && ch <= L'9' && allow_num) ||
|
|||
|
(ch >= L'a' && ch <= L'z') ||
|
|||
|
(ch >= L'A' && ch <= L'Z');
|
|||
|
}
|
|||
|
static bool skip_space(const wchar_t** str)
|
|||
|
{
|
|||
|
const wchar_t* bgn = *str;
|
|||
|
|
|||
|
while (is_space(str[0][0]))
|
|||
|
(*str)++;
|
|||
|
|
|||
|
return *str > bgn;
|
|||
|
}
|
|||
|
static void to_line_head(const wchar_t** str)
|
|||
|
{
|
|||
|
while (str[0][0] != L'\n')
|
|||
|
(*str)--;
|
|||
|
}
|
|||
|
static void erase_multiline_comment(std::wstring& cont)
|
|||
|
{
|
|||
|
for (int i = 0; i < cont.length(); ++i)
|
|||
|
{
|
|||
|
if (cont[i] == L'/')
|
|||
|
{
|
|||
|
if (cont[i + 1] == L'/')
|
|||
|
{
|
|||
|
std::wstring val(L"");
|
|||
|
int next = 0;
|
|||
|
coding_util::pick_line(cont.c_str() + i, got_wstr, &val, &next);
|
|||
|
i += next;
|
|||
|
}
|
|||
|
else if (cont[i + 1] == L'*')
|
|||
|
{
|
|||
|
size_t pos = cont.find(L"*/", i + 2);
|
|||
|
if (pos++ == std::wstring::npos)
|
|||
|
{
|
|||
|
cont.erase(i);
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
cont.erase(i, pos - i + 1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
static void transform_hz(std::wstring& hz)
|
|||
|
{
|
|||
|
int prev = -1;
|
|||
|
std::string inner("");
|
|||
|
for (int i = 0; i < hz.length() - 3; ++i)
|
|||
|
{
|
|||
|
if (hz[i] == L'\\')
|
|||
|
{
|
|||
|
if (hz[i + 1] == L'u')
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
else if (hz[i + 1] == L'x')
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
else if (hz[i + 1] >= L'0' && hz[i + 1] <= L'7')
|
|||
|
{
|
|||
|
if (hz[i + 2] >= L'0' && hz[i + 2] <= L'7' &&
|
|||
|
hz[i + 3] >= L'0' && hz[i + 3] <= L'7')
|
|||
|
{
|
|||
|
if (prev == -1)
|
|||
|
prev = i;
|
|||
|
char ch = (hz[i + 1] - L'0') * 64 + (hz[i + 2] - L'0') * 8 + hz[i + 3] - L'0';
|
|||
|
inner.append(1, ch);
|
|||
|
i += 3;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (inner.length())
|
|||
|
{
|
|||
|
std::wstring trans(L"");
|
|||
|
coding_util::utf8_2_unicode(inner.c_str(), got_wstr, &trans);
|
|||
|
hz.replace(prev, i - prev, trans);
|
|||
|
i = prev + trans.length();
|
|||
|
}
|
|||
|
prev = -1;
|
|||
|
inner = "";
|
|||
|
}
|
|||
|
}
|
|||
|
if (inner.length())
|
|||
|
{
|
|||
|
std::wstring trans(L"");
|
|||
|
coding_util::utf8_2_unicode(inner.c_str(), got_wstr, &trans);
|
|||
|
hz.replace(prev, hz.length() - prev, trans);
|
|||
|
}
|
|||
|
}
|
|||
|
static std::wstring now(void)
|
|||
|
{
|
|||
|
time_t t = time(NULL);
|
|||
|
tm* pt = localtime(&t);
|
|||
|
wchar_t buf[40] = { 0 };
|
|||
|
|
|||
|
swprintf_s(buf, _countof(buf) - 1, L"%04d-%02d-%02d %02d:%02d:%02d",
|
|||
|
pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec);
|
|||
|
|
|||
|
return buf;
|
|||
|
}
|
|||
|
static std::wstring get_text(HWND wnd)
|
|||
|
{
|
|||
|
int len = GetWindowTextLengthW(wnd);
|
|||
|
wchar_t * buf = new wchar_t[len + 128];
|
|||
|
std::wstring ret(L"");
|
|||
|
|
|||
|
len = ::GetWindowTextW(wnd, buf, len + 20);
|
|||
|
buf[len] = 0;
|
|||
|
ret = buf;
|
|||
|
delete[] buf;
|
|||
|
|
|||
|
return std::move(ret);
|
|||
|
}
|
|||
|
static void append_log(const wchar_t* log, HWND edit, bool scroll_last)
|
|||
|
{
|
|||
|
std::wstring text(std::move(get_text(edit))), cur(now() + L": "), str(log), space(L"");
|
|||
|
size_t pos = str.find(L"\r\n");
|
|||
|
|
|||
|
space.append(cur.length() * 2, L' ');
|
|||
|
while (pos != std::wstring::npos && pos < str.length() - 2)
|
|||
|
{
|
|||
|
str.insert(pos + 2, space);
|
|||
|
pos = str.find(L"\r\n", pos + space.length() + 2);
|
|||
|
}
|
|||
|
text += cur + str;
|
|||
|
::SetWindowTextW(edit, text.c_str());
|
|||
|
if (scroll_last)
|
|||
|
::SendMessage(edit, EM_LINESCROLL, 0, ::SendMessageW(edit, EM_GETLINECOUNT, 0, 0));
|
|||
|
else
|
|||
|
::SendMessageW(edit, EM_LINESCROLL, 0, (LPARAM)::GetPropW(edit, L"stop_line"));
|
|||
|
}
|
|||
|
static std::wstring load_file(const wchar_t* file, int *bom)
|
|||
|
{
|
|||
|
std::wstring cont(L"");
|
|||
|
std::string raw("");
|
|||
|
|
|||
|
file_util::load_file(file, got_str, &raw);
|
|||
|
if (raw.empty())
|
|||
|
return false;
|
|||
|
if (bom)
|
|||
|
*bom = coding_util::bom::is_unicode(raw.c_str(), NULL) ? BOM_UNICODE : (coding_util::bom::is_utf8(raw.c_str()) ? BOM_UTF8 : BOM_ANSI);
|
|||
|
coding_util::bom::to_unicode(raw.c_str(), raw.length(), got_wstr, &cont);
|
|||
|
|
|||
|
return std::move(cont);
|
|||
|
}
|
|||
|
static bool save_file(const wchar_t* file, const wchar_t* cont, int bom, std::wstring* bak = NULL)
|
|||
|
{
|
|||
|
std::string raw("");
|
|||
|
if (bom == BOM_UNICODE)
|
|||
|
coding_util::bom::from_unicode(cont, lstrlenW(cont) * 2, got_str, &raw);
|
|||
|
else if (bom == BOM_UTF8)
|
|||
|
{
|
|||
|
std::string utf8("");
|
|||
|
coding_util::unicode_2_utf8(cont, got_str, &utf8);
|
|||
|
coding_util::bom::from_utf8(utf8.c_str(), utf8.length(), got_str, &raw);
|
|||
|
}
|
|||
|
else
|
|||
|
coding_util::unicode_2_ansi(cont, got_str, &raw);
|
|||
|
|
|||
|
if (bak)
|
|||
|
{
|
|||
|
*bak = file;
|
|||
|
*bak += L".bak";
|
|||
|
file_util::force_copy_file(file, bak->c_str());
|
|||
|
}
|
|||
|
|
|||
|
return file_util::save_2_file(raw.c_str(), raw.length(), file) == 0;
|
|||
|
}
|
|||
|
std::string u2a(const wchar_t* u, bool to_utf8 = false)
|
|||
|
{
|
|||
|
std::string a("");
|
|||
|
|
|||
|
if (to_utf8)
|
|||
|
coding_util::unicode_2_utf8(u, got_str, &a);
|
|||
|
else
|
|||
|
coding_util::unicode_2_ansi(u, got_str, &a);
|
|||
|
|
|||
|
return std::move(a);
|
|||
|
}
|
|||
|
std::wstring a2u(const char* a, bool from_utf8 = false)
|
|||
|
{
|
|||
|
std::wstring u(L"");
|
|||
|
|
|||
|
if (from_utf8)
|
|||
|
coding_util::utf8_2_unicode(a, got_wstr, &u);
|
|||
|
else
|
|||
|
coding_util::ansi_2_unicode(a, got_wstr, &u);
|
|||
|
|
|||
|
return std::move(u);
|
|||
|
}
|
|||
|
|
|||
|
static std::wstring get_sane_opt_title(const wchar_t* key, const std::wstring& cont)
|
|||
|
{
|
|||
|
size_t pos = cont.find(key);
|
|||
|
std::wstring title(L"");
|
|||
|
|
|||
|
while (pos != std::wstring::npos)
|
|||
|
{
|
|||
|
if (pos)
|
|||
|
{
|
|||
|
int check = pos - 1;
|
|||
|
if (cont[check] == L' ' || cont[check] == L'\t')
|
|||
|
{
|
|||
|
const wchar_t* l = cont.c_str() + check;
|
|||
|
to_line_head(&l);
|
|||
|
skip_space(&l);
|
|||
|
if (wcsstr(l, L"#define") == l)
|
|||
|
{
|
|||
|
l += 7;
|
|||
|
skip_space(&l);
|
|||
|
if (wcsstr(l, key) == l)
|
|||
|
{
|
|||
|
l += lstrlenW(key);
|
|||
|
if (skip_space(&l) && *l++ == L'\"')
|
|||
|
{
|
|||
|
while (*l != L'\r' && *l != L'\n' && *l != L'\"' && *l != 0)
|
|||
|
title.append(1, *l++);
|
|||
|
transform_hz(title);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
pos += lstrlenW(key);
|
|||
|
pos = cont.find(key, pos);
|
|||
|
}
|
|||
|
|
|||
|
return std::move(title);
|
|||
|
}
|
|||
|
static void get_sane_opts(const wchar_t* file, std::vector<SANEOPT>& opts)
|
|||
|
{
|
|||
|
std::wstring tf(file), name(L"\r\n"), title(L"\r\n")
|
|||
|
, pre_n(L"SANE_STD_OPT_NAME_"), pre_t(L"OPTION_TITLE_"), define(L"#define")
|
|||
|
, line(L""), val(L"");
|
|||
|
std::string bom("");
|
|||
|
SANEOPT opt;
|
|||
|
int off = 0, next = 0;
|
|||
|
|
|||
|
STR_PARENT_FOLDER(tf);
|
|||
|
tf += L"\\sane_option_definitions.h";
|
|||
|
STR_TO_ABSOLUTE_PATH(tf);
|
|||
|
|
|||
|
file_util::load_file(file, got_str, &bom);
|
|||
|
if (bom.empty())
|
|||
|
return;
|
|||
|
coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &name);
|
|||
|
erase_multiline_comment(name);
|
|||
|
|
|||
|
bom = "";
|
|||
|
file_util::load_file(tf.c_str(), got_str, &bom);
|
|||
|
if (bom.empty())
|
|||
|
return;
|
|||
|
coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &title);
|
|||
|
bom = "";
|
|||
|
erase_multiline_comment(title);
|
|||
|
|
|||
|
// search ...
|
|||
|
coding_util::pick_line(name.c_str(), got_wstr, &line, &next);
|
|||
|
while (line.length() || next)
|
|||
|
{
|
|||
|
size_t pos = line.find(define);
|
|||
|
if (pos == 0 && line.length() > define.length() && is_space(line[define.length()]))
|
|||
|
{
|
|||
|
const wchar_t* str = line.c_str() + define.length(), * bgn = NULL;;
|
|||
|
util::skip_space(&str);
|
|||
|
if (wcsstr(str, pre_n.c_str()) == str)
|
|||
|
{
|
|||
|
bgn = str;
|
|||
|
str += pre_n.length();
|
|||
|
while (is_var_char(*str, true))
|
|||
|
str++;
|
|||
|
opt.name_key = std::wstring(bgn, str - bgn);
|
|||
|
if (util::skip_space(&str) && *str++ == L'\"')
|
|||
|
{
|
|||
|
bgn = str;
|
|||
|
while (*str != L'\"')
|
|||
|
str++;
|
|||
|
opt.name = std::wstring(bgn, str - bgn);
|
|||
|
str++;
|
|||
|
util::skip_space(&str);
|
|||
|
if (wcsstr(str, L"//") == str)
|
|||
|
{
|
|||
|
str += 2;
|
|||
|
util::skip_space(&str);
|
|||
|
if (wcsstr(str, pre_t.c_str()) == str)
|
|||
|
{
|
|||
|
bgn = str;
|
|||
|
str += pre_t.length();
|
|||
|
while (is_var_char(*str, true))
|
|||
|
str++;
|
|||
|
opt.title_key = std::wstring(bgn, str - bgn);
|
|||
|
opt.title = std::move(get_sane_opt_title(opt.title_key.c_str(), title));
|
|||
|
opts.push_back(opt);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
off += next;
|
|||
|
line = L"";
|
|||
|
coding_util::pick_line(name.c_str() + off, got_wstr, &line, &next);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static bool pick_option_id_function(std::wstring& code, int* off = NULL, const wchar_t* api_decl = L"scanner::init_options_id(void)", const wchar_t* ret = L"int")
|
|||
|
{
|
|||
|
std::wstring api(api_decl);
|
|||
|
size_t pos = code.find(api);
|
|||
|
const wchar_t* l = NULL;
|
|||
|
|
|||
|
while (pos != std::wstring::npos)
|
|||
|
{
|
|||
|
l = code.c_str() + pos;
|
|||
|
to_line_head(&l);
|
|||
|
skip_space(&l);
|
|||
|
if (wcsstr(l, ret) == l)
|
|||
|
{
|
|||
|
l += lstrlenW(ret);
|
|||
|
if (skip_space(&l))
|
|||
|
{
|
|||
|
if (wcsstr(l, api.c_str()) == l)
|
|||
|
{
|
|||
|
int bgn = 0, end = 0;
|
|||
|
|
|||
|
coding_util::pick_value(l, L"{", L"}", &bgn, &end);
|
|||
|
if (end > bgn)
|
|||
|
{
|
|||
|
api = std::wstring(l + bgn, end - bgn + 1);
|
|||
|
if (off)
|
|||
|
*off = l + bgn - code.c_str();
|
|||
|
code = std::move(api);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
pos += api.length();
|
|||
|
pos = code.find(api, pos);
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
static bool pick_twain_ex_enum(std::wstring& code, int* start = NULL)
|
|||
|
{
|
|||
|
// enum CapTypeEx : unsigned short {
|
|||
|
size_t pos = code.find(L"enum");
|
|||
|
|
|||
|
while (pos != std::wstring::npos)
|
|||
|
{
|
|||
|
const wchar_t* l = code.c_str() + pos;
|
|||
|
to_line_head(&l);
|
|||
|
skip_space(&l);
|
|||
|
if (wcsstr(l, L"enum") == l)
|
|||
|
{
|
|||
|
l += 4;
|
|||
|
if (skip_space(&l))
|
|||
|
{
|
|||
|
if (wcsstr(l, L"CapTypeEx") == l)
|
|||
|
{
|
|||
|
int bgn = 0, end = 0;
|
|||
|
coding_util::pick_value(l, L"{", L"}", &bgn, &end);
|
|||
|
if (start)
|
|||
|
*start = l + bgn - code.c_str();
|
|||
|
code = std::move(std::wstring(l + bgn, end - bgn + 1));
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
pos = code.find(L"enum", pos + 4);
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
static bool get_twain_id(const std::wstring& idtext, std::vector<OPTUSED>& used)
|
|||
|
{
|
|||
|
std::wstring pre(L"CAP_EX_SANE_"), line(L""), key(L"");
|
|||
|
OPTUSED ou;
|
|||
|
int off = 0, next = 0, id = 0x8801;
|
|||
|
|
|||
|
coding_util::pick_line(idtext.c_str(), got_wstr, &line, &next);
|
|||
|
while (!line.empty() || next)
|
|||
|
{
|
|||
|
const wchar_t* bgn = line.c_str(), * l = bgn;
|
|||
|
skip_space(&l);
|
|||
|
if (wcsstr(l, pre.c_str()) == l)
|
|||
|
{
|
|||
|
l += pre.length();
|
|||
|
bgn = l;
|
|||
|
while (is_var_char(*l, true))
|
|||
|
l++;
|
|||
|
key = std::wstring(bgn, l - bgn);
|
|||
|
ou.id_key = "";
|
|||
|
coding_util::unicode_2_ansi(key.c_str(), got_str, &ou.id_key);
|
|||
|
ou.id = id++;
|
|||
|
used.push_back(ou);
|
|||
|
}
|
|||
|
|
|||
|
off += next;
|
|||
|
line.clear();
|
|||
|
coding_util::pick_line(idtext.c_str() + off, got_wstr, &line, &next);
|
|||
|
}
|
|||
|
std::sort(used.begin(), used.end());
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
static void get_used_opts(const wchar_t* file, std::vector<OPTUSED>& used)
|
|||
|
{
|
|||
|
std::wstring key(L""), id(L""), idf(file), line(L""), pre_nk(L"SANE_STD_OPT_NAME_"), pre_ik(L"CAP_EX_SANE_"), setoid(L"SET_OPT_ID(");
|
|||
|
std::string bom("");
|
|||
|
OPTUSED ou;
|
|||
|
int off = 0, next = 0;
|
|||
|
|
|||
|
STR_PARENT_FOLDER(idf);
|
|||
|
idf += L"\\..\\..\\code_twain\\twain\\twain\\huagaods.cpp";
|
|||
|
STR_TO_ABSOLUTE_PATH(idf);
|
|||
|
|
|||
|
file_util::load_file(file, got_str, &bom);
|
|||
|
if (bom.empty())
|
|||
|
return;
|
|||
|
coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &key);
|
|||
|
erase_multiline_comment(key);
|
|||
|
|
|||
|
bom = "";
|
|||
|
file_util::load_file(idf.c_str(), got_str, &bom);
|
|||
|
if (bom.empty())
|
|||
|
return;
|
|||
|
coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &id);
|
|||
|
erase_multiline_comment(id);
|
|||
|
get_twain_id(id, used);
|
|||
|
|
|||
|
if (!pick_option_id_function(key) || !pick_twain_ex_enum(id))
|
|||
|
return;
|
|||
|
|
|||
|
bom = "";
|
|||
|
coding_util::pick_line(key.c_str(), got_wstr, &line, &next);
|
|||
|
while (!line.empty() || next > 0)
|
|||
|
{
|
|||
|
const wchar_t* l = line.c_str(), * bgn = NULL;
|
|||
|
skip_space(&l);
|
|||
|
if (wcsstr(l, L"else") == l)
|
|||
|
{
|
|||
|
l += 4;
|
|||
|
skip_space(&l);
|
|||
|
}
|
|||
|
if (wcsstr(l, setoid.c_str()) == l)
|
|||
|
{
|
|||
|
l += setoid.length();
|
|||
|
bgn = l;
|
|||
|
if (is_var_char(*l++, false))
|
|||
|
{
|
|||
|
while (is_var_char(*l, true))
|
|||
|
l++;
|
|||
|
ou.id_key = "";
|
|||
|
coding_util::unicode_2_ansi(std::wstring(bgn, l - bgn).c_str(), got_str, &ou.id_key);
|
|||
|
skip_space(&l);
|
|||
|
if (*l++ == L',')
|
|||
|
{
|
|||
|
skip_space(&l);
|
|||
|
bgn = l;
|
|||
|
if (is_var_char(*l++, false))
|
|||
|
{
|
|||
|
while (is_var_char(*l, true))
|
|||
|
l++;
|
|||
|
ou.name_key = std::wstring(bgn, l - bgn);
|
|||
|
|
|||
|
std::vector<OPTUSED>::iterator it = std::find(used.begin(), used.end(), ou.id_key.c_str());
|
|||
|
if (it != used.end())
|
|||
|
it->name_key = std::move(L"SANE_STD_OPT_NAME_" + ou.name_key);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
off += next;
|
|||
|
line = L"";
|
|||
|
coding_util::pick_line(key.c_str() + off, got_wstr, &line, &next);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static bool add_2_huagaods_cpp(const wchar_t* file, const SANEOPT& sane, const OPTUSED& twain, std::wstring* msg)
|
|||
|
{
|
|||
|
int off = 0, next = 0, bom = BOM_ANSI;
|
|||
|
std::wstring cont(std::move(load_file(file, &bom))), line(L""), lead(L"CAP_EX_SANE_");
|
|||
|
|
|||
|
if (cont.empty())
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg = L"File 'huagaods.cpp' is not found or empty.";
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
line = cont;
|
|||
|
if (pick_twain_ex_enum(line, &off))
|
|||
|
{
|
|||
|
size_t pos = line.rfind(L',');
|
|||
|
const wchar_t* l = line.c_str() + pos, * bgn = NULL;
|
|||
|
|
|||
|
to_line_head(&l);
|
|||
|
bgn = ++l;
|
|||
|
skip_space(&l);
|
|||
|
|
|||
|
std::wstring en(bgn, l - bgn);
|
|||
|
|
|||
|
en += lead + a2u(twain.id_key.c_str()) + L",\t\t// " + now() + L" " + sane.title;
|
|||
|
lead = line;
|
|||
|
lead.insert(pos + 1, L"\r\n" + en);
|
|||
|
cont.replace(off, line.length(), lead);
|
|||
|
|
|||
|
line = cont;
|
|||
|
if (pick_option_id_function(line, &off, L"huagao_ds::init_support_caps_ex(void)", L"void"))
|
|||
|
{
|
|||
|
pos = line.rfind(L';');
|
|||
|
l = line.c_str() + pos;
|
|||
|
to_line_head(&l);
|
|||
|
l++;
|
|||
|
bgn = l;
|
|||
|
skip_space(&l);
|
|||
|
en = std::wstring(bgn, l - bgn);
|
|||
|
en += L"ADD_SANE_CAP(";
|
|||
|
en += a2u(twain.id_key.c_str());
|
|||
|
en += L");\r\n";
|
|||
|
lead = line + en;
|
|||
|
cont.replace(off, line.length(), lead);
|
|||
|
|
|||
|
if (save_file(file, cont.c_str(), bom, &line))
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg += std::wstring(L"Changed: ") + file + L"\r\n";
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
*msg = L"Failed to save changes into file 'huagaods.cpp'.";
|
|||
|
|
|||
|
if (file_util::is_file_existing(line.c_str()))
|
|||
|
file_util::force_move_file(line.c_str(), file);
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to find function 'huagao_ds::init_support_caps_ex(void)' in huagaods.cpp.";
|
|||
|
}
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to find 'enum CapTypeEx' in huagaods.cpp.";
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
static bool add_2_scanner_codes(const wchar_t* cpp, const SANEOPT& sane, const OPTUSED& twain, std::wstring* msg)
|
|||
|
{
|
|||
|
int bom_c = BOM_ANSI, bom_h = BOM_ANSI;
|
|||
|
std::wstring hf(cpp), code_c(load_file(cpp, &bom_c)), code_h(L""), tag(L"// SANE options ID ..."), val(L""), hbak(L""), cbak(L"");
|
|||
|
size_t pos = hf.rfind(L'.');
|
|||
|
const wchar_t *l = NULL, *bgn = NULL;
|
|||
|
|
|||
|
if (code_c.empty())
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg = std::wstring(L"File '") + cpp + L"' is not found or empty.";
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
hf.erase(pos);
|
|||
|
hf += L".h";
|
|||
|
code_h = std::move(load_file(hf.c_str(), &bom_h));
|
|||
|
if (code_h.empty())
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg = std::wstring(L"File '") + hf + L"' is not found or empty.";
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
pos = code_h.find(tag);
|
|||
|
if (pos == std::wstring::npos)
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg = L"Cannot find tag '" + tag + L"' in file " + hf;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
bgn = l = code_h.c_str() + pos;
|
|||
|
to_line_head(&bgn);
|
|||
|
bgn++;
|
|||
|
val = L"\r\n" + std::wstring(bgn, l - bgn) + L"SANE_OPTION_ID(" + a2u(twain.id_key.c_str()) + L");";
|
|||
|
code_h.insert(pos + tag.length(), val + L"\t\t// " + now() + L" " + sane.title);
|
|||
|
if (save_file(hf.c_str(), code_h.c_str(), bom_h, &hbak))
|
|||
|
{
|
|||
|
code_h.clear();
|
|||
|
|
|||
|
pos = code_c.find(L"SANE_OPTION_ID_IMPLEMENT(");
|
|||
|
if (pos != std::wstring::npos)
|
|||
|
{
|
|||
|
int off = 0;
|
|||
|
|
|||
|
val = L"SANE_OPTION_ID_IMPLEMENT(" + a2u(twain.id_key.c_str()) + L")\r\n";
|
|||
|
code_c.insert(pos, val);
|
|||
|
code_h = code_c;
|
|||
|
if (pick_option_id_function(code_h, &off))
|
|||
|
{
|
|||
|
pos = code_h.find(L"op_id++;");
|
|||
|
if (pos != std::wstring::npos)
|
|||
|
{
|
|||
|
l = bgn = code_h.c_str() + pos;
|
|||
|
to_line_head(&bgn);
|
|||
|
bgn++;
|
|||
|
tag = sane.name_key;
|
|||
|
if (tag.find(L"SANE_STD_OPT_NAME_") == 0)
|
|||
|
tag.erase(0, lstrlenW(L"SANE_STD_OPT_NAME_"));
|
|||
|
val = std::wstring(bgn, l - bgn) + L"else SET_OPT_ID(" + a2u(twain.id_key.c_str()) + L", " + tag + L", extension_none)\r\n";
|
|||
|
off += bgn - code_h.c_str();
|
|||
|
code_c.insert(off, val);
|
|||
|
if (save_file(cpp, code_c.c_str(), bom_c, &cbak))
|
|||
|
{
|
|||
|
std::wstring s2t(hf);
|
|||
|
|
|||
|
STR_PARENT_FOLDER(s2t);
|
|||
|
s2t += L"\\s2t_api.h";
|
|||
|
code_h = std::move(load_file(s2t.c_str(), &bom_h));
|
|||
|
if (!code_h.empty())
|
|||
|
{
|
|||
|
tag = L"// SANE options ID ...";
|
|||
|
pos = code_h.find(tag);
|
|||
|
if (pos == std::wstring::npos)
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg = L"Cannot find tag '// SANE options ID ...' in file " + s2t;
|
|||
|
return false;
|
|||
|
}
|
|||
|
bgn = l = code_h.c_str() + pos;
|
|||
|
to_line_head(&bgn);
|
|||
|
bgn++;
|
|||
|
val = L"\r\n" + std::wstring(bgn, l - bgn) + L"SANE_OPTION_ID_API(" + a2u(twain.id_key.c_str()) + L");";
|
|||
|
code_h.insert(pos + tag.length(), val + L"\t\t// " + now() + L" " + sane.title);
|
|||
|
|
|||
|
if (save_file(s2t.c_str(), code_h.c_str(), bom_h, &val))
|
|||
|
{
|
|||
|
if (msg)
|
|||
|
*msg += std::wstring(L"Changed: ") + hf + L"\r\n" + L"Changed: " + cpp + L"\r\nChanged: " + s2t + L"\r\n";
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
*msg = L"Failed to save changes into file: " + s2t;
|
|||
|
if (file_util::is_file_existing(val.c_str()))
|
|||
|
file_util::force_move_file(val.c_str(), s2t.c_str());
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
*msg = std::wstring(L"File '") + s2t + L"' is not found or empty.";
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to save changes into file: " + std::wstring(cpp);
|
|||
|
}
|
|||
|
|
|||
|
if (file_util::is_file_existing(cbak.c_str()))
|
|||
|
file_util::force_move_file(cbak.c_str(), cpp);
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to find function 'scanner::init_options_id(void) - op_id++' in file: " + std::wstring(cpp);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to find function 'scanner::init_options_id(void)' in file: " + std::wstring(cpp);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to find 'SANE_OPTION_ID_IMPLEMENT' in file: " + std::wstring(cpp);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (msg)
|
|||
|
{
|
|||
|
*msg = L"Failed to save changes into file: " + hf;
|
|||
|
}
|
|||
|
|
|||
|
if (file_util::is_file_existing(hbak.c_str()))
|
|||
|
file_util::force_move_file(hbak.c_str(), hf.c_str());
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// CDlgTwain dialog
|
|||
|
|
|||
|
IMPLEMENT_DYNAMIC(CDlgTwain, CDialogEx)
|
|||
|
|
|||
|
CDlgTwain::CDlgTwain(CWnd* pParent /*=NULL*/)
|
|||
|
: CDialogEx(CDlgTwain::IDD, pParent)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
CDlgTwain::~CDlgTwain()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void CDlgTwain::DoDataExchange(CDataExchange* pDX)
|
|||
|
{
|
|||
|
CDialogEx::DoDataExchange(pDX);
|
|||
|
DDX_Control(pDX, IDC_COMBO1, sane_);
|
|||
|
}
|
|||
|
BOOL CDlgTwain::OnInitDialog()
|
|||
|
{
|
|||
|
CDialogEx::OnInitDialog();
|
|||
|
|
|||
|
// Set the icon for this dialog. The framework does this automatically
|
|||
|
// when the application's main window is not a dialog
|
|||
|
|
|||
|
return TRUE; // return TRUE unless you set the focus to a control
|
|||
|
}
|
|||
|
void CDlgTwain::on_sln_path_changed(void)
|
|||
|
{
|
|||
|
GetDlgItem(IDC_BUTTON_BROWSE)->EnableWindow(FALSE);
|
|||
|
GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(FALSE);
|
|||
|
GetDlgItem(IDC_COMBO1)->EnableWindow(FALSE);
|
|||
|
|
|||
|
util::append_log(L"parsing SANE attributes ...\r\n", GetDlgItem(IDC_EDIT2)->m_hWnd, true);
|
|||
|
sane_.ResetContent();
|
|||
|
|
|||
|
std::wstring path(util::get_text(GetDlgItem(IDC_EDIT1)->m_hWnd));
|
|||
|
|
|||
|
opts_.clear();
|
|||
|
used_.clear();
|
|||
|
|
|||
|
STR_PARENT_FOLDER(path);
|
|||
|
path += L"\\..\\..\\";
|
|||
|
STR_TO_ABSOLUTE_PATH(path);
|
|||
|
root_ = path;
|
|||
|
util::get_sane_opts((path + L"sdk\\include\\sane\\sane_ex.h").c_str(), opts_);
|
|||
|
if (opts_.size() == 0)
|
|||
|
{
|
|||
|
::MessageBoxW(m_hWnd, L"û<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD>SANE<EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD>塣", L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", MB_OK | MB_ICONSTOP);
|
|||
|
return;
|
|||
|
}
|
|||
|
for (auto& v : opts_)
|
|||
|
sane_.AddString((v.title + L" (" + v.name + L")").c_str());
|
|||
|
|
|||
|
GetDlgItem(IDC_BUTTON_BROWSE)->EnableWindow(TRUE);
|
|||
|
GetDlgItem(IDC_COMBO1)->EnableWindow(TRUE);
|
|||
|
GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
|
|||
|
util::append_log((L"Found " + std::to_wstring(opts_.size()) + L" options\r\n").c_str(), GetDlgItem(IDC_EDIT2)->m_hWnd, true);
|
|||
|
|
|||
|
// find used ...
|
|||
|
util::get_used_opts((path + L"code_twain\\sane\\scanner.cpp").c_str(), used_);
|
|||
|
}
|
|||
|
void CDlgTwain::synchronize_opt(const SANEOPT& opt)
|
|||
|
{
|
|||
|
OPTUSED ou;
|
|||
|
std::wstring pre(L"SANE_STD_OPT_NAME_"), key(L""), msg(L"");
|
|||
|
|
|||
|
if (used_.size())
|
|||
|
ou.id = used_[used_.size() - 1].id + 1;
|
|||
|
else
|
|||
|
ou.id = 0x8801;
|
|||
|
|
|||
|
ou.name_key = opt.name_key;
|
|||
|
if (ou.name_key.find(pre) == 0)
|
|||
|
key = ou.name_key.substr(pre.length());
|
|||
|
else
|
|||
|
key = ou.name_key;
|
|||
|
std::transform(key.begin(), key.end(), key.begin(), tolower);
|
|||
|
coding_util::unicode_2_ansi(key.c_str(), util::got_str, &ou.id_key);
|
|||
|
|
|||
|
std::vector<OPTUSED>::iterator it = std::find(used_.begin(), used_.end(), ou.id_key.c_str());
|
|||
|
if (it != used_.end())
|
|||
|
{
|
|||
|
::MessageBoxW(m_hWnd, (opt.title + L" already synchronized into TWAIN.").c_str(), L"Error", MB_OK | MB_ICONINFORMATION);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (util::add_2_huagaods_cpp((root_ + L"code_twain\\twain\\twain\\huagaods.cpp").c_str(), opt, ou, &msg) &&
|
|||
|
util::add_2_scanner_codes((root_ + L"code_twain\\sane\\scanner.cpp").c_str(), opt, ou, &msg))
|
|||
|
{
|
|||
|
used_.push_back(ou);
|
|||
|
|
|||
|
std::wstring tips(L"Added New TWAIN extended ATTR: CAP_EX_SANE_");
|
|||
|
wchar_t hex[40] = { 0 };
|
|||
|
|
|||
|
coding_util::ansi_2_unicode(ou.id_key.c_str(), util::got_wstr, &tips);
|
|||
|
swprintf_s(hex, _countof(hex) - 1, L" (ID: 0x%04x) - ", ou.id);
|
|||
|
tips += hex + opt.title + L"\r\n";
|
|||
|
util::append_log(tips.c_str(), GetDlgItem(IDC_EDIT2)->m_hWnd, true);
|
|||
|
}
|
|||
|
util::append_log(msg.c_str(), GetDlgItem(IDC_EDIT2)->m_hWnd, true);
|
|||
|
}
|
|||
|
|
|||
|
BEGIN_MESSAGE_MAP(CDlgTwain, CDialogEx)
|
|||
|
ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CDlgTwain::OnBnClickedButtonBrowse)
|
|||
|
ON_BN_CLICKED(IDC_BUTTON_ADD, &CDlgTwain::OnBnClickedButtonAdd)
|
|||
|
END_MESSAGE_MAP()
|
|||
|
|
|||
|
|
|||
|
// CDlgTwain message handlers
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void CDlgTwain::OnBnClickedButtonBrowse()
|
|||
|
{
|
|||
|
// TODO: <20>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD>ӿؼ<D3BF>֪ͨ<CDA8><D6AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
file_util::PATHFILE path = { 0 };
|
|||
|
|
|||
|
if (file_util::browser_file(m_hWnd, &path, L"Solution File(*.sln)\0\0"))
|
|||
|
{
|
|||
|
::SetDlgItemTextW(m_hWnd, IDC_EDIT1, path.path);
|
|||
|
on_sln_path_changed();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void CDlgTwain::OnBnClickedButtonAdd()
|
|||
|
{
|
|||
|
// TODO: <20>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD>ӿؼ<D3BF>֪ͨ<CDA8><D6AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
std::wstring text(util::get_text(sane_.m_hWnd));
|
|||
|
std::string ansi("");
|
|||
|
size_t pos = text.rfind(L'(');
|
|||
|
|
|||
|
if (pos++ == std::wstring::npos)
|
|||
|
{
|
|||
|
::MessageBoxW(m_hWnd, L"Invalid option name! (lost '()')", L"Error", MB_OK | MB_ICONSTOP);
|
|||
|
return;
|
|||
|
}
|
|||
|
text.erase(0, pos);
|
|||
|
pos = text.find(L")");
|
|||
|
if (pos != std::wstring::npos)
|
|||
|
text.erase(pos);
|
|||
|
if (text.empty())
|
|||
|
{
|
|||
|
::MessageBoxW(m_hWnd, L"Invalid option name! (empty)", L"Error", MB_OK | MB_ICONSTOP);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
coding_util::unicode_2_ansi(text.c_str(), util::got_str, &ansi);
|
|||
|
|
|||
|
pos = sane_.GetCurSel();
|
|||
|
synchronize_opt(opts_[pos]);
|
|||
|
}
|