#!/usr/bin/python # Copyright 2015 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """A Main file for command and structure generators. Takes in structures.txt and commands.txt as outputted by extract_*.sh, then passes files as input to structure_generator and command_generator objects. """ from __future__ import print_function import os import re import subprocess import sys import command_generator import extract_structures import structure_generator TMP_DIR = '/tmp' TYPES_FILE = 'tpm_types.h' class GeneratorException(Exception): """Generator error, a convenience class.""" pass usage = (''' usage: %s [-h|[tar_archive|part2.html part3.html]] -h show this message and exit tar_archive - a tarred archive consisting of at least two HTML files, parts 2 and 3 of the TCG TPM2 library specification. File names must include 'part2' and 'part3'. The extracted files could be found in %s after this script finished processing. part{23}.html - parts 2 and 3 of the TCG TPM2 library specification in html format. ''' % (os.path.basename(__file__), TMP_DIR)) def _TryUntarring(tar_file_name): """Try retrieving parts 2 and 3 from the passed in archive. Args: tar_file_name: a string, file name of the tar file which is supposed to contain parts 2 and 3 of the specification. Returns: A tuple of strings, two file names in case they were found in the archive and successfully extracted. """ part2 = None part3 = None tar_extract_base = ['tar', '-C', TMP_DIR, '-f'] components = subprocess.check_output(['tar', 'tf', tar_file_name], stderr=subprocess.STDOUT) for name in components.splitlines(): if re.search('part2', name, re.IGNORECASE): subprocess.check_output(tar_extract_base + [tar_file_name, '-x', name], stderr=subprocess.STDOUT) part2 = os.path.join(TMP_DIR, name) if re.search('part3', name, re.IGNORECASE): subprocess.check_output(tar_extract_base + [tar_file_name, '-x', name], stderr=subprocess.STDOUT) part3 = os.path.join(TMP_DIR, name) return part2, part3 def _ParseCommandLine(args): """Process command line and determine input file names. Input files could be supplied by two different ways - as part of a tar archive (in which case only one command line parameter is expected), or as two separate file names, one for part 2 and one for part 3. If a single command line parameter is supplied, and it is not '-h', tar extraction is attempted and if successful, two separate files are created in TMP_DIR. Args: args: a list of string, command line parameters retrieved from sys.argv Returns: A tuple of two strings, two html files to process, part 2 and part 3 of the spec. Raises: GeneratorException: on input errors. """ if len(args) == 1: if args[0] == '-h': print(usage) sys.exit(0) try: structures_file, commands_file = _TryUntarring(args[0]) except subprocess.CalledProcessError as e: raise GeneratorException("command '%s' failed:\n%s\n%s" % (' '.join(e.cmd), e.output, usage)) elif len(args) == 2: structures_file = args[0] commands_file = args[1] else: raise GeneratorException(usage) return structures_file, commands_file def main(argv): """A Main function. TPM structures and commands files are parsed and C header and C implementation files are generated. Args: argv: a list of strings, command line parameters. """ structures_file, commands_file = _ParseCommandLine(argv[1:]) print('parse part2...') html_parser = extract_structures.SpecParser() tpm_table = html_parser.GetTable() # The tables included in the below tuple are defined twice in the # specification, once in part 2 and once in part 4. Let's ignore the part 2 # definitions to avoid collisions. tpm_table.SetSkipTables((2, 6, 9, 10, 13)) html_parser.feed(open(structures_file).read()) html_parser.close() tpm_defines = tpm_table.GetHFile() print('parse part3...') tpm_table.SetSkipTables(()) html_parser.feed(open(commands_file).read()) html_parser.close() # Move to the root directory, which is one level above the script. os.chdir(os.path.join(os.path.dirname(argv[0]), '..')) # Save types include file. print('generate output...') types_file = open(TYPES_FILE, 'w') guard_name = TYPES_FILE.upper() guard_name = guard_name.replace('.', '_') guard_name = 'TPM2_' + guard_name + '_' types_file.write((structure_generator.COPYRIGHT_HEADER + structure_generator.HEADER_FILE_GUARD_HEADER) % {'name': guard_name}) types_file.write(tpm_defines) types_file.write((structure_generator.HEADER_FILE_GUARD_FOOTER) % {'name': guard_name}) types_file.close() typemap = tpm_table.GetTypeMap() structure_generator.GenerateHeader(typemap) structure_generator.GenerateImplementation(typemap) commands = tpm_table.GetCommandList() command_generator.GenerateHeader(commands) command_generator.GenerateImplementation(commands, typemap) print('Processed %d TPM types.' % len(typemap)) print('Processed %d commands.' % len(commands)) if __name__ == '__main__': try: main(sys.argv) except GeneratorException as e: if e.message: print(e, file=sys.stderr) sys.exit(1)