michael@0: /******* BEGIN LICENSE BLOCK ******* michael@0: * Version: MPL 1.1/GPL 2.0/LGPL 2.1 michael@0: * michael@0: * The contents of this file are subject to the Mozilla Public License Version michael@0: * 1.1 (the "License"); you may not use this file except in compliance with michael@0: * the License. You may obtain a copy of the License at michael@0: * http://www.mozilla.org/MPL/ michael@0: * michael@0: * Software distributed under the License is distributed on an "AS IS" basis, michael@0: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License michael@0: * for the specific language governing rights and limitations under the michael@0: * License. michael@0: * michael@0: * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) michael@0: * and László Németh (Hunspell). Portions created by the Initial Developers michael@0: * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. michael@0: * michael@0: * Contributor(s): László Németh (nemethl@gyorsposta.hu) michael@0: * Caolan McNamara (caolanm@redhat.com) michael@0: * michael@0: * Alternatively, the contents of this file may be used under the terms of michael@0: * either the GNU General Public License Version 2 or later (the "GPL"), or michael@0: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), michael@0: * in which case the provisions of the GPL or the LGPL are applicable instead michael@0: * of those above. If you wish to allow use of your version of this file only michael@0: * under the terms of either the GPL or the LGPL, and not to allow others to michael@0: * use your version of this file under the terms of the MPL, indicate your michael@0: * decision by deleting the provisions above and replace them with the notice michael@0: * and other provisions required by the GPL or the LGPL. If you do not delete michael@0: * the provisions above, a recipient may use your version of this file under michael@0: * the terms of any one of the MPL, the GPL or the LGPL. michael@0: * michael@0: ******* END LICENSE BLOCK *******/ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "hunzip.hxx" michael@0: michael@0: #define CODELEN 65536 michael@0: #define BASEBITREC 5000 michael@0: michael@0: #define UNCOMPRESSED '\002' michael@0: #define MAGIC "hz0" michael@0: #define MAGIC_ENCRYPT "hz1" michael@0: #define MAGICLEN (sizeof(MAGIC) - 1) michael@0: michael@0: int Hunzip::fail(const char * err, const char * par) { michael@0: fprintf(stderr, err, par); michael@0: return -1; michael@0: } michael@0: michael@0: Hunzip::Hunzip(const char * file, const char * key) { michael@0: bufsiz = 0; michael@0: lastbit = 0; michael@0: inc = 0; michael@0: outc = 0; michael@0: dec = NULL; michael@0: fin = NULL; michael@0: filename = (char *) malloc(strlen(file) + 1); michael@0: if (filename) strcpy(filename, file); michael@0: if (getcode(key) == -1) bufsiz = -1; michael@0: else bufsiz = getbuf(); michael@0: } michael@0: michael@0: int Hunzip::getcode(const char * key) { michael@0: unsigned char c[2]; michael@0: int i, j, n, p; michael@0: int allocatedbit = BASEBITREC; michael@0: const char * enc = key; michael@0: michael@0: if (!filename) return -1; michael@0: michael@0: fin = fopen(filename, "rb"); michael@0: if (!fin) return -1; michael@0: michael@0: // read magic number michael@0: if ((fread(in, 1, 3, fin) < MAGICLEN) michael@0: || !(strncmp(MAGIC, in, MAGICLEN) == 0 || michael@0: strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0)) { michael@0: return fail(MSG_FORMAT, filename); michael@0: } michael@0: michael@0: // check encryption michael@0: if (strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0) { michael@0: unsigned char cs; michael@0: if (!key) return fail(MSG_KEY, filename); michael@0: if (fread(&c, 1, 1, fin) < 1) return fail(MSG_FORMAT, filename); michael@0: for (cs = 0; *enc; enc++) cs ^= *enc; michael@0: if (cs != c[0]) return fail(MSG_KEY, filename); michael@0: enc = key; michael@0: } else key = NULL; michael@0: michael@0: // read record count michael@0: if (fread(&c, 1, 2, fin) < 2) return fail(MSG_FORMAT, filename); michael@0: michael@0: if (key) { michael@0: c[0] ^= *enc; michael@0: if (*(++enc) == '\0') enc = key; michael@0: c[1] ^= *enc; michael@0: } michael@0: michael@0: n = ((int) c[0] << 8) + c[1]; michael@0: dec = (struct bit *) malloc(BASEBITREC * sizeof(struct bit)); michael@0: if (!dec) return fail(MSG_MEMORY, filename); michael@0: dec[0].v[0] = 0; michael@0: dec[0].v[1] = 0; michael@0: michael@0: // read codes michael@0: for (i = 0; i < n; i++) { michael@0: unsigned char l; michael@0: if (fread(c, 1, 2, fin) < 2) return fail(MSG_FORMAT, filename); michael@0: if (key) { michael@0: if (*(++enc) == '\0') enc = key; michael@0: c[0] ^= *enc; michael@0: if (*(++enc) == '\0') enc = key; michael@0: c[1] ^= *enc; michael@0: } michael@0: if (fread(&l, 1, 1, fin) < 1) return fail(MSG_FORMAT, filename); michael@0: if (key) { michael@0: if (*(++enc) == '\0') enc = key; michael@0: l ^= *enc; michael@0: } michael@0: if (fread(in, 1, l/8+1, fin) < (size_t) l/8+1) return fail(MSG_FORMAT, filename); michael@0: if (key) for (j = 0; j <= l/8; j++) { michael@0: if (*(++enc) == '\0') enc = key; michael@0: in[j] ^= *enc; michael@0: } michael@0: p = 0; michael@0: for (j = 0; j < l; j++) { michael@0: int b = (in[j/8] & (1 << (7 - (j % 8)))) ? 1 : 0; michael@0: int oldp = p; michael@0: p = dec[p].v[b]; michael@0: if (p == 0) { michael@0: lastbit++; michael@0: if (lastbit == allocatedbit) { michael@0: allocatedbit += BASEBITREC; michael@0: dec = (struct bit *) realloc(dec, allocatedbit * sizeof(struct bit)); michael@0: } michael@0: dec[lastbit].v[0] = 0; michael@0: dec[lastbit].v[1] = 0; michael@0: dec[oldp].v[b] = lastbit; michael@0: p = lastbit; michael@0: } michael@0: } michael@0: dec[p].c[0] = c[0]; michael@0: dec[p].c[1] = c[1]; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: Hunzip::~Hunzip() michael@0: { michael@0: if (dec) free(dec); michael@0: if (fin) fclose(fin); michael@0: if (filename) free(filename); michael@0: } michael@0: michael@0: int Hunzip::getbuf() { michael@0: int p = 0; michael@0: int o = 0; michael@0: do { michael@0: if (inc == 0) inbits = fread(in, 1, BUFSIZE, fin) * 8; michael@0: for (; inc < inbits; inc++) { michael@0: int b = (in[inc / 8] & (1 << (7 - (inc % 8)))) ? 1 : 0; michael@0: int oldp = p; michael@0: p = dec[p].v[b]; michael@0: if (p == 0) { michael@0: if (oldp == lastbit) { michael@0: fclose(fin); michael@0: fin = NULL; michael@0: // add last odd byte michael@0: if (dec[lastbit].c[0]) out[o++] = dec[lastbit].c[1]; michael@0: return o; michael@0: } michael@0: out[o++] = dec[oldp].c[0]; michael@0: out[o++] = dec[oldp].c[1]; michael@0: if (o == BUFSIZE) return o; michael@0: p = dec[p].v[b]; michael@0: } michael@0: } michael@0: inc = 0; michael@0: } while (inbits == BUFSIZE * 8); michael@0: return fail(MSG_FORMAT, filename); michael@0: } michael@0: michael@0: const char * Hunzip::getline() { michael@0: char linebuf[BUFSIZE]; michael@0: int l = 0, eol = 0, left = 0, right = 0; michael@0: if (bufsiz == -1) return NULL; michael@0: while (l < bufsiz && !eol) { michael@0: linebuf[l++] = out[outc]; michael@0: switch (out[outc]) { michael@0: case '\t': break; michael@0: case 31: { // escape michael@0: if (++outc == bufsiz) { michael@0: bufsiz = getbuf(); michael@0: outc = 0; michael@0: } michael@0: linebuf[l - 1] = out[outc]; michael@0: break; michael@0: } michael@0: case ' ': break; michael@0: default: if (((unsigned char) out[outc]) < 47) { michael@0: if (out[outc] > 32) { michael@0: right = out[outc] - 31; michael@0: if (++outc == bufsiz) { michael@0: bufsiz = getbuf(); michael@0: outc = 0; michael@0: } michael@0: } michael@0: if (out[outc] == 30) left = 9; else left = out[outc]; michael@0: linebuf[l-1] = '\n'; michael@0: eol = 1; michael@0: } michael@0: } michael@0: if (++outc == bufsiz) { michael@0: outc = 0; michael@0: bufsiz = fin ? getbuf(): -1; michael@0: } michael@0: } michael@0: if (right) strcpy(linebuf + l - 1, line + strlen(line) - right - 1); michael@0: else linebuf[l] = '\0'; michael@0: strcpy(line + left, linebuf); michael@0: return line; michael@0: }