]>
Commit | Line | Data |
---|---|---|
4691b2df BH |
1 | #include <stdint.h> |
2 | #include <stdio.h> | |
3 | #include <string> | |
4 | #include <cstring> | |
5 | #include <stdlib.h> | |
6 | #include <iostream> | |
7 | #include "base32.hh" | |
8 | using namespace std; | |
9 | ||
10 | /* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */ | |
11 | uint32_t extract_bits(const char *s, int start, int length) | |
12 | { | |
13 | uint32_t x; | |
14 | unsigned char cl, cc, cr; | |
15 | ||
16 | cl = s[start / 8]; | |
17 | cc = s[start / 8 + 1]; | |
18 | cr = s[start / 8 + 2]; | |
19 | x = ((uint32_t) (cl << 8 | cc) << 8 | cr); | |
20 | x = x >> (24 - (length + (start % 8))); | |
21 | x = (x & (0xffff >> (16 - length))); | |
22 | return (x); | |
23 | } | |
24 | ||
25 | /* same, set bit ranges in a char* */ | |
26 | static void set_bits(char* s, int x, int start, int length) | |
27 | { | |
28 | unsigned char cl, cc, cr; | |
29 | uint32_t y; | |
30 | int shift; | |
31 | ||
32 | shift = ((8 - ((start + length) % 8)) % 8); | |
33 | y = (uint32_t) x << shift; | |
34 | cl = (y >> 16) & 0xff; | |
35 | cc = (y >> 8) & 0xff; | |
36 | cr = y & 0xff; | |
37 | if (shift + length > 16) { | |
38 | s[start / 8] |= cl; | |
39 | s[start / 8 + 1] |= cc; | |
40 | s[start / 8 + 2] |= cr; | |
41 | } | |
42 | else { | |
43 | if (shift + length > 8) { | |
44 | s[start / 8] |= cc; | |
45 | s[start / 8 + 1] |= cr; | |
46 | } else { | |
47 | s[start / 8] |= cr; | |
48 | } | |
49 | } | |
50 | } | |
51 | ||
52 | /* convert a base32 hex character to its decoded equivalent */ | |
53 | static int unbase32hex(char c) | |
54 | { | |
55 | if(c >= '0' && c<='9') | |
56 | return c-'0'; | |
57 | if(c >= 'a' && c<='z') | |
58 | return 10 + (c-'a'); | |
59 | if(c >= 'A' && c<='Z') | |
60 | return 10 + (c-'A'); | |
61 | if(c=='=') | |
62 | return '='; | |
63 | return -1; | |
64 | } | |
65 | ||
66 | /* convert a binary string to base32hex */ | |
67 | string toBase32Hex(const std::string& input) | |
68 | { | |
69 | static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV="; | |
70 | string ret; | |
71 | ret.reserve(4+ 8*input.length()/5); // optimization | |
72 | // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks | |
73 | for(string::size_type offset = 0 ; offset < input.length(); offset+=5) { | |
74 | int todo = input.length() - offset; | |
75 | int stuffing; // how much '=' to add at the end | |
76 | ||
77 | switch(todo) { | |
78 | case 1: | |
79 | stuffing = 6; break; | |
80 | case 2: | |
81 | stuffing = 4; break; | |
82 | case 3: | |
83 | stuffing = 3; break; | |
84 | case 4: | |
85 | stuffing = 1; break; | |
86 | default: // -> 0 or more than 5, no stuffing | |
87 | stuffing = 0; break; | |
88 | } | |
89 | ||
90 | for(int n=0; n < 8 - stuffing; ++n) | |
91 | ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]); | |
92 | ret.append(stuffing, '='); | |
93 | } | |
94 | ||
95 | return ret; | |
96 | } | |
97 | ||
98 | // convert base32hex encoded string to normal string | |
99 | string fromBase32Hex(const std::string& input) | |
100 | { | |
101 | string ret; | |
102 | char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time | |
103 | string::size_type n, toWrite=0; | |
104 | for(n = 0; n < input.length(); ++n) { | |
105 | int c=unbase32hex(input[n]); | |
106 | if(c == '=' || c < 0) // stop at stuffing or error | |
107 | break; | |
108 | set_bits(block, c , (n % 8) * 5, 5); | |
109 | if(++toWrite == 8) { | |
110 | ret.append(block, sizeof(block)); | |
111 | memset(block, 0, sizeof(block)); | |
112 | toWrite = 0; | |
113 | } | |
114 | } | |
115 | ret.append(block, (7+toWrite*5)/8); // round up | |
116 | ||
117 | return ret; | |
118 | } | |
119 | ||
120 | #if 0 | |
121 | int main(int argc, char **argv) | |
122 | { | |
123 | if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) { | |
124 | printf("syntax: base32 from|to string\n"); | |
125 | exit(0); | |
126 | } | |
127 | if(!strcmp(argv[1],"to")) { | |
128 | printf("input: '%s'\noutput: '%s'\n", | |
129 | argv[2], | |
130 | toBase32Hex(argv[2]).c_str()); | |
131 | } | |
132 | else { | |
133 | cout<<"input: '"<<argv[2]<<"'\noutput: '"<<fromBase32Hex(argv[2])<<"'\n"; | |
134 | } | |
135 | } | |
136 | #endif |