Subversion Repositories SvarDOS

Rev

Rev 219 | Rev 257 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 219 Rev 223
1
/*
1
/*
2
 * This file is part of the FDNPKG project
2
 * This file is part of the FDNPKG project
3
 * http://fdnpkg.sourceforge.net
3
 * http://fdnpkg.sourceforge.net
4
 *
4
 *
5
 * Copyright (C) 2012-2016 Mateusz Viste. All rights reserved.
5
 * Copyright (C) 2012-2016 Mateusz Viste. All rights reserved.
6
 *
6
 *
7
 * Simple library providing functions to unzip files from zip archives.
7
 * Simple library providing functions to unzip files from zip archives.
8
 */
8
 */
9
 
9
 
10
#include <stdio.h>     /* printf(), FILE, fclose()... */
10
#include <stdio.h>     /* printf(), FILE, fclose()... */
11
#include <stdlib.h>    /* NULL */
11
#include <stdlib.h>    /* NULL */
12
#include <string.h>    /* memset() */
12
#include <string.h>    /* memset() */
13
#include <time.h>      /* mktime() */
13
#include <time.h>      /* mktime() */
14
#include <utime.h>     /* utime() */
14
#include <utime.h>     /* utime() */
15
#include <unistd.h>   /* unlink() */
15
#include <unistd.h>   /* unlink() */
16
 
16
 
17
#include "crc32.h"
17
#include "crc32.h"
18
#include "kprintf.h"
18
#include "kprintf.h"
19
#include "parsecmd.h"
19
#include "parsecmd.h"
20
#ifndef NOLZMA
-
 
21
  #include "lzmadec.h"   /* LZMA support */
-
 
22
#endif
-
 
23
#include "inf.h"   /* DEFLATE support */
20
#include "inf.h"   /* DEFLATE support */
24
#include "version.h"
21
#include "version.h"
25
 
22
 
26
#include "libunzip.h"  /* include self for control */
23
#include "libunzip.h"  /* include self for control */
27
 
24
 
28
 
25
 
29
/* converts a "DOS format" timestamp into unix timestamp. The DOS timestamp is constructed an array of 4 bytes, that contains following data at the bit level:
26
/* converts a "DOS format" timestamp into unix timestamp. The DOS timestamp is constructed an array of 4 bytes, that contains following data at the bit level:
30
 * HHHHHMMM MMMSSSSS YYYYYYYM MMMDDDDD
27
 * HHHHHMMM MMMSSSSS YYYYYYYM MMMDDDDD
31
 *  where:
28
 *  where:
32
 * day of month is always within 1-31 range;
29
 * day of month is always within 1-31 range;
33
 * month is always within 1-12 range;
30
 * month is always within 1-12 range;
34
 * year starts from 1980 and continues for 127 years
31
 * year starts from 1980 and continues for 127 years
35
 * seconds are actually not 0-59 but rather 0-29 as there are only 32 possible values – to get actual seconds multiply this field by 2;
32
 * seconds are actually not 0-59 but rather 0-29 as there are only 32 possible values – to get actual seconds multiply this field by 2;
36
 * minutes are always within 0-59 range;
33
 * minutes are always within 0-59 range;
37
 * hours are always within 0-23 range.     */
34
 * hours are always within 0-23 range.     */
38
static time_t dostime2unix(unsigned char *buff) {
35
static time_t dostime2unix(unsigned char *buff) {
39
  struct tm curtime;
36
  struct tm curtime;
40
  time_t result;
37
  time_t result;
41
  memset(&curtime, 0, sizeof(curtime)); /* make sure to set everything in curtime to 0's */
38
  memset(&curtime, 0, sizeof(curtime)); /* make sure to set everything in curtime to 0's */
42
  curtime.tm_sec = (buff[0] & 31) << 1; /* seconds (0..60) */
39
  curtime.tm_sec = (buff[0] & 31) << 1; /* seconds (0..60) */
43
  curtime.tm_min = (((buff[1] << 8) | buff[0]) >> 5) & 63 ; /* minutes after the hour (0..59) */
40
  curtime.tm_min = (((buff[1] << 8) | buff[0]) >> 5) & 63 ; /* minutes after the hour (0..59) */
44
  curtime.tm_hour = (buff[1] >> 3); /* hours since midnight (0..23) */
41
  curtime.tm_hour = (buff[1] >> 3); /* hours since midnight (0..23) */
45
  curtime.tm_mday = buff[2] & 31; /* day of the month (1..31) */
42
  curtime.tm_mday = buff[2] & 31; /* day of the month (1..31) */
46
  curtime.tm_mon = ((((buff[3] << 8) | buff[2]) >> 5) & 15) - 1; /* months since January (0, 11) */
43
  curtime.tm_mon = ((((buff[3] << 8) | buff[2]) >> 5) & 15) - 1; /* months since January (0, 11) */
47
  curtime.tm_year = (buff[3] >> 1) + 80; /* years since 1900 */
44
  curtime.tm_year = (buff[3] >> 1) + 80; /* years since 1900 */
48
  curtime.tm_wday = 0; /* days since Sunday (0..6) - leave 0, mktime() will set it */
45
  curtime.tm_wday = 0; /* days since Sunday (0..6) - leave 0, mktime() will set it */
49
  curtime.tm_yday = 0; /* days since January 1 (0..365]) - leave 0, mktime() will set it */
46
  curtime.tm_yday = 0; /* days since January 1 (0..365]) - leave 0, mktime() will set it */
50
  curtime.tm_isdst = -1; /* Daylight Saving Time flag. Positive if DST is in effect, zero if not and negative if no information is available */
47
  curtime.tm_isdst = -1; /* Daylight Saving Time flag. Positive if DST is in effect, zero if not and negative if no information is available */
51
  result = mktime(&curtime);
48
  result = mktime(&curtime);
52
  if (result == (time_t)-1) return(0);
49
  if (result == (time_t)-1) return(0);
53
  return(result);
50
  return(result);
54
}
51
}
55
 
52
 
56
 
53
 
57
#ifndef NOLZMA
-
 
58
/* this is a wrapper on malloc(), used as a callback by lzmadec */
-
 
59
static void *SzAlloc(void *p, size_t size) {
-
 
60
  p = p; /* for gcc to not complain */
-
 
61
  if (size == 0) return(0);
-
 
62
  return(malloc(size));
-
 
63
}
-
 
64
 
-
 
65
/* this is a wrapper on free(), used as a callback by lzmadec */
-
 
66
static void SzFree(void *p, void *address) {
-
 
67
  p = p;  /* for gcc to not complain */
-
 
68
  free(address);
-
 
69
}
-
 
70
#endif
-
 
71
 
-
 
72
 
-
 
73
 
-
 
74
/* opens a zip file and provides the list of files in the archive.
54
/* opens a zip file and provides the list of files in the archive.
75
   returns a pointer to a ziplist (linked list) with all records, or NULL on error.
55
   returns a pointer to a ziplist (linked list) with all records, or NULL on error.
76
   The ziplist is allocated automatically, and must be freed via zip_freelist. */
56
   The ziplist is allocated automatically, and must be freed via zip_freelist. */
77
struct ziplist *zip_listfiles(FILE *fd) {
57
struct ziplist *zip_listfiles(FILE *fd) {
78
  struct ziplist *reslist = NULL;
58
  struct ziplist *reslist = NULL;
79
  struct ziplist *newentry;
59
  struct ziplist *newentry;
80
  unsigned long entrysig;
60
  unsigned long entrysig;
81
  unsigned short filenamelen, extrafieldlen, filecommentlen;
61
  unsigned short filenamelen, extrafieldlen, filecommentlen;
82
  unsigned long compfilelen;
62
  unsigned long compfilelen;
83
  int centraldirectoryfound = 0;
63
  int centraldirectoryfound = 0;
84
  unsigned int ux;
64
  unsigned int ux;
85
  unsigned char hdrbuff[64];
65
  unsigned char hdrbuff[64];
86
 
66
 
87
  rewind(fd);  /* make sure the file cursor is at the very beginning of the file */
67
  rewind(fd);  /* make sure the file cursor is at the very beginning of the file */
88
 
68
 
89
  for (;;) { /* read entry after entry */
69
  for (;;) { /* read entry after entry */
90
    int x, eofflag;
70
    int x, eofflag;
91
    long longbuff;
71
    long longbuff;
92
    entrysig = 0;
72
    entrysig = 0;
93
    eofflag = 0;
73
    eofflag = 0;
94
    /* read the entry signature first */
74
    /* read the entry signature first */
95
    for (x = 0; x < 32; x += 8) {
75
    for (x = 0; x < 32; x += 8) {
96
      if ((longbuff = fgetc(fd)) == EOF) {
76
      if ((longbuff = fgetc(fd)) == EOF) {
97
        eofflag = 1;
77
        eofflag = 1;
98
        break;
78
        break;
99
      }
79
      }
100
      entrysig |= (longbuff << x);
80
      entrysig |= (longbuff << x);
101
    }
81
    }
102
    if (eofflag != 0) break;
82
    if (eofflag != 0) break;
103
    /* printf("sig: 0x%08x\n", entrysig); */
83
    /* printf("sig: 0x%08x\n", entrysig); */
104
    if (entrysig == 0x04034b50ul) { /* local file */
84
    if (entrysig == 0x04034b50ul) { /* local file */
105
      unsigned int generalpurposeflags;
85
      unsigned int generalpurposeflags;
106
      /* read and parse the zip header */
86
      /* read and parse the zip header */
107
      fread(hdrbuff, 1, 26, fd);
87
      fread(hdrbuff, 1, 26, fd);
108
      /* read filename's length so I can allocate the proper amound of mem */
88
      /* read filename's length so I can allocate the proper amound of mem */
109
      filenamelen = hdrbuff[23];
89
      filenamelen = hdrbuff[23];
110
      filenamelen <<= 8;
90
      filenamelen <<= 8;
111
      filenamelen |= hdrbuff[22];
91
      filenamelen |= hdrbuff[22];
112
      /* create new entry and link it into the list */
92
      /* create new entry and link it into the list */
113
      newentry = calloc(sizeof(struct ziplist) + filenamelen, 1);
93
      newentry = calloc(sizeof(struct ziplist) + filenamelen, 1);
114
      if (newentry == NULL) {
94
      if (newentry == NULL) {
115
        kitten_puts(8, 0, "Out of memory!");
95
        kitten_puts(8, 0, "Out of memory!");
116
        zip_freelist(&reslist);
96
        zip_freelist(&reslist);
117
        break;
97
        break;
118
      }
98
      }
119
      newentry->nextfile = reslist;
99
      newentry->nextfile = reslist;
120
      newentry->flags = 0;
100
      newentry->flags = 0;
121
      reslist = newentry;
101
      reslist = newentry;
122
      /* read further areas of the header, and fill zip entry */
102
      /* read further areas of the header, and fill zip entry */
123
      generalpurposeflags = hdrbuff[3];  /* parse the general */
103
      generalpurposeflags = hdrbuff[3];  /* parse the general */
124
      generalpurposeflags <<= 8;         /* purpose flags and */
104
      generalpurposeflags <<= 8;         /* purpose flags and */
125
      generalpurposeflags |= hdrbuff[2]; /* save them for later */
105
      generalpurposeflags |= hdrbuff[2]; /* save them for later */
126
      newentry->compmethod = hdrbuff[4] | (hdrbuff[5] << 8);
106
      newentry->compmethod = hdrbuff[4] | (hdrbuff[5] << 8);
127
      newentry->timestamp = dostime2unix(&hdrbuff[6]);
107
      newentry->timestamp = dostime2unix(&hdrbuff[6]);
128
      newentry->crc32 = 0;
108
      newentry->crc32 = 0;
129
      for (x = 13; x >= 10; x--) {
109
      for (x = 13; x >= 10; x--) {
130
        newentry->crc32 <<= 8;
110
        newentry->crc32 <<= 8;
131
        newentry->crc32 |= hdrbuff[x];
111
        newentry->crc32 |= hdrbuff[x];
132
      }
112
      }
133
      newentry->compressedfilelen = 0;
113
      newentry->compressedfilelen = 0;
134
      for (x = 17; x >= 14; x--) {
114
      for (x = 17; x >= 14; x--) {
135
        newentry->compressedfilelen <<= 8;
115
        newentry->compressedfilelen <<= 8;
136
        newentry->compressedfilelen |= hdrbuff[x];
116
        newentry->compressedfilelen |= hdrbuff[x];
137
      }
117
      }
138
      newentry->filelen = 0;
118
      newentry->filelen = 0;
139
      for (x = 21; x >= 18; x--) {
119
      for (x = 21; x >= 18; x--) {
140
        newentry->filelen <<= 8;
120
        newentry->filelen <<= 8;
141
        newentry->filelen |= hdrbuff[x];
121
        newentry->filelen |= hdrbuff[x];
142
      }
122
      }
143
      extrafieldlen = hdrbuff[25];
123
      extrafieldlen = hdrbuff[25];
144
      extrafieldlen <<= 8;
124
      extrafieldlen <<= 8;
145
      extrafieldlen |= hdrbuff[24];
125
      extrafieldlen |= hdrbuff[24];
146
      /* printf("Filename len: %d / extrafield len: %d / compfile len: %ld / filelen: %ld\n", filenamelen, extrafieldlen, newentry->compressedfilelen, newentry->filelen); */
126
      /* printf("Filename len: %d / extrafield len: %d / compfile len: %ld / filelen: %ld\n", filenamelen, extrafieldlen, newentry->compressedfilelen, newentry->filelen); */
147
      /* check general purpose flags */
127
      /* check general purpose flags */
148
      if ((generalpurposeflags & 1) != 0) newentry->flags |= ZIP_FLAG_ENCRYPTED;
128
      if ((generalpurposeflags & 1) != 0) newentry->flags |= ZIP_FLAG_ENCRYPTED;
149
      /* parse the filename */
129
      /* parse the filename */
150
      for (ux = 0; ux < filenamelen; ux++) newentry->filename[ux] = fgetc(fd); /* store filename */
130
      for (ux = 0; ux < filenamelen; ux++) newentry->filename[ux] = fgetc(fd); /* store filename */
151
      if (newentry->filename[filenamelen - 1] == '/') newentry->flags |= ZIP_FLAG_ISADIR; /* if filename ends with / it's a dir. Note that ZIP forbids the usage of '\' in ZIP paths anyway */
131
      if (newentry->filename[filenamelen - 1] == '/') newentry->flags |= ZIP_FLAG_ISADIR; /* if filename ends with / it's a dir. Note that ZIP forbids the usage of '\' in ZIP paths anyway */
152
      /* printf("Filename: %s (%ld bytes compressed)\n", newentry->filename, newentry->compressedfilelen); */
132
      /* printf("Filename: %s (%ld bytes compressed)\n", newentry->filename, newentry->compressedfilelen); */
153
      newentry->dataoffset = ftell(fd) + extrafieldlen;
133
      newentry->dataoffset = ftell(fd) + extrafieldlen;
154
      /* skip rest of fields and data */
134
      /* skip rest of fields and data */
155
      fseek(fd, (extrafieldlen + newentry->compressedfilelen), SEEK_CUR);
135
      fseek(fd, (extrafieldlen + newentry->compressedfilelen), SEEK_CUR);
156
    } else if (entrysig == 0x02014b50ul) { /* central directory */
136
    } else if (entrysig == 0x02014b50ul) { /* central directory */
157
      centraldirectoryfound = 1;
137
      centraldirectoryfound = 1;
158
      /* parse header now */
138
      /* parse header now */
159
      fread(hdrbuff, 1, 42, fd);
139
      fread(hdrbuff, 1, 42, fd);
160
      filenamelen = hdrbuff[22] | (hdrbuff[23] << 8);
140
      filenamelen = hdrbuff[22] | (hdrbuff[23] << 8);
161
      extrafieldlen = hdrbuff[24] | (hdrbuff[25] << 8);
141
      extrafieldlen = hdrbuff[24] | (hdrbuff[25] << 8);
162
      filecommentlen = hdrbuff[26] | (hdrbuff[27] << 8);
142
      filecommentlen = hdrbuff[26] | (hdrbuff[27] << 8);
163
      compfilelen = 0;
143
      compfilelen = 0;
164
      for (x = 17; x >= 14; x--) {
144
      for (x = 17; x >= 14; x--) {
165
        compfilelen <<= 8;
145
        compfilelen <<= 8;
166
        compfilelen |= hdrbuff[x];
146
        compfilelen |= hdrbuff[x];
167
      }
147
      }
168
      /* printf("central dir\n"); */
148
      /* printf("central dir\n"); */
169
      /* skip rest of fields and data */
149
      /* skip rest of fields and data */
170
      fseek(fd, (filenamelen + extrafieldlen + compfilelen + filecommentlen), SEEK_CUR);
150
      fseek(fd, (filenamelen + extrafieldlen + compfilelen + filecommentlen), SEEK_CUR);
171
    } else if (entrysig == 0x08074b50ul) { /* Data descriptor header */
151
    } else if (entrysig == 0x08074b50ul) { /* Data descriptor header */
172
      /* no need to read the header we just have to skip it */
152
      /* no need to read the header we just have to skip it */
173
      fseek(fd, 12, SEEK_CUR); /* the header is 3x4 bytes (CRC + compressed len + uncompressed len) */
153
      fseek(fd, 12, SEEK_CUR); /* the header is 3x4 bytes (CRC + compressed len + uncompressed len) */
174
    } else { /* unknown sig */
154
    } else { /* unknown sig */
175
      kitten_printf(8, 1, "unknown zip sig: 0x%08lx", entrysig);
155
      kitten_printf(8, 1, "unknown zip sig: 0x%08lx", entrysig);
176
      puts("");
156
      puts("");
177
      zip_freelist(&reslist);
157
      zip_freelist(&reslist);
178
      break;
158
      break;
179
    }
159
    }
180
  }
160
  }
181
  /* if we got no central directory record, the file is incomplete */
161
  /* if we got no central directory record, the file is incomplete */
182
  if (centraldirectoryfound == 0) zip_freelist(&reslist);
162
  if (centraldirectoryfound == 0) zip_freelist(&reslist);
183
  return(reslist);
163
  return(reslist);
184
}
164
}
185
 
165
 
186
 
166
 
187
 
167
 
188
/* unzips a file. zipfd points to the open zip file, curzipnode to the entry to extract, and fulldestfilename is the destination file where to unzip it. returns 0 on success, non-zero otherwise. */
168
/* unzips a file. zipfd points to the open zip file, curzipnode to the entry to extract, and fulldestfilename is the destination file where to unzip it. returns 0 on success, non-zero otherwise. */
189
int zip_unzip(FILE *zipfd, struct ziplist *curzipnode, char *fulldestfilename) {
169
int zip_unzip(FILE *zipfd, struct ziplist *curzipnode, char *fulldestfilename) {
190
  #define buffsize 32 * 1024l /* MUST be at least 32K */
170
  #define buffsize 32 * 1024l /* MUST be at least 32K */
191
  FILE *filefd;
171
  FILE *filefd;
192
  unsigned long cksum;
172
  unsigned long cksum;
193
  int extract_res;
173
  int extract_res;
194
  unsigned char *buff;
174
  unsigned char *buff;
195
  struct utimbuf filetimestamp;
175
  struct utimbuf filetimestamp;
196
 
176
 
197
  /* first of all, check we support the compression method */
177
  /* first of all, check we support the compression method */
198
  switch (curzipnode->compmethod) {
178
  switch (curzipnode->compmethod) {
199
    case 0:  /* stored */
179
    case 0:  /* stored */
200
    case 8:  /* deflated */
180
    case 8:  /* deflated */
201
#ifndef NOLZMA
-
 
202
    case 14: /* lzma */
-
 
203
#endif
-
 
204
      break;
181
      break;
205
    default: /* unsupported compression method, sorry */
182
    default: /* unsupported compression method, sorry */
206
      return(-1);
183
      return(-1);
207
      break;
184
      break;
208
  }
185
  }
209
 
186
 
210
  /* open the dst file */
187
  /* open the dst file */
211
  filefd = fopen(fulldestfilename, "wb");
188
  filefd = fopen(fulldestfilename, "wb");
212
  if (filefd == NULL) return(-2);  /* failed to open the dst file */
189
  if (filefd == NULL) return(-2);  /* failed to open the dst file */
213
 
190
 
214
  /* allocate buffers for data I/O */
191
  /* allocate buffers for data I/O */
215
  buff = malloc(buffsize);
192
  buff = malloc(buffsize);
216
  if (buff == NULL) {
193
  if (buff == NULL) {
217
    fclose(filefd);
194
    fclose(filefd);
218
    unlink(fulldestfilename); /* remove the failed file once it is closed */
195
    unlink(fulldestfilename); /* remove the failed file once it is closed */
219
    return(-6);
196
    return(-6);
220
  }
197
  }
221
 
198
 
222
  if (fseek(zipfd, curzipnode->dataoffset, SEEK_SET) != 0) { /* set the reading position inside the zip file */
199
  if (fseek(zipfd, curzipnode->dataoffset, SEEK_SET) != 0) { /* set the reading position inside the zip file */
223
    free(buff);
200
    free(buff);
224
    fclose(filefd);
201
    fclose(filefd);
225
    unlink(fulldestfilename); /* remove the failed file once it is closed */
202
    unlink(fulldestfilename); /* remove the failed file once it is closed */
226
    return(-7);
203
    return(-7);
227
  }
204
  }
228
  extract_res = -255;
205
  extract_res = -255;
229
 
206
 
230
  cksum = crc32_init(); /* init the crc32 */
207
  cksum = crc32_init(); /* init the crc32 */
231
 
208
 
232
  if (curzipnode->compmethod == 0) { /* if the file is stored, copy it over */
209
  if (curzipnode->compmethod == 0) { /* if the file is stored, copy it over */
233
    long i, toread;
210
    long i, toread;
234
    extract_res = 0;   /* assume we will succeed */
211
    extract_res = 0;   /* assume we will succeed */
235
    for (i = 0; i < curzipnode->filelen;) {
212
    for (i = 0; i < curzipnode->filelen;) {
236
      toread = curzipnode->filelen - i;
213
      toread = curzipnode->filelen - i;
237
      if (toread > buffsize) toread = buffsize;
214
      if (toread > buffsize) toread = buffsize;
238
      if (fread(buff, toread, 1, zipfd) != 1) extract_res = -3;   /* read a chunk of data */
215
      if (fread(buff, toread, 1, zipfd) != 1) extract_res = -3;   /* read a chunk of data */
239
      crc32_feed(&cksum, buff, toread); /* update the crc32 checksum */
216
      crc32_feed(&cksum, buff, toread); /* update the crc32 checksum */
240
      if (fwrite(buff, toread, 1, filefd) != 1) extract_res = -4; /* write data chunk to dst file */
217
      if (fwrite(buff, toread, 1, filefd) != 1) extract_res = -4; /* write data chunk to dst file */
241
      i += toread;
218
      i += toread;
242
    }
219
    }
243
  } else if (curzipnode->compmethod == 8) {  /* if the file is deflated, inflate it */
220
  } else if (curzipnode->compmethod == 8) {  /* if the file is deflated, inflate it */
244
    extract_res = inf(zipfd, filefd, buff, &cksum, curzipnode->compressedfilelen);
221
    extract_res = inf(zipfd, filefd, buff, &cksum, curzipnode->compressedfilelen);
245
#ifndef NOLZMA
-
 
246
  } else if (curzipnode->compmethod == 14) {  /* LZMA */
-
 
247
    #define lzmaoutbufflen 32768u
-
 
248
    long bytesread, bytesreadtotal = 0, byteswritetotal = 0;
-
 
249
    SizeT buffoutreslen;
-
 
250
    ISzAlloc g_alloc;
-
 
251
    ELzmaStatus lzmastatus;
-
 
252
    SRes lzmaresult;
-
 
253
    CLzmaDec lzmahandle;
-
 
254
    unsigned char lzmahdr[LZMA_PROPS_SIZE]; /* 5 bytes of properties */
-
 
255
    unsigned char *lzmaoutbuff;
-
 
256
 
-
 
257
    extract_res = -5; /* assume we will fail. if we don't - then we will update this flag */
-
 
258
    lzmaoutbuff = malloc(lzmaoutbufflen);
-
 
259
    if (lzmaoutbuff == NULL) {
-
 
260
      free(buff);
-
 
261
      fclose(filefd);   /* close the dst file */
-
 
262
      return(-33);
-
 
263
    }
-
 
264
 
-
 
265
    fread(lzmahdr, 4, 1, zipfd); /* load the 4 bytes long 'zip-lzma header */
-
 
266
    bytesreadtotal = 4; /* remember we read 4 bytes already */
-
 
267
 
-
 
268
    /* lzma properties should be exactly 5 bytes long. If it's not, it's either not valid lzma, or some version that wasn't existing yet when I wrote these words. Also, check that the lzma content is at least 9 bytes long and that our previous malloc() calls suceeded. */
-
 
269
    if ((lzmahdr[2] == 5) && (lzmahdr[3] == 0) && (curzipnode->compressedfilelen >= 9)) {
-
 
270
 
-
 
271
      extract_res = 0;  /* since we got so far, let's assume we will succeed now */
-
 
272
 
-
 
273
      g_alloc.Alloc = SzAlloc; /* these will be used as callbacks by lzma to manage memory */
-
 
274
      g_alloc.Free = SzFree;
-
 
275
 
-
 
276
      fread(lzmahdr, sizeof(lzmahdr), 1, zipfd); /* load the lzma header */
-
 
277
      bytesreadtotal += sizeof(lzmahdr);
-
 
278
 
-
 
279
      /* Note, that in a 'normal' lzma stream we would have now 8 bytes with the uncompressed length of the file. Here we don't. ZIP cut this information out, since it stores it already in its own header. */
-
 
280
 
-
 
281
      memset(&lzmahandle, 0, sizeof(lzmahandle)); /* reset the whole lzmahandle structure - not doing this leads to CRASHES!!! */
-
 
282
      LzmaDec_Init(&lzmahandle);
-
 
283
      lzmaresult = LzmaDec_Allocate(&lzmahandle, lzmahdr, LZMA_PROPS_SIZE, &g_alloc); /* forget not to LzmaDec_Free() later! */
-
 
284
      if (lzmaresult != 0) extract_res = -13;
-
 
285
 
-
 
286
      while (extract_res == 0) {
-
 
287
        bytesread = buffsize;
-
 
288
        if (bytesread > curzipnode->compressedfilelen - bytesreadtotal) bytesread = curzipnode->compressedfilelen - bytesreadtotal;
-
 
289
        buffoutreslen = lzmaoutbufflen;
-
 
290
        /* printf("Will read %d bytes from input stream\n", bytesread); */
-
 
291
        fread(buff, bytesread, 1, zipfd); /* read stuff from input stream */
-
 
292
        fseek(zipfd, 0 - bytesread, SEEK_CUR); /* get back to the position at the start of our chunk of data */
-
 
293
        lzmaresult = LzmaDec_DecodeToBuf(&lzmahandle, lzmaoutbuff, &buffoutreslen, buff, (SizeT *)&bytesread, LZMA_FINISH_ANY, &lzmastatus);
-
 
294
        bytesreadtotal += bytesread;
-
 
295
        /* printf("expanded %ld bytes into %ld (total read: %ld bytes)\n", (long)bytesread, (long)buffoutreslen, (long)bytesreadtotal); */
-
 
296
        fseek(zipfd, bytesread, SEEK_CUR); /* go forward to the position next to the input we processed */
-
 
297
        if (lzmaresult != SZ_OK) {
-
 
298
          extract_res = -20;
-
 
299
          if (lzmaresult == SZ_ERROR_DATA) extract_res = -21;        /* DATA ERROR */
-
 
300
          if (lzmaresult == SZ_ERROR_MEM) extract_res = -22;         /* MEMORY ALLOC ERROR */
-
 
301
          if (lzmaresult == SZ_ERROR_UNSUPPORTED) extract_res = -23; /* UNSUPPORTED PROPERTY */
-
 
302
          if (lzmaresult == SZ_ERROR_INPUT_EOF) extract_res = -24;   /* NEED MORE INPUT */
-
 
303
          break;
-
 
304
        }
-
 
305
        /* check that we haven't got TOO MUCH decompressed data, and trim if necessary. It happens that LZMA provides a few bytes more than it should at the end of the stream. */
-
 
306
        if (byteswritetotal + (long)buffoutreslen > curzipnode->filelen) {
-
 
307
          buffoutreslen = curzipnode->filelen - byteswritetotal;
-
 
308
        }
-
 
309
        byteswritetotal += buffoutreslen;
-
 
310
        fwrite(lzmaoutbuff, buffoutreslen, 1, filefd); /* write stuff to output file */
-
 
311
        crc32_feed(&cksum, lzmaoutbuff, buffoutreslen);
-
 
312
        /* if (lzmastatus == LZMA_STATUS_FINISHED_WITH_MARK) puts("lzma says we are done!"); */
-
 
313
        if ((lzmastatus == LZMA_STATUS_FINISHED_WITH_MARK) || (bytesreadtotal >= curzipnode->compressedfilelen)) {
-
 
314
          extract_res = 0; /* looks like we succeeded! */
-
 
315
          break;
-
 
316
        }
-
 
317
      }
-
 
318
      LzmaDec_Free(&lzmahandle, &g_alloc); /* this will free all the stuff we allocated via LzmaDec_Allocate() */
-
 
319
      /* printf("Processed %d bytes of input into %d bytes of output. CRC32: %08lX\n", bytesreadtotal, byteswritetotal, crc32); */
-
 
320
    }
-
 
321
    free(lzmaoutbuff);
-
 
322
#endif
-
 
323
  }
222
  }
324
 
223
 
325
  /* clean up memory, close the dst file and terminates crc32 */
224
  /* clean up memory, close the dst file and terminates crc32 */
326
  free(buff);
225
  free(buff);
327
  fclose(filefd);   /* close the dst file */
226
  fclose(filefd);   /* close the dst file */
328
  crc32_finish(&cksum);
227
  crc32_finish(&cksum);
329
 
228
 
330
  /* printf("extract_res=%d / cksum_expected=%08lX / cksum_obtained=%08lX\n", extract_res, curzipnode->crc32, cksum); */
229
  /* printf("extract_res=%d / cksum_expected=%08lX / cksum_obtained=%08lX\n", extract_res, curzipnode->crc32, cksum); */
331
  if (extract_res != 0) {  /* was the extraction process successful? */
230
  if (extract_res != 0) {  /* was the extraction process successful? */
332
    unlink(fulldestfilename); /* remove the failed file */
231
    unlink(fulldestfilename); /* remove the failed file */
333
    return(extract_res);
232
    return(extract_res);
334
  }
233
  }
335
  if (cksum != curzipnode->crc32) { /* is the crc32 ok after extraction? */
234
  if (cksum != curzipnode->crc32) { /* is the crc32 ok after extraction? */
336
    unlink(fulldestfilename); /* remove the failed file */
235
    unlink(fulldestfilename); /* remove the failed file */
337
    return(-9);
236
    return(-9);
338
  }
237
  }
339
  /* Set the timestamp of the new file to what was set in the zip file */
238
  /* Set the timestamp of the new file to what was set in the zip file */
340
  filetimestamp.actime  = curzipnode->timestamp;
239
  filetimestamp.actime  = curzipnode->timestamp;
341
  filetimestamp.modtime = curzipnode->timestamp;
240
  filetimestamp.modtime = curzipnode->timestamp;
342
  utime(fulldestfilename, &filetimestamp);
241
  utime(fulldestfilename, &filetimestamp);
343
  return(0);
242
  return(0);
344
}
243
}
345
 
244
 
346
 
245
 
347
 
246
 
348
/* Call this to free a ziplist computed by zip_listfiles() */
247
/* Call this to free a ziplist computed by zip_listfiles() */
349
void zip_freelist(struct ziplist **ziplist) {
248
void zip_freelist(struct ziplist **ziplist) {
350
  struct ziplist *zipentrytobefreed;
249
  struct ziplist *zipentrytobefreed;
351
  while (*ziplist != NULL) { /* iterate through the linked list and free all nodes */
250
  while (*ziplist != NULL) { /* iterate through the linked list and free all nodes */
352
    zipentrytobefreed = *ziplist;
251
    zipentrytobefreed = *ziplist;
353
    *ziplist = zipentrytobefreed->nextfile;
252
    *ziplist = zipentrytobefreed->nextfile;
354
    /* free the node entry */
253
    /* free the node entry */
355
    free(zipentrytobefreed);
254
    free(zipentrytobefreed);
356
  }
255
  }
357
  *ziplist = NULL;
256
  *ziplist = NULL;
358
}
257
}
359
 
258