Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Unified Diff: third_party/inspector_protocol/lib/Parser_cpp.template

Issue 2447323002: [inspector] use own copy of third_party/inspector_protocol (Closed)
Patch Set: updated README.v8 Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/inspector_protocol/lib/Parser_cpp.template
diff --git a/third_party/inspector_protocol/lib/Parser_cpp.template b/third_party/inspector_protocol/lib/Parser_cpp.template
new file mode 100644
index 0000000000000000000000000000000000000000..a103b8228e066e0110bceae8267e1dd070eeb202
--- /dev/null
+++ b/third_party/inspector_protocol/lib/Parser_cpp.template
@@ -0,0 +1,553 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{% for namespace in config.protocol.namespace %}
+namespace {{namespace}} {
+{% endfor %}
+
+namespace {
+
+const int stackLimit = 1000;
+
+enum Token {
+ ObjectBegin,
+ ObjectEnd,
+ ArrayBegin,
+ ArrayEnd,
+ StringLiteral,
+ Number,
+ BoolTrue,
+ BoolFalse,
+ NullToken,
+ ListSeparator,
+ ObjectPairSeparator,
+ InvalidToken,
+};
+
+const char* const nullString = "null";
+const char* const trueString = "true";
+const char* const falseString = "false";
+
+bool isASCII(uint16_t c)
+{
+ return !(c & ~0x7F);
+}
+
+bool isSpaceOrNewLine(uint16_t c)
+{
+ return isASCII(c) && c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
+}
+
+double charactersToDouble(const uint16_t* characters, size_t length, bool* ok)
+{
+ std::vector<char> buffer;
+ buffer.reserve(length + 1);
+ for (size_t i = 0; i < length; ++i) {
+ if (!isASCII(characters[i])) {
+ *ok = false;
+ return 0;
+ }
+ buffer.push_back(static_cast<char>(characters[i]));
+ }
+ buffer.push_back('\0');
+ char* endptr;
+ double result = std::strtod(buffer.data(), &endptr);
+ *ok = !(*endptr);
+ return result;
+}
+
+double charactersToDouble(const uint8_t* characters, size_t length, bool* ok)
+{
+ std::string buffer(reinterpret_cast<const char*>(characters), length);
+ char* endptr;
+ double result = std::strtod(buffer.data(), &endptr);
+ *ok = !(*endptr);
+ return result;
+}
+
+template<typename Char>
+bool parseConstToken(const Char* start, const Char* end, const Char** tokenEnd, const char* token)
+{
+ while (start < end && *token != '\0' && *start++ == *token++) { }
+ if (*token != '\0')
+ return false;
+ *tokenEnd = start;
+ return true;
+}
+
+template<typename Char>
+bool readInt(const Char* start, const Char* end, const Char** tokenEnd, bool canHaveLeadingZeros)
+{
+ if (start == end)
+ return false;
+ bool haveLeadingZero = '0' == *start;
+ int length = 0;
+ while (start < end && '0' <= *start && *start <= '9') {
+ ++start;
+ ++length;
+ }
+ if (!length)
+ return false;
+ if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
+ return false;
+ *tokenEnd = start;
+ return true;
+}
+
+template<typename Char>
+bool parseNumberToken(const Char* start, const Char* end, const Char** tokenEnd)
+{
+ // We just grab the number here. We validate the size in DecodeNumber.
+ // According to RFC4627, a valid number is: [minus] int [frac] [exp]
+ if (start == end)
+ return false;
+ Char c = *start;
+ if ('-' == c)
+ ++start;
+
+ if (!readInt(start, end, &start, false))
+ return false;
+ if (start == end) {
+ *tokenEnd = start;
+ return true;
+ }
+
+ // Optional fraction part
+ c = *start;
+ if ('.' == c) {
+ ++start;
+ if (!readInt(start, end, &start, true))
+ return false;
+ if (start == end) {
+ *tokenEnd = start;
+ return true;
+ }
+ c = *start;
+ }
+
+ // Optional exponent part
+ if ('e' == c || 'E' == c) {
+ ++start;
+ if (start == end)
+ return false;
+ c = *start;
+ if ('-' == c || '+' == c) {
+ ++start;
+ if (start == end)
+ return false;
+ }
+ if (!readInt(start, end, &start, true))
+ return false;
+ }
+
+ *tokenEnd = start;
+ return true;
+}
+
+template<typename Char>
+bool readHexDigits(const Char* start, const Char* end, const Char** tokenEnd, int digits)
+{
+ if (end - start < digits)
+ return false;
+ for (int i = 0; i < digits; ++i) {
+ Char c = *start++;
+ if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
+ return false;
+ }
+ *tokenEnd = start;
+ return true;
+}
+
+template<typename Char>
+bool parseStringToken(const Char* start, const Char* end, const Char** tokenEnd)
+{
+ while (start < end) {
+ Char c = *start++;
+ if ('\\' == c) {
+ if (start == end)
+ return false;
+ c = *start++;
+ // Make sure the escaped char is valid.
+ switch (c) {
+ case 'x':
+ if (!readHexDigits(start, end, &start, 2))
+ return false;
+ break;
+ case 'u':
+ if (!readHexDigits(start, end, &start, 4))
+ return false;
+ break;
+ case '\\':
+ case '/':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ case '"':
+ break;
+ default:
+ return false;
+ }
+ } else if ('"' == c) {
+ *tokenEnd = start;
+ return true;
+ }
+ }
+ return false;
+}
+
+template<typename Char>
+bool skipComment(const Char* start, const Char* end, const Char** commentEnd)
+{
+ if (start == end)
+ return false;
+
+ if (*start != '/' || start + 1 >= end)
+ return false;
+ ++start;
+
+ if (*start == '/') {
+ // Single line comment, read to newline.
+ for (++start; start < end; ++start) {
+ if (*start == '\n' || *start == '\r') {
+ *commentEnd = start + 1;
+ return true;
+ }
+ }
+ *commentEnd = end;
+ // Comment reaches end-of-input, which is fine.
+ return true;
+ }
+
+ if (*start == '*') {
+ Char previous = '\0';
+ // Block comment, read until end marker.
+ for (++start; start < end; previous = *start++) {
+ if (previous == '*' && *start == '/') {
+ *commentEnd = start + 1;
+ return true;
+ }
+ }
+ // Block comment must close before end-of-input.
+ return false;
+ }
+
+ return false;
+}
+
+template<typename Char>
+void skipWhitespaceAndComments(const Char* start, const Char* end, const Char** whitespaceEnd)
+{
+ while (start < end) {
+ if (isSpaceOrNewLine(*start)) {
+ ++start;
+ } else if (*start == '/') {
+ const Char* commentEnd;
+ if (!skipComment(start, end, &commentEnd))
+ break;
+ start = commentEnd;
+ } else {
+ break;
+ }
+ }
+ *whitespaceEnd = start;
+}
+
+template<typename Char>
+Token parseToken(const Char* start, const Char* end, const Char** tokenStart, const Char** tokenEnd)
+{
+ skipWhitespaceAndComments(start, end, tokenStart);
+ start = *tokenStart;
+
+ if (start == end)
+ return InvalidToken;
+
+ switch (*start) {
+ case 'n':
+ if (parseConstToken(start, end, tokenEnd, nullString))
+ return NullToken;
+ break;
+ case 't':
+ if (parseConstToken(start, end, tokenEnd, trueString))
+ return BoolTrue;
+ break;
+ case 'f':
+ if (parseConstToken(start, end, tokenEnd, falseString))
+ return BoolFalse;
+ break;
+ case '[':
+ *tokenEnd = start + 1;
+ return ArrayBegin;
+ case ']':
+ *tokenEnd = start + 1;
+ return ArrayEnd;
+ case ',':
+ *tokenEnd = start + 1;
+ return ListSeparator;
+ case '{':
+ *tokenEnd = start + 1;
+ return ObjectBegin;
+ case '}':
+ *tokenEnd = start + 1;
+ return ObjectEnd;
+ case ':':
+ *tokenEnd = start + 1;
+ return ObjectPairSeparator;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ if (parseNumberToken(start, end, tokenEnd))
+ return Number;
+ break;
+ case '"':
+ if (parseStringToken(start + 1, end, tokenEnd))
+ return StringLiteral;
+ break;
+ }
+ return InvalidToken;
+}
+
+template<typename Char>
+int hexToInt(Char c)
+{
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ DCHECK(false);
+ return 0;
+}
+
+template<typename Char>
+bool decodeString(const Char* start, const Char* end, StringBuilder* output)
+{
+ while (start < end) {
+ uint16_t c = *start++;
+ if ('\\' != c) {
+ output->append(c);
+ continue;
+ }
+ if (start == end)
+ return false;
+ c = *start++;
+
+ if (c == 'x') {
+ // \x is not supported.
+ return false;
+ }
+
+ switch (c) {
+ case '"':
+ case '/':
+ case '\\':
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case 'u':
+ c = (hexToInt(*start) << 12) +
+ (hexToInt(*(start + 1)) << 8) +
+ (hexToInt(*(start + 2)) << 4) +
+ hexToInt(*(start + 3));
+ start += 4;
+ break;
+ default:
+ return false;
+ }
+ output->append(c);
+ }
+ return true;
+}
+
+template<typename Char>
+bool decodeString(const Char* start, const Char* end, String* output)
+{
+ if (start == end) {
+ *output = "";
+ return true;
+ }
+ if (start > end)
+ return false;
+ StringBuilder buffer;
+ StringUtil::builderReserve(buffer, end - start);
+ if (!decodeString(start, end, &buffer))
+ return false;
+ *output = buffer.toString();
+ return true;
+}
+
+template<typename Char>
+std::unique_ptr<Value> buildValue(const Char* start, const Char* end, const Char** valueTokenEnd, int depth)
+{
+ if (depth > stackLimit)
+ return nullptr;
+
+ std::unique_ptr<Value> result;
+ const Char* tokenStart;
+ const Char* tokenEnd;
+ Token token = parseToken(start, end, &tokenStart, &tokenEnd);
+ switch (token) {
+ case InvalidToken:
+ return nullptr;
+ case NullToken:
+ result = Value::null();
+ break;
+ case BoolTrue:
+ result = FundamentalValue::create(true);
+ break;
+ case BoolFalse:
+ result = FundamentalValue::create(false);
+ break;
+ case Number: {
+ bool ok;
+ double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok);
+ if (!ok)
+ return nullptr;
+ int number = static_cast<int>(value);
+ if (number == value)
+ result = FundamentalValue::create(number);
+ else
+ result = FundamentalValue::create(value);
+ break;
+ }
+ case StringLiteral: {
+ String value;
+ bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value);
+ if (!ok)
+ return nullptr;
+ result = StringValue::create(value);
+ break;
+ }
+ case ArrayBegin: {
+ std::unique_ptr<ListValue> array = ListValue::create();
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ while (token != ArrayEnd) {
+ std::unique_ptr<Value> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
+ if (!arrayNode)
+ return nullptr;
+ array->pushValue(std::move(arrayNode));
+
+ // After a list value, we expect a comma or the end of the list.
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == ListSeparator) {
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == ArrayEnd)
+ return nullptr;
+ } else if (token != ArrayEnd) {
+ // Unexpected value after list value. Bail out.
+ return nullptr;
+ }
+ }
+ if (token != ArrayEnd)
+ return nullptr;
+ result = std::move(array);
+ break;
+ }
+ case ObjectBegin: {
+ std::unique_ptr<DictionaryValue> object = DictionaryValue::create();
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ while (token != ObjectEnd) {
+ if (token != StringLiteral)
+ return nullptr;
+ String key;
+ if (!decodeString(tokenStart + 1, tokenEnd - 1, &key))
+ return nullptr;
+ start = tokenEnd;
+
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token != ObjectPairSeparator)
+ return nullptr;
+ start = tokenEnd;
+
+ std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, depth + 1);
+ if (!value)
+ return nullptr;
+ object->setValue(key, std::move(value));
+ start = tokenEnd;
+
+ // After a key/value pair, we expect a comma or the end of the
+ // object.
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == ListSeparator) {
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == ObjectEnd)
+ return nullptr;
+ } else if (token != ObjectEnd) {
+ // Unexpected value after last object value. Bail out.
+ return nullptr;
+ }
+ }
+ if (token != ObjectEnd)
+ return nullptr;
+ result = std::move(object);
+ break;
+ }
+
+ default:
+ // We got a token that's not a value.
+ return nullptr;
+ }
+
+ skipWhitespaceAndComments(tokenEnd, end, valueTokenEnd);
+ return result;
+}
+
+template<typename Char>
+std::unique_ptr<Value> parseJSONInternal(const Char* start, unsigned length)
+{
+ const Char* end = start + length;
+ const Char *tokenEnd;
+ std::unique_ptr<Value> value = buildValue(start, end, &tokenEnd, 0);
+ if (!value || tokenEnd != end)
+ return nullptr;
+ return value;
+}
+
+} // anonymous namespace
+
+std::unique_ptr<Value> parseJSON(const uint16_t* characters, unsigned length)
+{
+ return parseJSONInternal<uint16_t>(characters, length);
+}
+
+std::unique_ptr<Value> parseJSON(const uint8_t* characters, unsigned length)
+{
+ return parseJSONInternal<uint8_t>(characters, length);
+}
+
+{% for namespace in config.protocol.namespace %}
+} // namespace {{namespace}}
+{% endfor %}

Powered by Google App Engine
This is Rietveld 408576698