1 /* 2 * Copyright (C) 2012 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 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.Object} 34 */ 35 WebInspector.FileSystemMapping = function() 36 { 37 WebInspector.Object.call(this); 38 this._fileSystemMappingSetting = WebInspector.settings.createSetting("fileSystemMapping", {}); 39 /** @type {!Object.<string, Array.<WebInspector.FileSystemMapping.Entry>>} */ 40 this._fileSystemMappings = {}; 41 this._loadFromSettings(); 42 } 43 44 WebInspector.FileSystemMapping.Events = { 45 FileMappingAdded: "FileMappingAdded", 46 FileMappingRemoved: "FileMappingRemoved" 47 } 48 49 50 WebInspector.FileSystemMapping.prototype = { 51 _loadFromSettings: function() 52 { 53 var savedMapping = this._fileSystemMappingSetting.get(); 54 this._fileSystemMappings = {}; 55 for (var fileSystemPath in savedMapping) { 56 var savedFileSystemMappings = savedMapping[fileSystemPath]; 57 58 this._fileSystemMappings[fileSystemPath] = []; 59 var fileSystemMappings = this._fileSystemMappings[fileSystemPath]; 60 61 for (var i = 0; i < savedFileSystemMappings.length; ++i) { 62 var savedEntry = savedFileSystemMappings[i]; 63 var entry = new WebInspector.FileSystemMapping.Entry(savedEntry.fileSystemPath, savedEntry.urlPrefix, savedEntry.pathPrefix); 64 fileSystemMappings.push(entry); 65 } 66 } 67 this._rebuildIndexes(); 68 }, 69 70 _saveToSettings: function() 71 { 72 var savedMapping = this._fileSystemMappings; 73 this._fileSystemMappingSetting.set(savedMapping); 74 this._rebuildIndexes(); 75 }, 76 77 _rebuildIndexes: function() 78 { 79 // We are building an index here to search for the longest url prefix match faster. 80 this._mappingForURLPrefix = {}; 81 this._urlPrefixes = []; 82 for (var fileSystemPath in this._fileSystemMappings) { 83 var fileSystemMapping = this._fileSystemMappings[fileSystemPath]; 84 for (var i = 0; i < fileSystemMapping.length; ++i) { 85 var entry = fileSystemMapping[i]; 86 this._mappingForURLPrefix[entry.urlPrefix] = entry; 87 this._urlPrefixes.push(entry.urlPrefix); 88 } 89 } 90 this._urlPrefixes.sort(); 91 }, 92 93 /** 94 * @param {string} fileSystemPath 95 */ 96 addFileSystem: function(fileSystemPath) 97 { 98 if (this._fileSystemMappings[fileSystemPath]) 99 return; 100 101 this._fileSystemMappings[fileSystemPath] = []; 102 this._saveToSettings(); 103 }, 104 105 /** 106 * @param {string} fileSystemPath 107 */ 108 removeFileSystem: function(fileSystemPath) 109 { 110 if (!this._fileSystemMappings[fileSystemPath]) 111 return; 112 delete this._fileSystemMappings[fileSystemPath]; 113 this._saveToSettings(); 114 }, 115 116 /** 117 * @param {string} fileSystemPath 118 * @param {string} urlPrefix 119 * @param {string} pathPrefix 120 */ 121 addFileMapping: function(fileSystemPath, urlPrefix, pathPrefix) 122 { 123 var entry = new WebInspector.FileSystemMapping.Entry(fileSystemPath, urlPrefix, pathPrefix); 124 this._fileSystemMappings[fileSystemPath].push(entry); 125 this._saveToSettings(); 126 this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingAdded, entry); 127 }, 128 129 /** 130 * @param {string} fileSystemPath 131 * @param {string} urlPrefix 132 * @param {string} pathPrefix 133 */ 134 removeFileMapping: function(fileSystemPath, urlPrefix, pathPrefix) 135 { 136 var entry = this._mappingEntryForPathPrefix(fileSystemPath, pathPrefix); 137 if (!entry) 138 return; 139 this._fileSystemMappings[fileSystemPath].remove(entry); 140 this._saveToSettings(); 141 this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingRemoved, entry); 142 }, 143 144 /** 145 * @return {Array.<string>} 146 */ 147 fileSystemPaths: function() 148 { 149 return Object.keys(this._fileSystemMappings); 150 }, 151 152 /** 153 * @param {string} url 154 * @return {WebInspector.FileSystemMapping.Entry} 155 */ 156 _mappingEntryForURL: function(url) 157 { 158 for (var i = this._urlPrefixes.length - 1; i >= 0; --i) { 159 var urlPrefix = this._urlPrefixes[i]; 160 if (url.startsWith(urlPrefix)) 161 return this._mappingForURLPrefix[urlPrefix]; 162 } 163 return null; 164 }, 165 166 /** 167 * @param {string} fileSystemPath 168 * @param {string} filePath 169 * @return {?WebInspector.FileSystemMapping.Entry} 170 */ 171 _mappingEntryForPath: function(fileSystemPath, filePath) 172 { 173 var entries = this._fileSystemMappings[fileSystemPath]; 174 if (!entries) 175 return null; 176 177 var entry = null; 178 for (var i = 0; i < entries.length; ++i) { 179 var pathPrefix = entries[i].pathPrefix; 180 // We are looking for the longest pathPrefix match. 181 if (entry && entry.pathPrefix.length > pathPrefix.length) 182 continue; 183 if (filePath.startsWith(pathPrefix.substr(1))) 184 entry = entries[i]; 185 } 186 return entry; 187 }, 188 189 /** 190 * @param {string} fileSystemPath 191 * @param {string} pathPrefix 192 * @return {WebInspector.FileSystemMapping.Entry} 193 */ 194 _mappingEntryForPathPrefix: function(fileSystemPath, pathPrefix) 195 { 196 var entries = this._fileSystemMappings[fileSystemPath]; 197 for (var i = 0; i < entries.length; ++i) { 198 if (pathPrefix === entries[i].pathPrefix) 199 return entries[i]; 200 } 201 return null; 202 }, 203 204 /** 205 * @param {string} fileSystemPath 206 * @return {Array.<WebInspector.FileSystemMapping.Entry>} 207 */ 208 mappingEntries: function(fileSystemPath) 209 { 210 return this._fileSystemMappings[fileSystemPath].slice(); 211 }, 212 213 /** 214 * @param {string} url 215 * @return {boolean} 216 */ 217 hasMappingForURL: function(url) 218 { 219 return !!this._mappingEntryForURL(url); 220 }, 221 222 /** 223 * @param {string} url 224 * @return {?{fileSystemPath: string, filePath: string}} 225 */ 226 fileForURL: function(url) 227 { 228 var entry = this._mappingEntryForURL(url); 229 if (!entry) 230 return null; 231 var file = {}; 232 file.fileSystemPath = entry.fileSystemPath; 233 file.filePath = entry.pathPrefix.substr(1) + url.substr(entry.urlPrefix.length); 234 return file; 235 }, 236 237 /** 238 * @param {string} fileSystemPath 239 * @param {string} filePath 240 * @return {string} 241 */ 242 urlForPath: function(fileSystemPath, filePath) 243 { 244 var entry = this._mappingEntryForPath(fileSystemPath, filePath); 245 if (!entry) 246 return ""; 247 return entry.urlPrefix + filePath.substring(entry.pathPrefix.length - 1); 248 }, 249 250 /** 251 * @param {string} url 252 */ 253 removeMappingForURL: function(url) 254 { 255 var entry = this._mappingEntryForURL(url); 256 if (!entry) 257 return; 258 this._fileSystemMappings[entry.fileSystemPath].remove(entry); 259 this._saveToSettings(); 260 }, 261 262 /** 263 * @param {string} url 264 * @param {string} fileSystemPath 265 * @param {string} filePath 266 */ 267 addMappingForResource: function(url, fileSystemPath, filePath) 268 { 269 var commonPathSuffixLength = 0; 270 var normalizedFilePath = "/" + filePath; 271 for (var i = 0; i < normalizedFilePath.length; ++i) { 272 var filePathCharacter = normalizedFilePath[normalizedFilePath.length - 1 - i]; 273 var urlCharacter = url[url.length - 1 - i]; 274 if (filePathCharacter !== urlCharacter) 275 break; 276 if (filePathCharacter === "/") 277 commonPathSuffixLength = i; 278 } 279 var pathPrefix = normalizedFilePath.substr(0, normalizedFilePath.length - commonPathSuffixLength); 280 var urlPrefix = url.substr(0, url.length - commonPathSuffixLength); 281 this.addFileMapping(fileSystemPath, urlPrefix, pathPrefix); 282 }, 283 284 __proto__: WebInspector.Object.prototype 285 } 286 287 /** 288 * @constructor 289 * @param {string} fileSystemPath 290 * @param {string} urlPrefix 291 * @param {string} pathPrefix 292 */ 293 WebInspector.FileSystemMapping.Entry = function(fileSystemPath, urlPrefix, pathPrefix) 294 { 295 this.fileSystemPath = fileSystemPath; 296 this.urlPrefix = urlPrefix; 297 this.pathPrefix = pathPrefix; 298 } 299