github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/compress/libdeflate/gzip_decompress.c (about) 1 /* 2 * gzip_decompress.c - decompress with a gzip wrapper 3 * 4 * Originally public domain; changes after 2016-09-07 are copyrighted. 5 * 6 * Copyright 2016 Eric Biggers 7 * 8 * Permission is hereby granted, free of charge, to any person 9 * obtaining a copy of this software and associated documentation 10 * files (the "Software"), to deal in the Software without 11 * restriction, including without limitation the rights to use, 12 * copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following 15 * conditions: 16 * 17 * The above copyright notice and this permission notice shall be 18 * included in all copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 * OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 #include "gzip_constants.h" 31 #include "unaligned.h" 32 33 #include "libdeflate.h" 34 35 LIBDEFLATEAPI enum libdeflate_result 36 libdeflate_gzip_decompress_ex(struct libdeflate_decompressor *d, 37 const void *in, size_t in_nbytes, 38 void *out, size_t out_nbytes_avail, 39 size_t *actual_in_nbytes_ret, 40 size_t *actual_out_nbytes_ret) 41 { 42 const u8 *in_next = in; 43 const u8 * const in_end = in_next + in_nbytes; 44 u8 flg; 45 size_t actual_in_nbytes; 46 size_t actual_out_nbytes; 47 enum libdeflate_result result; 48 49 if (in_nbytes < GZIP_MIN_OVERHEAD) 50 return LIBDEFLATE_BAD_DATA; 51 52 /* ID1 */ 53 if (*in_next++ != GZIP_ID1) 54 return LIBDEFLATE_BAD_DATA; 55 /* ID2 */ 56 if (*in_next++ != GZIP_ID2) 57 return LIBDEFLATE_BAD_DATA; 58 /* CM */ 59 if (*in_next++ != GZIP_CM_DEFLATE) 60 return LIBDEFLATE_BAD_DATA; 61 flg = *in_next++; 62 /* MTIME */ 63 in_next += 4; 64 /* XFL */ 65 in_next += 1; 66 /* OS */ 67 in_next += 1; 68 69 if (flg & GZIP_FRESERVED) 70 return LIBDEFLATE_BAD_DATA; 71 72 /* Extra field */ 73 if (flg & GZIP_FEXTRA) { 74 u16 xlen = get_unaligned_le16(in_next); 75 in_next += 2; 76 77 if (in_end - in_next < (u32)xlen + GZIP_FOOTER_SIZE) 78 return LIBDEFLATE_BAD_DATA; 79 80 in_next += xlen; 81 } 82 83 /* Original file name (zero terminated) */ 84 if (flg & GZIP_FNAME) { 85 while (*in_next++ != 0 && in_next != in_end) 86 ; 87 if (in_end - in_next < GZIP_FOOTER_SIZE) 88 return LIBDEFLATE_BAD_DATA; 89 } 90 91 /* File comment (zero terminated) */ 92 if (flg & GZIP_FCOMMENT) { 93 while (*in_next++ != 0 && in_next != in_end) 94 ; 95 if (in_end - in_next < GZIP_FOOTER_SIZE) 96 return LIBDEFLATE_BAD_DATA; 97 } 98 99 /* CRC16 for gzip header */ 100 if (flg & GZIP_FHCRC) { 101 in_next += 2; 102 if (in_end - in_next < GZIP_FOOTER_SIZE) 103 return LIBDEFLATE_BAD_DATA; 104 } 105 106 /* Compressed data */ 107 result = libdeflate_deflate_decompress_ex(d, in_next, 108 in_end - GZIP_FOOTER_SIZE - in_next, 109 out, out_nbytes_avail, 110 &actual_in_nbytes, 111 actual_out_nbytes_ret); 112 if (result != LIBDEFLATE_SUCCESS) 113 return result; 114 115 if (actual_out_nbytes_ret) 116 actual_out_nbytes = *actual_out_nbytes_ret; 117 else 118 actual_out_nbytes = out_nbytes_avail; 119 120 in_next += actual_in_nbytes; 121 122 /* CRC32 */ 123 if (libdeflate_crc32(0, out, actual_out_nbytes) != 124 get_unaligned_le32(in_next)) 125 return LIBDEFLATE_BAD_DATA; 126 in_next += 4; 127 128 /* ISIZE */ 129 if ((u32)actual_out_nbytes != get_unaligned_le32(in_next)) 130 return LIBDEFLATE_BAD_DATA; 131 in_next += 4; 132 133 if (actual_in_nbytes_ret) 134 *actual_in_nbytes_ret = in_next - (u8 *)in; 135 136 return LIBDEFLATE_SUCCESS; 137 } 138 139 LIBDEFLATEAPI enum libdeflate_result 140 libdeflate_gzip_decompress(struct libdeflate_decompressor *d, 141 const void *in, size_t in_nbytes, 142 void *out, size_t out_nbytes_avail, 143 size_t *actual_out_nbytes_ret) 144 { 145 return libdeflate_gzip_decompress_ex(d, in, in_nbytes, 146 out, out_nbytes_avail, 147 NULL, actual_out_nbytes_ret); 148 }