SLUtil.cs 15 KB

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