|
9 | 9 | #include "common.h" |
10 | 10 | #include "lib/lz4/lz4.h" |
11 | 11 | #include "lib/lz4/lz4frame.h" |
| 12 | +#include "lib/lz4/lz4hc.h" |
12 | 13 | #include "lib/bz2/bzlib.h" |
13 | 14 | #include "lib/xz/xz.h" |
14 | 15 | #include "lib/sha/sha256.h" |
@@ -185,37 +186,76 @@ int compress_lz4(const uint8_t *in_data, size_t in_size, uint8_t **out_data, uin |
185 | 186 | *out_size = (uint32_t)compressed_size; |
186 | 187 | return 0; |
187 | 188 | } |
188 | | -int compress_lz4_le(const uint8_t *in_data, size_t in_size, uint8_t **out_data, uint32_t *out_size, compress_head data) { |
189 | | - int max_block_size = LZ4_compressBound((int)in_size); |
190 | | - |
191 | | - uint32_t total_max_size = 8 + max_block_size; |
192 | | - *out_data = (uint8_t *)malloc(total_max_size); |
193 | | - if (!*out_data) { |
194 | | - return -1; |
| 189 | +int compress_lz4_le( |
| 190 | + const uint8_t *in_data, |
| 191 | + size_t in_size, |
| 192 | + uint8_t **out_data, |
| 193 | + uint32_t *out_size, |
| 194 | + compress_head k_head |
| 195 | +) { |
| 196 | + |
| 197 | + size_t max_blocks = |
| 198 | + (in_size + LZ4_BLOCK_SIZE - 1) / LZ4_BLOCK_SIZE; |
| 199 | + // uint32_t max_blocks_1 = |
| 200 | + // ((uint32_t)k_head.magic[4]) |
| 201 | + // | ((uint32_t)k_head.magic[5] << 8) |
| 202 | + // | ((uint32_t)k_head.magic[6] << 16) |
| 203 | + // | ((uint32_t)k_head.magic[7] << 24); |
| 204 | + tools_logi("Calculated max blocks: %zu\n", max_blocks); |
| 205 | + size_t max_out = |
| 206 | + sizeof(uint32_t) + // MAGIC |
| 207 | + max_blocks * (sizeof(uint32_t) + // block header |
| 208 | + LZ4_compressBound(LZ4_BLOCK_SIZE)); |
| 209 | + |
| 210 | + uint8_t *out = malloc(max_out); |
| 211 | + if (!out) { |
| 212 | + tools_loge("Failed to allocate memory for LZ4 compression,size: %zu\n",max_out); |
| 213 | + return -2; |
195 | 214 | } |
196 | 215 |
|
197 | | - (*out_data)[0] = data.magic[0]; |
198 | | - (*out_data)[1] = data.magic[1]; |
199 | | - (*out_data)[2] = data.magic[2]; |
200 | | - (*out_data)[3] = data.magic[3]; |
201 | | - (*out_data)[4] = data.magic[4]; |
202 | | - (*out_data)[5] = data.magic[5]; |
203 | | - (*out_data)[6] = data.magic[6]; |
204 | | - (*out_data)[7] = data.magic[7]; |
205 | | - |
206 | | - int compressed_bytes = LZ4_compress_default( |
207 | | - (const char*)in_data, |
208 | | - (char*)(*out_data + 8), |
209 | | - (int)in_size, |
210 | | - max_block_size |
211 | | - ); |
212 | | - if (compressed_bytes <= 0) { |
213 | | - free(*out_data); |
214 | | - *out_data = NULL; |
215 | | - return -2; |
| 216 | + size_t out_off = 0; |
| 217 | + |
| 218 | + /* write MAGIC */ |
| 219 | + uint32_t magic = LZ4_MAGIC; |
| 220 | + memcpy(out + out_off, &magic, sizeof(magic)); |
| 221 | + out_off += sizeof(magic); |
| 222 | + |
| 223 | + size_t in_off = 0; |
| 224 | + |
| 225 | + while (in_off < in_size) { |
| 226 | + size_t chunk_size = in_size - in_off; |
| 227 | + if (chunk_size > LZ4_BLOCK_SIZE) |
| 228 | + chunk_size = LZ4_BLOCK_SIZE; |
| 229 | + |
| 230 | + int max_dst = LZ4_compressBound((int)chunk_size); |
| 231 | + |
| 232 | + int compressed = LZ4_compress_HC( |
| 233 | + (const char *)(in_data + in_off), |
| 234 | + (char *)(out + out_off + sizeof(uint32_t)), |
| 235 | + (int)chunk_size, |
| 236 | + max_dst, |
| 237 | + LZ4HC_CLEVEL |
| 238 | + ); |
| 239 | + |
| 240 | + if (compressed <= 0) { |
| 241 | + tools_loge("LZ4 compression failed for block at offset %zu\n", in_off); |
| 242 | + free(out); |
| 243 | + return -3; |
| 244 | + } |
| 245 | + |
| 246 | + /* write compressed block size */ |
| 247 | + uint32_t csz = (uint32_t)compressed; |
| 248 | + memcpy(out + out_off, &csz, sizeof(csz)); |
| 249 | + out_off += sizeof(uint32_t); |
| 250 | + |
| 251 | + /* advance over compressed data */ |
| 252 | + out_off += compressed; |
| 253 | + in_off += chunk_size; |
216 | 254 | } |
217 | | - *out_size = 8 + (uint32_t)compressed_bytes; |
218 | | - return 0; |
| 255 | + |
| 256 | + *out_data = out; |
| 257 | + *out_size = (uint32_t)out_off; |
| 258 | + return 0; |
219 | 259 | } |
220 | 260 |
|
221 | 261 | // int compress_zstd(const uint8_t *in_data, size_t in_size, uint8_t **out_data, uint32_t *out_size) { |
@@ -326,7 +366,7 @@ int auto_depress(const uint8_t *data, size_t size, const char *out_path) { |
326 | 366 | compress_head k_head; |
327 | 367 | memcpy(&k_head, data, sizeof(k_head)); |
328 | 368 | int method = detect_compress_method(k_head); |
329 | | - |
| 369 | + tools_logi("Auto-detect compression method: %d\n", method); |
330 | 370 |
|
331 | 371 | if (method == 1) { //Gzip |
332 | 372 | tools_logi("Detected GZIP compressed kernel.\n"); |
@@ -367,29 +407,104 @@ int auto_depress(const uint8_t *data, size_t size, const char *out_path) { |
367 | 407 | return 0; |
368 | 408 | } |
369 | 409 | } |
| 410 | + |
| 411 | + if (method == 3) { |
| 412 | + tools_logi("Probing LZ4 Legacy (block-based)...\n"); |
370 | 413 |
|
371 | | - if (method == 3) { |
372 | | - tools_logi("Detected LZ4 Legacy. Decompressing with LZ4 Block API...\n"); |
| 414 | + const uint8_t *p = (const uint8_t *)data; |
| 415 | + const uint8_t *end = p + size; |
373 | 416 |
|
374 | | - const char* compressed_ptr = (const char*)data + 8; |
375 | | - int compressed_size = (int)size - 8; |
376 | 417 |
|
377 | | - size_t dstCapacity = 64 * 1024 * 1024; |
378 | | - void* dst = malloc(dstCapacity); |
379 | | - if (!dst) return -1; |
| 418 | + if (size < 4) |
| 419 | + goto not_lz4; |
380 | 420 |
|
381 | | - int ret = LZ4_decompress_safe(compressed_ptr, (char*)dst, compressed_size, (int)dstCapacity); |
382 | 421 |
|
383 | | - if (ret < 0) { |
384 | | - tools_loge("LZ4 Legacy decompression failed.\n"); |
385 | | - free(dst); |
386 | | - return -1; |
387 | | - } else { |
388 | | - tools_logi("Decompressed: %d bytes\n", ret); |
389 | | - write_data_to_file(out_path, (uint8_t*)dst, (uint32_t)ret); |
390 | | - free(dst); |
391 | | - return 0; |
| 422 | + if (*(uint32_t *)p != LZ4_MAGIC) |
| 423 | + goto not_lz4; |
| 424 | + |
| 425 | + p += 4; |
| 426 | + |
| 427 | + size_t out_cap = 64 * 1024 * 1024; |
| 428 | + uint8_t *out = malloc(out_cap); |
| 429 | + if (!out) |
| 430 | + goto not_lz4; |
| 431 | + |
| 432 | + size_t out_off = 0; |
| 433 | + |
| 434 | + uint8_t *block_out = malloc(LZ4_BLOCK_SIZE); |
| 435 | + if (!block_out) { |
| 436 | + free(out); |
| 437 | + goto not_lz4; |
| 438 | + } |
| 439 | + |
| 440 | + int decoded_any = 0; |
| 441 | + while (1) { |
| 442 | + uint32_t block_size; |
| 443 | + |
| 444 | + if (p + 4 > end) |
| 445 | + break; |
| 446 | + |
| 447 | + memcpy(&block_size, p, 4); |
| 448 | + p += 4; |
| 449 | + |
| 450 | + if (block_size == 0) |
| 451 | + break; |
| 452 | + |
| 453 | + if (block_size > LZ4_compressBound(LZ4_BLOCK_SIZE)) |
| 454 | + goto fail; |
| 455 | + |
| 456 | + if (p + block_size > end) |
| 457 | + goto fail; |
| 458 | + |
| 459 | + int decoded = LZ4_decompress_safe( |
| 460 | + (const char *)p, |
| 461 | + (char *)block_out, |
| 462 | + (int)block_size, |
| 463 | + LZ4_BLOCK_SIZE |
| 464 | + ); |
| 465 | + |
| 466 | + if (decoded < 0) |
| 467 | + goto fail; |
| 468 | + |
| 469 | + decoded_any = 1; |
| 470 | + |
| 471 | + if (out_off + (size_t)decoded > out_cap) { |
| 472 | + size_t new_cap = out_cap * 2; |
| 473 | + while (new_cap < out_off + (size_t)decoded) |
| 474 | + new_cap *= 2; |
| 475 | + |
| 476 | + uint8_t *tmp = realloc(out, new_cap); |
| 477 | + if (!tmp) |
| 478 | + goto fail; |
| 479 | + |
| 480 | + out = tmp; |
| 481 | + out_cap = new_cap; |
| 482 | + } |
| 483 | + |
| 484 | + memcpy(out + out_off, block_out, (size_t)decoded); |
| 485 | + out_off += (size_t)decoded; |
| 486 | + |
| 487 | + p += block_size; |
392 | 488 | } |
| 489 | + |
| 490 | + |
| 491 | + if (!decoded_any) |
| 492 | + goto fail; |
| 493 | + |
| 494 | + tools_logi("LZ4 block decompressed: %zu bytes\n", out_off); |
| 495 | + write_data_to_file(out_path, out, (uint32_t)out_off); |
| 496 | + |
| 497 | + free(block_out); |
| 498 | + free(out); |
| 499 | + return 0; |
| 500 | + |
| 501 | + fail: |
| 502 | + free(block_out); |
| 503 | + free(out); |
| 504 | + |
| 505 | + not_lz4: |
| 506 | + |
| 507 | + tools_logi("Not LZ4 block format, fallback.\n"); |
393 | 508 | } |
394 | 509 |
|
395 | 510 | // till now no kernel use this |
@@ -691,7 +806,7 @@ int repack_bootimg(const char *orig_boot_path, |
691 | 806 | return -1; |
692 | 807 | } |
693 | 808 | } |
694 | | - |
| 809 | + tools_logi("Final kernel size after compression (if applied): %u bytes\n", final_k_size); |
695 | 810 | uint32_t old_k_aligned = ALIGN(hdr.kernel_size, page_size); |
696 | 811 | uint32_t rest_data_offset = page_size + old_k_aligned; |
697 | 812 | uint32_t rest_data_size = (total_size > rest_data_offset) ? (total_size - rest_data_offset) : 0; |
|
0 commit comments