summaryrefslogtreecommitdiff
path: root/core/rllpack.inc
blob: 996486c7b323b7d76ed552b75928a3b7d34848c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
; -*- 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 (E)SI and EDI.
;
rllpack:
		push word .pmentry
		call simple_pm_call
		ret

		bits 32
.pmentry:
		push ecx
		push ebx
		push edx
		movzx ecx,cx
		movzx esi,si
.startseq:
		xor eax,eax		; 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 ecx
		cmp ah,al
		je .same
.diff:
		mov ah,al
		xor ebx,ebx
.plainbyte:
		inc ebx
		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 ebx
		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 ebx
		dec ecx
		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 esi			; Reload subsequent byte
		jmp .startseq
.done:
		pop edx
		pop ebx
		pop ecx
		ret

		bits 16
;
; rllunpack:
;	Unpack bytes from SI into EDI
;	On return (E)SI, EDI are updated and
;	(E)CX contains number of bytes output.
;
rllunpack:
		push word .pmentry
		call simple_pm_call
		ret

		bits 32
.pmentry:
		push edi
		movzx esi,si
		xor ecx,ecx
.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 ecx
		sub ecx,edi
		neg ecx
		ret

		bits 16