]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/base32.cc
dnsdist: print stats from expungeByName
[thirdparty/pdns.git] / pdns / base32.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string>
28 #include <cstring>
29 #include <stdlib.h>
30 #include <iostream>
31 #include "base32.hh"
32 #include "namespaces.hh"
33
34 /* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */
35 /* NOTE: length should not exceed 8; all callers inside PowerDNS only pass length=5 though */
36 unsigned char extract_bits(const char *s, int start, int length)
37 {
38 uint16_t x;
39 unsigned char cl, cc;
40
41 if(!length)
42 return 0;
43
44 cl = s[start / 8];
45 if(start / 8 < (start + length-1)/8)
46 cc = s[start / 8 + 1];
47 else
48 cc = 0;
49
50 x = (uint16_t) (cl << 8 | cc);
51 x = x >> (16 - (length + (start % 8)));
52 x = (x & (0xffff >> (16 - length)));
53 return (x);
54 }
55
56 /* same, set bit ranges in a char* */
57 static void set_bits(char* s, int x, int start, int length)
58 {
59 unsigned char cl, cc, cr;
60 uint32_t y;
61 int shift;
62
63 shift = ((8 - ((start + length) % 8)) % 8);
64 y = (uint32_t) x << shift;
65 cl = (y >> 16) & 0xff;
66 cc = (y >> 8) & 0xff;
67 cr = y & 0xff;
68 if (shift + length > 16) {
69 s[start / 8] |= cl;
70 s[start / 8 + 1] |= cc;
71 s[start / 8 + 2] |= cr;
72 }
73 else {
74 if (shift + length > 8) {
75 s[start / 8] |= cc;
76 s[start / 8 + 1] |= cr;
77 } else {
78 s[start / 8] |= cr;
79 }
80 }
81 }
82
83 /* convert a base32 hex character to its decoded equivalent */
84 static int unbase32hex(char c)
85 {
86 if(c >= '0' && c<='9')
87 return c-'0';
88 if(c >= 'a' && c<='z')
89 return 10 + (c-'a');
90 if(c >= 'A' && c<='Z')
91 return 10 + (c-'A');
92 if(c=='=')
93 return '=';
94 return -1;
95 }
96
97 /* convert a binary string to base32hex */
98 string toBase32Hex(const std::string& input)
99 {
100 static const char base32hex[] = "0123456789abcdefghijklmnopqrstuv=";
101 string ret;
102 ret.reserve(4+ 8*input.length()/5); // optimization
103 // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks
104 for(string::size_type offset = 0 ; offset < input.length(); offset+=5) {
105 int todo = input.length() - offset;
106 int stuffing; // how much '=' to add at the end
107
108 switch(todo) {
109 case 1:
110 stuffing = 6; break;
111 case 2:
112 stuffing = 4; break;
113 case 3:
114 stuffing = 3; break;
115 case 4:
116 stuffing = 1; break;
117 default: // -> 0 or more than 5, no stuffing
118 stuffing = 0; break;
119 }
120
121 for(int n=0; n < 8 - stuffing; ++n)
122 ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]);
123 ret.append(stuffing, '=');
124 }
125
126 return ret;
127 }
128
129 // convert base32hex encoded string to normal string
130 string fromBase32Hex(const std::string& input)
131 {
132 string ret;
133 char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time
134 string::size_type n, toWrite=0;
135 for(n = 0; n < input.length(); ++n) {
136 int c=unbase32hex(input[n]);
137 if(c == '=' || c < 0) // stop at stuffing or error
138 break;
139 set_bits(block, c , (n % 8) * 5, 5);
140 if(++toWrite == 8) {
141 ret.append(block, sizeof(block));
142 memset(block, 0, sizeof(block));
143 toWrite = 0;
144 }
145 }
146 ret.append(block, (toWrite*5)/8);
147
148 return ret;
149 }
150
151 #if 0
152 int main(int argc, char **argv)
153 {
154 if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) {
155 printf("syntax: base32 from|to string\n");
156 exit(0);
157 }
158 if(!strcmp(argv[1],"to")) {
159 printf("input: '%s'\noutput: '%s'\n",
160 argv[2],
161 toBase32Hex(argv[2]).c_str());
162 }
163 else {
164 cout<<"input: '"<<argv[2]<<"'\noutput: '"<<fromBase32Hex(argv[2])<<"'\n";
165 }
166 }
167 #endif