123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using OpenMetaverse;
- using System;
- using System.Collections.Generic;
- namespace OpenSim.Framework
- {
- public static class SLUtil
- {
- // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- /// <summary>
- /// Asset types used only in OpenSim.
- /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here.
- /// </summary>
- public enum OpenSimAssetType : sbyte
- {
- Material = -2
- }
- #region SL / file extension / content-type conversions
- /// <summary>
- /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs
- /// to the AssetType or OpenSimAssetType enums.
- /// </summary>
- public static object AssetTypeFromCode(sbyte assetType)
- {
- if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
- return (OpenMetaverse.AssetType)assetType;
- else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType))
- return (OpenSimAssetType)assetType;
- else
- return OpenMetaverse.AssetType.Unknown;
- }
- private class TypeMapping
- {
- private sbyte assetType;
- private sbyte inventoryType;
- private string contentType;
- private string contentType2;
- private string extension;
- public sbyte AssetTypeCode
- {
- get { return assetType; }
- }
- public object AssetType
- {
- get { return AssetTypeFromCode(assetType); }
- }
- public sbyte InventoryType
- {
- get { return inventoryType; }
- }
- public string ContentType
- {
- get { return contentType; }
- }
- public string ContentType2
- {
- get { return contentType2; }
- }
- public string Extension
- {
- get { return extension; }
- }
- private TypeMapping(sbyte assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
- {
- this.assetType = assetType;
- this.inventoryType = inventoryType;
- this.contentType = contentType;
- this.contentType2 = contentType2;
- this.extension = extension;
- }
- public TypeMapping(AssetType assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
- : this((sbyte)assetType, inventoryType, contentType, contentType2, extension)
- {
- }
- public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
- : this((sbyte)assetType, (sbyte)inventoryType, contentType, contentType2, extension)
- {
- }
- public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension)
- : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
- {
- }
- public TypeMapping(AssetType assetType, FolderType inventoryType, string contentType, string extension)
- : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
- {
- }
- public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension)
- : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
- {
- }
- }
- /// <summary>
- /// Maps between AssetType, InventoryType and Content-Type.
- /// Where more than one possibility exists, the first one takes precedence. E.g.:
- /// AssetType "AssetType.Texture" -> Content-Type "image-xj2c"
- /// Content-Type "image/x-j2c" -> InventoryType "InventoryType.Texture"
- /// </summary>
- private static TypeMapping[] MAPPINGS = new TypeMapping[] {
- new TypeMapping(AssetType.Unknown, InventoryType.Unknown, "application/octet-stream", "bin"),
- new TypeMapping(AssetType.Texture, InventoryType.Texture, "image/x-j2c", "image/jp2", "j2c"),
- new TypeMapping(AssetType.Texture, InventoryType.Snapshot, "image/x-j2c", "image/jp2", "j2c"),
- new TypeMapping(AssetType.TextureTGA, InventoryType.Texture, "image/tga", "tga"),
- new TypeMapping(AssetType.ImageTGA, InventoryType.Texture, "image/tga", "tga"),
- new TypeMapping(AssetType.ImageJPEG, InventoryType.Texture, "image/jpeg", "jpg"),
- new TypeMapping(AssetType.Sound, InventoryType.Sound, "audio/ogg", "application/ogg", "ogg"),
- new TypeMapping(AssetType.SoundWAV, InventoryType.Sound, "audio/x-wav", "wav"),
- new TypeMapping(AssetType.CallingCard, InventoryType.CallingCard, "application/vnd.ll.callingcard", "application/x-metaverse-callingcard", "callingcard"),
- new TypeMapping(AssetType.Landmark, InventoryType.Landmark, "application/vnd.ll.landmark", "application/x-metaverse-landmark", "landmark"),
- new TypeMapping(AssetType.Clothing, InventoryType.Wearable, "application/vnd.ll.clothing", "application/x-metaverse-clothing", "clothing"),
- new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
- new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
- new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"),
- new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"),
- new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"),
- new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"),
- new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"),
- new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"),
- new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"),
- new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"),
- new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"),
- new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"),
- // The next few items are about inventory folders
- new TypeMapping(AssetType.Folder, FolderType.None, "application/vnd.ll.folder", "folder"),
- new TypeMapping(AssetType.Folder, FolderType.Root, "application/vnd.ll.rootfolder", "rootfolder"),
- new TypeMapping(AssetType.Folder, FolderType.Trash, "application/vnd.ll.trashfolder", "trashfolder"),
- new TypeMapping(AssetType.Folder, FolderType.Snapshot, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
- new TypeMapping(AssetType.Folder, FolderType.LostAndFound, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
- new TypeMapping(AssetType.Folder, FolderType.Favorites, "application/vnd.ll.favoritefolder", "favoritefolder"),
- new TypeMapping(AssetType.Folder, FolderType.CurrentOutfit, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"),
- new TypeMapping(AssetType.Folder, FolderType.Outfit, "application/vnd.ll.outfitfolder", "outfitfolder"),
- new TypeMapping(AssetType.Folder, FolderType.MyOutfits, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"),
- // This next mappping is an asset to inventory item mapping.
- // Note: LL stores folders as assets of type Folder = 8, and it has a corresponding InventoryType = 8
- // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server
- new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
- // OpenSim specific
- new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material")
- };
- private static Dictionary<sbyte, string> asset2Content;
- private static Dictionary<sbyte, string> asset2Extension;
- private static Dictionary<sbyte, string> inventory2Content;
- private static Dictionary<string, sbyte> content2Asset;
- private static Dictionary<string, sbyte> content2Inventory;
- static SLUtil()
- {
- asset2Content = new Dictionary<sbyte, string>();
- asset2Extension = new Dictionary<sbyte, string>();
- inventory2Content = new Dictionary<sbyte, string>();
- content2Asset = new Dictionary<string, sbyte>();
- content2Inventory = new Dictionary<string, sbyte>();
- foreach (TypeMapping mapping in MAPPINGS)
- {
- sbyte assetType = mapping.AssetTypeCode;
- if (!asset2Content.ContainsKey(assetType))
- asset2Content.Add(assetType, mapping.ContentType);
- if (!asset2Extension.ContainsKey(assetType))
- asset2Extension.Add(assetType, mapping.Extension);
- if (!inventory2Content.ContainsKey(mapping.InventoryType))
- inventory2Content.Add(mapping.InventoryType, mapping.ContentType);
- if (!content2Asset.ContainsKey(mapping.ContentType))
- content2Asset.Add(mapping.ContentType, assetType);
- if (!content2Inventory.ContainsKey(mapping.ContentType))
- content2Inventory.Add(mapping.ContentType, mapping.InventoryType);
- if (mapping.ContentType2 != null)
- {
- if (!content2Asset.ContainsKey(mapping.ContentType2))
- content2Asset.Add(mapping.ContentType2, assetType);
- if (!content2Inventory.ContainsKey(mapping.ContentType2))
- content2Inventory.Add(mapping.ContentType2, mapping.InventoryType);
- }
- }
- }
- public static string SLAssetTypeToContentType(int assetType)
- {
- string contentType;
- if (!asset2Content.TryGetValue((sbyte)assetType, out contentType))
- contentType = asset2Content[(sbyte)AssetType.Unknown];
- return contentType;
- }
- public static string SLInvTypeToContentType(int invType)
- {
- string contentType;
- if (!inventory2Content.TryGetValue((sbyte)invType, out contentType))
- contentType = inventory2Content[(sbyte)InventoryType.Unknown];
- return contentType;
- }
- public static sbyte ContentTypeToSLAssetType(string contentType)
- {
- sbyte assetType;
- if (!content2Asset.TryGetValue(contentType, out assetType))
- assetType = (sbyte)AssetType.Unknown;
- return (sbyte)assetType;
- }
- public static sbyte ContentTypeToSLInvType(string contentType)
- {
- sbyte invType;
- if (!content2Inventory.TryGetValue(contentType, out invType))
- invType = (sbyte)InventoryType.Unknown;
- return (sbyte)invType;
- }
- public static string SLAssetTypeToExtension(int assetType)
- {
- string extension;
- if (!asset2Extension.TryGetValue((sbyte)assetType, out extension))
- extension = asset2Extension[(sbyte)AssetType.Unknown];
- return extension;
- }
- #endregion SL / file extension / content-type conversions
- private class NotecardReader
- {
- private string rawInput;
- private int lineNumber;
- public int LineNumber
- {
- get
- {
- return lineNumber;
- }
- }
- public NotecardReader(string _rawInput)
- {
- rawInput = (string)_rawInput.Clone();
- lineNumber = 0;
- }
- public string getLine()
- {
- if(rawInput.Length == 0)
- {
- throw new NotANotecardFormatException(lineNumber + 1);
- }
- int pos = rawInput.IndexOf('\n');
- if(pos < 0)
- {
- pos = rawInput.Length;
- }
- /* cut line from rest */
- ++lineNumber;
- string line = rawInput.Substring(0, pos);
- if (pos + 1 >= rawInput.Length)
- {
- rawInput = string.Empty;
- }
- else
- {
- rawInput = rawInput.Substring(pos + 1);
- }
- /* clean up line from double spaces and tabs */
- line = line.Replace("\t", " ");
- while(line.IndexOf(" ") >= 0)
- {
- line = line.Replace(" ", " ");
- }
- return line.Replace("\r", "").Trim();
- }
- public string getBlock(int length)
- {
- /* cut line from rest */
- if(length > rawInput.Length)
- {
- throw new NotANotecardFormatException(lineNumber);
- }
- string line = rawInput.Substring(0, length);
- rawInput = rawInput.Substring(length);
- return line;
- }
- }
- public class NotANotecardFormatException : Exception
- {
- public int lineNumber;
- public NotANotecardFormatException(int _lineNumber)
- : base()
- {
- lineNumber = _lineNumber;
- }
- }
- private static void skipSection(NotecardReader reader)
- {
- if (reader.getLine() != "{")
- throw new NotANotecardFormatException(reader.LineNumber);
- string line;
- while ((line = reader.getLine()) != "}")
- {
- if(line.IndexOf('{')>=0)
- {
- throw new NotANotecardFormatException(reader.LineNumber);
- }
- }
- }
- private static void skipInventoryItem(NotecardReader reader)
- {
- if (reader.getLine() != "{")
- throw new NotANotecardFormatException(reader.LineNumber);
- string line;
- while((line = reader.getLine()) != "}")
- {
- string[] data = line.Split(' ');
- if(data.Length == 0)
- {
- continue;
- }
- if(data[0] == "permissions")
- {
- skipSection(reader);
- }
- else if(data[0] == "sale_info")
- {
- skipSection(reader);
- }
- else if (line.IndexOf('{') >= 0)
- {
- throw new NotANotecardFormatException(reader.LineNumber);
- }
- }
- }
- private static void skipInventoryItems(NotecardReader reader)
- {
- if(reader.getLine() != "{")
- {
- throw new NotANotecardFormatException(reader.LineNumber);
- }
- string line;
- while((line = reader.getLine()) != "}")
- {
- string[] data = line.Split(' ');
- if(data.Length == 0)
- {
- continue;
- }
- if(data[0] == "inv_item")
- {
- skipInventoryItem(reader);
- }
- else if (line.IndexOf('{') >= 0)
- {
- throw new NotANotecardFormatException(reader.LineNumber);
- }
- }
- }
- private static void skipInventory(NotecardReader reader)
- {
- if (reader.getLine() != "{")
- throw new NotANotecardFormatException(reader.LineNumber);
- string line;
- while((line = reader.getLine()) != "}")
- {
- string[] data = line.Split(' ');
- if(data[0] == "count")
- {
- int count = Int32.Parse(data[1]);
- for(int i = 0; i < count; ++i)
- {
- skipInventoryItems(reader);
- }
- }
- else if (line.IndexOf('{') >= 0)
- {
- throw new NotANotecardFormatException(reader.LineNumber);
- }
- }
- }
- private static string readNotecardText(NotecardReader reader)
- {
- if (reader.getLine() != "{")
- throw new NotANotecardFormatException(reader.LineNumber);
- string notecardString = string.Empty;
- string line;
- while((line = reader.getLine()) != "}")
- {
- string[] data = line.Split(' ');
- if (data.Length == 0)
- {
- continue;
- }
- if (data[0] == "LLEmbeddedItems")
- {
- skipInventory(reader);
- }
- else if(data[0] == "Text" && data.Length == 3)
- {
- int length = Int32.Parse(data[2]);
- notecardString = reader.getBlock(length);
- }
- else if (line.IndexOf('{') >= 0)
- {
- throw new NotANotecardFormatException(reader.LineNumber);
- }
- }
- return notecardString;
- }
- private static string readNotecard(byte[] rawInput)
- {
- string rawIntermedInput = string.Empty;
- /* make up a Raw Encoding here */
- foreach(byte c in rawInput)
- {
- char d = (char)c;
- rawIntermedInput += d;
- }
- NotecardReader reader = new NotecardReader(rawIntermedInput);
- string line;
- try
- {
- line = reader.getLine();
- }
- catch(Exception)
- {
- return System.Text.Encoding.UTF8.GetString(rawInput);
- }
- string[] versioninfo = line.Split(' ');
- if(versioninfo.Length < 3)
- {
- return System.Text.Encoding.UTF8.GetString(rawInput);
- }
- else if(versioninfo[0] != "Linden" || versioninfo[1] != "text")
- {
- return System.Text.Encoding.UTF8.GetString(rawInput);
- }
- else
- {
- /* now we actually decode the Encoding, before we needed it in raw */
- string o = readNotecardText(reader);
- byte[] a = new byte[o.Length];
- for(int i = 0; i < o.Length; ++i)
- {
- a[i] = (byte)o[i];
- }
- return System.Text.Encoding.UTF8.GetString(a);
- }
- }
- /// <summary>
- /// Parse a notecard in Linden format to a string of ordinary text.
- /// </summary>
- /// <param name="rawInput"></param>
- /// <returns></returns>
- public static string ParseNotecardToString(byte[] rawInput)
- {
- return readNotecard(rawInput);
- }
- /// <summary>
- /// Parse a notecard in Linden format to a list of ordinary lines.
- /// </summary>
- /// <param name="rawInput"></param>
- /// <returns></returns>
- public static string[] ParseNotecardToArray(byte[] rawInput)
- {
- return readNotecard(rawInput).Replace("\r", "").Split('\n');
- }
- }
- }
|