; -*- fundamental -*-
; -----------------------------------------------------------------------
;
;   Copyright 2004 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-255 	= (x-126) times subsequent byte
; 0		= end of data
;

		section .text

;
; rllpack:
;	Pack CX bytes from DS:SI into ES:DI
;	Returns updated SI, DI and CX = number of bytes output
;
rllpack:
		push ax
		push bx
		push cx
		push bp
		push di
.startseq:
		xor ax,ax		; Zero byte
		xor bx,bx		; Run length zero
		mov bp,di		; Pointer to header byte
		stosb			; Store header byte (might be zero)
		jcxz .done_null
.stdbyte:
		lodsb
		stosb
		dec cx
		cmp ah,al
		je .same
.diff:
		mov ah,al
		xor bx,bx
.plainbyte:
		inc bx
		inc byte [es:bp]
		jcxz .done
		jns .stdbyte
		jmp .startseq
.same:
		cmp bl,2
		jb .plainbyte
		; 3 bytes or more in a row, time to convert sequence
		sub byte [es:bp],bl
		jnz .normal
		dec di			; We killed a whole stretch, remove start byte
.normal:
		inc bx
		sub di,bx
		mov bp,di
		mov al,bl
		add al,126
		stosb
		mov al,ah
		stosb
.getrun:
		jcxz .done
		cmp bl,255-126
		jae .startseq
		lodsb
		cmp al,ah
		jne .nomatch
		inc bx
		inc byte [es:bp]
		dec cx
		jmp .getrun
.nomatch:
		dec si
		jmp .startseq
.done:
		xor al,al
		stosb
.done_null:
		pop dx
		sub dx,di
		neg dx
		pop bp
		pop cx
		pop bx
		pop ax
		ret
;
; rllunpack:
;	Unpack bytes from DS:SI into ES:DI
;	On return SI, DI are updated and CX contains number of bytes output
;
rllunpack:
		push ax
		push di
		xor cx,cx
.header:
		lodsb
		and al,al
		jz .done
		cmp al,129
		jae .isrun
		; Not a run
		mov cl,al
		rep movsb
		jmp .header
.isrun:
		sub al,126
		mov cl,al
		lodsb
		rep stosb
		jmp .header
.done:
		pop cx
		sub cx,di
		neg cx
		pop ax
		ret
