; -*- fundamental -*- ---------------------------------------------------
;
;   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
;
;   This program is free software; you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
;   Boston MA 02111-1307, USA; either version 2 of the License, or
;   (at your option) any later version; incorporated herein by reference.
;
; -----------------------------------------------------------------------

;
; rllpack.inc
;
; Very simple RLL compressor/decompressor, used to pack binary structures
; together.
;
; Format of leading byte
; 1-128		= x verbatim bytes follow
; 129-223	= (x-126) times subsequent byte
; 224-255	= (x-224)*256+(next byte) times the following byte
; 0		= end of data
;
; These structures are stored *in reverse order* in high memory.
; High memory pointers point to one byte beyond the end.
;

		section .text

;
; rllpack:
;	Pack CX bytes from SI into EDI.
;	Returns updated SI and EDI.
;
rllpack:
		push word .pmentry
		call simple_pm_call
		ret

.pmentry:
		push cx
		push ebx
		push edx
.startseq:
		xor ax,ax		; Zero byte
		xor ebx,ebx		; Run length zero
		dec edi
		mov edx,edi		; Pointer to header byte
		mov [edi],al		; Create header byte
		jcxz .done		; If done, this was the terminator
.stdbyte:
		lodsb
		dec edi
		mov [edi],al
		dec cx
		cmp ah,al
		je .same
.diff:
		mov ah,al
		xor bx,bx
.plainbyte:
		inc bx
		inc byte [edx]
		jcxz .startseq
		jns .stdbyte
		jmp .startseq
.same:
		cmp bl,2
		jb .plainbyte
		; 3 bytes or more in a row, time to convert sequence
		sub [edx],bl
		jnz .normal
		inc edi			; We killed a whole stretch,
					; drop start byte
.normal:
		inc bx
		add edi,ebx		; Remove the stored run bytes
.getrun:
		jcxz .nomatch
		lodsb
		cmp al,ah
		jne .nomatch
		cmp bx,(256-224)*256-1	; Maximum run size
		jae .nomatch
		inc bx
		dec cx
		jmp .getrun
.nomatch:
		cmp bx,224-126
		jae .twobyte
.onebyte:
		add bl,126
		dec edi
		mov [edi],bl
		jmp .storebyte
.twobyte:
		add bh,224
		sub edi,2
		mov [edi],bx
.storebyte:
		dec edi
		mov [edi],ah
		dec si			; Reload subsequent byte
		jmp .startseq
.done:
		pop edx
		pop ebx
		pop cx
		ret
;
; rllunpack:
;	Unpack bytes from ESI into DI
;	On return ESI, DI are updated and CX contains number of bytes output.
;
rllunpack:
		push word .pmentry
		call simple_pm_call
		ret

.pmentry:
		push di
		xor cx,cx
.header:
		dec esi
		mov cl,[esi]
		jcxz .done
		cmp cl,129
		jae .isrun
		; Not a run
.copy:
		dec esi
		mov al,[esi]
		stosb
		loop .copy
		jmp .header
.isrun:
		cmp cl,224
		jae .longrun
		sub cl,126
.dorun:
		dec esi
		mov al,[esi]
		rep stosb
		jmp .header
.longrun:
		sub cl,224
		mov ch,cl
		dec esi
		mov cl,[esi]
		jmp .dorun
.done:
		pop cx
		sub cx,di
		neg cx
		ret
