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