/* Copyright 2015 the unarr project authors (see AUTHORS file). License: LGPLv3 */ #ifndef rar_rar_h #define rar_rar_h #include "../common/unarr-imp.h" #include "lzss.h" #include "../lzmasdk/Ppmd7.h" #include static inline size_t smin(size_t a, size_t b) { return a < b ? a : b; } typedef struct ar_archive_rar_s ar_archive_rar; /***** parse-rar *****/ #define FILE_SIGNATURE_SIZE 7 enum block_types { TYPE_FILE_SIGNATURE = 0x72, TYPE_MAIN_HEADER = 0x73, TYPE_FILE_ENTRY = 0x74, TYPE_NEWSUB = 0x7A, TYPE_END_OF_ARCHIVE = 0x7B, }; enum archive_flags { MHD_VOLUME = 1 << 0, MHD_COMMENT = 1 << 1, MHD_LOCK = 1 << 2, MHD_SOLID = 1 << 3, MHD_PACK_COMMENT = 1 << 4, MHD_AV = 1 << 5, MHD_PROTECT = 1 << 6, MHD_PASSWORD = 1 << 7, MHD_FIRSTVOLUME = 1 << 8, MHD_ENCRYPTVER = 1 << 9, MHD_LONG_BLOCK = 1 << 15, }; enum entry_flags { LHD_SPLIT_BEFORE = 1 << 0, LHD_SPLIT_AFTER = 1 << 1, LHD_PASSWORD = 1 << 2, LHD_COMMENT = 1 << 3, LHD_SOLID = 1 << 4, LHD_DIRECTORY = (1 << 5) | (1 << 6) | (1 << 7), LHD_LARGE = 1 << 8, LHD_UNICODE = 1 << 9, LHD_SALT = 1 << 10, LHD_VERSION = 1 << 11, LHD_EXTTIME = 1 << 12, LHD_EXTFLAGS = 1 << 13, LHD_LONG_BLOCK = 1 << 15, }; enum compression_method { METHOD_STORE = 0x30, METHOD_FASTEST = 0x31, METHOD_FAST = 0x32, METHOD_NORMAL = 0x33, METHOD_GOOD = 0x34, METHOD_BEST = 0x35, }; struct rar_header { uint16_t crc; uint8_t type; uint16_t flags; uint16_t size; uint64_t datasize; }; struct rar_entry { uint64_t size; uint8_t os; uint32_t crc; uint32_t dosdate; uint8_t version; uint8_t method; uint16_t namelen; uint32_t attrs; }; struct ar_archive_rar_entry { uint8_t version; uint8_t method; uint32_t crc; uint16_t header_size; bool solid; char *name; }; bool rar_parse_header(ar_archive *ar, struct rar_header *header); bool rar_check_header_crc(ar_archive *ar); bool rar_parse_header_entry(ar_archive_rar *rar, struct rar_header *header, struct rar_entry *entry); const char *rar_get_name(ar_archive *ar, bool raw); /***** filter-rar *****/ struct RARVirtualMachine; struct RARProgramCode; struct RARFilter; struct ar_archive_rar_filters { struct RARVirtualMachine *vm; struct RARProgramCode *progs; struct RARFilter *stack; size_t filterstart; uint32_t lastfilternum; size_t lastend; uint8_t *bytes; size_t bytes_ready; }; bool rar_parse_filter(ar_archive_rar *rar, const uint8_t *bytes, uint16_t length, uint8_t flags); bool rar_run_filters(ar_archive_rar *rar); void rar_clear_filters(struct ar_archive_rar_filters *filters); /***** huffman-rar *****/ struct huffman_code { struct { int branches[2]; } *tree; int numentries; int capacity; int minlength; int maxlength; struct { int length; int value; } *table; int tablesize; }; bool rar_new_node(struct huffman_code *code); bool rar_add_value(struct huffman_code *code, int value, int codebits, int length); bool rar_create_code(struct huffman_code *code, uint8_t *lengths, int numsymbols); bool rar_make_table(struct huffman_code *code); void rar_free_code(struct huffman_code *code); static inline bool rar_is_leaf_node(struct huffman_code *code, int node) { return code->tree[node].branches[0] == code->tree[node].branches[1]; } /***** uncompress-rar *****/ #define LZSS_WINDOW_SIZE 0x400000 #define LZSS_OVERFLOW_SIZE 288 #define MAINCODE_SIZE 299 #define OFFSETCODE_SIZE 60 #define LOWOFFSETCODE_SIZE 17 #define LENGTHCODE_SIZE 28 #define HUFFMAN_TABLE_SIZE MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE struct ByteReader { IByteIn super; ar_archive_rar *rar; }; struct ar_archive_rar_uncomp_v3 { struct huffman_code maincode; struct huffman_code offsetcode; struct huffman_code lowoffsetcode; struct huffman_code lengthcode; uint8_t lengthtable[HUFFMAN_TABLE_SIZE]; uint32_t lastlength; uint32_t lastoffset; uint32_t oldoffset[4]; uint32_t lastlowoffset; uint32_t numlowoffsetrepeats; bool is_ppmd_block; int ppmd_escape; CPpmd7 ppmd7_context; struct ByteReader bytein; struct ar_archive_rar_filters filters; }; #define MAINCODE_SIZE_20 298 #define OFFSETCODE_SIZE_20 48 #define LENGTHCODE_SIZE_20 28 #define HUFFMAN_TABLE_SIZE_20 4 * 257 struct AudioState { int8_t weight[5]; int16_t delta[4]; int8_t lastdelta; int error[11]; int count; uint8_t lastbyte; }; struct ar_archive_rar_uncomp_v2 { struct huffman_code maincode; struct huffman_code offsetcode; struct huffman_code lengthcode; struct huffman_code audiocode[4]; uint8_t lengthtable[HUFFMAN_TABLE_SIZE_20]; uint32_t lastoffset; uint32_t lastlength; uint32_t oldoffset[4]; uint32_t oldoffsetindex; bool audioblock; uint8_t channel; uint8_t numchannels; struct AudioState audiostate[4]; int8_t channeldelta; }; struct ar_archive_rar_uncomp { uint8_t version; LZSS lzss; size_t bytes_ready; bool start_new_table; union { struct ar_archive_rar_uncomp_v3 v3; struct ar_archive_rar_uncomp_v2 v2; } state; struct StreamBitReader { uint64_t bits; int available; bool at_eof; } br; }; bool rar_uncompress_part(ar_archive_rar *rar, void *buffer, size_t buffer_size); int64_t rar_expand(ar_archive_rar *rar, int64_t end); void rar_clear_uncompress(struct ar_archive_rar_uncomp *uncomp); static inline void br_clear_leftover_bits(struct ar_archive_rar_uncomp *uncomp) { uncomp->br.available &= ~0x07; } /***** rar *****/ struct ar_archive_rar_progress { size_t data_left; size_t bytes_done; uint32_t crc; }; struct ar_archive_rar_solid { size_t size_total; bool part_done; bool restart; }; struct ar_archive_rar_s { ar_archive super; uint16_t archive_flags; struct ar_archive_rar_entry entry; struct ar_archive_rar_uncomp uncomp; struct ar_archive_rar_progress progress; struct ar_archive_rar_solid solid; }; #endif