def time_encode(tm, frac=0): dostime = ( tm.tm_sec >> 1 << DOS_2SEC_BIT ^ tm.tm_min << DOS_MIN_BIT ^ tm.tm_hour << DOS_HOUR_BIT ^ tm.tm_mday << DOS_DAY_BIT ^ tm.tm_mon << DOS_MONTH_BIT ^ tm.tm_year - 1980 << DOS_YEAR_BIT) one_sec = tm.tm_sec & 1 if not frac and not one_sec: return (dostime, None) flags = 1 << TIME_VALID_BIT flags |= one_sec << TIME_ONE_BIT frac = int(frac * 10 ** TIME_FRAC_DIGITS) size = TIME_FRAC_BYTES while size > 0: if frac & 0xFF: break frac >>= 8 size -= 1 flags |= size << TIME_SIZE_BIT xtime = bytearray(S_SHORT.pack( flags << MTIME_INDEX * TIME_FLAG_BITS)) for i in range(size): xtime.append(frac & 0xFF) frac >>= 8 return (dostime, xtime)
def time_encode(tm, frac=0): dostime = (tm.tm_sec >> 1 << DOS_2SEC_BIT ^ tm.tm_min << DOS_MIN_BIT ^ tm.tm_hour << DOS_HOUR_BIT ^ tm.tm_mday << DOS_DAY_BIT ^ tm.tm_mon << DOS_MONTH_BIT ^ tm.tm_year - 1980 << DOS_YEAR_BIT) one_sec = tm.tm_sec & 1 if not frac and not one_sec: return (dostime, None) flags = 1 << TIME_VALID_BIT flags |= one_sec << TIME_ONE_BIT frac = int(frac * 10**TIME_FRAC_DIGITS) size = TIME_FRAC_BYTES while size > 0: if frac & 0xFF: break frac >>= 8 size -= 1 flags |= size << TIME_SIZE_BIT xtime = bytearray(S_SHORT.pack(flags << MTIME_INDEX * TIME_FLAG_BITS)) for _ in range(size): xtime.append(frac & 0xFF) frac >>= 8 return (dostime, xtime)
def write_block(file, type, flags, data): block = bytearray() for part in data: block.extend(part) header = S_BLK_HDR_DATA.pack(type, flags, S_BLK_HDR.size + len(block)) crc = crc32(header) crc = crc32(block, crc) file.write(S_SHORT.pack(crc & bitmask(16))) file.write(header) file.write(block)
def write_block(file, btype, flags, data): block = bytearray() for part in data: block.extend(part) header = S_BLK_HDR_DATA.pack(btype, flags, S_BLK_HDR.size + len(block)) crc = crc32(header) crc = crc32(block, crc) file.write(S_SHORT.pack(crc & bitmask(16))) file.write(header) file.write(block)
def write_end(volume, version, flags, volnum, is_last_vol): size = volume.tell() volume.seek(0) crc = file_crc32(volume, size) if version >= 3: flags |= (RAR_SKIP_IF_UNKNOWN ^ (not is_last_vol) * RAR_ENDARC_NEXT_VOLUME) parts = list() if flags & RAR_ENDARC_DATACRC: parts.append(S_LONG.pack(crc)) if flags & RAR_ENDARC_VOLNR: parts.append(S_SHORT.pack(volnum)) if flags & RAR_ENDARC_REVSPACE: parts.append(0 for i in range(END_EXTRA)) write_block(volume, RAR_BLOCK_ENDARC, flags, parts) return crc
def rr_calc(volume, rr_count, size): volume.seek(0) rr_crcs = bytearray() rr_sects = tuple(BitVector(RR_SECT_SIZE) for i in range(rr_count)) slice = 0 while size > 0: if size < RR_SECT_SIZE: chunk = volume.read(size).ljust(RR_SECT_SIZE, bytes((0,))) size = 0 else: chunk = volume.read(RR_SECT_SIZE) size -= RR_SECT_SIZE rr_crcs.extend(S_SHORT.pack(~crc32(chunk) & bitmask(16))) rr_sects[slice].xor(chunk) slice = (slice + 1) % rr_count return (rr_crcs, rr_sects)
def write_end(volume, version, flags, volnum, is_last_vol): size = volume.tell() volume.seek(0) crc = file_crc32(volume, size) if version >= 3: flags |= (RAR_SKIP_IF_UNKNOWN ^ (not is_last_vol) * RAR_ENDARC_NEXT_VOLUME) parts = list() if flags & RAR_ENDARC_DATACRC: parts.append(S_LONG.pack(crc)) if flags & RAR_ENDARC_VOLNR: parts.append(S_SHORT.pack(volnum)) if flags & RAR_ENDARC_REVSPACE: parts.append(0 for _ in range(END_EXTRA)) write_block(volume, RAR_BLOCK_ENDARC, flags, parts) return crc
def rr_calc(volume, rr_count, size): volume.seek(0) rr_crcs = bytearray() rr_sects = tuple(BitVector(RR_SECT_SIZE) for _ in range(rr_count)) aslice = 0 while size > 0: if size < RR_SECT_SIZE: chunk = volume.read(size).ljust(RR_SECT_SIZE, bytes((0, ))) size = 0 else: chunk = volume.read(RR_SECT_SIZE) size -= RR_SECT_SIZE rr_crcs.extend(S_SHORT.pack(~crc32(chunk) & bitmask(16))) rr_sects[aslice].xor(chunk) aslice = (aslice + 1) % rr_count return (rr_crcs, rr_sects)
def write_rr(version, host_os, volume, rr_count): prot_size = volume.tell() (rr_crcs, rr_sects) = rr_calc(volume, rr_count, prot_size) crc = crc32(rr_crcs, RR_CRC_INIT) for s in rr_sects: crc = crc32(s.buffer(), crc) prot_sect_count = len(rr_crcs) // S_SHORT.size size = prot_sect_count * RR_CRC_SIZE + rr_count * RR_SECT_SIZE if version < 3: write_block(volume, type=RAR_BLOCK_OLD_RECOVERY, flags=RAR_LONG_BLOCK ^ RAR_SKIP_IF_UNKNOWN, data=( S_LONG.pack(size), (20,), S_SHORT.pack(rr_count), S_LONG.pack(prot_sect_count), RR_PROTECT_2, )) else: write_block(volume, type=RAR_BLOCK_SUB, flags=RAR_LONG_BLOCK ^ RAR_SKIP_IF_UNKNOWN, data=( S_FILE_HDR.pack(size, size, host_os, crc, 0, 29, ord("0"), len(RR_SUB_NAME), 0), RR_SUB_NAME, RR_PROTECT_3, S_LONG.pack(rr_count), struct.pack("<Q", prot_sect_count), )) volume.write(rr_crcs) for s in rr_sects: volume.write(s.buffer())
def write_rr(version, host_os, volume, rr_count): prot_size = volume.tell() (rr_crcs, rr_sects) = rr_calc(volume, rr_count, prot_size) crc = crc32(rr_crcs, RR_CRC_INIT) for s in rr_sects: crc = crc32(s.buffer(), crc) prot_sect_count = len(rr_crcs) // S_SHORT.size size = prot_sect_count * RR_CRC_SIZE + rr_count * RR_SECT_SIZE if version < 3: write_block(volume, type=RAR_BLOCK_OLD_RECOVERY, flags=RAR_LONG_BLOCK ^ RAR_SKIP_IF_UNKNOWN, data=( S_LONG.pack(size), (20, ), S_SHORT.pack(rr_count), S_LONG.pack(prot_sect_count), RR_PROTECT_2, )) else: write_block(volume, type=RAR_BLOCK_SUB, flags=RAR_LONG_BLOCK ^ RAR_SKIP_IF_UNKNOWN, data=( S_FILE_HDR.pack(size, size, host_os, crc, 0, 29, ord("0"), len(RR_SUB_NAME), 0), RR_SUB_NAME, RR_PROTECT_3, S_LONG.pack(rr_count), struct.pack("<Q", prot_sect_count), )) volume.write(rr_crcs) for s in rr_sects: volume.write(s.buffer())