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 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 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 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 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 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 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 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 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 326 readU16(const unsigned char *ptr) 327 { 328 return ptr[0]+(ptr[1]<<8); 329 } 330 331 static unsigned long 332 readU32(const unsigned char *ptr) 333 { 334 return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24); 335 } 336 337 int 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 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 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