This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| 
                    supercross_2000:ovln [2019/07/04 19:28] David created  | 
                
                    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 (arr[offset + 0] << 16) | (arr[offset + 1] << 8) | arr[offset + 2] | ||
| - | |||
| - | # get 4 bytes from the array and arrange them in little endian order. | ||
| - | def bytes_to_int_reversed(arr, offset): | ||
| - | arr_boundary = len(arr) - offset # for safety | ||
| - | if arr_boundary >= 4: | ||
| - | return (arr[offset + 3] << 24) | (arr[offset + 2] << 16) | (arr[offset + 1] << 8) | arr[offset] | ||
| - | elif arr_boundary == 3: | ||
| - | return (arr[offset + 2] << 16) | (arr[offset + 1] << 8) | arr[offset] | ||
| - | elif arr_boundary == 2: | ||
| - | return (arr[offset + 1] << 8) | arr[offset] | ||
| - | else: | ||
| - | return arr[offset] | ||
| - |  | ||
| - | 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> | ||
| ---- | ---- | ||