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