15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''python %prog [options] platform chromium_os_flag template
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)platform specifies which platform source is being generated for
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  and can be one of (win, mac, linux)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)chromium_os_flag should be 1 if this is a Chromium OS build
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template is the path to a .json policy template file.'''
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from __future__ import with_statement
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfrom functools import partial
15ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochimport json
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from optparse import OptionParser
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import textwrap
20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochimport types
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome'
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium'
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class PolicyDetails:
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  """Parses a policy template and caches all its details."""
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # Maps policy types to a tuple with 3 other types:
313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  # - the equivalent base::Value::Type or 'TYPE_EXTERNAL' if the policy
323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  #   references external data
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # - the equivalent Protobuf field type
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # - the name of one of the protobufs for shared policy types
35d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  # TODO(joaodasilva): refactor the 'dict' type into a more generic 'json' type
36d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  # that can also be used to represent lists of other JSON objects.
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TYPE_MAP = {
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'dict':             ('TYPE_DICTIONARY',   'string',       'String'),
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'external':         ('TYPE_EXTERNAL',     'string',       'String'),
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'int':              ('TYPE_INTEGER',      'int64',        'Integer'),
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'int-enum':         ('TYPE_INTEGER',      'int64',        'Integer'),
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'list':             ('TYPE_LIST',         'StringList',   'StringList'),
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'main':             ('TYPE_BOOLEAN',      'bool',         'Boolean'),
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'string':           ('TYPE_STRING',       'string',       'String'),
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'string-enum':      ('TYPE_STRING',       'string',       'String'),
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'string-enum-list': ('TYPE_LIST',         'StringList',   'StringList'),
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
492385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  class EnumItem:
502385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    def __init__(self, item):
512385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      self.caption = PolicyDetails._RemovePlaceholders(item['caption'])
522385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      self.value = item['value']
532385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def __init__(self, policy, os, is_chromium_os):
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.id = policy['id']
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.name = policy['name']
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    features = policy.get('features', {})
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.can_be_recommended = features.get('can_be_recommended', False)
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.can_be_mandatory = features.get('can_be_mandatory', True)
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.is_deprecated = policy.get('deprecated', False)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.is_device_only = policy.get('device_only', False)
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.schema = policy.get('schema', {})
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.has_enterprise_default = 'default_for_enterprise_users' in policy
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if self.has_enterprise_default:
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self.enterprise_default = policy['default_for_enterprise_users']
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    expected_platform = 'chrome_os' if is_chromium_os else os.lower()
68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    self.platforms = []
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for platform, version in [ p.split(':') for p in policy['supported_on'] ]:
70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      if not version.endswith('-'):
71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        continue
72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      if platform.startswith('chrome.'):
74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        platform_sub = platform[7:]
75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if platform_sub == '*':
76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          self.platforms.extend(['win', 'mac', 'linux'])
77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        else:
78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          self.platforms.append(platform_sub)
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      else:
80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        self.platforms.append(platform)
81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    self.platforms.sort()
83ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    self.is_supported = expected_platform in self.platforms
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if not PolicyDetails.TYPE_MAP.has_key(policy['type']):
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      raise NotImplementedError('Unknown policy type for %s: %s' %
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                (policy['name'], policy['type']))
883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    self.policy_type, self.protobuf_type, self.policy_protobuf_type = \
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        PolicyDetails.TYPE_MAP[policy['type']]
90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    self.schema = policy['schema']
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.desc = '\n'.join(
932385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        map(str.strip,
942385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch            PolicyDetails._RemovePlaceholders(policy['desc']).splitlines()))
952385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    self.caption = PolicyDetails._RemovePlaceholders(policy['caption'])
963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    self.max_size = policy.get('max_size', 0)
972385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
982385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    items = policy.get('items')
992385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if items is None:
1002385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      self.items = None
1012385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    else:
1022385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      self.items = [ PolicyDetails.EnumItem(entry) for entry in items ]
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PH_PATTERN = re.compile('<ph[^>]*>([^<]*|[^<]*<ex>([^<]*)</ex>[^<]*)</ph>')
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # Simplistic grit placeholder stripper.
1072385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  @staticmethod
1082385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  def _RemovePlaceholders(text):
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result = ''
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    pos = 0
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for m in PolicyDetails.PH_PATTERN.finditer(text):
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result += text[pos:m.start(0)]
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result += m.group(2) or m.group(1)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pos = m.end(0)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result += text[pos:]
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return result
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main():
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = OptionParser(usage=__doc__)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('--pch', '--policy-constants-header', dest='header_path',
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='generate header file of policy constants',
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='FILE')
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('--pcc', '--policy-constants-source', dest='source_path',
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='generate source file of policy constants',
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='FILE')
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option('--cpp', '--cloud-policy-protobuf',
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    dest='cloud_policy_proto_path',
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='generate cloud policy protobuf file',
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='FILE')
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option('--csp', '--chrome-settings-protobuf',
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    dest='chrome_settings_proto_path',
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    help='generate chrome settings protobuf file',
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    metavar='FILE')
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option('--cpd', '--cloud-policy-decoder',
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    dest='cloud_policy_decoder_path',
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    help='generate C++ code decoding the cloud policy protobuf',
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='FILE')
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (opts, args) = parser.parse_args()
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(args) != 3:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print 'exactly platform, chromium_os flag and input file must be specified.'
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.print_help()
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 2
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  os = args[0]
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  is_chromium_os = args[1] == '1'
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  template_file_name = args[2]
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  template_file_contents = _LoadJSONFile(template_file_name)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  policy_details = [ PolicyDetails(policy, os, is_chromium_os)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     for policy in _Flatten(template_file_contents) ]
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def GenerateFile(path, writer, sorted=False):
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if path:
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      with open(path, 'w') as f:
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        _OutputGeneratedWarningHeader(f, template_file_name)
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        writer(sorted and sorted_policy_details or policy_details, os, f)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GenerateFile(opts.header_path, _WritePolicyConstantHeader, sorted=True)
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GenerateFile(opts.source_path, _WritePolicyConstantSource, sorted=True)
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GenerateFile(opts.cloud_policy_proto_path, _WriteCloudPolicyProtobuf)
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GenerateFile(opts.chrome_settings_proto_path, _WriteChromeSettingsProtobuf)
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GenerateFile(opts.cloud_policy_decoder_path, _WriteCloudPolicyDecoder)
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#------------------ shared helpers ---------------------------------#
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _OutputGeneratedWarningHeader(f, template_file_path):
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('//\n'
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '// DO NOT MODIFY THIS FILE DIRECTLY!\n'
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '// IT IS GENERATED BY generate_policy_source.py\n'
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '// FROM ' + template_file_path + '\n'
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '//\n\n')
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMMENT_WRAPPER = textwrap.TextWrapper()
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMMENT_WRAPPER.width = 80
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMMENT_WRAPPER.initial_indent = '// '
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMMENT_WRAPPER.subsequent_indent = '// '
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMMENT_WRAPPER.replace_whitespace = False
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Writes a comment, each line prefixed by // and wrapped to 80 spaces.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _OutputComment(f, comment):
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in comment.splitlines():
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(line) == 0:
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write('//')
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write(COMMENT_WRAPPER.fill(line))
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    f.write('\n')
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Returns an iterator over all the policies in |template_file_contents|.
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def _Flatten(template_file_contents):
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for policy in template_file_contents['policy_definitions']:
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if policy['type'] == 'group':
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for sub_policy in policy['policies']:
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        yield sub_policy
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      yield policy
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _LoadJSONFile(json_file):
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  with open(json_file, 'r') as f:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text = f.read()
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return eval(text)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#------------------ policy constants header ------------------------#
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WritePolicyConstantHeader(policies, os, f):
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('#ifndef CHROME_COMMON_POLICY_CONSTANTS_H_\n'
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '#define CHROME_COMMON_POLICY_CONSTANTS_H_\n'
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '\n'
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '#include <string>\n'
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '\n'
2223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          '#include "base/basictypes.h"\n'
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '#include "base/values.h"\n'
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '#include "components/policy/core/common/policy_details.h"\n'
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          '#include "components/policy/core/common/policy_map.h"\n'
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '\n'
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'namespace policy {\n'
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '\n'
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'namespace internal {\n'
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'struct SchemaData;\n'
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '}\n\n')
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if os == 'win':
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    f.write('// The windows registry path where Chrome policy '
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            'configuration resides.\n'
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            'extern const wchar_t kRegistryChromePolicyKey[];\n')
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  f.write('#if defined (OS_CHROMEOS)\n'
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          '// Sets default values for enterprise users.\n'
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          'void SetEnterpriseUsersDefaults(PolicyMap* policy_map);\n'
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          '#endif\n'
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          '\n'
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          '// Returns the PolicyDetails for |policy| if |policy| is a known\n'
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '// Chrome policy, otherwise returns NULL.\n'
245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'const PolicyDetails* GetChromePolicyDetails('
246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)              'const std::string& policy);\n'
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '\n'
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '// Returns the schema data of the Chrome policy schema.\n'
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'const internal::SchemaData* GetChromeSchemaData();\n'
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '\n')
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('// Key names for the policy settings.\n'
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          'namespace key {\n\n')
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for policy in policies:
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # TODO(joaodasilva): Include only supported policies in
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # configuration_policy_handler.cc and configuration_policy_handler_list.cc
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # so that these names can be conditional on 'policy.is_supported'.
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # http://crbug.com/223616
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    f.write('extern const char k' + policy.name + '[];\n')
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('\n}  // namespace key\n\n'
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '}  // namespace policy\n\n'
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '#endif  // CHROME_COMMON_POLICY_CONSTANTS_H_\n')
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#------------------ policy constants source ------------------------#
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# A mapping of the simple schema types to base::Value::Types.
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SIMPLE_SCHEMA_NAME_MAP = {
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  'boolean': 'TYPE_BOOLEAN',
269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  'integer': 'TYPE_INTEGER',
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  'null'   : 'TYPE_NULL',
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  'number' : 'TYPE_DOUBLE',
272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  'string' : 'TYPE_STRING',
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class SchemaNodesGenerator:
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """Builds the internal structs to represent a JSON schema."""
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __init__(self, shared_strings):
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Creates a new generator.
280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    |shared_strings| is a map of strings to a C expression that evaluates to
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    that string at runtime. This mapping can be used to reuse existing string
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    constants."""
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.shared_strings = shared_strings
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.schema_nodes = []
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.property_nodes = []
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.properties_nodes = []
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.restriction_nodes = []
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.int_enums = []
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.string_enums = []
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.simple_types = {
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      'boolean': None,
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      'integer': None,
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      'null': None,
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      'number': None,
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      'string': None,
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.stringlist_type = None
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.ranges = {}
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.id_map = {}
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def GetString(self, s):
303c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if s in self.shared_strings:
304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return self.shared_strings[s]
305c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # Generate JSON escaped string, which is slightly different from desired
306c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # C/C++ escaped string. Known differences includes unicode escaping format.
307c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return json.dumps(s)
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def AppendSchema(self, type, extra, comment=''):
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    index = len(self.schema_nodes)
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.schema_nodes.append((type, extra, comment))
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return index
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def AppendRestriction(self, first, second):
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    r = (str(first), str(second))
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not r in self.ranges:
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.ranges[r] = len(self.restriction_nodes)
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.restriction_nodes.append(r)
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.ranges[r]
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def GetSimpleType(self, name):
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.simple_types[name] == None:
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self.simple_types[name] = self.AppendSchema(
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SIMPLE_SCHEMA_NAME_MAP[name],
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          -1,
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'simple type: ' + name)
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self.simple_types[name]
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def GetStringList(self):
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.stringlist_type == None:
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self.stringlist_type = self.AppendSchema(
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'TYPE_LIST',
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          self.GetSimpleType('string'),
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'simple type: stringlist')
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self.stringlist_type
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def SchemaHaveRestriction(self, schema):
338c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return any(keyword in schema for keyword in
339c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        ['minimum', 'maximum', 'enum', 'pattern'])
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def IsConsecutiveInterval(self, seq):
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sortedSeq = sorted(seq)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return all(sortedSeq[i] + 1 == sortedSeq[i + 1]
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               for i in xrange(len(sortedSeq) - 1))
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEnumIntegerType(self, schema, name):
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    assert all(type(x) == int for x in schema['enum'])
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    possible_values = schema['enum']
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.IsConsecutiveInterval(possible_values):
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      index = self.AppendRestriction(max(possible_values), min(possible_values))
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return self.AppendSchema('TYPE_INTEGER', index,
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'integer with enumeration restriction (use range instead): %s' % name)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    offset_begin = len(self.int_enums)
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.int_enums += possible_values
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    offset_end = len(self.int_enums)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.AppendSchema('TYPE_INTEGER',
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.AppendRestriction(offset_begin, offset_end),
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'integer with enumeration restriction: %s' % name)
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEnumStringType(self, schema, name):
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    assert all(type(x) == str for x in schema['enum'])
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    offset_begin = len(self.string_enums)
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.string_enums += schema['enum']
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    offset_end = len(self.string_enums)
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.AppendSchema('TYPE_STRING',
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.AppendRestriction(offset_begin, offset_end),
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'string with enumeration restriction: %s' % name)
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEnumType(self, schema, name):
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if len(schema['enum']) == 0:
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raise RuntimeError('Empty enumeration in %s' % name)
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    elif schema['type'] == 'integer':
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return self.GetEnumIntegerType(schema, name)
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    elif schema['type'] == 'string':
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return self.GetEnumStringType(schema, name)
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raise RuntimeError('Unknown enumeration type in %s' % name)
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  def GetPatternType(self, schema, name):
380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if schema['type'] != 'string':
381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      raise RuntimeError('Unknown pattern type in %s' % name)
382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    pattern = schema['pattern']
383c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # Try to compile the pattern to validate it, note that the syntax used
384c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # here might be slightly different from re2.
385c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # TODO(binjin): Add a python wrapper of re2 and use it here.
386c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    re.compile(pattern)
387c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    index = len(self.string_enums);
388c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.string_enums.append(pattern);
389c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return self.AppendSchema('TYPE_STRING',
390c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        self.AppendRestriction(index, index),
391c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        'string with pattern restriction: %s' % name);
392c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRangedType(self, schema, name):
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if schema['type'] != 'integer':
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raise RuntimeError('Unknown ranged type in %s' % name)
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    min_value_set, max_value_set = False, False
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if 'minimum' in schema:
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      min_value = int(schema['minimum'])
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      min_value_set = True
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if 'maximum' in schema:
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_value = int(schema['minimum'])
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_value_set = True
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if min_value_set and max_value_set and min_value > max_value:
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raise RuntimeError('Invalid ranged type in %s' % name)
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    index = self.AppendRestriction(
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        str(max_value) if max_value_set else 'INT_MAX',
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        str(min_value) if min_value_set else 'INT_MIN')
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.AppendSchema('TYPE_INTEGER',
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        index,
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'integer with ranged restriction: %s' % name)
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Generate(self, schema, name):
413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Generates the structs for the given schema.
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    |schema|: a valid JSON schema in a dictionary.
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    |name|: the name of the current node, for the generated comments."""
417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if schema.has_key('$ref'):
418c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if schema.has_key('id'):
419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        raise RuntimeError("Schemas with a $ref can't have an id")
420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if not isinstance(schema['$ref'], types.StringTypes):
421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        raise RuntimeError("$ref attribute must be a string")
422c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return schema['$ref']
423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if schema['type'] in self.simple_types:
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if not self.SchemaHaveRestriction(schema):
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Simple types use shared nodes.
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return self.GetSimpleType(schema['type'])
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      elif 'enum' in schema:
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return self.GetEnumType(schema, name)
429c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      elif 'pattern' in schema:
430c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        return self.GetPatternType(schema, name)
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else:
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return self.GetRangedType(schema, name)
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if schema['type'] == 'array':
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # Special case for lists of strings, which is a common policy type.
43646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      # The 'type' may be missing if the schema has a '$ref' attribute.
43746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if schema['items'].get('type', '') == 'string':
438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return self.GetStringList()
439c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return self.AppendSchema('TYPE_LIST',
440c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          self.GenerateAndCollectID(schema['items'], 'items of ' + name))
441f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    elif schema['type'] == 'object':
442f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # Reserve an index first, so that dictionaries come before their
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # properties. This makes sure that the root node is the first in the
444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # SchemaNodes array.
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      index = self.AppendSchema('TYPE_DICTIONARY', -1)
446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if 'additionalProperties' in schema:
448c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        additionalProperties = self.GenerateAndCollectID(
449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            schema['additionalProperties'],
450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            'additionalProperties of ' + name)
451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      else:
452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        additionalProperties = -1
453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # Properties must be sorted by name, for the binary search lookup.
455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # Note that |properties| must be evaluated immediately, so that all the
456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # recursive calls to Generate() append the necessary child nodes; if
457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # |properties| were a generator then this wouldn't work.
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      sorted_properties = sorted(schema.get('properties', {}).items())
459c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      properties = [
460c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          (self.GetString(key), self.GenerateAndCollectID(subschema, key))
461c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          for key, subschema in sorted_properties ]
462c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
463c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      pattern_properties = []
464c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      for pattern, subschema in schema.get('patternProperties', {}).items():
465c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        pattern_properties.append((self.GetString(pattern),
466c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            self.GenerateAndCollectID(subschema, pattern)));
467c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      begin = len(self.property_nodes)
469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self.property_nodes += properties
470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      end = len(self.property_nodes)
471c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      self.property_nodes += pattern_properties
472c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      pattern_end = len(self.property_nodes)
473c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if index == 0:
475f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        self.root_properties_begin = begin
476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        self.root_properties_end = end
477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extra = len(self.properties_nodes)
479c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      self.properties_nodes.append((begin, end, pattern_end,
480c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          additionalProperties, name))
481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # Set the right data at |index| now.
483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name)
484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return index
485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else:
486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      assert False
487f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  def GenerateAndCollectID(self, schema, name):
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    """A wrapper of Generate(), will take the return value, check and add 'id'
490c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    attribute to self.id_map. The wrapper needs to be used for every call to
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    Generate().
492c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    """
493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    index = self.Generate(schema, name)
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if not schema.has_key('id'):
495c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return index
496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    id_str = schema['id']
497c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if self.id_map.has_key(id_str):
498c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      raise RuntimeError('Duplicated id: ' + id_str)
499c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.id_map[id_str] = index
500c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return index
501c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Write(self, f):
503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Writes the generated structs to the given file.
504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    |f| an open file to write to."""
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    f.write('const internal::SchemaNode kSchemas[] = {\n'
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            '//  Type                          Extra\n')
508f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for type, extra, comment in self.schema_nodes:
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      type += ','
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      f.write('  { base::Value::%-18s %3d },  // %s\n' % (type, extra, comment))
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    f.write('};\n\n')
512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.property_nodes:
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('const internal::PropertyNode kPropertyNodes[] = {\n'
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              '//  Property                                          #Schema\n')
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for key, schema in self.property_nodes:
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        key += ','
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        f.write('  { %-50s %6d },\n' % (key, schema))
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('};\n\n')
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.properties_nodes:
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('const internal::PropertiesNode kProperties[] = {\n'
523c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch              '//  Begin    End  PatternEnd Additional Properties\n')
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for node in self.properties_nodes:
525c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        f.write('  { %5d, %5d, %10d, %5d },  // %s\n' % node)
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('};\n\n')
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.restriction_nodes:
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('const internal::RestrictionNode kRestrictionNodes[] = {\n')
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('//   FIRST, SECOND\n')
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for first, second in self.restriction_nodes:
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        f.write('  {{ %-8s %4s}},\n' % (first + ',', second))
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('};\n\n')
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.int_enums:
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('const int kIntegerEnumerations[] = {\n')
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for possible_values in self.int_enums:
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        f.write('  %d,\n' % possible_values)
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('};\n\n')
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.string_enums:
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('const char* kStringEnumerations[] = {\n')
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for possible_values in self.string_enums:
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        f.write('  %s,\n' % self.GetString(possible_values))
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      f.write('};\n\n')
546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    f.write('const internal::SchemaData kChromeSchemaData = {\n'
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            '  kSchemas,\n')
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write('  kPropertyNodes,\n' if self.property_nodes else '  NULL,\n')
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write('  kProperties,\n' if self.properties_nodes else '  NULL,\n')
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write('  kRestrictionNodes,\n' if self.restriction_nodes else '  NULL,\n')
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write('  kIntegerEnumerations,\n' if self.int_enums else '  NULL,\n')
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write('  kStringEnumerations,\n' if self.string_enums else '  NULL,\n')
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    f.write('};\n\n')
5553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
556c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  def GetByID(self, id_str):
557c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if not isinstance(id_str, types.StringTypes):
558c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return id_str
559c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if not self.id_map.has_key(id_str):
560c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      raise RuntimeError('Invalid $ref: ' + id_str)
561c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return self.id_map[id_str]
562c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
563c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  def ResolveID(self, index, params):
564c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return params[:index] + (self.GetByID(params[index]),) + params[index+1:]
565c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
566c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  def ResolveReferences(self):
567c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    """Resolve reference mapping, required to be called after Generate()
568c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
569c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    After calling Generate(), the type of indices used in schema structures
570c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    might be either int or string. An int type suggests that it's a resolved
571c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    index, but for string type it's unresolved. Resolving a reference is as
572c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    simple as looking up for corresponding ID in self.id_map, and replace the
573c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    old index with the mapped index.
574c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    """
575c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.schema_nodes = map(partial(self.ResolveID, 1), self.schema_nodes)
576c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.property_nodes = map(partial(self.ResolveID, 1), self.property_nodes)
577c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.properties_nodes = map(partial(self.ResolveID, 3),
578c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        self.properties_nodes)
5793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WritePolicyConstantSource(policies, os, f):
581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  f.write('#include "policy/policy_constants.h"\n'
582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '\n'
583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '#include <algorithm>\n'
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          '#include <climits>\n'
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '\n'
586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '#include "base/logging.h"\n'
587f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '#include "components/policy/core/common/schema_internal.h"\n'
588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '\n'
589f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'namespace policy {\n'
590f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '\n'
591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          'namespace {\n'
592f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '\n')
593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Generate the Chrome schema.
595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  chrome_schema = {
596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    'type': 'object',
597f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    'properties': {},
598f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
599f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  shared_strings = {}
600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for policy in policies:
601f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    shared_strings[policy.name] = "key::k%s" % policy.name
602f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if policy.is_supported:
603f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      chrome_schema['properties'][policy.name] = policy.schema
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
605f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Note: this list must be kept in sync with the known property list of the
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # Chrome schema, so that binary seaching in the PropertyNode array gets the
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # right index on this array as well. See the implementation of
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  # GetChromePolicyDetails() below.
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  f.write('const PolicyDetails kChromePolicyDetails[] = {\n'
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '//  is_deprecated  is_device_policy  id    max_external_data_size\n')
611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for policy in policies:
612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if policy.is_supported:
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      f.write('  { %-14s %-16s %3s, %24s },\n' % (
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  'true,' if policy.is_deprecated else 'false,',
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  'true,' if policy.is_device_only else 'false,',
616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  policy.id,
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  policy.max_size))
618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('};\n\n')
619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema_generator = SchemaNodesGenerator(shared_strings)
621c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  schema_generator.GenerateAndCollectID(chrome_schema, 'root node')
622c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  schema_generator.ResolveReferences()
623f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema_generator.Write(f)
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  f.write('bool CompareKeys(const internal::PropertyNode& node,\n'
626f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '                 const std::string& key) {\n'
627f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  return node.key < key;\n'
628f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '}\n\n')
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('}  // namespace\n\n')
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if os == 'win':
633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    f.write('#if defined(GOOGLE_CHROME_BUILD)\n'
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            'const wchar_t kRegistryChromePolicyKey[] = '
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            'L"' + CHROME_POLICY_KEY + '";\n'
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            '#else\n'
637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            'const wchar_t kRegistryChromePolicyKey[] = '
638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            'L"' + CHROMIUM_POLICY_KEY + '";\n'
639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            '#endif\n\n')
640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  f.write('const internal::SchemaData* GetChromeSchemaData() {\n'
642f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  return &kChromeSchemaData;\n'
643868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          '}\n\n')
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  f.write('#if defined (OS_CHROMEOS)\n'
6461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          'void SetEnterpriseUsersDefaults(PolicyMap* policy_map) {\n')
6471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
6481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for policy in policies:
6491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if policy.has_enterprise_default:
6501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if policy.policy_type == 'TYPE_BOOLEAN':
6511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        creation_expression = 'new base::FundamentalValue(%s)' %\
6521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              ('true' if policy.enterprise_default else 'false')
6531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      elif policy.policy_type == 'TYPE_INTEGER':
6541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        creation_expression = 'new base::FundamentalValue(%s)' %\
6551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              policy.enterprise_default
6561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      elif policy.policy_type == 'TYPE_STRING':
6571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        creation_expression = 'new base::StringValue("%s")' %\
6581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              policy.enterprise_default
6591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      else:
6601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        raise RuntimeError('Type %s of policy %s is not supported at '
6611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           'enterprise defaults' % (policy.policy_type,
6621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                    policy.name))
6631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      f.write('  if (!policy_map->Get(key::k%s)) {\n'
6641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              '    policy_map->Set(key::k%s,\n'
6651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              '                    POLICY_LEVEL_MANDATORY,\n'
6661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              '                    POLICY_SCOPE_USER,\n'
6671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              '                    %s,\n'
6681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              '                    NULL);\n'
6691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              '  }\n' % (policy.name, policy.name, creation_expression))
6701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
6711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  f.write('}\n'
6721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          '#endif\n\n')
6731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
674f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  f.write('const PolicyDetails* GetChromePolicyDetails('
675f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)              'const std::string& policy) {\n'
676f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // First index in kPropertyNodes of the Chrome policies.\n'
677f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  static const int begin_index = %s;\n'
678f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // One-past-the-end of the Chrome policies in kPropertyNodes.\n'
679f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  static const int end_index = %s;\n' %
680f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          (schema_generator.root_properties_begin,
681f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           schema_generator.root_properties_end))
682f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  f.write('  const internal::PropertyNode* begin =\n'
683f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '      kPropertyNodes + begin_index;\n'
684f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  const internal::PropertyNode* end = kPropertyNodes + end_index;\n'
685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  const internal::PropertyNode* it =\n'
686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '      std::lower_bound(begin, end, policy, CompareKeys);\n'
687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  if (it == end || it->key != policy)\n'
688f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '    return NULL;\n'
689f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // This relies on kPropertyNodes from begin_index to end_index\n'
690f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // having exactly the same policies (and in the same order) as\n'
691f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // kChromePolicyDetails, so that binary searching on the first\n'
692f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // gets the same results as a binary search on the second would.\n'
693f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // However, kPropertyNodes has the policy names and\n'
694f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // kChromePolicyDetails doesn\'t, so we obtain the index into\n'
695f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // the second array by searching the first to avoid duplicating\n'
696f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // the policy name pointers.\n'
697f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // Offsetting |it| from |begin| here obtains the index we\'re\n'
698f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  // looking for.\n'
699f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  size_t index = it - begin;\n'
700f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  CHECK_LT(index, arraysize(kChromePolicyDetails));\n'
701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          '  return kChromePolicyDetails + index;\n'
702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '}\n\n')
703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
704c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('namespace key {\n\n')
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for policy in policies:
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # TODO(joaodasilva): Include only supported policies in
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # configuration_policy_handler.cc and configuration_policy_handler_list.cc
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # so that these names can be conditional on 'policy.is_supported'.
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # http://crbug.com/223616
710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    f.write('const char k{name}[] = "{name}";\n'.format(name=policy.name))
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('\n}  // namespace key\n\n'
712c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '}  // namespace policy\n')
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#------------------ policy protobufs --------------------------------#
716c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CHROME_SETTINGS_PROTO_HEAD = '''
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syntax = "proto2";
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)option optimize_for = LITE_RUNTIME;
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)package enterprise_management;
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// For StringList and PolicyOptions.
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import "cloud_policy.proto";
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'''
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
729c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CLOUD_POLICY_PROTO_HEAD = '''
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syntax = "proto2";
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)option optimize_for = LITE_RUNTIME;
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package enterprise_management;
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)message StringList {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  repeated string entries = 1;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)message PolicyOptions {
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum PolicyMode {
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The given settings are applied regardless of user choice.
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MANDATORY = 0;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user may choose to override the given settings.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RECOMMENDED = 1;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No policy value is present and the policy should be ignored.
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UNSET = 2;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  optional PolicyMode mode = 1 [default = MANDATORY];
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)message BooleanPolicyProto {
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional PolicyOptions policy_options = 1;
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional bool value = 2;
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)message IntegerPolicyProto {
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional PolicyOptions policy_options = 1;
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional int64 value = 2;
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)message StringPolicyProto {
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional PolicyOptions policy_options = 1;
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional string value = 2;
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)message StringListPolicyProto {
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional PolicyOptions policy_options = 1;
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  optional StringList value = 2;
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
776c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Field IDs [1..RESERVED_IDS] will not be used in the wrapping protobuf.
777c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)RESERVED_IDS = 2
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
780c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WritePolicyProto(f, policy, fields):
781c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  _OutputComment(f, policy.caption + '\n\n' + policy.desc)
782a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if policy.items is not None:
783a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    _OutputComment(f, '\nValid values:')
784a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    for item in policy.items:
7852385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      _OutputComment(f, '  %s: %s' % (str(item.value), item.caption))
786ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if policy.policy_type == 'TYPE_DICTIONARY':
787ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    _OutputComment(f, '\nValue schema:\n%s' %
788ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                   json.dumps(policy.schema, sort_keys=True, indent=4,
789ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                              separators=(',', ': ')))
790ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  _OutputComment(f, '\nSupported on: %s' % ', '.join(policy.platforms))
7911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if policy.can_be_recommended and not policy.can_be_mandatory:
7921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    _OutputComment(f, '\nNote: this policy must have a RECOMMENDED ' +\
7931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      'PolicyMode set in PolicyOptions.')
794c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('message %sProto {\n' % policy.name)
795c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('  optional PolicyOptions policy_options = 1;\n')
796c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('  optional %s %s = 2;\n' % (policy.protobuf_type, policy.name))
797c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('}\n\n')
798c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fields += [ '  optional %sProto %s = %s;\n' %
799c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              (policy.name, policy.name, policy.id + RESERVED_IDS) ]
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
802c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WriteChromeSettingsProtobuf(policies, os, f):
803c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write(CHROME_SETTINGS_PROTO_HEAD)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  fields = []
806c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('// PBs for individual settings.\n\n')
807c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for policy in policies:
808c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # Note: this protobuf also gets the unsupported policies, since it's an
809c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # exaustive list of all the supported user policies on any platform.
810c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if not policy.is_device_only:
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      _WritePolicyProto(f, policy, fields)
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
813c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('// --------------------------------------------------\n'
814c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '// Big wrapper PB containing the above groups.\n\n'
815c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          'message ChromeSettingsProto {\n')
816c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write(''.join(fields))
817c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('}\n\n')
818c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
819c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
820c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WriteCloudPolicyProtobuf(policies, os, f):
821c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write(CLOUD_POLICY_PROTO_HEAD)
822c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('message CloudPolicySettings {\n')
823c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for policy in policies:
824c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if policy.is_supported and not policy.is_device_only:
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      f.write('  optional %sPolicyProto %s = %s;\n' %
826c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              (policy.policy_protobuf_type, policy.name,
827c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               policy.id + RESERVED_IDS))
828c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('}\n\n')
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#------------------ protobuf decoder -------------------------------#
832c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CPP_HEAD = '''
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/basictypes.h"
8387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/callback.h"
8399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/json/json_reader.h"
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
8419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/memory/scoped_ptr.h"
8423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "base/memory/weak_ptr.h"
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/cloud_external_data_manager.h"
845f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/external_data_fetcher.h"
846f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_map.h"
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "policy/policy_constants.h"
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "policy/proto/cloud_policy.pb.h"
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using google::protobuf::RepeatedPtrField;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace em = enterprise_management;
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
856eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbase::Value* DecodeIntegerValue(google::protobuf::int64 value) {
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value < std::numeric_limits<int>::min() ||
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value > std::numeric_limits<int>::max()) {
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Integer value " << value
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " out of numeric limits, ignoring.";
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
864116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return new base::FundamentalValue(static_cast<int>(value));
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
867eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbase::ListValue* DecodeStringList(const em::StringList& string_list) {
868eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ListValue* list_value = new base::ListValue;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RepeatedPtrField<std::string>::const_iterator entry;
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (entry = string_list.entries().begin();
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       entry != string_list.entries().end(); ++entry) {
8725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    list_value->AppendString(*entry);
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return list_value;
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
877d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::Value* DecodeJson(const std::string& json) {
8789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  scoped_ptr<base::Value> root(
8799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS));
880d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
881d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!root)
8829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    LOG(WARNING) << "Invalid JSON string, ignoring: " << json;
8839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
884d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Accept any Value type that parsed as JSON, and leave it to the handler to
885d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // convert and check the concrete type.
886d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return root.release();
8879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
8889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
8893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid DecodePolicy(const em::CloudPolicySettings& policy,
8903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                  base::WeakPtr<CloudExternalDataManager> external_data_manager,
8913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                  PolicyMap* map) {
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CPP_FOOT = '''}
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _CreateValue(type, arg):
902c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if type == 'TYPE_BOOLEAN':
903116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return 'new base::FundamentalValue(%s)' % arg
904c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  elif type == 'TYPE_INTEGER':
905c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 'DecodeIntegerValue(%s)' % arg
906c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  elif type == 'TYPE_STRING':
9075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return 'new base::StringValue(%s)' % arg
908c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  elif type == 'TYPE_LIST':
909c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 'DecodeStringList(%s)' % arg
9103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  elif type == 'TYPE_DICTIONARY' or type == 'TYPE_EXTERNAL':
911d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return 'DecodeJson(%s)' % arg
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
913c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    raise NotImplementedError('Unknown type %s' % type)
914c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
915c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochdef _CreateExternalDataFetcher(type, name):
9173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if type == 'TYPE_EXTERNAL':
9183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return 'new ExternalDataFetcher(external_data_manager, key::k%s)' % name
9193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return 'NULL'
9203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
9213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
922c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WritePolicyCode(f, policy):
923c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  membername = policy.name.lower()
924c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  proto_type = '%sPolicyProto' % policy.policy_protobuf_type
925c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('  if (policy.has_%s()) {\n' % membername)
926c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('    const em::%s& policy_proto = policy.%s();\n' %
927c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          (proto_type, membername))
928c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('    if (policy_proto.has_value()) {\n')
929c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write('      PolicyLevel level = POLICY_LEVEL_MANDATORY;\n'
930c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '      bool do_set = true;\n'
931c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '      if (policy_proto.has_policy_options()) {\n'
932c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '        do_set = false;\n'
933c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '        switch(policy_proto.policy_options().mode()) {\n'
934c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '          case em::PolicyOptions::MANDATORY:\n'
935c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            do_set = true;\n'
936c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            level = POLICY_LEVEL_MANDATORY;\n'
937c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            break;\n'
938c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '          case em::PolicyOptions::RECOMMENDED:\n'
939c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            do_set = true;\n'
940c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            level = POLICY_LEVEL_RECOMMENDED;\n'
941c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            break;\n'
942c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '          case em::PolicyOptions::UNSET:\n'
943c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '            break;\n'
944c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '        }\n'
945c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '      }\n'
946c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '      if (do_set) {\n')
947eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  f.write('        base::Value* value = %s;\n' %
9483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          (_CreateValue(policy.policy_type, 'policy_proto.value()')))
949a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  # TODO(bartfab): |value| == NULL indicates that the policy value could not be
950a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  # parsed successfully. Surface such errors in the UI.
951a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  f.write('        if (value) {\n')
952a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  f.write('          ExternalDataFetcher* external_data_fetcher = %s;\n' %
9533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          _CreateExternalDataFetcher(policy.policy_type, policy.name))
954a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  f.write('          map->Set(key::k%s, level, POLICY_SCOPE_USER,\n' %
955c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          policy.name)
956a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  f.write('                   value, external_data_fetcher);\n'
957a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          '        }\n'
958a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          '      }\n'
959c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '    }\n'
960c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          '  }\n')
961c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
962c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
963c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _WriteCloudPolicyDecoder(policies, os, f):
964c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write(CPP_HEAD)
965c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for policy in policies:
966c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if policy.is_supported and not policy.is_device_only:
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      _WritePolicyCode(f, policy)
968c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  f.write(CPP_FOOT)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main())
973