diff --git a/build/windows/HGSolution.sln b/build/windows/HGSolution.sln index 4127dfcb..30f72162 100644 --- a/build/windows/HGSolution.sln +++ b/build/windows/HGSolution.sln @@ -58,6 +58,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HGScannerLib", "HGScannerLi {4909ACEA-80FF-482E-9FA2-5E8534789A82} = {4909ACEA-80FF-482E-9FA2-5E8534789A82} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HGWebScan", "HGWebScan\HGWebScan.vcxproj", "{2A4A0C71-D333-4978-B7C4-08401230E0A5}" + ProjectSection(ProjectDependencies) = postProject + {F85F4457-1B42-46E7-BA86-F088D6D5994F} = {F85F4457-1B42-46E7-BA86-F088D6D5994F} + {5D85F2AC-FACD-436C-A67B-E13056DD0C03} = {5D85F2AC-FACD-436C-A67B-E13056DD0C03} + {4909ACEA-80FF-482E-9FA2-5E8534789A82} = {4909ACEA-80FF-482E-9FA2-5E8534789A82} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -230,6 +237,22 @@ Global {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x64.Build.0 = Release|x64 {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x86.ActiveCfg = Release|Win32 {62CAD8E9-4461-49A1-8EB8-4CEBE113FE02}.Release|x86.Build.0 = Release|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Debug|x64.ActiveCfg = Debug|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Debug|x64.Build.0 = Debug|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Debug|x86.ActiveCfg = Debug|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Debug|x86.Build.0 = Debug|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.HWRelease|x64.ActiveCfg = HWRelease|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.HWRelease|x64.Build.0 = HWRelease|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.HWRelease|x86.ActiveCfg = HWRelease|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.HWRelease|x86.Build.0 = HWRelease|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.LSCRelease|x64.ActiveCfg = LSCRelease|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.LSCRelease|x64.Build.0 = LSCRelease|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.LSCRelease|x86.ActiveCfg = LSCRelease|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.LSCRelease|x86.Build.0 = LSCRelease|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Release|x64.ActiveCfg = Release|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Release|x64.Build.0 = Release|x64 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Release|x86.ActiveCfg = Release|Win32 + {2A4A0C71-D333-4978-B7C4-08401230E0A5}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/build/windows/HGWebScan/HGWebScan.vcxproj b/build/windows/HGWebScan/HGWebScan.vcxproj new file mode 100644 index 00000000..b0b18bbc --- /dev/null +++ b/build/windows/HGWebScan/HGWebScan.vcxproj @@ -0,0 +1,353 @@ + + + + + Debug + Win32 + + + HWRelease + Win32 + + + HWRelease + x64 + + + LSCRelease + Win32 + + + LSCRelease + x64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + 16.0 + Win32Proj + {2A4A0C71-D333-4978-B7C4-08401230E0A5} + HGWebScan + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + false + v142 + true + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + false + v142 + true + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + false + HWWebScan + + + false + LSCWebScan + + + true + + + false + + + false + HWWebScan + + + false + LSCWebScan + + + + Level3 + true + WIN32;_DEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_HUAGAO;%(PreprocessorDefinitions) + true + MultiThreadedDebug + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + 28251;26812;%(DisableSpecificWarnings) + + + Windows + true + ../Debug/HGBase.lib;../Debug/HGImgFmt.lib;../Debug/HGImgProc.lib;../../../../sdk/lib/win/x86/OEM/huagao/sane.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/libcurl/windows/lib/x86/libcurld.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4098,4099,4075 %(AdditionalOptions) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_HUAGAO;%(PreprocessorDefinitions) + true + MultiThreaded + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + ../Release/HGBase.lib;../Release/HGImgFmt.lib;../Release/HGImgProc.lib;../../../../sdk/lib/win/x86/OEM/huagao/sane.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/libcurl/windows/lib/x86/libcurl.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4099 /LTCG %(AdditionalOptions) + + + copy $(OutDir)HGWebScan.exe $(SolutionDir)..\..\..\release\win\x86\Release\ + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_HANWANG;%(PreprocessorDefinitions) + true + MultiThreaded + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + ../HWRelease/HWBase.lib;../HWRelease/HWImgFmt.lib;../HWRelease/HWImgProc.lib;../../../../sdk/lib/win/x86/OEM/hanvon/sane.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/libcurl/windows/lib/x86/libcurl.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4099 /LTCG %(AdditionalOptions) + + + copy $(OutDir)HWWebScan.exe $(SolutionDir)..\..\..\release\win\x86\Release\ + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_LISICHENG;%(PreprocessorDefinitions) + true + MultiThreaded + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + ../LSCRelease/LSCBase.lib;../LSCRelease/LSCImgFmt.lib;../LSCRelease/LSCImgProc.lib;../../../../sdk/lib/win/x86/OEM/lanxum/sane.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/libcurl/windows/lib/x86/libcurl.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4099 /LTCG %(AdditionalOptions) + + + copy $(OutDir)LSCWebScan.exe $(SolutionDir)..\..\..\release\win\x86\Release\ + + + + + Level3 + true + _DEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_HUAGAO;%(PreprocessorDefinitions) + true + MultiThreadedDebug + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + ../x64/Debug/HGBase.lib;../x64/Debug/HGImgFmt.lib;../x64/Debug/HGImgProc.lib;../../../../sdk/lib/win/x64/OEM/huagao/sane.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/libcurl/windows/lib/x64/libcurld.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4098,4099,4075 %(AdditionalOptions) + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_HUAGAO;%(PreprocessorDefinitions) + true + MultiThreaded + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + ../x64/Release/HGBase.lib;../x64/Release/HGImgFmt.lib;../x64/Release/HGImgProc.lib;../../../../sdk/lib/win/x64/OEM/huagao/sane.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/libcurl/windows/lib/x64/libcurl.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4099 /LTCG %(AdditionalOptions) + + + copy $(OutDir)HGWebScan.exe $(SolutionDir)..\..\..\release\win\x64\Release\ + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_HANWANG;%(PreprocessorDefinitions) + true + MultiThreaded + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + ../x64/HWRelease/HWBase.lib;../x64/HWRelease/HWImgFmt.lib;../x64/HWRelease/HWImgProc.lib;../../../../sdk/lib/win/x64/OEM/hanvon/sane.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/libcurl/windows/lib/x64/libcurl.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4099 /LTCG %(AdditionalOptions) + + + copy $(OutDir)HWWebScan.exe $(SolutionDir)..\..\..\release\win\x64\Release\ + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_CONSOLE;_WINSOCK_DEPRECATED_NO_WARNINGS;ZIP_STATIC;CURL_STATICLIB;_CRT_SECURE_NO_WARNINGS;OEM_LISICHENG;%(PreprocessorDefinitions) + true + MultiThreaded + ../../../modules/;../../../third_party/sha1/;../../../third_party/base64/;../../../third_party/json/;../../../third_party/sqlite/;../../../utility/;../../../third_party/libzip/windows/include/;../../../third_party/libcurl/windows/include/;../../../../sdk/include/;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + ../x64/LSCRelease/LSCBase.lib;../x64/LSCRelease/LSCImgFmt.lib;../x64/LSCRelease/LSCImgProc.lib;../../../../sdk/lib/win/x64/OEM/lanxum/sane.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/libcurl/windows/lib/x64/libcurl.lib;wldap32.lib;ws2_32.lib;%(AdditionalDependencies) + /ignore:4099 /LTCG %(AdditionalOptions) + + + copy $(OutDir)LSCWebScan.exe $(SolutionDir)..\..\..\release\win\x64\Release\ + + + + + + \ No newline at end of file diff --git a/sdk/webscan/HttpHead.cpp b/sdk/webscan/HttpHead.cpp new file mode 100644 index 00000000..8788f529 --- /dev/null +++ b/sdk/webscan/HttpHead.cpp @@ -0,0 +1,438 @@ +#include "HttpHead.h" + +const unsigned int asciiTableData[256] = +{ + 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, + 0x004, 0x104, 0x104, 0x004, 0x104, 0x104, 0x004, 0x004, + 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, + 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, + 0x140, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, + 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, + 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, + 0x459, 0x459, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, + 0x0d0, 0x653, 0x653, 0x653, 0x653, 0x653, 0x653, 0x253, + 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, + 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, + 0x253, 0x253, 0x253, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, + 0x0d0, 0x473, 0x473, 0x473, 0x473, 0x473, 0x473, 0x073, + 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, + 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, + 0x073, 0x073, 0x073, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x004 + /* the upper 128 are all zeroes */ +}; + +static void TrimString(std::string& str) +{ + std::string str1; + bool add1 = false; + std::string::const_iterator iter1; + for (iter1 = str.begin(); iter1 != str.end(); ++iter1) + { + int c = (HGByte)(*iter1); + if (!add1) + { + if (!isspace(c)) + { + str1.push_back(c); + add1 = true; + } + } + else + { + str1.push_back(c); + } + } + + if (str1.empty()) + { + str.clear(); + return; + } + + std::string str2; + bool add2 = false; + std::string::const_reverse_iterator iter2; + for (iter2 = str1.rbegin(); iter2 != str1.rend(); ++iter2) + { + int c = (HGByte)(*iter2); + if (!add2) + { + if (!isspace(c)) + { + str2.push_back(c); + add2 = true; + } + } + else + { + str2.push_back(c); + } + } + + if (str2.empty()) + { + str.clear(); + return; + } + + str = std::string(str2.rbegin(), str2.rend()); +} + +HttpHead::HttpHead() +{ + +} + +HttpHead::~HttpHead() +{ + +} + +bool HttpHead::Parse(const std::string& head) +{ + AnalysisHead(head, m_requestMethod, m_requestURIPath, m_requestURIQueryInfos, + m_requestURIFragment, m_requestHttpVersion, m_headInfos); + return true; +} + +void HttpHead::Clear() +{ + m_requestMethod.clear(); + m_requestURIPath.clear(); + m_requestURIQueryInfos.clear(); + m_requestURIFragment.clear(); + m_requestHttpVersion.clear(); + m_headInfos.clear(); +} + +std::string HttpHead::GetRequestMethod() const +{ + return m_requestMethod; +} + +std::string HttpHead::GetRequestURIPath() const +{ + return m_requestURIPath; +} + +HttpPairs HttpHead::GetRequestURIQueryInfos() const +{ + return m_requestURIQueryInfos; +} + +std::string HttpHead::GetRequestURIFragment() const +{ + return m_requestURIFragment; +} + +std::string HttpHead::GetRequestHttpVersion() const +{ + return m_requestHttpVersion; +} + +HttpPairs HttpHead::GetHeadInfos() const +{ + return m_headInfos; +} + +int HttpHead::GetContentLength() const +{ + int len = 0; + for (int i = 0; i < (int)m_headInfos.size(); ++i) + { +#if defined(HG_CMP_MSC) + if (0 == _stricmp("Content-Length", m_headInfos[i].first.c_str())) +#else + if (0 == strcasecmp("Content-Length", m_headInfos[i].first.c_str())) +#endif + { + len = atoi(m_headInfos[i].second.c_str()); + break; + } + } + + return len; +} + +std::string HttpHead::GetContentType() const +{ + std::string type; + for (int i = 0; i < (int)m_headInfos.size(); ++i) + { +#if defined(HG_CMP_MSC) + if (0 == _stricmp("Content-Type", m_headInfos[i].first.c_str())) +#else + if (0 == strcasecmp("Content-Type", m_headInfos[i].first.c_str())) +#endif + { + type = m_headInfos[i].second.c_str(); + break; + } + } + + return type; +} + +std::string HttpHead::GetValue(const HttpPairs& infos, const std::string& key) +{ + std::string value; + for (int i = 0; i < (int)infos.size(); ++i) + { + if (key == infos[i].first) + { + value = infos[i].second; + break; + } + } + + return value; +} + +void HttpHead::AnalysisURIQuery(const std::string& query, HttpPairs& queryInfos) +{ + std::vector queryList; + + char* p = new char[query.size() + 1]; + strcpy(p, query.c_str()); + char* pStr = strtok(p, "&"); + if (NULL != pStr) + queryList.push_back(pStr); + while (1) + { + pStr = strtok(NULL, "&"); + if (NULL == pStr) + break; + queryList.push_back(pStr); + } + delete[] p; + + queryInfos.clear(); + for (int i = 0; i < (int)queryList.size(); ++i) + { + p = new char[queryList[i].size() + 1]; + strcpy(p, queryList[i].c_str()); + + std::pair pr; + pStr = strtok(p, "="); + if (NULL != pStr) + pr.first = AnalyURIString(pStr); + pStr = strtok(NULL, "="); + if (NULL != pStr) + pr.second = AnalyURIString(pStr); + + queryInfos.push_back(pr); + delete[] p; + } +} + +void HttpHead::AnalysisURI(const std::string& uri, std::string& path, HttpPairs& queryInfos, std::string& fragment) +{ + size_t pathPos = uri.find('/'); + size_t queryPos = uri.find('?'); + size_t fragmentPos = uri.find('#'); + + path.clear(); + if (std::string::npos != pathPos) + { + size_t count = std::string::npos; + if (queryPos != std::string::npos) + { + assert(queryPos > pathPos); + count = queryPos - pathPos; + } + else if (fragmentPos != std::string::npos) + { + assert(fragmentPos > pathPos); + count = fragmentPos - pathPos; + } + + path = AnalyURIString(uri.substr(pathPos, count)); + } + + queryInfos.clear(); + if (std::string::npos != queryPos) + { + size_t count = std::string::npos; + if (fragmentPos != std::string::npos) + { + assert(fragmentPos > queryPos); + count = fragmentPos - queryPos; + } + + std::string query = uri.substr(queryPos + 1, count - 1); + AnalysisURIQuery(query, queryInfos); + } + + fragment.clear(); + if (std::string::npos != fragmentPos) + { + fragment = AnalyURIString(uri.substr(fragmentPos + 1)); + } +} + +void HttpHead::AnalysisHead(const std::string& head, std::string& requestMethod, std::string& requestURIPath, + HttpPairs& requestURIQueryInfos, std::string& requestURIFragment, std::string& httpVersion, HttpPairs& headInfos) +{ + requestMethod.clear(); + requestURIPath.clear(); + requestURIQueryInfos.clear(); + requestURIFragment.clear(); + httpVersion.clear(); + headInfos.clear(); + + std::vector headList; + + char* p = new char[head.size() + 1]; + strcpy(p, head.c_str()); + char* pStr = strtok(p, "\r\n"); + if (NULL != pStr) + headList.push_back(pStr); + while (1) + { + pStr = strtok(NULL, "\r\n"); + if (NULL == pStr) + break; + headList.push_back(pStr); + } + delete[] p; + + if (headList.size() < 1) + { + return; + } + + std::string requestURI; + + // 解析请求行 + p = new char[headList[0].size() + 1]; + strcpy(p, headList[0].c_str()); + pStr = strtok(p, " "); + if (NULL != pStr) + requestMethod = pStr; + pStr = strtok(NULL, " "); + if (NULL != pStr) + requestURI = pStr; + pStr = strtok(NULL, " "); + if (NULL != pStr) + httpVersion = pStr; + delete[] p; + + // 解析URI + AnalysisURI(requestURI, requestURIPath, requestURIQueryInfos, requestURIFragment); + + // 解析请求头 + for (int i = 1; i < (int)headList.size(); ++i) + { + p = new char[headList[i].size() + 1]; + strcpy(p, headList[i].c_str()); + + std::pair pr; + pStr = strtok(p, ":"); + if (NULL != pStr) + pr.first = pStr; + pStr = strtok(NULL, ":"); + if (NULL != pStr) + pr.second = pStr; + + TrimString(pr.first); + TrimString(pr.second); + headInfos.push_back(pr); + + delete[] p; + } +} + +/*判断ascii码是否是数字0-9*/ +static bool asciiIsDigit(char c) +{ + /*字符的ascii码&8 结果为0-127,则是数字*/ + return asciiTableData[(unsigned char)c & (1 << 3)]; +} + +static int asciiDigitValue(char c) +{ + if (asciiIsDigit(c)) + return c - '0'; + return -1; +} + +static int asciiXdigitValue(char c) +{ + //printf("-->%c\n",c); + if (c >= 'A' && c <= 'F') + return c - 'A' + 10;//(A B C D E F)->(10 11 12 13 14 15) + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return asciiDigitValue(c);//('0'...'9')->(0...9) +} + +static int unescapeCharacter(const char* scanner) +{ + int first = asciiXdigitValue(scanner[0]); + if (first < 0) + return -1; + + int second = asciiXdigitValue(scanner[1]); + if (second < 0) + return -1; + + return (first << 4) | second; //== (first*16 | second) == (first*16 + second) +} + +static char* unescapeUriString(const char* uriString, bool asciiEscape) +{ + if (NULL == uriString) + return NULL; + + int strLen = (int)strlen(uriString); + char* result = (char*)malloc(strLen + 1);//可推测解码后的长度<=原长度 + char* out = result; + + const char* in, * end; + for (in = uriString, end = in + strLen; in < end; ++in) + { + int c = *in; + + //遇到了'%'才去解析 + if ('%' == c) + { + if (in + 3 > end) + break; + //获取%后2个字符的解码值 + c = unescapeCharacter(in + 1); + if (c <= 0) + break; + + if (asciiEscape && c <= 0x7F) + break; + + in += 2;//一般的格式为%后加两个ascii码字符 + } + + *out++ = c;//存储转义结果 + } + + *out = '\0'; + + if (in != end) + { + free(result); + return NULL; + } + + return result; +} + +std::string HttpHead::AnalyURIString(const std::string& str) +{ + std::string ret; + char* decodeStr = unescapeUriString(str.c_str(), false); + if (NULL != decodeStr) + { + ret = decodeStr; + free(decodeStr); + } + + return ret; +} \ No newline at end of file diff --git a/sdk/webscan/HttpHead.h b/sdk/webscan/HttpHead.h new file mode 100644 index 00000000..4f6d4062 --- /dev/null +++ b/sdk/webscan/HttpHead.h @@ -0,0 +1,45 @@ +#pragma once + +#include "base/HGDef.h" +#include "base/HGInc.h" +#include +#include + +typedef std::pair HttpPair; +typedef std::vector HttpPairs; + +class HttpHead +{ +public: + HttpHead(); + ~HttpHead(); + + bool Parse(const std::string& head); + void Clear(); + + std::string GetRequestMethod() const; + std::string GetRequestURIPath() const; + HttpPairs GetRequestURIQueryInfos() const; + std::string GetRequestURIFragment() const; + std::string GetRequestHttpVersion() const; + HttpPairs GetHeadInfos() const; + int GetContentLength() const; + std::string GetContentType() const; + + static std::string GetValue(const HttpPairs& infos, const std::string& key); + static void AnalysisURIQuery(const std::string& query, HttpPairs& queryInfos); + static void AnalysisURI(const std::string& uri, std::string& path, HttpPairs& queryInfos, std::string& fragment); + static void AnalysisHead(const std::string& head, std::string& requestMethod, std::string& requestURIPath, + HttpPairs& requestURIQueryInfos, std::string& requestURIFragment, std::string& httpVersion, HttpPairs& headInfos); + +private: + static std::string AnalyURIString(const std::string& str); + +private: + std::string m_requestMethod; + std::string m_requestURIPath; + HttpPairs m_requestURIQueryInfos; + std::string m_requestURIFragment; + std::string m_requestHttpVersion; + HttpPairs m_headInfos; +}; \ No newline at end of file diff --git a/sdk/webscan/Msg.h b/sdk/webscan/Msg.h new file mode 100644 index 00000000..503c350c --- /dev/null +++ b/sdk/webscan/Msg.h @@ -0,0 +1,65 @@ +#pragma once + +#include "base/HGDef.h" +#include "base/HGInc.h" +#include +#include "HttpHead.h" + +enum +{ + MSGID_CONNECT = 1L, + MSGID_DISCONNECT, + MSGID_CLOSE_DEVICE, + MSGID_SCAN_FINISH, + MSGID_WS_COMMAND, + MSGID_WS_EVENT +}; + +class WebServer; + +struct ConnectParam +{ + WebServer* svr; + std::string ip; + HGUShort port; +#if defined(HG_CMP_MSC) + SOCKET socket; +#else + int socket; +#endif +}; + +struct DisConnectParam +{ + WebServer* svr; + HGUInt usrId; +}; + +struct CloseDevParam +{ + WebServer* svr; + HGUInt usrId; + std::string devName; +}; + +struct ScanFinishParam +{ + WebServer* svr; + HGUInt usrId; +}; + +struct WSCmdParam +{ + WebServer* svr; + HGUInt usrId; + HGByte* data; + HGUInt size; +}; + +struct WSEvtParam +{ + WebServer* svr; + HGUInt usrId; + HGByte* data; + HGUInt size; +}; \ No newline at end of file diff --git a/sdk/webscan/MsgPumpCallback.cpp b/sdk/webscan/MsgPumpCallback.cpp new file mode 100644 index 00000000..34b6728c --- /dev/null +++ b/sdk/webscan/MsgPumpCallback.cpp @@ -0,0 +1,57 @@ +#include "MsgPumpCallback.h" +#include "base/HGDef.h" +#include "base/HGInc.h" +#include "WebServer.h" + +void HGMsgPumpCallback(HGMsgPump msgPump, const HGMsg* msg, HGPointer param) +{ + (void)msgPump; + (void)param; + assert(NULL != msg); + + switch (msg->id) + { + case MSGID_CONNECT: + { + ConnectParam* param = (ConnectParam*)msg->data; + param->svr->Connect(param); + delete param; + } + break; + case MSGID_DISCONNECT: + { + DisConnectParam* param = (DisConnectParam*)msg->data; + param->svr->DisConnect(param); + delete param; + } + break; + case MSGID_CLOSE_DEVICE: + { + CloseDevParam* param = (CloseDevParam*)msg->data; + param->svr->CloseDev(param); + delete param; + } + break; + case MSGID_SCAN_FINISH: + { + ScanFinishParam* param = (ScanFinishParam*)msg->data; + param->svr->ScanFinish(param); + delete param; + } + break; + case MSGID_WS_COMMAND: + { + WSCmdParam* param = (WSCmdParam*)msg->data; + param->svr->Command(param); + delete param; + } + break; + case MSGID_WS_EVENT: + { + WSEvtParam* param = (WSEvtParam*)msg->data; + param->svr->Event(param); + delete param; + } + break; + } +} diff --git a/sdk/webscan/MsgPumpCallback.h b/sdk/webscan/MsgPumpCallback.h new file mode 100644 index 00000000..046105e7 --- /dev/null +++ b/sdk/webscan/MsgPumpCallback.h @@ -0,0 +1,5 @@ +#pragma once + +#include "base/HGMsgPump.h" + +void HGMsgPumpCallback(HGMsgPump msgPump, const HGMsg* msg, HGPointer param); \ No newline at end of file diff --git a/sdk/webscan/WebServer.cpp b/sdk/webscan/WebServer.cpp new file mode 100644 index 00000000..ffa19405 --- /dev/null +++ b/sdk/webscan/WebServer.cpp @@ -0,0 +1,262 @@ +#include "WebServer.h" +#include "WebUser.h" +#include "base/HGInfo.h" + +WebServer::WebServer(HGMsgPump msgPump) +{ + m_msgPump = msgPump; + + m_currUserId = 1; +#if defined(HG_CMP_MSC) + m_sockServer = INVALID_SOCKET; +#else + m_sockServer = -1; +#endif + m_listenThread = NULL; +} + +WebServer::~WebServer() +{ + +} + +bool WebServer::Open(HGUShort port) +{ +#if defined(HG_CMP_MSC) + if (INVALID_SOCKET != m_sockServer) +#else + if (-1 != m_sockServer) +#endif + { + return false; + } + +#if defined(HG_CMP_MSC) + SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0); + if (INVALID_SOCKET == sockServer) +#else + int sockServer = socket(AF_INET, SOCK_STREAM, 0); + if (-1 == sockServer) +#endif + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "open webserver failed 1, port=%u", port); + return false; + } + + // bind +#if defined(HG_CMP_MSC) + SOCKADDR_IN addrServer; + addrServer.sin_addr.S_un.S_addr = INADDR_ANY; + addrServer.sin_family = AF_INET; + addrServer.sin_port = htons(port); + if (0 != bind(sockServer, (SOCKADDR*)&addrServer, sizeof(SOCKADDR_IN))) +#else + struct sockaddr_in addrServer; + addrServer.sin_addr.s_addr = htonl(INADDR_ANY); + addrServer.sin_family = AF_INET; + addrServer.sin_port = htons(port); + if (0 != bind(sockServer, (struct sockaddr*)&addrServer, sizeof(addrServer))) +#endif + { +#if defined(HG_CMP_MSC) + closesocket(sockServer); +#else + close(sockServer); +#endif + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "open webserver failed 2, port=%u", port); + return false; + } + + // listen + if (0 != listen(sockServer, 5)) + { +#if defined(HG_CMP_MSC) + closesocket(sockServer); +#else + close(sockServer); +#endif + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "open webserver failed 3, port=%u", port); + return false; + } + + m_sockServer = sockServer; + HGBase_OpenThread(ThreadFunc, this, &m_listenThread); + assert(NULL != m_listenThread); + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "open webserver success, port=%u", port); + return true; +} + +bool WebServer::Close() +{ +#if defined(HG_CMP_MSC) + if (INVALID_SOCKET == m_sockServer) +#else + if (-1 == m_sockServer) +#endif + { + return false; + } + + while (!m_vectorUser.empty()) + { + WebUser* pUser = m_vectorUser[0]; + m_vectorUser.erase(m_vectorUser.begin()); + delete pUser; + pUser = NULL; + } + +#if defined(HG_CMP_MSC) + closesocket(m_sockServer); + m_sockServer = INVALID_SOCKET; +#else + close(m_sockServer); + m_sockServer = -1; +#endif + HGBase_CloseThread(m_listenThread); + m_listenThread = NULL; + return true; +} + +void WebServer::Connect(const ConnectParam* param) +{ + assert(NULL != param && this == param->svr); + + if (!m_vectorUser.empty()) + { +#if defined(HG_CMP_MSC) + closesocket(param->socket); +#else + close(param->socket); +#endif + return; + } + + WebUser* user = new WebUser(this, m_currUserId, m_msgPump, param->ip, param->port, param->socket); + ++m_currUserId; + m_vectorUser.push_back(user); +} + +void WebServer::DisConnect(const DisConnectParam* param) +{ + assert(NULL != param && this == param->svr); + + int nIndex = GetUserIndex(param->usrId); + if (-1 != nIndex) + { + WebUser* pUser = m_vectorUser[nIndex]; + m_vectorUser.erase(m_vectorUser.begin() + nIndex); + delete pUser; + pUser = NULL; + } +} + +void WebServer::CloseDev(const CloseDevParam* param) +{ + assert(NULL != param && this == param->svr); + + int nIndex = GetUserIndex(param->usrId); + if (-1 != nIndex) + { + ((WebUser*)m_vectorUser[nIndex])->CloseDev(param); + } +} + +void WebServer::ScanFinish(const ScanFinishParam* param) +{ + assert(NULL != param && this == param->svr); + + int nIndex = GetUserIndex(param->usrId); + if (-1 != nIndex) + { + ((WebUser*)m_vectorUser[nIndex])->ScanFinish(param); + } +} + +void WebServer::Command(const WSCmdParam* param) +{ + assert(NULL != param && this == param->svr); + + int nIndex = GetUserIndex(param->usrId); + if (-1 != nIndex) + { + ((WebUser*)m_vectorUser[nIndex])->HandleCmd(param); + } +} + +void WebServer::Event(const WSEvtParam* param) +{ + assert(NULL != param && this == param->svr); + + int nIndex = GetUserIndex(param->usrId); + if (-1 != nIndex) + { + ((WebUser*)m_vectorUser[nIndex])->HandleEvent(param); + } +} + +#if defined(HG_CMP_MSC) +void WebServer::PostConnectMsg(const std::string& ip, uint16_t port, SOCKET sockConn) +#else +void WebServer::PostConnectMsg(const std::string& ip, uint16_t port, int sockConn) +#endif +{ + ConnectParam* param = new ConnectParam; + param->svr = this; + param->ip = ip; + param->port = port; + param->socket = sockConn; + + HGMsg msg; + msg.id = MSGID_CONNECT; + msg.data = param; + if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_msgPump, &msg)) + { +#if defined(HG_CMP_MSC) + closesocket(param->socket); +#else + close(param->socket); +#endif + delete param; + } +} + +int WebServer::GetUserIndex(HGUInt id) +{ + int nIndex = -1; + for (int i = 0; i < (int)m_vectorUser.size(); ++i) + { + if (id == m_vectorUser[i]->GetId()) + { + nIndex = i; + break; + } + } + + return nIndex; +} + +void WebServer::ThreadFunc(HGThread thread, HGPointer param) +{ + WebServer* p = (WebServer*)param; + + while (1) + { +#if defined(HG_CMP_MSC) + SOCKADDR_IN addrClient; + int len = sizeof(SOCKADDR_IN); + SOCKET socketConn = accept(p->m_sockServer, (SOCKADDR*)&addrClient, &len); + if (INVALID_SOCKET == socketConn) +#else + struct sockaddr_in addrClient; + socklen_t len = sizeof(addrClient); + int socketConn = accept(p->m_sockServer, (struct sockaddr*)&addrClient, &len); + if (-1 == socketConn) +#endif + { + // 这里跳出,可能是服务器关闭了m_sockServer + break; + } + + p->PostConnectMsg(inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port), socketConn); + } +} \ No newline at end of file diff --git a/sdk/webscan/WebServer.h b/sdk/webscan/WebServer.h new file mode 100644 index 00000000..75daeff4 --- /dev/null +++ b/sdk/webscan/WebServer.h @@ -0,0 +1,46 @@ +#pragma once + +#include "base/HGDef.h" +#include "base/HGInc.h" +#include "base/HGThread.h" +#include "base/HGMsgPump.h" +#include "Msg.h" +#include + +class WebServer +{ +public: + WebServer(HGMsgPump msgPump); + ~WebServer(); + + bool Open(HGUShort port); + bool Close(); + + void Connect(const ConnectParam* param); + void DisConnect(const DisConnectParam* param); + void CloseDev(const CloseDevParam* param); + void ScanFinish(const ScanFinishParam* param); + void Command(const WSCmdParam* param); + void Event(const WSEvtParam* param); + +private: +#if defined(HG_CMP_MSC) + void PostConnectMsg(const std::string &ip, uint16_t port, SOCKET sockConn); +#else + void PostConnectMsg(const std::string &ip, uint16_t port, int sockConn); +#endif + int GetUserIndex(HGUInt id); + static void ThreadFunc(HGThread thread, HGPointer param); + +private: + HGMsgPump m_msgPump; + + HGUInt m_currUserId; +#if defined(HG_CMP_MSC) + SOCKET m_sockServer; +#else + int m_sockServer; +#endif + HGThread m_listenThread; + std::vector m_vectorUser; +}; \ No newline at end of file diff --git a/sdk/webscan/WebUser.cpp b/sdk/webscan/WebUser.cpp new file mode 100644 index 00000000..fd931ad8 --- /dev/null +++ b/sdk/webscan/WebUser.cpp @@ -0,0 +1,1389 @@ +#include "WebUser.h" +#include "WebServer.h" +#include "base/HGInfo.h" +#include "base/HGBase64.h" +#include "base/HGImage.h" +#include "imgfmt/HGJpeg.h" +#include "sha1.h" +#include "base64.h" +#include "HGString.h" + +static int GetJsonIntValue(cJSON* json, const std::string& key, bool* find = NULL) +{ + int ret = 0; + if (NULL != find) + *find = false; + + cJSON* p = json->child; + while (NULL != p) + { + if (0 == strcmp(p->string, key.c_str())) + { + if (p->type == cJSON_Number) + { + ret = p->valueint; + if (NULL != find) + *find = true; + } + + break; + } + + p = p->next; + } + + return ret; +} + +static double GetJsonDoubleValue(cJSON* json, const std::string& key, bool* find = NULL) +{ + double ret = 0.0; + if (NULL != find) + *find = false; + + cJSON* p = json->child; + while (NULL != p) + { + if (0 == strcmp(p->string, key.c_str())) + { + if (p->type == cJSON_Number) + { + ret = p->valuedouble; + if (NULL != find) + *find = true; + } + + break; + } + + p = p->next; + } + + return ret; +} + +static bool GetJsonBoolValue(cJSON* json, const std::string& key, bool* find = NULL) +{ + bool ret = false; + if (NULL != find) + *find = false; + + cJSON* p = json->child; + while (NULL != p) + { + if (0 == strcmp(p->string, key.c_str())) + { + if (p->type == cJSON_True || p->type == cJSON_False) + { + ret = (p->type == cJSON_True) ? true : false; + if (NULL != find) + *find = true; + } + + break; + } + + p = p->next; + } + + return ret; +} + +static std::string GetJsonStringValue(cJSON* json, const std::string& key, bool* find = NULL) +{ + std::string ret; + if (NULL != find) + *find = false; + + cJSON* p = json->child; + while (NULL != p) + { + if (0 == strcmp(p->string, key.c_str())) + { + if (p->type == cJSON_String) + { + ret = p->valuestring; + if (NULL != find) + *find = true; + } + + break; + } + + p = p->next; + } + + return ret; +} + +static std::vector GetJsonStringListValue(cJSON* json, const std::string& key, bool* find = NULL) +{ + std::vector ret; + if (NULL != find) + *find = false; + + cJSON* p = json->child; + while (NULL != p) + { + if (0 == strcmp(p->string, key.c_str())) + { + if (p->type == cJSON_Array) + { + cJSON* pEx = p->child; + while (NULL != pEx) + { + if (pEx->type == cJSON_String) + ret.push_back(pEx->valuestring); + + pEx = pEx->next; + } + + if (NULL != find) + *find = true; + } + + break; + } + + p = p->next; + } + + return ret; +} + +static std::vector GetJsonIntListValue(cJSON* json, const std::string& key, bool* find = NULL) +{ + std::vector ret; + if (NULL != find) + *find = false; + + cJSON* p = json->child; + while (NULL != p) + { + if (0 == strcmp(p->string, key.c_str())) + { + if (p->type == cJSON_Array) + { + cJSON* pEx = p->child; + while (NULL != pEx) + { + if (pEx->type == cJSON_Number) + ret.push_back(pEx->valueint); + + pEx = pEx->next; + } + + if (NULL != find) + *find = true; + } + + break; + } + + p = p->next; + } + + return ret; +} + + +#if defined(HG_CMP_MSC) +WebUser::WebUser(WebServer* server, HGUInt id, HGMsgPump msgPump, const std::string& ip, uint16_t port, SOCKET sockConn) +#else +WebUser::WebUser(WebServer* server, HGUInt id, HGMsgPump msgPump, const std::string& ip, uint16_t port, int sockConn) +#endif +{ + m_lock = NULL; + HGBase_CreateLock(&m_lock); + m_lockName = NULL; + HGBase_CreateLock(&m_lockName); + m_server = server; + m_id = id; + m_msgPump = msgPump; + m_ip = ip; + m_port = port; + m_sockConn = sockConn; + + m_thread = NULL; + HGBase_OpenThread(ThreadFunc, this, &m_thread); + assert(NULL != m_thread); + + m_jpgQuality = 80; + m_devNameList.clear(); + m_devName.clear(); + m_devHandle = NULL; + m_dpi = 96; + m_scanEvent = NULL; + + SANE_Int version_code = 0; + sane_init_ex(&version_code, sane_ex_callback, this); +} + +WebUser::~WebUser() +{ + if (NULL != m_scanEvent) + { + assert(NULL != m_devHandle); + sane_cancel(m_devHandle); + + HGBase_WaitEvent(m_scanEvent); + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + } + + if (NULL != m_devHandle) + { + m_dpi = 96; + sane_close(m_devHandle); + m_devHandle = NULL; + m_devName.clear(); + } + + sane_exit(); + +#if defined(HG_CMP_MSC) + closesocket(m_sockConn); + m_sockConn = INVALID_SOCKET; +#else + close(m_sockConn); + m_sockConn = -1; +#endif + HGBase_CloseThread(m_thread); + m_thread = NULL; + + m_port = 0; + m_ip.clear(); + m_msgPump = NULL; + m_id = 0; + m_server = NULL; + HGBase_DestroyLock(m_lockName); + m_lockName = NULL; + HGBase_DestroyLock(m_lock); + m_lock = NULL; +} + +HGUInt WebUser::GetId() +{ + return m_id; +} + +void WebUser::CloseDev(const CloseDevParam* param) +{ + assert(NULL != param && m_id == param->usrId); + + if (m_devName == param->devName) + { + if (NULL != m_scanEvent) + { + assert(NULL != m_devHandle); + sane_cancel(m_devHandle); + + HGBase_WaitEvent(m_scanEvent); + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + } + + if (NULL != m_devHandle) + { + m_dpi = 96; + sane_close(m_devHandle); + m_devHandle = NULL; + m_devName.clear(); + } + } +} + +void WebUser::ScanFinish(const ScanFinishParam* param) +{ + assert(NULL != param && m_id == param->usrId); + + if (NULL != m_scanEvent) + { + assert(NULL != m_devHandle); + sane_cancel(m_devHandle); + + HGBase_WaitEvent(m_scanEvent); + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + } +} + +void WebUser::HandleCmd(const WSCmdParam* param) +{ + assert(NULL != param && m_id == param->usrId); + + std::string cmdData((const char*)param->data, param->size); + cJSON* json = cJSON_Parse(cmdData.c_str()); + if (NULL != json) + { + std::string func = GetJsonStringValue(json, "Func"); + if ("GetDeviceList" == func) + { + GetDeviceList(json); + } + else if ("SelectDevice" == func) + { + SelectDevice(json); + } + else if ("SetScanColorType" == func) + { + SetScanColorType(json); + } + else if ("SetDPI" == func) + { + SetDPI(json); + } + else if ("SetDuplex" == func) + { + SetDuplex(json); + } + else if ("SetScanJPGQuality" == func) + { + SetScanJPGQuality(json); + } + else if ("StartScan" == func) + { + StartScan(json); + } + + cJSON_Delete(json); + } +} + +void WebUser::HandleEvent(const WSEvtParam* param) +{ + assert(NULL != param && m_id == param->usrId); + + SendResponse(param->data, param->size, HGTRUE); +} + +void WebUser::GetDeviceList(cJSON* json) +{ + assert(NULL != json); + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("GetDeviceList")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(0)); + + cJSON* array = cJSON_CreateArray(); + cJSON_AddItemToObject(retJson, "result", array); + + HGBase_EnterLock(m_lockName); + for (int i = 0; i < (int)m_devNameList.size(); ++i) + { + cJSON* js = cJSON_CreateObject(); + cJSON_AddItemToObject(js, "index", cJSON_CreateNumber(i)); + cJSON_AddItemToObject(js, "name", cJSON_CreateString(m_devNameList[i].c_str())); + cJSON_AddItemToArray(array, js); + } + HGBase_LeaveLock(m_lockName); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::SelectDevice(cJSON* json) +{ + assert(NULL != json); + + if (NULL != m_scanEvent) + { + assert(NULL != m_devHandle); + sane_cancel(m_devHandle); + + HGBase_WaitEvent(m_scanEvent); + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + } + + if (NULL != m_devHandle) + { + m_dpi = 96; + sane_close(m_devHandle); + m_devHandle = NULL; + m_devName.clear(); + } + + int code = -1; + std::string result = "错误"; + + int index = GetJsonIntValue(json, "arg"); + + HGBase_EnterLock(m_lockName); + if (index >= 0 && index < (int)m_devNameList.size()) + { + SANE_Handle dev = NULL; + SANE_Status status = sane_open(m_devNameList[index].c_str(), &dev); + if (SANE_STATUS_GOOD == status) + { + m_devName = m_devNameList[index]; + m_devHandle = dev; + m_dpi = GetDpi(); + code = 0; + result.clear(); + } + } + HGBase_LeaveLock(m_lockName); + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("SelectDevice")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::SetScanColorType(cJSON* json) +{ + assert(NULL != json); + + int code = -1; + std::string result = "错误"; + + int colorMode = GetJsonIntValue(json, "arg"); + + if (NULL != m_devHandle && NULL == m_scanEvent && colorMode >= 1 && colorMode <= 3) + { + const char* colorModeStr = OPTION_VALUE_YSMS_24WCS; + if (2 == colorMode) + colorModeStr = OPTION_VALUE_YSMS_256JHD; + else if (3 == colorMode) + colorModeStr = OPTION_VALUE_YSMS_HB; + + if (SetParam(OPTION_TITLE_YSMS, colorModeStr)) + { + code = 0; + result.clear(); + } + } + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("SetScanColorType")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::SetDPI(cJSON* json) +{ + assert(NULL != json); + + int code = -1; + std::string result = "错误"; + + int dpi = GetJsonIntValue(json, "arg"); + + if (NULL != m_devHandle && NULL == m_scanEvent && dpi > 0) + { + if (SetParam(OPTION_TITLE_FBL, &dpi)) + { + m_dpi = dpi; + code = 0; + result.clear(); + } + } + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("SetDPI")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::SetDuplex(cJSON* json) +{ + assert(NULL != json); + + int code = -1; + std::string result = "错误"; + + int duplexMode = GetJsonIntValue(json, "arg"); + + if (NULL != m_devHandle && NULL == m_scanEvent && duplexMode >= 0 && duplexMode <= 1) + { + const char* duplexModeStr = OPTION_VALUE_SMYM_DM; + if (1 == duplexMode) + duplexModeStr = OPTION_VALUE_SMYM_SM; + + if (SetParam(OPTION_TITLE_SMYM, duplexModeStr)) + { + code = 0; + result.clear(); + } + } + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("SetDuplex")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::SetScanJPGQuality(cJSON* json) +{ + assert(NULL != json); + + int code = -1; + std::string result = "错误"; + + int jpegQuality = GetJsonIntValue(json, "arg"); + + if (NULL == m_scanEvent && jpegQuality >= 0 && jpegQuality <= 100) + { + m_jpgQuality = jpegQuality; + code = 0; + result.clear(); + } + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("SetScanJPGQuality")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::StartScan(cJSON* json) +{ + assert(NULL != json); + + int code = -1; + std::string result = "错误"; + + int scanPage = GetJsonIntValue(json, "arg"); + + if (NULL != m_devHandle && NULL == m_scanEvent && scanPage >= 0) + { + if (0 == scanPage) + { + SetParam(OPTION_TITLE_SMZS, OPTION_VALUE_SMZS_LXSM); + } + else + { + SetParam(OPTION_TITLE_SMZS, OPTION_VALUE_SMZS_SMZDZS); + SetParam(OPTION_TITLE_SMSL, &scanPage); + } + + HGBase_CreateEvent(HGFALSE, HGFALSE, &m_scanEvent); + assert(NULL != m_scanEvent); + + SANE_Status status = sane_start(m_devHandle); + if (SANE_STATUS_GOOD == status) + { + code = 0; + result.clear(); + } + else + { + HGBase_DestroyEvent(m_scanEvent); + m_scanEvent = NULL; + } + } + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("StartScan")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + SendResponse((const HGByte*)resp, (HGUInt)strlen(resp), HGTRUE); + free(resp); + } + + cJSON_Delete(retJson); + } +} + +void WebUser::PostDisConnectMsg() +{ + DisConnectParam* param = new DisConnectParam; + param->svr = m_server; + param->usrId = m_id; + + HGMsg msg; + msg.id = MSGID_DISCONNECT; + msg.data = param; + if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_msgPump, &msg)) + { + delete param; + } +} + +void WebUser::PostCmdMsg(const HGByte* data, HGUInt dataSize) +{ + WSCmdParam* param = new WSCmdParam; + param->svr = m_server; + param->usrId = m_id; + param->data = new HGByte[dataSize]; + param->size = dataSize; + memcpy(param->data, data, dataSize); + + HGMsg msg; + msg.id = MSGID_WS_COMMAND; + msg.data = param; + if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_msgPump, &msg)) + { + delete[] param->data; + param->size = 0; + delete param; + } +} + +void WebUser::PostEventMsg(const HGByte* data, HGUInt dataSize) +{ + WSEvtParam* param = new WSEvtParam; + param->svr = m_server; + param->usrId = m_id; + param->data = new HGByte[dataSize]; + param->size = dataSize; + memcpy(param->data, data, dataSize); + + HGMsg msg; + msg.id = MSGID_WS_EVENT; + msg.data = param; + if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_msgPump, &msg)) + { + delete[] param->data; + param->size = 0; + delete param; + } +} + +void WebUser::ThreadFunc(HGThread thread, HGPointer param) +{ + WebUser* p = (WebUser*)param; + + char chBuffer[2048]; + const char* pBuffer = chBuffer; + int nBufferSize = 0; + bool bConnect = false; + + unsigned char connectDataTail[4] = { '\r', '\n', '\r', '\n' }; + unsigned int connectDataTailLen = 0; + std::string connectData; + + uint8_t* pData = NULL; + int nDataSize = 0; + uint8_t* pDataEx = NULL; + int nRemainSize = 0; + uint8_t headData[20]; + uint32_t nHeadDataLen = 0; + uint8_t vMask[4]; + uint32_t nMaskCount = 0; + bool bHandle = false; + std::vector vAllData; + + while (1) + { + if (0 == nBufferSize) + { + int len = recv(p->m_sockConn, chBuffer, 2048, 0); + if (len <= 0) + { + // 这里跳出,可能是服务器关闭了socketConn,或者客户端关闭了socket,或者网络断开 + p->PostDisConnectMsg(); + break; + } + else + { + pBuffer = chBuffer; + nBufferSize = len; + } + } + + assert(nBufferSize > 0); + + if (!bConnect) + { + unsigned char b = *pBuffer; + ++pBuffer; + --nBufferSize; + + connectData.push_back(b); + if (b == connectDataTail[connectDataTailLen]) + { + ++connectDataTailLen; + } + else + { + connectDataTailLen = 0; + if (b == connectDataTail[connectDataTailLen]) + { + ++connectDataTailLen; + } + } + + if (4 == connectDataTailLen) + { + connectDataTailLen = 0; + bool shakeRet = p->ShakeHand(connectData); + connectData.clear(); + + if (!shakeRet) + { + p->PostDisConnectMsg(); + break; + } + + bConnect = true; + } + } + else + { + if (NULL == pData) + { + assert(0 == nDataSize); + + uint8_t b = *pBuffer; + ++pBuffer; + --nBufferSize; + headData[nHeadDataLen] = b; + ++nHeadDataLen; + + if (1 == nHeadDataLen) + { + if ((0x80 | 0x08) == headData[0]) // 断开连接 + { + p->PostDisConnectMsg(); + break; + } + else if ((0x80 | 0x09) == headData[0]) // PING帧 + { + // + } + else if ((0x80 | 0x0A) == headData[0]) // PONG帧 + { + // + } + else if ((0x00 | 0x01) == headData[0] || (0x00 | 0x02) == headData[0] || (0x00 | 0x00) == headData[0] || (0x80 | 0x00) == headData[0] + || (0x80 | 0x01) == headData[0] || (0x80 | 0x02) == headData[0]) // 数据帧 + { + if ((0x80 | 0x00) == headData[0] || (0x80 | 0x01) == headData[0] || (0x80 | 0x02) == headData[0]) + { + // 分片结束 + bHandle = true; + } + else + { + // 分片帧 + bHandle = false; + } + } + else // 帧错误,断开连接 + { + p->PostDisConnectMsg(); + break; + } + } + else if (2 == nHeadDataLen) + { + if (0 == (headData[1] & 0x80)) // 必须经过掩码处理 + { + p->PostDisConnectMsg(); + break; + } + + if ((0x80 | 0x09) == headData[0]) // PING帧 + { + if (0x80 != headData[1]) + { + p->PostDisConnectMsg(); + break; + } + } + else if ((0x80 | 0x0A) == headData[0]) // PONG帧 + { + if (0x80 != headData[1]) + { + p->PostDisConnectMsg(); + break; + } + } + else + { + if ((headData[1] & 0x7F) <= 125) + { + uint32_t nCmdSize = (headData[1] & 0x7F); + nHeadDataLen = 0; + + if (0 == nCmdSize) + { + p->PostDisConnectMsg(); + break; + } + + nDataSize = nCmdSize; + nRemainSize = nCmdSize; + pData = new uint8_t[nDataSize]; + pDataEx = pData; + } + } + } + else if (4 == nHeadDataLen) + { + if ((0x80 | 0x09) == headData[0]) // PING帧 + { + // + } + else if ((0x80 | 0x0A) == headData[0]) // PONG帧 + { + // + } + else + { + if ((headData[1] & 0x7F) == 126) + { + uint32_t nCmdSize = ntohs(*(uint16_t*)&headData[2]); + nHeadDataLen = 0; + + if (0 == nCmdSize) + { + p->PostDisConnectMsg(); + break; + } + + nDataSize = nCmdSize; + nRemainSize = nCmdSize; + pData = new uint8_t[nDataSize]; + pDataEx = pData; + } + } + } + else if (6 == nHeadDataLen) + { + if ((0x80 | 0x09) == headData[0]) // PING帧 + { + nHeadDataLen = 0; + + p->Pong(); + } + else if ((0x80 | 0x0A) == headData[0]) // PONG帧 + { + nHeadDataLen = 0; + } + } + else if (10 == nHeadDataLen) + { + if ((headData[1] & 0x7F) == 127) // 这里一定会等于127 + { + uint32_t nCmdSizeHigh = ntohl(*(uint32_t*)&headData[2]); + uint32_t nCmdSize = ntohl(*(uint32_t*)&headData[6]); + nHeadDataLen = 0; + + if ((0 != nCmdSizeHigh) || (0 == nCmdSize)) + { + p->PostDisConnectMsg(); + break; + } + + nDataSize = nCmdSize; + nRemainSize = nCmdSize; + pData = new uint8_t[nDataSize]; + pDataEx = pData; + } + } + } + else + { + if (4 != nMaskCount) + { + uint8_t b = *pBuffer; + ++pBuffer; + --nBufferSize; + vMask[nMaskCount] = b; + ++nMaskCount; + } + else + { + int nWriteSize = HGMIN(nBufferSize, nRemainSize); + memcpy(pDataEx, pBuffer, nWriteSize); + pBuffer += nWriteSize; + nBufferSize -= nWriteSize; + pDataEx += nWriteSize; + nRemainSize -= nWriteSize; + + if (0 == nRemainSize) + { + assert(pDataEx == pData + nDataSize); + + for (int i = 0; i < nDataSize; ++i) + { + int j = i % 4; + pData[i] = pData[i] ^ vMask[j]; + vAllData.push_back(pData[i]); + } + + delete[] pData; + pData = NULL; + nDataSize = 0; + nMaskCount = 0; + + if (bHandle) + { + p->PostCmdMsg(&vAllData[0], (HGUInt)vAllData.size()); + + bHandle = false; + vAllData.clear(); + } + } + } + } + } + } + + if (NULL != pData) + { + delete[] pData; + pData = NULL; + nDataSize = 0; + nMaskCount = 0; + } +} + +int WebUser::sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param) +{ + (void)hdev; + (void)len; + + WebUser* p = (WebUser*)param; + switch (code) + { + case SANE_EVENT_DEVICE_ARRIVED: + { + SANE_Device* sane_dev = (SANE_Device*)data; + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_DEVICE_ARRIVED, name=%s", Utf8ToStdString(sane_dev->name).c_str()); + + HGBase_EnterLock(p->m_lockName); + p->m_devNameList.push_back(sane_dev->name); + HGBase_LeaveLock(p->m_lockName); + } + break; + case SANE_EVENT_DEVICE_LEFT: + { + SANE_Device* sane_dev = (SANE_Device*)data; + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_DEVICE_LEFT, name=%s", Utf8ToStdString(sane_dev->name).c_str()); + + CloseDevParam* closeDevParam = new CloseDevParam; + closeDevParam->svr = p->m_server; + closeDevParam->usrId = p->m_id; + closeDevParam->devName = sane_dev->name; + + HGMsg msg; + msg.id = MSGID_CLOSE_DEVICE; + msg.data = closeDevParam; + if (HGBASE_ERR_OK != HGBase_PostPumpMessage(p->m_msgPump, &msg)) + { + delete closeDevParam; + } + + HGBase_EnterLock(p->m_lockName); + for (int i = 0; i < (int)p->m_devNameList.size(); ++i) + { + if (0 == strcmp(sane_dev->name, p->m_devNameList[i].c_str())) + { + p->m_devNameList.erase(p->m_devNameList.begin() + i); + break; + } + } + HGBase_LeaveLock(p->m_lockName); + } + break; + case SANE_EVENT_WORKING: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_WORKING, msg=%s", Utf8ToStdString((char*)data).c_str()); + } + break; + case SANE_EVENT_SCAN_FINISHED: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_SCAN_FINISHED, msg=%s", Utf8ToStdString((char*)data).c_str()); + + HGBase_SetEvent(p->m_scanEvent); + + ScanFinishParam* scanFinishParam = new ScanFinishParam; + scanFinishParam->svr = p->m_server; + scanFinishParam->usrId = p->m_id; + + HGMsg msg; + msg.id = MSGID_SCAN_FINISH; + msg.data = scanFinishParam; + if (HGBASE_ERR_OK != HGBase_PostPumpMessage(p->m_msgPump, &msg)) + { + delete scanFinishParam; + } + + int code = 0; + std::string result = ""; + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("ScanComplete")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + p->PostEventMsg((const HGByte*)resp, (HGUInt)strlen(resp)); + free(resp); + } + + cJSON_Delete(retJson); + } + } + break; + case SANE_EVENT_STATUS: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_STATUS, msg=%s", Utf8ToStdString((char*)data).c_str()); + } + break; + case SANE_EVENT_ERROR: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_ERROR, msg=%s", Utf8ToStdString((char*)data).c_str()); + } + break; + case SANE_EVENT_IMAGE_OK: + { + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SANE_EVENT_IMAGE_OK"); + + SANE_Image* sane_img = (SANE_Image*)data; + + HGUInt imgType = 0; + if (sane_img->header.format == SANE_FRAME_GRAY) + { + if (1 == sane_img->header.depth) + imgType = HGBASE_IMGTYPE_BINARY; + else if (8 == sane_img->header.depth) + imgType = HGBASE_IMGTYPE_GRAY; + } + else if (sane_img->header.format == SANE_FRAME_RGB) + imgType = HGBASE_IMGTYPE_RGB; + + HGByte* data = sane_img->data; + HGImageInfo imgInfo = { (HGUInt)sane_img->header.pixels_per_line, (HGUInt)sane_img->header.lines, + imgType, (HGUInt)sane_img->header.bytes_per_line, HGBASE_IMGORIGIN_TOP }; + + HGImage img = NULL; + HGBase_CreateImageFromData(data, &imgInfo, NULL, 0, HGBASE_IMGORIGIN_TOP, &img); + if (NULL != img) + { + HGBase_SetImageDpi(img, p->m_dpi, p->m_dpi); + + int code = 0; + std::string result = p->GetBase64(img); + + cJSON* retJson = cJSON_CreateObject(); + if (NULL != retJson) + { + cJSON_AddItemToObject(retJson, "Func", cJSON_CreateString("ImageSaveDone")); + cJSON_AddItemToObject(retJson, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(retJson, "result", cJSON_CreateString(StdStringToUtf8(result).c_str())); + + char* resp = cJSON_Print(retJson); + if (NULL != resp) + { + p->PostEventMsg((const HGByte*)resp, (HGUInt)strlen(resp)); + free(resp); + } + + cJSON_Delete(retJson); + } + + HGBase_DestroyImage(img); + } + } + break; + } + + return 0; +} + +std::string WebUser::GetBase64(HGImage image) +{ + std::string ret; + + if (NULL != image) + { + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image, &xDpi, &yDpi); + + HGBuffer buffer = NULL; + HGJpegSaveInfo saveInfo; + saveInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + saveInfo.xDensity = xDpi; + saveInfo.yDensity = yDpi; + saveInfo.quality = m_jpgQuality; + HGImgFmt_SaveJpegImageToBuffer(image, &saveInfo, &buffer); + if (NULL != buffer) + { + HGByte* data = NULL; + HGBase_GetBufferData(buffer, &data); + HGUSize size = 0; + HGBase_GetBufferSize(buffer, &size); + + HGSize base64Size = 0; + HGBase_Base64Encode(data, size, NULL, &base64Size); + HGByte* base64 = new HGByte[base64Size + 1]; + HGBase_Base64Encode(data, size, base64, &base64Size); + base64[base64Size] = 0; + ret = (const char *)base64; + delete[] base64; + + HGBase_DestroyBuffer(buffer); + } + } + + return ret; +} + +HGBool WebUser::SetParam(const char* optionName, const HGVoid* data) +{ + assert(NULL != m_devHandle); + if (NULL == data || NULL == optionName) + return HGFALSE; + + HGBool ret = HGFALSE; + SANE_Int num_dev_options = 0; + sane_control_option(m_devHandle, 0, SANE_ACTION_GET_VALUE, &num_dev_options, NULL); + for (int i = 1; i < num_dev_options; ++i) + { + const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, i); + if (NULL == desp) + continue; + + const char* name = desp->title; + while (' ' == *name) + ++name; + + if (0 == strcmp(optionName, name)) + { + if (SANE_TYPE_STRING == desp->type) + { + SANE_Char* value = (SANE_Char*)((HGChar*)data); + if (NULL != value) + { + if (SANE_STATUS_GOOD == sane_control_option(m_devHandle, i, SANE_ACTION_SET_VALUE, value, NULL)) + ret = HGTRUE; + } + } + else if (SANE_TYPE_INT == desp->type) + { + SANE_Int value = (SANE_Int)(*(HGInt*)data); + if (SANE_STATUS_GOOD != sane_control_option(m_devHandle, i, SANE_ACTION_SET_VALUE, &value, NULL)) + ret = HGTRUE; + } + else if (SANE_TYPE_FIXED == desp->type) + { + SANE_Fixed value = SANE_FIX(*(HGDouble*)data); + if (SANE_STATUS_GOOD != sane_control_option(m_devHandle, i, SANE_ACTION_SET_VALUE, &value, NULL)) + ret = HGTRUE; + } + else if (SANE_TYPE_BOOL == desp->type) + { + SANE_Bool value = (SANE_Bool)(*(HGBool*)data); + if (SANE_STATUS_GOOD != sane_control_option(m_devHandle, i, SANE_ACTION_SET_VALUE, &value, NULL)) + ret = HGTRUE; + } + + break; + } + } + + return ret; +} + +HGInt WebUser::GetDpi() +{ + assert(NULL != m_devHandle); + HGInt dpi = 96; + + SANE_Int num_dev_options = 0; + sane_control_option(m_devHandle, 0, SANE_ACTION_GET_VALUE, &num_dev_options, NULL); + for (int i = 1; i < num_dev_options; ++i) + { + const SANE_Option_Descriptor* desp = sane_get_option_descriptor(m_devHandle, i); + if (NULL == desp) + continue; + + const char* name = desp->title; + while (' ' == *name) + ++name; + + if (0 == strcmp(OPTION_TITLE_FBL, name)) + { + if (SANE_TYPE_INT == desp->type) + { + SANE_Int value = 96; + sane_control_option(m_devHandle, i, SANE_ACTION_GET_VALUE, &value, NULL); + dpi = value; + } + + break; + } + } + + return dpi; +} + +bool WebUser::ShakeHand(const std::string& head) +{ + std::string requestMethod; + std::string requestURIPath; + HttpPairs requestURIQueryInfos; + std::string requestURIFragment; + std::string httpVersion; + HttpPairs headInfos; + HttpHead::AnalysisHead(head, requestMethod, requestURIPath, requestURIQueryInfos, + requestURIFragment, httpVersion, headInfos); + + HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, head.c_str()); + + //if (std::string::npos == HttpHead::GetValue(headInfos, "Connection").find("Upgrade")) + // return false; + //if ("websocket" != HttpHead::GetValue(headInfos, "Upgrade")) + // return false; + + std::string key = HttpHead::GetValue(headInfos, "Sec-WebSocket-Key"); + if (key.empty()) + return false; + + key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + unsigned int message_digest[5]; + SHA1 sha; + sha.Reset(); + sha << key.c_str(); + sha.Result(message_digest); + + for (int i = 0; i < 5; ++i) + message_digest[i] = htonl(message_digest[i]); + std::string serverKey = base64_encode((const unsigned char*)message_digest, 20); + + std::string handShakeResp = "HTTP/1.1 101 Switching Protocols\r\n"; + handShakeResp += "Upgrade: websocket\r\n"; + handShakeResp += "Connection: Upgrade\r\n"; + handShakeResp += "Sec-WebSocket-Accept:"; + handShakeResp += serverKey; + handShakeResp += "\r\n\r\n"; + send(m_sockConn, handShakeResp.c_str(), (int)handShakeResp.length(), 0); + return true; +} + +void WebUser::Pong() +{ + uint8_t vHead[2]; + vHead[0] = 0x80 | 0x0A; + vHead[1] = 0; + + HGBase_EnterLock(m_lock); + send(m_sockConn, (const char*)vHead, 2, 0); + HGBase_LeaveLock(m_lock); +} + +bool WebUser::SendResponse(const HGByte* data, HGUInt size, HGBool text) +{ + if (NULL == data || 0 == size) + { + return false; + } + + uint32_t nHeadLen = 0; + + uint8_t vHead[20] = { 0 }; + vHead[0] = text ? (0x80 | 0x01) : (0x80 | 0x02); + if (size <= 125) + { + vHead[1] = (uint8_t)size; + nHeadLen = 2; + } + else if (size <= 0xFFFF) + { + vHead[1] = 126; + uint16_t payloadLength16b = htons((uint16_t)size); + memcpy(&vHead[2], &payloadLength16b, 2); + nHeadLen = 4; + } + else + { + vHead[1] = 127; + vHead[2] = 0; + vHead[3] = 0; + vHead[4] = 0; + vHead[5] = 0; + uint32_t payloadLength32b = htonl(size); + memcpy(&vHead[6], &payloadLength32b, 4); + nHeadLen = 10; + } + + HGBase_EnterLock(m_lock); + send(m_sockConn, (const char*)vHead, nHeadLen, 0); + send(m_sockConn, (const char*)data, size, 0); + HGBase_LeaveLock(m_lock); + return true; +} diff --git a/sdk/webscan/WebUser.h b/sdk/webscan/WebUser.h new file mode 100644 index 00000000..a1ab9e66 --- /dev/null +++ b/sdk/webscan/WebUser.h @@ -0,0 +1,78 @@ +#pragma once + +#include "base/HGDef.h" +#include "base/HGInc.h" +#include "base/HGLock.h" +#include "base/HGEvent.h" +#include "base/HGThread.h" +#include "base/HGImage.h" +#include "base/HGMsgPump.h" +#include "Msg.h" +#include "cJSON.h" +#include "sane/sane_ex.h" +#include "sane/sane_option_definitions.h" +#include + +class WebServer; + +class WebUser +{ +public: +#if defined(HG_CMP_MSC) + WebUser(WebServer* server, HGUInt id, HGMsgPump msgPump, const std::string& ip, uint16_t port, SOCKET sockConn); +#else + WebUser(WebServer* server, HGUInt id, HGMsgPump msgPump, const std::string& ip, uint16_t port, int sockConn); +#endif + ~WebUser(); + + HGUInt GetId(); + void CloseDev(const CloseDevParam* param); + void ScanFinish(const ScanFinishParam* param); + void HandleCmd(const WSCmdParam* param); + void HandleEvent(const WSEvtParam* param); + +private: + void GetDeviceList(cJSON *json); + void SelectDevice(cJSON* json); + void SetScanColorType(cJSON* json); + void SetDPI(cJSON* json); + void SetDuplex(cJSON* json); + void SetScanJPGQuality(cJSON* json); + void StartScan(cJSON* json); + +private: + void PostDisConnectMsg(); + void PostCmdMsg(const HGByte* data, HGUInt dataSize); + void PostEventMsg(const HGByte* data, HGUInt dataSize); + static void ThreadFunc(HGThread thread, HGPointer param); + static int sane_ex_callback(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param); + std::string GetBase64(HGImage image); + HGBool SetParam(const char* optionName, const HGVoid* data); + HGInt GetDpi(); + + bool ShakeHand(const std::string& head); + void Pong(); + bool SendResponse(const HGByte* data, HGUInt size, HGBool text); + +private: + HGLock m_lock; + HGLock m_lockName; + WebServer* m_server; + HGUInt m_id; + HGMsgPump m_msgPump; + std::string m_ip; + uint16_t m_port; +#if defined(HG_CMP_MSC) + SOCKET m_sockConn; +#else + int m_sockConn; +#endif + HGThread m_thread; + + int m_jpgQuality; + std::vector m_devNameList; + std::string m_devName; + SANE_Handle m_devHandle; + int m_dpi; + HGEvent m_scanEvent; +}; diff --git a/sdk/webscan/main.cpp b/sdk/webscan/main.cpp new file mode 100644 index 00000000..badff794 --- /dev/null +++ b/sdk/webscan/main.cpp @@ -0,0 +1,50 @@ +#include "base/HGDef.h" +#include "base/HGInc.h" +#include "base/HGThread.h" +#include "base/HGMsgPump.h" +#include "WebServer.h" +#include "MsgPumpCallback.h" + +static void ThreadFunc(HGThread thread, HGPointer param) +{ + (void)thread; + HGMsgPump msgPump = (HGMsgPump)param; + + WebServer wsServer(msgPump); + + HGInt port = 9458; + if (wsServer.Open(port)) + { + HGBase_RunMsgPump(msgPump, HGMsgPumpCallback, NULL); + wsServer.Close(); + } +} + +#if defined(HG_CMP_MSC) +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE iPrevInstance, LPWSTR lpCmdLine, int nCmdShow) +#else +int main() +#endif +{ +#if defined(HG_CMP_MSC) + WSADATA ws = { 0 }; + int ret = WSAStartup(MAKEWORD(2, 2), &ws); + assert(0 == ret); +#endif + + HGMsgPump msgPump = NULL; + HGBase_CreateMsgPump(&msgPump); + + HGThread thread = NULL; + HGBase_OpenThread(ThreadFunc, msgPump, &thread); + HGBase_CloseThread(thread); + thread = NULL; + + HGBase_DestroyMsgPump(msgPump); + msgPump = NULL; + +#if defined(HG_CMP_MSC) + WSACleanup(); +#endif + return 0; +} \ No newline at end of file diff --git a/test/webscan/demo.html b/test/webscan/demo.html new file mode 100644 index 00000000..6d6899d5 --- /dev/null +++ b/test/webscan/demo.html @@ -0,0 +1,190 @@ + +Test + + + + + + + + + + + + + + + + + + +
+
+ + + +