SolarisFalls

Untitled

Jan 10th, 2026
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.94 KB | None | 0 0
  1. import datetime
  2. import typing
  3. import sys
  4.  
  5.  
  6. # This table class is used to represent the CSV data
  7. # You can easily append/set fields in columns or rows with the data automatically being formatted
  8. class Table:
  9.     def __init__(self):
  10.         self.fields = {}
  11.         pass
  12.  
  13.     @staticmethod
  14.     def __set_capacity(_list: [], _elements: int):
  15.         if (length := len(_list)) < _elements:
  16.             _list.extend([""] * (_elements - length))
  17.  
  18.     def set_fields(self, _values: []):
  19.         for value in _values:
  20.             self.fields[value] = []
  21.  
  22.     def set(self, _index, _field, _value):  # This could be changed to __setitem__
  23.         self.__set_capacity(self.fields[_field], _index + 1)
  24.         self.fields[_field][_index] = _value
  25.  
  26.     def insert(self, _index, _field, _value):
  27.         for field in self.fields:
  28.             if field == _field:
  29.                 self.fields[field].insert(_index, _value)
  30.             else:
  31.                 self.fields[field].insert(_index, "")
  32.  
  33.     def get_rows(self):
  34.         longestColumn = 0
  35.         for field in self.fields:
  36.             if (length := len(self.fields[field])) > longestColumn:
  37.                 longestColumn = length
  38.  
  39.         return longestColumn
  40.  
  41.     def append(self, _field, _value):
  42.         self.fields[_field].append(_value)
  43.  
  44.     def to_csv(self):
  45.         output = bytearray()
  46.         toWrite = []
  47.  
  48.         def __append(_value):
  49.             output.extend(_value.encode("ascii"))
  50.  
  51.         for field in self.fields:
  52.             __append(field)
  53.             toWrite.append(self.fields[field])
  54.             __append(",")
  55.         output.pop()
  56.         __append("\n")
  57.  
  58.         longestColumn = 0
  59.         for field in self.fields:
  60.             length = len(self.fields[field])
  61.  
  62.             if length > longestColumn:
  63.                 longestColumn = length
  64.  
  65.         for index in range(longestColumn):
  66.             for column in toWrite:
  67.                 self.__set_capacity(column, longestColumn)
  68.                 __append(column[index])
  69.                 __append(',')
  70.             output.pop()
  71.             __append('\n')
  72.  
  73.         return output
  74.  
  75.  
  76. # To prevent leading zeros from the bitmask being removed by Python
  77. class Bitmask:
  78.     def __init__(self, _data: int, _bits: int):
  79.         self.bits = _bits
  80.  
  81.         self.data = bin(_data)[2:]
  82.         self.data = ('0' * (_bits - len(self.data))) + self.data
  83.  
  84.     def __getitem__(self, _index):
  85.         return self.data[_index] == '1'
  86.  
  87.  
  88. # A dictionary with a set size of non-mutable keys to ensure telemetry frame parameter names can reliably be
  89. # referenced, i.e., a typo of a parameter name will throw an error rather than silently adding a new element
  90. class FixedDict:
  91.     # Todo: Add typing.Literal type hinting to _v
  92.     def __init__(self, _v):
  93.         self.data = {}
  94.         self._literals = _v
  95.         self._literalValues = typing.get_args(self._literals)
  96.  
  97.         for literal in self._literalValues:
  98.             self.data[literal] = None
  99.  
  100.     def __setitem__(self, _key, _value):
  101.         if _key in self._literalValues:
  102.             self.data[_key] = _value
  103.         else:
  104.             raise Exception(f"Key '{_key}' does not exist")
  105.  
  106.     def __getitem__(self, _key):
  107.         if _key in self._literalValues:
  108.             return self.data[_key]
  109.         else:
  110.             raise Exception(f"Key '{_key}' does not exist")
  111.  
  112.     def __len__(self):
  113.         return len(self.data)
  114.  
  115.     def __iter__(self):
  116.         values = []
  117.  
  118.         for index, value in enumerate(self.data):
  119.             values += [(value, self.data[value])]
  120.  
  121.         return iter(values)
  122.  
  123.  
  124. # Check if a bit is set from the MSB given an index
  125. # E.g., is_set(0b0100, 1) == True
  126. # This is mostly redundant due to Python's variable width integers
  127. def is_set(_value=0x00, _bit=0):
  128.     if _value == 0:  # Zero has a bit length of 0 - This would cause a negative bit shift amount
  129.         return False
  130.     return (_value & (1 << (int.bit_length(_value) - 1)) >> _bit) != 0
  131.  
  132.  
  133. # I stole this from StackOverflow
  134. # https://stackoverflow.com/questions/32675679/convert-binary-string-to-bytearray-in-python-3
  135. def bitstring_to_bytes(s):
  136.     if s != '':
  137.         return int(s, 2).to_bytes((len(s) + 7) // 8, byteorder="big")
  138.     else:
  139.         return bytearray(0)
  140.  
  141.  
  142. def remove_bits_from_left_preserving_sign(number, n_bits):
  143.     # Remember the original sign
  144.     sign = -1 if number < 0 else 1
  145.  
  146.     # Work with the absolute value
  147.     abs_number = abs(number)
  148.  
  149.     total_bits = abs_number.bit_length()
  150.     bits_to_keep = total_bits - n_bits
  151.  
  152.     # Ensure that we are not trying to remove more bits than the number has
  153.     if bits_to_keep <= 0:
  154.         return 0
  155.  
  156.     # Create a mask to keep the rightmost bits_to_keep bits
  157.     mask = (1 << bits_to_keep) - 1
  158.  
  159.     # Apply the mask and reapply the original sign
  160.     return (abs_number & mask) * sign
  161.  
  162.  
  163. # Return byte array as an integer _width measured in bytes If _width = 0 then automatic width
  164. # Fixme: The method of discarding bits feels like bit of a hack... This works but there may be better methods
  165. def as_int(_bytes: bytearray, _width=0, _endian: typing.Literal["little", "big"] = "big", _l_discard=0, _r_discard=0, _signed=False):
  166.     value: int
  167.     if _width == 0:
  168.         value = int.from_bytes(_bytes, _endian, signed=_signed)
  169.     else:
  170.         value = int.from_bytes(_bytes[:_width], _endian, signed=_signed)
  171.  
  172.     value = remove_bits_from_left_preserving_sign(value, _l_discard)
  173.  
  174.     value = value >> _r_discard
  175.  
  176.     return value
  177.  
  178.  
  179. def as_date_str(_t):
  180.     if _t == 0:  # When you intentionally want it blank (hopefully nobody refers to this specific date)
  181.         return ""
  182.  
  183.     try:
  184.         return datetime.datetime.utcfromtimestamp(_t).strftime("%Y-%m-%d@%H:%M.%S")
  185.     except OSError:
  186.         return "INVALID EPOCH"
  187.  
  188.  
  189. # Used for issues with the log file, issues which cannot be resolved by the user raise an exception
  190. def error_exit(_message: str):
  191.     print(_message, file=sys.stderr)
  192.     exit(1)
Advertisement
Add Comment
Please, Sign In to add comment