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