0.Intro
In my first article about
LZS implementation I did some mistakes. Here I'll fix it and describe some interesting facts not listed in previous article.
1. Mistake in Ficedula's article
Rigth version of Ficedula's article is
here. Main difference between two texts is in example section. In article on his homepage literal and reference bits were swapped, that's why example had conflicts with format's description.
2. Mistake in suggested offset calculation algorithm
I think, the main advantage of researching is understanding what a code fragment really doing and why. Following formula looks like monster:
real_offset = tail - ((tail - 18 - raw_offset) mod 4096)
What does it mean? I tried to simplify it in previous article, but made a mistake. Let's try to fix it.
First of all we should check effective offset range. Extracted raw offset lenght is integer between 0x0000 and 0x0fff. But effective offset range is moved by 0x12 bytes to higher addresses. That's why effective offset (I also will call it offset) range is 0x0012 - 0x1011.
So,
posOffs = (tail - 18 - raw_offset)
is value between tail - 0x1011 and tail - 0x0012.
Next, we calculate posOffs & 0x0fff (or posOffs % 4096, no matter). What does it mean? Let's draw a little:
lowest posOffs (2)
buffer | posOffs (1)
addr | | tail
| | | |
|----------------|----------------|----^--------^--|-^--^----------->
0x0000 0x1000 0x2000 0x3000
I splitted outgoing buffer on 4Kb pages especially for showing what is "posOffs & 0x0fff". As you can see, posOffs can be greater (or equal) or smaller than current page start address. In first case in result we receive offset to posOffs from beginning of current page. In second - offset from beginning of previous page. We'll call it relPosOffs. So, we should begin to read from tail - relPosOffs. relPosOffs is integer between 0x0000 and 0x0fff (as you can see, it addresses 4Kb buffer) that describes buffer mapping.
highest
addr of
posOffs
|
C A | tail
|<==========================|<============|<-0x12->|
|-----^---------^-----------------|---------^---^--------^----------->
0x0000 | 0x1000 | |
|==========================>|===========>|
D B
Ofset range A is mapped to range B, range C to range D in directions shown by arrows.
3. LZS implemented in FF8 (PC) does not support one special FF7 trick
There is no "repeated run" support in FF8 (PC).
But negative offsets are supported as listed in previous article.
I tested own implementation of FF8 (which compliant with native FF8 LZS unpacker) with files compressed by ficeLZS. In general FF8 supports only none-compression and 8-bit mode.
4. Uncomplete chunks
Files for compressing usually are not aligned for storing like LZS archives. That's why last chunks (control byte + literal/reference data) are usually shorter than it can be counted from control byte. Native FF8 code handles this case successfully. But when you write own implementation of FF8 algorithm, you should remember it.
5. Outro
That's all I can say about LZS unpacking in FF8. But FF8 hides a lot of interesting facts, algorythms, etc.