1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
6 import struct_generator
8 def _JSONToCString16(json_string_literal
):
9 """Converts a JSON string literal to a C++ UTF-16 string literal. This is
10 done by converting \\u#### to \\x####.
12 c_string_literal
= json_string_literal
13 escape_index
= c_string_literal
.find('\\')
14 while escape_index
> 0:
15 if c_string_literal
[escape_index
+ 1] == 'u':
16 # We close the C string literal after the 4 hex digits and reopen it right
17 # after, otherwise the Windows compiler will sometimes try to get more
18 # than 4 characters in the hex string.
19 c_string_literal
= (c_string_literal
[0:escape_index
+ 1] + 'x' +
20 c_string_literal
[escape_index
+ 2:escape_index
+ 6] + '" L"' +
21 c_string_literal
[escape_index
+ 6:])
22 escape_index
= c_string_literal
.find('\\', escape_index
+ 6)
23 return c_string_literal
25 def _GenerateString(content
, lines
, indent
=' '):
26 """Generates an UTF-8 string to be included in a static structure initializer.
27 If content is not specified, uses NULL.
30 lines
.append(indent
+ 'NULL,')
32 # json.dumps quotes the string and escape characters as required.
33 lines
.append(indent
+ '%s,' % json
.dumps(content
))
35 def _GenerateString16(content
, lines
, indent
=' '):
36 """Generates an UTF-16 string to be included in a static structure
37 initializer. If content is not specified, uses NULL.
40 lines
.append(indent
+ 'NULL,')
42 # json.dumps quotes the string and escape characters as required.
43 lines
.append(indent
+ 'L%s,' % _JSONToCString16(json
.dumps(content
)))
45 def _GenerateArrayVariableName(element_name
, field_name
, field_name_count
):
46 # Generates a unique variable name for an array variable.
47 var
= 'array_%s_%s' % (element_name
, field_name
)
48 if var
not in field_name_count
:
49 field_name_count
[var
] = 0
51 new_var
= '%s_%d' % (var
, field_name_count
[var
])
52 field_name_count
[var
] += 1
55 def _GenerateArray(element_name
, field_info
, content
, lines
, indent
,
57 """Generates an array to be included in a static structure initializer. If
58 content is not specified, uses NULL. The array is assigned to a temporary
59 variable which is initialized before the structure.
62 lines
.append(indent
+ 'NULL,')
63 lines
.append(indent
+ '0,') # Size of the array.
66 # Create a new array variable and use it in the structure initializer.
67 # This prohibits nested arrays. Add a clash detection and renaming mechanism
68 # to solve the problem.
69 var
= _GenerateArrayVariableName(element_name
, field_info
['field'],
71 lines
.append(indent
+ '%s,' % var
)
72 lines
.append(indent
+ '%s,' % len(content
)) # Size of the array.
73 # Generate the array content.
75 field_info
['contents']['field'] = var
;
76 array_lines
.append(struct_generator
.GenerateField(
77 field_info
['contents']) + '[] = {')
78 for subcontent
in content
:
79 GenerateFieldContent(element_name
, field_info
['contents'], subcontent
,
80 array_lines
, indent
, field_name_count
)
81 array_lines
.append('};')
82 # Prepend the generated array so it is initialized before the structure.
85 lines
.extend(array_lines
)
88 def _GenerateStruct(element_name
, field_info
, content
, lines
, indent
,
90 """Generates a struct to be included in a static structure initializer. If
91 content is not specified, uses {0}.
94 lines
.append(indent
+ '{0},')
97 fields
= field_info
['fields']
98 lines
.append(indent
+ '{')
100 subcontent
= content
.get(field
['field'])
101 GenerateFieldContent(element_name
, field
, subcontent
, lines
, ' ' + indent
,
103 lines
.append(indent
+ '},')
105 def GenerateFieldContent(element_name
, field_info
, content
, lines
, indent
,
107 """Generate the content of a field to be included in the static structure
108 initializer. If the field's content is not specified, uses the default value
112 content
= field_info
.get('default', None)
113 type = field_info
['type']
114 if type == 'int' or type == 'enum':
115 lines
.append('%s%s,' % (indent
, content
))
116 elif type == 'string':
117 _GenerateString(content
, lines
, indent
)
118 elif type == 'string16':
119 _GenerateString16(content
, lines
, indent
)
120 elif type == 'array':
121 _GenerateArray(element_name
, field_info
, content
, lines
, indent
,
123 elif type == 'struct':
124 _GenerateStruct(element_name
, field_info
, content
, lines
, indent
,
127 raise RuntimeError('Unknown field type "%s"' % type)
129 def GenerateElement(type_name
, schema
, element_name
, element
, field_name_count
):
130 """Generate the static structure initializer for one element.
133 lines
.append('const %s %s = {' % (type_name
, element_name
));
134 for field_info
in schema
:
135 content
= element
.get(field_info
['field'], None)
136 if (content
== None and not field_info
.get('optional', False)):
137 raise RuntimeError('Mandatory field "%s" omitted in element "%s".' %
138 (field_info
['field'], element_name
))
139 GenerateFieldContent(element_name
, field_info
, content
, lines
, ' ',
142 return '\n'.join(lines
)
144 def GenerateElements(type_name
, schema
, description
, field_name_count
={}):
145 """Generate the static structure initializer for all the elements in the
146 description['elements'] dictionary, as well as for any variables in
147 description['int_variables'].
150 for var_name
, value
in description
.get('int_variables', {}).items():
151 result
.append('const int %s = %s;' % (var_name
, value
))
154 for element_name
, element
in description
.get('elements', {}).items():
155 result
.append(GenerateElement(type_name
, schema
, element_name
, element
,
158 return '\n'.join(result
)