]> git.saurik.com Git - apple/xnu.git/blob - libsa/mkext.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / libsa / mkext.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <string.h>
23 #if KERNEL
24 #include <libsa/mkext.h>
25 #include <libsa/stdlib.h>
26 #else
27 #include <Kernel/libsa/mkext.h>
28 #include <stdlib.h>
29 #endif /* KERNEL */
30
31 #define BASE 65521L /* largest prime smaller than 65536 */
32 #define NMAX 5000
33 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
34
35 #define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
36 #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
37 #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
38 #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
39 #define DO16(buf) DO8(buf,0); DO8(buf,8);
40
41 __private_extern__ u_int32_t
42 adler32(uint8_t *buf, int32_t len)
43 {
44 unsigned long s1 = 1; // adler & 0xffff;
45 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
46 int k;
47
48 while (len > 0) {
49 k = len < NMAX ? len : NMAX;
50 len -= k;
51 while (k >= 16) {
52 DO16(buf);
53 buf += 16;
54 k -= 16;
55 }
56 if (k != 0) do {
57 s1 += *buf++;
58 s2 += s1;
59 } while (--k);
60 s1 %= BASE;
61 s2 %= BASE;
62 }
63 return (s2 << 16) | s1;
64 }
65
66
67 /**************************************************************
68 LZSS.C -- A Data Compression Program
69 ***************************************************************
70 4/6/1989 Haruhiko Okumura
71 Use, distribute, and modify this program freely.
72 Please send me your improved versions.
73 PC-VAN SCIENCE
74 NIFTY-Serve PAF01022
75 CompuServe 74050,1022
76
77 **************************************************************/
78
79 #define N 4096 /* size of ring buffer - must be power of 2 */
80 #define F 18 /* upper limit for match_length */
81 #define THRESHOLD 2 /* encode string into position and length
82 if match_length is greater than this */
83 #define NIL N /* index for root of binary search trees */
84
85 struct encode_state {
86 /*
87 * left & right children & parent. These constitute binary search trees.
88 */
89 int lchild[N + 1], rchild[N + 257], parent[N + 1];
90
91 /* ring buffer of size N, with extra F-1 bytes to aid string comparison */
92 u_int8_t text_buf[N + F - 1];
93
94 /*
95 * match_length of longest match.
96 * These are set by the insert_node() procedure.
97 */
98 int match_position, match_length;
99 };
100
101
102 __private_extern__ int
103 decompress_lzss(u_int8_t *dst, u_int8_t *src, u_int32_t srclen)
104 {
105 /* ring buffer of size N, with extra F-1 bytes to aid string comparison */
106 u_int8_t text_buf[N + F - 1];
107 u_int8_t *dststart = dst;
108 u_int8_t *srcend = src + srclen;
109 int i, j, k, r, c;
110 unsigned int flags;
111
112 dst = dststart;
113 srcend = src + srclen;
114 for (i = 0; i < N - F; i++)
115 text_buf[i] = ' ';
116 r = N - F;
117 flags = 0;
118 for ( ; ; ) {
119 if (((flags >>= 1) & 0x100) == 0) {
120 if (src < srcend) c = *src++; else break;
121 flags = c | 0xFF00; /* uses higher byte cleverly */
122 } /* to count eight */
123 if (flags & 1) {
124 if (src < srcend) c = *src++; else break;
125 *dst++ = c;
126 text_buf[r++] = c;
127 r &= (N - 1);
128 } else {
129 if (src < srcend) i = *src++; else break;
130 if (src < srcend) j = *src++; else break;
131 i |= ((j & 0xF0) << 4);
132 j = (j & 0x0F) + THRESHOLD;
133 for (k = 0; k <= j; k++) {
134 c = text_buf[(i + k) & (N - 1)];
135 *dst++ = c;
136 text_buf[r++] = c;
137 r &= (N - 1);
138 }
139 }
140 }
141
142 return dst - dststart;
143 }
144
145 #if !KERNEL
146
147 /*
148 * initialize state, mostly the trees
149 *
150 * For i = 0 to N - 1, rchild[i] and lchild[i] will be the right and left
151 * children of node i. These nodes need not be initialized. Also, parent[i]
152 * is the parent of node i. These are initialized to NIL (= N), which stands
153 * for 'not used.' For i = 0 to 255, rchild[N + i + 1] is the root of the
154 * tree for strings that begin with character i. These are initialized to NIL.
155 * Note there are 256 trees. */
156 static void init_state(struct encode_state *sp)
157 {
158 int i;
159
160 bzero(sp, sizeof(*sp));
161
162 for (i = 0; i < N - F; i++)
163 sp->text_buf[i] = ' ';
164 for (i = N + 1; i <= N + 256; i++)
165 sp->rchild[i] = NIL;
166 for (i = 0; i < N; i++)
167 sp->parent[i] = NIL;
168 }
169
170 /*
171 * Inserts string of length F, text_buf[r..r+F-1], into one of the trees
172 * (text_buf[r]'th tree) and returns the longest-match position and length
173 * via the global variables match_position and match_length.
174 * If match_length = F, then removes the old node in favor of the new one,
175 * because the old one will be deleted sooner. Note r plays double role,
176 * as tree node and position in buffer.
177 */
178 static void insert_node(struct encode_state *sp, int r)
179 {
180 int i, p, cmp;
181 u_int8_t *key;
182
183 cmp = 1;
184 key = &sp->text_buf[r];
185 p = N + 1 + key[0];
186 sp->rchild[r] = sp->lchild[r] = NIL;
187 sp->match_length = 0;
188 for ( ; ; ) {
189 if (cmp >= 0) {
190 if (sp->rchild[p] != NIL)
191 p = sp->rchild[p];
192 else {
193 sp->rchild[p] = r;
194 sp->parent[r] = p;
195 return;
196 }
197 } else {
198 if (sp->lchild[p] != NIL)
199 p = sp->lchild[p];
200 else {
201 sp->lchild[p] = r;
202 sp->parent[r] = p;
203 return;
204 }
205 }
206 for (i = 1; i < F; i++) {
207 if ((cmp = key[i] - sp->text_buf[p + i]) != 0)
208 break;
209 }
210 if (i > sp->match_length) {
211 sp->match_position = p;
212 if ((sp->match_length = i) >= F)
213 break;
214 }
215 }
216 sp->parent[r] = sp->parent[p];
217 sp->lchild[r] = sp->lchild[p];
218 sp->rchild[r] = sp->rchild[p];
219 sp->parent[sp->lchild[p]] = r;
220 sp->parent[sp->rchild[p]] = r;
221 if (sp->rchild[sp->parent[p]] == p)
222 sp->rchild[sp->parent[p]] = r;
223 else
224 sp->lchild[sp->parent[p]] = r;
225 sp->parent[p] = NIL; /* remove p */
226 }
227
228 /* deletes node p from tree */
229 static void delete_node(struct encode_state *sp, int p)
230 {
231 int q;
232
233 if (sp->parent[p] == NIL)
234 return; /* not in tree */
235 if (sp->rchild[p] == NIL)
236 q = sp->lchild[p];
237 else if (sp->lchild[p] == NIL)
238 q = sp->rchild[p];
239 else {
240 q = sp->lchild[p];
241 if (sp->rchild[q] != NIL) {
242 do {
243 q = sp->rchild[q];
244 } while (sp->rchild[q] != NIL);
245 sp->rchild[sp->parent[q]] = sp->lchild[q];
246 sp->parent[sp->lchild[q]] = sp->parent[q];
247 sp->lchild[q] = sp->lchild[p];
248 sp->parent[sp->lchild[p]] = q;
249 }
250 sp->rchild[q] = sp->rchild[p];
251 sp->parent[sp->rchild[p]] = q;
252 }
253 sp->parent[q] = sp->parent[p];
254 if (sp->rchild[sp->parent[p]] == p)
255 sp->rchild[sp->parent[p]] = q;
256 else
257 sp->lchild[sp->parent[p]] = q;
258 sp->parent[p] = NIL;
259 }
260
261 __private_extern__ u_int8_t *
262 compress_lzss(u_int8_t *dst, u_int32_t dstlen, u_int8_t *src, u_int32_t srcLen)
263 {
264 /* Encoding state, mostly tree but some current match stuff */
265 struct encode_state *sp;
266
267 int i, c, len, r, s, last_match_length, code_buf_ptr;
268 u_int8_t code_buf[17], mask;
269 u_int8_t *srcend = src + srcLen;
270 u_int8_t *dstend = dst + dstlen;
271
272 /* initialize trees */
273 sp = (struct encode_state *) malloc(sizeof(*sp));
274 init_state(sp);
275
276 /*
277 * code_buf[1..16] saves eight units of code, and code_buf[0] works
278 * as eight flags, "1" representing that the unit is an unencoded
279 * letter (1 byte), "0" a position-and-length pair (2 bytes).
280 * Thus, eight units require at most 16 bytes of code.
281 */
282 code_buf[0] = 0;
283 code_buf_ptr = mask = 1;
284
285 /* Clear the buffer with any character that will appear often. */
286 s = 0; r = N - F;
287
288 /* Read F bytes into the last F bytes of the buffer */
289 for (len = 0; len < F && src < srcend; len++)
290 sp->text_buf[r + len] = *src++;
291 if (!len)
292 return (void *) 0; /* text of size zero */
293
294 /*
295 * Insert the F strings, each of which begins with one or more
296 * 'space' characters. Note the order in which these strings are
297 * inserted. This way, degenerate trees will be less likely to occur.
298 */
299 for (i = 1; i <= F; i++)
300 insert_node(sp, r - i);
301
302 /*
303 * Finally, insert the whole string just read.
304 * The global variables match_length and match_position are set.
305 */
306 insert_node(sp, r);
307 do {
308 /* match_length may be spuriously long near the end of text. */
309 if (sp->match_length > len)
310 sp->match_length = len;
311 if (sp->match_length <= THRESHOLD) {
312 sp->match_length = 1; /* Not long enough match. Send one byte. */
313 code_buf[0] |= mask; /* 'send one byte' flag */
314 code_buf[code_buf_ptr++] = sp->text_buf[r]; /* Send uncoded. */
315 } else {
316 /* Send position and length pair. Note match_length > THRESHOLD. */
317 code_buf[code_buf_ptr++] = (u_int8_t) sp->match_position;
318 code_buf[code_buf_ptr++] = (u_int8_t)
319 ( ((sp->match_position >> 4) & 0xF0)
320 | (sp->match_length - (THRESHOLD + 1)) );
321 }
322 if ((mask <<= 1) == 0) { /* Shift mask left one bit. */
323 /* Send at most 8 units of code together */
324 for (i = 0; i < code_buf_ptr; i++)
325 if (dst < dstend)
326 *dst++ = code_buf[i];
327 else
328 return (void *) 0;
329 code_buf[0] = 0;
330 code_buf_ptr = mask = 1;
331 }
332 last_match_length = sp->match_length;
333 for (i = 0; i < last_match_length && src < srcend; i++) {
334 delete_node(sp, s); /* Delete old strings and */
335 c = *src++;
336 sp->text_buf[s] = c; /* read new bytes */
337
338 /*
339 * If the position is near the end of buffer, extend the buffer
340 * to make string comparison easier.
341 */
342 if (s < F - 1)
343 sp->text_buf[s + N] = c;
344
345 /* Since this is a ring buffer, increment the position modulo N. */
346 s = (s + 1) & (N - 1);
347 r = (r + 1) & (N - 1);
348
349 /* Register the string in text_buf[r..r+F-1] */
350 insert_node(sp, r);
351 }
352 while (i++ < last_match_length) {
353 delete_node(sp, s);
354
355 /* After the end of text, no need to read, */
356 s = (s + 1) & (N - 1);
357 r = (r + 1) & (N - 1);
358 /* but buffer may not be empty. */
359 if (--len)
360 insert_node(sp, r);
361 }
362 } while (len > 0); /* until length of string to be processed is zero */
363
364 if (code_buf_ptr > 1) { /* Send remaining code. */
365 for (i = 0; i < code_buf_ptr; i++)
366 if (dst < dstend)
367 *dst++ = code_buf[i];
368 else
369 return (void *) 0;
370 }
371
372 return dst;
373 }
374
375 #endif /* !KERNEL */
376