File indexing completed on 2025-02-02 04:26:01
0001 /* Copyright 2015 the unarr project authors (see AUTHORS file). 0002 License: LGPLv3 */ 0003 0004 #include "rar.h" 0005 0006 static void rar_close(ar_archive *ar) 0007 { 0008 ar_archive_rar *rar = (ar_archive_rar *)ar; 0009 free(rar->entry.name); 0010 rar_clear_uncompress(&rar->uncomp); 0011 } 0012 0013 static bool rar_parse_entry(ar_archive *ar, off64_t offset) 0014 { 0015 ar_archive_rar *rar = (ar_archive_rar *)ar; 0016 struct rar_header header; 0017 struct rar_entry entry; 0018 bool out_of_order = offset != ar->entry_offset_next; 0019 0020 if (!ar_seek(ar->stream, offset, SEEK_SET)) { 0021 warn("Couldn't seek to offset %" PRIi64, offset); 0022 return false; 0023 } 0024 0025 for (;;) { 0026 ar->entry_offset = ar_tell(ar->stream); 0027 ar->entry_size_uncompressed = 0; 0028 0029 if (!rar_parse_header(ar, &header)) 0030 return false; 0031 0032 ar->entry_offset_next = ar->entry_offset + header.size + header.datasize; 0033 if (ar->entry_offset_next < ar->entry_offset + header.size) { 0034 warn("Integer overflow due to overly large data size"); 0035 return false; 0036 } 0037 0038 switch (header.type) { 0039 case TYPE_MAIN_HEADER: 0040 if ((header.flags & MHD_PASSWORD)) { 0041 warn("Encrypted archives aren't supported"); 0042 return false; 0043 } 0044 ar_skip(ar->stream, 6 /* reserved data */); 0045 if ((header.flags & MHD_ENCRYPTVER)) { 0046 log("MHD_ENCRYPTVER is set"); 0047 ar_skip(ar->stream, 1); 0048 } 0049 if ((header.flags & MHD_COMMENT)) 0050 log("MHD_COMMENT is set"); 0051 if (ar_tell(ar->stream) - ar->entry_offset > header.size) { 0052 warn("Invalid RAR header size: %d", header.size); 0053 return false; 0054 } 0055 rar->archive_flags = header.flags; 0056 break; 0057 0058 case TYPE_FILE_ENTRY: 0059 if (!rar_parse_header_entry(rar, &header, &entry)) 0060 return false; 0061 if ((header.flags & LHD_PASSWORD)) 0062 warn("Encrypted entries will fail to uncompress"); 0063 if ((header.flags & LHD_DIRECTORY) == LHD_DIRECTORY) { 0064 if (header.datasize == 0) { 0065 log("Skipping directory entry \"%s\"", rar_get_name(ar)); 0066 break; 0067 } 0068 warn("Can't skip directory entries containing data"); 0069 } 0070 if ((header.flags & (LHD_SPLIT_BEFORE | LHD_SPLIT_AFTER))) 0071 warn("Splitting files isn't really supported"); 0072 ar->entry_size_uncompressed = (size_t)entry.size; 0073 ar->entry_filetime = ar_conv_dosdate_to_filetime(entry.dosdate); 0074 if (!rar->entry.solid || rar->entry.method == METHOD_STORE || out_of_order) { 0075 rar_clear_uncompress(&rar->uncomp); 0076 memset(&rar->solid, 0, sizeof(rar->solid)); 0077 } 0078 else { 0079 br_clear_leftover_bits(&rar->uncomp); 0080 } 0081 0082 rar->solid.restart = rar->entry.solid && (out_of_order || !rar->solid.part_done); 0083 rar->solid.part_done = !ar->entry_size_uncompressed; 0084 rar->progress.data_left = (size_t)header.datasize; 0085 rar->progress.bytes_done = 0; 0086 rar->progress.crc = 0; 0087 0088 /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ 0089 if (!rar_check_header_crc(ar)) 0090 warn("Invalid header checksum @%" PRIi64, ar->entry_offset); 0091 if (ar_tell(ar->stream) != ar->entry_offset + rar->entry.header_size) { 0092 warn("Couldn't seek to offset %" PRIi64, ar->entry_offset + rar->entry.header_size); 0093 return false; 0094 } 0095 return true; 0096 0097 case TYPE_NEWSUB: 0098 log("Skipping newsub header @%" PRIi64, ar->entry_offset); 0099 break; 0100 0101 case TYPE_END_OF_ARCHIVE: 0102 ar->at_eof = true; 0103 return false; 0104 0105 default: 0106 log("Unknown RAR header type %02x", header.type); 0107 break; 0108 } 0109 0110 /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ 0111 if (!rar_check_header_crc(ar)) 0112 warn("Invalid header checksum @%" PRIi64, ar->entry_offset); 0113 if (!ar_seek(ar->stream, ar->entry_offset_next, SEEK_SET)) { 0114 warn("Couldn't seek to offset %" PRIi64, ar->entry_offset_next); 0115 return false; 0116 } 0117 } 0118 } 0119 0120 static bool rar_copy_stored(ar_archive_rar *rar, void *buffer, size_t count) 0121 { 0122 if (count > rar->progress.data_left) { 0123 warn("Unexpected EOS in stored data"); 0124 return false; 0125 } 0126 if (ar_read(rar->super.stream, buffer, count) != count) { 0127 warn("Unexpected EOF in stored data"); 0128 return false; 0129 } 0130 rar->progress.data_left -= count; 0131 rar->progress.bytes_done += count; 0132 return true; 0133 } 0134 0135 static bool rar_restart_solid(ar_archive *ar) 0136 { 0137 ar_archive_rar *rar = (ar_archive_rar *)ar; 0138 off64_t current_offset = ar->entry_offset; 0139 log("Restarting decompression for solid entry"); 0140 if (!ar_parse_entry_at(ar, ar->entry_offset_first)) { 0141 ar_parse_entry_at(ar, current_offset); 0142 return false; 0143 } 0144 while (ar->entry_offset < current_offset) { 0145 size_t size = ar->entry_size_uncompressed; 0146 rar->solid.restart = false; 0147 while (size > 0) { 0148 unsigned char buffer[1024]; 0149 size_t count = smin(size, sizeof(buffer)); 0150 if (!ar_entry_uncompress(ar, buffer, count)) { 0151 ar_parse_entry_at(ar, current_offset); 0152 return false; 0153 } 0154 size -= count; 0155 } 0156 if (!ar_parse_entry(ar)) { 0157 ar_parse_entry_at(ar, current_offset); 0158 return false; 0159 } 0160 } 0161 rar->solid.restart = false; 0162 return true; 0163 } 0164 0165 static bool rar_uncompress(ar_archive *ar, void *buffer, size_t count) 0166 { 0167 ar_archive_rar *rar = (ar_archive_rar *)ar; 0168 if (count > ar->entry_size_uncompressed - rar->progress.bytes_done) { 0169 warn("Requesting too much data (%" PRIuPTR " < %" PRIuPTR ")", ar->entry_size_uncompressed - rar->progress.bytes_done, count); 0170 return false; 0171 } 0172 if (rar->entry.method == METHOD_STORE) { 0173 if (!rar_copy_stored(rar, buffer, count)) 0174 return false; 0175 } 0176 else if (rar->entry.method == METHOD_FASTEST || rar->entry.method == METHOD_FAST || 0177 rar->entry.method == METHOD_NORMAL || rar->entry.method == METHOD_GOOD || 0178 rar->entry.method == METHOD_BEST) { 0179 if (rar->solid.restart && !rar_restart_solid(ar)) { 0180 warn("Failed to produce the required solid decompression state"); 0181 return false; 0182 } 0183 if (!rar_uncompress_part(rar, buffer, count)) 0184 return false; 0185 } 0186 else { 0187 warn("Unknown compression method %#02x", rar->entry.method); 0188 return false; 0189 } 0190 0191 rar->progress.crc = ar_crc32(rar->progress.crc, buffer, count); 0192 if (rar->progress.bytes_done < ar->entry_size_uncompressed) 0193 return true; 0194 if (rar->progress.data_left) 0195 log("Compressed block has more data than required"); 0196 rar->solid.part_done = true; 0197 rar->solid.size_total += rar->progress.bytes_done; 0198 if (rar->progress.crc != rar->entry.crc) { 0199 warn("Checksum of extracted data doesn't match"); 0200 return false; 0201 } 0202 return true; 0203 } 0204 0205 ar_archive *ar_open_rar_archive(ar_stream *stream) 0206 { 0207 char signature[FILE_SIGNATURE_SIZE]; 0208 if (!ar_seek(stream, 0, SEEK_SET)) 0209 return NULL; 0210 if (ar_read(stream, signature, sizeof(signature)) != sizeof(signature)) 0211 return NULL; 0212 if (memcmp(signature, "Rar!\x1A\x07\x00", sizeof(signature)) != 0) { 0213 if (memcmp(signature, "Rar!\x1A\x07\x01", sizeof(signature)) == 0) 0214 warn("RAR 5 format isn't supported"); 0215 else if (memcmp(signature, "RE~^", 4) == 0) 0216 warn("Ancient RAR format isn't supported"); 0217 else if (memcmp(signature, "MZ", 2) == 0 || memcmp(signature, "\x7F\x45LF", 4) == 0) 0218 warn("SFX archives aren't supported"); 0219 return NULL; 0220 } 0221 0222 return ar_open_archive(stream, sizeof(ar_archive_rar), rar_close, rar_parse_entry, rar_get_name, rar_uncompress, NULL, FILE_SIGNATURE_SIZE); 0223 }