clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using System.Text;
32 using log4net;
33 using OpenMetaverse;
34 using OpenSim.Framework;
35 using OpenSim.Services.Interfaces;
36  
37 namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
38 {
39 /// <summary>
40 /// Utility methods for inventory archiving
41 /// </summary>
42 public static class InventoryArchiveUtils
43 {
44 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45  
46 // Character used for escaping the path delimter ("\/") and itself ("\\") in human escaped strings
47 public static readonly char ESCAPE_CHARACTER = '\\';
48  
49 // The character used to separate inventory path components (different folders and items)
50 public static readonly char PATH_DELIMITER = '/';
51  
52 /// <summary>
53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder
54 /// </summary>
55 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors
57 ///
58 /// FIXME: We have no way of distinguishing folders with the same path
59 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
61 /// </remarks>
62 /// <param name="inventoryService">
63 /// Inventory service to query
64 /// </param>
65 /// <param name="userId">
66 /// User id to search
67 /// </param>
68 /// <param name="path">
69 /// The path to the required folder.
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param>
72 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
73 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
74 public static InventoryFolderBase FindFolderByPath(
75 IInventoryService inventoryService, UUID userId, string path)
76 {
77 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, userId, path);
78  
79 if (folders.Count == 0)
80 return null;
81 else
82 return folders[0];
83 }
84  
85 /// <summary>
86 /// Find a folder given a PATH_DELIMITER delimited path starting from a given folder
87 /// </summary>
88 /// <remarks>
89 /// This method does not handle paths that contain multiple delimitors
90 ///
91 /// FIXME: We have no way of distinguishing folders with the same path
92 ///
93 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
94 /// </remarks>
95 /// <param name="inventoryService">
96 /// Inventory service to query
97 /// </param>
98 /// <param name="startFolder">
99 /// The folder from which the path starts
100 /// </param>
101 /// <param name="path">
102 /// The path to the required folder.
103 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
104 /// </param>
105 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
106 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
107 public static InventoryFolderBase FindFolderByPath(
108 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
109 {
110 if (null == startFolder)
111 return null;
112  
113 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, startFolder, path);
114  
115 if (folders.Count == 0)
116 return null;
117 else
118 return folders[0];
119 }
120  
121 /// <summary>
122 /// Find a set of folders given a PATH_DELIMITER delimited path starting from a user's root folder
123 /// </summary>
124 /// <remarks>
125 /// This method does not handle paths that contain multiple delimitors
126 ///
127 /// FIXME: We have no way of distinguishing folders with the same path
128 ///
129 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
130 /// </remarks>
131 /// <param name="inventoryService">
132 /// Inventory service to query
133 /// </param>
134 /// <param name="userId">
135 /// User id to search
136 /// </param>
137 /// <param name="path">
138 /// The path to the required folder.
139 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
140 /// </param>
141 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
142 public static List<InventoryFolderBase> FindFoldersByPath(
143 IInventoryService inventoryService, UUID userId, string path)
144 {
145 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
146  
147 if (null == rootFolder)
148 return new List<InventoryFolderBase>();
149  
150 return FindFoldersByPath(inventoryService, rootFolder, path);
151 }
152  
153 /// <summary>
154 /// Find a set of folders given a PATH_DELIMITER delimited path starting from this folder
155 /// </summary>
156 /// <remarks>
157 /// This method does not handle paths that contain multiple delimitors
158 ///
159 /// FIXME: We have no way of distinguishing folders with the same path.
160 ///
161 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
162 /// </remarks>
163 /// <param name="inventoryService">
164 /// Inventory service to query
165 /// </param>
166 /// <param name="startFolder">
167 /// The folder from which the path starts
168 /// </param>
169 /// <param name="path">
170 /// The path to the required folder.
171 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
172 /// </param>
173 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
174 public static List<InventoryFolderBase> FindFoldersByPath(
175 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
176 {
177 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>();
178  
179 if (path == string.Empty)
180 {
181 foundFolders.Add(startFolder);
182 return foundFolders;
183 }
184  
185 path = path.Trim();
186  
187 if (path == PATH_DELIMITER.ToString())
188 {
189 foundFolders.Add(startFolder);
190 return foundFolders;
191 }
192  
193 // If the path isn't just / then trim any starting extraneous slashes
194 path = path.TrimStart(new char[] { PATH_DELIMITER });
195  
196 // m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Adjusted path in FindFolderByPath() is [{0}]", path);
197  
198 string[] components = SplitEscapedPath(path);
199 components[0] = UnescapePath(components[0]);
200  
201 //string[] components = path.Split(new string[] { PATH_DELIMITER.ToString() }, 2, StringSplitOptions.None);
202  
203 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);
204  
205 // m_log.DebugFormat(
206 // "Found {0} folders in {1} for {2}", contents.Folders.Count, startFolder.Name, startFolder.Owner);
207  
208 foreach (InventoryFolderBase folder in contents.Folders)
209 {
210 if (folder.Name == components[0])
211 {
212 if (components.Length > 1)
213 foundFolders.AddRange(FindFoldersByPath(inventoryService, folder, components[1]));
214 else
215 foundFolders.Add(folder);
216 }
217 }
218  
219 return foundFolders;
220 }
221  
222 /// <summary>
223 /// Find an item given a PATH_DELIMITOR delimited path starting from the user's root folder.
224 /// </summary>
225 /// <remarks>
226 /// This method does not handle paths that contain multiple delimitors
227 ///
228 /// FIXME: We do not yet handle situations where folders or items have the same name. We could handle this by some
229 /// XPath like expression
230 ///
231 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
232 /// </remarks>
233 ///
234 /// <param name="inventoryService">
235 /// Inventory service to query
236 /// </param>
237 /// <param name="userId">
238 /// The user to search
239 /// </param>
240 /// <param name="path">
241 /// The path to the required item.
242 /// </param>
243 /// <returns>null if the item is not found</returns>
244 public static InventoryItemBase FindItemByPath(
245 IInventoryService inventoryService, UUID userId, string path)
246 {
247 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
248  
249 if (null == rootFolder)
250 return null;
251  
252 return FindItemByPath(inventoryService, rootFolder, path);
253 }
254  
255 /// <summary>
256 /// Find an item given a PATH_DELIMITOR delimited path starting from this folder.
257 /// </summary>
258 /// <remarks>
259 /// This method does not handle paths that contain multiple delimiters
260 ///
261 /// FIXME: We do not yet handle situations where folders or items have the same name. We could handle this by some
262 /// XPath like expression
263 ///
264 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
265 /// </remarks>
266 ///
267 /// <param name="inventoryService">Inventory service to query</param>
268 /// <param name="startFolder">The folder from which the path starts</param>
269 /// <param name="path">The path to the required item.</param>
270 /// <returns>null if the item is not found</returns>
271 public static InventoryItemBase FindItemByPath(
272 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
273 {
274 List<InventoryItemBase> foundItems = FindItemsByPath(inventoryService, startFolder, path);
275  
276 if (foundItems.Count != 0)
277 return foundItems[0];
278 else
279 return null;
280 }
281  
282 public static List<InventoryItemBase> FindItemsByPath(
283 IInventoryService inventoryService, UUID userId, string path)
284 {
285 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
286  
287 if (null == rootFolder)
288 return new List<InventoryItemBase>();
289  
290 return FindItemsByPath(inventoryService, rootFolder, path);
291 }
292  
293 /// <summary>
294 /// Find items that match a given PATH_DELIMITOR delimited path starting from this folder.
295 /// </summary>
296 /// <remarks>
297 /// This method does not handle paths that contain multiple delimiters
298 ///
299 /// FIXME: We do not yet handle situations where folders or items have the same name. We could handle this by some
300 /// XPath like expression
301 ///
302 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
303 /// </remarks>
304 ///
305 /// <param name="inventoryService">Inventory service to query</param>
306 /// <param name="startFolder">The folder from which the path starts</param>
307 /// <param name="path">The path to the required item.</param>
308 /// <returns>The items that were found with this path. An empty list if no items were found.</returns>
309 public static List<InventoryItemBase> FindItemsByPath(
310 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
311 {
312 List<InventoryItemBase> foundItems = new List<InventoryItemBase>();
313  
314 // If the path isn't just / then trim any starting extraneous slashes
315 path = path.TrimStart(new char[] { PATH_DELIMITER });
316  
317 string[] components = SplitEscapedPath(path);
318 components[0] = UnescapePath(components[0]);
319  
320 //string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None);
321  
322 if (components.Length == 1)
323 {
324 // m_log.DebugFormat(
325 // "FOUND SINGLE COMPONENT [{0}]. Looking for this in [{1}] {2}",
326 // components[0], startFolder.Name, startFolder.ID);
327  
328 List<InventoryItemBase> items = inventoryService.GetFolderItems(startFolder.Owner, startFolder.ID);
329  
330 // m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Found {0} items in FindItemByPath()", items.Count);
331  
332 foreach (InventoryItemBase item in items)
333 {
334 // m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Inspecting item {0} {1}", item.Name, item.ID);
335  
336 if (item.Name == components[0])
337 foundItems.Add(item);
338 }
339 }
340 else
341 {
342 // m_log.DebugFormat("FOUND COMPONENTS [{0}] and [{1}]", components[0], components[1]);
343  
344 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);
345  
346 foreach (InventoryFolderBase folder in contents.Folders)
347 {
348 if (folder.Name == components[0])
349 foundItems.AddRange(FindItemsByPath(inventoryService, folder, components[1]));
350 }
351 }
352  
353 return foundItems;
354 }
355  
356 /// <summary>
357 /// Split a human escaped path into two components if it contains an unescaped path delimiter, or one component
358 /// if no delimiter is present
359 /// </summary>
360 /// <param name="path"></param>
361 /// <returns>
362 /// The split path. We leave the components in their originally unescaped state (though we remove the delimiter
363 /// which originally split them if applicable).
364 /// </returns>
365 public static string[] SplitEscapedPath(string path)
366 {
367 // m_log.DebugFormat("SPLITTING PATH {0}", path);
368  
369 bool singleEscapeChar = false;
370  
371 for (int i = 0; i < path.Length; i++)
372 {
373 if (path[i] == ESCAPE_CHARACTER && !singleEscapeChar)
374 {
375 singleEscapeChar = true;
376 }
377 else
378 {
379 if (PATH_DELIMITER == path[i] && !singleEscapeChar)
380 return new string[2] { path.Remove(i), path.Substring(i + 1) };
381 else
382 singleEscapeChar = false;
383 }
384 }
385  
386 // We didn't find a delimiter
387 return new string[1] { path };
388 }
389  
390 /// <summary>
391 /// Unescapes a human escaped path. This means that "\\" goes to "\", and "\/" goes to "/"
392 /// </summary>
393 /// <param name="path"></param>
394 /// <returns></returns>
395 public static string UnescapePath(string path)
396 {
397 // m_log.DebugFormat("ESCAPING PATH {0}", path);
398  
399 StringBuilder sb = new StringBuilder();
400  
401 bool singleEscapeChar = false;
402 for (int i = 0; i < path.Length; i++)
403 {
404 if (path[i] == ESCAPE_CHARACTER && !singleEscapeChar)
405 singleEscapeChar = true;
406 else
407 singleEscapeChar = false;
408  
409 if (singleEscapeChar)
410 {
411 if (PATH_DELIMITER == path[i])
412 sb.Append(PATH_DELIMITER);
413 }
414 else
415 {
416 sb.Append(path[i]);
417 }
418 }
419  
420 // m_log.DebugFormat("ESCAPED PATH TO {0}", sb);
421  
422 return sb.ToString();
423 }
424  
425 /// <summary>
426 /// Escape an archive path.
427 /// </summary>
428 /// This has to be done differently from human paths because we can't leave in any "/" characters (due to
429 /// problems if the archive is built from or extracted to a filesystem
430 /// <param name="path"></param>
431 /// <returns></returns>
432 public static string EscapeArchivePath(string path)
433 {
434 // Only encode ampersands (for escaping anything) and / (since this is used as general dir separator).
435 return path.Replace("&", "&amp;").Replace("/", "&#47;");
436 }
437  
438 /// <summary>
439 /// Unescape an archive path.
440 /// </summary>
441 /// <param name="path"></param>
442 /// <returns></returns>
443 public static string UnescapeArchivePath(string path)
444 {
445 return path.Replace("&#47;", "/").Replace("&amp;", "&");
446 }
447 }
448 }