1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 import json
32 import os
33
34 import JsonHelper
35
36
38 """
39 Data provider for request concerning WinApi information.
40 """
41
43 print ("Loading WinApiProvider")
44 self.idascope_config = idascope_config
45 self.os = os
46 self.winapi_data = {}
47 if self.idascope_config.winapi_load_keyword_database:
48 self._load_keywords()
49 self.last_delivered_filepath = self.idascope_config.winapi_rootdir
50 self.backward_history = []
51 self.forward_history = []
52 self.is_appending_to_history = True
53
55 """
56 Loads the keywords database from the file specified in the config.
57 """
58 keywords_file = open(self.idascope_config.winapi_keywords_file, "r")
59 self.winapi_data = json.loads(keywords_file.read(), object_hook=JsonHelper.decode_dict)
60
62 """
63 Determines wther the offline MSDN database is available or not.
64 This is evaluated based on whether the keywords database has been loaded or not.
65 @return: (bool) availablity of the MSDN database
66 """
67 if len(self.winapi_data.keys()) > 0:
68 return True
69 return False
70
72 """
73 Get all keywords that start with the given initial character.
74 @param keyword_initial: an initial character
75 @type keyword_initial: str
76 @return: (a list of str) keywords in WinApi that start with that initial.
77 """
78 if keyword_initial in self.winapi_data.keys():
79 return sorted(self.winapi_data[keyword_initial], key=str.lower)
80 else:
81 return []
82
83 - def get_keyword_content(self, keyword):
84 """
85 Get the content for this keyword.
86 @type keyword: str
87 @return: (str) HTML content.
88 """
89 api_filenames = self._get_api_filenames(keyword)
90 if len(api_filenames) == 1:
91 api_filenames = [self.idascope_config.winapi_rootdir + api_filenames[0]]
92 return self._get_document_content(api_filenames)
93
95 """
96 Get the content for a requested linked document
97 @param url: URL of the requested file
98 @type url: QUrl
99 @return: a tuple (str, str) with content and anchor within the content
100 """
101 anchor = ""
102 if url.isRelative():
103 url_str = url.toString()
104 anchor = ""
105 document_content = ""
106 if "#" in url_str:
107 anchor = url_str[1 + url_str.rfind("#"):]
108 url_str = url_str[:url_str.rfind("#")]
109 if url_str != "":
110 filename = self.os.path.join(str(self.last_delivered_filepath), str(url_str))
111 document_content = self._get_single_document_content(filename)
112 return document_content, anchor
113 else:
114 return self._get_single_document_content(url.toString()), anchor
115
117 """
118 Get information about whether history stepping (backward, forward) is available or not.
119 @return: a tuple (boolean, boolean) telling about availability of history stepping.
120 """
121 return (len(self.backward_history) > 1, len(self.forward_history) > 0)
122
124 """
125 Get the content of the previously accessed document. This implements the well-known "back"-button
126 functionality.
127 @return: a tuple (str, str) with content and anchor within the content
128 """
129 self._cleanup_histories()
130
131 if len(self.backward_history) > 0:
132 history_entry = self.backward_history.pop()
133 self.forward_history.append(history_entry)
134
135 if len(self.backward_history) > 0:
136 self.is_appending_to_history = False
137 history_entry = self.backward_history[-1]
138 document_content = self._get_document_content(history_entry[0]), history_entry[1]
139 self.is_appending_to_history = True
140 return document_content
141 return ("", "")
142
144 """
145 Get the content of the previously accessed document. This implements the well-known "back"-button
146 functionality.
147 @return: a tuple (str, str) with content and anchor within the content
148 """
149
150 self._cleanup_histories()
151 if len(self.forward_history) > 0:
152 history_entry = self.forward_history.pop()
153 self.backward_history.append(history_entry)
154 self.is_appending_to_history = False
155 document_content = self._get_document_content(history_entry[0]), history_entry[1]
156 self.is_appending_to_history = True
157 return document_content
158 return ("", "")
159
161 """
162 Eliminate subsequent similar items from history lists
163 """
164 self.backward_history = self._cleanup_list(self.backward_history)
165 self.forward_history = self._cleanup_list(self.forward_history)
166
168 """
169 Eliminate subsequent similar items from a list
170 @param input_list: A list of arbitrary items
171 @type input_list: list
172 @return: (list) the input list without subsequent similar items
173 """
174 cleaned_list = []
175 last_entry = None
176 for entry in input_list:
177 if entry != last_entry:
178 cleaned_list.append(entry)
179 last_entry = entry
180 return cleaned_list
181
183 """
184 Get filenames that are associated with the given keyword.
185 @param keyword: keyword to get the filenames for
186 @type keyword: str
187 @return: (a list of str) filenames that cover this keyword.
188 """
189 if len(keyword) > 0:
190 keyword_initial = keyword[0].lower()
191 if keyword_initial in self.winapi_data.keys():
192 if keyword in self.winapi_data[keyword_initial]:
193 return self.winapi_data[keyword_initial][keyword]
194 return []
195
196 - def _get_document_content(self, filenames):
197 """
198 Produce the document content for a given list of filenames.
199 If there are multiple filenames, no document content is returned but a rendered list fo the filenames,
200 @param filenames: the filename(s) to get content for
201 @type filenames: list of str
202 @return: (str) HTML content.
203 """
204 document_content = "<p>No entries for your query.</p>"
205 if len(filenames) > 1:
206 document_content = self._generate_html_list_of_filenames(filenames)
207 if self.is_appending_to_history:
208 self.forward_history = []
209 self.backward_history.append((filenames, ""))
210 self._cleanup_histories()
211 elif len(filenames) == 1:
212 document_content = self._get_single_document_content(filenames[0])
213 return document_content
214
216 """
217 Convert a list of filenames as string into a mini-HTML document with the list entries as links to the files
218 in a bullet list.
219 @param filenames: the filenames to include in the bullet list
220 @type filenames: list of str
221 @return: (str) a HTML file with a bullet list of links to the filenames
222 """
223 document_content = "<p>Multiple files are covering this keyword. Choose one:</p><ul>"
224 for filename in filenames:
225
226 filename = filename.replace('\\', self.os.sep)
227 document_content += "<li><a href=\"%s\">%s</a></li>" % (self.idascope_config.winapi_rootdir + \
228 filename, filename)
229 return document_content
230
232 """
233 Load a single document by filename and return its content.
234 @param filename: the filename to load
235 @type filename: str
236 @return: (str) the content of the file
237 """
238 document_content = ""
239 try:
240
241 filename = filename.replace('\\', self.os.sep)
242 with open(filename, "r") as f:
243 document_content = f.read()
244 self.last_delivered_filepath = filename[:filename.rfind(self.os.sep)] + self.os.sep
245 if self.is_appending_to_history:
246 self.forward_history = []
247 self.backward_history.append(([filename], ""))
248 self._cleanup_histories()
249 except Exception as exc:
250 document_content = "<html><head /><body>Well, something has gone wrong here. Try again with some" \
251 + " proper API name.<hr /><p>Exception: %s</p></body></html>" % exc
252 return document_content
253