Home | History | Annotate | Download | only in json_to_struct
      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.
      4 
      5 import json
      6 import struct_generator
      7 
      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####.
     11   """
     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
     24 
     25 def _GenerateString(content, lines):
     26   """Generates an UTF-8 string to be included in a static structure initializer.
     27   If content is not specified, uses NULL.
     28   """
     29   if content is None:
     30     lines.append('  NULL,')
     31   else:
     32     # json.dumps quotes the string and escape characters as required.
     33     lines.append('  %s,' % json.dumps(content))
     34 
     35 def _GenerateString16(content, lines):
     36   """Generates an UTF-16 string to be included in a static structure
     37   initializer. If content is not specified, uses NULL.
     38   """
     39   if content is None:
     40     lines.append('  NULL,')
     41   else:
     42     # json.dumps quotes the string and escape characters as required.
     43     lines.append('  L%s,' % _JSONToCString16(json.dumps(content)))
     44 
     45 def _GenerateArray(element_name, field_info, content, lines):
     46   """Generates an array to be included in a static structure initializer. If
     47   content is not specified, uses NULL. The array is assigned to a temporary
     48   variable which is initialized before the structure.
     49   """
     50   if content is None:
     51     lines.append('  NULL,')
     52     lines.append('  0,')  # Size of the array.
     53     return
     54 
     55   # Create a new array variable and use it in the structure initializer.
     56   # This prohibits nested arrays. Add a clash detection and renaming mechanism
     57   # to solve the problem.
     58   var = 'array_%s_%s' % (element_name, field_info['field']);
     59   lines.append('  %s,' % var)
     60   lines.append('  %s,' % len(content))  # Size of the array.
     61   # Generate the array content.
     62   array_lines = []
     63   field_info['contents']['field'] = var;
     64   array_lines.append(struct_generator.GenerateField(
     65                      field_info['contents']) + '[] = {')
     66   for subcontent in content:
     67     GenerateFieldContent(element_name, field_info['contents'], subcontent,
     68                          array_lines)
     69   array_lines.append('};')
     70   # Prepend the generated array so it is initialized before the structure.
     71   lines.reverse()
     72   array_lines.reverse()
     73   lines.extend(array_lines)
     74   lines.reverse()
     75 
     76 def GenerateFieldContent(element_name, field_info, content, lines):
     77   """Generate the content of a field to be included in the static structure
     78   initializer. If the field's content is not specified, uses the default value
     79   if one exists.
     80   """
     81   if content is None:
     82     content = field_info.get('default', None)
     83   type = field_info['type']
     84   if type == 'int' or type == 'enum':
     85     lines.append('  %s,' % content)
     86   elif type == 'string':
     87     _GenerateString(content, lines)
     88   elif type == 'string16':
     89     _GenerateString16(content, lines)
     90   elif type == 'array':
     91     _GenerateArray(element_name, field_info, content, lines)
     92   else:
     93     raise RuntimeError('Unknown field type "%s"' % type)
     94 
     95 def GenerateElement(type_name, schema, element_name, element):
     96   """Generate the static structure initializer for one element.
     97   """
     98   lines = [];
     99   lines.append('const %s %s = {' % (type_name, element_name));
    100   for field_info in schema:
    101     content = element.get(field_info['field'], None)
    102     if (content == None and not field_info.get('optional', False)):
    103       raise RuntimeError('Mandatory field "%s" omitted in element "%s".' %
    104                          (field_info['field'], element_name))
    105     GenerateFieldContent(element_name, field_info, content, lines)
    106   lines.append('};')
    107   return '\n'.join(lines)
    108 
    109 def GenerateElements(type_name, schema, description):
    110   """Generate the static structure initializer for all the elements in the
    111   description['elements'] dictionary, as well as for any variables in
    112   description['int_variables'].
    113   """
    114   result = [];
    115   for var_name, value in description.get('int_variables', {}).items():
    116     result.append('const int %s = %s;' % (var_name, value))
    117   result.append('')
    118 
    119   for element_name, element in description.get('elements', {}).items():
    120     result.append(GenerateElement(type_name, schema, element_name, element))
    121     result.append('')
    122   return '\n'.join(result)
    123