#!/usr/bin/env python """This module is mostly a playground for descriptor-parsing code. Copyright (c) 2005 Charles Lepple You may distribute this file under the terms of either the GNU General Public License or the Artistic License.""" __author__ = "Charles Lepple " __date__ = "20 February 2005" import os, sys, re def extract_bytes_libhid(f): """Extract an array of bytes from a hex dump generated by libhid. The returned list contains unsigned integers corresponding to the bytes.""" descriptor_seen = 0 descriptor_text = [] for line in f: if descriptor_seen: if 'parsing the HID tree' in line: descriptor_seen = 0 else: # Chop off "TRACE: hid_prepare_parser(): 0xZZZ": descriptor_text += line.split()[3:] else: if 'raw report descriptor' in line: descriptor_seen = 1 # Map each string element into an integer: return [int(var, 16) for var in descriptor_text] def extract_bytes(f): """Extract an array of descriptor bytes from an assembly file, or just a list of hex bytes. ('ret' statements, colons, comments and labels are removed.) The returned list contains unsigned integers corresponding to the bytes.""" descriptor_text = [] re_ret = re.compile(r'ret[a-z]+', re.IGNORECASE) # Labels begin in the first column, and optionally have a colon afterwards: re_label = re.compile(r'^[a-z0-9_]+:?', re.IGNORECASE) re_comment = re.compile(r';.*$') for line in f: line = re_comment.sub('', line) line = re_label.sub('', line) line = re_ret.sub('', line) # print "Line: " + line descriptor_text += line.split() # Map each string element into an integer: return [int(var, 16) for var in descriptor_text] # string.join([ "%02x" % var for var in descriptor_bytes]) def parse_tag(desc, index = 0): """Examine and print information about the item at desc[index]. Returns the length of the item (including the tag), which can be used to advance index to the next item in the descriptor. Currently, only short tags are handled. bSize: 0 = 0 bytes 1 = 1 byte 2 = 2 bytes 3 = 4 bytes""" bSize = (1 << (desc[index] & 0x3)) / 2 bType = (desc[index] >> 2) & 0x3 bTag = (desc[index] >> 4) & 0xF print "[0x%04x]" % index, data = 0 for byte in range(bSize+1): print "0x%02x" % desc[index+byte], if byte > 0: data = desc[index+byte] << (8*(byte-1)) | data # FIXME: sign-extend data if necessary if bSize > 0: print "(value: 0x%x / %d)" % (data, data), print print " bSize = %d byte(s)" % bSize print " bType = 0x%02x (%s)" \ % (bType, ('Main', 'Global', 'Local', 'Reserved')[bType]) print " bTag = 0x%02x" % bTag, if bType == 0: # Main print "(%s)" % ('Input', 'Output', 'Collection', 'Feature', \ 'End Collection')[bTag-8], if bTag == 0x0a: # Collection type if data <= 6: print "(%s)" % ('Physical', 'Application', 'Logical', 'Report', \ 'Named Array', 'Usage Switch', 'Usage Modifier')[data], else: print "(Vendor defined: 0x%x)" % data, elif bType == 1: # Global print "(%s)" % ('Usage page', 'Logical Minimum', 'Logical Maximum', \ 'Physical Minimum', 'Physical Maximum', 'Unit Exponent', 'Unit', \ 'Report Size', 'Report ID', 'Report Count', 'Push', 'Pop')[bTag], elif bType == 2: # Local print "(%s)" % ('Usage', 'Usage Minimum', 'Usage Maximum', \ 'Designator Index', 'Designator Minimum', 'Designator Maximum', \ 'String Index', 'String Minimum', 'String Maximum', \ 'Delimiter')[bTag], print print return bSize + 1 def tokenize_descriptor(desc): byte_index = 0; while byte_index < len(desc): byte_index += parse_tag(desc, byte_index) def main(): if(len(sys.argv) > 1): fname = sys.argv[1] else: fname = '../ref/test_libhid_output/MGE_Pulsar_Evolution_500' f = open(fname, 'r') # desc_bytes = extract_bytes(f) # - or - desc_bytes = extract_bytes_libhid(f) f.close() tokenize_descriptor(desc_bytes) print "done" if __name__ == '__main__': main()