OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SLUtil.cs
Go to the documentation of this file.
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 OpenMetaverse;
29 using System;
30 using System.Collections.Generic;
31 
32 namespace OpenSim.Framework
33 {
34  public static class SLUtil
35  {
36 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
37 
42  public enum OpenSimAssetType : sbyte
43  {
44  Material = -2
45  }
46 
47 
48  #region SL / file extension / content-type conversions
49 
54  public static object AssetTypeFromCode(sbyte assetType)
55  {
56  if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
57  return (OpenMetaverse.AssetType)assetType;
58  else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType))
59  return (OpenSimAssetType)assetType;
60  else
61  return OpenMetaverse.AssetType.Unknown;
62  }
63 
64  private class TypeMapping
65  {
66  private sbyte assetType;
67  private sbyte inventoryType;
68  private string contentType;
69  private string contentType2;
70  private string extension;
71 
72  public sbyte AssetTypeCode
73  {
74  get { return assetType; }
75  }
76 
77  public object AssetType
78  {
79  get { return AssetTypeFromCode(assetType); }
80  }
81 
82  public sbyte InventoryType
83  {
84  get { return inventoryType; }
85  }
86 
87  public string ContentType
88  {
89  get { return contentType; }
90  }
91 
92  public string ContentType2
93  {
94  get { return contentType2; }
95  }
96 
97  public string Extension
98  {
99  get { return extension; }
100  }
101 
102  private TypeMapping(sbyte assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
103  {
104  this.assetType = assetType;
105  this.inventoryType = inventoryType;
106  this.contentType = contentType;
107  this.contentType2 = contentType2;
108  this.extension = extension;
109  }
110 
111  public TypeMapping(AssetType assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
112  : this((sbyte)assetType, inventoryType, contentType, contentType2, extension)
113  {
114  }
115 
116  public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
117  : this((sbyte)assetType, (sbyte)inventoryType, contentType, contentType2, extension)
118  {
119  }
120 
121  public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension)
122  : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
123  {
124  }
125 
126  public TypeMapping(AssetType assetType, FolderType inventoryType, string contentType, string extension)
127  : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
128  {
129  }
130 
131  public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension)
132  : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
133  {
134  }
135  }
136 
143  private static TypeMapping[] MAPPINGS = new TypeMapping[] {
144  new TypeMapping(AssetType.Unknown, InventoryType.Unknown, "application/octet-stream", "bin"),
145  new TypeMapping(AssetType.Texture, InventoryType.Texture, "image/x-j2c", "image/jp2", "j2c"),
146  new TypeMapping(AssetType.Texture, InventoryType.Snapshot, "image/x-j2c", "image/jp2", "j2c"),
147  new TypeMapping(AssetType.TextureTGA, InventoryType.Texture, "image/tga", "tga"),
148  new TypeMapping(AssetType.ImageTGA, InventoryType.Texture, "image/tga", "tga"),
149  new TypeMapping(AssetType.ImageJPEG, InventoryType.Texture, "image/jpeg", "jpg"),
150  new TypeMapping(AssetType.Sound, InventoryType.Sound, "audio/ogg", "application/ogg", "ogg"),
151  new TypeMapping(AssetType.SoundWAV, InventoryType.Sound, "audio/x-wav", "wav"),
152  new TypeMapping(AssetType.CallingCard, InventoryType.CallingCard, "application/vnd.ll.callingcard", "application/x-metaverse-callingcard", "callingcard"),
153  new TypeMapping(AssetType.Landmark, InventoryType.Landmark, "application/vnd.ll.landmark", "application/x-metaverse-landmark", "landmark"),
154  new TypeMapping(AssetType.Clothing, InventoryType.Wearable, "application/vnd.ll.clothing", "application/x-metaverse-clothing", "clothing"),
155  new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
156  new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
157  new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"),
158  new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"),
159  new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"),
160  new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"),
161  new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"),
162  new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"),
163  new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"),
164  new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"),
165  new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"),
166  new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"),
167 
168  // The next few items are about inventory folders
169  new TypeMapping(AssetType.Folder, FolderType.None, "application/vnd.ll.folder", "folder"),
170  new TypeMapping(AssetType.Folder, FolderType.Root, "application/vnd.ll.rootfolder", "rootfolder"),
171  new TypeMapping(AssetType.Folder, FolderType.Trash, "application/vnd.ll.trashfolder", "trashfolder"),
172  new TypeMapping(AssetType.Folder, FolderType.Snapshot, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
173  new TypeMapping(AssetType.Folder, FolderType.LostAndFound, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
174  new TypeMapping(AssetType.Folder, FolderType.Favorites, "application/vnd.ll.favoritefolder", "favoritefolder"),
175  new TypeMapping(AssetType.Folder, FolderType.CurrentOutfit, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"),
176  new TypeMapping(AssetType.Folder, FolderType.Outfit, "application/vnd.ll.outfitfolder", "outfitfolder"),
177  new TypeMapping(AssetType.Folder, FolderType.MyOutfits, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"),
178 
179  // This next mappping is an asset to inventory item mapping.
180  // Note: LL stores folders as assets of type Folder = 8, and it has a corresponding InventoryType = 8
181  // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server
182  new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
183 
184  // OpenSim specific
185  new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material")
186  };
187 
188  private static Dictionary<sbyte, string> asset2Content;
189  private static Dictionary<sbyte, string> asset2Extension;
190  private static Dictionary<sbyte, string> inventory2Content;
191  private static Dictionary<string, sbyte> content2Asset;
192  private static Dictionary<string, sbyte> content2Inventory;
193 
194  static SLUtil()
195  {
196  asset2Content = new Dictionary<sbyte, string>();
197  asset2Extension = new Dictionary<sbyte, string>();
198  inventory2Content = new Dictionary<sbyte, string>();
199  content2Asset = new Dictionary<string, sbyte>();
200  content2Inventory = new Dictionary<string, sbyte>();
201 
202  foreach (TypeMapping mapping in MAPPINGS)
203  {
204  sbyte assetType = mapping.AssetTypeCode;
205  if (!asset2Content.ContainsKey(assetType))
206  asset2Content.Add(assetType, mapping.ContentType);
207 
208  if (!asset2Extension.ContainsKey(assetType))
209  asset2Extension.Add(assetType, mapping.Extension);
210 
211  if (!inventory2Content.ContainsKey(mapping.InventoryType))
212  inventory2Content.Add(mapping.InventoryType, mapping.ContentType);
213 
214  if (!content2Asset.ContainsKey(mapping.ContentType))
215  content2Asset.Add(mapping.ContentType, assetType);
216 
217  if (!content2Inventory.ContainsKey(mapping.ContentType))
218  content2Inventory.Add(mapping.ContentType, mapping.InventoryType);
219 
220  if (mapping.ContentType2 != null)
221  {
222  if (!content2Asset.ContainsKey(mapping.ContentType2))
223  content2Asset.Add(mapping.ContentType2, assetType);
224  if (!content2Inventory.ContainsKey(mapping.ContentType2))
225  content2Inventory.Add(mapping.ContentType2, mapping.InventoryType);
226  }
227  }
228  }
229 
230  public static string SLAssetTypeToContentType(int assetType)
231  {
232  string contentType;
233  if (!asset2Content.TryGetValue((sbyte)assetType, out contentType))
234  contentType = asset2Content[(sbyte)AssetType.Unknown];
235  return contentType;
236  }
237 
238  public static string SLInvTypeToContentType(int invType)
239  {
240  string contentType;
241  if (!inventory2Content.TryGetValue((sbyte)invType, out contentType))
242  contentType = inventory2Content[(sbyte)InventoryType.Unknown];
243  return contentType;
244  }
245 
246  public static sbyte ContentTypeToSLAssetType(string contentType)
247  {
248  sbyte assetType;
249  if (!content2Asset.TryGetValue(contentType, out assetType))
250  assetType = (sbyte)AssetType.Unknown;
251  return (sbyte)assetType;
252  }
253 
254  public static sbyte ContentTypeToSLInvType(string contentType)
255  {
256  sbyte invType;
257  if (!content2Inventory.TryGetValue(contentType, out invType))
258  invType = (sbyte)InventoryType.Unknown;
259  return (sbyte)invType;
260  }
261 
262  public static string SLAssetTypeToExtension(int assetType)
263  {
264  string extension;
265  if (!asset2Extension.TryGetValue((sbyte)assetType, out extension))
266  extension = asset2Extension[(sbyte)AssetType.Unknown];
267  return extension;
268  }
269 
270  #endregion SL / file extension / content-type conversions
271 
272  private class NotecardReader
273  {
274  private string rawInput;
275  private int lineNumber;
276 
277  public int LineNumber
278  {
279  get
280  {
281  return lineNumber;
282  }
283  }
284 
285  public NotecardReader(string _rawInput)
286  {
287  rawInput = (string)_rawInput.Clone();
288  lineNumber = 0;
289  }
290 
291  public string getLine()
292  {
293  if(rawInput.Length == 0)
294  {
295  throw new NotANotecardFormatException(lineNumber + 1);
296  }
297 
298  int pos = rawInput.IndexOf('\n');
299  if(pos < 0)
300  {
301  pos = rawInput.Length;
302  }
303 
304  /* cut line from rest */
305  ++lineNumber;
306  string line = rawInput.Substring(0, pos);
307  if (pos + 1 >= rawInput.Length)
308  {
309  rawInput = string.Empty;
310  }
311  else
312  {
313  rawInput = rawInput.Substring(pos + 1);
314  }
315  /* clean up line from double spaces and tabs */
316  line = line.Replace("\t", " ");
317  while(line.IndexOf(" ") >= 0)
318  {
319  line = line.Replace(" ", " ");
320  }
321  return line.Replace("\r", "").Trim();
322  }
323 
324  public string getBlock(int length)
325  {
326  /* cut line from rest */
327  if(length > rawInput.Length)
328  {
329  throw new NotANotecardFormatException(lineNumber);
330  }
331  string line = rawInput.Substring(0, length);
332  rawInput = rawInput.Substring(length);
333  return line;
334  }
335  }
336 
337  public class NotANotecardFormatException : Exception
338  {
339  public int lineNumber;
340  public NotANotecardFormatException(int _lineNumber)
341  : base()
342  {
343  lineNumber = _lineNumber;
344  }
345  }
346 
347  private static void skipSection(NotecardReader reader)
348  {
349  if (reader.getLine() != "{")
350  throw new NotANotecardFormatException(reader.LineNumber);
351 
352  string line;
353  while ((line = reader.getLine()) != "}")
354  {
355  if(line.IndexOf('{')>=0)
356  {
357  throw new NotANotecardFormatException(reader.LineNumber);
358  }
359  }
360  }
361 
362  private static void skipInventoryItem(NotecardReader reader)
363  {
364  if (reader.getLine() != "{")
365  throw new NotANotecardFormatException(reader.LineNumber);
366 
367  string line;
368  while((line = reader.getLine()) != "}")
369  {
370  string[] data = line.Split(' ');
371  if(data.Length == 0)
372  {
373  continue;
374  }
375  if(data[0] == "permissions")
376  {
377  skipSection(reader);
378  }
379  else if(data[0] == "sale_info")
380  {
381  skipSection(reader);
382  }
383  else if (line.IndexOf('{') >= 0)
384  {
385  throw new NotANotecardFormatException(reader.LineNumber);
386  }
387  }
388  }
389 
390  private static void skipInventoryItems(NotecardReader reader)
391  {
392  if(reader.getLine() != "{")
393  {
394  throw new NotANotecardFormatException(reader.LineNumber);
395  }
396 
397  string line;
398  while((line = reader.getLine()) != "}")
399  {
400  string[] data = line.Split(' ');
401  if(data.Length == 0)
402  {
403  continue;
404  }
405 
406  if(data[0] == "inv_item")
407  {
408  skipInventoryItem(reader);
409  }
410  else if (line.IndexOf('{') >= 0)
411  {
412  throw new NotANotecardFormatException(reader.LineNumber);
413  }
414 
415  }
416  }
417 
418  private static void skipInventory(NotecardReader reader)
419  {
420  if (reader.getLine() != "{")
421  throw new NotANotecardFormatException(reader.LineNumber);
422 
423  string line;
424  while((line = reader.getLine()) != "}")
425  {
426  string[] data = line.Split(' ');
427  if(data[0] == "count")
428  {
429  int count = Int32.Parse(data[1]);
430  for(int i = 0; i < count; ++i)
431  {
432  skipInventoryItems(reader);
433  }
434  }
435  else if (line.IndexOf('{') >= 0)
436  {
437  throw new NotANotecardFormatException(reader.LineNumber);
438  }
439  }
440  }
441 
442  private static string readNotecardText(NotecardReader reader)
443  {
444  if (reader.getLine() != "{")
445  throw new NotANotecardFormatException(reader.LineNumber);
446 
447  string notecardString = string.Empty;
448  string line;
449  while((line = reader.getLine()) != "}")
450  {
451  string[] data = line.Split(' ');
452  if (data.Length == 0)
453  {
454  continue;
455  }
456 
457  if (data[0] == "LLEmbeddedItems")
458  {
459  skipInventory(reader);
460  }
461  else if(data[0] == "Text" && data.Length == 3)
462  {
463  int length = Int32.Parse(data[2]);
464  notecardString = reader.getBlock(length);
465  }
466  else if (line.IndexOf('{') >= 0)
467  {
468  throw new NotANotecardFormatException(reader.LineNumber);
469  }
470 
471  }
472  return notecardString;
473  }
474 
475  private static string readNotecard(byte[] rawInput)
476  {
477  string rawIntermedInput = string.Empty;
478 
479  /* make up a Raw Encoding here */
480  foreach(byte c in rawInput)
481  {
482  char d = (char)c;
483  rawIntermedInput += d;
484  }
485 
486  NotecardReader reader = new NotecardReader(rawIntermedInput);
487  string line;
488  try
489  {
490  line = reader.getLine();
491  }
492  catch(Exception)
493  {
494  return System.Text.Encoding.UTF8.GetString(rawInput);
495  }
496  string[] versioninfo = line.Split(' ');
497  if(versioninfo.Length < 3)
498  {
499  return System.Text.Encoding.UTF8.GetString(rawInput);
500  }
501  else if(versioninfo[0] != "Linden" || versioninfo[1] != "text")
502  {
503  return System.Text.Encoding.UTF8.GetString(rawInput);
504  }
505  else
506  {
507  /* now we actually decode the Encoding, before we needed it in raw */
508  string o = readNotecardText(reader);
509  byte[] a = new byte[o.Length];
510  for(int i = 0; i < o.Length; ++i)
511  {
512  a[i] = (byte)o[i];
513  }
514  return System.Text.Encoding.UTF8.GetString(a);
515  }
516  }
517 
523  public static string ParseNotecardToString(byte[] rawInput)
524  {
525  return readNotecard(rawInput);
526  }
527 
533  public static string[] ParseNotecardToArray(byte[] rawInput)
534  {
535  return readNotecard(rawInput).Replace("\r", "").Split('\n');
536  }
537  }
538 }
OpenSim.Framework.SLUtil.OpenSimAssetType OpenSimAssetType
Material
Material type for a primitive
Definition: OdeScene.cs:79