Home | History | Annotate | Download | only in generator
      1 #!/usr/bin/python
      2 
      3 # Copyright 2015 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 """A Main file for command and structure generators.
      8 
      9 Takes in structures.txt and commands.txt as outputted by extract_*.sh, then
     10 passes files as input to structure_generator and command_generator objects.
     11 """
     12 
     13 from __future__ import print_function
     14 
     15 import os
     16 import re
     17 import subprocess
     18 import sys
     19 
     20 import command_generator
     21 import extract_structures
     22 import structure_generator
     23 
     24 TMP_DIR = '/tmp'
     25 TYPES_FILE = 'tpm_types.h'
     26 
     27 
     28 class GeneratorException(Exception):
     29   """Generator error, a convenience class."""
     30   pass
     31 
     32 usage = ('''
     33 usage: %s [-h|[tar_archive|part2.html part3.html]]
     34 
     35     -h  show this message and exit
     36 
     37     tar_archive - a tarred archive consisting of at least two HTML files,
     38                   parts 2 and 3 of the TCG TPM2 library specification. File
     39                   names must include 'part2' and 'part3'. The extracted files
     40                   could be found in %s after this script finished processing.
     41 
     42     part{23}.html - parts 2 and 3 of the TCG TPM2 library specification in
     43                     html format.
     44 ''' % (os.path.basename(__file__), TMP_DIR))
     45 
     46 
     47 def _TryUntarring(tar_file_name):
     48   """Try retrieving parts 2 and 3 from the passed in archive.
     49 
     50   Args:
     51     tar_file_name: a string, file name of the tar file which is supposed to
     52         contain parts 2 and 3 of the specification.
     53 
     54   Returns:
     55     A tuple of strings, two file names in case they were found in the archive
     56     and successfully extracted.
     57   """
     58   part2 = None
     59   part3 = None
     60   tar_extract_base = ['tar', '-C', TMP_DIR, '-f']
     61 
     62   components = subprocess.check_output(['tar', 'tf', tar_file_name],
     63                                        stderr=subprocess.STDOUT)
     64   for name in components.splitlines():
     65     if re.search('part2', name, re.IGNORECASE):
     66       subprocess.check_output(tar_extract_base + [tar_file_name, '-x', name],
     67                               stderr=subprocess.STDOUT)
     68       part2 = os.path.join(TMP_DIR, name)
     69     if re.search('part3', name, re.IGNORECASE):
     70       subprocess.check_output(tar_extract_base + [tar_file_name, '-x', name],
     71                               stderr=subprocess.STDOUT)
     72       part3 = os.path.join(TMP_DIR, name)
     73   return part2, part3
     74 
     75 
     76 def _ParseCommandLine(args):
     77 
     78   """Process command line and determine input file names.
     79 
     80   Input files could be supplied by two different ways - as part of a tar
     81   archive (in which case only one command line parameter is expected), or as
     82   two separate file names, one for part 2 and one for part 3.
     83 
     84   If a single command line parameter is supplied, and it is not '-h', tar
     85   extraction is attempted and if successful, two separate files are created in
     86   TMP_DIR.
     87 
     88   Args:
     89     args: a list of string, command line parameters retrieved from sys.argv
     90 
     91   Returns:
     92     A tuple of two strings, two html files to process, part 2 and part 3 of
     93     the spec.
     94 
     95   Raises:
     96     GeneratorException: on input errors.
     97   """
     98   if len(args) == 1:
     99     if args[0] == '-h':
    100       print(usage)
    101       sys.exit(0)
    102     try:
    103       structures_file, commands_file = _TryUntarring(args[0])
    104     except subprocess.CalledProcessError as e:
    105       raise GeneratorException("command '%s' failed:\n%s\n%s" %
    106                                (' '.join(e.cmd), e.output, usage))
    107 
    108   elif len(args) == 2:
    109     structures_file = args[0]
    110     commands_file = args[1]
    111   else:
    112     raise GeneratorException(usage)
    113   return structures_file, commands_file
    114 
    115 
    116 def main(argv):
    117   """A Main function.
    118 
    119   TPM structures and commands files are parsed and C header and C implementation
    120   files are generated.
    121 
    122   Args:
    123     argv: a list of strings, command line parameters.
    124   """
    125 
    126   structures_file, commands_file = _ParseCommandLine(argv[1:])
    127   print('parse part2...')
    128   html_parser = extract_structures.SpecParser()
    129   tpm_table = html_parser.GetTable()
    130   # The tables included in the below tuple are defined twice in the
    131   # specification, once in part 2 and once in part 4. Let's ignore the part 2
    132   # definitions to avoid collisions.
    133   tpm_table.SetSkipTables((2, 6, 9, 10, 13))
    134   html_parser.feed(open(structures_file).read())
    135   html_parser.close()
    136   tpm_defines = tpm_table.GetHFile()
    137 
    138   print('parse part3...')
    139   tpm_table.SetSkipTables(())
    140   html_parser.feed(open(commands_file).read())
    141   html_parser.close()
    142 
    143   # Move to the root directory, which is one level above the script.
    144   os.chdir(os.path.join(os.path.dirname(argv[0]), '..'))
    145 
    146   # Save types include file.
    147   print('generate output...')
    148   types_file = open(TYPES_FILE, 'w')
    149   guard_name = TYPES_FILE.upper()
    150   guard_name = guard_name.replace('.', '_')
    151   guard_name = 'TPM2_' + guard_name + '_'
    152   types_file.write((structure_generator.COPYRIGHT_HEADER +
    153                     structure_generator.HEADER_FILE_GUARD_HEADER) %
    154                    {'name': guard_name})
    155   types_file.write(tpm_defines)
    156   types_file.write((structure_generator.HEADER_FILE_GUARD_FOOTER) %
    157                    {'name': guard_name})
    158   types_file.close()
    159   typemap = tpm_table.GetTypeMap()
    160   structure_generator.GenerateHeader(typemap)
    161   structure_generator.GenerateImplementation(typemap)
    162   commands = tpm_table.GetCommandList()
    163   command_generator.GenerateHeader(commands)
    164   command_generator.GenerateImplementation(commands, typemap)
    165   print('Processed %d TPM types.' % len(typemap))
    166   print('Processed %d commands.' % len(commands))
    167 
    168 if __name__ == '__main__':
    169   try:
    170     main(sys.argv)
    171   except GeneratorException as e:
    172     if e.message:
    173       print(e, file=sys.stderr)
    174       sys.exit(1)
    175