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.

84 lines
2.4 KiB

  1. #
  2. # This file is part of usb-protocol.
  3. #
  4. from collections import defaultdict
  5. from . import ConstructEmitter
  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 = defaultdict(int)
  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. self._type_counts[subordinate_type] += 1
  38. # ... and add the relevant bytes to our list of subordinates.
  39. self._subordinates.append(subordinate)
  40. def _pre_emit(self):
  41. """ Performs any manipulations needed on this object before emission. """
  42. pass
  43. def emit(self, include_subordinates=True):
  44. """ Emit our descriptor.
  45. Parameters:
  46. include_subordinates -- If true or not provided, any subordinate descriptors will be included.
  47. """
  48. # Run any pre-emit hook code before we perform our emission...
  49. self._pre_emit()
  50. # Start with our core descriptor...
  51. result = bytearray()
  52. result.extend(super().emit())
  53. # ... and if descired, add our subordinates...
  54. for sub in self._subordinates:
  55. result.extend(sub)
  56. return bytes(result)