~ubuntu-branches/ubuntu/utopic/cmake/utopic

« back to all changes in this revision

Viewing changes to Utilities/cmlibarchive/libarchive/archive_write_add_filter_uuencode.c

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-10-10 12:54:39 UTC
  • mfrom: (1.14.7)
  • Revision ID: package-import@ubuntu.com-20131010125439-h0ahaj004on6oj92
Tags: 2.8.12-0ubuntu1
New upstream release LP: #1246701

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2012 Michihiro NAKAJIMA
 
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
 * 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.
 
13
 *
 
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.
 
24
 */
 
25
 
 
26
#include "archive_platform.h"
 
27
 
 
28
__FBSDID("$FreeBSD$");
 
29
 
 
30
#ifdef HAVE_ERRNO_H
 
31
#include <errno.h>
 
32
#endif
 
33
#ifdef HAVE_STDLIB_H
 
34
#include <stdlib.h>
 
35
#endif
 
36
#ifdef HAVE_STRING_H
 
37
#include <string.h>
 
38
#endif
 
39
 
 
40
#include "archive.h"
 
41
#include "archive_private.h"
 
42
#include "archive_string.h"
 
43
#include "archive_write_private.h"
 
44
 
 
45
#define LBYTES 45
 
46
 
 
47
struct private_uuencode {
 
48
        int                     mode;
 
49
        struct archive_string   name;
 
50
        struct archive_string   encoded_buff;
 
51
        size_t                  bs;
 
52
        size_t                  hold_len;
 
53
        unsigned char           hold[LBYTES];
 
54
};
 
55
 
 
56
static int archive_filter_uuencode_options(struct archive_write_filter *,
 
57
    const char *, const char *);
 
58
static int archive_filter_uuencode_open(struct archive_write_filter *);
 
59
static int archive_filter_uuencode_write(struct archive_write_filter *,
 
60
    const void *, size_t);
 
61
static int archive_filter_uuencode_close(struct archive_write_filter *);
 
62
static int archive_filter_uuencode_free(struct archive_write_filter *);
 
63
static void uu_encode(struct archive_string *, const unsigned char *, size_t);
 
64
static int64_t atol8(const char *, size_t);
 
65
 
 
66
/*
 
67
 * Add a compress filter to this write handle.
 
68
 */
 
69
int
 
70
archive_write_add_filter_uuencode(struct archive *_a)
 
71
{
 
72
        struct archive_write *a = (struct archive_write *)_a;
 
73
        struct archive_write_filter *f = __archive_write_allocate_filter(_a);
 
74
        struct private_uuencode *state;
 
75
 
 
76
        archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 
77
            ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
 
78
 
 
79
        state = (struct private_uuencode *)calloc(1, sizeof(*state));
 
80
        if (state == NULL) {
 
81
                archive_set_error(f->archive, ENOMEM,
 
82
                    "Can't allocate data for uuencode filter");
 
83
                return (ARCHIVE_FATAL);
 
84
        }
 
85
        archive_strcpy(&state->name, "-");
 
86
        state->mode = 0644;
 
87
 
 
88
        f->data = state;
 
89
        f->name = "uuencode";
 
90
        f->code = ARCHIVE_FILTER_UU;
 
91
        f->open = archive_filter_uuencode_open;
 
92
        f->options = archive_filter_uuencode_options;
 
93
        f->write = archive_filter_uuencode_write;
 
94
        f->close = archive_filter_uuencode_close;
 
95
        f->free = archive_filter_uuencode_free;
 
96
 
 
97
        return (ARCHIVE_OK);
 
98
}
 
99
 
 
100
/*
 
101
 * Set write options.
 
102
 */
 
103
static int
 
104
archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
 
105
    const char *value)
 
106
{
 
107
        struct private_uuencode *state = (struct private_uuencode *)f->data;
 
108
 
 
109
        if (strcmp(key, "mode") == 0) {
 
110
                if (value == NULL) {
 
111
                        archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 
112
                            "mode option requires octal digits");
 
113
                        return (ARCHIVE_FAILED);
 
114
                }
 
115
                state->mode = (int)atol8(value, strlen(value)) & 0777;
 
116
                return (ARCHIVE_OK);
 
117
        } else if (strcmp(key, "name") == 0) {
 
118
                if (value == NULL) {
 
119
                        archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 
120
                            "name option requires a string");
 
121
                        return (ARCHIVE_FAILED);
 
122
                }
 
123
                archive_strcpy(&state->name, value);
 
124
                return (ARCHIVE_OK);
 
125
        }
 
126
 
 
127
        /* Note: The "warn" return is just to inform the options
 
128
         * supervisor that we didn't handle it.  It will generate
 
129
         * a suitable error if no one used this option. */
 
130
        return (ARCHIVE_WARN);
 
131
}
 
132
 
 
133
/*
 
134
 * Setup callback.
 
135
 */
 
136
static int
 
137
archive_filter_uuencode_open(struct archive_write_filter *f)
 
138
{
 
139
        struct private_uuencode *state = (struct private_uuencode *)f->data;
 
140
        size_t bs = 65536, bpb;
 
141
        int ret;
 
142
 
 
143
        ret = __archive_write_open_filter(f->next_filter);
 
144
        if (ret != ARCHIVE_OK)
 
145
                return (ret);
 
146
 
 
147
        if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
 
148
                /* Buffer size should be a multiple number of the of bytes
 
149
                 * per block for performance. */
 
150
                bpb = archive_write_get_bytes_per_block(f->archive);
 
151
                if (bpb > bs)
 
152
                        bs = bpb;
 
153
                else if (bpb != 0)
 
154
                        bs -= bs % bpb;
 
155
        }
 
156
 
 
157
        state->bs = bs;
 
158
        if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
 
159
                archive_set_error(f->archive, ENOMEM,
 
160
                    "Can't allocate data for uuencode buffer");
 
161
                return (ARCHIVE_FATAL);
 
162
        }
 
163
 
 
164
        archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
 
165
            state->mode, state->name.s);
 
166
 
 
167
        f->data = state;
 
168
        return (0);
 
169
}
 
170
 
 
171
static void
 
172
uu_encode(struct archive_string *as, const unsigned char *p, size_t len)
 
173
{
 
174
        int c;
 
175
 
 
176
        c = (int)len;
 
177
        archive_strappend_char(as, c?c + 0x20:'`');
 
178
        for (; len >= 3; p += 3, len -= 3) {
 
179
                c = p[0] >> 2;
 
180
                archive_strappend_char(as, c?c + 0x20:'`');
 
181
                c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
 
182
                archive_strappend_char(as, c?c + 0x20:'`');
 
183
                c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
 
184
                archive_strappend_char(as, c?c + 0x20:'`');
 
185
                c = p[2] & 0x3f;
 
186
                archive_strappend_char(as, c?c + 0x20:'`');
 
187
        }
 
188
        if (len > 0) {
 
189
                c = p[0] >> 2;
 
190
                archive_strappend_char(as, c?c + 0x20:'`');
 
191
                c = (p[0] & 0x03) << 4;
 
192
                if (len == 1) {
 
193
                        archive_strappend_char(as, c?c + 0x20:'`');
 
194
                        archive_strappend_char(as, '`');
 
195
                        archive_strappend_char(as, '`');
 
196
                } else {
 
197
                        c |= (p[1] & 0xf0) >> 4;
 
198
                        archive_strappend_char(as, c?c + 0x20:'`');
 
199
                        c = (p[1] & 0x0f) << 2;
 
200
                        archive_strappend_char(as, c?c + 0x20:'`');
 
201
                        archive_strappend_char(as, '`');
 
202
                }
 
203
        }
 
204
        archive_strappend_char(as, '\n');
 
205
}
 
206
 
 
207
/*
 
208
 * Write data to the encoded stream.
 
209
 */
 
210
static int
 
211
archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
 
212
    size_t length)
 
213
{
 
214
        struct private_uuencode *state = (struct private_uuencode *)f->data;
 
215
        const unsigned char *p = buff;
 
216
        int ret = ARCHIVE_OK;
 
217
 
 
218
        if (length == 0)
 
219
                return (ret);
 
220
 
 
221
        if (state->hold_len) {
 
222
                while (state->hold_len < LBYTES && length > 0) {
 
223
                        state->hold[state->hold_len++] = *p++;
 
224
                        length--;
 
225
                }
 
226
                if (state->hold_len < LBYTES)
 
227
                        return (ret);
 
228
                uu_encode(&state->encoded_buff, state->hold, LBYTES);
 
229
                state->hold_len = 0;
 
230
        }
 
231
 
 
232
        for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
 
233
                uu_encode(&state->encoded_buff, p, LBYTES);
 
234
 
 
235
        /* Save remaining bytes. */
 
236
        if (length > 0) {
 
237
                memcpy(state->hold, p, length);
 
238
                state->hold_len = length;
 
239
        }
 
240
        while (archive_strlen(&state->encoded_buff) >= state->bs) {
 
241
                ret = __archive_write_filter(f->next_filter,
 
242
                    state->encoded_buff.s, state->bs);
 
243
                memmove(state->encoded_buff.s,
 
244
                    state->encoded_buff.s + state->bs,
 
245
                    state->encoded_buff.length - state->bs);
 
246
                state->encoded_buff.length -= state->bs;
 
247
        }
 
248
 
 
249
        return (ret);
 
250
}
 
251
 
 
252
 
 
253
/*
 
254
 * Finish the compression...
 
255
 */
 
256
static int
 
257
archive_filter_uuencode_close(struct archive_write_filter *f)
 
258
{
 
259
        struct private_uuencode *state = (struct private_uuencode *)f->data;
 
260
        int ret, ret2;
 
261
 
 
262
        /* Flush remaining bytes. */
 
263
        if (state->hold_len != 0)
 
264
                uu_encode(&state->encoded_buff, state->hold, state->hold_len);
 
265
        archive_string_sprintf(&state->encoded_buff, "`\nend\n");
 
266
        /* Write the last block */
 
267
        archive_write_set_bytes_in_last_block(f->archive, 1);
 
268
        ret = __archive_write_filter(f->next_filter,
 
269
            state->encoded_buff.s, archive_strlen(&state->encoded_buff));
 
270
        ret2 = __archive_write_close_filter(f->next_filter);
 
271
        if (ret > ret2)
 
272
                ret = ret2;
 
273
        return (ret);
 
274
}
 
275
 
 
276
static int
 
277
archive_filter_uuencode_free(struct archive_write_filter *f)
 
278
{
 
279
        struct private_uuencode *state = (struct private_uuencode *)f->data;
 
280
 
 
281
        archive_string_free(&state->name);
 
282
        archive_string_free(&state->encoded_buff);
 
283
        free(state);
 
284
        return (ARCHIVE_OK);
 
285
}
 
286
 
 
287
static int64_t
 
288
atol8(const char *p, size_t char_cnt)
 
289
{
 
290
        int64_t l;
 
291
        int digit;
 
292
        
 
293
        l = 0;
 
294
        while (char_cnt-- > 0) {
 
295
                if (*p >= '0' && *p <= '7')
 
296
                        digit = *p - '0';
 
297
                else
 
298
                        break;
 
299
                p++;
 
300
                l <<= 3;
 
301
                l |= digit;
 
302
        }
 
303
        return (l);
 
304
}
 
305