[svn-inject] Applying Debian modifications to trunk
[debian/iodine.git] / encoding.c
1 /*
2  * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <stdio.h>
18 #include <strings.h>
19 #include <string.h>
20
21 // For FreeBSD
22 #ifndef MIN
23 #define MIN(a,b) ((a)<(b)?(a):(b))
24 #endif
25
26 #define SPACING 63
27 #define ENC_CHUNK 8
28 #define RAW_CHUNK 5
29
30 static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ98765-";
31 static const char padder[] = " 1234";
32 static char reverse32[128];
33 static int reverse_init = 0;
34
35 /* Eat 5 bytes from src, write 8 bytes to dest */
36 static void
37 encode_chunk(char *dest, char *src)
38 {
39         unsigned char c;
40
41         *dest++ = base32[(*src & 0xF8) >> 3];   // 1111 1000 first byte
42
43         c = (*src++ & 0x07) << 2;               // 0000 0111 first byte
44         c |=  ((*src & 0xC0) >> 6);             // 1100 0000 second byte
45         *dest++ = base32[(int) c];
46
47         *dest++ = base32[(*src & 0x3E) >> 1];   // 0011 1110 second byte
48
49         c = (*src++ & 0x01) << 4;               // 0000 0001 second byte
50         c |=  ((*src & 0xF0) >> 4);             // 1111 0000 third byte
51         *dest++ = base32[(int) c];
52         
53         c = (*src++ & 0x0F) << 1;               // 0000 1111 third byte
54         c |=  ((*src & 0x80) >> 7);             // 1000 0000 fourth byte
55         *dest++ = base32[(int) c];
56         
57         *dest++ = base32[(*src & 0x7C) >> 2];   // 0111 1100 fourth byte
58
59         c = (*src++ & 0x03) << 3;               // 0000 0011 fourth byte
60         c |=  ((*src & 0xE0) >> 5);             // 1110 0000 fifth byte
61         *dest++ = base32[(int) c];
62
63         *dest++ = base32[*src++ & 0x1F];        // 0001 1111 fifth byte
64 }
65
66 /* Eat 8 bytes from src, write 5 bytes to dest */
67 static void
68 decode_chunk(char *dest, char *src)
69 {
70         unsigned char c;
71         int i;
72
73         if (!reverse_init) {
74                 for (i = 0; i < 32; i++) {
75                         c = base32[i];
76                         reverse32[(int) c] = i;
77                 }
78                 reverse_init = 1;
79         }
80
81         c = reverse32[(int) *src++] << 3;               // Take bits 11111 from byte 1
82         c |= (reverse32[(int) *src] & 0x1C) >> 2;       // Take bits 11100 from byte 2
83         *dest++ = c;
84         
85         c = (reverse32[(int) *src++] & 0x3) << 6;       // Take bits 00011 from byte 2
86         c |= reverse32[(int) *src++] << 1;              // Take bits 11111 from byte 3
87         c |= (reverse32[(int) *src] & 0x10) >> 4;       // Take bits 10000 from byte 4
88         *dest++ = c;
89         
90         c = (reverse32[(int) *src++] & 0xF) << 4;       // Take bits 01111 from byte 4
91         c |= (reverse32[(int) *src] & 0x1E) >> 1;       // Take bits 11110 from byte 5
92         *dest++ = c;
93         
94         c = reverse32[(int) *src++] << 7;               // Take bits 00001 from byte 5
95         c |= reverse32[(int) *src++] << 2;              // Take bits 11111 from byte 6
96         c |= (reverse32[(int) *src] & 0x18) >> 3;       // Take bits 11000 from byte 7
97         *dest++ = c;
98         
99         c = (reverse32[(int) *src++] & 0x7) << 5;       // Take bits 00111 from byte 7
100         c |= reverse32[(int) *src++];                   // Take bits 11111 from byte 8
101         *dest++ = c;
102 }
103
104 int
105 encode_data(char *buf, int len, int space, char *dest, char flag)
106 {
107         int final;
108         int write;
109         int realwrite;
110         int chunks;
111         int leftovers;
112         int i;
113         char encoded[255];
114         char padding[5];
115         char *pp;
116         char *dp;
117         char *ep;
118
119         space -= space / SPACING;
120         chunks = (space - 1) / ENC_CHUNK;
121         while ((chunks + 1) * ENC_CHUNK + 1 > space) {
122                 chunks--;
123         }
124         write = RAW_CHUNK * chunks;
125         write = MIN(write, len); // do not use more bytes than is available;
126         final = (write == len); // is this the last block?
127         chunks = write / RAW_CHUNK;
128         leftovers = write % RAW_CHUNK;
129
130         // flag is special character to be placed first in the encoded data
131         if (flag != 0) {
132                 *dest = flag;
133         } else {
134                 // First byte is 0 for middle packet and 1 for last packet
135                 *dest = '0' + final;
136         }
137         dest++;
138
139         memset(encoded, 0, sizeof(encoded));
140         ep = encoded;
141         dp = buf;
142         for (i = 0; i < chunks; i++) {
143                 encode_chunk(ep, dp);
144                 ep += ENC_CHUNK;
145                 dp += RAW_CHUNK;
146         }
147         realwrite = ENC_CHUNK * chunks;
148         memset(padding, 0, sizeof(padding));
149         pp = padding;
150         if (leftovers) {
151                 pp += RAW_CHUNK - leftovers;
152                 memcpy(pp, dp, leftovers);
153
154                 pp = padding;
155                 *ep++ = padder[leftovers];
156                 encode_chunk(ep, pp);
157                 
158                 realwrite += ENC_CHUNK + 1;     // plus padding character
159         }
160         ep = encoded;
161         if (len > 0) {
162                 for (i = 1; i <= realwrite; i++) {
163                         if (i % SPACING == 0) {
164                                 *dest++ = '.';
165                         }
166                         *dest++ = *ep++;
167                 }
168         }
169         
170         return write;
171 }
172
173 int
174 decode_data(char *dest, int size, const char *src, char *srcend)
175 {
176         int len;
177         int i;
178         int chunks;
179         int padded;
180         char encoded[255];
181         char padding[5];
182         char *pp;
183         char *ep;
184
185         // Copy flag
186         len = 1;
187         *dest = *src;
188         dest++;
189         src++;
190
191         memset(encoded, 0, sizeof(encoded));
192         ep = encoded;
193         while(len < size && src < srcend) {
194                 if(*src == '.') {
195                         src++;
196                         continue;
197                 }
198
199                 *ep++ = *src++;
200         }
201         chunks = strlen(encoded) / 8;
202         padded = strlen(encoded) % 8;
203
204         ep = encoded;
205         for (i = 0; i < chunks-1; i++) {
206                 decode_chunk(dest, ep);
207                 dest += RAW_CHUNK;
208                 ep += ENC_CHUNK;
209                 len += RAW_CHUNK;
210         }
211         // Read last chunk:
212         if (padded) {
213                 pp = padding;
214                 padded = *ep++ - '0';
215                 decode_chunk(pp, ep);
216                 pp += RAW_CHUNK - padded;
217                 memcpy(dest, pp, padded);
218                 len += padded;
219         } else {
220                 decode_chunk(dest, ep);
221                 len += RAW_CHUNK;
222         }
223
224         return len;
225 }
226