This shows you the differences between two versions of the page.
Both sides previous revision Previous revision | |||
supercross_2000:ovln [2019/07/04 19:59] David [Python] Simplified bytes_to_int24 |
supercross_2000:ovln [2019/07/14 01:53] (current) David Updated information. |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== OVLN ====== | ====== OVLN ====== | ||
- | This is a compression format used by EA Games | + | This is a format for compressing game code and other misc data in the ROM. There are 4 OVLN blocks in Supercross 2000. |
+ | |||
+ | This format uses [[supercross_2000:eahd|EAHD]] for the compression, which starts at offset 0x10 of the OVLN block. | ||
---- | ---- | ||
===== Header ===== | ===== Header ===== | ||
- | The header takes up the first 0x15 bytes of the compressed file | + | The OVLN header takes up the first 0x10 bytes of the compressed file. After the header is a EAHD compressed block. |
^Offset^#Bytes^Description^ | ^Offset^#Bytes^Description^ | ||
Line 13: | Line 15: | ||
|0x08|4|RAM location to decompress| | |0x08|4|RAM location to decompress| | ||
|0x0C|4|RAM location to JAL to when done| | |0x0C|4|RAM location to JAL to when done| | ||
- | |0x10|2|Magic Number. If it is 0x10FB then decompress, otherwise directly DMA with uncompressed size.| | ||
- | |0x12|3|Uncompressed size| | ||
- | |||
- | ---- | ||
- | ===== Decompression Code ===== | ||
- | |||
- | ==== Python ==== | ||
- | |||
- | <code python [enable_line_numbers="true"] ovln_parse.py> | ||
- | def bytes_to_int24(arr, offset): | ||
- | return int.from_bytes(arr[offset:offset+3], byteorder='big') | ||
- | |||
- | def bytes_to_int_reversed(arr, offset): | ||
- | return int.from_bytes(arr[offset:offset+4], byteorder='little') | ||
- | | ||
- | def ovln_memset(dst, dst_offset, value, amount): | ||
- | for i in range(amount): | ||
- | dst[dst_offset + i] = value | ||
- | |||
- | def ovln_memcpy(dst, dst_offset, dst_backwards_offset, amount): | ||
- | src_offset = dst_offset - dst_backwards_offset | ||
- | for i in range(amount): | ||
- | dst[dst_offset + i] = dst[src_offset + i] | ||
- | |||
- | def ovln_fetch_bytes(dst, dst_offset, dst_backwards_offset, amount): | ||
- | if dst_backwards_offset > 1: | ||
- | ovln_memcpy(dst, dst_offset, dst_backwards_offset, amount) | ||
- | else: | ||
- | ovln_memset(dst, dst_offset, dst[dst_offset - dst_backwards_offset], amount) | ||
- | return dst_offset + amount | ||
- | |||
- | def ovln_copy_literal(dst, dst_offset, src, src_offset, amount): | ||
- | for i in range(amount): | ||
- | dst[dst_offset + i] = src[src_offset + i] | ||
- | |||
- | # Input: src = compressed data list | ||
- | # Output: returns decompressed data list | ||
- | def ovln_parse(src): | ||
- | decompressed_size = bytes_to_int24(src, 0x12) | ||
- | dst = [0] * decompressed_size # Decompressed data list | ||
- | src_offset = 0x15 | ||
- | dst_offset = 0 | ||
- | while True: | ||
- | cmd = bytes_to_int_reversed(src, src_offset) | ||
- | if cmd & 0x80 == 0: # Covers commands 00 to 7F | ||
- | src_offset += 2 | ||
- | # Copy bytes from the compressed data array | ||
- | amount_to_copy = cmd & 0x3 | ||
- | ovln_copy_literal(dst, dst_offset, src, src_offset, amount_to_copy) | ||
- | src_offset += amount_to_copy | ||
- | dst_offset += amount_to_copy | ||
- | # Fetch bytes from previous decompressed data | ||
- | backward_fetch_offset = ((cmd << 3) & 0x300) + ((cmd >> 8) & 0xFF) + 1 | ||
- | amount_of_bytes_to_fetch = ((cmd >> 2) & 0x7) + 3 | ||
- | dst_offset = ovln_fetch_bytes(dst, dst_offset, backward_fetch_offset, amount_of_bytes_to_fetch) | ||
- | continue | ||
- | if cmd & 0x40 == 0: # Covers commands 0x80 to 0xBF | ||
- | # Copy bytes from the compressed data array | ||
- | src_offset += 3 | ||
- | amount_to_copy = ((cmd >> 8) >> 6) & 0x3 | ||
- | ovln_copy_literal(dst, dst_offset, src, src_offset, amount_to_copy) | ||
- | src_offset += amount_to_copy | ||
- | dst_offset += amount_to_copy | ||
- | # Fetch bytes from previous decompressed data | ||
- | backward_fetch_offset = (((cmd >> 8) << 8) & 0x3F00) + ((cmd >> 16) & 0xFF) + 1 | ||
- | amount_of_bytes_to_fetch = (cmd & 0x3F) + 4 | ||
- | dst_offset = ovln_fetch_bytes(dst, dst_offset, backward_fetch_offset, amount_of_bytes_to_fetch) | ||
- | continue | ||
- | if cmd & 0x20 == 0: # Covers commands 0xC0 to 0xDF | ||
- | src_offset += 4 | ||
- | amount_to_copy = cmd & 0x3 | ||
- | ovln_copy_literal(dst, dst_offset, src, src_offset, amount_to_copy) | ||
- | src_offset += amount_to_copy | ||
- | dst_offset += amount_to_copy | ||
- | # Fetch bytes from previous decompressed data | ||
- | backward_fetch_offset = ((cmd << 12) & 0x10000) + (((cmd >> 8) << 8) & 0xFF00) + 1 + ((cmd >> 16) & 0xFF) | ||
- | amount_of_bytes_to_fetch = ((cmd << 6) & 0x300) + ((cmd >> 24) & 0xFF) + 5 | ||
- | dst_offset = ovln_fetch_bytes(dst, dst_offset, backward_fetch_offset, amount_of_bytes_to_fetch) | ||
- | continue | ||
- | src_offset += 1 | ||
- | if (cmd & 0xFF) < 0xFC: # Covers commands 0xE0 to 0xFB | ||
- | # Copy bytes from the compressed data array | ||
- | amount_to_copy = ((cmd & 0x1F) + 1) * 4 | ||
- | ovln_copy_literal(dst, dst_offset, src, src_offset, amount_to_copy) | ||
- | src_offset += amount_to_copy | ||
- | dst_offset += amount_to_copy | ||
- | continue | ||
- | if cmd & 3 != 0: # Copy any left-over bytes | ||
- | # Copy bytes from the compressed data array | ||
- | amount_to_copy = cmd & 0x3 | ||
- | ovln_copy_literal(dst, dst_offset, src, src_offset, amount_to_copy) | ||
- | src_offset += amount_to_copy | ||
- | dst_offset += amount_to_copy | ||
- | break # A command of 0xFC, 0xFD, 0xFE, or 0xFF will end the decompression routine. | ||
- | return dst | ||
- | </code> | ||
---- | ---- | ||