Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
445 theseven 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
}