OSDN Git Service

e5d4f17347f4bf7cecde217dd818be1543088ef4
[uclinux-h8/elf2flt.git] / compress.c
1 /*
2  * Helper functions to handle compression via zlib
3  *
4  * Copyright (C) 2007-2008 Julian Brown
5  * Copyright (C) 2008 Mike Frysinger
6  *
7  * Licensed under the GPL-2 or later.
8  */
9
10 #include <assert.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include <zlib.h>
15 #include "compress.h"
16
17 /* Open an (uncompressed) file as a stream.  Return 0 on success, 1 on
18    error.
19    NOTE: The MODE argument must remain valid for the lifetime of the stream,
20    because it is referred to by reopen_stream_compressed() if it is called.
21    String constants work fine.  */
22
23 int
24 fopen_stream_u(stream *fp, const char *path, const char *mode)
25 {
26         fp->u.filep = fopen(path, mode);
27         fp->type = (fp->u.filep) ? UNCOMPRESSED : INVALID;
28         fp->mode = mode;
29         return (fp->u.filep) ? 0 : 1;
30 }
31
32 /* Read from stream.  Return number of elements read.  */
33
34 size_t
35 fread_stream(void *ptr, size_t size, size_t nmemb, stream *str)
36 {
37         size_t read;
38
39         switch (str->type) {
40                 case UNCOMPRESSED:
41                 read = fread(ptr, size, nmemb, str->u.filep);
42                 break;
43
44                 case COMPRESSED:
45                 read = gzread(str->u.gzfilep, ptr, size * nmemb) / size;
46                 break;
47
48                 default:
49                 abort();
50         }
51
52         return read;
53 }
54
55 /* Write to stream.  Return number of elements written.  */
56
57 size_t
58 fwrite_stream(const void *ptr, size_t size, size_t nmemb, stream *str)
59 {
60         size_t written;
61
62         switch (str->type) {
63                 case UNCOMPRESSED:
64                 written = fwrite(ptr, size, nmemb, str->u.filep);
65                 break;
66
67                 case COMPRESSED:
68                 written = gzwrite(str->u.gzfilep, ptr, size * nmemb) / size;
69                 break;
70
71                 default:
72                 abort();
73         }
74
75         return written;
76 }
77
78 /* Close stream.  */
79
80 int
81 fclose_stream(stream *str)
82 {
83         switch (str->type) {
84                 case UNCOMPRESSED:
85                 return fclose(str->u.filep);
86
87                 case COMPRESSED:
88                 return gzclose(str->u.gzfilep);
89
90                 default:
91                 abort();
92         }
93
94         return 0;
95 }
96
97 int
98 ferror_stream(stream *str)
99 {
100         switch (str->type) {
101                 case UNCOMPRESSED:
102                 return ferror(str->u.filep);
103
104                 case COMPRESSED:
105                 {
106                         const char *err;
107                         int errno;
108
109                         err = gzerror(str->u.gzfilep, &errno);
110                         if (errno == Z_OK || errno == Z_STREAM_END)
111                                 return 0;
112                         else if (errno == Z_ERRNO)
113                                 return 1;
114                         else {
115                                 fprintf(stderr, "%s\n", err);
116                                 return 1;
117                         }
118                 }
119                 break;
120
121                 default:
122                 abort();
123         }
124
125         return 0;
126 }
127
128 int
129 fseek_stream(stream *str, long offset, int whence)
130 {
131         switch (str->type) {
132                 case UNCOMPRESSED:
133                 return fseek(str->u.filep, offset, whence);
134
135                 case COMPRESSED:
136                 return gzseek(str->u.gzfilep, offset, whence);
137
138                 default:
139                 abort();
140         }
141 }
142
143 /* Reopen a stream at the current file position.  */
144
145 void
146 reopen_stream_compressed(stream *str)
147 {
148         int fd;
149         long offset, roffset;
150
151         /* Already a compressed stream, return immediately  */
152         if (str->type == COMPRESSED)
153                 return;
154
155         if (str->type == INVALID)
156                 abort();
157
158         fd = fileno(str->u.filep);
159         /* Get current (buffered) file position.  */
160         offset = ftell(str->u.filep);
161
162         /* Make sure there's nothing left in buffers.  */
163         fflush(str->u.filep);
164
165         /* Reposition underlying FD.  (Might be unnecessary?)  */
166         roffset = lseek(fd, offset, SEEK_SET);
167
168         assert(roffset == offset);
169
170         /* Reopen as compressed stream.  */
171         str->u.gzfilep = gzdopen(fd, str->mode);
172         gzsetparams(str->u.gzfilep, 9, Z_DEFAULT_STRATEGY);
173         str->type = COMPRESSED;
174 }
175
176 void
177 transfer(stream *ifp, stream *ofp, int count)
178 {
179         char cmd[1024];
180         int n, num;
181
182         while (count == -1 || count > 0) {
183                 if (count == -1 || count > sizeof(cmd))
184                         num = sizeof(cmd);
185                 else
186                         num = count;
187                 n = fread_stream(cmd, 1, num, ifp);
188                 if (n == 0)
189                         break;
190                 if (fwrite_stream(cmd, n, 1, ofp) != 1) {
191                         fprintf(stderr, "Write failed :-(\n");
192                         exit(1);
193                 }
194                 if (count != -1)
195                         count -= n;
196         }
197         if (count > 0) {
198                 fprintf(stderr, "Failed to transfer %d bytes\n", count);
199                 exit(1);
200         }
201 }