You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.5 KiB

  1. #
  2. # This file is part of usb-protocol.
  3. #
  4. from . import ConstructEmitter
  5. from collections import defaultdict
  6. class ComplexDescriptorEmitter(ConstructEmitter):
  7. """ Base class for emitting complex descriptors, which contain nested subordinates. """
  8. # Base classes should override this.
  9. DESCRIPTOR_FORMAT = None
  10. def __init__(self, collection=None):
  11. """
  12. Parameters:
  13. collection -- If this descriptor belongs to a collection, it should be
  14. provided here. Using a collection object allows e.g. automatic
  15. assignment of string descriptor indices.
  16. """
  17. self._collection = collection
  18. # Always create a basic ConstructEmitter from the given format.
  19. super().__init__(self.DESCRIPTOR_FORMAT)
  20. # Store a list of subordinate descriptors, and a count of
  21. # subordinate descriptor types.
  22. self._subordinates = []
  23. self._type_counts = {}
  24. def add_subordinate_descriptor(self, subordinate):
  25. """ Adds a subordinate descriptor to the relevant descriptor.
  26. Parameter:
  27. subordinate -- The subordinate descriptor to add; can be an emitter,
  28. or a bytes-like object.
  29. """
  30. if hasattr(subordinate, 'emit'):
  31. subordinate = subordinate.emit()
  32. else:
  33. subordinate = bytes(subordinate)
  34. # The second byte of a given descriptor is always its type number.
  35. # Count this descriptor type...
  36. subordinate_type = subordinate[1]
  37. try:
  38. self._type_counts[subordinate_type] += 1
  39. except KeyError:
  40. self._type_counts[subordinate_type] = 1
  41. # ... and add the relevant bytes to our list of subordinates.
  42. self._subordinates.append(subordinate)
  43. def _pre_emit(self):
  44. """ Performs any manipulations needed on this object before emission. """
  45. pass
  46. def emit(self, include_subordinates=True):
  47. """ Emit our descriptor.
  48. Parameters:
  49. include_subordinates -- If true or not provided, any subordinate descriptors will be included.
  50. """
  51. # Run any pre-emit hook code before we perform our emission...
  52. self._pre_emit()
  53. # Start with our core descriptor...
  54. result = bytearray()
  55. result.extend(super().emit())
  56. # ... and if descired, add our subordinates...
  57. for sub in self._subordinates:
  58. result.extend(sub)
  59. return bytes(result)