X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=include%2Fwimlib%2Fdecompress_common.h;h=ef7ebe953960cd33c2e91efd341c37f4ba717441;hb=76b57cc8cf113194136a7e264644a37515650ccc;hp=40fa49ab4438796e2df043f95f1fecc9d491cc8f;hpb=67c5f2c5954d07c25f57b6d9aedb73fb3720ec0b;p=wimlib diff --git a/include/wimlib/decompress_common.h b/include/wimlib/decompress_common.h index 40fa49ab..ef7ebe95 100644 --- a/include/wimlib/decompress_common.h +++ b/include/wimlib/decompress_common.h @@ -9,7 +9,6 @@ #include "wimlib/assert.h" #include "wimlib/compiler.h" -#include "wimlib/error.h" #include "wimlib/endianness.h" #include "wimlib/types.h" @@ -165,7 +164,7 @@ bitstream_read_byte(struct input_bitstream *istream) * lzms-decompress.c. */ static inline u16 read_huffsym(struct input_bitstream *istream, const u16 decode_table[], - unsigned num_syms, unsigned table_bits, unsigned max_codeword_len) + unsigned table_bits, unsigned max_codeword_len) { u16 entry; u16 key_bits; @@ -200,4 +199,56 @@ make_huffman_decode_table(u16 decode_table[], unsigned num_syms, unsigned num_bits, const u8 lens[], unsigned max_codeword_len); -#endif /* _WIMLIB_DECOMPRESS_H */ + +/* + * Copy a LZ77 match at (dst - offset) to dst. + * + * The length and offset must be already validated --- that is, (dst - offset) + * can't underrun the output buffer, and (dst + length) can't overrun the output + * buffer. Also, the length cannot be 0. + * + * @winend points to the byte past the end of the output buffer. + * This function won't write any data beyond this position. + */ +static inline void +lz_copy(u8 *dst, unsigned length, unsigned offset, const u8 *winend) +{ + const u8 *src = dst - offset; +#if defined(__x86_64__) || defined(__i386__) + /* Copy one 'unsigned long' at a time. On i386 and x86_64 this is + * faster than copying one byte at a time, unless the data is + * near-random and all the matches have very short lengths. Note that + * since this requires unaligned memory accesses, it won't necessarily + * be faster on every architecture. + * + * Also note that we might copy more than the length of the match. For + * example, if an 'unsigned long' is 8 bytes and the match is of length + * 5, then we'll simply copy 8 bytes. This is okay as long as we don't + * write beyond the end of the output buffer, hence the check for + * (winend - (dst + length) >= sizeof(unsigned long) - 1). */ + if (offset >= sizeof(unsigned long) && + winend - (dst + length) >= sizeof(unsigned long) - 1) + { + /* Access memory through a packed struct. This tricks the + * compiler into allowing unaligned memory accesses. */ + struct ulong_wrapper { + unsigned long v; + } _packed_attribute; + + const u8 *end = dst + length; + do { + unsigned long v = ((struct ulong_wrapper *)src)->v; + ((struct ulong_wrapper *)dst)->v = v; + dst += sizeof(unsigned long); + src += sizeof(unsigned long); + } while (dst < end); + + return; + } +#endif + do { + *dst++ = *src++; + } while (--length); +} + +#endif /* _WIMLIB_DECOMPRESS_COMMON_H */