• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
2# reserved. Use of this source code is governed by a BSD-style license that
3# can be found in the LICENSE file.
4
5from __future__ import absolute_import
6from cef_parser import *
7
8
9def make_ctocpp_impl_proto(clsname, name, func, parts):
10  const = ''
11
12  proto = 'NO_SANITIZE("cfi-icall") '
13  if clsname is None:
14    proto += 'CEF_GLOBAL ' + parts['retval'] + ' '
15  else:
16    proto += parts['retval'] + ' ' + clsname
17    if isinstance(func, obj_function_virtual):
18      proto += 'CToCpp'
19      if func.is_const():
20        const = ' const'
21
22    proto += '::'
23
24  proto += name + '(' + ', '.join(parts['args']) + ')' + const
25  return proto
26
27
28def make_ctocpp_function_impl_existing(clsname, name, func, impl):
29  notify(name + ' has manual edits')
30
31  # retrieve the C++ prototype parts
32  parts = func.get_cpp_parts(True)
33
34  changes = format_translation_changes(impl, parts)
35  if len(changes) > 0:
36    notify(name + ' prototype changed')
37
38  return make_ctocpp_impl_proto(clsname, name, func, parts)+'{'+ \
39         changes+impl['body']+'\n}\n\n'
40
41
42def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
43  # Special handling for the CefShutdown global function.
44  is_cef_shutdown = name == 'CefShutdown' and isinstance(
45      func.parent, obj_header)
46
47  # build the C++ prototype
48  parts = func.get_cpp_parts(True)
49  result = make_ctocpp_impl_proto(clsname, name, func, parts) + ' {'
50
51  if isinstance(func.parent, obj_class) and \
52      not func.parent.has_attrib('no_debugct_check') and \
53      not base_scoped:
54    result += '\n  shutdown_checker::AssertNotShutdown();\n'
55
56  if isinstance(func, obj_function_virtual):
57    # determine how the struct should be referenced
58    if clsname == func.parent.get_name():
59      result += '\n  ' + get_capi_name(clsname,
60                                       True) + '* _struct = GetStruct();'
61    else:
62      result += '\n  '+func.parent.get_capi_name()+'* _struct = reinterpret_cast<'+\
63                func.parent.get_capi_name()+'*>(GetStruct());'
64
65  invalid = []
66
67  # retrieve the function arguments
68  args = func.get_arguments()
69
70  # determine the argument types
71  for arg in args:
72    if arg.get_arg_type() == 'invalid':
73      invalid.append(arg.get_name())
74
75  # retrieve the function return value
76  retval = func.get_retval()
77  retval_type = retval.get_retval_type()
78  if retval_type == 'invalid':
79    invalid.append('(return value)')
80    retval_default = ''
81  else:
82    retval_default = retval.get_retval_default(False)
83    if len(retval_default) > 0:
84      retval_default = ' ' + retval_default
85
86  # add API hash check
87  if func.has_attrib('api_hash_check'):
88    result += '\n  const char* api_hash = cef_api_hash(0);'\
89              '\n  if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {'\
90              '\n    // The libcef API hash does not match the current header API hash.'\
91              '\n    NOTREACHED();'\
92              '\n    return'+retval_default+';'\
93              '\n  }\n'
94
95  if isinstance(func, obj_function_virtual):
96    # add the structure size check
97    result += '\n  if (CEF_MEMBER_MISSING(_struct, ' + func.get_capi_name(
98    ) + '))'
99    result += '\n    return' + retval_default + ';\n'
100
101  if len(invalid) > 0:
102    notify(name + ' could not be autogenerated')
103    # code could not be auto-generated
104    result += '\n  // BEGIN DELETE BEFORE MODIFYING'
105    result += '\n  // AUTO-GENERATED CONTENT'
106    result += '\n  // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
107    result += '\n  #pragma message("Warning: "__FILE__": ' + name + ' is not implemented")'
108    result += '\n  // END DELETE BEFORE MODIFYING'
109    result += '\n}\n\n'
110    return result
111
112  result += '\n  // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n'
113
114  result_len = len(result)
115
116  optional = []
117
118  # parameter verification
119  for arg in args:
120    arg_type = arg.get_arg_type()
121    arg_name = arg.get_type().get_name()
122
123    # skip optional params
124    optional_params = arg.parent.get_attrib_list('optional_param')
125    if not optional_params is None and arg_name in optional_params:
126      optional.append(arg_name)
127      continue
128
129    comment = '\n  // Verify param: ' + arg_name + '; type: ' + arg_type
130
131    if arg_type == 'simple_byaddr' or arg_type == 'bool_byaddr':
132      result += comment+\
133                '\n  DCHECK('+arg_name+');'\
134                '\n  if (!'+arg_name+')'\
135                '\n    return'+retval_default+';'
136    elif arg_type == 'refptr_same' or arg_type == 'refptr_diff' or \
137         arg_type == 'ownptr_same' or arg_type == 'ownptr_diff':
138      result += comment+\
139                '\n  DCHECK('+arg_name+'.get());'\
140                '\n  if (!'+arg_name+'.get())'\
141                '\n    return'+retval_default+';'
142    elif arg_type == 'rawptr_same' or arg_type == 'rawptr_diff':
143      result += comment+\
144                '\n  DCHECK('+arg_name+');'\
145                '\n  if (!'+arg_name+')'\
146                '\n    return'+retval_default+';'
147    elif arg_type == 'string_byref_const':
148      result += comment+\
149                '\n  DCHECK(!'+arg_name+'.empty());'\
150                '\n  if ('+arg_name+'.empty())'\
151                '\n    return'+retval_default+';'
152
153    # check index params
154    index_params = arg.parent.get_attrib_list('index_param')
155    if not index_params is None and arg_name in index_params:
156      result += comment+\
157                '\n  DCHECK_GE('+arg_name+', 0);'\
158                '\n  if ('+arg_name+' < 0)'\
159                '\n    return'+retval_default+';'
160
161  if len(optional) > 0:
162    # Wrap the comment at 80 characters.
163    str = '\n  // Unverified params: ' + optional[0]
164    for name in optional[1:]:
165      str += ','
166      if len(str) + len(name) + 1 > 80:
167        result += str
168        str = '\n  //'
169      str += ' ' + name
170    result += str
171
172  if len(result) != result_len:
173    result += '\n'
174  result_len = len(result)
175
176  # parameter translation
177  params = []
178  if isinstance(func, obj_function_virtual):
179    params.append('_struct')
180
181  for arg in args:
182    arg_type = arg.get_arg_type()
183    arg_name = arg.get_type().get_name()
184
185    comment = '\n  // Translate param: ' + arg_name + '; type: ' + arg_type
186
187    if arg_type == 'simple_byval' or arg_type == 'simple_byaddr' or \
188       arg_type == 'bool_byval':
189      params.append(arg_name)
190    elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \
191        arg_type == 'struct_byref_const' or arg_type == 'struct_byref':
192      params.append('&' + arg_name)
193    elif arg_type == 'bool_byref':
194      result += comment+\
195                '\n  int '+arg_name+'Int = '+arg_name+';'
196      params.append('&' + arg_name + 'Int')
197    elif arg_type == 'bool_byaddr':
198      result += comment+\
199                '\n  int '+arg_name+'Int = '+arg_name+'?*'+arg_name+':0;'
200      params.append('&' + arg_name + 'Int')
201    elif arg_type == 'string_byref_const':
202      params.append(arg_name + '.GetStruct()')
203    elif arg_type == 'string_byref':
204      params.append(arg_name + '.GetWritableStruct()')
205    elif arg_type == 'refptr_same':
206      ptr_class = arg.get_type().get_ptr_type()
207      params.append(ptr_class + 'CToCpp::Unwrap(' + arg_name + ')')
208    elif arg_type == 'ownptr_same':
209      ptr_class = arg.get_type().get_ptr_type()
210      params.append(ptr_class + 'CToCpp::UnwrapOwn(OWN_PASS(' + arg_name + '))')
211    elif arg_type == 'rawptr_same':
212      ptr_class = arg.get_type().get_ptr_type()
213      params.append(ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + ')')
214    elif arg_type == 'refptr_diff':
215      ptr_class = arg.get_type().get_ptr_type()
216      params.append(ptr_class + 'CppToC::Wrap(' + arg_name + ')')
217    elif arg_type == 'ownptr_diff':
218      ptr_class = arg.get_type().get_ptr_type()
219      params.append(ptr_class + 'CppToC::WrapOwn(OWN_PASS(' + arg_name + '))')
220    elif arg_type == 'rawptr_diff':
221      ptr_class = arg.get_type().get_ptr_type()
222      result += comment+\
223                '\n  CefOwnPtr<'+ptr_class+'CppToC> '+arg_name+'Ptr('+ptr_class+'CppToC::WrapRaw('+arg_name+'));'
224      params.append(arg_name + 'Ptr->GetStruct()')
225    elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
226      ptr_class = arg.get_type().get_ptr_type()
227      ptr_struct = arg.get_type().get_result_ptr_type_root()
228      if arg_type == 'refptr_same_byref':
229        assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + ')'
230      else:
231        assign = ptr_class + 'CppToC::Wrap(' + arg_name + ')'
232      result += comment+\
233                '\n  '+ptr_struct+'* '+arg_name+'Struct = NULL;'\
234                '\n  if ('+arg_name+'.get())'\
235                '\n    '+arg_name+'Struct = '+assign+';'\
236                '\n  '+ptr_struct+'* '+arg_name+'Orig = '+arg_name+'Struct;'
237      params.append('&' + arg_name + 'Struct')
238    elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
239      result += comment+\
240                '\n  cef_string_list_t '+arg_name+'List = cef_string_list_alloc();'\
241                '\n  DCHECK('+arg_name+'List);'\
242                '\n  if ('+arg_name+'List)'\
243                '\n    transfer_string_list_contents('+arg_name+', '+arg_name+'List);'
244      params.append(arg_name + 'List')
245    elif arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const':
246      result += comment+\
247                '\n  cef_string_map_t '+arg_name+'Map = cef_string_map_alloc();'\
248                '\n  DCHECK('+arg_name+'Map);'\
249                '\n  if ('+arg_name+'Map)'\
250                '\n    transfer_string_map_contents('+arg_name+', '+arg_name+'Map);'
251      params.append(arg_name + 'Map')
252    elif arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
253      result += comment+\
254                '\n  cef_string_multimap_t '+arg_name+'Multimap = cef_string_multimap_alloc();'\
255                '\n  DCHECK('+arg_name+'Multimap);'\
256                '\n  if ('+arg_name+'Multimap)'\
257                '\n    transfer_string_multimap_contents('+arg_name+', '+arg_name+'Multimap);'
258      params.append(arg_name + 'Multimap')
259    elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
260         arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
261      count_func = arg.get_attrib_count_func()
262      vec_type = arg.get_type().get_result_vector_type_root()
263      if arg_type == 'refptr_vec_same_byref':
264        ptr_class = arg.get_type().get_ptr_type()
265        assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
266      elif arg_type == 'refptr_vec_diff_byref':
267        ptr_class = arg.get_type().get_ptr_type()
268        assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
269      else:
270        assign = arg_name + '[i]'
271      result += comment+\
272                '\n  size_t '+arg_name+'Size = '+arg_name+'.size();'\
273                '\n  size_t '+arg_name+'Count = std::max('+count_func+'(), '+arg_name+'Size);'\
274                '\n  '+vec_type+'* '+arg_name+'List = NULL;'\
275                '\n  if ('+arg_name+'Count > 0) {'\
276                '\n    '+arg_name+'List = new '+vec_type+'['+arg_name+'Count];'\
277                '\n    DCHECK('+arg_name+'List);'\
278                '\n    if ('+arg_name+'List) {'\
279                '\n       memset('+arg_name+'List, 0, sizeof('+vec_type+')*'+arg_name+'Count);'\
280                '\n    }'\
281                '\n    if ('+arg_name+'List && '+arg_name+'Size > 0) {'\
282                '\n      for (size_t i = 0; i < '+arg_name+'Size; ++i) {'\
283                '\n        '+arg_name+'List[i] = '+assign+';'\
284                '\n      }'\
285                '\n    }'\
286                '\n  }'
287      params.append('&' + arg_name + 'Count')
288      params.append(arg_name + 'List')
289    elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
290         arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
291         arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
292      count_func = arg.get_attrib_count_func()
293      vec_type = arg.get_type().get_result_vector_type_root()
294      if arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const':
295        assign = arg_name + '[i]'
296      else:
297        ptr_class = arg.get_type().get_ptr_type()
298        if arg_type == 'refptr_vec_same_byref_const':
299          assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
300        elif arg_type == 'refptr_vec_diff_byref_const':
301          assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
302        elif arg_type == 'rawptr_vec_same_byref_const':
303          assign = ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + '[i])'
304        elif arg_type == 'rawptr_vec_diff_byref_const':
305          assign = ptr_class + 'CppToC::WrapRaw(' + arg_name + '[i]).release()->GetStruct()'
306      result += comment+\
307                '\n  const size_t '+arg_name+'Count = '+arg_name+'.size();'\
308                '\n  '+vec_type+'* '+arg_name+'List = NULL;'\
309                '\n  if ('+arg_name+'Count > 0) {'\
310                '\n    '+arg_name+'List = new '+vec_type+'['+arg_name+'Count];'\
311                '\n    DCHECK('+arg_name+'List);'\
312                '\n    if ('+arg_name+'List) {'\
313                '\n      for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
314                '\n        '+arg_name+'List[i] = '+assign+';'\
315                '\n      }'\
316                '\n    }'\
317                '\n  }'
318      params.append(arg_name + 'Count')
319      params.append(arg_name + 'List')
320    else:
321      raise Exception('Unsupported argument type %s for parameter %s in %s' %
322                      (arg_type, arg_name, name))
323
324  if len(result) != result_len:
325    result += '\n'
326  result_len = len(result)
327
328  if is_cef_shutdown:
329    result += '\n\n#if DCHECK_IS_ON()'\
330              '\n  shutdown_checker::SetIsShutdown();'\
331              '\n#endif\n'
332
333  # execution
334  result += '\n  // Execute\n  '
335
336  if retval_type != 'none':
337    # has a return value
338    if retval_type == 'simple' or retval_type == 'bool':
339      result += retval.get_type().get_result_simple_type_root()
340    elif retval_type == 'string':
341      result += 'cef_string_userfree_t'
342    elif retval_type == 'refptr_same' or retval_type == 'refptr_diff' or \
343         retval_type == 'ownptr_same' or retval_type == 'ownptr_diff':
344      ptr_struct = retval.get_type().get_result_ptr_type_root()
345      result += ptr_struct + '*'
346    else:
347      raise Exception('Unsupported return type %s in %s' % (retval_type, name))
348
349    result += ' _retval = '
350
351  if isinstance(func, obj_function_virtual):
352    result += '_struct->'
353  result += func.get_capi_name() + '('
354
355  if len(params) > 0:
356    if not isinstance(func, obj_function_virtual):
357      result += '\n      '
358    result += ',\n      '.join(params)
359
360  result += ');\n'
361
362  result_len = len(result)
363
364  # parameter restoration
365  for arg in args:
366    arg_type = arg.get_arg_type()
367    arg_name = arg.get_type().get_name()
368
369    comment = '\n  // Restore param:' + arg_name + '; type: ' + arg_type
370
371    if arg_type == 'bool_byref':
372      result += comment+\
373                '\n  '+arg_name+' = '+arg_name+'Int?true:false;'
374    elif arg_type == 'bool_byaddr':
375      result += comment+\
376                '\n  if ('+arg_name+')'\
377                '\n    *'+arg_name+' = '+arg_name+'Int?true:false;'
378    elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
379      ptr_class = arg.get_type().get_ptr_type()
380      ptr_struct = arg.get_type().get_result_ptr_type_root()
381      if arg_type == 'refptr_same_byref':
382        assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'Struct)'
383      else:
384        assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'Struct)'
385      result += comment+\
386                '\n  if ('+arg_name+'Struct) {'\
387                '\n    if ('+arg_name+'Struct != '+arg_name+'Orig) {'\
388                '\n      '+arg_name+' = '+assign+';'\
389                '\n    }'\
390                '\n  } else {'\
391                '\n    '+arg_name+' = nullptr;'\
392                '\n  }'
393    elif arg_type == 'string_vec_byref':
394      result += comment+\
395                '\n  if ('+arg_name+'List) {'\
396                '\n    '+arg_name+'.clear();'\
397                '\n    transfer_string_list_contents('+arg_name+'List, '+arg_name+');'\
398                '\n    cef_string_list_free('+arg_name+'List);'\
399                '\n  }'
400    elif arg_type == 'string_vec_byref_const':
401      result += comment+\
402                '\n  if ('+arg_name+'List)'\
403                '\n    cef_string_list_free('+arg_name+'List);'
404    elif arg_type == 'string_map_single_byref':
405      result += comment+\
406                '\n  if ('+arg_name+'Map) {'\
407                '\n    '+arg_name+'.clear();'\
408                '\n    transfer_string_map_contents('+arg_name+'Map, '+arg_name+');'\
409                '\n    cef_string_map_free('+arg_name+'Map);'\
410                '\n  }'
411    elif arg_type == 'string_map_single_byref_const':
412      result += comment+\
413                '\n  if ('+arg_name+'Map)'\
414                '\n    cef_string_map_free('+arg_name+'Map);'
415    elif arg_type == 'string_map_multi_byref':
416      result += comment+\
417                '\n  if ('+arg_name+'Multimap) {'\
418                '\n    '+arg_name+'.clear();'\
419                '\n    transfer_string_multimap_contents('+arg_name+'Multimap, '+arg_name+');'\
420                '\n    cef_string_multimap_free('+arg_name+'Multimap);'\
421                '\n  }'
422    elif arg_type == 'string_map_multi_byref_const':
423      result += comment+\
424                '\n  if ('+arg_name+'Multimap)'\
425                '\n    cef_string_multimap_free('+arg_name+'Multimap);'
426    elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
427         arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
428      count_func = arg.get_attrib_count_func()
429      vec_type = arg.get_type().get_result_vector_type_root()
430      if arg_type == 'refptr_vec_same_byref':
431        ptr_class = arg.get_type().get_ptr_type()
432        assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'List[i])'
433      elif arg_type == 'refptr_vec_diff_byref':
434        ptr_class = arg.get_type().get_ptr_type()
435        assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'List[i])'
436      elif arg_type == 'bool_vec_byref':
437        assign = arg_name + 'List[i]?true:false'
438      else:
439        assign = arg_name + 'List[i]'
440      result += comment+\
441                '\n  '+arg_name+'.clear();'\
442                '\n  if ('+arg_name+'Count > 0 && '+arg_name+'List) {'\
443                '\n    for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
444                '\n      '+arg_name+'.push_back('+assign+');'\
445                '\n    }'\
446                '\n    delete [] '+arg_name+'List;'\
447                '\n  }'
448    elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
449         arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
450         arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
451      result += comment
452      if arg_type == 'rawptr_vec_diff_byref_const':
453        result += '\n  if ('+arg_name+'Count > 0) {'\
454                  '\n    for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
455                  '\n      delete '+ptr_class+'CppToC::GetWrapper('+arg_name+'List[i]);'\
456                  '\n    }'\
457                  '\n  }'
458      result += '\n  if ('+arg_name+'List)'\
459                '\n    delete [] '+arg_name+'List;'
460
461  if len(result) != result_len:
462    result += '\n'
463  result_len = len(result)
464
465  if len(result) != result_len:
466    result += '\n'
467  result_len = len(result)
468
469  # return translation
470  if retval_type != 'none':
471    # has a return value
472    result += '\n  // Return type: ' + retval_type
473    if retval_type == 'simple':
474      result += '\n  return _retval;'
475    elif retval_type == 'bool':
476      result += '\n  return _retval?true:false;'
477    elif retval_type == 'string':
478      result += '\n  CefString _retvalStr;'\
479                '\n  _retvalStr.AttachToUserFree(_retval);'\
480                '\n  return _retvalStr;'
481    elif retval_type == 'refptr_same' or retval_type == 'ownptr_same':
482      ptr_class = retval.get_type().get_ptr_type()
483      result += '\n  return ' + ptr_class + 'CToCpp::Wrap(_retval);'
484    elif retval_type == 'refptr_diff':
485      ptr_class = retval.get_type().get_ptr_type()
486      result += '\n  return ' + ptr_class + 'CppToC::Unwrap(_retval);'
487    elif retval_type == 'ownptr_diff':
488      ptr_class = retval.get_type().get_ptr_type()
489      result += '\n  return ' + ptr_class + 'CppToC::UnwrapOwn(_retval);'
490    else:
491      raise Exception('Unsupported return type %s in %s' % (retval_type, name))
492
493  if len(result) != result_len:
494    result += '\n'
495
496  result += '}\n\n'
497  return result
498
499
500def make_ctocpp_function_impl(clsname, funcs, existing, base_scoped):
501  impl = ''
502
503  for func in funcs:
504    name = func.get_name()
505    value = get_next_function_impl(existing, name)
506    if not value is None \
507        and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
508      # an implementation exists that was not auto-generated
509      impl += make_ctocpp_function_impl_existing(clsname, name, func, value)
510    else:
511      impl += make_ctocpp_function_impl_new(clsname, name, func, base_scoped)
512
513  return impl
514
515
516def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
517  impl = make_ctocpp_function_impl(cls.get_name(),
518                                   cls.get_virtual_funcs(), existing,
519                                   base_scoped)
520
521  cur_cls = cls
522  while True:
523    parent_name = cur_cls.get_parent_name()
524    if is_base_class(parent_name):
525      break
526    else:
527      parent_cls = header.get_class(parent_name)
528      if parent_cls is None:
529        raise Exception('Class does not exist: ' + parent_name)
530      impl += make_ctocpp_function_impl(cls.get_name(),
531                                        parent_cls.get_virtual_funcs(),
532                                        existing, base_scoped)
533    cur_cls = header.get_class(parent_name)
534
535  return impl
536
537
538def make_ctocpp_unwrap_derived(header, cls, base_scoped):
539  # identify all classes that derive from cls
540  derived_classes = []
541  clsname = cls.get_name()
542  allclasses = header.get_classes()
543  for cur_cls in allclasses:
544    if cur_cls.get_name() == clsname:
545      continue
546    if cur_cls.has_parent(clsname):
547      derived_classes.append(cur_cls.get_name())
548
549  derived_classes = sorted(derived_classes)
550
551  if base_scoped:
552    impl = ['', '']
553    for clsname in derived_classes:
554      impl[0] += '  if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
555                 '    return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
556                 clsname+'CToCpp::UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\
557                 '  }\n'
558      impl[1] += '  if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
559                 '    return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
560                 clsname+'CToCpp::UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(CEF_RAW_PTR_GET(c)))));\n'+\
561                 '  }\n'
562  else:
563    impl = ''
564    for clsname in derived_classes:
565      impl += '  if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
566              '    return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
567              clsname+'CToCpp::Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\
568              '  }\n'
569  return impl
570
571
572def make_ctocpp_class_impl(header, clsname, impl):
573  cls = header.get_class(clsname)
574  if cls is None:
575    raise Exception('Class does not exist: ' + clsname)
576
577  capiname = cls.get_capi_name()
578
579  # retrieve the existing virtual function implementations
580  existing = get_function_impls(impl, clsname + 'CToCpp::')
581
582  base_class_name = header.get_base_class_name(clsname)
583  base_scoped = True if base_class_name == 'CefBaseScoped' else False
584  if base_scoped:
585    template_class = 'CefCToCppScoped'
586  else:
587    template_class = 'CefCToCppRefCounted'
588
589  # generate virtual functions
590  virtualimpl = make_ctocpp_virtual_function_impl(header, cls, existing,
591                                                  base_scoped)
592  if len(virtualimpl) > 0:
593    virtualimpl = '\n// VIRTUAL METHODS - Body may be edited by hand.\n\n' + virtualimpl
594
595  # retrieve the existing static function implementations
596  existing = get_function_impls(impl, clsname + '::')
597
598  # generate static functions
599  staticimpl = make_ctocpp_function_impl(clsname,
600                                         cls.get_static_funcs(), existing,
601                                         base_scoped)
602  if len(staticimpl) > 0:
603    staticimpl = '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
604
605  resultingimpl = staticimpl + virtualimpl
606
607  # any derived classes can be unwrapped
608  unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped)
609
610  const =  '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
611           clsname+'CToCpp::'+clsname+'CToCpp() {\n'+ \
612           '}\n\n'+ \
613           '// DESTRUCTOR - Do not edit by hand.\n\n'+ \
614           clsname+'CToCpp::~'+clsname+'CToCpp() {\n'
615
616  if not cls.has_attrib('no_debugct_check') and not base_scoped:
617    const += '  shutdown_checker::AssertNotShutdown();\n'
618
619  const += '}\n\n'
620
621  # determine what includes are required by identifying what translation
622  # classes are being used
623  includes = format_translation_includes(header, const + resultingimpl +
624                                         (unwrapderived[0]
625                                          if base_scoped else unwrapderived))
626
627  # build the final output
628  result = get_copyright()
629
630  result += includes + '\n' + resultingimpl + '\n'
631
632  parent_sig = template_class + '<' + clsname + 'CToCpp, ' + clsname + ', ' + capiname + '>'
633
634  if base_scoped:
635    const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<'+clsname+'> c) {\n'+ \
636             unwrapderived[0] + \
637             '  NOTREACHED() << "Unexpected class type: " << type;\n'+ \
638             '  return nullptr;\n'+ \
639             '}\n\n' + \
640             'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<'+clsname+'> c) {\n'+ \
641             unwrapderived[1] + \
642             '  NOTREACHED() << "Unexpected class type: " << type;\n'+ \
643             '  return nullptr;\n'+ \
644             '}\n\n'
645  else:
646    const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \
647             unwrapderived + \
648             '  NOTREACHED() << "Unexpected class type: " << type;\n'+ \
649             '  return nullptr;\n'+ \
650             '}\n\n'
651
652  const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
653      clsname) + ';'
654
655  result += const
656
657  return result
658
659
660def make_ctocpp_global_impl(header, impl):
661  # retrieve the existing global function implementations
662  existing = get_function_impls(impl, 'CEF_GLOBAL')
663
664  # generate static functions
665  impl = make_ctocpp_function_impl(None, header.get_funcs(), existing, False)
666  if len(impl) > 0:
667    impl = '\n// GLOBAL METHODS - Body may be edited by hand.\n\n' + impl
668
669  includes = ''
670
671  # include required headers for global functions
672  filenames = []
673  for func in header.get_funcs():
674    filename = func.get_file_name()
675    if not filename in filenames:
676      includes += '#include "include/'+func.get_file_name()+'"\n' \
677                  '#include "include/capi/'+func.get_capi_file_name()+'"\n'
678      filenames.append(filename)
679
680  # determine what includes are required by identifying what translation
681  # classes are being used
682  includes += format_translation_includes(header, impl)
683
684  # build the final output
685  result = get_copyright()
686
687  result += includes + '\n// Define used to facilitate parsing.\n#define CEF_GLOBAL\n\n' + impl
688
689  return result
690
691
692def write_ctocpp_impl(header, clsname, dir):
693  if clsname is None:
694    # global file
695    file = dir
696  else:
697    # class file
698    # give the output file the same directory offset as the input file
699    cls = header.get_class(clsname)
700    dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
701    file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_ctocpp.cc')
702
703  if path_exists(file):
704    oldcontents = read_file(file)
705  else:
706    oldcontents = ''
707
708  if clsname is None:
709    newcontents = make_ctocpp_global_impl(header, oldcontents)
710  else:
711    newcontents = make_ctocpp_class_impl(header, clsname, oldcontents)
712  return (file, newcontents)
713
714
715# test the module
716if __name__ == "__main__":
717  import sys
718
719  # verify that the correct number of command-line arguments are provided
720  if len(sys.argv) < 4:
721    sys.stderr.write('Usage: ' + sys.argv[0] +
722                     ' <infile> <classname> <existing_impl>\n')
723    sys.exit()
724
725  # create the header object
726  header = obj_header()
727  header.add_file(sys.argv[1])
728
729  # read the existing implementation file into memory
730  try:
731    with open(sys.argv[3], 'r') as f:
732      data = f.read()
733  except IOError as e:
734    (errno, strerror) = e.args
735    raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror)
736
737  # dump the result to stdout
738  sys.stdout.write(make_ctocpp_class_impl(header, sys.argv[2], data))
739