Source code for AERzip.CompressedFileHeader
import AERzip
[docs]
class CompressedFileHeader:
"""
A CompressedFileHeader contains useful metadata for compressed files from AERzip. Thus, compressed files consist of a header and
the recorded data (addresses and time stamps of the spikes).
The main fields of this header are the following:
- library_version (string): A string indicating the library version.
- compressor (string): A string indicating the compressor used.
- address_size (int): An integer indicating the size of the addresses contained in the compressed file.
- timestamp_size (int): An integer indicating the size of the timestamps contained in the compressed file.
- header_end (string): The string that represents the end of the header. This is the string used in generic AEDAT files.
Each field has a specific size. Thus, the sum of the size of all these fields determines the total size of the header.
"""
def __init__(self, compressor=None, address_size=None, timestamp_size=None):
# Checking parameters
# TODO: Compressors? Empty for now
'''if compressor is not None and not (compressor == "ZSTD" or compressor == "LZ4" or compressor == "LZMA"):
raise ValueError("Only ZSTD, LZ4 or LZMA compression algorithms are supported for now")'''
# Field sizes (bytes)
self.library_version_bytes = 20
self.compressor_bytes = 10
self.address_size_bytes = 1
self.timestamp_size_bytes = 1
self.optional_bytes = 40
self.header_end_bytes = 22 # Size of fixed string "#End Of ASCII Header\r\n"
# Other internal attributes
self.optional_available = self.optional_bytes # Allows to control the space available in the optional field
self.header_size = self.library_version_bytes + self.compressor_bytes + self.address_size_bytes + self.timestamp_size_bytes + self.optional_bytes + self.header_end_bytes
# Field values
self.library_version = "AERzip v" + AERzip.__version__
self.compressor = compressor
self.address_size = address_size
self.timestamp_size = timestamp_size
self.optional = bytearray().ljust(self.optional_bytes)
self.header_end = "#End Of ASCII Header\r\n"
[docs]
def addOptional(self, data):
"""
This function allows to insert data (in bytes) into the optional field of the header.
:param bytearray data: Data to insert into the optional
:raises MemoryError: It is not allowed to use this function when there is not enough space in the optional field.
:return: None
"""
data_size = len(data)
if data_size > self.optional_available:
raise MemoryError("The optional field has reached its maximum capacity.")
start_index = self.optional_bytes - self.optional_available
end_index = start_index + data_size
self.optional[start_index:end_index] = data
self.optional_available -= data_size
[docs]
def toBytes(self):
"""
This function constructs a bytearray from the CompressedFileHeader object. This facilitates its storage in a compressed file.
:return: The CompressedFileHeader object as a bytearray.
:rtype: bytearray
"""
if self.address_size is None:
raise ValueError("The address size must be defined first.")
if self.timestamp_size is None:
raise ValueError("The time stamp size must be defined first.")
header_bytes = bytearray()
# Inserting header data
header_bytes.extend(bytes(self.library_version.ljust(self.library_version_bytes), "utf-8"))
if self.compressor is not None:
header_bytes.extend(bytes(self.compressor.ljust(self.compressor_bytes), "utf-8"))
else:
header_bytes.extend(bytes("".ljust(self.compressor_bytes), "utf-8"))
header_bytes.extend(self.address_size.to_bytes(self.address_size_bytes, "little"))
header_bytes.extend(self.timestamp_size.to_bytes(self.timestamp_size_bytes, "little"))
header_bytes.extend(self.optional.ljust(self.optional_bytes))
header_bytes.extend(bytes(self.header_end.ljust(self.header_end_bytes), "utf-8"))
return header_bytes