def outputEnumerations(enumerationSpec, options, pyFile): """ Outputs the enmerations into a Python file. Given the portion of the specification definining all the enumerations, output options and an output file, write out all the necessary enumerations definitions and return information on their values for use in future parsing. Args: enumerationSpec (dict): The portion of the specification covering enumerations. options (dict): A dictionary of options to modify output. pyFile (file): A file-like object to which to save the struct code. Returns: A dictionary of constants to be pulled into the environment for parsing structure definitions. """ assert isinstance(enumerationSpec, list) assert isinstance(options, dict) assert hasattr(pyFile, 'write') newLocals = [] for enumerationName, enumeration in enumerationSpec: writeOut(pyFile, '##') if 'title' in enumeration: writeOut(pyFile, enumeration['title'], '# ') else: writeOut(pyFile, enumerationName, '# ') if 'description' in enumeration: writeOut(pyFile, '#') writeOutBlock(pyFile, enumeration['description'], '# ') writeOut(pyFile, '#') varType = enumeration.get('type', None) value = None for optionName, option in enumeration['options'].items(): line = [] if 'description' in option: writeOut(pyFile, ' #') writeOutBlock(pyFile, option['description'], ' # ') writeOut(pyFile, ' #') if 'value' in option: varType = option.get('type', varType) if isStringType(varType): varType = 'str' elif isFloatType(varType): varType = 'float' elif isBooleanType(varType): varType = 'bool' else: varType = 'int' if varType is None: if options['verbose']: print('Guessing enumeration type based on value.') varType = str(type(option['value']))[7:-2] if varType == 'str' and (value.startswith('(') and value.endswith(')')): varType = 'int' if options['verbose']: print('Second-guessing enumeration type.') value = option['value'] else: if varType is None: varType = 'int' if options['verbose']: print('Defaulting enumeration type to int.') if not isinstance(value, int): value = 0 else: value += 1 if varType == str: delim = '"' else: delim = '' line.append(optionName) line.append(' = {}{}{}'.format(delim, value, delim)) if 'title' in option: line.append(' # {}'.format(option['title'])) writeOut(pyFile, ''.join(line)) newLocals.append((optionName, value)) writeOut(pyFile, '') writeOut(pyFile, '') return newLocals
def outputPython(specification, options, pyFile): """ Outputs Python struct file. Given the specification construct a valid Python struct file that describes all the binary packets. Args: specification (dict): The specification object. options (dict): A dictionary of options to modify output. pyFile (file): A file-like object to which to save the struct code. """ assert isinstance(specification, dict) assert isinstance(options, dict) assert hasattr(pyFile, 'write') packetLengths = {} writeOut(pyFile, '#!/usr/bin/env python') writeOut(pyFile, '# -*- coding: utf-8 -*-') writeOut(pyFile, '"""') writeOut(pyFile, specification['title']) if 'description' in specification: writeOut(pyFile, '') writeOutBlock(pyFile, specification['description']) for tag in ('version', 'date', 'author', 'documentation', 'metadata'): if tag in specification: writeOut(pyFile, '') writeOut(pyFile, '{}: {}'.format(tag.title(), specification[tag])) writeOut(pyFile, '"""') writeOut(pyFile, '') writeOut(pyFile, 'from struct import calcsize, pack, unpack_from') writeOut(pyFile, 'from zope.interface import directlyProvides, Interface') writeOut(pyFile, '') writeOut(pyFile, '') prefix = ' ' # Create interfaces for testing and documenting extensionlessName = options['pyFilename'].split('.')[0] extensionlessName = extensionlessName[0].upper() + extensionlessName[1:] writeOut(pyFile, 'class I{}Length(Interface):'.format(extensionlessName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'A binary packet length calculator', prefix) writeOut(pyFile, '') writeOut(pyFile, 'Interface for an entity that returns the length ' \ + 'of a binary packet buffer.', prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'def __call__():', prefix) writeOut(pyFile, '"""Returns the length of the object in bytes."""', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, '') writeOut(pyFile, 'class I{}Packer(Interface):'.format(extensionlessName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'A binary data packer', prefix) writeOut(pyFile, '') writeOut(pyFile, 'Interface for an entity that packs binary data.', prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'def __call__(packet):', prefix) writeOut(pyFile, '"""Packs a packet dict into a string."""', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, '') writeOut(pyFile, 'class I{}Unpacker(Interface):'.format(extensionlessName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'A binary data unpacker', prefix) writeOut(pyFile, '') writeOut(pyFile, 'Interface for an entity that unpacks binary data.', prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'def __call__(buffer):', prefix) writeOut(pyFile, '"""Unpacks a binary string into a dict."""', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, '') # Parse the enumerations newLocals = outputEnumerations(specification['enums'].items(), options, pyFile) # The following is a little ugly but places the enumerations # in the current namespace so that they may be referenced # when evaluating formats. for optionName, value in newLocals: if varNameRE.match(optionName) and exprRE.match(str(value)): exec '{} = {}'.format(optionName, value) # Parse the structure for packetName, packet in specification['packets'].items(): structDefList = [] structAccretions = { 'formatList': [], 'countList': [], 'varList': [], 'bitFields': [], 'titles': [], 'descriptions': [] } bitFieldCount = populateWorkLists( packet, specification, structDefList, structAccretions ) # Create the get length function writeOut(pyFile, 'def get_{}_len():'.format(packetName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, "Calculates the size of {}.".format(packetName), prefix) writeOut(pyFile, '') writeOut(pyFile, "Calculates the total size of the {} structure".format( packetName), prefix) writeOut(pyFile, "(including any internal substructures).", prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'The size of {}.'.format(packetName), 2 * prefix) # The following section determines how many bytes a packet # consists of so we can make good doctests. To do so it # evaluates the expressions used for the format descriptions. packetLen = 0 try: for structDef in structDefList: if structDef['type'] == 'segment': assert structFmtRE.match(structDef['fmt']) packetLen += calcsize(eval(structDef['fmt'])) elif structDef['type'] == 'substructure': packetLen += packetLengths[structDef['itemType']] packetLengths[packetName] = packetLen writeOut(pyFile, '') writeOut(pyFile, 'Examples:', prefix) writeOut(pyFile, '>>> get_{}_len()'.format(packetName), prefix * 2) writeOut(pyFile, '{}'.format(packetLen), prefix * 2) except KeyError: # If we can't evaluate it don't bother with a doctest # for this one. This can happen if dependencies get # defined after they're used. pass writeOut(pyFile, '"""', prefix) # Create the function itself. formatStrList = [structDef['fmt'] for structDef in structDefList if structDef['type'] == 'segment'] if not formatStrList: writeOut(pyFile, 'totalSize = 0', prefix) else: writeOut(pyFile, 'totalSize = calcsize({})'.format( ') + calcsize('.join(formatStrList)), prefix) substructureList = [structDef['itemType'] for structDef in structDefList if structDef['type'] == 'substructure'] for substruct in substructureList: writeOut(pyFile, 'totalSize += get_{}_len()'.format(substruct), prefix) writeOut(pyFile, 'return totalSize', prefix) writeOut(pyFile, 'directlyProvides(get_{}_len, I{}Length)'.format( packetName, extensionlessName)) writeOut(pyFile, '') writeOut(pyFile, '') # Create the pack function writeOut(pyFile, 'def pack_{}(packet):'.format(packetName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, "Packs a {} packet.".format(packetName), prefix) if 'description' in packet: writeOut(pyFile, '') writeOutBlock(pyFile, packet['description'], prefix) writeOut(pyFile, '') writeOut(pyFile, 'Args:', prefix) writeOut(pyFile, 'packet (dict): A dictionary of data to be packed.', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'A binary string containing the packed data.', 2 * prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'assert isinstance(packet, dict)', prefix) writeOut(pyFile, 'outList = []', prefix) for structDef in structDefList: if structDef['type'] == 'segment': for fragNum, (bitFieldName, bitFieldNum, bitFieldSize, bitFieldLabel ) in enumerate(reversed(structDef['bitFields'])): if fragNum == 0: writeOut(pyFile, 'bitField{} = {}'.format( bitFieldNum, bitFieldName), prefix) else: writeOut(pyFile, 'bitField{} <<= {}'.format( bitFieldNum, bitFieldSize), prefix) writeOut(pyFile, 'bitField{} |= {}'.format( bitFieldNum, bitFieldName), prefix) writeOut(pyFile, 'outList.append(pack({}, {}))'.format( structDef['fmt'], structDef['vars'][1:-1]), prefix) elif structDef['type'] == 'substructure': writeOut(pyFile, 'outList.append(pack_{}(packet["{}"]))'.format( structDef['itemType'], structDef['itemName']), prefix) writeOut(pyFile, 'return "".join(outList)', prefix) writeOut(pyFile, 'directlyProvides(pack_{}, I{}Packer)'.format( packetName, extensionlessName)) writeOut(pyFile, '') writeOut(pyFile, '') # Create the unpack function writeOut(pyFile, 'def unpack_{}(rawData):'.format(packetName)) writeOut(pyFile, '"""', prefix) if 'title' in packet: writeOut(pyFile, packet['title'], prefix) else: writeOut(pyFile, packetName, prefix) if 'description' in packet: writeOut(pyFile, '') writeOutBlock(pyFile, packet['description'], prefix) writeOut(pyFile, '') writeOut(pyFile, 'Args:', prefix) writeOut(pyFile, 'rawData (str): The raw binary data to be unpacked.', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'A dictionary of the unpacked data.', 2 * prefix) # Write out the next bit to a temporary buffer. outBufStr = StringIO() writeOut(outBufStr, '"""', prefix) writeOut(outBufStr, 'assert isinstance(rawData, str)', prefix) writeOut(outBufStr, 'packet = {}', prefix) writeOut(outBufStr, 'position = 0', prefix) for structDef in structDefList: line = [] if structDef['type'] == 'segment': line.append('segmentFmt = {}{}'.format(structDef['fmt'], linesep)) line.append('{}segmentLen = calcsize(segmentFmt){}'.format(prefix, linesep)) line.append('{}{} = unpack_from(segmentFmt, rawData, position){}'.format( prefix, structDef['vars'], linesep)) line.append('{}position += segmentLen{}'.format(prefix, linesep)) for fragNum, (bitFieldName, bitFieldNum, bitFieldSize, bitFieldLabel) in enumerate(structDef['bitFields']): bitFieldMask = hex(int(pow(2, bitFieldSize)) - 1) if isFloatType(bitFieldLabel): bitFieldType = 'float' elif isBooleanType(bitFieldLabel): bitFieldType = 'bool' elif isStringType(bitFieldLabel): bitFieldType = 'str' else: bitFieldType = 'int' line.append("{}{} = {}(bitField{} & {}){}".format(prefix, bitFieldName, bitFieldType, bitFieldNum, bitFieldMask, linesep)) if fragNum < len(structDef['bitFields']) - 1: line.append("{}bitField{} >>= {}{}".format(prefix, bitFieldNum, bitFieldSize, linesep)) if line[-1].endswith(linesep): line[-1] = line[-1][:-len(linesep)] elif structDef['type'] == 'substructure': if structDef['description']: writeOut(outBufStr, '') writeOutBlock(outBufStr, structDef['description'], ' # ') line.append("packet['{}'] = unpack_{}(rawData[position:]){}".format( structDef['itemName'], structDef['itemType'], linesep)) line.append("{}position += get_{}_len()".format( prefix, structDef['itemType'])) if structDef['title']: line.append(' # {}'.format(structDef['title'])) if line: writeOut(outBufStr, ''.join(line), prefix) writeOut(outBufStr, 'return packet', prefix) writeOut(outBufStr, 'directlyProvides(unpack_{}, I{}Unpacker)'.format( packetName, extensionlessName)) # Write the temporary buffer to the output file. writeOut(pyFile, outBufStr.getvalue()) outBufStr.close() writeOut(pyFile, '') # Create the validate function writeOut(pyFile, 'def validate_{}(rawData):'.format(packetName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, "Reads and validates a {} packet.".format(packetName), prefix) writeOut(pyFile, '') writeOut(pyFile, "Reads a {} structure from raw binary data".format( packetName), prefix) writeOut(pyFile, "and validates it.", prefix) writeOut(pyFile, '') writeOut(pyFile, 'Args:', prefix) writeOut(pyFile, 'rawData (str): The raw binary data to be unpacked.', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'A structure representing the {} packet.'.format(packetName), 2 * prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'assert isinstance(rawData, str)', prefix) writeOut(pyFile, 'packet = get_{}(rawData)'.format(packetName), prefix) writeOut(pyFile, 'return packet', prefix) writeOut(pyFile, '') writeOut(pyFile, '') writeOut(pyFile, 'if __name__ == "__main__":') writeOut(pyFile, 'from zope.interface.verify import verifyObject', prefix) writeOut(pyFile, 'import doctest', prefix) writeOut(pyFile, 'doctest.testmod()', prefix)
def outputPython(specification, options, pyFile): """ Outputs Python struct file. Given the specification construct a valid Python struct file that describes all the binary packets. Args: specification (dict): The specification object. options (dict): A dictionary of options to modify output. pyFile (file): A file-like object to which to save the struct code. """ assert isinstance(specification, dict) assert isinstance(options, dict) assert hasattr(pyFile, 'write') packetLengths = {} writeOut(pyFile, '#!/usr/bin/env python') writeOut(pyFile, '# -*- coding: utf-8 -*-') writeOut(pyFile, '"""') writeOut(pyFile, specification['title']) if 'description' in specification: writeOut(pyFile, '') writeOutBlock(pyFile, specification['description']) for tag in ('version', 'date', 'author', 'documentation', 'metadata'): if tag in specification: writeOut(pyFile, '') writeOut(pyFile, '{}: {}'.format(tag.title(), specification[tag])) writeOut(pyFile, '"""') writeOut(pyFile, '') writeOut(pyFile, 'from struct import calcsize, pack, unpack_from') writeOut(pyFile, 'from zope.interface import directlyProvides, Interface') writeOut(pyFile, '') writeOut(pyFile, '') prefix = ' ' # Create interfaces for testing and documenting extensionlessName = options['pyFilename'].split('.')[0] extensionlessName = extensionlessName[0].upper() + extensionlessName[1:] writeOut(pyFile, 'class I{}Length(Interface):'.format(extensionlessName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'A binary packet length calculator', prefix) writeOut(pyFile, '') writeOut(pyFile, 'Interface for an entity that returns the length ' \ + 'of a binary packet buffer.', prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'def __call__():', prefix) writeOut(pyFile, '"""Returns the length of the object in bytes."""', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, '') writeOut(pyFile, 'class I{}Packer(Interface):'.format(extensionlessName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'A binary data packer', prefix) writeOut(pyFile, '') writeOut(pyFile, 'Interface for an entity that packs binary data.', prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'def __call__(packet):', prefix) writeOut(pyFile, '"""Packs a packet dict into a string."""', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, '') writeOut(pyFile, 'class I{}Unpacker(Interface):'.format(extensionlessName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'A binary data unpacker', prefix) writeOut(pyFile, '') writeOut(pyFile, 'Interface for an entity that unpacks binary data.', prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'def __call__(buffer):', prefix) writeOut(pyFile, '"""Unpacks a binary string into a dict."""', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, '') # Parse the enumerations newLocals = outputEnumerations(specification['enums'].items(), options, pyFile) # The following is a little ugly but places the enumerations # in the current namespace so that they may be referenced # when evaluating formats. for optionName, value in newLocals: if varNameRE.match(optionName) and exprRE.match(str(value)): exec '{} = {}'.format(optionName, value) # Parse the structure for packetName, packet in specification['packets'].items(): structDefList = [] structAccretions = { 'formatList': [], 'countList': [], 'varList': [], 'bitFields': [], 'titles': [], 'descriptions': [] } bitFieldCount = populateWorkLists(packet, specification, structDefList, structAccretions) # Create the get length function writeOut(pyFile, 'def get_{}_len():'.format(packetName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, "Calculates the size of {}.".format(packetName), prefix) writeOut(pyFile, '') writeOut( pyFile, "Calculates the total size of the {} structure".format(packetName), prefix) writeOut(pyFile, "(including any internal substructures).", prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'The size of {}.'.format(packetName), 2 * prefix) # The following section determines how many bytes a packet # consists of so we can make good doctests. To do so it # evaluates the expressions used for the format descriptions. packetLen = 0 try: for structDef in structDefList: if structDef['type'] == 'segment': assert structFmtRE.match(structDef['fmt']) packetLen += calcsize(eval(structDef['fmt'])) elif structDef['type'] == 'substructure': packetLen += packetLengths[structDef['itemType']] packetLengths[packetName] = packetLen writeOut(pyFile, '') writeOut(pyFile, 'Examples:', prefix) writeOut(pyFile, '>>> get_{}_len()'.format(packetName), prefix * 2) writeOut(pyFile, '{}'.format(packetLen), prefix * 2) except KeyError: # If we can't evaluate it don't bother with a doctest # for this one. This can happen if dependencies get # defined after they're used. pass writeOut(pyFile, '"""', prefix) # Create the function itself. formatStrList = [ structDef['fmt'] for structDef in structDefList if structDef['type'] == 'segment' ] if not formatStrList: writeOut(pyFile, 'totalSize = 0', prefix) else: writeOut( pyFile, 'totalSize = calcsize({})'.format( ') + calcsize('.join(formatStrList)), prefix) substructureList = [ structDef['itemType'] for structDef in structDefList if structDef['type'] == 'substructure' ] for substruct in substructureList: writeOut(pyFile, 'totalSize += get_{}_len()'.format(substruct), prefix) writeOut(pyFile, 'return totalSize', prefix) writeOut( pyFile, 'directlyProvides(get_{}_len, I{}Length)'.format( packetName, extensionlessName)) writeOut(pyFile, '') writeOut(pyFile, '') # Create the pack function writeOut(pyFile, 'def pack_{}(packet):'.format(packetName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, "Packs a {} packet.".format(packetName), prefix) if 'description' in packet: writeOut(pyFile, '') writeOutBlock(pyFile, packet['description'], prefix) writeOut(pyFile, '') writeOut(pyFile, 'Args:', prefix) writeOut(pyFile, 'packet (dict): A dictionary of data to be packed.', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'A binary string containing the packed data.', 2 * prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'assert isinstance(packet, dict)', prefix) writeOut(pyFile, 'outList = []', prefix) for structDef in structDefList: if structDef['type'] == 'segment': for fragNum, (bitFieldName, bitFieldNum, bitFieldSize, bitFieldLabel) in enumerate( reversed(structDef['bitFields'])): if fragNum == 0: writeOut( pyFile, 'bitField{} = {}'.format(bitFieldNum, bitFieldName), prefix) else: writeOut( pyFile, 'bitField{} <<= {}'.format(bitFieldNum, bitFieldSize), prefix) writeOut( pyFile, 'bitField{} |= {}'.format(bitFieldNum, bitFieldName), prefix) writeOut( pyFile, 'outList.append(pack({}, {}))'.format( structDef['fmt'], structDef['vars'][1:-1]), prefix) elif structDef['type'] == 'substructure': writeOut( pyFile, 'outList.append(pack_{}(packet["{}"]))'.format( structDef['itemType'], structDef['itemName']), prefix) writeOut(pyFile, 'return "".join(outList)', prefix) writeOut( pyFile, 'directlyProvides(pack_{}, I{}Packer)'.format( packetName, extensionlessName)) writeOut(pyFile, '') writeOut(pyFile, '') # Create the unpack function writeOut(pyFile, 'def unpack_{}(rawData):'.format(packetName)) writeOut(pyFile, '"""', prefix) if 'title' in packet: writeOut(pyFile, packet['title'], prefix) else: writeOut(pyFile, packetName, prefix) if 'description' in packet: writeOut(pyFile, '') writeOutBlock(pyFile, packet['description'], prefix) writeOut(pyFile, '') writeOut(pyFile, 'Args:', prefix) writeOut(pyFile, 'rawData (str): The raw binary data to be unpacked.', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'A dictionary of the unpacked data.', 2 * prefix) # Write out the next bit to a temporary buffer. outBufStr = StringIO() writeOut(outBufStr, '"""', prefix) writeOut(outBufStr, 'assert isinstance(rawData, str)', prefix) writeOut(outBufStr, 'packet = {}', prefix) writeOut(outBufStr, 'position = 0', prefix) for structDef in structDefList: line = [] if structDef['type'] == 'segment': line.append('segmentFmt = {}{}'.format(structDef['fmt'], linesep)) line.append('{}segmentLen = calcsize(segmentFmt){}'.format( prefix, linesep)) line.append( '{}{} = unpack_from(segmentFmt, rawData, position){}'. format(prefix, structDef['vars'], linesep)) line.append('{}position += segmentLen{}'.format( prefix, linesep)) for fragNum, (bitFieldName, bitFieldNum, bitFieldSize, bitFieldLabel) in enumerate( structDef['bitFields']): bitFieldMask = hex(int(pow(2, bitFieldSize)) - 1) if isFloatType(bitFieldLabel): bitFieldType = 'float' elif isBooleanType(bitFieldLabel): bitFieldType = 'bool' elif isStringType(bitFieldLabel): bitFieldType = 'str' else: bitFieldType = 'int' line.append("{}{} = {}(bitField{} & {}){}".format( prefix, bitFieldName, bitFieldType, bitFieldNum, bitFieldMask, linesep)) if fragNum < len(structDef['bitFields']) - 1: line.append("{}bitField{} >>= {}{}".format( prefix, bitFieldNum, bitFieldSize, linesep)) if line[-1].endswith(linesep): line[-1] = line[-1][:-len(linesep)] elif structDef['type'] == 'substructure': if structDef['description']: writeOut(outBufStr, '') writeOutBlock(outBufStr, structDef['description'], ' # ') line.append( "packet['{}'] = unpack_{}(rawData[position:]){}".format( structDef['itemName'], structDef['itemType'], linesep)) line.append("{}position += get_{}_len()".format( prefix, structDef['itemType'])) if structDef['title']: line.append(' # {}'.format(structDef['title'])) if line: writeOut(outBufStr, ''.join(line), prefix) writeOut(outBufStr, 'return packet', prefix) writeOut( outBufStr, 'directlyProvides(unpack_{}, I{}Unpacker)'.format( packetName, extensionlessName)) # Write the temporary buffer to the output file. writeOut(pyFile, outBufStr.getvalue()) outBufStr.close() writeOut(pyFile, '') # Create the validate function writeOut(pyFile, 'def validate_{}(rawData):'.format(packetName)) writeOut(pyFile, '"""', prefix) writeOut(pyFile, "Reads and validates a {} packet.".format(packetName), prefix) writeOut(pyFile, '') writeOut( pyFile, "Reads a {} structure from raw binary data".format(packetName), prefix) writeOut(pyFile, "and validates it.", prefix) writeOut(pyFile, '') writeOut(pyFile, 'Args:', prefix) writeOut(pyFile, 'rawData (str): The raw binary data to be unpacked.', 2 * prefix) writeOut(pyFile, '') writeOut(pyFile, 'Returns:', prefix) writeOut(pyFile, 'A structure representing the {} packet.'.format(packetName), 2 * prefix) writeOut(pyFile, '"""', prefix) writeOut(pyFile, 'assert isinstance(rawData, str)', prefix) writeOut(pyFile, 'packet = get_{}(rawData)'.format(packetName), prefix) writeOut(pyFile, 'return packet', prefix) writeOut(pyFile, '') writeOut(pyFile, '') writeOut(pyFile, 'if __name__ == "__main__":') writeOut(pyFile, 'from zope.interface.verify import verifyObject', prefix) writeOut(pyFile, 'import doctest', prefix) writeOut(pyFile, 'doctest.testmod()', prefix)