1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 FastLZ - lightning-fast lossless compression library
14
15 Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
16 Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
17 Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
18
19 Permission is hereby granted, free of charge, to any person obtaining a copy
20 of this software and associated documentation files (the "Software"), to deal
21 in the Software without restriction, including without limitation the rights
22 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 copies of the Software, and to permit persons to whom the Software is
24 furnished to do so, subject to the following conditions:
25
26 The above copyright notice and this permission notice shall be included in
27 all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 THE SOFTWARE.
36 */
37
38 #include "osdep.h"
39 #include "cudbg.h"
40 #include "cudbg_lib_common.h"
41 #include "fastlz.h"
42
43 #ifndef _KERNEL
44 #include <string.h>
45 #endif
46
47 static unsigned char sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10};
48
49 #define CUDBG_BLOCK_SIZE (63*1024)
50 #define CUDBG_CHUNK_BUF_LEN 16
51 #define CUDBG_MIN_COMPR_LEN 32 /*min data length for applying compression*/
52
53 /* for Adler-32 checksum algorithm, see RFC 1950 Section 8.2 */
54
55 #define ADLER32_BASE 65521
56
57 static unsigned long
update_adler32(unsigned long checksum,const void * buf,int len)58 update_adler32(unsigned long checksum,
59 const void *buf, int len)
60 {
61 const unsigned char *ptr = (const unsigned char *)buf;
62 unsigned long s1 = checksum & 0xffff;
63 unsigned long s2 = (checksum >> 16) & 0xffff;
64
65 while (len > 0) {
66 unsigned k = len < 5552 ? len : 5552;
67 len -= k;
68
69 while (k >= 8) {
70 s1 += *ptr++; s2 += s1;
71 s1 += *ptr++; s2 += s1;
72 s1 += *ptr++; s2 += s1;
73 s1 += *ptr++; s2 += s1;
74 s1 += *ptr++; s2 += s1;
75 s1 += *ptr++; s2 += s1;
76 s1 += *ptr++; s2 += s1;
77 s1 += *ptr++; s2 += s1;
78 k -= 8;
79 }
80
81 while (k-- > 0) {
82 s1 += *ptr++; s2 += s1;
83 }
84 s1 = s1 % ADLER32_BASE;
85 s2 = s2 % ADLER32_BASE;
86 }
87 return (s2 << 16) + s1;
88 }
89
90 int
write_magic(struct cudbg_buffer * _out_buff)91 write_magic(struct cudbg_buffer *_out_buff)
92 {
93 int rc;
94
95 rc = write_to_buf(_out_buff->data, _out_buff->size, &_out_buff->offset,
96 sixpack_magic, 8);
97
98 return rc;
99 }
100
101 int
write_to_buf(void * out_buf,u32 out_buf_size,u32 * offset,void * in_buf,u32 in_buf_size)102 write_to_buf(void *out_buf, u32 out_buf_size, u32 *offset, void *in_buf,
103 u32 in_buf_size)
104 {
105 int rc = 0;
106
107 if (*offset >= out_buf_size) {
108 rc = CUDBG_STATUS_OUTBUFF_OVERFLOW;
109 goto err;
110 }
111
112 memcpy((char *)out_buf + *offset, in_buf, in_buf_size);
113 *offset = *offset + in_buf_size;
114
115 err:
116 return rc;
117 }
118
119 int
read_from_buf(void * in_buf,u32 in_buf_size,u32 * offset,void * out_buf,u32 out_buf_size)120 read_from_buf(void *in_buf, u32 in_buf_size, u32 *offset, void *out_buf,
121 u32 out_buf_size)
122 {
123 if (in_buf_size - *offset < out_buf_size)
124 return 0;
125
126 memcpy((char *)out_buf, (char *)in_buf + *offset, out_buf_size);
127 *offset = *offset + out_buf_size;
128 return out_buf_size;
129 }
130
131 int
write_chunk_header(struct cudbg_buffer * _outbuf,int id,int options,unsigned long size,unsigned long checksum,unsigned long extra)132 write_chunk_header(struct cudbg_buffer *_outbuf, int id, int options,
133 unsigned long size, unsigned long checksum,
134 unsigned long extra)
135 {
136 unsigned char buffer[CUDBG_CHUNK_BUF_LEN];
137 int rc = 0;
138
139 buffer[0] = id & 255;
140 buffer[1] = (unsigned char)(id >> 8);
141 buffer[2] = options & 255;
142 buffer[3] = (unsigned char)(options >> 8);
143 buffer[4] = size & 255;
144 buffer[5] = (size >> 8) & 255;
145 buffer[6] = (size >> 16) & 255;
146 buffer[7] = (size >> 24) & 255;
147 buffer[8] = checksum & 255;
148 buffer[9] = (checksum >> 8) & 255;
149 buffer[10] = (checksum >> 16) & 255;
150 buffer[11] = (checksum >> 24) & 255;
151 buffer[12] = extra & 255;
152 buffer[13] = (extra >> 8) & 255;
153 buffer[14] = (extra >> 16) & 255;
154 buffer[15] = (extra >> 24) & 255;
155
156 rc = write_to_buf(_outbuf->data, _outbuf->size, &_outbuf->offset,
157 buffer, 16);
158
159 return rc;
160 }
161
162 int
write_compression_hdr(struct cudbg_buffer * pin_buff,struct cudbg_buffer * pout_buff)163 write_compression_hdr(struct cudbg_buffer *pin_buff,
164 struct cudbg_buffer *pout_buff)
165 {
166 struct cudbg_buffer tmp_buffer;
167 unsigned long fsize = pin_buff->size;
168 unsigned char *buffer;
169 unsigned long checksum;
170 int rc;
171 char *shown_name = "abc";
172
173 /* Always release inner scratch buffer, before releasing outer. */
174 rc = get_scratch_buff(pout_buff, 10, &tmp_buffer);
175
176 if (rc)
177 goto err;
178
179 buffer = (unsigned char *)tmp_buffer.data;
180
181 rc = write_magic(pout_buff);
182
183 if (rc)
184 goto err1;
185
186 /* chunk for File Entry */
187 buffer[0] = fsize & 255;
188 buffer[1] = (fsize >> 8) & 255;
189 buffer[2] = (fsize >> 16) & 255;
190 buffer[3] = (fsize >> 24) & 255;
191 buffer[4] = 0;
192 buffer[5] = 0;
193 buffer[6] = 0;
194 buffer[7] = 0;
195 buffer[8] = (strlen(shown_name)+1) & 255;
196 buffer[9] = (unsigned char)((strlen(shown_name)+1) >> 8);
197 checksum = 1L;
198 checksum = update_adler32(checksum, buffer, 10);
199 checksum = update_adler32(checksum, shown_name,
200 (int)strlen(shown_name)+1);
201
202 rc = write_chunk_header(pout_buff, 1, 0,
203 10+(unsigned long)strlen(shown_name)+1,
204 checksum, 0);
205
206 if (rc)
207 goto err1;
208
209 rc = write_to_buf(pout_buff->data, pout_buff->size,
210 &(pout_buff->offset), buffer, 10);
211
212 if (rc)
213 goto err1;
214
215 rc = write_to_buf(pout_buff->data, pout_buff->size,
216 &(pout_buff->offset), shown_name,
217 (u32)strlen(shown_name)+1);
218
219 if (rc)
220 goto err1;
221
222 err1:
223 release_scratch_buff(&tmp_buffer, pout_buff);
224 err:
225 return rc;
226 }
227
228 int
compress_buff(struct cudbg_buffer * pin_buff,struct cudbg_buffer * pout_buff)229 compress_buff(struct cudbg_buffer *pin_buff, struct cudbg_buffer *pout_buff)
230 {
231 struct cudbg_buffer tmp_buffer;
232 struct cudbg_hdr *cudbg_hdr;
233 unsigned long checksum;
234 unsigned char *result;
235 unsigned int bytes_read;
236 int chunk_size, level = 2, rc = 0;
237 int compress_method = 1;
238
239 bytes_read = pin_buff->size;
240 rc = get_scratch_buff(pout_buff, CUDBG_BLOCK_SIZE, &tmp_buffer);
241
242 if (rc)
243 goto err;
244
245 result = (unsigned char *)tmp_buffer.data;
246
247 if (bytes_read < 32)
248 compress_method = 0;
249
250 cudbg_hdr = (struct cudbg_hdr *) pout_buff->data;
251
252 switch (compress_method) {
253 case 1:
254 chunk_size = fastlz_compress_level(level, pin_buff->data,
255 bytes_read, result);
256
257 checksum = update_adler32(1L, result, chunk_size);
258
259 if ((chunk_size > 62000) && (cudbg_hdr->reserved[7] < (u32)
260 chunk_size)) /* 64512 */
261 cudbg_hdr->reserved[7] = (u32) chunk_size;
262
263 rc = write_chunk_header(pout_buff, 17, 1, chunk_size, checksum,
264 bytes_read);
265
266 if (rc)
267 goto err_put_buff;
268
269 rc = write_to_buf(pout_buff->data, pout_buff->size,
270 &pout_buff->offset, result, chunk_size);
271
272 if (rc)
273 goto err_put_buff;
274
275 break;
276
277 /* uncompressed, also fallback method */
278 case 0:
279 default:
280 checksum = update_adler32(1L, pin_buff->data, bytes_read);
281
282 rc = write_chunk_header(pout_buff, 17, 0, bytes_read, checksum,
283 bytes_read);
284
285 if (rc)
286 goto err_put_buff;
287
288 rc = write_to_buf(pout_buff->data, pout_buff->size,
289 &pout_buff->offset, pin_buff->data,
290 bytes_read);
291 if (rc)
292 goto err_put_buff;
293
294 break;
295 }
296
297 err_put_buff:
298 release_scratch_buff(&tmp_buffer, pout_buff);
299 err:
300 return rc;
301 }
302
303 /* return non-zero if magic sequence is detected */
304 /* warning: reset the read pointer to the beginning of the file */
305 int
detect_magic(struct cudbg_buffer * _c_buff)306 detect_magic(struct cudbg_buffer *_c_buff)
307 {
308 unsigned char buffer[8];
309 size_t bytes_read;
310 int c;
311
312 bytes_read = read_from_buf(_c_buff->data, _c_buff->size,
313 &_c_buff->offset, buffer, 8);
314
315 if (bytes_read < 8)
316 return 0;
317
318 for (c = 0; c < 8; c++)
319 if (buffer[c] != sixpack_magic[c])
320 return 0;
321
322 return -1;
323 }
324
325 static unsigned long
readU16(const unsigned char * ptr)326 readU16(const unsigned char *ptr)
327 {
328 return ptr[0]+(ptr[1]<<8);
329 }
330
331 static unsigned long
readU32(const unsigned char * ptr)332 readU32(const unsigned char *ptr)
333 {
334 return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
335 }
336
337 int
read_chunk_header(struct cudbg_buffer * pc_buff,int * pid,int * poptions,unsigned long * psize,unsigned long * pchecksum,unsigned long * pextra)338 read_chunk_header(struct cudbg_buffer *pc_buff, int *pid, int *poptions,
339 unsigned long *psize, unsigned long *pchecksum,
340 unsigned long *pextra)
341 {
342 unsigned char buffer[CUDBG_CHUNK_BUF_LEN];
343 int byte_r = read_from_buf(pc_buff->data, pc_buff->size,
344 &pc_buff->offset, buffer, 16);
345 if (byte_r == 0)
346 return 0;
347
348 *pid = readU16(buffer) & 0xffff;
349 *poptions = readU16(buffer+2) & 0xffff;
350 *psize = readU32(buffer+4) & 0xffffffff;
351 *pchecksum = readU32(buffer+8) & 0xffffffff;
352 *pextra = readU32(buffer+12) & 0xffffffff;
353 return 0;
354 }
355
356 int
validate_buffer(struct cudbg_buffer * compressed_buffer)357 validate_buffer(struct cudbg_buffer *compressed_buffer)
358 {
359 if (!detect_magic(compressed_buffer))
360 return CUDBG_STATUS_INVALID_BUFF;
361
362 return 0;
363 }
364
365 int
decompress_buffer(struct cudbg_buffer * pc_buff,struct cudbg_buffer * pd_buff)366 decompress_buffer(struct cudbg_buffer *pc_buff,
367 struct cudbg_buffer *pd_buff)
368 {
369 struct cudbg_buffer tmp_compressed_buffer;
370 struct cudbg_buffer tmp_decompressed_buffer;
371 unsigned char *compressed_buffer;
372 unsigned char *decompressed_buffer;
373 unsigned char buffer[CUDBG_MIN_COMPR_LEN];
374 unsigned long chunk_size;
375 unsigned long chunk_checksum;
376 unsigned long chunk_extra;
377 unsigned long checksum;
378 unsigned long total_extracted = 0;
379 unsigned long r;
380 unsigned long remaining;
381 unsigned long bytes_read;
382 u32 decompressed_size = 0;
383 int chunk_id, chunk_options, rc;
384
385 if (pd_buff->size < 2 * CUDBG_BLOCK_SIZE)
386 return CUDBG_STATUS_SMALL_BUFF;
387
388 rc = get_scratch_buff(pd_buff, CUDBG_BLOCK_SIZE,
389 &tmp_compressed_buffer);
390
391 if (rc)
392 goto err_cbuff;
393
394 rc = get_scratch_buff(pd_buff, CUDBG_BLOCK_SIZE,
395 &tmp_decompressed_buffer);
396 if (rc)
397 goto err_dcbuff;
398
399 compressed_buffer = (unsigned char *)tmp_compressed_buffer.data;
400 decompressed_buffer = (unsigned char *)tmp_decompressed_buffer.data;
401
402 /* main loop */
403
404 for (;;) {
405 if (pc_buff->offset > pc_buff->size)
406 break;
407
408 rc = read_chunk_header(pc_buff, &chunk_id, &chunk_options,
409 &chunk_size, &chunk_checksum,
410 &chunk_extra);
411 if (rc != 0)
412 break;
413
414 /* skip 8+16 */
415 if ((chunk_id == 1) && (chunk_size > 10) &&
416 (chunk_size < CUDBG_BLOCK_SIZE)) {
417
418 bytes_read = read_from_buf(pc_buff->data, pc_buff->size,
419 &pc_buff->offset, buffer,
420 chunk_size);
421
422 if (bytes_read == 0)
423 return 0;
424
425 checksum = update_adler32(1L, buffer, chunk_size);
426 if (checksum != chunk_checksum)
427 return CUDBG_STATUS_CHKSUM_MISSMATCH;
428
429 decompressed_size = (u32)readU32(buffer);
430
431 if (pd_buff->size < decompressed_size) {
432
433 pd_buff->size = 2 * CUDBG_BLOCK_SIZE +
434 decompressed_size;
435 pc_buff->offset -= chunk_size + 16;
436 return CUDBG_STATUS_SMALL_BUFF;
437 }
438 total_extracted = 0;
439
440 }
441
442 if (chunk_size > CUDBG_BLOCK_SIZE) {
443 /* Release old allocated memory */
444 release_scratch_buff(&tmp_decompressed_buffer, pd_buff);
445 release_scratch_buff(&tmp_compressed_buffer, pd_buff);
446
447 /* allocate new memory with chunk_size size */
448 rc = get_scratch_buff(pd_buff, chunk_size,
449 &tmp_compressed_buffer);
450 if (rc)
451 goto err_cbuff;
452
453 rc = get_scratch_buff(pd_buff, chunk_size,
454 &tmp_decompressed_buffer);
455 if (rc)
456 goto err_dcbuff;
457
458 compressed_buffer = (unsigned char *)tmp_compressed_buffer.data;
459 decompressed_buffer = (unsigned char *)tmp_decompressed_buffer.data;
460 }
461
462 if ((chunk_id == 17) && decompressed_size) {
463 /* uncompressed */
464 switch (chunk_options) {
465 /* stored, simply copy to output */
466 case 0:
467 total_extracted += chunk_size;
468 remaining = chunk_size;
469 checksum = 1L;
470 for (;;) {
471 /* Write a funtion for this */
472 r = (CUDBG_BLOCK_SIZE < remaining) ?
473 CUDBG_BLOCK_SIZE : remaining;
474 bytes_read =
475 read_from_buf(pc_buff->data,
476 pc_buff->size,
477 &pc_buff->offset, buffer,
478 r);
479
480 if (bytes_read == 0)
481 return 0;
482
483 write_to_buf(pd_buff->data,
484 pd_buff->size,
485 &pd_buff->offset, buffer,
486 bytes_read);
487 checksum = update_adler32(checksum,
488 buffer,
489 bytes_read);
490 remaining -= bytes_read;
491
492 /* verify everything is written
493 * correctly */
494 if (checksum != chunk_checksum)
495 return
496 CUDBG_STATUS_CHKSUM_MISSMATCH;
497 }
498
499 break;
500
501 /* compressed using FastLZ */
502 case 1:
503 bytes_read = read_from_buf(pc_buff->data,
504 pc_buff->size,
505 &pc_buff->offset,
506 compressed_buffer,
507 chunk_size);
508
509 if (bytes_read == 0)
510 return 0;
511
512 checksum = update_adler32(1L, compressed_buffer,
513 chunk_size);
514 total_extracted += chunk_extra;
515
516 /* verify that the chunk data is correct */
517 if (checksum != chunk_checksum) {
518 return CUDBG_STATUS_CHKSUM_MISSMATCH;
519 } else {
520 /* decompress and verify */
521 remaining =
522 fastlz_decompress(compressed_buffer,
523 chunk_size,
524 decompressed_buffer,
525 chunk_extra);
526
527 if (remaining != chunk_extra) {
528 rc =
529 CUDBG_STATUS_DECOMPRESS_FAIL;
530 goto err;
531 } else {
532 write_to_buf(pd_buff->data,
533 pd_buff->size,
534 &pd_buff->offset,
535 decompressed_buffer,
536 chunk_extra);
537 }
538 }
539 break;
540
541 default:
542 break;
543 }
544
545 }
546
547 }
548
549 err:
550 release_scratch_buff(&tmp_decompressed_buffer, pd_buff);
551 err_dcbuff:
552 release_scratch_buff(&tmp_compressed_buffer, pd_buff);
553
554 err_cbuff:
555 return rc;
556 }
557