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 9Takes in structures.txt and commands.txt as outputted by extract_*.sh, then 10passes files as input to structure_generator and command_generator objects. 11""" 12 13from __future__ import print_function 14 15import os 16import re 17import subprocess 18import sys 19 20import command_generator 21import extract_structures 22import structure_generator 23 24TMP_DIR = '/tmp' 25TYPES_FILE = 'tpm_types.h' 26 27 28class GeneratorException(Exception): 29 """Generator error, a convenience class.""" 30 pass 31 32usage = (''' 33usage: %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 47def _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 76def _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 116def 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 168if __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