Merge pull request #2 from svost/master
[novacoin-seeder.git] / util.cpp
1 #include <stdio.h>
2 #include "util.h"
3
4 using namespace std;
5
6 string vstrprintf(const std::string &format, va_list ap)
7 {
8     char buffer[50000];
9     char* p = buffer;
10     int limit = sizeof(buffer);
11     int ret;
12     loop
13     {
14         va_list arg_ptr;
15         va_copy(arg_ptr, ap);
16         ret = vsnprintf(p, limit, format.c_str(), arg_ptr);
17         va_end(arg_ptr);
18         if (ret >= 0 && ret < limit)
19             break;
20         if (p != buffer)
21             delete[] p;
22         limit *= 2;
23         p = new char[limit];
24         if (p == NULL)
25             throw std::bad_alloc();
26     }
27     string str(p, p+ret);
28     if (p != buffer)
29         delete[] p;
30     return str;
31 }
32
33 string EncodeBase32(const unsigned char* pch, size_t len)
34 {
35     static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
36
37     string strRet="";
38     strRet.reserve((len+4)/5*8);
39
40     int mode=0, left=0;
41     const unsigned char *pchEnd = pch+len;
42
43     while (pch<pchEnd)
44     {
45         int enc = *(pch++);
46         switch (mode)
47         {
48             case 0: // we have no bits
49                 strRet += pbase32[enc >> 3];
50                 left = (enc & 7) << 2;
51                 mode = 1;
52                 break;
53
54             case 1: // we have three bits
55                 strRet += pbase32[left | (enc >> 6)];
56                 strRet += pbase32[(enc >> 1) & 31];
57                 left = (enc & 1) << 4;
58                 mode = 2;
59                 break;
60
61             case 2: // we have one bit
62                 strRet += pbase32[left | (enc >> 4)];
63                 left = (enc & 15) << 1;
64                 mode = 3;
65                 break;
66
67             case 3: // we have four bits
68                 strRet += pbase32[left | (enc >> 7)];
69                 strRet += pbase32[(enc >> 2) & 31];
70                 left = (enc & 3) << 3;
71                 mode = 4;
72                 break;
73
74             case 4: // we have two bits
75                 strRet += pbase32[left | (enc >> 5)];
76                 strRet += pbase32[enc & 31];
77                 mode = 0;
78         }
79     }
80
81     static const int nPadding[5] = {0, 6, 4, 3, 1};
82     if (mode)
83     {
84         strRet += pbase32[left];
85         for (int n=0; n<nPadding[mode]; n++)
86              strRet += '=';
87     }
88
89     return strRet;
90 }
91
92 string EncodeBase32(const string& str)
93 {
94     return EncodeBase32((const unsigned char*)str.c_str(), str.size());
95 }
96
97 vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
98 {
99     static const int decode32_table[256] =
100     {
101         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
102         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
103         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
104         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
105         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,  0,  1,  2,
106          3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
107         23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
108         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
109         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
110         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
111         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
112         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
113         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
114     };
115
116     if (pfInvalid)
117         *pfInvalid = false;
118
119     vector<unsigned char> vchRet;
120     vchRet.reserve((strlen(p))*5/8);
121
122     int mode = 0;
123     int left = 0;
124
125     while (1)
126     {
127          int dec = decode32_table[(unsigned char)*p];
128          if (dec == -1) break;
129          p++;
130          switch (mode)
131          {
132              case 0: // we have no bits and get 5
133                  left = dec;
134                  mode = 1;
135                  break;
136
137               case 1: // we have 5 bits and keep 2
138                   vchRet.push_back((left<<3) | (dec>>2));
139                   left = dec & 3;
140                   mode = 2;
141                   break;
142
143              case 2: // we have 2 bits and keep 7
144                  left = left << 5 | dec;
145                  mode = 3;
146                  break;
147
148              case 3: // we have 7 bits and keep 4
149                  vchRet.push_back((left<<1) | (dec>>4));
150                  left = dec & 15;
151                  mode = 4;
152                  break;
153
154              case 4: // we have 4 bits, and keep 1
155                  vchRet.push_back((left<<4) | (dec>>1));
156                  left = dec & 1;
157                  mode = 5;
158                  break;
159
160              case 5: // we have 1 bit, and keep 6
161                  left = left << 5 | dec;
162                  mode = 6;
163                  break;
164
165              case 6: // we have 6 bits, and keep 3
166                  vchRet.push_back((left<<2) | (dec>>3));
167                  left = dec & 7;
168                  mode = 7;
169                  break;
170
171              case 7: // we have 3 bits, and keep 0
172                  vchRet.push_back((left<<5) | dec);
173                  mode = 0;
174                  break;
175          }
176     }
177
178     if (pfInvalid)
179         switch (mode)
180         {
181             case 0: // 8n base32 characters processed: ok
182                 break;
183
184             case 1: // 8n+1 base32 characters processed: impossible
185             case 3: //   +3
186             case 6: //   +6
187                 *pfInvalid = true;
188                 break;
189
190             case 2: // 8n+2 base32 characters processed: require '======'
191                 if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1)
192                     *pfInvalid = true;
193                 break;
194
195             case 4: // 8n+4 base32 characters processed: require '===='
196                 if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1)
197                     *pfInvalid = true;
198                 break;
199
200             case 5: // 8n+5 base32 characters processed: require '==='
201                 if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1)
202                     *pfInvalid = true;
203                 break;
204
205             case 7: // 8n+7 base32 characters processed: require '='
206                 if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1)
207                     *pfInvalid = true;
208                 break;
209         }
210
211     return vchRet;
212 }
213
214 string DecodeBase32(const string& str)
215 {
216     vector<unsigned char> vchRet = DecodeBase32(str.c_str());
217     return string((const char*)&vchRet[0], vchRet.size());
218 }