OSDN Git Service

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