-
Notifications
You must be signed in to change notification settings - Fork 80
/
base64encode.c
104 lines (89 loc) · 2.9 KB
/
base64encode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
base64encode.c - modified by David Lazar
Originally:
cencoder.c - c source to a base64 encoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include <stddef.h>
#include <stdint.h>
#include "base64encode.h"
void base64_encode_init(base64_encodestate *S) {
S->step = step_A;
S->result = 0;
}
char base64_encode_value(uint8_t value) {
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (value > 63) return '=';
return encoding[value];
}
ptrdiff_t base64_encode_update(base64_encodestate *S, const uint8_t *data, uint64_t datalen, char *encoded) {
char *encoded_begin = encoded;
const uint8_t *currbyte = data;
const uint8_t *data_end = data + datalen;
uint8_t result;
uint8_t fragment;
result = S->result;
switch (S->step) {
while (1) {
case step_A:
if (currbyte == data_end) {
S->result = result;
S->step = step_A;
return encoded - encoded_begin;
}
fragment = *currbyte++;
result = (fragment & 0x0fc) >> 2;
*encoded++ = base64_encode_value(result);
result = (fragment & 0x003) << 4;
case step_B:
if (currbyte == data_end) {
S->result = result;
S->step = step_B;
return encoded - encoded_begin;
}
fragment = *currbyte++;
result |= (fragment & 0x0f0) >> 4;
*encoded++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2;
case step_C:
if (currbyte == data_end) {
S->result = result;
S->step = step_C;
return encoded - encoded_begin;
}
fragment = *currbyte++;
result |= (fragment & 0x0c0) >> 6;
*encoded++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*encoded++ = base64_encode_value(result);
}
}
// control flow shouldn't reach here
return encoded - encoded_begin;
}
ptrdiff_t base64_encode_final(base64_encodestate *S, char *encoded) {
char *encoded_begin = encoded;
switch (S->step) {
case step_B:
*encoded++ = base64_encode_value(S->result);
*encoded++ = '=';
*encoded++ = '=';
break;
case step_C:
*encoded++ = base64_encode_value(S->result);
*encoded++ = '=';
break;
case step_A:
break;
}
return encoded - encoded_begin;
}
ptrdiff_t base64_encode(const uint8_t *data, uint64_t datalen, char *encoded) {
ptrdiff_t c = 0;
base64_encodestate S;
base64_encode_init(&S);
c += base64_encode_update(&S, data, datalen, encoded);
c += base64_encode_final(&S, encoded + c);
return c;
}