Skip to content

Instantly share code, notes, and snippets.

@sailfish009
Created August 12, 2020 08:48
Show Gist options
  • Save sailfish009/8470dced2621ae8633f8d5ba30563728 to your computer and use it in GitHub Desktop.
Save sailfish009/8470dced2621ae8633f8d5ba30563728 to your computer and use it in GitHub Desktop.
https://forums.gentoo.org/viewtopic-t-1108872-start-0.html
# Python3+ instead of python2.7
# by Pavel Kabikov aka bitMan
--- chromium-81.0.4044.26/build/toolchain/gcc_solink_wrapper.py 2020-02-20 03:32:08.000000000 +0300
+++ /tmp/gcc_solink_wrapper.py 2020-02-27 00:45:25.526917216 +0300
@@ -11,6 +11,7 @@
"""
import argparse
+import io
import os
import subprocess
import sys
@@ -18,12 +19,19 @@
import wrapper_utils
+def read_as_utf8(fileno):
+ fp = io.open(fileno, mode="r", encoding="utf-8", closefd=False)
+ content = fp.read()
+ fp.close()
+ return content
+
def CollectSONAME(args):
"""Replaces: readelf -d $sofile | grep SONAME"""
toc = ''
readelf = subprocess.Popen(wrapper_utils.CommandToRun(
[args.readelf, '-d', args.sofile]), stdout=subprocess.PIPE, bufsize=-1)
- for line in readelf.stdout:
+ # print(readelf.stdout)
+ for line in read_as_utf8(readelf.stdout.fileno()):
if 'SONAME' in line:
toc += line
return readelf.wait(), toc
@@ -35,7 +43,7 @@
nm = subprocess.Popen(wrapper_utils.CommandToRun([
args.nm, '--format=posix', '-g', '-D', args.sofile]),
stdout=subprocess.PIPE, bufsize=-1)
- for line in nm.stdout:
+ for line in read_as_utf8(nm.stdout.fileno()):
toc += ' '.join(line.split(' ', 2)[:2]) + '\n'
return nm.wait(), toc
@sailfish009
Copy link
Author

sailfish009 commented Aug 12, 2020

# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This module's classes provide an interface to mojo modules. Modules are
# collections of interfaces and structs to be used by mojo ipc clients and
# servers.
#
# A simple interface would be created this way:
# module = mojom.generate.module.Module('Foo')
# interface = module.AddInterface('Bar')
# method = interface.AddMethod('Tat', 0)
# method.AddParameter('baz', 0, mojom.INT32)
import pickle
# We use our own version of __repr__ when displaying the AST, as the
# AST currently doesn't capture which nodes are reference (e.g. to
# types) and which nodes are definitions. This allows us to e.g. print
# the definition of a struct when it's defined inside a module, but
# only print its name when it's referenced in e.g. a method parameter.
def Repr(obj, as_ref=True):
  """A version of __repr__ that can distinguish references.
  Sometimes we like to print an object's full representation
  (e.g. with its fields) and sometimes we just want to reference an
  object that was printed in full elsewhere. This function allows us
  to make that distinction.
  Args:
    obj: The object whose string representation we compute.
    as_ref: If True, use the short reference representation.
  Returns:
    A str representation of |obj|.
  """
  if hasattr(obj, 'Repr'):
    return obj.Repr(as_ref=as_ref)
  # Since we cannot implement Repr for existing container types, we
  # handle them here.
  elif isinstance(obj, list):
    if not obj:
      return '[]'
    else:
      return ('[\n%s\n]' % (',\n'.join(
          '    %s' % Repr(elem, as_ref).replace('\n', '\n    ')
          for elem in obj)))
  elif isinstance(obj, dict):
    if not obj:
      return '{}'
    else:
      return ('{\n%s\n}' % (',\n'.join(
          '    %s: %s' % (Repr(key, as_ref).replace('\n', '\n    '),
                          Repr(val, as_ref).replace('\n', '\n    '))
          for key, val in obj.items())))
  else:
    return repr(obj)
def GenericRepr(obj, names):
  """Compute generic Repr for |obj| based on the attributes in |names|.
  Args:
    obj: The object to compute a Repr for.
    names: A dict from attribute names to include, to booleans
        specifying whether those attributes should be shown as
        references or not.
  Returns:
    A str representation of |obj|.
  """
  def ReprIndent(name, as_ref):
    return '    %s=%s' % (name, Repr(getattr(obj, name), as_ref).replace(
        '\n', '\n    '))
  return '%s(\n%s\n)' % (obj.__class__.__name__, ',\n'.join(
      ReprIndent(name, as_ref) for (name, as_ref) in names.items()))
class Kind(object):
  """Kind represents a type (e.g. int8, string).
  Attributes:
    spec: A string uniquely identifying the type. May be None.
    module: {Module} The defining module. Set to None for built-in types.
    parent_kind: The enclosing type. For example, an enum defined
        inside an interface has that interface as its parent. May be None.
  """
  def __init__(self, spec=None, module=None):
    self.spec = spec
    self.module = module
    self.parent_kind = None
  def Repr(self, as_ref=True):
    # pylint: disable=unused-argument
    return '<%s spec=%r>' % (self.__class__.__name__, self.spec)
  def __repr__(self):
    # Gives us a decent __repr__ for all kinds.
    return self.Repr()
  def __eq__(self, rhs):
    # pylint: disable=unidiomatic-typecheck
    return (type(self) == type(rhs)
            and (self.spec, self.parent_kind) == (rhs.spec, rhs.parent_kind))
  def __hash__(self):
    # TODO(crbug.com/1060471): Remove this and other __hash__ methods on Kind
    # and its subclasses. This is to support existing generator code which uses
    # some primitive Kinds as dict keys. The default hash (object identity)
    # breaks these dicts when a pickled Module instance is unpickled and used
    # during a subsequent run of the parser.
    return hash((self.spec, self.parent_kind))
class ReferenceKind(Kind):
  """ReferenceKind represents pointer and handle types.
  A type is nullable if null (for pointer types) or invalid handle (for handle
  types) is a legal value for the type.
  Attributes:
    is_nullable: True if the type is nullable.
  """
  def __init__(self, spec=None, is_nullable=False, module=None):
    assert spec is None or is_nullable == spec.startswith('?')
    Kind.__init__(self, spec, module)
    self.is_nullable = is_nullable
    self.shared_definition = {}
  def Repr(self, as_ref=True):
    return '<%s spec=%r is_nullable=%r>' % (self.__class__.__name__, self.spec,
                                            self.is_nullable)
  def MakeNullableKind(self):
    assert not self.is_nullable
    if self == STRING:
      return NULLABLE_STRING
    if self == HANDLE:
      return NULLABLE_HANDLE
    if self == DCPIPE:
      return NULLABLE_DCPIPE
    if self == DPPIPE:
      return NULLABLE_DPPIPE
    if self == MSGPIPE:
      return NULLABLE_MSGPIPE
    if self == SHAREDBUFFER:
      return NULLABLE_SHAREDBUFFER
    if self == PLATFORMHANDLE:
      return NULLABLE_PLATFORMHANDLE
    nullable_kind = type(self)()
    nullable_kind.shared_definition = self.shared_definition
    if self.spec is not None:
      nullable_kind.spec = '?' + self.spec
    nullable_kind.is_nullable = True
    nullable_kind.parent_kind = self.parent_kind
    nullable_kind.module = self.module
    return nullable_kind
  @classmethod
  def AddSharedProperty(cls, name):
    """Adds a property |name| to |cls|, which accesses the corresponding item in
       |shared_definition|.
       The reason of adding such indirection is to enable sharing definition
       between a reference kind and its nullable variation. For example:
         a = Struct('test_struct_1')
         b = a.MakeNullableKind()
         a.name = 'test_struct_2'
         print(b.name)  # Outputs 'test_struct_2'.
    """
    def Get(self):
      try:
        return self.shared_definition[name]
      except KeyError:  # Must raise AttributeError if property doesn't exist.
        raise AttributeError
    def Set(self, value):
      self.shared_definition[name] = value
    setattr(cls, name, property(Get, Set))
  def __eq__(self, rhs):
    return (isinstance(rhs, ReferenceKind)
            and super(ReferenceKind, self).__eq__(rhs)
            and self.is_nullable == rhs.is_nullable)
  def __hash__(self):
    return hash((super(ReferenceKind, self).__hash__(), self.is_nullable))
# Initialize the set of primitive types. These can be accessed by clients.
BOOL = Kind('b')
INT8 = Kind('i8')
INT16 = Kind('i16')
INT32 = Kind('i32')
INT64 = Kind('i64')
UINT8 = Kind('u8')
UINT16 = Kind('u16')
UINT32 = Kind('u32')
UINT64 = Kind('u64')
FLOAT = Kind('f')
DOUBLE = Kind('d')
STRING = ReferenceKind('s')
HANDLE = ReferenceKind('h')
DCPIPE = ReferenceKind('h:d:c')
DPPIPE = ReferenceKind('h:d:p')
MSGPIPE = ReferenceKind('h:m')
SHAREDBUFFER = ReferenceKind('h:s')
PLATFORMHANDLE = ReferenceKind('h:p')
NULLABLE_STRING = ReferenceKind('?s', True)
NULLABLE_HANDLE = ReferenceKind('?h', True)
NULLABLE_DCPIPE = ReferenceKind('?h:d:c', True)
NULLABLE_DPPIPE = ReferenceKind('?h:d:p', True)
NULLABLE_MSGPIPE = ReferenceKind('?h:m', True)
NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True)
NULLABLE_PLATFORMHANDLE = ReferenceKind('?h:p', True)
# Collection of all Primitive types
PRIMITIVES = (
    BOOL,
    INT8,
    INT16,
    INT32,
    INT64,
    UINT8,
    UINT16,
    UINT32,
    UINT64,
    FLOAT,
    DOUBLE,
    STRING,
    HANDLE,
    DCPIPE,
    DPPIPE,
    MSGPIPE,
    SHAREDBUFFER,
    PLATFORMHANDLE,
    NULLABLE_STRING,
    NULLABLE_HANDLE,
    NULLABLE_DCPIPE,
    NULLABLE_DPPIPE,
    NULLABLE_MSGPIPE,
    NULLABLE_SHAREDBUFFER,
    NULLABLE_PLATFORMHANDLE,
)
ATTRIBUTE_MIN_VERSION = 'MinVersion'
ATTRIBUTE_EXTENSIBLE = 'Extensible'
ATTRIBUTE_STABLE = 'Stable'
ATTRIBUTE_SYNC = 'Sync'
class NamedValue(object):
  def __init__(self, module, parent_kind, mojom_name):
    self.module = module
    self.parent_kind = parent_kind
    self.mojom_name = mojom_name
  def GetSpec(self):
    return (self.module.GetNamespacePrefix() +
            (self.parent_kind and
             (self.parent_kind.mojom_name + '.') or "") + self.mojom_name)
  def __eq__(self, rhs):
    return (isinstance(rhs, NamedValue)
            and (self.parent_kind, self.mojom_name) == (rhs.parent_kind,
                                                        rhs.mojom_name))
class BuiltinValue(object):
  def __init__(self, value):
    self.value = value
  def __eq__(self, rhs):
    return isinstance(rhs, BuiltinValue) and self.value == rhs.value
class ConstantValue(NamedValue):
  def __init__(self, module, parent_kind, constant):
    NamedValue.__init__(self, module, parent_kind, constant.mojom_name)
    self.constant = constant
  @property
  def name(self):
    return self.constant.name
class EnumValue(NamedValue):
  def __init__(self, module, enum, field):
    NamedValue.__init__(self, module, enum.parent_kind, field.mojom_name)
    self.field = field
    self.enum = enum
  def GetSpec(self):
    return (self.module.GetNamespacePrefix() +
            (self.parent_kind and (self.parent_kind.mojom_name + '.') or "") +
            self.enum.mojom_name + '.' + self.mojom_name)
  @property
  def name(self):
    return self.field.name
class Constant(object):
  def __init__(self, mojom_name=None, kind=None, value=None, parent_kind=None):
    self.mojom_name = mojom_name
    self.name = None
    self.kind = kind
    self.value = value
    self.parent_kind = parent_kind
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeConstant(self.mojom_name)
  def __eq__(self, rhs):
    return (isinstance(rhs, Constant)
            and (self.mojom_name, self.kind, self.value,
                 self.parent_kind) == (rhs.mojom_name, rhs.kind, rhs.value,
                                       rhs.parent_kind))
class Field(object):
  def __init__(self,
               mojom_name=None,
               kind=None,
               ordinal=None,
               default=None,
               attributes=None):
    if self.__class__.__name__ == 'Field':
      raise Exception()
    self.mojom_name = mojom_name
    self.name = None
    self.kind = kind
    self.ordinal = ordinal
    self.default = default
    self.attributes = attributes
  def Repr(self, as_ref=True):
    # pylint: disable=unused-argument
    # Fields are only referenced by objects which define them and thus
    # they are always displayed as non-references.
    return GenericRepr(self, {'mojom_name': False, 'kind': True})
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeField(self.mojom_name)
  @property
  def min_version(self):
    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
        if self.attributes else None
  def __eq__(self, rhs):
    return (isinstance(rhs, Field)
            and (self.mojom_name, self.kind, self.ordinal, self.default,
                 self.attributes) == (rhs.mojom_name, rhs.kind, rhs.ordinal,
                                      rhs.default, rhs.attributes))
  def __hash__(self):
    return hash((self.mojom_name, self.kind, self.ordinal, self.default))
class StructField(Field):
  pass
class UnionField(Field):
  pass
def _IsFieldBackwardCompatible(new_field, old_field):
  if (new_field.min_version or 0) != (old_field.min_version or 0):
    return False
  if isinstance(new_field.kind, (Enum, Struct, Union)):
    return new_field.kind.IsBackwardCompatible(old_field.kind)
  return new_field.kind == old_field.kind
class Struct(ReferenceKind):
  """A struct with typed fields.
  Attributes:
    mojom_name: {str} The name of the struct type as defined in mojom.
    name: {str} The stylized name.
    native_only: {bool} Does the struct have a body (i.e. any fields) or is it
        purely a native struct.
    custom_serializer: {bool} Should we generate a serializer for the struct or
        will one be provided by non-generated code.
    fields: {List[StructField]} The members of the struct.
    enums: {List[Enum]} The enums defined in the struct scope.
    constants: {List[Constant]} The constants defined in the struct scope.
    attributes: {dict} Additional information about the struct, such as
        if it's a native struct.
  """
  ReferenceKind.AddSharedProperty('mojom_name')
  ReferenceKind.AddSharedProperty('name')
  ReferenceKind.AddSharedProperty('native_only')
  ReferenceKind.AddSharedProperty('custom_serializer')
  ReferenceKind.AddSharedProperty('fields')
  ReferenceKind.AddSharedProperty('enums')
  ReferenceKind.AddSharedProperty('constants')
  ReferenceKind.AddSharedProperty('attributes')
  def __init__(self, mojom_name=None, module=None, attributes=None):
    if mojom_name is not None:
      spec = 'x:' + mojom_name
    else:
      spec = None
    ReferenceKind.__init__(self, spec, False, module)
    self.mojom_name = mojom_name
    self.name = None
    self.native_only = False
    self.custom_serializer = False
    self.fields = []
    self.enums = []
    self.constants = []
    self.attributes = attributes
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s mojom_name=%r module=%s>' % (self.__class__.__name__,
                                               self.mojom_name,
                                               Repr(self.module, as_ref=True))
    else:
      return GenericRepr(self, {
          'mojom_name': False,
          'fields': False,
          'module': True
      })
  def AddField(self,
               mojom_name,
               kind,
               ordinal=None,
               default=None,
               attributes=None):
    field = StructField(mojom_name, kind, ordinal, default, attributes)
    self.fields.append(field)
    return field
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeStruct(self.mojom_name)
    for field in self.fields:
      field.Stylize(stylizer)
    for enum in self.enums:
      enum.Stylize(stylizer)
    for constant in self.constants:
      constant.Stylize(stylizer)
  def IsBackwardCompatible(self, older_struct):
    """This struct is backward-compatible with older_struct if and only if all
    of the following conditions hold:
      - Any newly added field is tagged with a [MinVersion] attribute specifying
        a version number greater than all previously used [MinVersion]
        attributes within the struct.
      - All fields present in older_struct remain present in the new struct,
        with the same ordinal position, same optional or non-optional status,
        same (or backward-compatible) type and where applicable, the same
        [MinVersion] attribute value.
      - All [MinVersion] attributes must be non-decreasing in ordinal order.
      - All reference-typed (string, array, map, struct, or union) fields tagged
        with a [MinVersion] greater than zero must be optional.
    """
    def buildOrdinalFieldMap(struct):
      fields_by_ordinal = {}
      for field in struct.fields:
        if field.ordinal in fields_by_ordinal:
          raise Exception('Multiple fields with ordinal %s in struct %s.' %
                          (field.ordinal, struct.mojom_name))
        fields_by_ordinal[field.ordinal] = field
      return fields_by_ordinal
    new_fields = buildOrdinalFieldMap(self)
    old_fields = buildOrdinalFieldMap(older_struct)
    if len(new_fields) < len(old_fields):
      # At least one field was removed, which is not OK.
      return False
    # If there are N fields, existing ordinal values must exactly cover the
    # range from 0 to N-1.
    num_old_ordinals = len(old_fields)
    max_old_min_version = 0
    for ordinal in range(num_old_ordinals):
      new_field = new_fields[ordinal]
      old_field = old_fields[ordinal]
      if (old_field.min_version or 0) > max_old_min_version:
        max_old_min_version = old_field.min_version
      if not _IsFieldBackwardCompatible(new_field, old_field):
        # Type or min-version mismatch between old and new versions of the same
        # ordinal field.
        return False
    # At this point we know all old fields are intact in the new struct
    # definition. Now verify that all new fields have a high enough min version
    # and are appropriately optional where required.
    num_new_ordinals = len(new_fields)
    last_min_version = max_old_min_version
    for ordinal in range(num_old_ordinals, num_new_ordinals):
      new_field = new_fields[ordinal]
      min_version = new_field.min_version or 0
      if min_version <= max_old_min_version:
        # A new field is being added to an existing version, which is not OK.
        return False
      if min_version < last_min_version:
        # The [MinVersion] of a field cannot be lower than the [MinVersion] of
        # a field with lower ordinal value.
        return False
      if IsReferenceKind(new_field.kind) and not IsNullableKind(new_field.kind):
        # New fields whose type can be nullable MUST be nullable.
        return False
    return True
  @property
  def stable(self):
    return self.attributes.get(ATTRIBUTE_STABLE, False) \
        if self.attributes else False
  @property
  def qualified_name(self):
    if self.parent_kind:
      prefix = self.parent_kind.qualified_name + '.'
    else:
      prefix = self.module.GetNamespacePrefix()
    return '%s%s' % (prefix, self.mojom_name)
  def __eq__(self, rhs):
    return (isinstance(rhs, Struct) and
            (self.mojom_name, self.native_only, self.fields, self.constants,
             self.attributes) == (rhs.mojom_name, rhs.native_only, rhs.fields,
                                  rhs.constants, rhs.attributes))
  def __hash__(self):
    return id(self)
class Union(ReferenceKind):
  """A union of several kinds.
  Attributes:
    mojom_name: {str} The name of the union type as defined in mojom.
    name: {str} The stylized name.
    fields: {List[UnionField]} The members of the union.
    attributes: {dict} Additional information about the union, such as
        which Java class name to use to represent it in the generated
        bindings.
  """
  ReferenceKind.AddSharedProperty('mojom_name')
  ReferenceKind.AddSharedProperty('name')
  ReferenceKind.AddSharedProperty('fields')
  ReferenceKind.AddSharedProperty('attributes')
  def __init__(self, mojom_name=None, module=None, attributes=None):
    if mojom_name is not None:
      spec = 'x:' + mojom_name
    else:
      spec = None
    ReferenceKind.__init__(self, spec, False, module)
    self.mojom_name = mojom_name
    self.name = None
    self.fields = []
    self.attributes = attributes
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s spec=%r is_nullable=%r fields=%s>' % (
          self.__class__.__name__, self.spec, self.is_nullable, Repr(
              self.fields))
    else:
      return GenericRepr(self, {'fields': True, 'is_nullable': False})
  def AddField(self, mojom_name, kind, ordinal=None, attributes=None):
    field = UnionField(mojom_name, kind, ordinal, None, attributes)
    self.fields.append(field)
    return field
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeUnion(self.mojom_name)
    for field in self.fields:
      field.Stylize(stylizer)
  def IsBackwardCompatible(self, older_union):
    """This union is backward-compatible with older_union if and only if all
    of the following conditions hold:
      - Any newly added field is tagged with a [MinVersion] attribute specifying
        a version number greater than all previously used [MinVersion]
        attributes within the union.
      - All fields present in older_union remain present in the new union,
        with the same ordinal value, same optional or non-optional status,
        same (or backward-compatible) type, and where applicable, the same
        [MinVersion] attribute value.
    """
    def buildOrdinalFieldMap(union):
      fields_by_ordinal = {}
      for field in union.fields:
        if field.ordinal in fields_by_ordinal:
          raise Exception('Multiple fields with ordinal %s in union %s.' %
                          (field.ordinal, union.mojom_name))
        fields_by_ordinal[field.ordinal] = field
      return fields_by_ordinal
    new_fields = buildOrdinalFieldMap(self)
    old_fields = buildOrdinalFieldMap(older_union)
    if len(new_fields) < len(old_fields):
      # At least one field was removed, which is not OK.
      return False
    max_old_min_version = 0
    for ordinal, old_field in old_fields.items():
      new_field = new_fields.get(ordinal)
      if not new_field:
        # A field was removed, which is not OK.
        return False
      if not _IsFieldBackwardCompatible(new_field, old_field):
        # An field changed its type or MinVersion, which is not OK.
        return False
      old_min_version = old_field.min_version or 0
      if old_min_version > max_old_min_version:
        max_old_min_version = old_min_version
    new_ordinals = set(new_fields.keys()) - set(old_fields.keys())
    for ordinal in new_ordinals:
      if (new_fields[ordinal].min_version or 0) <= max_old_min_version:
        # New fields must use a MinVersion greater than any old fields.
        return False
    return True
  @property
  def stable(self):
    return self.attributes.get(ATTRIBUTE_STABLE, False) \
        if self.attributes else False
  @property
  def qualified_name(self):
    if self.parent_kind:
      prefix = self.parent_kind.qualified_name + '.'
    else:
      prefix = self.module.GetNamespacePrefix()
    return '%s%s' % (prefix, self.mojom_name)
  def __eq__(self, rhs):
    return (isinstance(rhs, Union) and
            (self.mojom_name, self.fields,
             self.attributes) == (rhs.mojom_name, rhs.fields, rhs.attributes))
  def __hash__(self):
    return id(self)
class Array(ReferenceKind):
  """An array.
  Attributes:
    kind: {Kind} The type of the elements. May be None.
    length: The number of elements. None if unknown.
  """
  ReferenceKind.AddSharedProperty('kind')
  ReferenceKind.AddSharedProperty('length')
  def __init__(self, kind=None, length=None):
    if kind is not None:
      if length is not None:
        spec = 'a%d:%s' % (length, kind.spec)
      else:
        spec = 'a:%s' % kind.spec
      ReferenceKind.__init__(self, spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
    self.length = length
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % (
          self.__class__.__name__, self.spec, self.is_nullable, Repr(
              self.kind), self.length)
    else:
      return GenericRepr(self, {
          'kind': True,
          'length': False,
          'is_nullable': False
      })
  def __eq__(self, rhs):
    return (isinstance(rhs, Array)
            and (self.kind, self.length) == (rhs.kind, rhs.length))
  def __hash__(self):
    return id(self)
class Map(ReferenceKind):
  """A map.
  Attributes:
    key_kind: {Kind} The type of the keys. May be None.
    value_kind: {Kind} The type of the elements. May be None.
  """
  ReferenceKind.AddSharedProperty('key_kind')
  ReferenceKind.AddSharedProperty('value_kind')
  def __init__(self, key_kind=None, value_kind=None):
    if (key_kind is not None and value_kind is not None):
      ReferenceKind.__init__(
          self, 'm[' + key_kind.spec + '][' + value_kind.spec + ']')
      if IsNullableKind(key_kind):
        raise Exception("Nullable kinds cannot be keys in maps.")
      if IsAnyHandleKind(key_kind):
        raise Exception("Handles cannot be keys in maps.")
      if IsAnyInterfaceKind(key_kind):
        raise Exception("Interfaces cannot be keys in maps.")
      if IsArrayKind(key_kind):
        raise Exception("Arrays cannot be keys in maps.")
    else:
      ReferenceKind.__init__(self)
    self.key_kind = key_kind
    self.value_kind = value_kind
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s spec=%r is_nullable=%r key_kind=%s value_kind=%s>' % (
          self.__class__.__name__, self.spec, self.is_nullable,
          Repr(self.key_kind), Repr(self.value_kind))
    else:
      return GenericRepr(self, {'key_kind': True, 'value_kind': True})
  def __eq__(self, rhs):
    return (isinstance(rhs, Map) and
            (self.key_kind, self.value_kind) == (rhs.key_kind, rhs.value_kind))
  def __hash__(self):
    return id(self)
class PendingRemote(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, Interface):
        raise Exception(
            'pending_remote<T> requires T to be an interface type. Got %r' %
            kind.spec)
      ReferenceKind.__init__(self, 'rmt:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
  def __eq__(self, rhs):
    return isinstance(rhs, PendingRemote) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class PendingReceiver(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, Interface):
        raise Exception(
            'pending_receiver<T> requires T to be an interface type. Got %r' %
            kind.spec)
      ReferenceKind.__init__(self, 'rcv:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
  def __eq__(self, rhs):
    return isinstance(rhs, PendingReceiver) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class PendingAssociatedRemote(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, Interface):
        raise Exception(
            'pending_associated_remote<T> requires T to be an interface ' +
            'type. Got %r' % kind.spec)
      ReferenceKind.__init__(self, 'rma:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
  def __eq__(self, rhs):
    return isinstance(rhs, PendingAssociatedRemote) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class PendingAssociatedReceiver(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, Interface):
        raise Exception(
            'pending_associated_receiver<T> requires T to be an interface' +
            'type. Got %r' % kind.spec)
      ReferenceKind.__init__(self, 'rca:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
  def __eq__(self, rhs):
    return isinstance(rhs, PendingAssociatedReceiver) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class InterfaceRequest(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, Interface):
        raise Exception(
            "Interface request requires %r to be an interface." % kind.spec)
      ReferenceKind.__init__(self, 'r:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
  def __eq__(self, rhs):
    return isinstance(rhs, InterfaceRequest) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class AssociatedInterfaceRequest(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, InterfaceRequest):
        raise Exception(
            "Associated interface request requires %r to be an interface "
            "request." % kind.spec)
      assert not kind.is_nullable
      ReferenceKind.__init__(self, 'asso:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind.kind if kind is not None else None
  def __eq__(self, rhs):
    return isinstance(rhs, AssociatedInterfaceRequest) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class Parameter(object):
  def __init__(self,
               mojom_name=None,
               kind=None,
               ordinal=None,
               default=None,
               attributes=None):
    self.mojom_name = mojom_name
    self.name = None
    self.ordinal = ordinal
    self.kind = kind
    self.default = default
    self.attributes = attributes
  def Repr(self, as_ref=True):
    # pylint: disable=unused-argument
    return '<%s mojom_name=%r kind=%s>' % (
        self.__class__.__name__, self.mojom_name, self.kind.Repr(as_ref=True))
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeParameter(self.mojom_name)
  @property
  def min_version(self):
    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
        if self.attributes else None
  def __eq__(self, rhs):
    return (isinstance(rhs, Parameter)
            and (self.mojom_name, self.ordinal, self.kind, self.default,
                 self.attributes) == (rhs.mojom_name, rhs.ordinal, rhs.kind,
                                      rhs.default, rhs.attributes))
class Method(object):
  def __init__(self, interface, mojom_name, ordinal=None, attributes=None):
    self.interface = interface
    self.mojom_name = mojom_name
    self.name = None
    self.explicit_ordinal = ordinal
    self.ordinal = ordinal
    self.parameters = []
    self.param_struct = None
    self.response_parameters = None
    self.response_param_struct = None
    self.attributes = attributes
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
    else:
      return GenericRepr(self, {
          'mojom_name': False,
          'parameters': True,
          'response_parameters': True
      })
  def AddParameter(self,
                   mojom_name,
                   kind,
                   ordinal=None,
                   default=None,
                   attributes=None):
    parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
    self.parameters.append(parameter)
    return parameter
  def AddResponseParameter(self,
                           mojom_name,
                           kind,
                           ordinal=None,
                           default=None,
                           attributes=None):
    if self.response_parameters == None:
      self.response_parameters = []
    parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
    self.response_parameters.append(parameter)
    return parameter
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeMethod(self.mojom_name)
    for param in self.parameters:
      param.Stylize(stylizer)
    if self.response_parameters is not None:
      for param in self.response_parameters:
        param.Stylize(stylizer)
    if self.param_struct:
      self.param_struct.Stylize(stylizer)
    if self.response_param_struct:
      self.response_param_struct.Stylize(stylizer)
  @property
  def min_version(self):
    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
        if self.attributes else None
  @property
  def sync(self):
    return self.attributes.get(ATTRIBUTE_SYNC) \
        if self.attributes else None
  def __eq__(self, rhs):
    return (isinstance(rhs, Method) and
            (self.mojom_name, self.ordinal, self.parameters,
             self.response_parameters,
             self.attributes) == (rhs.mojom_name, rhs.ordinal, rhs.parameters,
                                  rhs.response_parameters, rhs.attributes))
class Interface(ReferenceKind):
  ReferenceKind.AddSharedProperty('mojom_name')
  ReferenceKind.AddSharedProperty('name')
  ReferenceKind.AddSharedProperty('methods')
  ReferenceKind.AddSharedProperty('enums')
  ReferenceKind.AddSharedProperty('constants')
  ReferenceKind.AddSharedProperty('attributes')
  def __init__(self, mojom_name=None, module=None, attributes=None):
    if mojom_name is not None:
      spec = 'x:' + mojom_name
    else:
      spec = None
    ReferenceKind.__init__(self, spec, False, module)
    self.mojom_name = mojom_name
    self.name = None
    self.methods = []
    self.enums = []
    self.constants = []
    self.attributes = attributes
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
    else:
      return GenericRepr(self, {
          'mojom_name': False,
          'attributes': False,
          'methods': False
      })
  def AddMethod(self, mojom_name, ordinal=None, attributes=None):
    method = Method(self, mojom_name, ordinal, attributes)
    self.methods.append(method)
    return method
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeInterface(self.mojom_name)
    for method in self.methods:
      method.Stylize(stylizer)
    for enum in self.enums:
      enum.Stylize(stylizer)
    for constant in self.constants:
      constant.Stylize(stylizer)
  def IsBackwardCompatible(self, older_interface):
    """This interface is backward-compatible with older_interface if and only
    if all of the following conditions hold:
      - All defined methods in older_interface (when identified by ordinal) have
        backward-compatible definitions in this interface. For each method this
        means:
          - The parameter list is backward-compatible, according to backward-
            compatibility rules for structs, where each parameter is essentially
            a struct field.
          - If the old method definition does not specify a reply message, the
            new method definition must not specify a reply message.
          - If the old method definition specifies a reply message, the new
            method definition must also specify a reply message with a parameter
            list that is backward-compatible according to backward-compatibility
            rules for structs.
      - All newly introduced methods in this interface have a [MinVersion]
        attribute specifying a version greater than any method in
        older_interface.
    """
    def buildOrdinalMethodMap(interface):
      methods_by_ordinal = {}
      for method in interface.methods:
        if method.ordinal in methods_by_ordinal:
          raise Exception('Multiple methods with ordinal %s in interface %s.' %
                          (method.ordinal, interface.mojom_name))
        methods_by_ordinal[method.ordinal] = method
      return methods_by_ordinal
    new_methods = buildOrdinalMethodMap(self)
    old_methods = buildOrdinalMethodMap(older_interface)
    max_old_min_version = 0
    for ordinal, old_method in old_methods.items():
      new_method = new_methods.get(ordinal)
      if not new_method:
        # A method was removed, which is not OK.
        return False
      if not new_method.param_struct.IsBackwardCompatible(
          old_method.param_struct):
        # The parameter list is not backward-compatible, which is not OK.
        return False
      if old_method.response_param_struct is None:
        if new_method.response_param_struct is not None:
          # A reply was added to a message which didn't have one before, and
          # this is not OK.
          return False
      else:
        if new_method.response_param_struct is None:
          # A reply was removed from a message, which is not OK.
          return False
        if not new_method.response_param_struct.IsBackwardCompatible(
            old_method.response_param_struct):
          # The new message's reply is not backward-compatible with the old
          # message's reply, which is not OK.
          return False
      if (old_method.min_version or 0) > max_old_min_version:
        max_old_min_version = old_method.min_version
    # All the old methods are compatible with their new counterparts. Now verify
    # that newly added methods are properly versioned.
    new_ordinals = set(new_methods.keys()) - set(old_methods.keys())
    for ordinal in new_ordinals:
      new_method = new_methods[ordinal]
      if (new_method.min_version or 0) <= max_old_min_version:
        # A method was added to an existing version, which is not OK.
        return False
    return True
  @property
  def stable(self):
    return self.attributes.get(ATTRIBUTE_STABLE, False) \
        if self.attributes else False
  @property
  def qualified_name(self):
    if self.parent_kind:
      prefix = self.parent_kind.qualified_name + '.'
    else:
      prefix = self.module.GetNamespacePrefix()
    return '%s%s' % (prefix, self.mojom_name)
  def __eq__(self, rhs):
    return (isinstance(rhs, Interface)
            and (self.mojom_name, self.methods, self.enums, self.constants,
                 self.attributes) == (rhs.mojom_name, rhs.methods, rhs.enums,
                                      rhs.constants, rhs.attributes))
  def __hash__(self):
    return id(self)
class AssociatedInterface(ReferenceKind):
  ReferenceKind.AddSharedProperty('kind')
  def __init__(self, kind=None):
    if kind is not None:
      if not isinstance(kind, Interface):
        raise Exception(
            "Associated interface requires %r to be an interface." % kind.spec)
      assert not kind.is_nullable
      ReferenceKind.__init__(self, 'asso:' + kind.spec)
    else:
      ReferenceKind.__init__(self)
    self.kind = kind
  def __eq__(self, rhs):
    return isinstance(rhs, AssociatedInterface) and self.kind == rhs.kind
  def __hash__(self):
    return id(self)
class EnumField(object):
  def __init__(self,
               mojom_name=None,
               value=None,
               attributes=None,
               numeric_value=None):
    self.mojom_name = mojom_name
    self.name = None
    self.value = value
    self.attributes = attributes
    self.numeric_value = numeric_value
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeEnumField(self.mojom_name)
  @property
  def min_version(self):
    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
        if self.attributes else None
  def __eq__(self, rhs):
    return (isinstance(rhs, EnumField)
            and (self.mojom_name, self.value, self.attributes,
                 self.numeric_value) == (rhs.mojom_name, rhs.value,
                                         rhs.attributes, rhs.numeric_value))
class Enum(Kind):
  def __init__(self, mojom_name=None, module=None, attributes=None):
    self.mojom_name = mojom_name
    self.name = None
    self.native_only = False
    if mojom_name is not None:
      spec = 'x:' + mojom_name
    else:
      spec = None
    Kind.__init__(self, spec, module)
    self.fields = []
    self.attributes = attributes
    self.min_value = None
    self.max_value = None
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
    else:
      return GenericRepr(self, {'mojom_name': False, 'fields': False})
  def Stylize(self, stylizer):
    self.name = stylizer.StylizeEnum(self.mojom_name)
    for field in self.fields:
      field.Stylize(stylizer)
  @property
  def extensible(self):
    return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \
        if self.attributes else False
  @property
  def stable(self):
    return self.attributes.get(ATTRIBUTE_STABLE, False) \
        if self.attributes else False
  @property
  def qualified_name(self):
    if self.parent_kind:
      prefix = self.parent_kind.qualified_name + '.'
    else:
      prefix = self.module.GetNamespacePrefix()
    return '%s%s' % (prefix, self.mojom_name)
  def IsBackwardCompatible(self, older_enum):
    """This enum is backward-compatible with older_enum if and only if one of
    the following conditions holds:
        - Neither enum is [Extensible] and both have the exact same set of valid
          numeric values. Field names and aliases for the same numeric value do
          not affect compatibility.
        - older_enum is [Extensible], and for every version defined by
          older_enum, this enum has the exact same set of valid numeric values.
    """
    def buildVersionFieldMap(enum):
      fields_by_min_version = {}
      for field in enum.fields:
        if field.min_version not in fields_by_min_version:
          fields_by_min_version[field.min_version] = set()
        fields_by_min_version[field.min_version].add(field.numeric_value)
      return fields_by_min_version
    old_fields = buildVersionFieldMap(older_enum)
    new_fields = buildVersionFieldMap(self)
    if new_fields.keys() != old_fields.keys() and not older_enum.extensible:
      return False
    for min_version, valid_values in old_fields.items():
      if (min_version not in new_fields
          or new_fields[min_version] != valid_values):
        return False
    return True
  def __eq__(self, rhs):
    return (isinstance(rhs, Enum) and
            (self.mojom_name, self.native_only, self.fields, self.attributes,
             self.min_value,
             self.max_value) == (rhs.mojom_name, rhs.native_only, rhs.fields,
                                 rhs.attributes, rhs.min_value, rhs.max_value))
  def __hash__(self):
    return id(self)
class Module(object):
  def __init__(self, path=None, mojom_namespace=None, attributes=None):
    self.path = path
    self.mojom_namespace = mojom_namespace
    self.namespace = None
    self.structs = []
    self.unions = []
    self.interfaces = []
    self.enums = []
    self.constants = []
    self.kinds = {}
    self.attributes = attributes
    self.imports = []
    self.imported_kinds = {}
  def __repr__(self):
    # Gives us a decent __repr__ for modules.
    return self.Repr()
  def __eq__(self, rhs):
    return (isinstance(rhs, Module) and
            (self.path, self.attributes, self.mojom_namespace, self.imports,
             self.constants, self.enums, self.structs, self.unions,
             self.interfaces) == (rhs.path, rhs.attributes, rhs.mojom_namespace,
                                  rhs.imports, rhs.constants, rhs.enums,
                                  rhs.structs, rhs.unions, rhs.interfaces))
  def Repr(self, as_ref=True):
    if as_ref:
      return '<%s path=%r mojom_namespace=%r>' % (
          self.__class__.__name__, self.path, self.mojom_namespace)
    else:
      return GenericRepr(
          self, {
              'path': False,
              'mojom_namespace': False,
              'attributes': False,
              'structs': False,
              'interfaces': False,
              'unions': False
          })
  def GetNamespacePrefix(self):
    return '%s.' % self.mojom_namespace if self.mojom_namespace else ''
  def AddInterface(self, mojom_name, attributes=None):
    interface = Interface(mojom_name, self, attributes)
    self.interfaces.append(interface)
    return interface
  def AddStruct(self, mojom_name, attributes=None):
    struct = Struct(mojom_name, self, attributes)
    self.structs.append(struct)
    return struct
  def AddUnion(self, mojom_name, attributes=None):
    union = Union(mojom_name, self, attributes)
    self.unions.append(union)
    return union
  def Stylize(self, stylizer):
    self.namespace = stylizer.StylizeModule(self.mojom_namespace)
    for struct in self.structs:
      struct.Stylize(stylizer)
    for union in self.unions:
      union.Stylize(stylizer)
    for interface in self.interfaces:
      interface.Stylize(stylizer)
    for enum in self.enums:
      enum.Stylize(stylizer)
    for constant in self.constants:
      constant.Stylize(stylizer)
    for imported_module in self.imports:
      imported_module.Stylize(stylizer)
  def Dump(self, f):
    pickle.dump(self, f, 2)
  @classmethod
  def Load(cls, f):
    result = pickle.load(f)
    assert isinstance(result, Module)
    return result
def IsBoolKind(kind):
  return kind.spec == BOOL.spec
def IsFloatKind(kind):
  return kind.spec == FLOAT.spec
def IsDoubleKind(kind):
  return kind.spec == DOUBLE.spec
def IsIntegralKind(kind):
  return (kind.spec == BOOL.spec or kind.spec == INT8.spec
          or kind.spec == INT16.spec or kind.spec == INT32.spec
          or kind.spec == INT64.spec or kind.spec == UINT8.spec
          or kind.spec == UINT16.spec or kind.spec == UINT32.spec
          or kind.spec == UINT64.spec)
def IsStringKind(kind):
  return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec
def IsGenericHandleKind(kind):
  return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec
def IsDataPipeConsumerKind(kind):
  return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec
def IsDataPipeProducerKind(kind):
  return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec
def IsMessagePipeKind(kind):
  return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec
def IsSharedBufferKind(kind):
  return (kind.spec == SHAREDBUFFER.spec
          or kind.spec == NULLABLE_SHAREDBUFFER.spec)
def IsPlatformHandleKind(kind):
  return (kind.spec == PLATFORMHANDLE.spec
          or kind.spec == NULLABLE_PLATFORMHANDLE.spec)
def IsStructKind(kind):
  return isinstance(kind, Struct)
def IsUnionKind(kind):
  return isinstance(kind, Union)
def IsArrayKind(kind):
  return isinstance(kind, Array)
def IsInterfaceKind(kind):
  return isinstance(kind, Interface)
def IsAssociatedInterfaceKind(kind):
  return isinstance(kind, AssociatedInterface)
def IsInterfaceRequestKind(kind):
  return isinstance(kind, InterfaceRequest)
def IsAssociatedInterfaceRequestKind(kind):
  return isinstance(kind, AssociatedInterfaceRequest)
def IsPendingRemoteKind(kind):
  return isinstance(kind, PendingRemote)
def IsPendingReceiverKind(kind):
  return isinstance(kind, PendingReceiver)
def IsPendingAssociatedRemoteKind(kind):
  return isinstance(kind, PendingAssociatedRemote)
def IsPendingAssociatedReceiverKind(kind):
  return isinstance(kind, PendingAssociatedReceiver)
def IsEnumKind(kind):
  return isinstance(kind, Enum)
def IsReferenceKind(kind):
  return isinstance(kind, ReferenceKind)
def IsNullableKind(kind):
  return IsReferenceKind(kind) and kind.is_nullable
def IsMapKind(kind):
  return isinstance(kind, Map)
def IsObjectKind(kind):
  return IsPointerKind(kind) or IsUnionKind(kind)
def IsPointerKind(kind):
  return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind)
          or IsMapKind(kind))
# Please note that it doesn't include any interface kind.
def IsAnyHandleKind(kind):
  return (IsGenericHandleKind(kind) or IsDataPipeConsumerKind(kind)
          or IsDataPipeProducerKind(kind) or IsMessagePipeKind(kind)
          or IsSharedBufferKind(kind) or IsPlatformHandleKind(kind))
def IsAnyInterfaceKind(kind):
  return (IsInterfaceKind(kind) or IsInterfaceRequestKind(kind)
          or IsAssociatedKind(kind) or IsPendingRemoteKind(kind)
          or IsPendingReceiverKind(kind))
def IsAnyHandleOrInterfaceKind(kind):
  return IsAnyHandleKind(kind) or IsAnyInterfaceKind(kind)
def IsAssociatedKind(kind):
  return (IsAssociatedInterfaceKind(kind)
          or IsAssociatedInterfaceRequestKind(kind)
          or IsPendingAssociatedRemoteKind(kind)
          or IsPendingAssociatedReceiverKind(kind))
def HasCallbacks(interface):
  for method in interface.methods:
    if method.response_parameters != None:
      return True
  return False
# Finds out whether an interface passes associated interfaces and associated
# interface requests.
def PassesAssociatedKinds(interface):
  visited_kinds = set()
  for method in interface.methods:
    if MethodPassesAssociatedKinds(method, visited_kinds):
      return True
  return False
def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None):
  def _HasProperty(kind):
    if kind in visited_kinds:
      # No need to examine the kind again.
      return False
    visited_kinds.add(kind)
    if predicate(kind):
      return True
    if IsArrayKind(kind):
      return _HasProperty(kind.kind)
    if IsStructKind(kind) or IsUnionKind(kind):
      for field in kind.fields:
        if _HasProperty(field.kind):
          return True
    if IsMapKind(kind):
      if _HasProperty(kind.key_kind) or _HasProperty(kind.value_kind):
        return True
    return False
  if visited_kinds is None:
    visited_kinds = set()
  for param in method.parameters:
    if _HasProperty(param.kind):
      return True
  if method.response_parameters != None:
    for param in method.response_parameters:
      if _HasProperty(param.kind):
        return True
  return False
# Finds out whether a method passes associated interfaces and associated
# interface requests.
def MethodPassesAssociatedKinds(method, visited_kinds=None):
  return _AnyMethodParameterRecursive(
      method, IsAssociatedKind, visited_kinds=visited_kinds)
# Determines whether a method passes interfaces.
def MethodPassesInterfaces(method):
  return _AnyMethodParameterRecursive(method, IsInterfaceKind)
def HasSyncMethods(interface):
  for method in interface.methods:
    if method.sync:
      return True
  return False
def ContainsHandlesOrInterfaces(kind):
  """Check if the kind contains any handles.
  This check is recursive so it checks all struct fields, containers elements,
  etc.
  Args:
    struct: {Kind} The kind to check.
  Returns:
    {bool}: True if the kind contains handles.
  """
  # We remember the types we already checked to avoid infinite recursion when
  # checking recursive (or mutually recursive) types:
  checked = set()
  def Check(kind):
    if kind.spec in checked:
      return False
    checked.add(kind.spec)
    if IsStructKind(kind):
      return any(Check(field.kind) for field in kind.fields)
    elif IsUnionKind(kind):
      return any(Check(field.kind) for field in kind.fields)
    elif IsAnyHandleKind(kind):
      return True
    elif IsAnyInterfaceKind(kind):
      return True
    elif IsArrayKind(kind):
      return Check(kind.kind)
    elif IsMapKind(kind):
      return Check(kind.key_kind) or Check(kind.value_kind)
    else:
      return False
  return Check(kind)
def ContainsNativeTypes(kind):
  """Check if the kind contains any native type (struct or enum).
  This check is recursive so it checks all struct fields, scoped interface
  enums, etc.
  Args:
    struct: {Kind} The kind to check.
  Returns:
    {bool}: True if the kind contains native types.
  """
  # We remember the types we already checked to avoid infinite recursion when
  # checking recursive (or mutually recursive) types:
  checked = set()
  def Check(kind):
    if kind.spec in checked:
      return False
    checked.add(kind.spec)
    if IsEnumKind(kind):
      return kind.native_only
    elif IsStructKind(kind):
      if kind.native_only:
        return True
      if any(enum.native_only for enum in kind.enums):
        return True
      return any(Check(field.kind) for field in kind.fields)
    elif IsUnionKind(kind):
      return any(Check(field.kind) for field in kind.fields)
    elif IsInterfaceKind(kind):
      return any(enum.native_only for enum in kind.enums)
    elif IsArrayKind(kind):
      return Check(kind.kind)
    elif IsMapKind(kind):
      return Check(kind.key_kind) or Check(kind.value_kind)
    else:
      return False
  return Check(kind)

@sailfish009
Copy link
Author

#!/usr/bin/env python
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Embeds Chrome user data files in C++ code."""

import base64
import optparse
import os
# import StringIO
import sys
import zipfile

import cpp_source

# try:
#     from StringIO import StringIO
# except ImportError:
#     from io import StringIO
from io import BytesIO


def main():
  parser = optparse.OptionParser()
  parser.add_option(
      '', '--directory', type='string', default='.',
      help='Path to directory where the cc/h  file should be created')
  options, args = parser.parse_args()

  global_string_map = {}
  # string_buffer = StringIO.StringIO()
  # string_buffer = StringIO()
  string_buffer = BytesIO()

  zipper = zipfile.ZipFile(string_buffer, 'w')
  for f in args:
    zipper.write(f, os.path.basename(f), zipfile.ZIP_STORED)
  zipper.close()
  global_string_map['kAutomationExtension'] = base64.b64encode(
      string_buffer.getvalue())
  string_buffer.close()

  cpp_source.WriteSource('embedded_automation_extension',
                         'chrome/test/chromedriver/chrome',
                         options.directory, global_string_map)


if __name__ == '__main__':
  sys.exit(main())

@sailfish009
Copy link
Author

# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Writes C++ header/cc source files for embedding resources into C++."""
import datetime
import os
import sys
def WriteSource(base_name,
                dir_from_src,
                output_dir,
                global_string_map):
  """Writes C++ header/cc source files for the given map of string variables.
  Args:
      base_name: The basename of the file, without the extension.
      dir_from_src: Path from src to the directory that will contain the file,
          using forward slashes.
      output_dir: Directory to output the sources to.
      global_string_map: Map of variable names to their string values. These
          variables will be available as globals.
  """
  copyright_header_template = (
      '// Copyright 2018 The Chromium Authors. All rights reserved.\n'
      '// Use of this source code is governed by a BSD-style license '
      'that can be\n'
      '// found in the LICENSE file.\n\n'
      '// This file was generated by running:\n'
      '//     %s')
  copyright_header = copyright_header_template % (' '.join(sys.argv))
  # Write header file.
  externs = []
  for name in global_string_map.keys():
    externs += ['extern const char %s[];' % name]
  temp = '_'.join(dir_from_src.split('/') + [base_name])
  define = temp.upper() + '_H_'
  header = '\n'.join([
      copyright_header,
      '',
      '#ifndef ' + define,
      '#define ' + define,
      '',
      '\n'.join(externs),
      '',
      '#endif  // ' + define])
  header += '\n'
  with open(os.path.join(output_dir, base_name + '.h'), 'w') as f:
    f.write(header)
  # Write cc file.
  def EscapeLine(line):
    return line.replace('\\', '\\\\').replace('"', '\\"')
  definitions = []
  for name, contents in global_string_map.items():
    lines = []
    if '\n' not in contents:
      lines = ['    "%s"' % EscapeLine(contents)]
    else:
      for line in contents.split('\n'):
        lines += ['    "%s\\n"' % EscapeLine(line)]
    definitions += ['const char %s[] =\n%s;' % (name, '\n'.join(lines))]
  cc = '\n'.join([
      copyright_header,
      '',
      '#include "%s"' % (dir_from_src + '/' + base_name + '.h'),
      '',
      '\n'.join(definitions)])
  cc += '\n'
  with open(os.path.join(output_dir, base_name + '.cc'), 'w') as f:
    f.write(cc)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment