From c28238f7874e559adff89750fbf8be7dc0773533 Mon Sep 17 00:00:00 2001 From: lingeringwillx <111698406+lingeringwillx@users.noreply.github.com> Date: Fri, 13 Dec 2024 08:08:46 +0300 Subject: [PATCH] Simplify library --- README.md | 122 +++------------ pyproject.toml | 4 +- structio.py | 396 +++++++++++++++++------------------------------- test.py | 397 +++++++------------------------------------------ 4 files changed, 213 insertions(+), 706 deletions(-) diff --git a/README.md b/README.md index 6a1eebd..d756e13 100644 --- a/README.md +++ b/README.md @@ -84,17 +84,17 @@ Converts a list of integers into a byte. Converts bytes object *b* into an integer. The endian can be specified with the *endian* argument. The *signed* argument is used to specify whether the integer is signed or not. -**pack_int(number, numbytes, endian=None, signed=False)** +**pack_int(number, size, endian=None, signed=False)** -Converts *number* into a bytes object with length *numbytes* and endian *endian*. The *signed* argument is used to specify whether the integer is signed or not. +Converts *number* into a bytes object with length *size* and endian *endian*. The *signed* argument is used to specify whether the integer is signed or not. -**unpack_float(b, numbytes, endian=None)** +**unpack_float(b, size, endian=None)** -Converts bytes object *b* into a float. *numbytes* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. +Converts bytes object *b* into a float. *size* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. -**pack_float(number, numbytes, endian=None)** +**pack_float(number, size, endian=None)** -Converts *number* into a bytes object. *numbytes* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. +Converts *number* into a bytes object. *size* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. **unpack_str(b)** @@ -112,13 +112,13 @@ Convert bytes object *b* into a string up to the null termination. If *start* is Converts *string* into a bytes object representing a null-terminated string. -**unpack_pstr(b, numbytes, endian=None, start=0)** +**unpack_pstr(b, size, endian=None, start=0)** -Converts bytes object *b* into a Pascal string. *numbytes* is used to specify how many bytes are used for the string's length in the object. The endian of the length of the string can be specified with the *endian* argument. *b* will only be converted up to the length specified in the bytes object. If *start* is specified, then the bytes object will be converted starting from position *start*. Returns a tuple containing both the value and the length of the type. +Converts bytes object *b* into a Pascal string. *size* is used to specify how many bytes are used for the string's length in the object. The endian of the length of the string can be specified with the *endian* argument. *b* will only be converted up to the length specified in the bytes object. If *start* is specified, then the bytes object will be converted starting from position *start*. Returns a tuple containing both the value and the length of the type. -**pack_pstr(string, numbytes, endian=None)** +**pack_pstr(string, size, endian=None)** -Converts *string* into a bytes object in the Pascal string format. *numbytes* is used to specify how many bytes are used for the string's length. The endian of the length of the string can be specified with the *endian* argument. +Converts *string* into a bytes object in the Pascal string format. *size* is used to specify how many bytes are used for the string's length. The endian of the length of the string can be specified with the *endian* argument. **unpack_7bint(b, start=0)** @@ -158,10 +158,6 @@ Returns the size/length of the file. Checks if the content of the object is equal to the content of another instance of the same object. -**is_eof()** - -Return True if the end of the stream has been reached. - **copy()** Creates a copy of the object and returns it. @@ -170,18 +166,6 @@ Creates a copy of the object and returns it. Clear the internal buffer of the object. -**append(b)** - -Appends bytes object *b* to the object at the current location. - -**overwrite(self, length, b)** - -Overwrites *length* bytes at the current position with *b*. - -**delete(length)** - -Deletes *length* bytes from the object starting from the current position. - **find(bytes_sequence, n=1)** Searches the object for *bytes_sequence*. Returns the location in which the *nth* occurrence of *bytes_sequence* can be found, returns -1 if it's not found. Starts searching from the current position in the buffer. @@ -198,10 +182,6 @@ Read one byte from the object and converts it into a boolean. Writes *boolean* to the object. -**append_bool()** - -Appends *boolean* to the object. - **read_bits()** Reads one byte from the object and converts it into a list of integers representing the individual bits in the byte. The first element in the list is LSB in the byte. @@ -210,33 +190,21 @@ Reads one byte from the object and converts it into a list of integers represent Converts list of integers *bits* into a byte and writes it to the object. -**append_bits(bits)** +**read_int(size, endian=None, signed=False)** -Converts list of integers *bits* into a byte and writes it to the object. - -**read_int(numbytes, endian=None, signed=False)** - -Reads *numbytes* bytes from the object and converts it into an integer. The endian can be specified with the *endian* argument. The *signed* argument is used to specify whether the integer is signed or not. - -**write_int(number, numbytes, endian=None, signed=False)** - -Converts *number* into a bytes object with length *numbytes* and endian *endian*, then writes it into the object. The *signed* argument is used to specify whether the integer is signed or not. +Reads *size* bytes from the object and converts it into an integer. The endian can be specified with the *endian* argument. The *signed* argument is used to specify whether the integer is signed or not. -**append_int(number, numbytes, endian=None, signed=False)** +**write_int(number, size, endian=None, signed=False)** -Same as *write_int* but appends the value to the object at the current position instead of overwriting existing bytes. +Converts *number* into a bytes object with length *size* and endian *endian*, then writes it into the object. The *signed* argument is used to specify whether the integer is signed or not. -**read_float(numbytes, endian=None)** +**read_float(size, endian=None)** -Reads *numbytes* bytes from the object and converts them into a float. *numbytes* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. +Reads *size* bytes from the object and converts them into a float. *size* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. -**write_float(number, numbytes, endian=None)** +**write_float(number, size, endian=None)** -Converts *number* into a bytes object then writes it into the object. *numbytes* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. - -**append_float(number, numbytes, endian=None)** - -Same as *write_float* but appends the value to the object at the current position instead of overwriting existing bytes. *numbytes* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. +Converts *number* into a bytes object then writes it into the object. *size* can be 2 for half precision, 4 for single precision, or 8 for double precision. The endian can be specified with the *endian* argument. **read_str(length)** @@ -246,14 +214,6 @@ Reads a string with length *length* from the object. Writes *string* into the object. -**append_str(string)** - -Same as *write_str* but appends the value to the object at the current position instead of overwriting existing bytes. - -**overwrite_str(string, length)** - -Deletes *length* bytes starting from the current location, then writes *string* in it's place. - **read_cstr()** Reads a string from the object up to the null termination. Raises a *ValueError* if it fails to find a null termination. @@ -262,46 +222,22 @@ Reads a string from the object up to the null termination. Raises a *ValueError* Writes *string* into the object. -**append_cstr(string)** - -Same as *write_cstr* but appends the value to the object at the current position instead of overwriting existing bytes. - -**overwrite_cstr(string)** - -Deletes the null-terminated string existing at the current location, then writes *string* as a null-terminated string in it's place. Raises a *ValueError* if it fails to find a null termination. - **skip_cstr()** Skips the null-terminated string at the current position. -**delete_cstr()** +**read_pstr(size, endian=None)** -Deletes the null-terminated string at the current position. +Reads a Pascal string from the object and returns it. *size* is used to specify how many bytes are used for the string's length in the object. The endian of the length of the string can be specified with the *endian* argument. -**read_pstr(numbytes, endian=None)** - -Reads a Pascal string from the object and returns it. *numbytes* is used to specify how many bytes are used for the string's length in the object. The endian of the length of the string can be specified with the *endian* argument. - -**write_pstr(string, numbytes, endian=None)** +**write_pstr(string, size, endian=None)** Writes *string* to the object as a Pascal string. -**append_pstr(string, numbytes, endian=None)** - -Same as *write_pstr* but appends the value to the object at the current position instead of overwriting existing bytes. - -**overwrite_pstr(string, numbytes, endian=None)** - -Deletes the existing Pascal string at the current position and writes *string* as a Pascal string in it's place. - -**skip_pstr(numbytes, endian=None)** +**skip_pstr(size, endian=None)** Skips the Pascal string at the current position. -**delete_pstr(numbytes, endian=None)** - -Deletes the Pascal string at the current position. - **read_7bint()** Reads the bytes representing a 7 bit integer from the object at the current position and converts them into an integer. @@ -310,18 +246,6 @@ Reads the bytes representing a 7 bit integer from the object at the current posi Converts *number* into a 7 bit integer and writes it to the object. -**append_7bint(number)** - -Converts *number* into a 7 bit integer and appends it to the object. - -**overwrite_7bint(number)** - -Overwrites the 7 bit integer at the current position with *number*. - **skip_7bint()** -Skips the 7 bit integer at the current position. - -**delete_7bint()** - -Deletes the 7 bit integer at the current position. \ No newline at end of file +Skips the 7 bit integer at the current position. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0596d2d..b575eb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "structio" -version = "1.3.7" +version = "1.4.0" description = "A Library for unparsing, parsing, and editing binary files" readme = "README.md" -requires-python = ">=3.2" +requires-python = ">=3.8" [project.urls] "Homepage" = "https://github.com/lingeringwillx/StructIO" diff --git a/structio.py b/structio.py index dd65122..7fb1c6c 100644 --- a/structio.py +++ b/structio.py @@ -9,13 +9,13 @@ def __init__(self, endian='little', encoding='utf-8', errors='ignore'): self.endian = endian self.encoding = encoding self.errors = errors - + def _get_endian(self, endian): if endian is None: return self.endian else: return endian - + def unpack_bool(self, b): if isinstance(b, int): return b != 0 @@ -23,13 +23,13 @@ def unpack_bool(self, b): return b != b'\x00' else: raise ValueError('expected int or bytes object of length 1') - + def pack_bool(self, boolean): if boolean: return b'\x01' else: return b'\x00' - + def unpack_bits(self, b): if isinstance(b, int): number = b @@ -37,374 +37,254 @@ def unpack_bits(self, b): number = self.unpack_int(b) else: raise ValueError('expected int or bytes object of length 1') - + return [number >> i & 1 for i in range(8)] - + def pack_bits(self, bits): return self.pack_int(sum(bits[i] << i for i in range(8)), 1) - + def unpack_int(self, b, endian=None, signed=False): return int.from_bytes(b, self._get_endian(endian), signed=signed) - - def pack_int(self, number, numbytes, endian=None, signed=False): - return number.to_bytes(numbytes, self._get_endian(endian), signed=signed) - - def _get_format(self, numbytes, endian=None): - if numbytes not in _float_formats: - raise ValueError("float size '{}' not supported".format(numbytes)) - + + def pack_int(self, number, size, endian=None, signed=False): + return number.to_bytes(size, self._get_endian(endian), signed=signed) + + def _get_format(self, size, endian=None): + if size not in _float_formats: + raise ValueError("float size '{}' not supported".format(size)) + if endian not in _endians: raise ValueError("endian '{}' is not recognized".format(endian)) - - return _endians[endian] + _float_formats[numbytes] - - def unpack_float(self, b, numbytes, endian=None): - return struct.unpack(self._get_format(numbytes, self._get_endian(endian)), b)[0] - - def pack_float(self, number, numbytes, endian=None): - return struct.pack(self._get_format(numbytes, self._get_endian(endian)), number) - + + return _endians[endian] + _float_formats[size] + + def unpack_float(self, b, size, endian=None): + return struct.unpack(self._get_format(size, self._get_endian(endian)), b)[0] + + def pack_float(self, number, size, endian=None): + return struct.pack(self._get_format(size, self._get_endian(endian)), number) + def unpack_str(self, b): return b.decode(self.encoding, errors=self.errors) - + def pack_str(self, string): return string.encode(self.encoding, errors=self.errors) - - def _get_cstr_len(self, b, start=0): + + def unpack_cstr(self, b, start=0): end = b.find(b'\x00', start) - + if end == -1: raise ValueError('null termination not found') - - return end - start + 1 - - def unpack_cstr(self, b, start=0): - length = self._get_cstr_len(b, start) - string = self.unpack_str(b[start:(start + length - 1)]) - return string, length - + + string = self.unpack_str(b[start:end]) + return string, end - start + 1 + def pack_cstr(self, string): return self.pack_str(string) + b'\x00' - - def _get_pstr_len(self, b, numbytes, endian=None, start=0): - return numbytes + self.unpack_int(b[start:(start + numbytes)], endian) - - def unpack_pstr(self, b, numbytes, endian=None, start=0): - length = self._get_pstr_len(b, numbytes, endian, start) - string = self.unpack_str(b[(start + numbytes):(start + length)]) - return string, length - - def pack_pstr(self, string, numbytes, endian=None): + + def unpack_pstr(self, b, size, endian=None, start=0): + length = self.unpack_int(b[start:start + size], endian) + string = self.unpack_str(b[start + size:start + size + length]) + return string, size + length + + def pack_pstr(self, string, size, endian=None): b = self.pack_str(string) - return self.pack_int(len(b), numbytes, endian) + b - - def _get_7bint_len(self, b, start=0): - i = 0 - while b[start + i] > 127: - i += 1 - - return i + 1 - + return self.pack_int(len(b), size, endian) + b + def unpack_7bint(self, b, start=0): number = 0 i = 0 - + byte = b[start] while byte > 127: number += (byte & 0b01111111) << (7 * i) i += 1 - + byte = b[start + i] - + number += byte << (7 * i) length = i + 1 - + return number, length - + def pack_7bint(self, number): b = b'' - + while number > 127: b += self.pack_int(number & 0b01111111 | 0b10000000, 1) number >>= 7 - + b += self.pack_int(number, 1) return b - + class StructIO(io.BytesIO): def __init__(self, b=b'', endian='little', encoding='utf-8', errors='ignore'): super().__init__(b) self.endian = endian self.encoding = encoding self.errors = errors - + @property def buffer(self): return self.getvalue() - + @buffer.setter def buffer(self, b): position = self.tell() self.seek(0) self.write(b) self.truncate() - + if position < len(b): self.seek(position) - + def __len__(self): position = self.tell() self.seek(0, 2) length = self.tell() self.seek(position) return length - + def __eq__(self, other): return self.getvalue() == other.getvalue() - + def _get_endian(self, endian): if endian is None: return self.endian else: return endian - - def is_eof(self): - if self.read(1) == b'': - return True - else: - self.seek(-1, 1) - return False - + def copy(self): return StructIO(self.getvalue(), self.endian, self.encoding, self.errors) - + def clear(self): self.seek(0) self.truncate() - - def append(self, b): - return self.overwrite(0, b) - - def overwrite(self, length, b): - position = self.tell() - self.seek(length, 1) - buffer = self.read() - self.seek(position) - length = self.write(b) - self.write(buffer) - self.truncate() - self.seek(position + length) - return length - - def delete(self, length): - start = self.tell() - buf_length = len(self) - - if start + length > buf_length: - length = buf_length - start - - self.overwrite(length , b'') - return length - + def find(self, bytes_sequence, n=1): start = self.tell() content = self.getvalue() location = content.find(bytes_sequence, start) - + for i in range(1, n): location = content.find(bytes_sequence, location + 1) - + if location == -1: break - + return location - + def index(self, bytes_sequence, n=1): location = self.find(bytes_sequence, n) - + if location == -1: raise ValueError('{} not found'.format(bytes_sequence)) - + return location - + def read_bool(self): return self.read(1) != b'\x00' - - def _pack_bool(self, boolean): + + def write_bool(self, boolean): if boolean: - return b'\x01' + return self.write(b'\x01') else: - return b'\x00' - - def write_bool(self, boolean): - return self.write(self._pack_bool(boolean)) - - def append_bool(self, boolean): - return self.append(self._pack_bool(boolean)) - + return self.write(b'\x00') + def read_bits(self): number = self.read_int(1) return [number >> i & 1 for i in range(8)] - - def _pack_bits(self, bits): - return self._pack_int(sum(bits[i] << i for i in range(8)), 1) - + def write_bits(self, bits): - return self.write(self._pack_bits(bits)) - - def append_bits(self, bits): - return self.append(self._pack_bits(bits)) - - def read_int(self, numbytes, endian=None, signed=False): - return int.from_bytes(self.read(numbytes), self._get_endian(endian), signed=signed) - - def _pack_int(self, number, numbytes, endian=None, signed=False): - return number.to_bytes(numbytes, self._get_endian(endian), signed=signed) - - def write_int(self, number, numbytes, endian=None, signed=False): - return self.write(self._pack_int(number, numbytes, endian, signed)) - - def append_int(self, number, numbytes, endian=None, signed=False): - return self.append(self._pack_int(number, numbytes, endian, signed)) - - def _get_format(self, numbytes, endian=None): - if numbytes not in _float_formats: - raise ValueError("float size '{}' not supported".format(numbytes)) - + return self.write_int(sum(bits[i] << i for i in range(8)), 1) + + def read_int(self, size, endian=None, signed=False): + return int.from_bytes(self.read(size), self._get_endian(endian), signed=signed) + + def write_int(self, number, size, endian=None, signed=False): + return self.write(number.to_bytes(size, self._get_endian(endian), signed=signed)) + + def _get_format(self, size, endian=None): + if size not in _float_formats: + raise ValueError("float size '{}' not supported".format(size)) + if endian not in _endians: raise ValueError("endian '{}' is not recognized".format(endian)) - - return _endians[endian] + _float_formats[numbytes] - - def read_float(self, numbytes, endian=None): - return struct.unpack(self._get_format(numbytes, self._get_endian(endian)), self.read(numbytes))[0] - - def _pack_float(self, number, numbytes, endian=None): - return struct.pack(self._get_format(numbytes, self._get_endian(endian)), number) - - def write_float(self, number, numbytes, endian=None): - return self.write(self._pack_float(number, numbytes, endian)) - - def append_float(self, number, numbytes, endian=None): - return self.append(self._pack_float(number, numbytes, endian)) - + + return _endians[endian] + _float_formats[size] + + def read_float(self, size, endian=None): + return struct.unpack(self._get_format(size, self._get_endian(endian)), self.read(size))[0] + + def write_float(self, number, size, endian=None): + return self.write(struct.pack(self._get_format(size, self._get_endian(endian)), number)) + def read_str(self, length): return self.read(length).decode(self.encoding, errors=self.errors) - - def _pack_str(self, string): - return string.encode(self.encoding, errors=self.errors) - + def write_str(self, string): - return self.write(self._pack_str(string)) - - def append_str(self, string): - return self.append(self._pack_str(string)) - - def overwrite_str(self, string, length): - return self.overwrite(length, self._pack_str(string)) - - def _get_cstr_len(self): + return self.write(string.encode(self.encoding, errors=self.errors)) + + def read_cstr(self): + start = self.tell() end = self.find(b'\x00') - + if end == -1: raise ValueError('null termination not found') - - return end - self.tell() + 1 - - def read_cstr(self): - string = self.read_str(self._get_cstr_len() - 1) + + string = self.read_str(end - start) self.seek(1, 1) return string - - def _pack_cstr(self, string): - return self._pack_str(string) + b'\x00' - + def write_cstr(self, string): - return self.write(self._pack_cstr(string)) - - def append_cstr(self, string): - return self.append(self._pack_cstr(string)) - - def overwrite_cstr(self, string): - return self.overwrite(self._get_cstr_len(), self._pack_cstr(string)) - + return self.write_str(string) + self.write(b'\x00') + def skip_cstr(self): - return self.seek(self._get_cstr_len(), 1) - - def delete_cstr(self): - return self.delete(self._get_cstr_len()) - - def _get_pstr_len(self, numbytes, endian=None): - length = self.read_int(numbytes, endian) - self.seek(-numbytes, 1) - return numbytes + length - - def read_pstr(self, numbytes, endian=None): - return self.read_str(self.read_int(numbytes, endian)) - - def _pack_pstr(self, string, numbytes, endian=None): - b = self._pack_str(string) - return self._pack_int(len(b), numbytes, endian) + b - - def write_pstr(self, string, numbytes, endian=None): - return self.write(self._pack_pstr(string, numbytes, endian)) - - def append_pstr(self, string, numbytes, endian=None): - return self.append(self._pack_pstr(string, numbytes, endian)) - - def overwrite_pstr(self, string, numbytes, endian=None): - return self.overwrite(self._get_pstr_len(numbytes, endian), self._pack_pstr(string, numbytes, endian)) - - def skip_pstr(self, numbytes, endian=None): - return self.seek(self._get_pstr_len(numbytes, endian), 1) - - def delete_pstr(self, numbytes, endian=None): - return self.delete(self._get_pstr_len(numbytes, endian)) - - def _get_7bint_len(self): - i = 0 - while self.read_int(1) > 127: - i += 1 - - self.seek(- i - 1, 1) - return i + 1 - + end = self.find(b'\x00') + + if end == -1: + raise ValueError('null termination not found') + + return self.seek(end + 1) + + def read_pstr(self, size, endian=None): + return self.read_str(self.read_int(size, endian)) + + def write_pstr(self, string, size, endian=None): + b = string.encode(self.encoding, errors=self.errors) + return self.write_int(len(b), size, endian) + self.write(b) + + def skip_pstr(self, size, endian=None): + return self.seek(self.read_int(size, endian), 1) + def read_7bint(self): number = 0 i = 0 - + byte = self.read_int(1) while byte > 127: number += (byte & 0b01111111) << (7 * i) i += 1 - + byte = self.read_int(1) - + number += byte << (7 * i) - + return number - - def _pack_7bint(self, number): - b = b'' - + + def write_7bint(self, number): + length = 0 + while number > 127: - b += self._pack_int(number & 0b01111111 | 0b10000000, 1) + length += self.write_int(number & 0b01111111 | 0b10000000, 1) number >>= 7 - - b += self._pack_int(number, 1) - return b - - def write_7bint(self, number): - return self.write(self._pack_7bint(number)) - - def append_7bint(self, number): - return self.append(self._pack_7bint(number)) - - def overwrite_7bint(self, number): - return self.overwrite(self._get_7bint_len(), self._pack_7bint(number)) - + + length += self.write_int(number, 1) + + return length + def skip_7bint(self): - return self.seek(self._get_7bint_len(), 1) - - def delete_7bint(self): - return self.delete(self._get_7bint_len()) \ No newline at end of file + while self.read_int(1) > 127: + pass + + return self.tell() \ No newline at end of file diff --git a/test.py b/test.py index 69f20e5..4e101e3 100644 --- a/test.py +++ b/test.py @@ -10,58 +10,58 @@ def testbool(self): self.assertEqual(True, struct.unpack_bool(1)) #True int self.assertEqual(True, struct.unpack_bool(2)) #True not one int self.assertEqual(False, struct.unpack_bool(0)) #False int - + def testbits(self): struct = Struct() self.assertEqual([0,1,0,1,0,1,0,1], struct.unpack_bits(struct.pack_bits([0,1,0,1,0,1,0,1]))) #byte self.assertEqual([0,1,0,1,0,1,0,1], struct.unpack_bits(170)) #int - + def testint(self): struct = Struct('big') self.assertEqual(10, struct.unpack_int(struct.pack_int(10, 2))) #default endian unsigned self.assertEqual(10, struct.unpack_int(struct.pack_int(10, 2, 'little'), 'little')) #little endian unsigned self.assertEqual(10, struct.unpack_int(struct.pack_int(10, 2, 'big'), 'big'))#big endian unsigned - + self.assertEqual(-10, struct.unpack_int(struct.pack_int(-10, 2, signed=True), signed=True)) #default endian signed self.assertEqual(-10, struct.unpack_int(struct.pack_int(-10, 2, 'little', signed=True), 'little', signed=True)) #little endian signed self.assertEqual(-10, struct.unpack_int(struct.pack_int(-10, 2, 'big', signed=True), 'big', signed=True)) #big endian signed - + def testfloat(self): struct = Struct('big') self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 2), 2), 2)) #half defualt endian self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 4), 4), 2)) #single default endian self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 8), 8), 2)) #double default endian - + self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 2, 'little'), 2, 'little'), 2)) #half little endian self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 4, 'big'), 4, 'big'), 2)) #single big endian self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 8, 'little'), 8,'little'), 2)) #double little endian - + self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 2, 'big'), 2, 'big'), 2)) #single big endian self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 4, 'little'), 4, 'little'), 2)) #double little endian self.assertEqual(3.14, round(struct.unpack_float(struct.pack_float(3.14, 8, 'big'), 8, 'big'), 2)) #double big endian - + def teststr(self): struct = Struct() self.assertEqual('Unit Test', struct.unpack_str(struct.pack_str('Unit Test'))) - + def testcstr(self): struct = Struct() self.assertEqual('Unit Test', struct.unpack_cstr(struct.pack_cstr('Unit Test'))[0]) self.assertEqual('Test', struct.unpack_cstr(b'Unit\x00Test\x00', 5)[0]) - + def testpstr(self): struct = Struct('big') self.assertEqual('Unit Test', struct.unpack_pstr(struct.pack_pstr('Unit Test', 2), 2)[0]) #default endian self.assertEqual('Unit Test', struct.unpack_pstr(struct.pack_pstr('Unit Test', 2, 'little'), 2, 'little')[0]) #little endian self.assertEqual('Unit Test', struct.unpack_pstr(struct.pack_pstr('Unit Test', 2, 'big'), 2, 'big')[0]) #big endian - + self.assertEqual('Test', struct.unpack_pstr(b'\x04Unit\x04Test', 1, 'little', 5)[0]) - + def test7bint(self): struct = Struct() self.assertEqual(128, struct.unpack_7bint(struct.pack_7bint(128))[0]) self.assertEqual(128, struct.unpack_7bint(b'\x00' + struct.pack_7bint(128), start=1)[0]) - + class ExampleTest(unittest.TestCase): def testexample(self): #making sure that the example at least doesn't crash @@ -72,32 +72,32 @@ def testexample(self): stream.write_pstr('World!', 1) stream.seek(0) stream.read() - + stream.seek(0) stream.read_int(2) stream.read_float(4) stream.read_cstr() stream.read_pstr(1) - + class GenericStreamMethodsTest(unittest.TestCase): def testbufgettersetter(self): stream = StructIO() self.assertEqual(stream.buffer, stream.getvalue()) - + stream.seek(4) stream.buffer = b'Unit Test' self.assertEqual(b'Unit Test', stream.getvalue()) - + stream.seek(10) stream.buffer = b'Unit Test' self.assertEqual(9, stream.tell()) - + def testlen(self): stream = StructIO(b'Unit Test') stream.seek(5) self.assertEqual(9, len(stream)) self.assertEqual(5, stream.tell()) #should be unchanged - + def testeq(self): stream1 = StructIO(b'Test') stream2 = StructIO(b'Test') @@ -106,421 +106,163 @@ def testeq(self): self.assertEqual(stream1, stream2) stream3.seek(1) self.assertNotEqual(stream1, stream3) - + def testclear(self): stream = StructIO(b'Unit Test') stream.seek(5) stream.clear() self.assertEqual(0, stream.tell()) self.assertEqual(b'', stream.read()) - - def testiseof(self): - stream = StructIO(b'Unit Test') - self.assertFalse(stream.is_eof()) - self.assertEqual(0, stream.tell()) - stream.seek(0, 2) - self.assertTrue(stream.is_eof()) - + def testcopy(self): stream = StructIO(b'Unit Test') stream2 = stream.copy() stream.seek(0) self.assertEqual(0, stream2.tell()) self.assertEqual(stream.read(), stream2.read()) - - def testappend(self): - stream = StructIO() - stream.write(b'Test') - stream.seek(0) - stream.append(b'Unit ') - stream.seek(0) - self.assertEqual(b'Unit Test', stream.read()) - - def testoverwrite(self): - stream = StructIO() - stream.write(b'Unit Test') - stream.seek(0) - stream.overwrite(4, b'New') - self.assertEqual(3, stream.tell()) - stream.seek(0) - self.assertEqual(b'New Test', stream.read()) - - def testdelete(self): - stream = StructIO(b'Unit Test') - stream.seek(4) - stream.delete(5) - stream.seek(0) - self.assertEqual(b'Unit', stream.read()) - - stream = StructIO(b'Unit Test') - stream.delete(5) - self.assertEqual(b'Test', stream.read()) - + def testfind(self): stream = StructIO(b'Unit Test Unit Test') self.assertEqual(5, stream.find(b'Test')) #first instance self.assertEqual(15, stream.find(b'Test', 2)) #second - + def testindex(self): stream = StructIO(b'Unit Test Unit Test') self.assertEqual(5, stream.index(b'Test')) #first instance self.assertEqual(15, stream.index(b'Test', 2)) #second self.assertRaises(ValueError, lambda: stream.index(b'Test', 3)) - + class WriteReadMethodsTest(unittest.TestCase): def testbool(self): stream = StructIO() stream.write_bool(True) stream.seek(0) self.assertEqual(True, stream.read_bool()) #True - + stream = StructIO() stream.write_bool(False) stream.seek(0) self.assertEqual(False, stream.read_bool()) #False - + def testbits(self): stream = StructIO() stream.write_bits([0,1,0,1,0,1,0,1]) stream.seek(0) self.assertEqual([0,1,0,1,0,1,0,1], stream.read_bits()) - + def testint(self): stream = StructIO() stream.write_int(10, 2) stream.seek(0) self.assertEqual(10, stream.read_int(2)) #default endian unsigned - + stream = StructIO(endian='big') stream.write_int(10, 2, 'little') stream.seek(0) self.assertEqual(10, stream.read_int(2, 'little')) #little endian unsigned - + stream = StructIO() stream.write_int(10, 2, 'big') stream.seek(0) self.assertEqual(10, stream.read_int(2, 'big')) #big endian unsigned - + stream = StructIO() stream.write_int(-10, 2, signed=True) stream.seek(0) self.assertEqual(-10, stream.read_int(2, signed=True)) #default endian signed - + stream = StructIO(endian='big') stream.write_int(-10, 2, 'little', signed=True) stream.seek(0) self.assertEqual(-10, stream.read_int(2, 'little', signed=True)) #little endian signed - + stream = StructIO() stream.write_int(-10, 2, 'big', signed=True) stream.seek(0) self.assertEqual(-10, stream.read_int(2, 'big', signed=True)) #big endian signed - + def testfloat(self): stream = StructIO() stream.write_float(3.14, 2) stream.seek(0) self.assertEqual(3.14, round(stream.read_float(2), 2)) #half default endian - + stream = StructIO(endian='big') stream.write_float(3.14, 2, 'little') stream.seek(0) self.assertEqual(3.14, round(stream.read_float(2, 'little'), 2)) #half little endian - + stream = StructIO() stream.write_float(3.14, 2, 'big') stream.seek(0) self.assertEqual(3.14, round(stream.read_float(2, 'big'), 2)) #half big endian - + stream = StructIO() stream.write_float(3.14, 4) stream.seek(0) self.assertEqual(3.14, round(stream.read_float(4), 2)) #single default endian - + stream = StructIO(endian='big') stream.write_float(3.14, 4, 'little') stream.seek(0) self.assertEqual(3.14, round(stream.read_float(4, 'little'), 2)) #single little endian - + stream = StructIO() stream.write_float(3.14, 4, 'big') stream.seek(0) self.assertEqual(3.14, round(stream.read_float(4, 'big'), 2)) #single big endian - + stream = StructIO() stream.write_float(3.14, 8) stream.seek(0) self.assertEqual(3.14, round(stream.read_float(8), 2)) #double default endian - + stream = StructIO(endian='big') stream.write_float(3.14, 8, 'little') stream.seek(0) self.assertEqual(3.14, round(stream.read_float(8, 'little'), 2)) #double little endian - + stream = StructIO() stream.write_float(3.14, 8, 'big') stream.seek(0) self.assertEqual(3.14, round(stream.read_float(8, 'big'), 2)) #double big endian - + def teststr(self): stream = StructIO() stream.write_str('Unit Test') stream.seek(0) self.assertEqual('Unit Test', stream.read_str(len('Unit Test'))) - + def testcstr(self): stream = StructIO() stream.write_cstr('Unit Test') stream.seek(0) self.assertEqual('Unit Test', stream.read_cstr()) self.assertEqual(10, stream.tell()) - + def testpstr(self): stream = StructIO() stream.write_pstr('Unit Test', 2) stream.seek(0) self.assertEqual('Unit Test', stream.read_pstr(2)) #default endian - + stream = StructIO(endian='big') stream.write_pstr('Unit Test', 2, 'little') stream.seek(0) self.assertEqual('Unit Test', stream.read_pstr(2, 'little')) #little endian - + stream = StructIO() stream.write_pstr('Unit Test', 2, 'big') stream.seek(0) self.assertEqual('Unit Test', stream.read_pstr(2, 'big')) #big endian - + def test7bint(self): stream = StructIO() stream.write_7bint(128) stream.seek(0) self.assertEqual(128, stream.read_7bint()) self.assertEqual(2, stream.tell()) - -class AppendMethodsTest(unittest.TestCase): - def testappendbool(self): - stream = StructIO() - stream.write_bool(False) - stream.seek(0) - stream.append_bool(True) - stream.seek(0) - self.assertEqual(True, stream.read_bool()) - - def testappendbits(self): - stream = StructIO() - stream.write_bits([0,0,0,0,0,0,0,0]) - stream.seek(0) - stream.append_bits([1,1,1,1,1,1,1,1]) - stream.seek(0) - self.assertEqual([1,1,1,1,1,1,1,1], stream.read_bits()) #default endian unsigned - - def testappendint(self): - stream = StructIO() - stream.write_int(2, 2) - stream.seek(0) - stream.append_int(1, 2) - stream.seek(0) - self.assertEqual(1, stream.read_int(2)) #default endian unsigned - - stream = StructIO(endian='big') - stream.write_int(2, 2, 'little') - stream.seek(0) - stream.append_int(1, 2, 'little') - stream.seek(0) - self.assertEqual(1, stream.read_int(2, 'little')) #little endian unsigned - - stream = StructIO() - stream.write_int(2, 2, 'big') - stream.seek(0) - stream.append_int(1, 2, 'big') - stream.seek(0) - self.assertEqual(1, stream.read_int(2, 'big')) #big endian unsigned - - stream = StructIO() - stream.write_int(-2, 2, signed=True) - stream.seek(0) - stream.append_int(-1, 2, signed=True) - stream.seek(0) - self.assertEqual(-1, stream.read_int(2, signed=True)) #default endian signed - - stream = StructIO(endian='big') - stream.write_int(-2, 2, 'little', signed=True) - stream.seek(0) - stream.append_int(-1, 2, 'little', signed=True) - stream.seek(0) - self.assertEqual(-1, stream.read_int(2, 'little', signed=True)) #little endian signed - - stream = StructIO() - stream.write_int(-2, 2, 'big', signed=True) - stream.seek(0) - stream.append_int(-1, 2, 'big', signed=True) - stream.seek(0) - self.assertEqual(-1, stream.read_int(2, 'big', signed=True)) #big endian signed - - def testappendfloat(self): - stream = StructIO() - stream.write_float(3.14, 2) - stream.seek(0) - stream.append_float(6.28, 2) - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(2), 2)) #default endian half - - stream = StructIO(endian='big') - stream.write_float(3.14, 2, 'little') - stream.seek(0) - stream.append_float(6.28, 2, 'little') - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(2, 'little'), 2)) #little endian half - - stream = StructIO() - stream.write_float(3.14, 2, 'big') - stream.seek(0) - stream.append_float(6.28, 2, 'big') - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(2, 'big'), 2)) #big endian half - - stream = StructIO() - stream.write_float(3.14, 4) - stream.seek(0) - stream.append_float(6.28, 4) - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(4), 2)) #default endian single - - stream = StructIO(endian='big') - stream.write_float(3.14, 4, 'little') - stream.seek(0) - stream.append_float(6.28, 4, 'little') - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(4, 'little'), 2)) #little endian single - - stream = StructIO() - stream.write_float(3.14, 4, 'big') - stream.seek(0) - stream.append_float(6.28, 4, 'big') - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(4, 'big'), 2)) #big endian single - - stream = StructIO() - stream.write_float(3.14, 8) - stream.seek(0) - stream.append_float(6.28, 8) - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(8), 2)) #default endian double - - stream = StructIO(endian='big') - stream.write_float(3.14, 8, 'little') - stream.seek(0) - stream.append_float(6.28, 8, 'little') - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(8, 'little'), 2)) #little endian double - - stream = StructIO() - stream.write_float(3.14, 8, 'big') - stream.seek(0) - stream.append_float(6.28, 8, 'big') - stream.seek(0) - self.assertEqual(6.28, round(stream.read_float(8, 'big'), 2)) #big endian double - - def testappendstr(self): - stream = StructIO() - stream.write_str('Test') - stream.seek(0) - stream.append_str('Unit ') - stream.seek(0) - self.assertEqual('Unit Test', stream.read_str(len('Unit Test'))) - - def testappendcstr(self): - stream = StructIO() - stream.write_cstr('Test') - stream.seek(0) - stream.append_cstr('Unit') - stream.seek(0) - self.assertEqual('Unit', stream.read_cstr()) - self.assertEqual('Test', stream.read_cstr()) - self.assertEqual(10, stream.tell()) - - def testappendpstr(self): - stream = StructIO() - stream.write_pstr('Test', 2) - stream.seek(0) - stream.append_pstr('Unit', 2) - stream.seek(0) - self.assertEqual('Unit', stream.read_pstr(2)) #default endian - self.assertEqual('Test', stream.read_pstr(2)) - - stream = StructIO(endian='big') - stream.write_pstr('Test', 2, 'little') - stream.seek(0) - stream.append_pstr('Unit', 2, 'little') - stream.seek(0) - self.assertEqual('Unit', stream.read_pstr(2, 'little')) #little endian - self.assertEqual('Test', stream.read_pstr(2, 'little')) - - stream = StructIO() - stream.write_pstr('Test', 2, 'big') - stream.seek(0) - stream.append_pstr('Unit', 2, 'big') - stream.seek(0) - self.assertEqual('Unit', stream.read_pstr(2, 'big')) #big endian - self.assertEqual('Test', stream.read_pstr(2, 'big')) - - def testappend7bint(self): - stream = StructIO() - stream.write_7bint(128) - stream.seek(0) - stream.append_7bint(127) - stream.seek(0) - self.assertEqual(127, stream.read_7bint()) - -class OverwriteMethodsTest(unittest.TestCase): - def testoverwritestr(self): - stream = StructIO() - stream.write_str('Unit Test') - stream.seek(0) - stream.overwrite_str('Working', 9) - stream.seek(0) - self.assertEqual('Working', stream.read_str(len('Working'))) - - def testoverwritecstr(self): - stream = StructIO() - stream.write_cstr('Unit Test') - stream.seek(0) - stream.overwrite_cstr('Working') - self.assertEqual(8, stream.tell()) - stream.seek(0) - self.assertEqual('Working', stream.read_cstr()) - - def testoverwritepstr(self): - stream = StructIO(endian='big') - stream.write_pstr('Unit Test', 2) - stream.seek(0) - stream.overwrite_pstr('Working', 3) - stream.seek(0) - self.assertEqual('Working', stream.read_pstr(3)) #default endian - - stream = StructIO(endian='big') - stream.write_pstr('Unit Test', 2, 'little') - stream.seek(0) - stream.overwrite_pstr('Working', 3, 'little') - stream.seek(0) - self.assertEqual('Working', stream.read_pstr(3, 'little')) #little endian - - stream = StructIO() - stream.write_pstr('Unit Test', 2, 'big') - stream.seek(0) - stream.overwrite_pstr('Working', 3, 'big') - stream.seek(0) - self.assertEqual('Working', stream.read_pstr(3, 'big')) #big endian - - def testoverwrite7bint(self): - stream = StructIO() - stream.write_7bint(128) - stream.seek(0) - stream.overwrite_7bint(127) - stream.seek(0) - self.assertEqual(127, stream.read_7bint()) - + class SkipMethodsTest(unittest.TestCase): def testskipcstr(self): stream = StructIO() @@ -529,7 +271,7 @@ def testskipcstr(self): stream.seek(0) stream.skip_cstr() self.assertEqual('Test', stream.read_cstr()) - + def testskippstr(self): stream = StructIO() stream.write_pstr('Unit', 2) @@ -537,7 +279,7 @@ def testskippstr(self): stream.seek(0) stream.skip_pstr(2) self.assertEqual('Test', stream.read_pstr(2)) - + def testskip7bint(self): stream = StructIO() stream.write_7bint(128) @@ -545,44 +287,5 @@ def testskip7bint(self): stream.seek(0) stream.skip_7bint() self.assertEqual(127, stream.read_7bint()) - -class DeleteMethodsTest(unittest.TestCase): - def testdeletecstr(self): - stream = StructIO() - stream.write_cstr('Unit') - stream.write_cstr('Test') - stream.seek(0) - stream.delete_cstr() - self.assertEqual('Test', stream.read_cstr()) - - def testdeletepstr(self): - stream = StructIO(endian='big') - stream.write_pstr('Unit', 2) - stream.write_pstr('Test', 2) - stream.seek(0) - stream.delete_pstr(2) - self.assertEqual('Test', stream.read_pstr(2)) #default endian - - stream = StructIO(endian='big') - stream.write_pstr('Unit', 2, 'little') - stream.write_pstr('Test', 2, 'little') - stream.seek(0) - stream.delete_pstr(2, 'little') - self.assertEqual('Test', stream.read_pstr(2, 'little')) #little endian - - stream = StructIO() - stream.write_pstr('Unit', 2, 'big') - stream.write_pstr('Test', 2, 'big') - stream.seek(0) - stream.delete_pstr(2, 'big') - self.assertEqual('Test', stream.read_pstr(2, 'big')) #big endian - - def testdelete7bint(self): - stream = StructIO() - stream.write_7bint(128) - stream.write_7bint(127) - stream.seek(0) - stream.delete_7bint() - self.assertEqual(127, stream.read_7bint()) - + unittest.main() \ No newline at end of file