/* AbiSource Program Utilities * Copyright (C) 1998,1999 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "zlib.h" #include "stdio.h" #include "ut_string_class.h" #include "ut_string.h" #include "ut_path.h" #include "ut_debugmsg.h" #include "ut_decompress.h" /* Portions based on or from untgz.c in zlib contrib directory */ #define TGZ_BLOCKSIZE 512 struct tar_header { /* byte offset */ char name[100]; /* 0 */ char mode[8]; /* 100 */ char uid[8]; /* 108 */ char gid[8]; /* 116 */ char size[12]; /* 124 */ char mtime[12]; /* 136 */ char chksum[8]; /* 148 */ char typeflag; /* 156 */ char linkname[100]; /* 157 */ char magic[6]; /* 257 */ char version[2]; /* 263 */ char uname[32]; /* 265 */ char gname[32]; /* 297 */ char devmajor[8]; /* 329 */ char devminor[8]; /* 337 */ char prefix[155]; /* 345 */ /* 500 */ }; union tar_buffer { char buffer[TGZ_BLOCKSIZE]; struct tar_header header; }; static int getoct(char *p,int width) { int result = 0; char c; while (width --) { c = *p++; if (c == ' ') continue; if (c == 0) break; result = result * 8 + (c - '0'); } return result; } // we strip any path components static char * strippath(char *fname) { const char * fn = UT_basename(fname); // be sure terminating '\0' is copied and // use ansi memcpy equivalent that handles overlapping regions memmove(fname, fn, strlen(fn) + 1 ); return fname; } /* return 0 on success * extract a file in tarball to appropriate directory, ignoring any paths in archive * note that szDestPath lacks slash at end * szFName is the file to extract * szWantedFile is the file to extract * szDestPath is the path to extract to (without trailing slash) - if NULL, extracted data wont be saved to disk * retBuf is a pointer to a bufferpointer - will be g_try_malloc'ed and filled with data if retBuf != NULL * retFileSize will be filled with the size of the file, if it's != NULL * * extraction routines derived from logic in zlib's contrib untgz.c program */ int UT_untgz(const char *szFName, const char *szWantedFile, const char *szDestPath, char **retBuf, int *retFileSize) { gzFile tarball; union tar_buffer buffer; int getheader = 1; int remaining = 0; int len; char fname[TGZ_BLOCKSIZE]; FILE *outfile = NULL; int fileSize = 0; if (retBuf) FREEP(*retBuf); if ((tarball = gzopen(szFName, "rb")) == NULL) { UT_DEBUGMSG(("untgz: Error while opening downloaded dictionary archive")); return 1; } bool done = false; while (!done) { if ((len = gzread(tarball, &buffer, TGZ_BLOCKSIZE)) != TGZ_BLOCKSIZE) { // error (gzerror(in, &err)); UT_DEBUGMSG(("untgz: gzread failed to read in complete block")); gzclose(tarball); return 1; } /* * If we have to get a tar header */ if (getheader == 1) { /* * if we met the end of the tar * or the end-of-tar block, * we are done */ if ((len == 0) || (buffer.header.name[0]== 0)) { done = true; continue; } // tartime = static_cast(getoct(buffer.header.mtime,12)); strcpy(fname, buffer.header.name); strippath(fname); if ((buffer.header.typeflag == '\0') || // [A]REGTYPE, ie regular files (buffer.header.typeflag == '0') ) { remaining = getoct(buffer.header.size, 12); if ((remaining) && (g_ascii_strcasecmp(fname, szWantedFile) == 0)) { fileSize = remaining; if (retBuf) { if (!(*retBuf = static_cast(g_try_malloc(fileSize)))) *retBuf = NULL; } if (retFileSize) *retFileSize = fileSize; if (szDestPath) { UT_String outfilename(szDestPath); outfilename += "/"; outfilename += fname; if ((outfile = fopen(outfilename.c_str(), "wb")) == NULL) { UT_DEBUGMSG(("untgz: Unable to save %s", outfilename.c_str())); } } else outfile = NULL; } else outfile = NULL; /* * could have no contents */ getheader = (remaining) ? 0 : 1; } } else // if (getheader != 1) { unsigned int bytes = (remaining > TGZ_BLOCKSIZE) ? TGZ_BLOCKSIZE : remaining; if (retBuf && *retBuf) { memcpy(retBuf[fileSize - remaining], buffer.buffer, bytes); } if (outfile != NULL) { if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) { UT_DEBUGMSG(("untgz: error writing, skipping %s", fname)); fclose(outfile); g_unlink(fname); } } remaining -= bytes; if (remaining == 0) { getheader = 1; if (outfile != NULL) { // TODO: should actually set proper time from archive, oh well fclose(outfile); outfile = NULL; } } } // if (getheader == 1) else end } if (tarball != NULL) gzclose(tarball); return 0; } /* End from untgz.c */