12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import json 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import struct_generator 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def _JSONToCString16(json_string_literal): 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Converts a JSON string literal to a C++ UTF-16 string literal. This is 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) done by converting \\u#### to \\x####. 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) c_string_literal = json_string_literal 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) escape_index = c_string_literal.find('\\') 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while escape_index > 0: 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if c_string_literal[escape_index + 1] == 'u': 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # We close the C string literal after the 4 hex digits and reopen it right 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # after, otherwise the Windows compiler will sometimes try to get more 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # than 4 characters in the hex string. 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) c_string_literal = (c_string_literal[0:escape_index + 1] + 'x' + 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) c_string_literal[escape_index + 2:escape_index + 6] + '" L"' + 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) c_string_literal[escape_index + 6:]) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) escape_index = c_string_literal.find('\\', escape_index + 6) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return c_string_literal 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def _GenerateString(content, lines): 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Generates an UTF-8 string to be included in a static structure initializer. 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) If content is not specified, uses NULL. 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if content is None: 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' NULL,') 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # json.dumps quotes the string and escape characters as required. 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' %s,' % json.dumps(content)) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def _GenerateString16(content, lines): 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Generates an UTF-16 string to be included in a static structure 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) initializer. If content is not specified, uses NULL. 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if content is None: 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' NULL,') 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # json.dumps quotes the string and escape characters as required. 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' L%s,' % _JSONToCString16(json.dumps(content))) 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochdef _GenerateArray(element_name, field_info, content, lines): 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Generates an array to be included in a static structure initializer. If 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content is not specified, uses NULL. The array is assigned to a temporary 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) variable which is initialized before the structure. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if content is None: 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' NULL,') 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' 0,') # Size of the array. 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Create a new array variable and use it in the structure initializer. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # This prohibits nested arrays. Add a clash detection and renaming mechanism 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # to solve the problem. 58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch var = 'array_%s_%s' % (element_name, field_info['field']); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' %s,' % var) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' %s,' % len(content)) # Size of the array. 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Generate the array content. 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) array_lines = [] 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) field_info['contents']['field'] = var; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) array_lines.append(struct_generator.GenerateField( 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) field_info['contents']) + '[] = {') 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for subcontent in content: 67bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch GenerateFieldContent(element_name, field_info['contents'], subcontent, 68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch array_lines) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) array_lines.append('};') 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Prepend the generated array so it is initialized before the structure. 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.reverse() 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) array_lines.reverse() 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.extend(array_lines) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.reverse() 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 76bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochdef GenerateFieldContent(element_name, field_info, content, lines): 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Generate the content of a field to be included in the static structure 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) initializer. If the field's content is not specified, uses the default value 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if one exists. 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if content is None: 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content = field_info.get('default', None) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) type = field_info['type'] 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if type == 'int' or type == 'enum': 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append(' %s,' % content) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) elif type == 'string': 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) _GenerateString(content, lines) 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) elif type == 'string16': 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) _GenerateString16(content, lines) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) elif type == 'array': 91bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch _GenerateArray(element_name, field_info, content, lines) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) raise RuntimeError('Unknown field type "%s"' % type) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def GenerateElement(type_name, schema, element_name, element): 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Generate the static structure initializer for one element. 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines = []; 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append('const %s %s = {' % (type_name, element_name)); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for field_info in schema: 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content = element.get(field_info['field'], None) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (content == None and not field_info.get('optional', False)): 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) raise RuntimeError('Mandatory field "%s" omitted in element "%s".' % 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (field_info['field'], element_name)) 105bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch GenerateFieldContent(element_name, field_info, content, lines) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) lines.append('};') 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return '\n'.join(lines) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def GenerateElements(type_name, schema, description): 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """Generate the static structure initializer for all the elements in the 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) description['elements'] dictionary, as well as for any variables in 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) description['int_variables']. 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result = []; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for var_name, value in description.get('int_variables', {}).items(): 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.append('const int %s = %s;' % (var_name, value)) 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.append('') 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for element_name, element in description.get('elements', {}).items(): 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.append(GenerateElement(type_name, schema, element_name, element)) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.append('') 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return '\n'.join(result) 123