mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-23 18:49:01 +08:00
commit
c911c9ad19
127
mongoose.c
127
mongoose.c
@ -2385,7 +2385,7 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
|
||||
if (src[i] == '%') {
|
||||
// Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len
|
||||
if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) {
|
||||
mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]);
|
||||
mg_str_to_num(mg_str_n(src + i + 1, 2), 16, &dst[j], sizeof(uint8_t));
|
||||
i += 2;
|
||||
} else {
|
||||
return -1;
|
||||
@ -3204,9 +3204,10 @@ static int skip_chunk(const char *buf, int len, int *pl, int *dl) {
|
||||
if (i == 0) return -1; // Error, no length specified
|
||||
if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big
|
||||
if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error
|
||||
n = (int) mg_unhexn(buf, (size_t) i); // Decode chunk length
|
||||
if (n < 0) return -1; // Error
|
||||
if (n > len - i - 4) return 0; // Chunk not yet fully buffered
|
||||
if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false)
|
||||
return -1; // Decode chunk length, overflow
|
||||
if (n < 0) return -1; // Error. TODO(): some checks now redundant
|
||||
if (n > len - i - 4) return 0; // Chunk not yet fully buffered
|
||||
if (buf[i + n + 2] != '\r' || buf[i + n + 3] != '\n') return -1; // Error
|
||||
*pl = i + 2, *dl = n;
|
||||
return i + 2 + n + 2;
|
||||
@ -3715,12 +3716,12 @@ bool mg_json_unescape(struct mg_str s, char *to, size_t n) {
|
||||
size_t i, j;
|
||||
for (i = 0, j = 0; i < s.len && j < n; i++, j++) {
|
||||
if (s.buf[i] == '\\' && i + 5 < s.len && s.buf[i + 1] == 'u') {
|
||||
// \uXXXX escape. We could process a simple one-byte chars
|
||||
// \u00xx from the ASCII range. More complex chars would require
|
||||
// dragging in a UTF8 library, which is too much for us
|
||||
if (s.buf[i + 2] != '0' || s.buf[i + 3] != '0') return false; // Give up
|
||||
((unsigned char *) to)[j] = (unsigned char) mg_unhexn(s.buf + i + 4, 2);
|
||||
|
||||
// \uXXXX escape. We process simple one-byte chars \u00xx within ASCII
|
||||
// range. More complex chars would require dragging in a UTF8 library,
|
||||
// which is too much for us
|
||||
if (mg_str_to_num(mg_str_n(s.buf + i + 2, 4), 16, &to[j],
|
||||
sizeof(uint8_t)) == false)
|
||||
return false;
|
||||
i += 5;
|
||||
} else if (s.buf[i] == '\\' && i + 1 < s.len) {
|
||||
char c = json_esc(s.buf[i + 1], 0);
|
||||
@ -3767,7 +3768,11 @@ char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
|
||||
int len = 0, off = mg_json_get(json, path, &len);
|
||||
if (off >= 0 && json.buf[off] == '"' && len > 1 &&
|
||||
(result = (char *) calloc(1, (size_t) len / 2)) != NULL) {
|
||||
mg_unhex(json.buf + off + 1, (size_t) (len - 2), (uint8_t *) result);
|
||||
int i;
|
||||
for (i = 0; i < len - 2; i += 2) {
|
||||
mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1],
|
||||
sizeof(uint8_t));
|
||||
}
|
||||
result[len / 2 - 1] = '\0';
|
||||
if (slen != NULL) *slen = len / 2 - 1;
|
||||
}
|
||||
@ -4654,7 +4659,7 @@ static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
|
||||
|
||||
static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
|
||||
uint8_t data[4] = {0, 0, 0, 0};
|
||||
size_t i, num_dots = 0;
|
||||
size_t i, num_dots = 0; // TODO(): refactor to mg_span() + mg_str_num()
|
||||
for (i = 0; i < str.len; i++) {
|
||||
if (str.buf[i] >= '0' && str.buf[i] <= '9') {
|
||||
int octet = data[num_dots] * 10 + (str.buf[i] - '0');
|
||||
@ -4700,10 +4705,10 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
||||
if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
|
||||
(str.buf[i] >= 'a' && str.buf[i] <= 'f') ||
|
||||
(str.buf[i] >= 'A' && str.buf[i] <= 'F')) {
|
||||
unsigned long val;
|
||||
unsigned long val; // TODO(): This loops, refactor
|
||||
if (i > j + 3) return false;
|
||||
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j]));
|
||||
val = mg_unhexn(&str.buf[j], i - j + 1);
|
||||
mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val));
|
||||
addr->ip[n] = (uint8_t) ((val >> 8) & 255);
|
||||
addr->ip[n + 1] = (uint8_t) (val & 255);
|
||||
} else if (str.buf[i] == ':') {
|
||||
@ -4716,12 +4721,9 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
||||
}
|
||||
if (n > 14) return false;
|
||||
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
|
||||
} else if (str.buf[i] == '%') { // Scope ID
|
||||
for (i = i + 1; i < str.len; i++) {
|
||||
if (str.buf[i] < '0' || str.buf[i] > '9') return false;
|
||||
addr->scope_id = (uint8_t) (addr->scope_id * 10);
|
||||
addr->scope_id = (uint8_t) (addr->scope_id + (str.buf[i] - '0'));
|
||||
}
|
||||
} else if (str.buf[i] == '%') { // Scope ID, last in string
|
||||
return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
|
||||
&addr->scope_id, sizeof(uint8_t));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -8119,25 +8121,74 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) {
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
: (c >= 'a' && c <= 'f') ? (uint8_t) (c - 'W')
|
||||
: (uint8_t) ~0
|
||||
: (uint8_t) ~0;
|
||||
}
|
||||
|
||||
unsigned long mg_unhexn(const char *s, size_t len) {
|
||||
unsigned long i = 0, v = 0;
|
||||
for (i = 0; i < len; i++) v <<= 4, v |= mg_toi(((char *) s)[i], 16);
|
||||
return v;
|
||||
}
|
||||
|
||||
void mg_unhex(const char *buf, size_t len, unsigned char *to) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; i += 2) {
|
||||
to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
|
||||
bool 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 == sizeof(uint8_t) ? 0xFF
|
||||
: val_len == sizeof(uint16_t) ? 0xFFFF
|
||||
: val_len == sizeof(uint32_t) ? 0xFFFFFFFF
|
||||
: (uint64_t) ~0;
|
||||
uint64_t result = 0;
|
||||
if (max == (uint64_t) ~0 && val_len != sizeof(uint64_t)) return false;
|
||||
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 > max/2) return false; // Overflow
|
||||
result *= 2;
|
||||
if (result > max - digit) return false; // 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 > max/10) return false; // Overflow
|
||||
result *= 10;
|
||||
if (result > max - digit) return false; // 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 > max/16) return false; // Overflow
|
||||
result *= 16;
|
||||
if (result > max - digit) return false; // Overflow
|
||||
result += digit;
|
||||
i++, ndigits++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (ndigits == 0) return false;
|
||||
if (i != str.len) return false;
|
||||
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 true;
|
||||
}
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
|
@ -860,14 +860,11 @@ 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);
|
||||
|
||||
|
||||
|
||||
|
@ -169,7 +169,7 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
|
||||
if (src[i] == '%') {
|
||||
// Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len
|
||||
if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) {
|
||||
mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]);
|
||||
mg_str_to_num(mg_str_n(src + i + 1, 2), 16, &dst[j], sizeof(uint8_t));
|
||||
i += 2;
|
||||
} else {
|
||||
return -1;
|
||||
@ -988,9 +988,10 @@ static int skip_chunk(const char *buf, int len, int *pl, int *dl) {
|
||||
if (i == 0) return -1; // Error, no length specified
|
||||
if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big
|
||||
if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error
|
||||
n = (int) mg_unhexn(buf, (size_t) i); // Decode chunk length
|
||||
if (n < 0) return -1; // Error
|
||||
if (n > len - i - 4) return 0; // Chunk not yet fully buffered
|
||||
if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false)
|
||||
return -1; // Decode chunk length, overflow
|
||||
if (n < 0) return -1; // Error. TODO(): some checks now redundant
|
||||
if (n > len - i - 4) return 0; // Chunk not yet fully buffered
|
||||
if (buf[i + n + 2] != '\r' || buf[i + n + 3] != '\n') return -1; // Error
|
||||
*pl = i + 2, *dl = n;
|
||||
return i + 2 + n + 2;
|
||||
|
20
src/json.c
20
src/json.c
@ -1,6 +1,6 @@
|
||||
#include "json.h"
|
||||
#include "base64.h"
|
||||
#include "fmt.h"
|
||||
#include "json.h"
|
||||
|
||||
static const char *escapeseq(int esc) {
|
||||
return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\"";
|
||||
@ -295,12 +295,12 @@ bool mg_json_unescape(struct mg_str s, char *to, size_t n) {
|
||||
size_t i, j;
|
||||
for (i = 0, j = 0; i < s.len && j < n; i++, j++) {
|
||||
if (s.buf[i] == '\\' && i + 5 < s.len && s.buf[i + 1] == 'u') {
|
||||
// \uXXXX escape. We could process a simple one-byte chars
|
||||
// \u00xx from the ASCII range. More complex chars would require
|
||||
// dragging in a UTF8 library, which is too much for us
|
||||
if (s.buf[i + 2] != '0' || s.buf[i + 3] != '0') return false; // Give up
|
||||
((unsigned char *) to)[j] = (unsigned char) mg_unhexn(s.buf + i + 4, 2);
|
||||
|
||||
// \uXXXX escape. We process simple one-byte chars \u00xx within ASCII
|
||||
// range. More complex chars would require dragging in a UTF8 library,
|
||||
// which is too much for us
|
||||
if (mg_str_to_num(mg_str_n(s.buf + i + 2, 4), 16, &to[j],
|
||||
sizeof(uint8_t)) == false)
|
||||
return false;
|
||||
i += 5;
|
||||
} else if (s.buf[i] == '\\' && i + 1 < s.len) {
|
||||
char c = json_esc(s.buf[i + 1], 0);
|
||||
@ -347,7 +347,11 @@ char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
|
||||
int len = 0, off = mg_json_get(json, path, &len);
|
||||
if (off >= 0 && json.buf[off] == '"' && len > 1 &&
|
||||
(result = (char *) calloc(1, (size_t) len / 2)) != NULL) {
|
||||
mg_unhex(json.buf + off + 1, (size_t) (len - 2), (uint8_t *) result);
|
||||
int i;
|
||||
for (i = 0; i < len - 2; i += 2) {
|
||||
mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1],
|
||||
sizeof(uint8_t));
|
||||
}
|
||||
result[len / 2 - 1] = '\0';
|
||||
if (slen != NULL) *slen = len / 2 - 1;
|
||||
}
|
||||
|
15
src/net.c
15
src/net.c
@ -1,7 +1,7 @@
|
||||
#include "net.h"
|
||||
#include "dns.h"
|
||||
#include "fmt.h"
|
||||
#include "log.h"
|
||||
#include "net.h"
|
||||
#include "printf.h"
|
||||
#include "profile.h"
|
||||
#include "timer.h"
|
||||
@ -85,10 +85,10 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
||||
if ((str.buf[i] >= '0' && str.buf[i] <= '9') ||
|
||||
(str.buf[i] >= 'a' && str.buf[i] <= 'f') ||
|
||||
(str.buf[i] >= 'A' && str.buf[i] <= 'F')) {
|
||||
unsigned long val;
|
||||
unsigned long val; // TODO(): This loops on chars, refactor
|
||||
if (i > j + 3) return false;
|
||||
// MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j]));
|
||||
val = mg_unhexn(&str.buf[j], i - j + 1);
|
||||
mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val));
|
||||
addr->ip[n] = (uint8_t) ((val >> 8) & 255);
|
||||
addr->ip[n + 1] = (uint8_t) (val & 255);
|
||||
} else if (str.buf[i] == ':') {
|
||||
@ -101,12 +101,9 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
||||
}
|
||||
if (n > 14) return false;
|
||||
addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
|
||||
} else if (str.buf[i] == '%') { // Scope ID
|
||||
for (i = i + 1; i < str.len; i++) {
|
||||
if (str.buf[i] < '0' || str.buf[i] > '9') return false;
|
||||
addr->scope_id = (uint8_t) (addr->scope_id * 10);
|
||||
addr->scope_id = (uint8_t) (addr->scope_id + (str.buf[i] - '0'));
|
||||
}
|
||||
} else if (str.buf[i] == '%') { // Scope ID, last in string
|
||||
return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10,
|
||||
&addr->scope_id, sizeof(uint8_t));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
85
src/str.c
85
src/str.c
@ -96,23 +96,72 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) {
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
: (c >= 'a' && c <= 'f') ? (uint8_t) (c - 'W')
|
||||
: (uint8_t) ~0
|
||||
: (uint8_t) ~0;
|
||||
}
|
||||
|
||||
unsigned long mg_unhexn(const char *s, size_t len) {
|
||||
unsigned long i = 0, v = 0;
|
||||
for (i = 0; i < len; i++) v <<= 4, v |= mg_toi(((char *) s)[i], 16);
|
||||
return v;
|
||||
}
|
||||
|
||||
void mg_unhex(const char *buf, size_t len, unsigned char *to) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; i += 2) {
|
||||
to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
|
||||
bool 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 == sizeof(uint8_t) ? 0xFF
|
||||
: val_len == sizeof(uint16_t) ? 0xFFFF
|
||||
: val_len == sizeof(uint32_t) ? 0xFFFFFFFF
|
||||
: (uint64_t) ~0;
|
||||
uint64_t result = 0;
|
||||
if (max == (uint64_t) ~0 && val_len != sizeof(uint64_t)) return false;
|
||||
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 > max/2) return false; // Overflow
|
||||
result *= 2;
|
||||
if (result > max - digit) return false; // 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 > max/10) return false; // Overflow
|
||||
result *= 10;
|
||||
if (result > max - digit) return false; // 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 > max/16) return false; // Overflow
|
||||
result *= 16;
|
||||
if (result > max - digit) return false; // Overflow
|
||||
result += digit;
|
||||
i++, ndigits++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (ndigits == 0) return false;
|
||||
if (i != str.len) return false;
|
||||
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 true;
|
||||
}
|
||||
|
@ -15,11 +15,8 @@ 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);
|
||||
|
@ -1878,17 +1878,6 @@ static void test_str(void) {
|
||||
ASSERT(mg_strcasecmp(mg_str("b"), mg_str("A")) > 0);
|
||||
ASSERT(mg_strcasecmp(mg_str("hi"), mg_str("HI")) == 0);
|
||||
|
||||
ASSERT(mg_toi('0', 10) == 0);
|
||||
ASSERT(mg_toi('9', 10) == 9);
|
||||
ASSERT(mg_toi('A', 10) == (uint8_t) ~0);
|
||||
ASSERT(mg_toi('0', 16) == 0);
|
||||
ASSERT(mg_toi('9', 16) == 9);
|
||||
ASSERT(mg_toi('A', 16) == 10);
|
||||
ASSERT(mg_toi('a', 16) == 10);
|
||||
ASSERT(mg_toi('f', 16) == 15);
|
||||
ASSERT(mg_toi('F', 16) == 15);
|
||||
ASSERT(mg_toi('G', 16) == (uint8_t) ~0);
|
||||
|
||||
{
|
||||
ASSERT(chkdbl(mg_str_n("1.23", 3), 1.2));
|
||||
ASSERT(chkdbl(mg_str("1.23 "), 1.23));
|
||||
@ -2277,6 +2266,9 @@ static void test_util(void) {
|
||||
|
||||
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
|
||||
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
|
||||
ASSERT(mg_url_decode("a=%1", 4, buf, sizeof(buf), 0) < 0);
|
||||
ASSERT(mg_url_decode("a=%12", 5, buf, sizeof(buf), 0) == 3 && buf[2] == 0x12);
|
||||
ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 && buf[2] == 0x12 && buf[3] == '3');
|
||||
|
||||
memset(a.ip, 0xaa, sizeof(a.ip));
|
||||
ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
|
||||
@ -2331,6 +2323,70 @@ static void test_util(void) {
|
||||
ASSERT(mg_to_size_t(mg_str(buf), &val) && val == max);
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t val, max = (uint64_t) -1;
|
||||
ASSERT(mg_str_to_num(mg_str("0"), 10, &val, sizeof(uint64_t)) && val == 0);
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint64_t)) && val == 123);
|
||||
ASSERT(mg_str_to_num(mg_str(" 123"), 10, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str("123 "), 10, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str(""), 10, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str(" 123x"), 10, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str("-"), 10, &val, sizeof(uint64_t)) == false);
|
||||
mg_snprintf(buf, sizeof(buf), "%llu", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint64_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("0"), 2, &val, sizeof(uint64_t)) && val == 0);
|
||||
ASSERT(mg_str_to_num(mg_str("1"), 2, &val, sizeof(uint64_t)) && val == 1);
|
||||
ASSERT(mg_str_to_num(mg_str("0123"), 2, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 2, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint64_t)) && val == 123);
|
||||
ASSERT(mg_str_to_num(mg_str("1111111111111111111111111111111111111111111111111111111111111111"), 2, &val, sizeof(uint64_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("0"), 16, &val, sizeof(uint64_t)) && val == 0);
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint64_t)) && val == 0x123);
|
||||
ASSERT(mg_str_to_num(mg_str("def"), 16, &val, sizeof(uint64_t)) && val == 0xdef);
|
||||
ASSERT(mg_str_to_num(mg_str("defg"), 16, &val, sizeof(uint64_t)) == false);
|
||||
mg_snprintf(buf, sizeof(buf), "%llx", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint64_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("0x123"), 0, &val, sizeof(uint64_t)) && val == 0x123);
|
||||
ASSERT(mg_str_to_num(mg_str("0b123"), 0, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str("0c123"), 0, &val, sizeof(uint64_t)) == false);
|
||||
ASSERT(mg_str_to_num(mg_str("0b101"), 0, &val, sizeof(uint64_t)) && val == 5);
|
||||
ASSERT(mg_str_to_num(mg_str("0123"), 0, &val, sizeof(uint64_t)) && val == 123);
|
||||
}
|
||||
{
|
||||
uint32_t val, max = (uint32_t) -1;
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint32_t)) && val == 123);
|
||||
mg_snprintf(buf, sizeof(buf), "%lu", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint32_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint32_t)) && val == 123);
|
||||
ASSERT(mg_str_to_num(mg_str("11111111111111111111111111111111"), 2, &val, sizeof(uint32_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("0"), 16, &val, sizeof(uint32_t)) && val == 0);
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint32_t)) && val == 0x123);
|
||||
mg_snprintf(buf, sizeof(buf), "%lx", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint32_t)) && val == max);
|
||||
}
|
||||
{
|
||||
uint16_t val, max = (uint16_t) -1;
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint16_t)) && val == 123);
|
||||
mg_snprintf(buf, sizeof(buf), "%u", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint16_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint16_t)) && val == 123);
|
||||
ASSERT(mg_str_to_num(mg_str("1111111111111111"), 2, &val, sizeof(uint16_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint16_t)) && val == 0x123);
|
||||
mg_snprintf(buf, sizeof(buf), "%x", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint16_t)) && val == max);
|
||||
}
|
||||
{
|
||||
uint8_t val, max = (uint8_t) -1;
|
||||
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint8_t)) && val == 123);
|
||||
mg_snprintf(buf, sizeof(buf), "%u", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint8_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint8_t)) && val == 123);
|
||||
ASSERT(mg_str_to_num(mg_str("11111111"), 2, &val, sizeof(uint8_t)) && val == max);
|
||||
ASSERT(mg_str_to_num(mg_str("12"), 16, &val, sizeof(uint8_t)) && val == 0x12);
|
||||
mg_snprintf(buf, sizeof(buf), "%x", max);
|
||||
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint8_t)) && val == max);
|
||||
}
|
||||
|
||||
{
|
||||
size_t i;
|
||||
memset(buf, ' ', sizeof(buf));
|
||||
@ -2927,6 +2983,17 @@ static void test_json(void) {
|
||||
ASSERT(mg_json_get(json, "$.a1", &n) == MG_JSON_NOT_FOUND);
|
||||
ASSERT(mg_json_get(json, "$.c", &n) == 19 && n == 1);
|
||||
|
||||
{
|
||||
char to[4], expect[4] = {0,0,0,0};
|
||||
memset(to, 0, sizeof(to));
|
||||
ASSERT(mg_json_unescape(mg_str("\\u0000"), to, 4) && memcmp(to, expect, 4) == 0);
|
||||
to[0] = 0;
|
||||
expect[0] = (char) 0xff;
|
||||
ASSERT(mg_json_unescape(mg_str("\\u00ff"), to, 4) && memcmp(to, expect, 4) == 0);
|
||||
ASSERT(!mg_json_unescape(mg_str("\\u0100"), to, 4));
|
||||
ASSERT(!mg_json_unescape(mg_str("\\u1000"), to, 4));
|
||||
}
|
||||
|
||||
{
|
||||
double d = 0;
|
||||
bool b = false;
|
||||
|
Loading…
Reference in New Issue
Block a user