Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 605ad62 | 2016-03-25 20:07:21 -0700 | [diff] [blame] | 3 | * Copyright 2015-2016, Google Inc. |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 4 | * All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions are |
| 8 | * met: |
| 9 | * |
| 10 | * * Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * * Redistributions in binary form must reproduce the above |
| 13 | * copyright notice, this list of conditions and the following disclaimer |
| 14 | * in the documentation and/or other materials provided with the |
| 15 | * distribution. |
| 16 | * * Neither the name of Google Inc. nor the names of its |
| 17 | * contributors may be used to endorse or promote products derived from |
| 18 | * this software without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | * |
| 32 | */ |
| 33 | |
| 34 | /* generates constant tables for hpack.c */ |
| 35 | |
Craig Tiller | ffae43c | 2016-03-25 19:34:29 -0700 | [diff] [blame] | 36 | #include <assert.h> |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 37 | #include <stddef.h> |
| 38 | #include <stdio.h> |
| 39 | #include <string.h> |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 40 | |
| 41 | #include <grpc/support/log.h> |
Craig Tiller | c7762a8 | 2016-03-28 10:13:08 -0700 | [diff] [blame] | 42 | #include "src/core/ext/transport/chttp2/transport/huffsyms.h" |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 43 | |
| 44 | /* |
| 45 | * first byte LUT generation |
| 46 | */ |
| 47 | |
| 48 | typedef struct { |
| 49 | const char *call; |
| 50 | /* bit prefix for the field type */ |
| 51 | unsigned char prefix; |
| 52 | /* length of the bit prefix for the field type */ |
| 53 | unsigned char prefix_length; |
| 54 | /* index value: 0 = all zeros, 2 = all ones, 1 otherwise */ |
| 55 | unsigned char index; |
| 56 | } spec; |
| 57 | |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 58 | static const spec fields[] = { |
| 59 | {"INDEXED_FIELD", 0X80, 1, 1}, {"INDEXED_FIELD_X", 0X80, 1, 2}, |
| 60 | {"LITHDR_INCIDX", 0X40, 2, 1}, {"LITHDR_INCIDX_X", 0X40, 2, 2}, |
| 61 | {"LITHDR_INCIDX_V", 0X40, 2, 0}, {"LITHDR_NOTIDX", 0X00, 4, 1}, |
| 62 | {"LITHDR_NOTIDX_X", 0X00, 4, 2}, {"LITHDR_NOTIDX_V", 0X00, 4, 0}, |
| 63 | {"LITHDR_NVRIDX", 0X10, 4, 1}, {"LITHDR_NVRIDX_X", 0X10, 4, 2}, |
| 64 | {"LITHDR_NVRIDX_V", 0X10, 4, 0}, {"MAX_TBL_SIZE", 0X20, 3, 1}, |
| 65 | {"MAX_TBL_SIZE_X", 0X20, 3, 2}, |
| 66 | }; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 67 | |
| 68 | static const int num_fields = sizeof(fields) / sizeof(*fields); |
| 69 | |
| 70 | static unsigned char prefix_mask(unsigned char prefix_len) { |
| 71 | unsigned char i; |
| 72 | unsigned char out = 0; |
| 73 | for (i = 0; i < prefix_len; i++) { |
David Garcia Quintas | 809831e | 2015-10-05 13:40:07 -0700 | [diff] [blame] | 74 | /* NB: the following integer arithmetic operation needs to be in its |
| 75 | * expanded form due to the "integral promotion" performed (see section |
David Garcia Quintas | 35284f0 | 2015-10-06 11:05:05 -0700 | [diff] [blame] | 76 | * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type |
| 77 | * is then required to avoid the compiler warning */ |
David Garcia Quintas | d76cdac | 2015-10-03 15:57:09 -0700 | [diff] [blame] | 78 | out = (unsigned char)(out | (unsigned char)(1 << (7 - i))); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 79 | } |
| 80 | return out; |
| 81 | } |
| 82 | |
| 83 | static unsigned char suffix_mask(unsigned char prefix_len) { |
Craig Tiller | 6a6b36c | 2015-09-10 16:00:22 -0700 | [diff] [blame] | 84 | return (unsigned char)~prefix_mask(prefix_len); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 85 | } |
| 86 | |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 87 | static void generate_first_byte_lut(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 88 | int i, j, n; |
| 89 | const spec *chrspec; |
| 90 | unsigned char suffix; |
| 91 | |
| 92 | n = printf("static CALLTYPE first_byte[256] = {"); |
| 93 | /* for each potential first byte of a header */ |
| 94 | for (i = 0; i < 256; i++) { |
| 95 | /* find the field type that matches it */ |
| 96 | chrspec = NULL; |
| 97 | for (j = 0; j < num_fields; j++) { |
| 98 | if ((prefix_mask(fields[j].prefix_length) & i) == fields[j].prefix) { |
David Garcia Quintas | 809831e | 2015-10-05 13:40:07 -0700 | [diff] [blame] | 99 | /* NB: the following integer arithmetic operation needs to be in its |
| 100 | * expanded form due to the "integral promotion" performed (see section |
David Garcia Quintas | 35284f0 | 2015-10-06 11:05:05 -0700 | [diff] [blame] | 101 | * 3.2.1.1 of the C89 draft standard). A cast to the smaller container |
| 102 | * type is then required to avoid the compiler warning */ |
David Garcia Quintas | d76cdac | 2015-10-03 15:57:09 -0700 | [diff] [blame] | 103 | suffix = (unsigned char)(suffix_mask(fields[j].prefix_length) & |
| 104 | (unsigned char)i); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 105 | if (suffix == suffix_mask(fields[j].prefix_length)) { |
| 106 | if (fields[j].index != 2) continue; |
| 107 | } else if (suffix == 0) { |
| 108 | if (fields[j].index != 0) continue; |
| 109 | } else { |
| 110 | if (fields[j].index != 1) continue; |
| 111 | } |
| 112 | GPR_ASSERT(chrspec == NULL); |
| 113 | chrspec = &fields[j]; |
| 114 | } |
| 115 | } |
| 116 | if (chrspec) { |
| 117 | n += printf("%s, ", chrspec->call); |
| 118 | } else { |
| 119 | n += printf("ILLEGAL, "); |
| 120 | } |
| 121 | /* make some small effort towards readable output */ |
| 122 | if (n > 70) { |
| 123 | printf("\n "); |
| 124 | n = 2; |
| 125 | } |
| 126 | } |
| 127 | printf("};\n"); |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | * Huffman decoder table generation |
| 132 | */ |
| 133 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 134 | #define MAXHUFFSTATES 1024 |
| 135 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 136 | /* represents a set of symbols as an array of booleans indicating inclusion */ |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 137 | typedef struct { char included[GRPC_CHTTP2_NUM_HUFFSYMS]; } symset; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 138 | /* represents a lookup table indexed by a nibble */ |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 139 | typedef struct { unsigned values[16]; } nibblelut; |
| 140 | |
| 141 | #define NOT_SET (~(unsigned)0) |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 142 | |
| 143 | /* returns a symset that includes all possible symbols */ |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 144 | static symset symset_all(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 145 | symset x; |
| 146 | memset(x.included, 1, sizeof(x.included)); |
| 147 | return x; |
| 148 | } |
| 149 | |
| 150 | /* returns a symset that includes no symbols */ |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 151 | static symset symset_none(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 152 | symset x; |
| 153 | memset(x.included, 0, sizeof(x.included)); |
| 154 | return x; |
| 155 | } |
| 156 | |
| 157 | /* returns an empty nibblelut */ |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 158 | static nibblelut nibblelut_empty(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 159 | nibblelut x; |
| 160 | int i; |
| 161 | for (i = 0; i < 16; i++) { |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 162 | x.values[i] = NOT_SET; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 163 | } |
| 164 | return x; |
| 165 | } |
| 166 | |
| 167 | /* counts symbols in a symset - only used for debug builds */ |
| 168 | #ifndef NDEBUG |
| 169 | static int nsyms(symset s) { |
| 170 | int i; |
| 171 | int c = 0; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 172 | for (i = 0; i < GRPC_CHTTP2_NUM_HUFFSYMS; i++) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 173 | c += s.included[i] != 0; |
| 174 | } |
| 175 | return c; |
| 176 | } |
| 177 | #endif |
| 178 | |
| 179 | /* global table of discovered huffman decoding states */ |
| 180 | static struct { |
| 181 | /* the bit offset that this state starts at */ |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 182 | unsigned bitofs; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 183 | /* the set of symbols that this state started with */ |
| 184 | symset syms; |
| 185 | |
| 186 | /* lookup table for the next state */ |
| 187 | nibblelut next; |
| 188 | /* lookup table for what to emit */ |
| 189 | nibblelut emit; |
| 190 | } huffstates[MAXHUFFSTATES]; |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 191 | static unsigned nhuffstates = 0; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 192 | |
| 193 | /* given a number of decoded bits and a set of symbols that are live, |
| 194 | return the index into the decoder table for this state. |
| 195 | set isnew to 1 if this state was previously undiscovered */ |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 196 | static unsigned state_index(unsigned bitofs, symset syms, unsigned *isnew) { |
| 197 | unsigned i; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 198 | for (i = 0; i < nhuffstates; i++) { |
| 199 | if (huffstates[i].bitofs != bitofs) continue; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 200 | if (0 != memcmp(huffstates[i].syms.included, syms.included, |
| 201 | GRPC_CHTTP2_NUM_HUFFSYMS)) |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 202 | continue; |
| 203 | *isnew = 0; |
| 204 | return i; |
| 205 | } |
| 206 | GPR_ASSERT(nhuffstates != MAXHUFFSTATES); |
| 207 | i = nhuffstates++; |
| 208 | huffstates[i].bitofs = bitofs; |
| 209 | huffstates[i].syms = syms; |
| 210 | huffstates[i].next = nibblelut_empty(); |
| 211 | huffstates[i].emit = nibblelut_empty(); |
| 212 | *isnew = 1; |
| 213 | return i; |
| 214 | } |
| 215 | |
| 216 | /* recursively build a decoding table |
| 217 | |
| 218 | state - the huffman state that we are trying to fill in |
| 219 | nibble - the current nibble |
| 220 | nibbits - the number of bits in the nibble that have been filled in |
| 221 | bitofs - the number of bits of symbol that have been decoded |
| 222 | emit - the symbol to emit on this nibble (or -1 if no symbol has been |
| 223 | found) |
| 224 | syms - the set of symbols that could be matched */ |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 225 | static void build_dec_tbl(unsigned state, unsigned nibble, int nibbits, |
| 226 | unsigned bitofs, unsigned emit, symset syms) { |
| 227 | unsigned i; |
Nicolas "Pixel" Noble | 8535263 | 2015-06-02 02:01:51 +0200 | [diff] [blame] | 228 | unsigned bit; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 229 | |
| 230 | /* If we have four bits in the nibble we're looking at, then we can fill in |
| 231 | a slot in the lookup tables. */ |
| 232 | if (nibbits == 4) { |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 233 | unsigned isnew; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 234 | /* Find the state that we are in: this may be a new state, in which case |
| 235 | we recurse to fill it in, or we may have already seen this state, in |
| 236 | which case the recursion terminates */ |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 237 | unsigned st = state_index(bitofs, syms, &isnew); |
| 238 | GPR_ASSERT(huffstates[state].next.values[nibble] == NOT_SET); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 239 | huffstates[state].next.values[nibble] = st; |
| 240 | huffstates[state].emit.values[nibble] = emit; |
| 241 | if (isnew) { |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 242 | build_dec_tbl(st, 0, 0, bitofs, NOT_SET, syms); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 243 | } |
| 244 | return; |
| 245 | } |
| 246 | |
| 247 | assert(nsyms(syms)); |
| 248 | |
| 249 | /* A bit can be 0 or 1 */ |
| 250 | for (bit = 0; bit < 2; bit++) { |
| 251 | /* walk over active symbols and see if they have this bit set */ |
| 252 | symset nextsyms = symset_none(); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 253 | for (i = 0; i < GRPC_CHTTP2_NUM_HUFFSYMS; i++) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 254 | if (!syms.included[i]) continue; /* disregard inactive symbols */ |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 255 | if (((grpc_chttp2_huffsyms[i].bits >> |
| 256 | (grpc_chttp2_huffsyms[i].length - bitofs - 1)) & |
| 257 | 1) == bit) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 258 | /* the bit is set, include it in the next recursive set */ |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 259 | if (grpc_chttp2_huffsyms[i].length == bitofs + 1) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 260 | /* additionally, we've gotten to the end of a symbol - this is a |
| 261 | special recursion step: re-activate all the symbols, reset |
| 262 | bitofs to zero, and recurse */ |
| 263 | build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, 0, i, |
| 264 | symset_all()); |
| 265 | /* skip the remainder of this loop */ |
| 266 | goto next; |
| 267 | } |
| 268 | nextsyms.included[i] = 1; |
| 269 | } |
| 270 | } |
| 271 | /* recurse down for this bit */ |
| 272 | build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, bitofs + 1, emit, |
| 273 | nextsyms); |
Craig Tiller | 4aa71a1 | 2015-06-15 13:00:55 -0700 | [diff] [blame] | 274 | next:; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 275 | } |
| 276 | } |
| 277 | |
| 278 | static nibblelut ctbl[MAXHUFFSTATES]; |
| 279 | static int nctbl; |
| 280 | |
| 281 | static int ctbl_idx(nibblelut x) { |
| 282 | int i; |
| 283 | for (i = 0; i < nctbl; i++) { |
| 284 | if (0 == memcmp(&x, ctbl + i, sizeof(nibblelut))) return i; |
| 285 | } |
| 286 | ctbl[i] = x; |
| 287 | nctbl++; |
| 288 | return i; |
| 289 | } |
| 290 | |
| 291 | static void dump_ctbl(const char *name) { |
| 292 | int i, j; |
| 293 | printf("static const gpr_int16 %s[%d*16] = {\n", name, nctbl); |
| 294 | for (i = 0; i < nctbl; i++) { |
| 295 | for (j = 0; j < 16; j++) { |
| 296 | printf("%d,", ctbl[i].values[j]); |
| 297 | } |
| 298 | printf("\n"); |
| 299 | } |
| 300 | printf("};\n"); |
| 301 | } |
| 302 | |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 303 | static void generate_huff_tables(void) { |
Craig Tiller | f96dfc3 | 2015-09-10 14:43:18 -0700 | [diff] [blame] | 304 | unsigned i; |
| 305 | build_dec_tbl(state_index(0, symset_all(), &i), 0, 0, 0, NOT_SET, |
| 306 | symset_all()); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 307 | |
| 308 | nctbl = 0; |
| 309 | printf("static const gpr_uint8 next_tbl[%d] = {", nhuffstates); |
| 310 | for (i = 0; i < nhuffstates; i++) { |
| 311 | printf("%d,", ctbl_idx(huffstates[i].next)); |
| 312 | } |
| 313 | printf("};\n"); |
| 314 | dump_ctbl("next_sub_tbl"); |
| 315 | |
| 316 | nctbl = 0; |
| 317 | printf("static const gpr_uint16 emit_tbl[%d] = {", nhuffstates); |
| 318 | for (i = 0; i < nhuffstates; i++) { |
| 319 | printf("%d,", ctbl_idx(huffstates[i].emit)); |
| 320 | } |
| 321 | printf("};\n"); |
| 322 | dump_ctbl("emit_sub_tbl"); |
| 323 | } |
| 324 | |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 325 | static void generate_base64_huff_encoder_table(void) { |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 326 | static const char alphabet[] = |
| 327 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 328 | int i; |
| 329 | |
| 330 | printf( |
| 331 | "static const struct { gpr_uint16 bits, gpr_uint8 length } " |
| 332 | "base64_syms[64] = {\n"); |
| 333 | for (i = 0; i < 64; i++) { |
| 334 | printf("{0x%x, %d},", grpc_chttp2_huffsyms[(unsigned char)alphabet[i]].bits, |
| 335 | grpc_chttp2_huffsyms[(unsigned char)alphabet[i]].length); |
| 336 | } |
| 337 | printf("};\n"); |
| 338 | } |
| 339 | |
Craig Tiller | 32946d3 | 2015-01-15 11:37:30 -0800 | [diff] [blame] | 340 | static void generate_base64_inverse_table(void) { |
ctiller | 33023c4 | 2014-12-12 16:28:33 -0800 | [diff] [blame] | 341 | static const char alphabet[] = |
| 342 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
| 343 | unsigned char inverse[256]; |
Nicolas "Pixel" Noble | 8535263 | 2015-06-02 02:01:51 +0200 | [diff] [blame] | 344 | unsigned i; |
ctiller | 33023c4 | 2014-12-12 16:28:33 -0800 | [diff] [blame] | 345 | |
| 346 | memset(inverse, 255, sizeof(inverse)); |
| 347 | for (i = 0; i < strlen(alphabet); i++) { |
Craig Tiller | 6a6b36c | 2015-09-10 16:00:22 -0700 | [diff] [blame] | 348 | inverse[(unsigned char)alphabet[i]] = (unsigned char)i; |
ctiller | 33023c4 | 2014-12-12 16:28:33 -0800 | [diff] [blame] | 349 | } |
| 350 | |
| 351 | printf("static const gpr_uint8 inverse_base64[256] = {"); |
| 352 | for (i = 0; i < 256; i++) { |
| 353 | printf("%d,", inverse[i]); |
| 354 | } |
| 355 | printf("};\n"); |
| 356 | } |
| 357 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 358 | int main(void) { |
| 359 | generate_huff_tables(); |
| 360 | generate_first_byte_lut(); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 361 | generate_base64_huff_encoder_table(); |
ctiller | 33023c4 | 2014-12-12 16:28:33 -0800 | [diff] [blame] | 362 | generate_base64_inverse_table(); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 363 | |
| 364 | return 0; |
Craig Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 365 | } |