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 284 : const char *passgen_token_state_string(enum passgen_token_state state) { 10 284 : switch(state) { 11 1 : case PASSGEN_TOKEN_INIT: 12 1 : return "ready for parsing"; 13 218 : case PASSGEN_TOKEN_ESCAPED: 14 218 : return "parsing escaped token"; 15 7 : case PASSGEN_TOKEN_UNICODE: 16 7 : return "parsing unicode token"; 17 4 : case PASSGEN_TOKEN_UNICODE_PAYLOAD: 18 4 : return "parsing unicode token payload"; 19 47 : case PASSGEN_TOKEN_ERROR_UNICODE_START: 20 47 : return "unexpected character while parsing unicode literal"; 21 2 : case PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD: 22 2 : 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 5566264 : static inline int8_t hex_decode(uint32_t c) { 31 5566264 : if('0' <= c && c <= '9') { 32 3501846 : return c - '0'; 33 : } 34 : 35 2064418 : if('A' <= c && c <= 'F') { 36 5 : return 10 + c - 'A'; 37 : } 38 : 39 2064413 : if('a' <= c && c <= 'f') { 40 2064402 : return 10 + c - 'a'; 41 : } 42 : 43 11 : return -1; 44 : } 45 : 46 3684056 : 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 3684056 : token->offset = parser->offset; 52 3684056 : token->byte_offset = parser->byte_offset; 53 : 54 3684056 : if(codepoint == '\\') { 55 2231106 : parser->state = PASSGEN_TOKEN_ESCAPED; 56 : } else { 57 1452950 : token->codepoint = codepoint; 58 1452950 : parser->state = PASSGEN_TOKEN_INIT; 59 : } 60 3684056 : } 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 2230889 : 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 2230889 : if(codepoint < sizeof(simple_escaped) && simple_escaped[codepoint]) { 83 378 : token->codepoint = simple_escaped[codepoint]; 84 378 : parser->state = PASSGEN_TOKEN_INIT; 85 : 86 378 : return; 87 : } 88 : 89 2230511 : switch(codepoint) { 90 1114203 : case 'u': 91 1114203 : parser->state = PASSGEN_TOKEN_UNICODE; 92 1114203 : break; 93 1116308 : default: 94 1116308 : token->codepoint = codepoint | PASSGEN_TOKEN_ESCAPED_BIT; 95 1116308 : parser->state = PASSGEN_TOKEN_INIT; 96 : } 97 : } 98 : 99 : static inline void 100 1114197 : token_parse_unicode(struct passgen_token_parser *parser, uint32_t codepoint) { 101 1114197 : if(codepoint == '{') { 102 1114140 : parser->state = PASSGEN_TOKEN_UNICODE_PAYLOAD; 103 1114140 : parser->data.unicode_payload.length = 0; 104 1114140 : parser->data.unicode_payload.codepoint = 0; 105 : } else { 106 57 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_START; 107 : } 108 1114197 : } 109 : 110 6680390 : 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 6680390 : 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 5566270 : parser->data.unicode_payload.length++; 125 5566270 : 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 5566264 : int8_t decoded = hex_decode(codepoint); 133 5566264 : if(decoded < 0) { 134 11 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD; 135 : 136 11 : return; 137 : } 138 : 139 5566253 : parser->data.unicode_payload.codepoint *= 16; 140 5566253 : parser->data.unicode_payload.codepoint += decoded; 141 : } 142 : 143 13709535 : int passgen_token_parse( 144 : struct passgen_token_parser *parser, 145 : struct passgen_token *token, 146 : uint8_t width, 147 : uint32_t codepoint) { 148 13709535 : switch(parser->state) { 149 3684056 : case PASSGEN_TOKEN_INIT: 150 3684056 : token_parse_init(parser, token, codepoint); 151 3684056 : break; 152 2230889 : case PASSGEN_TOKEN_ESCAPED: 153 2230889 : token_parse_escaped(parser, token, codepoint); 154 2230889 : break; 155 1114197 : case PASSGEN_TOKEN_UNICODE: 156 1114197 : token_parse_unicode(parser, codepoint); 157 1114197 : break; 158 6680390 : case PASSGEN_TOKEN_UNICODE_PAYLOAD: 159 6680390 : token_parse_unicode_payload(parser, token, codepoint); 160 6680390 : break; 161 3 : default: 162 3 : return parser->state; 163 : } 164 : 165 : // update parser offsets 166 13709532 : parser->offset += 1; 167 13709532 : parser->byte_offset += width; 168 : 169 13709532 : return parser->state; 170 : } 171 : 172 275 : const char *passgen_token_parse_error_str(int ret) { 173 275 : return passgen_token_state_string(ret); 174 : }