Skip to content

Commit

Permalink
parser: rework ReadHexNumber function
Browse files Browse the repository at this point in the history
  • Loading branch information
belochub committed Jun 23, 2017
1 parent a57c662 commit 314c0de
Showing 1 changed file with 67 additions and 26 deletions.
93 changes: 67 additions & 26 deletions src/jsrs_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,11 @@ MaybeLocal<Value> ParseString(Isolate* isolate,
return result_str;
}

static unsigned int ReadHexNumber(const char* str, size_t len, bool* ok);
static uint32_t ReadHexNumber(const char* str,
size_t required_len,
bool is_limited,
size_t* len,
bool* ok);

// Parses a Unicode escape sequence after the '\u' part and returns it's
// code point value. Supports surrogate pairs. Total size of escape
Expand All @@ -565,26 +569,22 @@ static uint32_t ReadUnicodeEscapeSequence(Isolate* isolate,
uint32_t result = 0xFFFD;

if (isxdigit(str[0])) {
result = ReadHexNumber(str, 4, ok);
result = ReadHexNumber(str, 4, true, nullptr, ok);
if (!*ok) {
THROW_EXCEPTION(SyntaxError, "Invalid Unicode escape sequence");
return 0xFFFD;
}
*size = 4;
} else if (str[0] == '{') {
size_t hex_size;
for (hex_size = 1;
str[hex_size + 1] != '}';
hex_size++) {
if (str[hex_size + 1] == '\0') {
THROW_EXCEPTION(SyntaxError, "Invalid Unicode code point escape");
*ok = false;
return 0xFFFD;
}
}
result = ReadHexNumber(str + 1, hex_size, ok);
if (!*ok) {
result = ReadHexNumber(str + 1, 0, false, &hex_size, ok);
if (!*ok || result > 0x10FFFF) {
THROW_EXCEPTION(SyntaxError, "Invalid Unicode escape sequence");
return 0xFFFD;
}
*size = hex_size + 2;
} else {
THROW_EXCEPTION(SyntaxError, "Expected Unicode code point escape");
THROW_EXCEPTION(SyntaxError, "Expected Unicode escape sequence");
*ok = false;
}

Expand Down Expand Up @@ -645,7 +645,8 @@ static bool GetControlChar(Isolate* isolate,
}

case 'x': {
*write_to = static_cast<char>(ReadHexNumber(str + 1, 2, &ok));
*write_to = static_cast<char>(ReadHexNumber(str + 1, 2, true,
nullptr, &ok));
if (!ok) {
THROW_EXCEPTION(SyntaxError, "Invalid hexadecimal escape sequence");
return false;
Expand Down Expand Up @@ -676,19 +677,59 @@ static bool GetControlChar(Isolate* isolate,
return true;
}

// Parses a hexadecimal number into unsigned int. Whether the parsing
// was successful is determined by the value of `ok`.
static unsigned int ReadHexNumber(const char* str, size_t len, bool* ok) {
char t[6];
char* end;
strncpy(t, str, len);
t[len] = '\0';
unsigned int result = strtol(t, &end, 16);
if (end - t != static_cast<ptrdiff_t>(len)) {
*ok = false;
// Parses a hexadecimal number with maximal length of max_len (if is_limited true)
// into uint32_t. Whether the parsing was successful is determined by the value
// of `ok`. Resulting size of the value will be outputted in len (if is_limited is
// false).
static uint32_t ReadHexNumber(const char* str,
size_t required_len,
bool is_limited,
size_t* len,
bool* ok) {
static const int8_t xdigit_table[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // '0' to '9'
-1, -1, -1, -1, -1, -1, -1, // 0x3A to 0x40
10, 11, 12, 13, 14, 15, // 'A' to 'F'
// 'G' to 'Z':
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, // 0x5B to 0x60
10, 11, 12, 13, 14, 15, // 'a' to 'f'
};

uint32_t result = 0;
uint64_t current_value = 0;
size_t current_length = 0;
char current_digit;

*ok = true;

while (isxdigit(str[current_length])) {
current_digit = str[current_length];
current_length++;
current_value *= 16;
current_value += xdigit_table[current_digit - '0'];
if (current_value > UINT32_MAX) {
*ok = false;
return result;
}
result = current_value;
if (is_limited && current_length == required_len) {
break;
}
}

if (is_limited) {
if (current_length < required_len) {
*ok = false;
}
} else {
*ok = true;
if (current_length == 0) {
*ok = false;
}
*len = current_length;
}

return result;
}

Expand Down

0 comments on commit 314c0de

Please sign in to comment.