SLUtil.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Reflection;
  31. using System.Xml;
  32. using log4net;
  33. using OpenMetaverse;
  34. namespace OpenSim.Framework
  35. {
  36. public static class SLUtil
  37. {
  38. // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  39. /// <summary>
  40. /// Asset types used only in OpenSim.
  41. /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here.
  42. /// </summary>
  43. public enum OpenSimAssetType : sbyte
  44. {
  45. Material = -2
  46. }
  47. #region SL / file extension / content-type conversions
  48. /// <summary>
  49. /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs
  50. /// to the AssetType or OpenSimAssetType enums.
  51. /// </summary>
  52. public static object AssetTypeFromCode(sbyte assetType)
  53. {
  54. if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
  55. return (OpenMetaverse.AssetType)assetType;
  56. else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType))
  57. return (OpenSimAssetType)assetType;
  58. else
  59. return OpenMetaverse.AssetType.Unknown;
  60. }
  61. private class TypeMapping
  62. {
  63. private sbyte assetType;
  64. private InventoryType inventoryType;
  65. private string contentType;
  66. private string contentType2;
  67. private string extension;
  68. public sbyte AssetTypeCode
  69. {
  70. get { return assetType; }
  71. }
  72. public object AssetType
  73. {
  74. get { return AssetTypeFromCode(assetType); }
  75. }
  76. public InventoryType InventoryType
  77. {
  78. get { return inventoryType; }
  79. }
  80. public string ContentType
  81. {
  82. get { return contentType; }
  83. }
  84. public string ContentType2
  85. {
  86. get { return contentType2; }
  87. }
  88. public string Extension
  89. {
  90. get { return extension; }
  91. }
  92. private TypeMapping(sbyte assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
  93. {
  94. this.assetType = assetType;
  95. this.inventoryType = inventoryType;
  96. this.contentType = contentType;
  97. this.contentType2 = contentType2;
  98. this.extension = extension;
  99. }
  100. public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
  101. : this((sbyte)assetType, inventoryType, contentType, contentType2, extension)
  102. {
  103. }
  104. public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension)
  105. : this((sbyte)assetType, inventoryType, contentType, null, extension)
  106. {
  107. }
  108. public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension)
  109. : this((sbyte)assetType, inventoryType, contentType, null, extension)
  110. {
  111. }
  112. }
  113. /// <summary>
  114. /// Maps between AssetType, InventoryType and Content-Type.
  115. /// Where more than one possibility exists, the first one takes precedence. E.g.:
  116. /// AssetType "AssetType.Texture" -> Content-Type "image-xj2c"
  117. /// Content-Type "image/x-j2c" -> InventoryType "InventoryType.Texture"
  118. /// </summary>
  119. private static TypeMapping[] MAPPINGS = new TypeMapping[] {
  120. new TypeMapping(AssetType.Unknown, InventoryType.Unknown, "application/octet-stream", "bin"),
  121. new TypeMapping(AssetType.Texture, InventoryType.Texture, "image/x-j2c", "image/jp2", "j2c"),
  122. new TypeMapping(AssetType.Texture, InventoryType.Snapshot, "image/x-j2c", "image/jp2", "j2c"),
  123. new TypeMapping(AssetType.TextureTGA, InventoryType.Texture, "image/tga", "tga"),
  124. new TypeMapping(AssetType.ImageTGA, InventoryType.Texture, "image/tga", "tga"),
  125. new TypeMapping(AssetType.ImageJPEG, InventoryType.Texture, "image/jpeg", "jpg"),
  126. new TypeMapping(AssetType.Sound, InventoryType.Sound, "audio/ogg", "application/ogg", "ogg"),
  127. new TypeMapping(AssetType.SoundWAV, InventoryType.Sound, "audio/x-wav", "wav"),
  128. new TypeMapping(AssetType.CallingCard, InventoryType.CallingCard, "application/vnd.ll.callingcard", "application/x-metaverse-callingcard", "callingcard"),
  129. new TypeMapping(AssetType.Landmark, InventoryType.Landmark, "application/vnd.ll.landmark", "application/x-metaverse-landmark", "landmark"),
  130. new TypeMapping(AssetType.Clothing, InventoryType.Wearable, "application/vnd.ll.clothing", "application/x-metaverse-clothing", "clothing"),
  131. new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
  132. new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
  133. new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"),
  134. new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
  135. new TypeMapping(AssetType.RootFolder, InventoryType.RootCategory, "application/vnd.ll.rootfolder", "rootfolder"),
  136. new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"),
  137. new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"),
  138. new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"),
  139. new TypeMapping(AssetType.TrashFolder, InventoryType.Folder, "application/vnd.ll.trashfolder", "trashfolder"),
  140. new TypeMapping(AssetType.SnapshotFolder, InventoryType.Folder, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
  141. new TypeMapping(AssetType.LostAndFoundFolder, InventoryType.Folder, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
  142. new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"),
  143. new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"),
  144. new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"),
  145. new TypeMapping(AssetType.FavoriteFolder, InventoryType.Unknown, "application/vnd.ll.favoritefolder", "favoritefolder"),
  146. new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"),
  147. new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"),
  148. new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"),
  149. new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"),
  150. new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"),
  151. new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"),
  152. new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material")
  153. };
  154. private static Dictionary<sbyte, string> asset2Content;
  155. private static Dictionary<sbyte, string> asset2Extension;
  156. private static Dictionary<InventoryType, string> inventory2Content;
  157. private static Dictionary<string, sbyte> content2Asset;
  158. private static Dictionary<string, InventoryType> content2Inventory;
  159. static SLUtil()
  160. {
  161. asset2Content = new Dictionary<sbyte, string>();
  162. asset2Extension = new Dictionary<sbyte, string>();
  163. inventory2Content = new Dictionary<InventoryType, string>();
  164. content2Asset = new Dictionary<string, sbyte>();
  165. content2Inventory = new Dictionary<string, InventoryType>();
  166. foreach (TypeMapping mapping in MAPPINGS)
  167. {
  168. sbyte assetType = mapping.AssetTypeCode;
  169. if (!asset2Content.ContainsKey(assetType))
  170. asset2Content.Add(assetType, mapping.ContentType);
  171. if (!asset2Extension.ContainsKey(assetType))
  172. asset2Extension.Add(assetType, mapping.Extension);
  173. if (!inventory2Content.ContainsKey(mapping.InventoryType))
  174. inventory2Content.Add(mapping.InventoryType, mapping.ContentType);
  175. if (!content2Asset.ContainsKey(mapping.ContentType))
  176. content2Asset.Add(mapping.ContentType, assetType);
  177. if (!content2Inventory.ContainsKey(mapping.ContentType))
  178. content2Inventory.Add(mapping.ContentType, mapping.InventoryType);
  179. if (mapping.ContentType2 != null)
  180. {
  181. if (!content2Asset.ContainsKey(mapping.ContentType2))
  182. content2Asset.Add(mapping.ContentType2, assetType);
  183. if (!content2Inventory.ContainsKey(mapping.ContentType2))
  184. content2Inventory.Add(mapping.ContentType2, mapping.InventoryType);
  185. }
  186. }
  187. }
  188. public static string SLAssetTypeToContentType(int assetType)
  189. {
  190. string contentType;
  191. if (!asset2Content.TryGetValue((sbyte)assetType, out contentType))
  192. contentType = asset2Content[(sbyte)AssetType.Unknown];
  193. return contentType;
  194. }
  195. public static string SLInvTypeToContentType(int invType)
  196. {
  197. string contentType;
  198. if (!inventory2Content.TryGetValue((InventoryType)invType, out contentType))
  199. contentType = inventory2Content[InventoryType.Unknown];
  200. return contentType;
  201. }
  202. public static sbyte ContentTypeToSLAssetType(string contentType)
  203. {
  204. sbyte assetType;
  205. if (!content2Asset.TryGetValue(contentType, out assetType))
  206. assetType = (sbyte)AssetType.Unknown;
  207. return (sbyte)assetType;
  208. }
  209. public static sbyte ContentTypeToSLInvType(string contentType)
  210. {
  211. InventoryType invType;
  212. if (!content2Inventory.TryGetValue(contentType, out invType))
  213. invType = InventoryType.Unknown;
  214. return (sbyte)invType;
  215. }
  216. public static string SLAssetTypeToExtension(int assetType)
  217. {
  218. string extension;
  219. if (!asset2Extension.TryGetValue((sbyte)assetType, out extension))
  220. extension = asset2Extension[(sbyte)AssetType.Unknown];
  221. return extension;
  222. }
  223. #endregion SL / file extension / content-type conversions
  224. /// <summary>
  225. /// Parse a notecard in Linden format to a string of ordinary text.
  226. /// </summary>
  227. /// <param name="rawInput"></param>
  228. /// <returns></returns>
  229. public static string ParseNotecardToString(string rawInput)
  230. {
  231. string[] output = ParseNotecardToList(rawInput).ToArray();
  232. // foreach (string line in output)
  233. // m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line);
  234. return string.Join("\n", output);
  235. }
  236. /// <summary>
  237. /// Parse a notecard in Linden format to a list of ordinary lines.
  238. /// </summary>
  239. /// <param name="rawInput"></param>
  240. /// <returns></returns>
  241. public static List<string> ParseNotecardToList(string rawInput)
  242. {
  243. string[] input;
  244. int idx = 0;
  245. int level = 0;
  246. List<string> output = new List<string>();
  247. string[] words;
  248. //The Linden format always ends with a } after the input data.
  249. //Strip off trailing } so there is nothing after the input data.
  250. int i = rawInput.LastIndexOf("}");
  251. rawInput = rawInput.Remove(i, rawInput.Length-i);
  252. input = rawInput.Replace("\r", "").Split('\n');
  253. while (idx < input.Length)
  254. {
  255. if (input[idx] == "{")
  256. {
  257. level++;
  258. idx++;
  259. continue;
  260. }
  261. if (input[idx]== "}")
  262. {
  263. level--;
  264. idx++;
  265. continue;
  266. }
  267. switch (level)
  268. {
  269. case 0:
  270. words = input[idx].Split(' '); // Linden text ver
  271. // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard)
  272. if (words.Length < 3)
  273. return output;
  274. int version = int.Parse(words[3]);
  275. if (version != 2)
  276. return output;
  277. break;
  278. case 1:
  279. words = input[idx].Split(' ');
  280. if (words[0] == "LLEmbeddedItems")
  281. break;
  282. if (words[0] == "Text")
  283. {
  284. idx++; //Now points to first line of notecard text
  285. //Number of lines in notecard.
  286. int lines = input.Length - idx;
  287. int line = 0;
  288. while (line < lines)
  289. {
  290. // m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", input[idx]);
  291. output.Add(input[idx]);
  292. idx++;
  293. line++;
  294. }
  295. return output;
  296. }
  297. break;
  298. case 2:
  299. words = input[idx].Split(' '); // count
  300. if (words[0] == "count")
  301. {
  302. int c = int.Parse(words[1]);
  303. if (c > 0)
  304. return output;
  305. break;
  306. }
  307. break;
  308. }
  309. idx++;
  310. }
  311. return output;
  312. }
  313. }
  314. }