Line data Source code
1 : #include "passgen/parser/token.h" 2 : 3 61 : void passgen_token_parser_init(struct passgen_token_parser *token_parser) { 4 61 : token_parser->state = PASSGEN_TOKEN_INIT; 5 61 : token_parser->offset = 0; 6 61 : token_parser->byte_offset = 0; 7 61 : } 8 : 9 287 : const char *passgen_token_state_string(enum passgen_token_state state) { 10 287 : switch(state) { 11 1 : case PASSGEN_TOKEN_INIT: 12 1 : return "ready for parsing"; 13 236 : case PASSGEN_TOKEN_ESCAPED: 14 236 : return "parsing escaped token"; 15 4 : case PASSGEN_TOKEN_UNICODE: 16 4 : return "parsing unicode token"; 17 3 : case PASSGEN_TOKEN_UNICODE_PAYLOAD: 18 3 : return "parsing unicode token payload"; 19 37 : case PASSGEN_TOKEN_ERROR_UNICODE_START: 20 37 : return "unexpected character while parsing unicode literal"; 21 1 : case PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD: 22 1 : return "unexpected character while parsing unicode literal"; 23 3 : case PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD_LEN: 24 3 : return "unicode literal payload too long"; 25 2 : default: 26 2 : return NULL; 27 : } 28 : } 29 : 30 5566260 : static inline int8_t hex_decode(uint32_t c) { 31 5566260 : if('0' <= c && c <= '9') { 32 3501844 : return c - '0'; 33 : } 34 : 35 2064416 : if('A' <= c && c <= 'F') { 36 5 : return 10 + c - 'A'; 37 : } 38 : 39 2064411 : if('a' <= c && c <= 'f') { 40 2064401 : return 10 + c - 'a'; 41 : } 42 : 43 10 : return -1; 44 : } 45 : 46 3685005 : static inline void token_parse_init( 47 : struct passgen_token_parser *parser, 48 : struct passgen_token *token, 49 : uint32_t codepoint) { 50 : // save position of initial token 51 3685005 : token->offset = parser->offset; 52 3685005 : token->byte_offset = parser->byte_offset; 53 : 54 3685005 : if(codepoint == '\\') { 55 2231031 : parser->state = PASSGEN_TOKEN_ESCAPED; 56 : } else { 57 1453974 : token->codepoint = codepoint; 58 1453974 : parser->state = PASSGEN_TOKEN_INIT; 59 : } 60 3685005 : } 61 : 62 : // Simple ASCII escape map. Don't use this for large (unicode) codepoints. 63 : // Provides efficient O(1) lookup. 64 : static const char simple_escaped[] = { 65 : 0, 66 : ['a'] = '\a', 67 : ['b'] = '\b', 68 : ['e'] = '\033', 69 : ['f'] = '\f', 70 : ['n'] = '\n', 71 : ['r'] = '\r', 72 : ['t'] = '\t', 73 : ['v'] = '\v', 74 : ['\\'] = '\\'}; 75 : 76 2230796 : static inline void token_parse_escaped( 77 : struct passgen_token_parser *parser, 78 : struct passgen_token *token, 79 : uint32_t codepoint) { 80 : // simple_escaped only covers ASCII, whereas codepoint could be much 81 : // larger. 82 2230796 : if(codepoint < sizeof(simple_escaped) && simple_escaped[codepoint]) { 83 402 : token->codepoint = simple_escaped[codepoint]; 84 402 : parser->state = PASSGEN_TOKEN_INIT; 85 : 86 402 : return; 87 : } 88 : 89 2230394 : switch(codepoint) { 90 1114188 : case 'u': 91 1114188 : parser->state = PASSGEN_TOKEN_UNICODE; 92 1114188 : break; 93 1116206 : default: 94 1116206 : token->codepoint = codepoint | PASSGEN_TOKEN_ESCAPED_BIT; 95 1116206 : parser->state = PASSGEN_TOKEN_INIT; 96 : } 97 : } 98 : 99 : static inline void 100 1114185 : token_parse_unicode(struct passgen_token_parser *parser, uint32_t codepoint) { 101 1114185 : if(codepoint == '{') { 102 1114138 : parser->state = PASSGEN_TOKEN_UNICODE_PAYLOAD; 103 1114138 : parser->data.unicode_payload.length = 0; 104 1114138 : parser->data.unicode_payload.codepoint = 0; 105 : } else { 106 47 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_START; 107 : } 108 1114185 : } 109 : 110 6680386 : static inline void token_parse_unicode_payload( 111 : struct passgen_token_parser *parser, 112 : struct passgen_token *token, 113 : uint32_t codepoint) { 114 : // once we read the closing brace, the payload is over and we can emit the 115 : // token. 116 6680386 : if(codepoint == '}') { 117 1114120 : token->codepoint = parser->data.unicode_payload.codepoint; 118 1114120 : parser->state = PASSGEN_TOKEN_INIT; 119 : 120 1114120 : return; 121 : } 122 : 123 : // keep track of length, make sure it's not too long. 124 5566266 : parser->data.unicode_payload.length++; 125 5566266 : if(parser->data.unicode_payload.length > 6) { 126 6 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD_LEN; 127 : 128 6 : return; 129 : } 130 : 131 : // try to decode the hex value. 132 5566260 : int8_t decoded = hex_decode(codepoint); 133 5566260 : if(decoded < 0) { 134 10 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD; 135 : 136 10 : return; 137 : } 138 : 139 5566250 : parser->data.unicode_payload.codepoint *= 16; 140 5566250 : parser->data.unicode_payload.codepoint += decoded; 141 : } 142 : 143 13710375 : int passgen_token_parse( 144 : struct passgen_token_parser *parser, 145 : struct passgen_token *token, 146 : uint8_t width, 147 : uint32_t codepoint) { 148 13710375 : switch(parser->state) { 149 3685005 : case PASSGEN_TOKEN_INIT: 150 3685005 : token_parse_init(parser, token, codepoint); 151 3685005 : break; 152 2230796 : case PASSGEN_TOKEN_ESCAPED: 153 2230796 : token_parse_escaped(parser, token, codepoint); 154 2230796 : break; 155 1114185 : case PASSGEN_TOKEN_UNICODE: 156 1114185 : token_parse_unicode(parser, codepoint); 157 1114185 : break; 158 6680386 : case PASSGEN_TOKEN_UNICODE_PAYLOAD: 159 6680386 : token_parse_unicode_payload(parser, token, codepoint); 160 6680386 : break; 161 3 : default: 162 3 : return parser->state; 163 : } 164 : 165 : // update parser offsets 166 13710372 : parser->offset += 1; 167 13710372 : parser->byte_offset += width; 168 : 169 13710372 : return parser->state; 170 : } 171 : 172 278 : const char *passgen_token_parse_error_str(int ret) { 173 278 : return passgen_token_state_string(ret); 174 : }