Merge from vendor branch FILE:
[dragonfly.git] / contrib / libarchive / archive_write_set_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_write_set_compression_none.c,v 1.7 2004/11/06 05:25:53 kientzle Exp $");
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "archive.h"
35 #include "archive_private.h"
36
37 static int      archive_compressor_none_finish(struct archive *a);
38 static int      archive_compressor_none_init(struct archive *);
39 static int      archive_compressor_none_write(struct archive *, const void *,
40                     size_t);
41
42 struct archive_none {
43         char    *buffer;
44         ssize_t  buffer_size;
45         char    *next;          /* Current insert location */
46         ssize_t  avail;         /* Free space left in buffer */
47 };
48
49 int
50 archive_write_set_compression_none(struct archive *a)
51 {
52         archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW);
53         a->compression_init = &archive_compressor_none_init;
54         a->compression_code = ARCHIVE_COMPRESSION_NONE;
55         a->compression_name = "none";
56         return (0);
57 }
58
59 /*
60  * Setup callback.
61  */
62 static int
63 archive_compressor_none_init(struct archive *a)
64 {
65         int ret;
66         struct archive_none *state;
67
68         a->compression_code = ARCHIVE_COMPRESSION_NONE;
69         a->compression_name = "none";
70
71         if (a->client_opener != NULL) {
72                 ret = (a->client_opener)(a, a->client_data);
73                 if (ret != 0)
74                         return (ret);
75         }
76
77         state = (struct archive_none *)malloc(sizeof(*state));
78         if (state == NULL) {
79                 archive_set_error(a, ENOMEM,
80                     "Can't allocate data for output buffering");
81                 return (ARCHIVE_FATAL);
82         }
83         memset(state, 0, sizeof(*state));
84
85         state->buffer_size = a->bytes_per_block;
86         state->buffer = malloc(state->buffer_size);
87
88         if (state->buffer == NULL) {
89                 archive_set_error(a, ENOMEM,
90                     "Can't allocate output buffer");
91                 free(state);
92                 return (ARCHIVE_FATAL);
93         }
94
95         state->next = state->buffer;
96         state->avail = state->buffer_size;
97
98         a->compression_data = state;
99         a->compression_write = archive_compressor_none_write;
100         a->compression_finish = archive_compressor_none_finish;
101         return (ARCHIVE_OK);
102 }
103
104 /*
105  * Write data to the stream.
106  */
107 static int
108 archive_compressor_none_write(struct archive *a, const void *vbuff,
109     size_t length)
110 {
111         const char *buff;
112         ssize_t remaining, to_copy;
113         ssize_t bytes_written;
114         struct archive_none *state;
115
116         state = a->compression_data;
117         buff = vbuff;
118         if (a->client_writer == NULL) {
119                 archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
120                     "No write callback is registered?  "
121                     "This is probably an internal programming error.");
122                 return (ARCHIVE_FATAL);
123         }
124
125         remaining = length;
126         while (remaining > 0) {
127                 /*
128                  * If we have a full output block, write it and reset the
129                  * output buffer.
130                  */
131                 if (state->avail == 0) {
132                         bytes_written = (a->client_writer)(a, a->client_data,
133                             state->buffer, state->buffer_size);
134                         if (bytes_written <= 0)
135                                 return (ARCHIVE_FATAL);
136                         /* XXX TODO: if bytes_written < state->buffer_size */
137                         a->raw_position += bytes_written;
138                         state->next = state->buffer;
139                         state->avail = state->buffer_size;
140                 }
141
142                 /* Now we have space in the buffer; copy new data into it. */
143                 to_copy = (remaining > state->avail) ?
144                     state->avail : remaining;
145                 memcpy(state->next, buff, to_copy);
146                 state->next += to_copy;
147                 state->avail -= to_copy;
148                 buff += to_copy;
149                 remaining -= to_copy;
150         }
151         a->file_position += length;
152         return (ARCHIVE_OK);
153 }
154
155
156 /*
157  * Finish the compression.
158  */
159 static int
160 archive_compressor_none_finish(struct archive *a)
161 {
162         ssize_t block_length;
163         ssize_t target_block_length;
164         ssize_t bytes_written;
165         int ret;
166         int ret2;
167         struct archive_none *state;
168
169         state = a->compression_data;
170         ret = ret2 = ARCHIVE_OK;
171         if (a->client_writer == NULL) {
172                 archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
173                     "No write callback is registered?  "
174                     "This is probably an internal programming error.");
175                 return (ARCHIVE_FATAL);
176         }
177
178         /* If there's pending data, pad and write the last block */
179         if (state->next != state->buffer) {
180                 block_length = state->buffer_size - state->avail;
181
182                 /* Tricky calculation to determine size of last block */
183                 target_block_length = block_length;
184                 if (a->bytes_in_last_block <= 0)
185                         /* Default or Zero: pad to full block */
186                         target_block_length = a->bytes_per_block;
187                 else
188                         /* Round to next multiple of bytes_in_last_block. */
189                         target_block_length = a->bytes_in_last_block *
190                             ( (block_length + a->bytes_in_last_block - 1) /
191                                 a->bytes_in_last_block);
192                 if (target_block_length > a->bytes_per_block)
193                         target_block_length = a->bytes_per_block;
194                 if (block_length < target_block_length) {
195                         memset(state->next, 0,
196                             target_block_length - block_length);
197                         block_length = target_block_length;
198                 }
199                 bytes_written = (a->client_writer)(a, a->client_data,
200                     state->buffer, block_length);
201                 if (bytes_written <= 0)
202                         ret = ARCHIVE_FATAL;
203                 else {
204                         a->raw_position += bytes_written;
205                         ret = ARCHIVE_OK;
206                 }
207         }
208
209         /* Close the output */
210         if (a->client_closer != NULL)
211                 ret2 = (a->client_closer)(a, a->client_data);
212
213         free(state->buffer);
214         free(state);
215         a->compression_data = NULL;
216
217         return (ret != ARCHIVE_OK ? ret : ret2);
218 }