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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import struct_generator
def _JSONToCString16(json_string_literal):
"""Converts a JSON string literal to a C++ UTF-16 string literal. This is
done by converting \\u#### to \\x####.
"""
c_string_literal = json_string_literal
escape_index = c_string_literal.find('\\')
while escape_index > 0:
if c_string_literal[escape_index + 1] == 'u':
# We close the C string literal after the 4 hex digits and reopen it right
# after, otherwise the Windows compiler will sometimes try to get more
# than 4 characters in the hex string.
c_string_literal = (c_string_literal[0:escape_index + 1] + 'x' +
c_string_literal[escape_index + 2:escape_index + 6] +
'" u"' + c_string_literal[escape_index + 6:])
escape_index = c_string_literal.find('\\', escape_index + 6)
return c_string_literal
def _GenerateString(content, lines, indent=' '):
"""Generates an UTF-8 string to be included in a static structure initializer.
If content is not specified, uses nullptr.
"""
if content is None:
lines.append(indent + 'nullptr,')
else:
# json.dumps quotes the string and escape characters as required.
lines.append(indent + '%s,' % json.dumps(content))
def _GenerateString16(content, lines, indent=' '):
"""Generates an UTF-16 string to be included in a static structure
initializer. If content is not specified, uses nullptr.
"""
if content is None:
lines.append(indent + 'nullptr,')
else:
# json.dumps quotes the string and escape characters as required.
lines.append(indent + 'u%s,' % _JSONToCString16(json.dumps(content)))
def _GenerateArrayVariableName(element_name, field_name, field_name_count):
# Generates a unique variable name for an array variable.
var = 'array_%s_%s' % (element_name, field_name)
if var not in field_name_count:
field_name_count[var] = 0
return var
new_var = '%s_%d' % (var, field_name_count[var])
field_name_count[var] += 1
return new_var
def _GenerateArray(element_name, field_info, content, lines, indent,
field_name_count):
"""Generates an array to be included in a static structure initializer. If
content is not specified, uses nullptr. The array is assigned to a temporary
variable which is initialized before the structure.
"""
if not content:
lines.append(indent + '{},')
return
# Create a new array variable and use it in the structure initializer.
# This prohibits nested arrays. Add a clash detection and renaming mechanism
# to solve the problem.
var = _GenerateArrayVariableName(element_name, field_info['field'],
field_name_count)
lines.append(indent + '%s,' % var)
# Generate the array content.
array_lines = []
field_info['contents']['field'] = var;
array_lines.append(struct_generator.GenerateField(
field_info['contents']) + '[] = {')
for subcontent in content:
GenerateFieldContent(element_name, field_info['contents'], subcontent,
array_lines, indent, field_name_count)
array_lines.append('};')
# Prepend the generated array so it is initialized before the structure.
lines.reverse()
array_lines.reverse()
lines.extend(array_lines)
lines.reverse()
def _GenerateStruct(element_name, field_info, content, lines, indent,
field_name_count):
"""Generates a struct to be included in a static structure initializer. If
content is not specified, uses {}.
"""
if content is None:
lines.append(indent + '{},')
return
fields = field_info['fields']
lines.append(indent + '{')
for field in fields:
subcontent = content.get(field['field'])
GenerateFieldContent(element_name, field, subcontent, lines, ' ' + indent,
field_name_count)
lines.append(indent + '},')
def GenerateFieldContent(element_name, field_info, content, lines, indent,
field_name_count):
"""Generate the content of a field to be included in the static structure
initializer. If the field's content is not specified, uses the default value
if one exists.
"""
if content is None:
content = field_info.get('default', None)
type = field_info['type']
if type in ('int', 'enum', 'class'):
lines.append('%s%s,' % (indent, content))
elif type == 'string':
_GenerateString(content, lines, indent)
elif type == 'string16':
_GenerateString16(content, lines, indent)
elif type == 'array':
_GenerateArray(element_name, field_info, content, lines, indent,
field_name_count)
elif type == 'struct':
_GenerateStruct(element_name, field_info, content, lines, indent,
field_name_count)
else:
raise RuntimeError('Unknown field type "%s"' % type)
def GenerateElement(type_name, schema, element_name, element, field_name_count):
"""Generate the static structure initializer for one element.
"""
lines = [];
lines.append('const %s %s = {' % (type_name, element_name));
for field_info in schema:
content = element.get(field_info['field'], None)
if (content == None and not field_info.get('optional', False)):
raise RuntimeError('Mandatory field "%s" omitted in element "%s".' %
(field_info['field'], element_name))
GenerateFieldContent(element_name, field_info, content, lines, ' ',
field_name_count)
lines.append('};')
return '\n'.join(lines)
def GenerateElements(type_name, schema, description, field_name_count={}):
"""Generate the static structure initializer for all the elements in the
description['elements'] dictionary, as well as for any variables in
description['int_variables'].
"""
result = [];
for var_name, value in description.get('int_variables', {}).items():
result.append('const int %s = %s;' % (var_name, value))
result.append('')
for element_name, element in description.get('elements', {}).items():
result.append(GenerateElement(type_name, schema, element_name, element,
field_name_count))
result.append('')
return '\n'.join(result)
|