VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/python/xpt.py

Last change on this file was 59798, checked in by vboxsync, 8 years ago

re-applied the Python 3 changes which were backed out in r105674 sans the changes in .cpp

  • Property svn:eol-style set to native
File size: 17.2 KB
Line 
1# ***** BEGIN LICENSE BLOCK *****
2# Version: MPL 1.1/GPL 2.0/LGPL 2.1
3#
4# The contents of this file are subject to the Mozilla Public License Version
5# 1.1 (the "License"); you may not use this file except in compliance with
6# the License. You may obtain a copy of the License at
7# http://www.mozilla.org/MPL/
8#
9# Software distributed under the License is distributed on an "AS IS" basis,
10# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11# for the specific language governing rights and limitations under the
12# License.
13#
14# The Original Code is the Python XPCOM language bindings.
15#
16# The Initial Developer of the Original Code is
17# ActiveState Tool Corp.
18# Portions created by the Initial Developer are Copyright (C) 2000, 2001
19# the Initial Developer. All Rights Reserved.
20#
21# Contributor(s):
22# David Ascher <DavidA@ActiveState.com> (original author)
23# Mark Hammond <mhammond@skippinet.com.au>
24#
25# Alternatively, the contents of this file may be used under the terms of
26# either the GNU General Public License Version 2 or later (the "GPL"), or
27# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28# in which case the provisions of the GPL or the LGPL are applicable instead
29# of those above. If you wish to allow use of your version of this file only
30# under the terms of either the GPL or the LGPL, and not to allow others to
31# use your version of this file under the terms of the MPL, indicate your
32# decision by deleting the provisions above and replace them with the notice
33# and other provisions required by the GPL or the LGPL. If you do not delete
34# the provisions above, a recipient may use your version of this file under
35# the terms of any one of the MPL, the GPL or the LGPL.
36#
37# ***** END LICENSE BLOCK *****
38
39"""
40Program: xpt.py
41
42Task: describe interfaces etc using XPCOM reflection.
43
44Subtasks:
45 output (nearly) exactly the same stuff as xpt_dump, for verification
46 output Python source code that can be used as a template for an interface
47
48Status: Works pretty well if you ask me :-)
49
50Author:
51 David Ascher did an original version that parsed XPT files
52 directly. Mark Hammond changed it to use the reflection interfaces,
53 but kept most of the printing logic.
54
55
56Revision:
57
58 0.1: March 6, 2000
59 0.2: April 2000 - Mark removed lots of Davids lovely parsing code in favour
60 of the new xpcom interfaces that provide this info.
61
62 May 2000 - Moved into Perforce - track the log there!
63 Early 2001 - Moved into the Mozilla CVS tree - track the log there!
64
65Todo:
66 Fill out this todo list.
67
68"""
69
70import string, sys
71import xpcom
72import xpcom._xpcom
73
74from .xpcom_consts import *
75
76class Interface:
77 def __init__(self, iid):
78 iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager()
79 if hasattr(iid, "upper"): # Is it a stringy thing.
80 item = iim.GetInfoForName(iid)
81 else:
82 item = iim.GetInfoForIID(iid)
83 self.interface_info = item
84 self.namespace = "" # where does this come from?
85 self.methods = Methods(item)
86 self.constants = Constants(item)
87
88 # delegate attributes to the real interface
89 def __getattr__(self, attr):
90 return getattr(self.interface_info, attr)
91
92 def GetParent(self):
93 try:
94 raw_parent = self.interface_info.GetParent()
95 if raw_parent is None:
96 return None
97 return Interface(raw_parent.GetIID())
98 except xpcom.Exception:
99 # Parent interface is probably not scriptable - assume nsISupports.
100 if xpcom.verbose:
101 # The user may be confused as to why this is happening!
102 print("The parent interface of IID '%s' can not be located - assuming nsISupports")
103 return Interface(xpcom._xpcom.IID_nsISupports)
104
105 def Describe_Python(self):
106 method_reprs = []
107 methods = [m for m in self.methods if not m.IsNotXPCOM()]
108 for m in methods:
109 method_reprs.append(m.Describe_Python())
110 method_joiner = "\n"
111 methods_repr = method_joiner.join(method_reprs)
112 return \
113"""class %s:
114 _com_interfaces_ = xpcom.components.interfaces.%s
115 # If this object needs to be registered, the following 2 are also needed.
116 # _reg_clsid_ = "{a new clsid generated for this object}"
117 # _reg_contractid_ = "The.Object.Name"\n%s""" % (self.GetName(), self.GetIID().name, methods_repr)
118
119 def Describe(self):
120 # Make the IID look like xtp_dump - "(" instead of "{"
121 iid_use = "(" + str(self.GetIID())[1:-1] + ")"
122 s = ' - '+self.namespace+'::'+ self.GetName() + ' ' + iid_use + ':\n'
123
124 parent = self.GetParent()
125 if parent is not None:
126 s = s + ' Parent: ' + parent.namespace + '::' + parent.GetName() + '\n'
127 s = s + ' Flags:\n'
128 if self.IsScriptable(): word = 'TRUE'
129 else: word = 'FALSE'
130 s = s + ' Scriptable: ' + word + '\n'
131 s = s + ' Methods:\n'
132 methods = [m for m in self.methods if not m.IsNotXPCOM()]
133 if len(methods):
134 for m in methods:
135 s = s + ' ' + m.Describe() + '\n'
136 else:
137 s = s + ' No Methods\n'
138 s = s + ' Constants:\n'
139 if self.constants:
140 for c in self.constants:
141 s = s + ' ' + c.Describe() + '\n'
142 else:
143 s = s + ' No Constants\n'
144
145 return s
146
147# A class that allows caching and iterating of methods.
148class Methods:
149 def __init__(self, interface_info):
150 self.interface_info = interface_info
151 try:
152 self.items = [None] * interface_info.GetMethodCount()
153 except xpcom.Exception:
154 if xpcom.verbose:
155 print("** GetMethodCount failed?? - assuming no methods")
156 self.items = []
157 def __len__(self):
158 return len(self.items)
159 def __getitem__(self, index):
160 ret = self.items[index]
161 if ret is None:
162 mi = self.interface_info.GetMethodInfo(index)
163 ret = self.items[index] = Method(mi, index, self.interface_info)
164 return ret
165
166class Method:
167
168 def __init__(self, method_info, method_index, interface_info = None):
169 self.interface_info = interface_info
170 self.method_index = method_index
171 self.flags, self.name, param_descs, self.result_desc = method_info
172 # Build the params.
173 self.params = []
174 pi=0
175 for pd in param_descs:
176 self.params.append( Parameter(pd, pi, method_index, interface_info) )
177 pi = pi + 1
178 # Run over the params setting the "sizeof" params to hidden.
179 for p in self.params:
180 td = p.type_desc
181 tag = XPT_TDP_TAG(td[0])
182 if tag==T_ARRAY and p.IsIn():
183 self.params[td[1]].hidden_indicator = 2
184 elif tag in [T_PSTRING_SIZE_IS, T_PWSTRING_SIZE_IS] and p.IsIn():
185 self.params[td[1]].hidden_indicator = 1
186
187 def IsGetter(self):
188 return (self.flags & XPT_MD_GETTER)
189 def IsSetter(self):
190 return (self.flags & XPT_MD_SETTER)
191 def IsNotXPCOM(self):
192 return (self.flags & XPT_MD_NOTXPCOM)
193 def IsConstructor(self):
194 return (self.flags & XPT_MD_CTOR)
195 def IsHidden(self):
196 return (self.flags & XPT_MD_HIDDEN)
197
198 def Describe_Python(self):
199 if self.method_index < 3: # Ignore QI etc
200 return ""
201 base_name = self.name
202 if self.IsGetter():
203 name = "get_%s" % (base_name,)
204 elif self.IsSetter():
205 name = "set_%s" % (base_name,)
206 else:
207 name = base_name
208 param_decls = ["self"]
209 in_comments = []
210 out_descs = []
211 result_comment = "Result: void - None"
212 for p in self.params:
213 in_desc, in_desc_comments, out_desc, this_result_comment = p.Describe_Python()
214 if in_desc is not None:
215 param_decls.append(in_desc)
216 if in_desc_comments is not None:
217 in_comments.append(in_desc_comments)
218 if out_desc is not None:
219 out_descs.append(out_desc)
220 if this_result_comment is not None:
221 result_comment = this_result_comment
222 joiner = "\n # "
223 in_comment = out_desc = ""
224 if in_comments: in_comment = joiner + joiner.join(in_comments)
225 if out_descs: out_desc = joiner + joiner.join(out_descs)
226
227 return """ def %s( %s ):
228 # %s%s%s
229 pass""" % (name, ", ".join(param_decls), result_comment, in_comment, out_desc)
230
231 def Describe(self):
232 s = ''
233 if self.IsGetter():
234 G = 'G'
235 else:
236 G = ' '
237 if self.IsSetter():
238 S = 'S'
239 else: S = ' '
240 if self.IsHidden():
241 H = 'H'
242 else:
243 H = ' '
244 if self.IsNotXPCOM():
245 N = 'N'
246 else:
247 N = ' '
248 if self.IsConstructor():
249 C = 'C'
250 else:
251 C = ' '
252
253 def desc(a): return a.Describe()
254 method_desc = string.join(list(map(desc, self.params)), ', ')
255 result_type = TypeDescriber(self.result_desc[0], None)
256 return_desc = result_type.Describe()
257 i = string.find(return_desc, 'retval ')
258 if i != -1:
259 return_desc = return_desc[:i] + return_desc[i+len('retval '):]
260 return G+S+H+N+C+' '+return_desc+' '+self.name + '('+ method_desc + ');'
261
262class Parameter:
263 def __init__(self, param_desc, param_index, method_index, interface_info = None):
264 self.param_flags, self.type_desc = param_desc
265 self.hidden_indicator = 0 # Is this a special "size" type param that will be hidden from Python?
266 self.param_index = param_index
267 self.method_index= method_index
268 self.interface_info = interface_info
269 def __repr__(self):
270 return "<param %(param_index)d (method %(method_index)d) - flags = 0x%(param_flags)x, type = %(type_desc)s>" % self.__dict__
271 def IsIn(self):
272 return XPT_PD_IS_IN(self.param_flags)
273 def IsOut(self):
274 return XPT_PD_IS_OUT(self.param_flags)
275 def IsInOut(self):
276 return self.IsIn() and self.IsOut()
277 def IsRetval(self):
278 return XPT_PD_IS_RETVAL(self.param_flags)
279 def IsShared(self):
280 return XPT_PD_IS_SHARED(self.param_flags)
281 def IsDipper(self):
282 return XPT_PD_IS_DIPPER(self.param_flags)
283
284 def Describe_Python(self):
285 name = "param%d" % (self.param_index,)
286 if self.hidden_indicator:
287 # Could remove the comment - Im trying to tell the user where that param has
288 # gone from the signature!
289 return None, "%s is a hidden parameter" % (name,), None, None
290 t = TypeDescriber(self.type_desc[0], self)
291 decl = in_comment = out_comment = result_comment = None
292 type_desc = t.Describe()
293 if self.IsIn() and not self.IsDipper():
294 decl = name
295 extra=""
296 if self.IsOut():
297 extra = "Out"
298 in_comment = "In%s: %s: %s" % (extra, name, type_desc)
299 elif self.IsOut() or self.IsDipper():
300 if self.IsRetval():
301 result_comment = "Result: %s" % (type_desc,)
302 else:
303 out_comment = "Out: %s" % (type_desc,)
304 return decl, in_comment, out_comment, result_comment
305
306 def Describe(self):
307 parts = []
308 if self.IsInOut():
309 parts.append('inout')
310 elif self.IsIn():
311 parts.append('in')
312 elif self.IsOut():
313 parts.append('out')
314
315 if self.IsDipper(): parts.append("dipper")
316 if self.IsRetval(): parts.append('retval')
317 if self.IsShared(): parts.append('shared')
318 t = TypeDescriber(self.type_desc[0], self)
319 type_str = t.Describe()
320 parts.append(type_str)
321 return string.join(parts)
322
323# A class that allows caching and iterating of constants.
324class Constants:
325 def __init__(self, interface_info):
326 self.interface_info = interface_info
327 try:
328 self.items = [None] * interface_info.GetConstantCount()
329 except xpcom.Exception:
330 if xpcom.verbose:
331 print("** GetConstantCount failed?? - assuming no constants")
332 self.items = []
333 def __len__(self):
334 return len(self.items)
335 def __getitem__(self, index):
336 ret = self.items[index]
337 if ret is None:
338 ci = self.interface_info.GetConstant(index)
339 ret = self.items[index] = Constant(ci)
340 return ret
341
342class Constant:
343 def __init__(self, ci):
344 self.name, self.type, self.value = ci
345
346 def Describe(self):
347 return TypeDescriber(self.type, None).Describe() + ' ' +self.name+' = '+str(self.value)+';'
348
349 __str__ = Describe
350
351def MakeReprForInvoke(param):
352 tag = param.type_desc[0] & XPT_TDP_TAGMASK
353 if tag == T_INTERFACE:
354 i_info = param.interface_info
355 try:
356 iid = i_info.GetIIDForParam(param.method_index, param.param_index)
357 except xpcom.Exception:
358 # IID not available (probably not scriptable) - just use nsISupports.
359 iid = xpcom._xpcom.IID_nsISupports
360 return param.type_desc[0], 0, 0, str(iid)
361 elif tag == T_ARRAY:
362 i_info = param.interface_info
363 array_desc = i_info.GetTypeForParam(param.method_index, param.param_index, 1)
364 return param.type_desc[:-1] + array_desc[:1]
365 return param.type_desc
366
367
368class TypeDescriber:
369 def __init__(self, type_flags, param):
370 self.type_flags = type_flags
371 self.tag = XPT_TDP_TAG(self.type_flags)
372 self.param = param
373 def IsPointer(self):
374 return XPT_TDP_IS_POINTER(self.type_flags)
375 def IsUniquePointer(self):
376 return XPT_TDP_IS_UNIQUE_POINTER(self.type_flags)
377 def IsReference(self):
378 return XPT_TDP_IS_REFERENCE(self.type_flags)
379 def repr_for_invoke(self):
380 return (self.type_flags,)
381 def GetName(self):
382 is_ptr = self.IsPointer()
383 data = type_info_map.get(self.tag)
384 if data is None:
385 data = ("unknown",)
386 if self.IsReference():
387 if len(data) > 2:
388 return data[2]
389 return data[0] + " &"
390 if self.IsPointer():
391 if len(data)>1:
392 return data[1]
393 return data[0] + " *"
394 return data[0]
395
396 def Describe(self):
397 if self.tag == T_ARRAY:
398 # NOTE - Adding a type specifier to the array is different from xpt_dump.exe
399 if self.param is None or self.param.interface_info is None:
400 type_desc = "" # Dont have explicit info about the array type :-(
401 else:
402 i_info = self.param.interface_info
403 type_code = i_info.GetTypeForParam(self.param.method_index, self.param.param_index, 1)
404 type_desc = TypeDescriber( type_code[0], None).Describe()
405 return self.GetName() + "[" + type_desc + "]"
406 elif self.tag == T_INTERFACE:
407 if self.param is None or self.param.interface_info is None:
408 return "nsISomething" # Dont have explicit info about the IID :-(
409 i_info = self.param.interface_info
410 m_index = self.param.method_index
411 p_index = self.param.param_index
412 try:
413 iid = i_info.GetIIDForParam(m_index, p_index)
414 return iid.name
415 except xpcom.Exception:
416 return "nsISomething"
417 return self.GetName()
418
419# These are just for output purposes, so should be
420# the same as xpt_dump uses
421type_info_map = {
422 T_I8 : ("int8",),
423 T_I16 : ("int16",),
424 T_I32 : ("int32",),
425 T_I64 : ("int64",),
426 T_U8 : ("uint8",),
427 T_U16 : ("uint16",),
428 T_U32 : ("uint32",),
429 T_U64 : ("uint64",),
430 T_FLOAT : ("float",),
431 T_DOUBLE : ("double",),
432 T_BOOL : ("boolean",),
433 T_CHAR : ("char",),
434 T_WCHAR : ("wchar_t", "wstring"),
435 T_VOID : ("void",),
436 T_IID : ("reserved", "nsIID *", "nsIID &"),
437 T_DOMSTRING : ("DOMString",),
438 T_CHAR_STR : ("reserved", "string"),
439 T_WCHAR_STR : ("reserved", "wstring"),
440 T_INTERFACE : ("reserved", "Interface"),
441 T_INTERFACE_IS : ("reserved", "InterfaceIs *"),
442 T_ARRAY : ("reserved", "Array"),
443 T_PSTRING_SIZE_IS : ("reserved", "string_s"),
444 T_PWSTRING_SIZE_IS : ("reserved", "wstring_s"),
445}
446
447def dump_interface(iid, mode):
448 interface = Interface(iid)
449 describer_name = "Describe"
450 if mode == "xptinfo": mode = None
451 if mode is not None:
452 describer_name = describer_name + "_" + mode.capitalize()
453 describer = getattr(interface, describer_name)
454 print(describer())
455
456if __name__=='__main__':
457 if len(sys.argv) == 1:
458 print("Usage: xpt.py [-xptinfo] interface_name, ...")
459 print(" -info: Dump in a style similar to the xptdump tool")
460 print("Dumping nsISupports and nsIInterfaceInfo")
461 sys.argv.append('nsIInterfaceInfo')
462 sys.argv.append('-xptinfo')
463 sys.argv.append('nsISupports')
464 sys.argv.append('nsIInterfaceInfo')
465
466 mode = "Python"
467 for i in sys.argv[1:]:
468 if i[0] == "-":
469 mode = i[1:]
470 else:
471 dump_interface(i, mode)
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use