1e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li/* 2e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * Copyright (c) 2000-2010 Marc Alexander Lehmann <schmorp@schmorp.de> 3e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 4e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * Redistribution and use in source and binary forms, with or without modifica- 5e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * tion, are permitted provided that the following conditions are met: 6e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 7e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 1. Redistributions of source code must retain the above copyright notice, 8e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * this list of conditions and the following disclaimer. 9e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 10e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 2. Redistributions in binary form must reproduce the above copyright 11e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * notice, this list of conditions and the following disclaimer in the 12e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * documentation and/or other materials provided with the distribution. 13e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 14e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 15e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 16e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 18e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 22e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 23e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * OF THE POSSIBILITY OF SUCH DAMAGE. 24e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * 25e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * Alternatively, the contents of this file may be used under the terms of 26e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * the GNU General Public License ("GPL") version 2 or any later version, 27e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * in which case the provisions of the GPL are applicable instead of 28e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * the above. If you wish to allow the use of your version of this file 29e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * only under the terms of the GPL and not to allow others to use your 30e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * version of this file under the BSD license, indicate your decision 31e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * by deleting the provisions above and replace them with the notice 32e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * and other provisions required by the GPL. If you do not delete the 33e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * provisions above, a recipient may use your version of this file under 34e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li * either the BSD or the GPL. 35e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li */ 36e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 37e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#include "lzfP.h" 38e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 39e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#if AVOID_ERRNO 40e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li# define SET_ERRNO(n) 41e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#else 42e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li# include <errno.h> 43e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li# define SET_ERRNO(n) errno = (n) 44e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 45e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 46e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#if USE_REP_MOVSB /* small win on amd, big loss on intel */ 47e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#if (__i386 || __amd64) && __GNUC__ >= 3 48e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li# define lzf_movsb(dst, src, len) \ 49e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li asm ("rep movsb" \ 50e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li : "=D" (dst), "=S" (src), "=c" (len) \ 51e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li : "0" (dst), "1" (src), "2" (len)); 52e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 53e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 54e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 55e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Liunsigned int 56e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Lilzf_decompress (const void *const in_data, unsigned int in_len, 57e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li void *out_data, unsigned int out_len) 58e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li{ 59e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li u8 const *ip = (const u8 *)in_data; 60e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li u8 *op = (u8 *)out_data; 61e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li u8 const *const in_end = ip + in_len; 62e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li u8 *const out_end = op + out_len; 63e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 64e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li do 65e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 66e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li unsigned int ctrl = *ip++; 67e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 68e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (ctrl < (1 << 5)) /* literal run */ 69e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 70e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li ctrl++; 71e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 72e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (op + ctrl > out_end) 73e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 74e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li SET_ERRNO (E2BIG); 75e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return 0; 76e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 77e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 78e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#if CHECK_INPUT 79e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (ip + ctrl > in_end) 80e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 81e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li SET_ERRNO (EINVAL); 82e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return 0; 83e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 84e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 85e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 86e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#ifdef lzf_movsb 87e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li lzf_movsb (op, ip, ctrl); 88e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#else 89e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li switch (ctrl) 90e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 91e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 32: *op++ = *ip++; case 31: *op++ = *ip++; case 30: *op++ = *ip++; case 29: *op++ = *ip++; 92e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 28: *op++ = *ip++; case 27: *op++ = *ip++; case 26: *op++ = *ip++; case 25: *op++ = *ip++; 93e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 24: *op++ = *ip++; case 23: *op++ = *ip++; case 22: *op++ = *ip++; case 21: *op++ = *ip++; 94e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 20: *op++ = *ip++; case 19: *op++ = *ip++; case 18: *op++ = *ip++; case 17: *op++ = *ip++; 95e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 16: *op++ = *ip++; case 15: *op++ = *ip++; case 14: *op++ = *ip++; case 13: *op++ = *ip++; 96e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 12: *op++ = *ip++; case 11: *op++ = *ip++; case 10: *op++ = *ip++; case 9: *op++ = *ip++; 97e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 8: *op++ = *ip++; case 7: *op++ = *ip++; case 6: *op++ = *ip++; case 5: *op++ = *ip++; 98e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 4: *op++ = *ip++; case 3: *op++ = *ip++; case 2: *op++ = *ip++; case 1: *op++ = *ip++; 99e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 100e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 101e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 102e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li else /* back reference */ 103e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 104e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li unsigned int len = ctrl >> 5; 105e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 106e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; 107e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 108e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#if CHECK_INPUT 109e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (ip >= in_end) 110e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 111e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li SET_ERRNO (EINVAL); 112e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return 0; 113e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 114e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 115e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (len == 7) 116e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 117e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li len += *ip++; 118e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#if CHECK_INPUT 119e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (ip >= in_end) 120e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 121e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li SET_ERRNO (EINVAL); 122e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return 0; 123e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 124e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 125e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 126e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 127e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li ref -= *ip++; 128e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 129e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (op + len + 2 > out_end) 130e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 131e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li SET_ERRNO (E2BIG); 132e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return 0; 133e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 134e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 135e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (ref < (u8 *)out_data) 136e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 137e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li SET_ERRNO (EINVAL); 138e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return 0; 139e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 140e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 141e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#ifdef lzf_movsb 142e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li len += 2; 143e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li lzf_movsb (op, ref, len); 144e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#else 145e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li switch (len) 146e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 147e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li default: 148e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li len += 2; 149e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 150e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li if (op >= ref + len) 151e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 152e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li /* disjunct areas */ 153e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li memcpy (op, ref, len); 154e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li op += len; 155e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 156e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li else 157e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li { 158e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li /* overlapping, use octte by octte copying */ 159e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li do 160e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li *op++ = *ref++; 161e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li while (--len); 162e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 163e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 164e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li break; 165e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 166e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 9: *op++ = *ref++; 167e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 8: *op++ = *ref++; 168e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 7: *op++ = *ref++; 169e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 6: *op++ = *ref++; 170e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 5: *op++ = *ref++; 171e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 4: *op++ = *ref++; 172e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 3: *op++ = *ref++; 173e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 2: *op++ = *ref++; 174e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 1: *op++ = *ref++; 175e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li case 0: *op++ = *ref++; /* two octets more */ 176e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li *op++ = *ref++; 177e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 178e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li#endif 179e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 180e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li } 181e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li while (ip < in_end); 182e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 183e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li return op - (u8 *)out_data; 184e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li} 185e54acca48ba1ab84ac7c693de45ed31ac3f311c2David Li 186