1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "InputCodingTableBaiduPY.h"
10 
11 #include "ServiceBroker.h"
12 #include "filesystem/CurlFile.h"
13 #include "guilib/GUIComponent.h"
14 #include "guilib/GUIMessage.h"
15 #include "guilib/GUIWindowManager.h"
16 #include "utils/RegExp.h"
17 #include "utils/StringUtils.h"
18 
19 #include <stdlib.h>
20 #include <utility>
21 
CInputCodingTableBaiduPY(const std::string & strUrl)22 CInputCodingTableBaiduPY::CInputCodingTableBaiduPY(const std::string& strUrl)
23   : CThread("BaiduPYApi"),
24     m_messageCounter{0},
25     m_api_begin{0},
26     m_api_end{20},
27     m_api_nomore{false},
28     m_initialized{false}
29 {
30   m_url = strUrl;
31   m_codechars = "abcdefghijklmnopqrstuvwxyz";
32   m_code = "";
33 }
34 
Process()35 void CInputCodingTableBaiduPY::Process()
36 {
37   m_initialized = true;
38   while (!m_bStop) // Make sure we don't exit the thread
39   {
40     AbortableWait(m_Event, -1); // Wait for work to appear
41     while (!m_bStop) // Process all queued work before going back to wait on the event
42     {
43       CSingleLock lock(m_CS);
44       if (m_work.empty())
45         break;
46 
47       auto work = m_work.front();
48       m_work.pop_front();
49       lock.Leave();
50 
51       std::string data;
52       XFILE::CCurlFile http;
53       std::string strUrl;
54       strUrl = StringUtils::Format(m_url.c_str(), work.c_str(), m_api_begin, m_api_end);
55 
56       if (http.Get(strUrl, data))
57         HandleResponse(work, data);
58     }
59   }
60 }
61 
HandleResponse(const std::string & strCode,const std::string & response)62 void CInputCodingTableBaiduPY::HandleResponse(const std::string& strCode,
63                                               const std::string& response)
64 {
65   if (strCode != m_code) // don't handle obsolete response
66     return;
67 
68   std::vector<std::wstring> words;
69   CRegExp reg;
70   reg.RegComp("\\[\"(.+?)\",[^\\]]+\\]");
71   int pos = 0;
72   int num = 0;
73   while ((pos = reg.RegFind(response.c_str(), pos)) >= 0)
74   {
75     num++;
76     std::string full = reg.GetMatch(0);
77     std::string word = reg.GetMatch(1);
78     pos += full.length();
79     words.push_back(UnicodeToWString(word));
80   }
81   if (words.size() < 20)
82     m_api_nomore = true;
83   else
84   {
85     m_api_begin += 20;
86     m_api_end += 20;
87   }
88   CSingleLock lock(m_CS);
89   m_responses.insert(std::make_pair(++m_messageCounter, words));
90   CGUIMessage msg(GUI_MSG_CODINGTABLE_LOOKUP_COMPLETED, 0, 0, m_messageCounter);
91   msg.SetStringParam(strCode);
92   lock.Leave();
93   CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(
94       msg, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog());
95 }
96 
UnicodeToWString(const std::string & unicode)97 std::wstring CInputCodingTableBaiduPY::UnicodeToWString(const std::string& unicode)
98 {
99   std::wstring result = L"";
100   for (unsigned int i = 0; i < unicode.length(); i += 6)
101   {
102     int c;
103     sscanf(unicode.c_str() + i, "\\u%x", &c);
104     result += (wchar_t)c;
105   }
106   return result;
107 }
108 
GetResponse(int response)109 std::vector<std::wstring> CInputCodingTableBaiduPY::GetResponse(int response)
110 {
111   CSingleLock lock(m_CS);
112   auto words = m_responses.at(response);
113   m_responses.erase(response);
114   return words;
115 }
116 
Initialize()117 void CInputCodingTableBaiduPY::Initialize()
118 {
119   CSingleLock lock(m_CS);
120   if (!IsRunning())
121     Create();
122 }
123 
Deinitialize()124 void CInputCodingTableBaiduPY::Deinitialize()
125 {
126   m_Event.Set();
127   StopThread(true);
128   m_initialized = false;
129 }
130 
IsInitialized() const131 bool CInputCodingTableBaiduPY::IsInitialized() const
132 {
133   return m_initialized;
134 }
135 
GetWordListPage(const std::string & strCode,bool isFirstPage)136 bool CInputCodingTableBaiduPY::GetWordListPage(const std::string& strCode, bool isFirstPage)
137 {
138   if (strCode.empty())
139     return false;
140   if (isFirstPage || m_code != strCode)
141   {
142     m_api_begin = 0;
143     m_api_end = 20;
144     m_code = strCode;
145     m_api_nomore = false;
146   }
147   else
148   {
149     if (m_api_nomore)
150       return false;
151   }
152 
153   CSingleLock lock(m_CS);
154   m_work.push_back(strCode);
155   m_Event.Set();
156   return true;
157 }
158