• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20  * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 
31 #include "core/inspector/ContentSearchUtils.h"
32 
33 #include "bindings/v8/ScriptRegexp.h"
34 #include "wtf/text/StringBuilder.h"
35 
36 using namespace std;
37 
38 namespace WebCore {
39 namespace ContentSearchUtils {
40 
41 namespace {
42 // This should be kept the same as the one in front-end/utilities.js
43 static const char regexSpecialCharacters[] = "[](){}+-*.,?\\^$|";
44 }
45 
createSearchRegexSource(const String & text)46 static String createSearchRegexSource(const String& text)
47 {
48     StringBuilder result;
49     String specials(regexSpecialCharacters);
50 
51     for (unsigned i = 0; i < text.length(); i++) {
52         if (specials.find(text[i]) != kNotFound)
53             result.append("\\");
54         result.append(text[i]);
55     }
56 
57     return result.toString();
58 }
59 
getScriptRegexpMatchesByLines(const ScriptRegexp * regex,const String & text)60 static Vector<pair<int, String> > getScriptRegexpMatchesByLines(const ScriptRegexp* regex, const String& text)
61 {
62     Vector<pair<int, String> > result;
63     if (text.isEmpty())
64         return result;
65 
66     OwnPtr<Vector<unsigned> > endings(lineEndings(text));
67     unsigned size = endings->size();
68     unsigned start = 0;
69     for (unsigned lineNumber = 0; lineNumber < size; ++lineNumber) {
70         unsigned lineEnd = endings->at(lineNumber);
71         String line = text.substring(start, lineEnd - start);
72         if (line.endsWith('\r'))
73             line = line.left(line.length() - 1);
74 
75         int matchLength;
76         if (regex->match(line, 0, &matchLength) != -1)
77             result.append(pair<int, String>(lineNumber, line));
78 
79         start = lineEnd + 1;
80     }
81     return result;
82 }
83 
buildObjectForSearchMatch(int lineNumber,const String & lineContent)84 static PassRefPtr<TypeBuilder::Page::SearchMatch> buildObjectForSearchMatch(int lineNumber, const String& lineContent)
85 {
86     return TypeBuilder::Page::SearchMatch::create()
87         .setLineNumber(lineNumber)
88         .setLineContent(lineContent)
89         .release();
90 }
91 
createSearchRegex(const String & query,bool caseSensitive,bool isRegex)92 PassOwnPtr<ScriptRegexp> createSearchRegex(const String& query, bool caseSensitive, bool isRegex)
93 {
94     String regexSource = isRegex ? query : createSearchRegexSource(query);
95     return adoptPtr(new ScriptRegexp(regexSource, caseSensitive ? TextCaseSensitive : TextCaseInsensitive));
96 }
97 
countScriptRegexpMatches(const ScriptRegexp * regex,const String & content)98 int countScriptRegexpMatches(const ScriptRegexp* regex, const String& content)
99 {
100     if (content.isEmpty())
101         return 0;
102 
103     int result = 0;
104     int position;
105     unsigned start = 0;
106     int matchLength;
107     while ((position = regex->match(content, start, &matchLength)) != -1) {
108         if (start >= content.length())
109             break;
110         if (matchLength > 0)
111             ++result;
112         start = position + 1;
113     }
114     return result;
115 }
116 
searchInTextByLines(const String & text,const String & query,const bool caseSensitive,const bool isRegex)117 PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex)
118 {
119     RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > result = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create();
120 
121     OwnPtr<ScriptRegexp> regex = ContentSearchUtils::createSearchRegex(query, caseSensitive, isRegex);
122     Vector<pair<int, String> > matches = getScriptRegexpMatchesByLines(regex.get(), text);
123 
124     for (Vector<pair<int, String> >::const_iterator it = matches.begin(); it != matches.end(); ++it)
125         result->addItem(buildObjectForSearchMatch(it->first, it->second));
126 
127     return result;
128 }
129 
findMagicComment(const String & content,const String & name,MagicCommentType commentType,bool * deprecated=0)130 static String findMagicComment(const String& content, const String& name, MagicCommentType commentType, bool* deprecated = 0)
131 {
132     ASSERT(name.find("=") == kNotFound);
133     if (deprecated)
134         *deprecated = false;
135     String pattern;
136     String deprecatedPattern;
137     switch (commentType) {
138     case JavaScriptMagicComment:
139         pattern = "//#[\040\t]" + createSearchRegexSource(name) + "=[\040\t]*([^\\s\'\"]*)[\040\t]*$";
140         deprecatedPattern = "//@[\040\t]" + createSearchRegexSource(name) + "=[\040\t]*([^\\s\'\"]*)[\040\t]*$";
141         break;
142     case CSSMagicComment:
143         pattern = "/\\*#[\040\t]" + createSearchRegexSource(name) + "=[\040\t]*([^\\s]*)[\040\t]*\\*/[\040\t]*$";
144         deprecatedPattern = "/\\*@[\040\t]" + createSearchRegexSource(name) + "=[\040\t]*([^\\s]*)[\040\t]*\\*/[\040\t]*$";
145         break;
146     default:
147         ASSERT_NOT_REACHED();
148         return String();
149     }
150     ScriptRegexp regex(pattern, TextCaseSensitive, MultilineEnabled);
151     ScriptRegexp deprecatedRegex(deprecatedPattern, TextCaseSensitive, MultilineEnabled);
152 
153     int matchLength;
154     int offset = regex.match(content, 0, &matchLength);
155     if (offset == -1) {
156         offset = deprecatedRegex.match(content, 0, &matchLength);
157         if (offset != -1 && deprecated)
158             *deprecated = true;
159     }
160     if (offset == -1)
161         return String();
162 
163     String match = content.substring(offset, matchLength);
164     size_t separator = match.find("=");
165     ASSERT(separator != kNotFound);
166     match = match.substring(separator + 1);
167 
168     switch (commentType) {
169     case JavaScriptMagicComment:
170         return match.stripWhiteSpace();
171     case CSSMagicComment: {
172         size_t lastStarIndex = match.reverseFind('*');
173         ASSERT(lastStarIndex != kNotFound);
174         return match.substring(0, lastStarIndex).stripWhiteSpace();
175     }
176     default:
177         ASSERT_NOT_REACHED();
178         return String();
179     }
180 }
181 
findSourceURL(const String & content,MagicCommentType commentType,bool * deprecated)182 String findSourceURL(const String& content, MagicCommentType commentType, bool* deprecated)
183 {
184     return findMagicComment(content, "sourceURL", commentType, deprecated);
185 }
186 
findSourceMapURL(const String & content,MagicCommentType commentType,bool * deprecated)187 String findSourceMapURL(const String& content, MagicCommentType commentType, bool* deprecated)
188 {
189     return findMagicComment(content, "sourceMappingURL", commentType, deprecated);
190 }
191 
192 } // namespace ContentSearchUtils
193 } // namespace WebCore
194 
195