15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/inspector/ContentSearchUtils.h"
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
33197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "bindings/core/v8/ScriptRegexp.h"
34c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "wtf/Vector.h"
35c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)#include "wtf/text/StringBuilder.h"
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace ContentSearchUtils {
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace {
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// This should be kept the same as the one in front-end/utilities.js
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const char regexSpecialCharacters[] = "[](){}+-*.,?\\^$|";
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static String createSearchRegexSource(const String& text)
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
47c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)    StringBuilder result;
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String specials(regexSpecialCharacters);
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < text.length(); i++) {
5106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        if (specials.find(text[i]) != kNotFound)
529e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)            result.append('\\');
53591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        result.append(text[i]);
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
56c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)    return result.toString();
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
59a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)static Vector<pair<int, String> > getScriptRegexpMatchesByLines(const ScriptRegexp* regex, const String& text)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<pair<int, String> > result;
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (text.isEmpty())
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return result;
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
65591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    OwnPtr<Vector<unsigned> > endings(lineEndings(text));
66591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    unsigned size = endings->size();
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned start = 0;
68591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    for (unsigned lineNumber = 0; lineNumber < size; ++lineNumber) {
69591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        unsigned lineEnd = endings->at(lineNumber);
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        String line = text.substring(start, lineEnd - start);
71926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (line.endsWith('\r'))
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            line = line.left(line.length() - 1);
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int matchLength;
7553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if (regex->match(line, 0, &matchLength) != -1)
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.append(pair<int, String>(lineNumber, line));
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
78926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        start = lineEnd + 1;
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
83926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static PassRefPtr<TypeBuilder::Page::SearchMatch> buildObjectForSearchMatch(int lineNumber, const String& lineContent)
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return TypeBuilder::Page::SearchMatch::create()
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        .setLineNumber(lineNumber)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        .setLineContent(lineContent)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        .release();
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
91a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)PassOwnPtr<ScriptRegexp> createSearchRegex(const String& query, bool caseSensitive, bool isRegex)
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String regexSource = isRegex ? query : createSearchRegexSource(query);
94a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    return adoptPtr(new ScriptRegexp(regexSource, caseSensitive ? TextCaseSensitive : TextCaseInsensitive));
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex)
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > result = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create();
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
101a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    OwnPtr<ScriptRegexp> regex = ContentSearchUtils::createSearchRegex(query, caseSensitive, isRegex);
102a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    Vector<pair<int, String> > matches = getScriptRegexpMatchesByLines(regex.get(), text);
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Vector<pair<int, String> >::const_iterator it = matches.begin(); it != matches.end(); ++it)
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result->addItem(buildObjectForSearchMatch(it->first, it->second));
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1105267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)static String findMagicComment(const String& content, const String& name, MagicCommentType commentType, bool* deprecated = 0)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    ASSERT(name.find("=") == kNotFound);
1135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    if (deprecated)
1145267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        *deprecated = false;
115d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
116d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    unsigned length = content.length();
117d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    unsigned nameLength = name.length();
118d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
119d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t pos = length;
120d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t equalSignPos = 0;
121d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t closingCommentPos = 0;
122d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    while (true) {
123d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        pos = content.reverseFind(name, pos);
124d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (pos == kNotFound)
125d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return String();
126d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
127d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        // Check for a /\/[\/*][@#][ \t]/ regexp (length of 4) before found name.
128d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (pos < 4)
129d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return String();
130d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        pos -= 4;
131d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (content[pos] != '/')
132d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            continue;
133d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if ((content[pos + 1] != '/' || commentType != JavaScriptMagicComment)
134d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            && (content[pos + 1] != '*' || commentType != CSSMagicComment))
135d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            continue;
136d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (content[pos + 2] != '#' && content[pos + 2] != '@')
137d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            continue;
138d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (content[pos + 3] != ' ' && content[pos + 3] != '\t')
139d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            continue;
140d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        equalSignPos = pos + 4 + nameLength;
141d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (equalSignPos < length && content[equalSignPos] != '=')
142d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            continue;
143d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (commentType == CSSMagicComment) {
144d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            closingCommentPos = content.find("*/", equalSignPos + 1);
145d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            if (closingCommentPos == kNotFound)
146d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                return String();
147d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
148d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
14981a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)        break;
15081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    }
15153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
152d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (deprecated && content[pos + 2] == '@')
153d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        *deprecated = true;
154d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
155d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ASSERT(equalSignPos);
156d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ASSERT(commentType != CSSMagicComment || closingCommentPos);
157d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t urlPos = equalSignPos + 1;
158d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    String match = commentType == CSSMagicComment
159d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        ? content.substring(urlPos, closingCommentPos - urlPos)
160d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        : content.substring(urlPos);
161f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
162f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    size_t newLine = match.find("\n");
163f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    if (newLine != kNotFound)
164f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        match = match.substring(0, newLine);
165d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    match = match.stripWhiteSpace();
166d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
167f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    String disallowedChars("\"' \t");
168d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    for (unsigned i = 0; i < match.length(); ++i) {
169d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (disallowedChars.find(match[i]) != kNotFound)
170f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu            return "";
17181a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    }
172d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
173d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    return match;
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)String findSourceURL(const String& content, MagicCommentType commentType, bool* deprecated)
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1785267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    return findMagicComment(content, "sourceURL", commentType, deprecated);
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1815267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)String findSourceMapURL(const String& content, MagicCommentType commentType, bool* deprecated)
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1835267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    return findMagicComment(content, "sourceMappingURL", commentType, deprecated);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace ContentSearchUtils
187c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
189