diff options
| author | ThomasintAnker <thomasintanker1@gmail.com> | 2024-05-31 15:06:06 +0200 |
|---|---|---|
| committer | ThomasintAnker <thomasintanker1@gmail.com> | 2024-05-31 15:06:06 +0200 |
| commit | 0278037aaf3fd497aae57d90f2638ceda3b12a6d (patch) | |
| tree | 3354a14d4551b9524108d02971bfa42fc1ad4993 /client/parse.cpp | |
| parent | b865921e5dcf2ae2d6532b88eba1a0a49998eb27 (diff) | |
| parent | 18d06c79b9f6a625eb218a15c8216556fb99dc02 (diff) | |
Merge branch 'wip/client' into wip/i2c-communication
Diffstat (limited to 'client/parse.cpp')
| -rw-r--r-- | client/parse.cpp | 169 |
1 files changed, 118 insertions, 51 deletions
diff --git a/client/parse.cpp b/client/parse.cpp index 223dc5d..16f0781 100644 --- a/client/parse.cpp +++ b/client/parse.cpp @@ -1,14 +1,12 @@ -#include <math.h> #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <netinet/in.h> #include "parse.h" -static int parse_str(const char* str, char* data, size_t* size) { - char closing = str[0]; +static int parse_string(const char * str, char * data, size_t * offset) { char escape = false; - bool scan = data == NULL; int i = 0; size_t len = strlen(str); @@ -22,34 +20,76 @@ static int parse_str(const char* str, char* data, size_t* size) { default: return -i; } + char closing = str[i]; - for (i = 1; i < len && str[i] != '\0'; i++) { + for (i = 1; i < len && str[i] != '\0'; i++, *offset += 1) { char c = str[i]; - if (c == closing) { - if (scan) printf("string%s of length %d\n", escape ? " (w/ escape)" : "", i - 1); + if (c == closing) return i + 1; // +1 for closing quote + + if (escape && c == '\\') { + char x = str[i + 1]; + if (x == '0') c = '\0'; + else if (x == 't') c = '\t'; + else if (x == 'n') c = '\n'; + else if (x == 'r') c = '\r'; + else if (x == '\\') c = '\\'; + else if (x == '\"') c = '\"'; + else if (x == '\'') c = '\''; + else break; + i++; } - if (scan) *size += 1; + if (data != NULL) + data[*offset] = c; } return -i; } -static int parse_num(const char* str, char* data, size_t* size) { - const char* ifs = IFS; - size_t len = strcspn(str, ifs); - bool scan = data == NULL; +static int parse_hexstr(const char * str, char * data, size_t * offset) { + size_t len = strcspn(str, IFS); + int i = 0; + + // check if token contains at least one colon + const char* colon = strchr(str, ':'); + if (colon == NULL) return -i; + if (colon >= str + len) return -i; + + // check if token only contains allowed characters [0-9a-fA-F:] + size_t len_ok = strspn(str + i, SET_HEX_STR) + i; + if (len != len_ok) return -len_ok; + + size_t c = 0; + while (c < len) { // count bytes in bytestring + if (strspn(str + c, SET_HEX) != 2) + return -i -c; + + if (data != NULL) + data[*offset] = strtol(str + c, NULL, 16) & 0xff; + + c += 2; + *offset += 1; + + if (str[c] == ':') { + c += 1; + continue; + } + break; + } + + i += len; + return i; +} + +static int parse_number(const char * str, char * data, size_t * offset) { + size_t len = strcspn(str, IFS); int i = 0; int base = 10; bool bytestring = false; - const char* colon = strchr(str, ':'); - if (colon != NULL && colon < str + len) { // byte string - base = 16; - bytestring = true; - } else if (len > 2 && strncmp(str, "0x", 2) == 0) { // hexadecimal prefix + if (len > 2 && strncmp(str, "0x", 2) == 0) { // hexadecimal prefix base = 16; i += 2; }/* else if (len > 1 && strncmp(str, "0", 1) == 0) { // octal prefix @@ -60,58 +100,85 @@ static int parse_num(const char* str, char* data, size_t* size) { const char* set; // if (base == 8) set = SET_OCT; if (base == 10) set = SET_DEC; - if (base == 16) { - if (bytestring) set = SET_HEX_STR; - else set = SET_HEX; - } + if (base == 16) set = SET_HEX; size_t len_ok = strspn(str + i, set) + i; if (len != len_ok) return -len_ok; - if (scan) { - if (base == 10) *size += 1; - else if (base == 16) { - if (!bytestring) { - *size += (len - i + 1) / 2; - } else { - for (; colon != NULL && colon < str + len; colon = strchr(str, ':')) { - *size += 1; - } - } + size_t size = 1; // default integer size in bytes + if (base == 16) { + size_t prefixless = len - i; + switch (prefixless) { + case 2: // 8-bit (2 hex characters) + case 4: // 16-bit + case 8: // 32-bit + case 16: // 64-bit + break; + default: + return -i; + } + size = prefixless / 2; + } + + if (data != NULL) { + unsigned long number = strtol(str + i, NULL, base); + long long mask = (1 << 8 * size) - 1; + number &= mask; + // NOTE: the hton? functions are used to convert host endianness to network + // endianness (big), and are required + switch (size) { + case 1: + data[*offset] = number & 0xff; + break; + case 2: + number = htons(number); + // TODO: check if the endianness is OK, or reverse these *offset indices* + data[*offset + 1] = (number) & 0xff; + data[*offset + 0] = (number >>= 8) & 0xff; + break; + case 4: + number = htonl(number); + data[*offset + 3] = (number) & 0xff; + data[*offset + 2] = (number >>= 8) & 0xff; + data[*offset + 1] = (number >>= 8) & 0xff; + data[*offset + 0] = (number >>= 8) & 0xff; + break; } } - if (scan) printf("number (base %d%s) of length %lu\n", base, bytestring ? " as bytestring" : "", len - i); + *offset += size; return len; } -int strtodata(const char* str, char** data, size_t* size) { - const char* ifs = IFS; - *size = 0; - size_t i; +static int _strtodata_main(const char * str, char* data, size_t * offset) { size_t len = strlen(str); - for (i = 0; i < len;) { - // skip whitespace - int run; - run = strspn(&str[i], ifs); - if (run > 0) printf("skipping whitespace for %d bytes...\n", run); - i += run; - // end of string - if (str[i] == '\0') break; + int i, run; + for (i = 0; i < len; i += run) { + i += strspn(&str[i], IFS); // skip whitespace + if (str[i] == '\0') break; // end of string - if ((run = parse_str(str + i, NULL, size)) > 0) { i += run; continue; } - if ((run = parse_num(str + i, NULL, size)) > 0) { i += run; continue; } + if ((run = parse_string(str + i, data, offset)) > 0) continue; + if ((run = parse_hexstr(str + i, data, offset)) > 0) continue; + if ((run = parse_number(str + i, data, offset)) > 0) continue; // no format detected return -i + run; } - printf("end of string w/o parse errors\n"); - printf("buffer size is now %lu\n", *size); - exit(0); - *data = (char*) malloc(*size); + return i; +} - return 0; +int strtodata(const char * str, char ** data, size_t * size) { + *size = 0; + + // 1st pass: check data format + int ret = _strtodata_main(str, NULL, size); + if (ret <= 0) return ret; // on error + + // 2nd pass: convert string literals into binary data + *data = (char*) malloc(*size); + size_t written = 0; + return _strtodata_main(str, *data, &written); } |