Fewer memory leaks
[pspp] / src / libpspp / zip-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <errno.h>
26 #include <xalloc.h>
27 #include <libpspp/assertion.h>
28
29 #include <byteswap.h>
30 #include <crc.h>
31
32 #include "inflate.h"
33
34 #include "str.h"
35
36 #include "zip-reader.h"
37 #include "zip-private.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) (msgid)
42
43
44 static bool find_eocd (FILE *fp, off_t *off);
45
46 static int
47 stored_read (struct zip_member *zm, void *buf, size_t n)
48 {
49   return fread (buf, 1, n, zm->fp);
50 }
51
52 static bool
53 stored_init (struct zip_member *zm UNUSED)
54 {
55   return true;
56 }
57
58 static void
59 stored_finish (struct zip_member *zm UNUSED)
60 {
61   /* Nothing required */
62 }
63
64
65 static struct decompressor decompressors[n_COMPRESSION] = 
66   {
67     {stored_init, stored_read, stored_finish},
68 #if HAVE_ZLIB_H
69     {inflate_init, inflate_read, inflate_finish}
70 #endif
71   };
72
73 static enum compression
74 comp_code (struct zip_member *zm, uint16_t c)
75 {
76   enum compression which;
77   switch (c)
78     {
79     case 0:
80       which = COMPRESSION_STORED;
81       break;
82 #if HAVE_ZLIB_H
83     case 8:
84       which = COMPRESSION_INFLATE;
85       break;
86 #endif
87     default:
88       ds_put_format (zm->errs, _("Unsupported compression type (%d)"), c);
89       which = n_COMPRESSION;
90       break;
91     }
92   return which;
93 }
94
95
96 struct zip_reader
97 {
98   char *filename;                  /* The name of the file from which the data is read */
99   FILE *fr;                        /* The stream from which the meta data is read */
100   uint16_t n_members;              /* The number of members in this archive */
101   struct zip_member **members;     /* The members (may be null pointers until the headers have been read */
102   int nm;
103   struct string *errs;
104 };
105
106 void
107 zip_member_finish (struct zip_member *zm)
108 {
109   ds_clear (zm->errs);
110   /*  Probably not useful, because we would have to read right to the end of the member
111   if (zm->expected_crc != zm->crc)
112     {
113       ds_put_cstr (zm->errs, _("CRC error reading zip"));
114     }
115   */
116   zip_member_unref (zm);
117 }
118
119
120
121 /* Destroy the zip reader */
122 void
123 zip_reader_destroy (struct zip_reader *zr)
124 {
125   int i;
126   if (zr == NULL) 
127     return;
128
129   if (zr->fr != NULL)
130     fclose (zr->fr);
131
132   free (zr->filename);
133
134   for (i = 0; i < zr->n_members; ++i)
135     {
136       zip_member_unref (zr->members[i]);
137     }
138   free (zr->members);
139   free (zr);
140 }
141
142
143 void
144 zm_dump (const struct zip_member *zm)
145 {
146   printf ("%d\t%08x\t %s\n", zm->ucomp_size, zm->expected_crc, zm->name);
147 }
148
149
150 /* Skip N bytes in F */
151 static void
152 skip_bytes (FILE *f, size_t n)
153 {
154   fseeko (f, n, SEEK_CUR);
155 }
156
157 /* Read N bytes from F, storing the result in X */
158 static void
159 get_bytes (FILE *f, void *x, size_t n)
160 {
161   fread (x, 1, n, f);
162 }
163
164 /* Read a 32 bit value from F */
165 static void
166 get_u32 (FILE *f, uint32_t *v)
167 {
168   uint32_t x;
169   get_bytes (f, &x, sizeof x);
170 #ifdef WORDS_BIGENDIAN
171   *v = bswap_32 (x);
172 #else
173   *v = x;
174 #endif
175 }
176
177 /* Read a 16 bit value from F */
178 static void
179 get_u16 (FILE *f, uint16_t *v)
180 {
181   uint16_t x;
182   get_bytes (f, &x, sizeof x);
183 #ifdef WORDS_BIGENDIAN
184   *v = bswap_16 (x);
185 #else
186   *v = x;
187 #endif
188 }
189
190
191 /* Read 32 bit integer and compare it with EXPECTED.
192    place an error string in ERR if necessary. */
193 static bool
194 check_magic (FILE *f, uint32_t expected, struct string *err)
195 {
196   uint32_t magic;
197
198   get_u32 (f, &magic);
199
200   if ((expected != magic))
201     {
202       ds_put_format (err,
203                      _("Corrupt file at 0x%llx: Expected %"PRIx32"; got %"PRIx32), 
204                      (long long int) ftello (f) - sizeof (uint32_t), expected, magic);
205
206       return false;
207     }
208   return true;
209 }
210
211
212 /* Reads upto BYTES bytes from ZM and puts them in BUF.
213    Returns the number of bytes read, or -1 on error */
214 int
215 zip_member_read (struct zip_member *zm, void *buf, size_t bytes)
216 {
217   int bytes_read = 0;
218
219   ds_clear (zm->errs);
220
221   if ( bytes > zm->bytes_unread)
222     bytes = zm->bytes_unread;
223
224   bytes_read  = decompressors[zm->compression].read (zm, buf, bytes);
225   if ( bytes_read < 0)
226     return bytes_read;
227
228   zm->crc = crc32_update (zm->crc, buf, bytes_read);
229
230   zm->bytes_unread -= bytes_read;
231
232   return bytes_read;
233 }
234
235
236 /*
237   Read a local file header from ZR and add it to ZR's internal array.
238   Returns a pointer to the member read.  This pointer belongs to ZR.
239   If the caller wishes to control it, she should ref it with 
240   zip_member_ref.
241 */
242 static struct zip_member *
243 zip_header_read_next (struct zip_reader *zr)
244 {
245   struct zip_member *zm = xzalloc (sizeof *zm);
246
247   uint16_t v, nlen, extralen;
248   uint16_t gp, time, date;
249   
250   uint16_t clen, diskstart, iattr;
251   uint32_t eattr;
252   uint16_t comp_type;
253
254   ds_clear (zr->errs);
255
256   if ( ! check_magic (zr->fr, MAGIC_SOCD, zr->errs))
257     return NULL;
258
259   get_u16 (zr->fr, &v);
260
261   get_u16 (zr->fr, &v);
262   get_u16 (zr->fr, &gp);
263   get_u16 (zr->fr, &comp_type);
264
265   zm->compression = comp_code (zm, comp_type);
266
267   get_u16 (zr->fr, &time);
268   get_u16 (zr->fr, &date);
269   get_u32 (zr->fr, &zm->expected_crc);
270   get_u32 (zr->fr, &zm->comp_size);
271   get_u32 (zr->fr, &zm->ucomp_size);
272   get_u16 (zr->fr, &nlen);
273   get_u16 (zr->fr, &extralen);
274   get_u16 (zr->fr, &clen);
275   get_u16 (zr->fr, &diskstart);
276   get_u16 (zr->fr, &iattr);
277   get_u32 (zr->fr, &eattr);
278   get_u32 (zr->fr, &zm->offset);
279
280   zm->name = xzalloc (nlen + 1);
281   get_bytes (zr->fr, zm->name, nlen);
282
283   skip_bytes (zr->fr, extralen);
284   
285   zr->members[zr->nm++] = zm;
286
287   zm->fp = fopen (zr->filename, "r");
288   zm->ref_cnt = 1;
289   zm->errs = zr->errs;
290
291   return zm;
292 }
293
294
295 /* Create a reader from the zip called FILENAME */
296 struct zip_reader *
297 zip_reader_create (const char *filename, struct string *errs)
298 {
299   uint16_t disknum, total_members;
300   off_t offset = 0;
301   uint32_t central_dir_start, central_dir_length;
302
303   struct zip_reader *zr = xzalloc (sizeof *zr);
304   zr->errs = errs;
305   if ( zr->errs)
306     ds_init_empty (zr->errs);
307
308   zr->nm = 0;
309
310   zr->fr = fopen (filename, "r");
311   if (NULL == zr->fr)
312     {
313       ds_put_cstr (zr->errs, strerror (errno));
314       free (zr);
315       return NULL;
316     }
317
318   if ( ! check_magic (zr->fr, MAGIC_LHDR, zr->errs))
319     {
320       fclose (zr->fr);
321       free (zr);
322       return NULL;
323     }
324
325   if ( ! find_eocd (zr->fr, &offset))
326     {
327       ds_put_format (zr->errs, _("Cannot find central directory"));
328       fclose (zr->fr);
329       free (zr);
330       return NULL;
331     }
332
333   if ( 0 != fseeko (zr->fr, offset, SEEK_SET))
334     {
335       const char *mm = strerror (errno);
336       ds_put_format (zr->errs, _("Failed to seek to end of central directory record: %s"), mm);
337       fclose (zr->fr);
338       free (zr);
339       return NULL;
340     }
341
342
343   if ( ! check_magic (zr->fr, MAGIC_EOCD, zr->errs))
344     {
345       fclose (zr->fr);
346       free (zr);
347       return NULL;
348     }
349   
350   get_u16 (zr->fr, &disknum);
351   get_u16 (zr->fr, &disknum);
352
353   get_u16 (zr->fr, &zr->n_members);
354   get_u16 (zr->fr, &total_members);
355
356   get_u32 (zr->fr, &central_dir_length);
357   get_u32 (zr->fr, &central_dir_start);
358
359   if ( 0 != fseeko (zr->fr, central_dir_start, SEEK_SET))
360     {
361       const char *mm = strerror (errno);
362       ds_put_format (zr->errs, _("Failed to seek to central directory: %s"), mm);
363       fclose (zr->fr);
364       free (zr);
365       return NULL;
366     }
367
368   zr->members = xcalloc (zr->n_members, sizeof (*zr->members));
369   memset (zr->members, 0, zr->n_members * sizeof (*zr->members));
370
371   zr->filename = strdup (filename);
372
373   return zr;
374 }
375
376
377
378 /* Return the member called MEMBER from the reader ZR  */
379 struct zip_member *
380 zip_member_open (struct zip_reader *zr, const char *member)
381 {
382   uint16_t v, nlen, extra_len;
383   uint16_t gp, comp_type, time, date;
384   uint32_t ucomp_size, comp_size;
385   
386   uint32_t crc;
387
388   char *name = NULL;
389
390   int i;
391   struct zip_member *zm = NULL;
392
393   if ( zr == NULL)
394     return NULL;
395
396   for (i = 0; i < zr->n_members; ++i)
397   {
398     zm = zr->members[i];
399
400     if (zm == NULL)
401       zm = zr->members[i] = zip_header_read_next (zr);
402     if (zm && 0 == strcmp (zm->name, member))
403       break;
404     else
405       zm = NULL;
406   }
407   
408   if ( zm == NULL)
409     return NULL;
410
411   if ( 0 != fseeko (zm->fp, zm->offset, SEEK_SET))
412     {
413       const char *mm = strerror (errno);
414       ds_put_format (zm->errs, _("Failed to seek to start of member `%s': %s"), zm->name, mm);
415       return NULL;
416     }
417
418   if ( ! check_magic (zm->fp, MAGIC_LHDR, zr->errs))
419     {
420       return NULL;
421     }
422
423   get_u16 (zm->fp, &v);
424   get_u16 (zm->fp, &gp);
425   get_u16 (zm->fp, &comp_type);
426   zm->compression = comp_code (zm, comp_type);
427   get_u16 (zm->fp, &time);
428   get_u16 (zm->fp, &date);
429   get_u32 (zm->fp, &crc);
430   get_u32 (zm->fp, &comp_size);
431
432   get_u32 (zm->fp, &ucomp_size);
433   get_u16 (zm->fp, &nlen);
434   get_u16 (zm->fp, &extra_len);
435
436   name = xzalloc (nlen + 1);
437
438   get_bytes (zm->fp, name, nlen);
439
440   skip_bytes (zm->fp, extra_len);
441
442   if (strcmp (name, zm->name) != 0)
443     {
444       ds_put_format (zm->errs,
445                      _("Name mismatch in zip archive. Central directory says `%s'; local file header says `%s'"),
446                      zm->name, name);
447       free (name);
448       free (zm);
449       return NULL;
450     }
451
452   free (name);
453
454   zm->bytes_unread = zm->ucomp_size;
455
456   if ( !  decompressors[zm->compression].init (zm) )
457     return NULL;
458
459   return zm;
460 }
461
462 void
463 zip_member_ref (struct zip_member *zm)
464 {
465   zm->ref_cnt++;
466 }
467
468
469
470
471 void
472 zip_member_unref (struct zip_member *zm)
473 {
474   if ( zm == NULL)
475     return;
476
477   if (--zm->ref_cnt == 0)
478     {
479       decompressors[zm->compression].finish (zm);
480       if (zm->fp)
481         fclose (zm->fp);
482       free (zm->name);
483       free (zm);
484     }
485 }
486
487
488 \f
489
490 static bool probe_magic (FILE *fp, uint32_t magic, off_t start, off_t stop, off_t *off);
491
492
493 /* Search for something that looks like the End Of Central Directory in FP.
494    If found, the offset of the record will be placed in OFF.
495    Returns true if found false otherwise.
496 */
497 static bool
498 find_eocd (FILE *fp, off_t *off)
499 {
500   off_t start, stop;
501   const uint32_t magic = MAGIC_EOCD;
502   bool found = false;
503
504   /* The magic cannot be more than 22 bytes from the end of the file, 
505      because that is the minimum length of the EndOfCentralDirectory
506      record.
507    */
508   if ( 0 > fseeko (fp, -22, SEEK_END))
509     {
510       return false;
511     }
512   start = ftello (fp);
513   stop = start + sizeof (magic);
514   do 
515     {
516       found = probe_magic (fp, magic, start, stop, off);
517       /* FIXME: For extra confidence lookup the directory start record here*/
518       if ( start == 0)
519         break;
520       stop = start + sizeof (magic);
521       start >>= 1;
522     }
523   while (!found );
524
525   return found;
526 }
527
528
529 /*
530   Search FP for MAGIC starting at START and reaching until STOP.
531   Returns true iff MAGIC is found.  False otherwise.
532   OFF receives the location of the magic.
533 */
534 static bool
535 probe_magic (FILE *fp, uint32_t magic, off_t start, off_t stop, off_t *off)
536 {
537   int i;
538   int state = 0;
539   unsigned char seq[4];
540   unsigned char byte;
541
542   if ( 0 > fseeko (fp, start, SEEK_SET))
543     {
544       return -1;
545     }
546
547   for (i = 0; i < 4 ; ++i)
548     {
549       seq[i] = (magic >> i * 8) & 0xFF;
550     }
551
552   do
553     {
554       fread (&byte, 1, 1, fp);
555
556       if ( byte == seq[state])
557         state++;
558       else
559         state = 0;
560       
561       if ( state == 4)
562         {
563           *off = ftello (fp) - 4;
564           return true;
565         }
566       start++;
567       if ( start >= stop)
568         break;
569     }
570   while (!feof (fp));
571
572   return false;
573 }
574