2 * Copyright (c) 2012 Michihiro NAKAJIMA
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
41 #include "archive_private.h"
42 #include "archive_string.h"
43 #include "archive_write_private.h"
47 struct private_b64encode {
49 struct archive_string name;
50 struct archive_string encoded_buff;
53 unsigned char hold[LBYTES];
56 static int archive_filter_b64encode_options(struct archive_write_filter *,
57 const char *, const char *);
58 static int archive_filter_b64encode_open(struct archive_write_filter *);
59 static int archive_filter_b64encode_write(struct archive_write_filter *,
60 const void *, size_t);
61 static int archive_filter_b64encode_close(struct archive_write_filter *);
62 static int archive_filter_b64encode_free(struct archive_write_filter *);
63 static void la_b64_encode(struct archive_string *, const unsigned char *, size_t);
64 static int64_t atol8(const char *, size_t);
66 static const char base64[] = {
67 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
68 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
69 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
70 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
71 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
72 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
73 'w', 'x', 'y', 'z', '0', '1', '2', '3',
74 '4', '5', '6', '7', '8', '9', '+', '/'
78 * Add a compress filter to this write handle.
81 archive_write_add_filter_b64encode(struct archive *_a)
83 struct archive_write *a = (struct archive_write *)_a;
84 struct archive_write_filter *f = __archive_write_allocate_filter(_a);
85 struct private_b64encode *state;
87 archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
88 ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
90 state = (struct private_b64encode *)calloc(1, sizeof(*state));
92 archive_set_error(f->archive, ENOMEM,
93 "Can't allocate data for b64encode filter");
94 return (ARCHIVE_FATAL);
96 archive_strcpy(&state->name, "-");
100 f->name = "b64encode";
101 f->code = ARCHIVE_FILTER_UU;
102 f->open = archive_filter_b64encode_open;
103 f->options = archive_filter_b64encode_options;
104 f->write = archive_filter_b64encode_write;
105 f->close = archive_filter_b64encode_close;
106 f->free = archive_filter_b64encode_free;
115 archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,
118 struct private_b64encode *state = (struct private_b64encode *)f->data;
120 if (strcmp(key, "mode") == 0) {
122 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
123 "mode option requires octal digits");
124 return (ARCHIVE_FAILED);
126 state->mode = (int)atol8(value, strlen(value)) & 0777;
128 } else if (strcmp(key, "name") == 0) {
130 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
131 "name option requires a string");
132 return (ARCHIVE_FAILED);
134 archive_strcpy(&state->name, value);
138 /* Note: The "warn" return is just to inform the options
139 * supervisor that we didn't handle it. It will generate
140 * a suitable error if no one used this option. */
141 return (ARCHIVE_WARN);
148 archive_filter_b64encode_open(struct archive_write_filter *f)
150 struct private_b64encode *state = (struct private_b64encode *)f->data;
151 size_t bs = 65536, bpb;
153 if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
154 /* Buffer size should be a multiple number of the of bytes
155 * per block for performance. */
156 bpb = archive_write_get_bytes_per_block(f->archive);
164 if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
165 archive_set_error(f->archive, ENOMEM,
166 "Can't allocate data for b64encode buffer");
167 return (ARCHIVE_FATAL);
170 archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
171 state->mode, state->name.s);
178 la_b64_encode(struct archive_string *as, const unsigned char *p, size_t len)
182 for (; len >= 3; p += 3, len -= 3) {
184 archive_strappend_char(as, base64[c]);
185 c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
186 archive_strappend_char(as, base64[c]);
187 c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
188 archive_strappend_char(as, base64[c]);
190 archive_strappend_char(as, base64[c]);
194 archive_strappend_char(as, base64[c]);
195 c = (p[0] & 0x03) << 4;
197 archive_strappend_char(as, base64[c]);
198 archive_strappend_char(as, '=');
199 archive_strappend_char(as, '=');
201 c |= (p[1] & 0xf0) >> 4;
202 archive_strappend_char(as, base64[c]);
203 c = (p[1] & 0x0f) << 2;
204 archive_strappend_char(as, base64[c]);
205 archive_strappend_char(as, '=');
208 archive_strappend_char(as, '\n');
212 * Write data to the encoded stream.
215 archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
218 struct private_b64encode *state = (struct private_b64encode *)f->data;
219 const unsigned char *p = buff;
220 int ret = ARCHIVE_OK;
225 if (state->hold_len) {
226 while (state->hold_len < LBYTES && length > 0) {
227 state->hold[state->hold_len++] = *p++;
230 if (state->hold_len < LBYTES)
232 la_b64_encode(&state->encoded_buff, state->hold, LBYTES);
236 for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
237 la_b64_encode(&state->encoded_buff, p, LBYTES);
239 /* Save remaining bytes. */
241 memcpy(state->hold, p, length);
242 state->hold_len = length;
244 while (archive_strlen(&state->encoded_buff) >= state->bs) {
245 ret = __archive_write_filter(f->next_filter,
246 state->encoded_buff.s, state->bs);
247 memmove(state->encoded_buff.s,
248 state->encoded_buff.s + state->bs,
249 state->encoded_buff.length - state->bs);
250 state->encoded_buff.length -= state->bs;
258 * Finish the compression...
261 archive_filter_b64encode_close(struct archive_write_filter *f)
263 struct private_b64encode *state = (struct private_b64encode *)f->data;
265 /* Flush remaining bytes. */
266 if (state->hold_len != 0)
267 la_b64_encode(&state->encoded_buff, state->hold, state->hold_len);
268 archive_string_sprintf(&state->encoded_buff, "====\n");
269 /* Write the last block */
270 archive_write_set_bytes_in_last_block(f->archive, 1);
271 return __archive_write_filter(f->next_filter,
272 state->encoded_buff.s, archive_strlen(&state->encoded_buff));
276 archive_filter_b64encode_free(struct archive_write_filter *f)
278 struct private_b64encode *state = (struct private_b64encode *)f->data;
280 archive_string_free(&state->name);
281 archive_string_free(&state->encoded_buff);
287 atol8(const char *p, size_t char_cnt)
293 while (char_cnt-- > 0) {
294 if (*p >= '0' && *p <= '7')