58 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			58 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | def hal_decompress(comp: bytes) -> bytes: | ||
|  |     """
 | ||
|  |     HAL decompression based on exhal by devinacker | ||
|  |     https://github.com/devinacker/exhal | ||
|  |     """
 | ||
|  |     inpos = 0 | ||
|  | 
 | ||
|  |     inval = 0 | ||
|  |     output = bytearray() | ||
|  |     while inval != 0xFF: | ||
|  |         remaining = 65536 - inpos | ||
|  |         if remaining < 1: | ||
|  |             return bytes() | ||
|  |         inval = comp[inpos] | ||
|  |         inpos += 1 | ||
|  |         if inval == 0xFF: | ||
|  |             break | ||
|  |         if (inval & 0xE0) == 0xE0: | ||
|  |             command = (inval >> 2) & 0x07 | ||
|  |             length = (((inval & 0x03) << 8) | comp[inpos]) + 1 | ||
|  |             inpos += 1 | ||
|  |         else: | ||
|  |             command = inval >> 5 | ||
|  |             length = (inval & 0x1F) + 1 | ||
|  |         if (command == 2 and ((len(output) + 2*length) > 65536)) or (len(output) + length) > 65536: | ||
|  |             return bytes() | ||
|  |         if command == 0: | ||
|  |             output.extend(comp[inpos:inpos+length]) | ||
|  |             inpos += length | ||
|  |         elif command == 1: | ||
|  |             output.extend([comp[inpos] for _ in range(length)]) | ||
|  |             inpos += 1 | ||
|  |         elif command == 2: | ||
|  |             output.extend([comp[x] for _ in range(length) for x in (inpos, inpos+1)]) | ||
|  |             inpos += 2 | ||
|  |         elif command == 3: | ||
|  |             output.extend([comp[inpos] + i for i in range(length)]) | ||
|  |             inpos += 1 | ||
|  |         elif command == 4 or command == 7: | ||
|  |             offset = (comp[inpos] << 8) | comp[inpos + 1] | ||
|  |             if (offset + length) > 65536: | ||
|  |                 return bytes() | ||
|  |             output.extend(output[offset:offset+length]) | ||
|  |             inpos += 2 | ||
|  |         elif command == 5: | ||
|  |             offset = (comp[inpos] << 8) | comp[inpos + 1] | ||
|  |             if (offset + length) > 65536: | ||
|  |                 return bytes() | ||
|  |             output.extend([int('{:08b}'.format(x)[::-1], 2) for x in output[offset:offset+length]]) | ||
|  |             inpos += 2 | ||
|  |         elif command == 6: | ||
|  |             offset = (comp[inpos] << 8) | comp[inpos + 1] | ||
|  |             if offset < length - 1: | ||
|  |                 return bytes() | ||
|  |             output.extend([output[offset - x] for x in range(length)]) | ||
|  |             inpos += 2 | ||
|  |     return bytes(output) |