Skip to content

Commit

Permalink
add mg_str_to_num
Browse files Browse the repository at this point in the history
  • Loading branch information
scaprile committed May 14, 2024
1 parent 3ae1a0f commit 0813747
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 30 deletions.
92 changes: 78 additions & 14 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -2240,21 +2240,11 @@ static int mg_ncasecmp(const char *s1, const char *s2, size_t len) {

bool mg_to_size_t(struct mg_str str, size_t *val);
bool mg_to_size_t(struct mg_str str, size_t *val) {
size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0;
extern size_t mg_str_to_num_(struct mg_str, int, void *, size_t);
size_t i = mg_str_to_num_(str, 10, val, sizeof(size_t));
if (i == 0) return false;
while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++;
if (i < str.len && str.buf[i] == '-') return false;
while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') {
size_t digit = (size_t) (str.buf[i] - '0');
if (result > max2) return false; // Overflow
result *= 10;
if (result > max - digit) return false; // Overflow
result += digit;
i++, ndigits++;
}
while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++;
if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT
if (i != str.len) return false; // Ditto
*val = (size_t) result;
if (i != str.len) return false; // #2322: Content-Length = 1 * DIGIT
return true;
}

Expand Down Expand Up @@ -8120,6 +8110,80 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) {
}
}

size_t mg_str_to_num_(struct mg_str str, int base, void *val, size_t val_len);
size_t mg_str_to_num_(struct mg_str str, int base, void *val, size_t val_len) {
size_t i = 0, ndigits = 0;
uint64_t max = val_len == 1 ? 0xFF
: val_len == 2 ? 0xFFFF
: val_len == 4 ? 0xFFFFFFFF
: (uint64_t) ~0;
uint64_t max2 = max / 10, result = 0;
while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++;
if (base == 0 && str.len >= 2) {
if (str.buf[i] == '0') {
i++;
base = str.buf[i] == 'b' ? 2 : str.buf[i] == 'x' ? 16 : 10;
if (base != 10) ++i;
} else {
base = 10;
}
}
switch (base) {
case 2:
while (i < str.len && (str.buf[i] == '0' || str.buf[i] == '1')) {
uint64_t digit = (uint64_t) (str.buf[i] - '0');
if (result > max2) return 0; // Overflow
result *= 2;
if (result > max - digit) return 0; // Overflow
result += digit;
i++, ndigits++;
}
break;
case 10:
while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') {
uint64_t digit = (uint64_t) (str.buf[i] - '0');
if (result > max2) return 0; // Overflow
result *= 10;
if (result > max - digit) return 0; // Overflow
result += digit;
i++, ndigits++;
}
break;
case 16:
while (i < str.len) {
char c = str.buf[i];
uint64_t digit = (c >= '0' && c <= '9') ? (uint64_t) (c - '0')
: (c >= 'A' && c <= 'F') ? (uint64_t) (c - '7')
: (c >= 'a' && c <= 'f') ? (uint64_t) (c - 'W')
: (uint64_t) ~0;
if (digit == (uint64_t) ~0) break;
if (result > max2) return 0; // Overflow
result *= 16;
if (result > max - digit) return 0; // Overflow
result += digit;
i++, ndigits++;
}
break;
default:
return 0;
}
if (ndigits == 0) return 0; // #2322: Content-Length = 1 * DIGIT
if (val_len == 1) {
*((uint8_t *) val) = (uint8_t) result;
} else if (val_len == 2) {
*((uint16_t *) val) = (uint16_t) result;
} else if (val_len == 4) {
*((uint32_t *) val) = (uint32_t) result;
} else {
*((uint64_t *) val) = (uint64_t) result;
}
return i;
}

bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
return (mg_str_to_num_(str, base, val, val_len) > 0);
}

uint8_t mg_toi(char c, int base) {
return (c >= '0' && c <= '9') ? (uint8_t) (c - '0')
: base == 16 ? (c >= 'A' && c <= 'F') ? (uint8_t) (c - '7')
Expand Down
4 changes: 3 additions & 1 deletion mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ struct mg_str mg_str(const char *s);
struct mg_str mg_str_n(const char *s, size_t n);
int mg_casecmp(const char *s1, const char *s2);
int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2); // this one is new
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2);
bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim);

Expand All @@ -869,6 +869,8 @@ unsigned long mg_unhexn(const char *s, size_t len);

uint8_t mg_toi(char c, int base); // base: 16, 10

bool mg_str_to_num(struct mg_str, int base, void *val, size_t val_len);




Expand Down
18 changes: 4 additions & 14 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,11 @@ static int mg_ncasecmp(const char *s1, const char *s2, size_t len) {

bool mg_to_size_t(struct mg_str str, size_t *val);
bool mg_to_size_t(struct mg_str str, size_t *val) {
size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0;
extern size_t mg_str_to_num_(struct mg_str, int, void *, size_t);
size_t i = mg_str_to_num_(str, 10, val, sizeof(size_t));
if (i == 0) return false;
while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++;
if (i < str.len && str.buf[i] == '-') return false;
while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') {
size_t digit = (size_t) (str.buf[i] - '0');
if (result > max2) return false; // Overflow
result *= 10;
if (result > max - digit) return false; // Overflow
result += digit;
i++, ndigits++;
}
while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++;
if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT
if (i != str.len) return false; // Ditto
*val = (size_t) result;
if (i != str.len) return false; // #2322: Content-Length = 1 * DIGIT
return true;
}

Expand Down
74 changes: 74 additions & 0 deletions src/str.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,80 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) {
}
}

size_t mg_str_to_num_(struct mg_str str, int base, void *val, size_t val_len);
size_t mg_str_to_num_(struct mg_str str, int base, void *val, size_t val_len) {
size_t i = 0, ndigits = 0;
uint64_t max = val_len == 1 ? 0xFF
: val_len == 2 ? 0xFFFF
: val_len == 4 ? 0xFFFFFFFF
: (uint64_t) ~0;
uint64_t max2 = max / 10, result = 0;
while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++;
if (base == 0 && str.len >= 2) {
if (str.buf[i] == '0') {
i++;
base = str.buf[i] == 'b' ? 2 : str.buf[i] == 'x' ? 16 : 10;
if (base != 10) ++i;
} else {
base = 10;
}
}
switch (base) {
case 2:
while (i < str.len && (str.buf[i] == '0' || str.buf[i] == '1')) {
uint64_t digit = (uint64_t) (str.buf[i] - '0');
if (result > max2) return 0; // Overflow
result *= 2;
if (result > max - digit) return 0; // Overflow
result += digit;
i++, ndigits++;
}
break;
case 10:
while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') {
uint64_t digit = (uint64_t) (str.buf[i] - '0');
if (result > max2) return 0; // Overflow
result *= 10;
if (result > max - digit) return 0; // Overflow
result += digit;
i++, ndigits++;
}
break;
case 16:
while (i < str.len) {
char c = str.buf[i];
uint64_t digit = (c >= '0' && c <= '9') ? (uint64_t) (c - '0')
: (c >= 'A' && c <= 'F') ? (uint64_t) (c - '7')
: (c >= 'a' && c <= 'f') ? (uint64_t) (c - 'W')
: (uint64_t) ~0;
if (digit == (uint64_t) ~0) break;
if (result > max2) return 0; // Overflow
result *= 16;
if (result > max - digit) return 0; // Overflow
result += digit;
i++, ndigits++;
}
break;
default:
return 0;
}
if (ndigits == 0) return 0; // #2322: Content-Length = 1 * DIGIT
if (val_len == 1) {
*((uint8_t *) val) = (uint8_t) result;
} else if (val_len == 2) {
*((uint16_t *) val) = (uint16_t) result;
} else if (val_len == 4) {
*((uint32_t *) val) = (uint32_t) result;
} else {
*((uint64_t *) val) = (uint64_t) result;
}
return i;
}

bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) {
return (mg_str_to_num_(str, base, val, val_len) > 0);
}

uint8_t mg_toi(char c, int base) {
return (c >= '0' && c <= '9') ? (uint8_t) (c - '0')
: base == 16 ? (c >= 'A' && c <= 'F') ? (uint8_t) (c - '7')
Expand Down
4 changes: 3 additions & 1 deletion src/str.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ struct mg_str mg_str(const char *s);
struct mg_str mg_str_n(const char *s, size_t n);
int mg_casecmp(const char *s1, const char *s2);
int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2); // this one is new
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2);
bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim);

void mg_unhex(const char *buf, size_t len, unsigned char *to);
unsigned long mg_unhexn(const char *s, size_t len);

uint8_t mg_toi(char c, int base); // base: 16, 10

bool mg_str_to_num(struct mg_str, int base, void *val, size_t val_len);

0 comments on commit 0813747

Please sign in to comment.