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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+