1/* 2 * Copyright (c) 2005-2007 Rob Braun 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Rob Braun nor the names of his contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * 03-Apr-2005 31 * DRI: Rob Braun <bbraun@synack.net> 32 */ 33/* 34 * Portions Copyright 2006, Apple Computer, Inc. 35 * Christopher Ryan <ryanc@apple.com> 36*/ 37 38 39#include "config.h" 40#ifndef HAVE_ASPRINTF 41#include "asprintf.h" 42#endif 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <sys/types.h> 47#include <errno.h> 48#ifdef HAVE_LIBBZ2 49#include <bzlib.h> 50#endif 51#include "xar.h" 52#include "filetree.h" 53#include "io.h" 54 55#ifdef HAVE_LIBBZ2 56 57struct _bzip_context{ 58 uint8_t bzipcompressed; 59 bz_stream bz; 60}; 61 62 63#define BZIP2_CONTEXT(x) ((struct _bzip_context *)(*x)) 64#endif 65 66int xar_bzip_fromheap_done(xar_t x, xar_file_t f, xar_prop_t p, void **context) { 67#ifdef HAVE_LIBBZ2 68 69 if( !context || !BZIP2_CONTEXT(context) ) 70 return 0; 71 72 if( BZIP2_CONTEXT(context)->bzipcompressed){ 73 BZ2_bzDecompressEnd(&BZIP2_CONTEXT(context)->bz); 74 } 75 76 /* free the context */ 77 free(BZIP2_CONTEXT(context)); 78 *context = NULL; 79 80#endif /* HAVE_LIBBZ2 */ 81 return 0; 82} 83 84int xar_bzip_fromheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_t *inlen, void **context) { 85 const char *opt; 86 xar_prop_t tmpp; 87#ifdef HAVE_LIBBZ2 88 void *out = NULL; 89 size_t outlen, offset = 0; 90 int r; 91 92 /* on first run, we init the context and check the compression type */ 93 if( !BZIP2_CONTEXT(context) ) { 94 *context = calloc(1,sizeof(struct _bzip_context)); 95 96 opt = NULL; 97 tmpp = xar_prop_pget(p, "encoding"); 98 if( tmpp ) 99 opt = xar_attr_pget(f, tmpp, "style"); 100 if( !opt ) return 0; 101 if( strcmp(opt, "application/x-bzip2") != 0 ) return 0; 102 103 BZ2_bzDecompressInit(&BZIP2_CONTEXT(context)->bz, 0, 0); 104 BZIP2_CONTEXT(context)->bzipcompressed = 1; 105 if( *inlen == 0 ) 106 return 0; 107 }else if( !(BZIP2_CONTEXT(context)->bzipcompressed) ){ 108 /* once the context has been initialized, then we have already 109 checked the compression type, so we need only check if we 110 actually are compressed */ 111 return 0; 112 } 113 114 outlen = *inlen; 115 116 BZIP2_CONTEXT(context)->bz.next_in = *in; 117 BZIP2_CONTEXT(context)->bz.avail_in = *inlen; 118 BZIP2_CONTEXT(context)->bz.next_out = out; 119 BZIP2_CONTEXT(context)->bz.avail_out = 0; 120 121 while( BZIP2_CONTEXT(context)->bz.avail_in != 0 ) { 122 outlen = outlen * 2; 123 out = realloc(out, outlen); 124 if( out == NULL ) abort(); 125 126 BZIP2_CONTEXT(context)->bz.next_out = ((char *)out) + offset; 127 BZIP2_CONTEXT(context)->bz.avail_out = outlen - offset; 128 129 r = BZ2_bzDecompress(&BZIP2_CONTEXT(context)->bz); 130 if( (r != BZ_OK) && (r != BZ_STREAM_END) ) { 131 xar_err_new(x); 132 xar_err_set_file(x, f); 133 xar_err_set_string(x, "Error decompressing file"); 134 xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_EXTRACTION); 135 return -1; 136 } 137 offset += outlen - offset - BZIP2_CONTEXT(context)->bz.avail_out; 138 if( (r == BZ_STREAM_END) && (offset == 0) ) 139 break; 140 } 141 142 free(*in); 143 *in = out; 144 *inlen = offset; 145#else 146 opt = NULL; 147 tmpp = xar_prop_pget(p, "encoding"); 148 if( tmpp ) 149 opt = xar_attr_pget(f, tmpp, "style"); 150 if( !opt ) return 0; 151 if( strcmp(opt, "application/x-bzip2") != 0 ) return 0; 152 xar_err_new(x); 153 xar_err_set_file(x, f); 154 xar_err_set_errno(x, 0); 155 xar_err_set_string(x, "bzip2 support not compiled in."); 156 xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_EXTRACTION); 157 158#endif /* HAVE_LIBBZ2 */ 159 return 0; 160} 161 162int xar_bzip_toheap_done(xar_t x, xar_file_t f, xar_prop_t p, void **context) { 163#ifdef HAVE_LIBBZ2 164 xar_prop_t tmpp; 165 166 if( BZIP2_CONTEXT(context)->bzipcompressed){ 167 BZ2_bzCompressEnd(&BZIP2_CONTEXT(context)->bz); 168 169 tmpp = xar_prop_pset(f, p, "encoding", NULL); 170 if( tmpp ) 171 xar_attr_pset(f, tmpp, "style", "application/x-bzip2"); 172 } 173 174 /* free the context */ 175 free(BZIP2_CONTEXT(context)); 176 *context = NULL; 177 178#endif /* HAVE_LIBBZ2 */ 179 return 0; 180} 181 182int32_t xar_bzip_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_t *inlen, void **context) { 183 const char *opt; 184#ifdef HAVE_LIBBZ2 185 void *out = NULL; 186 size_t outlen, offset = 0; 187 int r; 188 189 /* on first run, we init the context and check the compression type */ 190 if( !BZIP2_CONTEXT(context) ) { 191 int level = 9; 192 *context = calloc(1,sizeof(struct _bzip_context)); 193 194 opt = xar_opt_get(x, XAR_OPT_COMPRESSION); 195 if( !opt ) 196 return 0; 197 198 if( strcmp(opt, XAR_OPT_VAL_BZIP) != 0 ) 199 return 0; 200 201 opt = xar_opt_get(x, XAR_OPT_COMPRESSIONARG); 202 if( opt ) { 203 int tmp; 204 errno = 0; 205 tmp = strtol(opt, NULL, 10); 206 if( errno == 0 ) { 207 if( (level >= 0) && (level <= 9) ) 208 level = tmp; 209 } 210 } 211 212 BZ2_bzCompressInit(&BZIP2_CONTEXT(context)->bz, level, 0, 30); 213 BZIP2_CONTEXT(context)->bzipcompressed = 1; 214 }else if( !BZIP2_CONTEXT(context)->bzipcompressed ){ 215 /* once the context has been initialized, then we have already 216 checked the compression type, so we need only check if we 217 actually are compressed */ 218 return 0; 219 } 220 221 outlen = *inlen/2; 222 if(outlen == 0) outlen = 1024; 223 BZIP2_CONTEXT(context)->bz.next_in = *in; 224 BZIP2_CONTEXT(context)->bz.avail_in = *inlen; 225 BZIP2_CONTEXT(context)->bz.next_out = out; 226 BZIP2_CONTEXT(context)->bz.avail_out = 0; 227 228 if( *inlen != 0 ) { 229 do { 230 outlen *= 2; 231 out = realloc(out, outlen); 232 if( out == NULL ) abort(); 233 234 BZIP2_CONTEXT(context)->bz.next_out = ((char *)out) + offset; 235 BZIP2_CONTEXT(context)->bz.avail_out = outlen - offset; 236 237 r = BZ2_bzCompress(&BZIP2_CONTEXT(context)->bz, BZ_RUN); 238 offset = outlen - BZIP2_CONTEXT(context)->bz.avail_out; 239 } while( r == BZ_RUN_OK && BZIP2_CONTEXT(context)->bz.avail_in != 0 ); 240 } else { 241 do { 242 outlen *= 2; 243 out = realloc(out, outlen); 244 if( out == NULL ) abort(); 245 246 BZIP2_CONTEXT(context)->bz.next_out = ((char *)out) + offset; 247 BZIP2_CONTEXT(context)->bz.avail_out = outlen - offset; 248 249 r = BZ2_bzCompress(&BZIP2_CONTEXT(context)->bz, BZ_FINISH); 250 offset = outlen - BZIP2_CONTEXT(context)->bz.avail_out; 251 } while( (r == BZ_FINISH_OK) && (r != BZ_STREAM_END /* no-op */) ); 252 } 253 254 if( (r != BZ_RUN_OK && r != BZ_STREAM_END && r != BZ_SEQUENCE_ERROR) ) { 255 xar_err_new(x); 256 xar_err_set_file(x, f); 257 xar_err_set_string(x, "Error compressing file"); 258 xar_err_set_errno(x, r); 259 xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); 260 return -1; 261 } 262 263 free(*in); 264 *in = out; 265 *inlen = offset; 266#else 267 opt = xar_opt_get(x, XAR_OPT_COMPRESSION); 268 if( !opt ) 269 return 0; 270 if( strcmp(opt, XAR_OPT_VAL_BZIP) != 0 ) 271 return 0; 272 xar_err_new(x); 273 xar_err_set_file(x, f); 274 xar_err_set_errno(x, 0); 275 xar_err_set_string(x, "bzip2 support not compiled in."); 276 xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); 277#endif /* HAVE_LIBBZ2 */ 278 return 0; 279} 280