Rev 26 | Rev 30 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 26 | Rev 27 | ||
---|---|---|---|
Line 663... | Line 663... | ||
663 | size_t imageheader_offset = 0; |
663 | size_t imageheader_offset = 0; |
664 | size_t imagetrailer_offset = 0; |
664 | size_t imagetrailer_offset = 0; |
665 | fsentry_t **fsentries = NULL; // mallocated |
665 | fsentry_t **fsentries = NULL; // mallocated |
666 | size_t fsentry_count = 0; |
666 | size_t fsentry_count = 0; |
667 | fsentry_t *current_fsentry = NULL; |
667 | fsentry_t *current_fsentry = NULL; |
- | 668 | buffer_t decompression_dst; |
|
668 | size_t startupfile_blobsize = 0; |
669 | size_t startupfile_blobsize = 0; |
- | 670 | size_t compressed_blocksize; |
|
669 | struct utimbuf file_times = { 0, 0 }; |
671 | struct utimbuf file_times = { 0, 0 }; |
670 | void *reallocated_ptr; |
672 | void *reallocated_ptr; |
- | 673 | uint8_t *decompressor_out; |
|
- | 674 | uint8_t *decompressor_in; |
|
- | 675 | size_t decompressor_outlen; |
|
671 | size_t bootfile_blobsize = 0; |
676 | size_t bootfile_blobsize = 0; |
672 | size_t current_offset; |
677 | size_t current_offset; |
673 | size_t fsentry_index; |
678 | size_t fsentry_index; |
674 | size_t nearest_distance; |
679 | size_t nearest_distance; |
675 | size_t nearest_index; |
680 | size_t nearest_index; |
676 | size_t byte_index; |
681 | size_t byte_index; |
677 | buffer_t file; |
682 | buffer_t file; |
678 | FILE *fp; |
683 | FILE *fp; |
- | 684 | int cf; |
|
679 | 685 | ||
680 | // open and read IFS file |
686 | // open and read IFS file |
681 | if (!Buffer_ReadFromFile (&file, ifs_pathname)) |
687 | if (!Buffer_ReadFromFile (&file, ifs_pathname)) |
682 | DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
688 | DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
683 | 689 | ||
Line 688... | Line 694... | ||
688 | // parse file from start to end |
694 | // parse file from start to end |
689 | current_offset = 0; |
695 | current_offset = 0; |
690 | for (;;) |
696 | for (;;) |
691 | { |
697 | { |
692 | // does a startup header start here ? |
698 | // does a startup header start here ? |
- | 699 | if ((current_offset + sizeof (startup_header_t) < file.size) |
|
- | 700 | && (startup_header == NULL) |
|
693 |
|
701 | && (memcmp (&file.bytes[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
694 | { |
702 | { |
695 | startupheader_offset = current_offset; |
703 | startupheader_offset = current_offset; |
696 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; |
704 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; |
697 | 705 | ||
698 | // layout: |
706 | // layout: |
Line 704... | Line 712... | ||
704 | if (current_offset + startup_header->startup_size > file.size) |
712 | if (current_offset + startup_header->startup_size > file.size) |
705 | { |
713 | { |
706 | LOG_WARNING ("this IFS file is corrupted (startup trailer extends past end of file)"); |
714 | LOG_WARNING ("this IFS file is corrupted (startup trailer extends past end of file)"); |
707 | goto endofdata; |
715 | goto endofdata; |
708 | } |
716 | } |
- | 717 | ||
- | 718 | // take note of the image compression flags |
|
- | 719 | cf = startup_header->flags1 & STARTUP_HDR_FLAGS1_COMPRESS_MASK; |
|
709 | 720 | ||
710 | // locate the right startup trailer at the right offset |
721 | // locate the right startup trailer at the right offset |
711 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
722 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
712 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
723 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
713 | else // old V1 trailer |
724 | else // old V1 trailer |
714 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
725 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
715 | 726 | ||
716 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
727 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
717 | 728 | ||
718 | // write startup blob |
729 | // write startup blob |
719 | sprintf_s (outfile_pathname, sizeof (outfile_pathname), "%s/startup.bin", outdir); |
730 | sprintf_s (outfile_pathname, sizeof (outfile_pathname), "%s/startup.bin", outdir); |
720 | fopen_s (&fp, outfile_pathname, "wb"); |
731 | fopen_s (&fp, outfile_pathname, "wb"); |
721 | ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
732 | ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
722 | fwrite (&file.bytes[current_offset], 1, startupfile_blobsize, fp); |
733 | fwrite (&file.bytes[current_offset], 1, startupfile_blobsize, fp); |
723 | fclose (fp); |
734 | fclose (fp); |
724 | 735 | ||
725 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
736 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
726 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // jump over the startup trailer and reach the next segment |
737 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // jump over the startup trailer and reach the next segment |
727 | } |
738 | } |
728 | 739 | ||
729 | // else does an image header start here ? |
740 | // else does an image header start here ? |
- | 741 | else if ((current_offset + sizeof (image_header_t) < file.size) |
|
- | 742 | && (image_header == NULL) |
|
730 |
|
743 | && (((cf == STARTUP_HDR_FLAGS1_COMPRESS_NONE) && (memcmp (&file.bytes[current_offset], "imagefs", 7) == 0)) |
- | 744 | || (cf != STARTUP_HDR_FLAGS1_COMPRESS_NONE) && (startup_header->imagefs_size > 0))) |
|
731 | { |
745 | { |
732 | imageheader_offset = current_offset; |
746 | imageheader_offset = current_offset; |
733 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; |
747 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; |
- | 748 | ||
- | 749 | // should we decompress it ? |
|
- | 750 | if (cf != STARTUP_HDR_FLAGS1_COMPRESS_NONE) |
|
- | 751 | { |
|
- | 752 | // it appears mkifs compresses data in blocks, prefixed by 2-byte block size in BIG ENDIAN |
|
- | 753 | Buffer_InitWithSize (&decompression_dst, startup_header->imagefs_size * 11 / 10); // mallocate and add 10% for safety |
|
- | 754 | decompression_dst.size = 0; |
|
- | 755 | ||
- | 756 | if (cf == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
|
- | 757 | ASSERT (ucl_init () == UCL_E_OK, "UCL library initialization failed -- please recompile this tool with less aggressive optimizations"); |
|
- | 758 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
|
- | 759 | ASSERT (lzo_init () == LZO_E_OK, "LZO library initialization failed -- please recompile this tool with less aggressive optimizations"); |
|
- | 760 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
|
- | 761 | { |
|
- | 762 | LOG_WARNING ("unimplemented compression scheme: zlib (FIXME)"); |
|
- | 763 | goto endofdata; |
|
- | 764 | } |
|
- | 765 | else |
|
- | 766 | { |
|
- | 767 | LOG_WARNING ("unsupported compression flags: 0x%2x", cf); |
|
- | 768 | goto endofdata; |
|
- | 769 | } |
|
- | 770 | ||
- | 771 | // run the compressed payload (the imagefs) through the right decompression algorithm |
|
- | 772 | for (;;) |
|
- | 773 | { |
|
- | 774 | compressed_blocksize = (file.bytes[current_offset + 0] << 8) | (file.bytes[current_offset + 1] << 0); // read block size word (in big engian) |
|
- | 775 | current_offset += 2; // skip it |
|
- | 776 | if (compressed_blocksize == 0) |
|
- | 777 | break; // a nil block size means end of stream is reached |
|
- | 778 | LOG_DEBUG ("about to decompress block of %zd bytes", compressed_blocksize); |
|
- | 779 | decompressor_in = &file.bytes[current_offset]; |
|
- | 780 | decompressor_out = &decompression_dst.bytes[decompression_dst.size]; |
|
- | 781 | decompressor_outlen = 0; |
|
- | 782 | ||
- | 783 | if (cf == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
|
- | 784 | { |
|
- | 785 | // UCL compression. NOTE: the decompressor function used in startup-x86 is "ucl_nrv2b_decompress_8 / ucl_nrv2b_decompress_le16 / ucl_nrv2b_decompress_le32" |
|
- | 786 | static ucl_uint ucl_outlen; // have a different variable because of pointer size mismatch |
|
- | 787 | if (ucl_nrv2b_decompress_8 (decompressor_in, (ucl_uint) compressed_blocksize, decompressor_out, &ucl_outlen, NULL) != UCL_E_OK) |
|
- | 788 | { |
|
- | 789 | LOG_WARNING ("this IFS file is corrupted (UCL decompression failed)"); |
|
- | 790 | goto endofdata; |
|
- | 791 | } |
|
- | 792 | decompressor_outlen = ucl_outlen; |
|
- | 793 | } |
|
- | 794 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
|
- | 795 | { |
|
- | 796 | // LZO decompression. NOTE: mkifs uses the full LZO package, whereas I use minilzo. |
|
- | 797 | static lzo_uint lzo_outlen; // have a different variable because of pointer size mismatch |
|
- | 798 | if (lzo1x_decompress (decompressor_in, (lzo_uint) compressed_blocksize, decompressor_out, &lzo_outlen, NULL) != LZO_E_OK) |
|
- | 799 | { |
|
- | 800 | LOG_WARNING ("this IFS file is corrupted (UCL decompression failed)"); |
|
- | 801 | goto endofdata; |
|
- | 802 | } |
|
- | 803 | decompressor_outlen = lzo_outlen; |
|
- | 804 | } |
|
- | 805 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
|
- | 806 | ; // TODO |
|
- | 807 | ||
- | 808 | current_offset += compressed_blocksize; |
|
- | 809 | decompression_dst.size += decompressor_outlen; |
|
- | 810 | } |
|
- | 811 | ||
- | 812 | LOG_INFO ("decompressed %zd bytes into %zd bytes\n", file.size - imageheader_offset, decompression_dst.size); |
|
- | 813 | ||
- | 814 | // now place the decompressed buffer in the payload at the imagefs offset |
|
- | 815 | ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&file, imageheader_offset, &decompression_dst)); |
|
- | 816 | current_offset = imageheader_offset; // jump back to where we put the uncompressed data |
|
- | 817 | file.size = imageheader_offset + decompression_dst.size; // update IFS data size |
|
- | 818 | ||
- | 819 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; // fix the pointers that might have changed |
|
- | 820 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; // fix the pointers that might have changed |
|
- | 821 | } |
|
734 | 822 | ||
735 | // layout: |
823 | // layout: |
736 | // [IMAGE HEADER] |
824 | // [IMAGE HEADER] |
737 | // [image directory entries] |
825 | // [image directory entries] |
738 | // [smallest file blobs up to KERNEL] |
826 | // [smallest file blobs up to KERNEL] |