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 259 : const char *passgen_token_state_string(enum passgen_token_state state) { 10 259 : switch(state) { 11 1 : case PASSGEN_TOKEN_INIT: 12 1 : return "ready for parsing"; 13 209 : case PASSGEN_TOKEN_ESCAPED: 14 209 : return "parsing escaped token"; 15 7 : case PASSGEN_TOKEN_UNICODE: 16 7 : return "parsing unicode token"; 17 3 : case PASSGEN_TOKEN_UNICODE_PAYLOAD: 18 3 : return "parsing unicode token payload"; 19 32 : case PASSGEN_TOKEN_ERROR_UNICODE_START: 20 32 : 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 5566261 : static inline int8_t hex_decode(uint32_t c) { 31 5566261 : if('0' <= c && c <= '9') { 32 3501844 : return c - '0'; 33 : } 34 : 35 2064417 : if('A' <= c && c <= 'F') { 36 5 : return 10 + c - 'A'; 37 : } 38 : 39 2064412 : if('a' <= c && c <= 'f') { 40 2064401 : return 10 + c - 'a'; 41 : } 42 : 43 11 : return -1; 44 : } 45 : 46 3685679 : 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 3685679 : token->offset = parser->offset; 52 3685679 : token->byte_offset = parser->byte_offset; 53 : 54 3685679 : if(codepoint == '\\') { 55 2231025 : parser->state = PASSGEN_TOKEN_ESCAPED; 56 : } else { 57 1454654 : token->codepoint = codepoint; 58 1454654 : parser->state = PASSGEN_TOKEN_INIT; 59 : } 60 3685679 : } 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 2230817 : 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 2230817 : if(codepoint < sizeof(simple_escaped) && simple_escaped[codepoint]) { 83 408 : token->codepoint = simple_escaped[codepoint]; 84 408 : parser->state = PASSGEN_TOKEN_INIT; 85 : 86 408 : return; 87 : } 88 : 89 2230409 : switch(codepoint) { 90 1114187 : case 'u': 91 1114187 : parser->state = PASSGEN_TOKEN_UNICODE; 92 1114187 : break; 93 1116222 : default: 94 1116222 : token->codepoint = codepoint | PASSGEN_TOKEN_ESCAPED_BIT; 95 1116222 : parser->state = PASSGEN_TOKEN_INIT; 96 : } 97 : } 98 : 99 : static inline void 100 1114181 : token_parse_unicode(struct passgen_token_parser *parser, uint32_t codepoint) { 101 1114181 : if(codepoint == '{') { 102 1114139 : parser->state = PASSGEN_TOKEN_UNICODE_PAYLOAD; 103 1114139 : parser->data.unicode_payload.length = 0; 104 1114139 : parser->data.unicode_payload.codepoint = 0; 105 : } else { 106 42 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_START; 107 : } 108 1114181 : } 109 : 110 6680387 : 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 6680387 : 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 5566267 : parser->data.unicode_payload.length++; 125 5566267 : 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 5566261 : int8_t decoded = hex_decode(codepoint); 133 5566261 : if(decoded < 0) { 134 11 : parser->state = PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD; 135 : 136 11 : return; 137 : } 138 : 139 5566250 : parser->data.unicode_payload.codepoint *= 16; 140 5566250 : parser->data.unicode_payload.codepoint += decoded; 141 : } 142 : 143 13711067 : int passgen_token_parse( 144 : struct passgen_token_parser *parser, 145 : struct passgen_token *token, 146 : uint8_t width, 147 : uint32_t codepoint) { 148 13711067 : switch(parser->state) { 149 3685679 : case PASSGEN_TOKEN_INIT: 150 3685679 : token_parse_init(parser, token, codepoint); 151 3685679 : break; 152 2230817 : case PASSGEN_TOKEN_ESCAPED: 153 2230817 : token_parse_escaped(parser, token, codepoint); 154 2230817 : break; 155 1114181 : case PASSGEN_TOKEN_UNICODE: 156 1114181 : token_parse_unicode(parser, codepoint); 157 1114181 : break; 158 6680387 : case PASSGEN_TOKEN_UNICODE_PAYLOAD: 159 6680387 : token_parse_unicode_payload(parser, token, codepoint); 160 6680387 : break; 161 3 : default: 162 3 : return parser->state; 163 : } 164 : 165 : // update parser offsets 166 13711064 : parser->offset += 1; 167 13711064 : parser->byte_offset += width; 168 : 169 13711064 : return parser->state; 170 : } 171 : 172 250 : const char *passgen_token_parse_error_str(int ret) { 173 250 : return passgen_token_state_string(ret); 174 : }