1f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// Copyright 2016 the V8 project authors. All rights reserved. 2f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch// found in the LICENSE file. 4f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 5f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#include "src/inspector/v8-regex.h" 6f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 7f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#include <limits.h> 8f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 9f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#include "src/inspector/string-util.h" 10f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#include "src/inspector/v8-inspector-impl.h" 11f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 12f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch#include "include/v8-inspector.h" 13f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 14f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochnamespace v8_inspector { 15f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 16f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben MurdochV8Regex::V8Regex(V8InspectorImpl* inspector, const String16& pattern, 17f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch bool caseSensitive, bool multiline) 18f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch : m_inspector(inspector) { 19f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Isolate* isolate = m_inspector->isolate(); 20f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::HandleScope handleScope(isolate); 21f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Context> context = m_inspector->regexContext(); 22f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Context::Scope contextScope(context); 23f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::TryCatch tryCatch(isolate); 24f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 25f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch unsigned flags = v8::RegExp::kNone; 26f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (!caseSensitive) flags |= v8::RegExp::kIgnoreCase; 27f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (multiline) flags |= v8::RegExp::kMultiline; 28f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 29f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::RegExp> regex; 30f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (v8::RegExp::New(context, toV8String(isolate, pattern), 31f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch static_cast<v8::RegExp::Flags>(flags)) 32f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch .ToLocal(®ex)) 33f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch m_regex.Reset(isolate, regex); 34f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch else if (tryCatch.HasCaught()) 35f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch m_errorMessage = toProtocolString(tryCatch.Message()->Get()); 36f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch else 37f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch m_errorMessage = "Internal error"; 38f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch} 39f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 40f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdochint V8Regex::match(const String16& string, int startFrom, 41f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch int* matchLength) const { 42f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (matchLength) *matchLength = 0; 43f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 44f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (m_regex.IsEmpty() || string.isEmpty()) return -1; 45f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 46f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // v8 strings are limited to int. 47f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (string.length() > INT_MAX) return -1; 48f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 49f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Isolate* isolate = m_inspector->isolate(); 50f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::HandleScope handleScope(isolate); 51f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Context> context = m_inspector->regexContext(); 52f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::MicrotasksScope microtasks(isolate, 53f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::MicrotasksScope::kDoNotRunMicrotasks); 54f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::TryCatch tryCatch(isolate); 55f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 56f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::RegExp> regex = m_regex.Get(isolate); 57f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Value> exec; 58f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (!regex->Get(context, toV8StringInternalized(isolate, "exec")) 59f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch .ToLocal(&exec)) 60f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch return -1; 61f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Value> argv[] = { 62f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch toV8String(isolate, string.substring(startFrom))}; 63f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Value> returnValue; 64f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (!exec.As<v8::Function>() 65f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch ->Call(context, regex, arraysize(argv), argv) 66f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch .ToLocal(&returnValue)) 67f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch return -1; 68f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 69f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // RegExp#exec returns null if there's no match, otherwise it returns an 70f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // Array of strings with the first being the whole match string and others 71f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // being subgroups. The Array also has some random properties tacked on like 72f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // "index" which is the offset of the match. 73f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // 74f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec 75f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 76f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch DCHECK(!returnValue.IsEmpty()); 77f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (!returnValue->IsArray()) return -1; 78f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 79f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Array> result = returnValue.As<v8::Array>(); 80f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Value> matchOffset; 81f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (!result->Get(context, toV8StringInternalized(isolate, "index")) 82f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch .ToLocal(&matchOffset)) 83f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch return -1; 84f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (matchLength) { 85f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch v8::Local<v8::Value> match; 86f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (!result->Get(context, 0).ToLocal(&match)) return -1; 87f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch *matchLength = match.As<v8::String>()->Length(); 88f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch } 89f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 90f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch return matchOffset.As<v8::Int32>()->Value() + startFrom; 91f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch} 92f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch 93f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch} // namespace v8_inspector 94