summaryrefslogtreecommitdiff
path: root/zip.c
blob: 42ac8860c5f47b649e7cea7f522a66ab8fc5c11b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* zip.c -- compress files to the gzip or pkzip format

   Copyright (C) 1997-1999, 2006-2007, 2009-2023 Free Software Foundation, Inc.
   Copyright (C) 1992-1993 Jean-loup Gailly

   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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <config.h>
#include <ctype.h>

#include "tailor.h"
#include "gzip.h"

off_t header_bytes;   /* number of bytes in gzip header */

/* Speed options for the general purpose bit flag.  */
enum { SLOW = 2, FAST = 4 };

/* ===========================================================================
 * Deflate in to out.
 * IN assertions: the input and output buffers are cleared.
 *   The variables time_stamp and save_orig_name are initialized.
 * 'in' and 'out' are input and output file descriptors.
 */
int
zip (int in, int out)
{
    uch  flags = 0;         /* general purpose bit flags */
    ush  attr = 0;          /* ascii/binary flag */
    ush  deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
    ulg  stamp;

    ifd = in;
    ofd = out;
    outcnt = 0;

    /* Write the header to the gzip file. See algorithm.doc for the format */

    method = DEFLATED;
    put_byte(GZIP_MAGIC[0]); /* magic header */
    put_byte(GZIP_MAGIC[1]);
    put_byte(DEFLATED);      /* compression method */

    if (save_orig_name) {
        flags |= ORIG_NAME;
    }
    put_byte(flags);         /* general flags */
    if (time_stamp.tv_nsec < 0)
      stamp = 0;
    else if (0 < time_stamp.tv_sec && time_stamp.tv_sec <= 0xffffffff)
      stamp = time_stamp.tv_sec;
    else
      {
        /* It's intended that timestamp 0 generates this warning,
           since gzip format reserves 0 for something else.  */
        warning ("file timestamp out of range for gzip format");
        stamp = 0;
      }
    put_long (stamp);

    /* Write deflated file to zip file */
    updcrc (NULL, 0);

    bi_init(out);
    ct_init(&attr, &method);
    if (level == 1)
      deflate_flags |= FAST;
    else if (level == 9)
      deflate_flags |= SLOW;

    put_byte((uch)deflate_flags); /* extra flags */
    put_byte(OS_CODE);            /* OS identifier */

    if (save_orig_name) {
        char *p = gzip_base_name (ifname); /* Don't save the directory part. */
        do {
            put_byte (*p);
        } while (*p++);
    }
    header_bytes = (off_t)outcnt;

#ifdef IBM_Z_DFLTCC
    dfltcc_deflate (level);
#else
    deflate (level);
#endif

#ifndef NO_SIZE_CHECK
  /* Check input size
   * (but not on MSDOS -- diet in TSR mode reports an incorrect file size)
   */
    if (ifile_size != -1L && bytes_in != ifile_size) {
        fprintf(stderr, "%s: %s: file size changed while zipping\n",
                program_name, ifname);
    }
#endif

    /* Write the crc and uncompressed size */
    put_long (getcrc ());
    put_long((ulg)bytes_in);
    header_bytes += 2*4;

    flush_outbuf();
    return OK;
}


/* ===========================================================================
 * Read a new buffer from the current input file, perform end-of-line
 * translation, and update the crc and input file size.
 * IN assertion: size >= 2 (for end-of-line translation)
 */
int
file_read (char *buf, unsigned size)
{
    unsigned len;

    Assert(insize == 0, "inbuf not empty");

    len = read_buffer (ifd, buf, size);
    if (len == 0) return (int)len;
    if (len == (unsigned)-1) {
        read_error();
    }

    updcrc ((uch *) buf, len);
    bytes_in += (off_t)len;
    return (int)len;
}