Merge from vendor branch CVS:
[dragonfly.git] / contrib / libarchive / archive_read_support_compression_none.c
1 /*-
2  * Copyright (c) 2003-2004 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.5 2004/04/28 04:41:27 kientzle Exp $");
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 #include "archive.h"
36 #include "archive_private.h"
37
38 struct archive_decompress_none {
39         char            *buffer;
40         size_t           buffer_size;
41         char            *next;          /* Current read location. */
42         size_t           avail;         /* Bytes in my buffer. */
43         const char      *client_buff;   /* Client buffer information. */
44         size_t           client_total;
45         const char      *client_next;
46         size_t           client_avail;
47         char             end_of_file;
48         char             fatal;
49 };
50
51 /*
52  * Size of internal buffer used for combining short reads.  This is
53  * also an upper limit on the size of a read request.  Recall,
54  * however, that we can (and will!) return blocks of data larger than
55  * this.  The read semantics are: you ask for a minimum, I give you a
56  * pointer to my best-effort match and tell you how much data is
57  * there.  It could be less than you asked for, it could be much more.
58  * For example, a client might use mmap() to "read" the entire file as
59  * a single block.  In that case, I will return that entire block to
60  * my clients.
61  */
62 #define BUFFER_SIZE     65536
63
64 static int      archive_decompressor_none_bid(const void *, size_t);
65 static int      archive_decompressor_none_finish(struct archive *);
66 static int      archive_decompressor_none_init(struct archive *,
67                     const void *, size_t);
68 static ssize_t  archive_decompressor_none_read_ahead(struct archive *,
69                     const void **, size_t);
70 static ssize_t  archive_decompressor_none_read_consume(struct archive *,
71                     size_t);
72
73 int
74 archive_read_support_compression_none(struct archive *a)
75 {
76         return (__archive_read_register_compression(a,
77                     archive_decompressor_none_bid,
78                     archive_decompressor_none_init));
79 }
80
81 /*
82  * Try to detect an "uncompressed" archive.
83  */
84 static int
85 archive_decompressor_none_bid(const void *buff, size_t len)
86 {
87         (void)buff;
88         (void)len;
89
90         return (1); /* Default: We'll take it if noone else does. */
91 }
92
93 static int
94 archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
95 {
96         struct archive_decompress_none  *state;
97
98         a->compression_code = ARCHIVE_COMPRESSION_NONE;
99         a->compression_name = "none";
100
101         state = (struct archive_decompress_none *)malloc(sizeof(*state));
102         if (!state) {
103                 archive_set_error(a, ENOMEM, "Can't allocate input data");
104                 return (ARCHIVE_FATAL);
105         }
106         memset(state, 0, sizeof(*state));
107
108         state->buffer_size = BUFFER_SIZE;
109         state->buffer = malloc(state->buffer_size);
110         state->next = state->buffer;
111         if (state->buffer == NULL) {
112                 free(state);
113                 archive_set_error(a, ENOMEM, "Can't allocate input buffer");
114                 return (ARCHIVE_FATAL);
115         }
116
117         /* Save reference to first block of data. */
118         state->client_buff = buff;
119         state->client_total = n;
120         state->client_next = state->client_buff;
121         state->client_avail = state->client_total;
122
123         a->compression_data = state;
124         a->compression_read_ahead = archive_decompressor_none_read_ahead;
125         a->compression_read_consume = archive_decompressor_none_read_consume;
126         a->compression_finish = archive_decompressor_none_finish;
127
128         return (ARCHIVE_OK);
129 }
130
131 /*
132  * We just pass through pointers to the client buffer if we can.
133  * If the client buffer is short, then we copy stuff to our internal
134  * buffer to combine reads.
135  */
136 static ssize_t
137 archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
138     size_t min)
139 {
140         struct archive_decompress_none *state;
141         ssize_t bytes_read;
142
143         state = a->compression_data;
144         if (state->fatal)
145                 return (-1);
146
147         if (min > state->buffer_size)
148                 min = state->buffer_size;
149
150         /* Keep reading until we have accumulated enough data. */
151         while (state->avail + state->client_avail < min) {
152                 if (state->next > state->buffer &&
153                     state->next + min > state->buffer + state->buffer_size &&
154                     state->avail > 0) {
155                         memmove(state->buffer, state->next, state->avail);
156                         state->next = state->buffer;
157                 }
158                 if (state->client_avail > 0) {
159                         memcpy(state->next + state->avail, state->client_next,
160                              state->client_avail);
161                         state->client_next += state->client_avail;
162                         state->avail += state->client_avail;
163                         state->client_avail = 0;
164                 }
165                 /*
166                  * It seems to me that const void ** and const char **
167                  * should be compatible, but they aren't, hence the cast.
168                  */
169                 bytes_read = (a->client_reader)(a, a->client_data,
170                     (const void **)&state->client_buff);
171                 if (bytes_read < 0) {           /* Read error. */
172                         state->client_total = state->client_avail = 0;
173                         state->client_next = state->client_buff = NULL;
174                         state->fatal = 1;
175                         return (-1);
176                 }
177                 if (bytes_read == 0) {          /* End-of-file. */
178                         state->client_total = state->client_avail = 0;
179                         state->client_next = state->client_buff = NULL;
180                         state->end_of_file = 1;
181                         break;
182                 }
183                 a->raw_position += bytes_read;
184                 state->client_total = bytes_read;
185                 state->client_avail = state->client_total;
186                 state->client_next = state->client_buff;
187         }
188
189         /* Common case: If client buffer suffices, use that. */
190         if (state->avail == 0) {
191                 *buff = state->client_next;
192                 return (state->client_avail);
193         }
194
195         /* Add in bytes from client buffer as necessary to meet the minimum. */
196         if (min > state->avail + state->client_avail)
197                 min = state->avail + state->client_avail;
198         if (state->avail < min) {
199                 memcpy(state->next + state->avail, state->client_next,
200                      min - state->avail);
201                 state->client_next += min - state->avail;
202                 state->client_avail -= min - state->avail;
203                 state->avail = min;
204         }
205
206         *buff = state->next;
207         return (state->avail);
208 }
209
210 /*
211  * Mark the appropriate data as used.  Note that the request here could
212  * be much smaller than the size of the previous read_ahead request, but
213  * typically it won't be.  I make an attempt to go back to reading straight
214  * from the client buffer in case some end-of-block alignment mismatch forced
215  * me to combine writes above.
216  */
217 static ssize_t
218 archive_decompressor_none_read_consume(struct archive *a, size_t request)
219 {
220         struct archive_decompress_none *state;
221
222         state = a->compression_data;
223         if (state->avail > 0) {
224                 state->next += request;
225                 state->avail -= request;
226                 /*
227                  * Rollback state->client_next if we can so that future
228                  * reads come straight from the client buffer and we
229                  * avoid copying more data into our buffer.
230                  */
231                 if (state->avail <=
232                     (size_t)(state->client_next - state->client_buff)) {
233                         state->client_next -= state->avail;
234                         state->client_avail += state->avail;
235                         state->avail = 0;
236                         state->next = state->buffer;
237                 }
238         } else {
239                 state->client_next += request;
240                 state->client_avail -= request;
241         }
242         a->file_position += request;
243         return (request);
244 }
245
246 static int
247 archive_decompressor_none_finish(struct archive *a)
248 {
249         struct archive_decompress_none  *state;
250
251         state = a->compression_data;
252         free(state->buffer);
253         free(state);
254         a->compression_data = NULL;
255         if (a->client_closer != NULL)
256                 return ((a->client_closer)(a, a->client_data));
257         return (ARCHIVE_OK);
258 }