#!/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)