1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
5 * Copyright (C) 2003-2008, Evan Battaglia <gtoevan@gmx.net>
6 * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
7 * Copyright (C) 2013, Rob Norris <rw_norris@hotmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
37 #include "compression.h"
39 #include <glib/gstdio.h>
42 /* return size of unzip data or 0 if failed */
43 static guint uncompress_data(void *uncompressed_buffer, guint uncompressed_size, void *compressed_data, guint compressed_size)
48 stream.next_in = compressed_data;
49 stream.avail_in = compressed_size;
50 stream.next_out = uncompressed_buffer;
51 stream.avail_out = uncompressed_size;
52 stream.zalloc = (alloc_func)0;
53 stream.zfree = (free_func)0;
54 stream.opaque = (voidpf)0;
56 /* negative windowBits to inflateInit2 means "no header" */
57 if ((err = inflateInit2(&stream, -MAX_WBITS)) != Z_OK) {
58 g_warning("%s(): inflateInit2 failed", __PRETTY_FUNCTION__);
62 err = inflate(&stream, Z_FINISH);
63 if ((err != Z_OK) && (err != Z_STREAM_END) && stream.msg) {
64 g_warning("%s() inflate failed err=%d \"%s\"", __PRETTY_FUNCTION__, err, stream.msg == NULL ? "unknown" : stream.msg);
70 return(stream.total_out);
76 * @zip_file: pointer to start of compressed data
77 * @unzip_size: the size of the compressed data block
79 * Returns a pointer to uncompressed data (maybe NULL)
81 void *unzip_file(gchar *zip_file, gulong *unzip_size)
83 void *unzip_data = NULL;
90 guint16 extract_version;
96 guint32 compressed_size;
97 guint32 uncompressed_size;
99 guint16 extra_field_len;
100 } __attribute__ ((__packed__)) *local_file_header = NULL;
103 local_file_header = (struct _lfh *) zip_file;
104 if (GUINT32_FROM_LE(local_file_header->sig) != 0x04034b50) {
105 g_warning("%s(): wrong format", __PRETTY_FUNCTION__);
110 zip_data = zip_file + sizeof(struct _lfh)
111 + GUINT16_FROM_LE(local_file_header->filename_len)
112 + GUINT16_FROM_LE(local_file_header->extra_field_len);
113 gulong uncompressed_size = GUINT32_FROM_LE(local_file_header->uncompressed_size);
114 unzip_data = g_malloc(uncompressed_size);
116 if (!(*unzip_size = uncompress_data(unzip_data, uncompressed_size, zip_data, GUINT32_FROM_LE(local_file_header->compressed_size)))) {
129 * @name: The name of the file to attempt to decompress
131 * Returns: The name of the uncompressed file (in a temporary location) or NULL
132 * free the returned name after use.
134 * Also see: http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
136 gchar* uncompress_bzip2 ( gchar *name )
139 FILE *ff = g_fopen ( name, "r" );
144 BZFILE* bf = BZ2_bzReadOpen ( &bzerror, ff, 0, 0, NULL, 0 ); // This should take care of the bz2 file header
145 if ( bzerror != BZ_OK ) {
146 BZ2_bzReadClose ( &bzerror, bf );
148 g_warning ( "%s: BZ ReadOpen error on %s", __FUNCTION__, name );
153 GError *error = NULL;
154 gchar *tmpname = NULL;
155 #if GLIB_CHECK_VERSION(2,32,0)
156 GFile *gf = g_file_new_tmp ( "vik-bz2-tmp.XXXXXX", &gios, &error );
157 tmpname = g_file_get_path (gf);
159 gint fd = g_file_open_tmp ( "vik-bz2-tmp.XXXXXX", &tmpname, &error );
161 g_warning ( error->message );
162 g_error_free ( error );
165 gios = g_file_open_readwrite ( g_file_new_for_path (tmpname), NULL, &error );
167 g_warning ( error->message );
168 g_error_free ( error );
173 GOutputStream *gos = g_io_stream_get_output_stream ( G_IO_STREAM(gios) );
175 // Process in arbitary sized chunks
179 // Now process the actual compression data
180 while ( bzerror == BZ_OK ) {
181 nBuf = BZ2_bzRead ( &bzerror, bf, buf, 4096 );
182 if ( bzerror == BZ_OK || bzerror == BZ_STREAM_END) {
183 // do something with buf[0 .. nBuf-1]
184 if ( g_output_stream_write ( gos, buf, nBuf, NULL, &error ) < 0 ) {
185 g_critical ( "Couldn't write bz2 tmp %s file due to %s", tmpname, error->message );
186 g_error_free (error);
187 BZ2_bzReadClose ( &bzerror, bf );
192 if ( bzerror != BZ_STREAM_END ) {
194 g_warning ( "%s: BZ error :( %d", __FUNCTION__, bzerror );
196 BZ2_bzReadClose ( &bzerror, bf );
197 g_output_stream_close ( gos, NULL, &error );